完善政府端
This commit is contained in:
@@ -42,8 +42,8 @@ Page({
|
||||
// 并行获取各项统计数据
|
||||
const [productsRes, applicationsRes, contractsRes, releasesRes] = await Promise.allSettled([
|
||||
apiService.loanProducts.getStats(),
|
||||
apiService.loanApplications.getStats(),
|
||||
apiService.loanContracts.getStats(),
|
||||
// apiService.loanApplications.getStats(),
|
||||
// apiService.loanContracts.getStats(),
|
||||
apiService.loanReleases.getStats()
|
||||
]);
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
</a-sub-menu>
|
||||
|
||||
<!-- 无纸化检疫 -->
|
||||
<a-sub-menu key="/paperless/quarantine">
|
||||
<!-- <a-sub-menu key="/paperless/quarantine">
|
||||
<template #icon><SafetyOutlined /></template>
|
||||
<template #title>
|
||||
<span>无纸化检疫</span>
|
||||
@@ -93,7 +93,7 @@
|
||||
<a-menu-item key="/paperless/quarantine/declaration"><span>检疫审批</span></a-menu-item>
|
||||
<a-menu-item key="/paperless/quarantine/record-query"><span>检疫证查询</span></a-menu-item>
|
||||
<a-menu-item key="/paperless/quarantine/config"><span>检疫站清单</span></a-menu-item>
|
||||
</a-sub-menu>
|
||||
</a-sub-menu> -->
|
||||
|
||||
<!-- 生资认证 -->
|
||||
<a-menu-item key="/examine/index">
|
||||
@@ -108,7 +108,7 @@
|
||||
</a-menu-item>
|
||||
|
||||
<!-- 设备预警 -->
|
||||
<a-menu-item key="/device-alert">
|
||||
<a-menu-item key="/device-warning">
|
||||
<template #icon><ExclamationCircleOutlined /></template>
|
||||
<span>设备预警</span>
|
||||
</a-menu-item>
|
||||
|
||||
62
government-admin/src/utils/approvalProcessApi.js
Normal file
62
government-admin/src/utils/approvalProcessApi.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import axios from 'axios'
|
||||
|
||||
const API_BASE_URL = 'http://localhost:5352/api/approval-process'
|
||||
|
||||
// 创建axios实例
|
||||
const api = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
// 请求拦截器
|
||||
api.interceptors.request.use(
|
||||
config => {
|
||||
// 可以在这里添加token等认证信息
|
||||
const token = localStorage.getItem('token')
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 响应拦截器
|
||||
api.interceptors.response.use(
|
||||
response => {
|
||||
return response.data
|
||||
},
|
||||
error => {
|
||||
console.error('API请求错误:', error)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 审批流程管理API
|
||||
export default {
|
||||
// 获取审批流程列表
|
||||
getApprovalProcesses: (params) => api.get('/', { params }),
|
||||
|
||||
// 获取审批流程详情
|
||||
getApprovalProcessById: (id) => api.get(`/${id}`),
|
||||
|
||||
// 创建审批流程
|
||||
createApprovalProcess: (data) => api.post('/', data),
|
||||
|
||||
// 更新审批流程
|
||||
updateApprovalProcess: (id, data) => api.put(`/${id}`, data),
|
||||
|
||||
// 删除审批流程
|
||||
deleteApprovalProcess: (id) => api.delete(`/${id}`),
|
||||
|
||||
// 审批操作(通过/拒绝)
|
||||
processApproval: (id, data) => api.post(`/${id}/process`, data),
|
||||
|
||||
// 更新审批状态
|
||||
updateApprovalStatus: (id, status) => api.patch(`/${id}/status`, { status })
|
||||
}
|
||||
62
government-admin/src/utils/cattleAcademyApi.js
Normal file
62
government-admin/src/utils/cattleAcademyApi.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import axios from 'axios'
|
||||
|
||||
const API_BASE_URL = 'http://localhost:5352/api/cattle-academy'
|
||||
|
||||
// 创建axios实例
|
||||
const api = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
// 请求拦截器
|
||||
api.interceptors.request.use(
|
||||
config => {
|
||||
// 可以在这里添加token等认证信息
|
||||
const token = localStorage.getItem('token')
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 响应拦截器
|
||||
api.interceptors.response.use(
|
||||
response => {
|
||||
return response.data
|
||||
},
|
||||
error => {
|
||||
console.error('API请求错误:', error)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 养牛学院资讯管理API
|
||||
export default {
|
||||
// 获取养牛学院资讯列表
|
||||
getCattleAcademyList: (params) => api.get('/', { params }),
|
||||
|
||||
// 获取养牛学院资讯详情
|
||||
getCattleAcademyById: (id) => api.get(`/${id}`),
|
||||
|
||||
// 创建养牛学院资讯
|
||||
createCattleAcademy: (data) => api.post('/', data),
|
||||
|
||||
// 更新养牛学院资讯
|
||||
updateCattleAcademy: (id, data) => api.put(`/${id}`, data),
|
||||
|
||||
// 删除养牛学院资讯
|
||||
deleteCattleAcademy: (id) => api.delete(`/${id}`),
|
||||
|
||||
// 切换资讯状态
|
||||
toggleCattleAcademyStatus: (id, status) => api.patch(`/${id}/status`, { status }),
|
||||
|
||||
// 批量更新排序
|
||||
updateSort: (items) => api.patch('/sort', { items })
|
||||
}
|
||||
44
government-admin/src/utils/deviceWarningApi.js
Normal file
44
government-admin/src/utils/deviceWarningApi.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const API_BASE_URL = 'http://localhost:5352/api/device-warning';
|
||||
|
||||
const api = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
api.interceptors.request.use(
|
||||
config => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
error => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
api.interceptors.response.use(
|
||||
response => {
|
||||
return response.data;
|
||||
},
|
||||
error => {
|
||||
console.error('API Error:', error.response ? error.response.data : error.message);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default {
|
||||
getDeviceWarnings: (params) => api.get('/', { params }),
|
||||
getDeviceWarningById: (id) => api.get(`/${id}`),
|
||||
createDeviceWarning: (data) => api.post('/', data),
|
||||
updateDeviceWarning: (id, data) => api.put(`/${id}`, data),
|
||||
deleteDeviceWarning: (id) => api.delete(`/${id}`),
|
||||
updateWarningStatus: (id, data) => api.patch(`/${id}/status`, data),
|
||||
getWarningStats: () => api.get('/stats'),
|
||||
};
|
||||
73
government-admin/src/utils/epidemicActivityApi.js
Normal file
73
government-admin/src/utils/epidemicActivityApi.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import axios from 'axios'
|
||||
|
||||
const API_BASE_URL = 'http://localhost:5352/api/epidemic-activity'
|
||||
|
||||
// 创建axios实例
|
||||
const api = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
// 请求拦截器
|
||||
api.interceptors.request.use(
|
||||
config => {
|
||||
// 可以在这里添加token等认证信息
|
||||
const token = localStorage.getItem('token')
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 响应拦截器
|
||||
api.interceptors.response.use(
|
||||
response => {
|
||||
return response.data
|
||||
},
|
||||
error => {
|
||||
console.error('API请求错误:', error)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 防疫活动管理API
|
||||
export const epidemicActivityApi = {
|
||||
// 获取防疫活动列表
|
||||
getActivities(params = {}) {
|
||||
return api.get('/', { params })
|
||||
},
|
||||
|
||||
// 根据ID获取防疫活动详情
|
||||
getActivityById(id) {
|
||||
return api.get(`/${id}`)
|
||||
},
|
||||
|
||||
// 创建防疫活动
|
||||
createActivity(data) {
|
||||
return api.post('/', data)
|
||||
},
|
||||
|
||||
// 更新防疫活动
|
||||
updateActivity(id, data) {
|
||||
return api.put(`/${id}`, data)
|
||||
},
|
||||
|
||||
// 删除防疫活动
|
||||
deleteActivity(id) {
|
||||
return api.delete(`/${id}`)
|
||||
},
|
||||
|
||||
// 切换活动状态
|
||||
toggleActivityStatus(id) {
|
||||
return api.patch(`/${id}/status`)
|
||||
}
|
||||
}
|
||||
|
||||
export default epidemicActivityApi
|
||||
@@ -0,0 +1,59 @@
|
||||
import axios from 'axios'
|
||||
|
||||
const API_BASE_URL = 'http://localhost:5352/api/production-material-certification'
|
||||
|
||||
// 创建axios实例
|
||||
const api = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
// 请求拦截器
|
||||
api.interceptors.request.use(
|
||||
config => {
|
||||
// 可以在这里添加token等认证信息
|
||||
const token = localStorage.getItem('token')
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 响应拦截器
|
||||
api.interceptors.response.use(
|
||||
response => {
|
||||
return response.data
|
||||
},
|
||||
error => {
|
||||
console.error('API请求错误:', error)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 生资认证管理API
|
||||
export default {
|
||||
// 获取生资认证列表
|
||||
getCertifications: (params) => api.get('/', { params }),
|
||||
|
||||
// 获取生资认证详情
|
||||
getCertificationById: (id) => api.get(`/${id}`),
|
||||
|
||||
// 创建生资认证
|
||||
createCertification: (data) => api.post('/', data),
|
||||
|
||||
// 更新生资认证
|
||||
updateCertification: (id, data) => api.put(`/${id}`, data),
|
||||
|
||||
// 删除生资认证
|
||||
deleteCertification: (id) => api.delete(`/${id}`),
|
||||
|
||||
// 切换认证状态
|
||||
toggleCertificationStatus: (id, status) => api.patch(`/${id}/status`, { status })
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 审批卡片列表 -->
|
||||
<div class="card-list">
|
||||
<div class="card-list" v-loading="loading">
|
||||
<a-row :gutter="[16, 16]">
|
||||
<a-col :span="8" v-for="item in approvalList" :key="item.id">
|
||||
<a-card class="approval-card" @click="() => viewApprovalDetail(item.id)">
|
||||
@@ -32,15 +32,21 @@
|
||||
<a-tag :color="getStatusColor(item.status)">{{ getStatusText(item.status) }}</a-tag>
|
||||
</div>
|
||||
</template>
|
||||
<p>认证申请人: {{ item.applicant }}</p>
|
||||
<p>认证类型: {{ item.type }}</p>
|
||||
<p>认证数量: {{ item.quantity }}</p>
|
||||
<p>申请时间: {{ item.create_time }}</p>
|
||||
<p>联系电话: {{ item.phone }}</p>
|
||||
<p>养殖场名称: {{ item.farmName }}</p>
|
||||
<p><strong>审批标题:</strong> {{ item.title }}</p>
|
||||
<p><strong>申请人:</strong> {{ item.applicant }}</p>
|
||||
<p><strong>审批类型:</strong> {{ getTypeText(item.type) }}</p>
|
||||
<p><strong>申请时间:</strong> {{ item.create_time }}</p>
|
||||
<p><strong>联系电话:</strong> {{ item.phone || '未填写' }}</p>
|
||||
<p><strong>养殖场名称:</strong> {{ item.farmName }}</p>
|
||||
<p v-if="item.quantity"><strong>认证数量:</strong> {{ item.quantity }}</p>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<div v-if="!loading && approvalList.length === 0" class="empty-state">
|
||||
<a-empty description="暂无审批流程数据" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
@@ -137,8 +143,8 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { message } from 'antd'
|
||||
import axios from 'axios'
|
||||
import { message } from 'ant-design-vue'
|
||||
import approvalProcessApi from '@/utils/approvalProcessApi'
|
||||
import { UploadOutlined } from '@ant-design/icons-vue'
|
||||
|
||||
const allData = ref([])
|
||||
@@ -148,6 +154,7 @@ const currentPage = ref(1)
|
||||
const pageSize = ref(9)
|
||||
const totalItems = ref(0)
|
||||
const searchInput = ref('')
|
||||
const loading = ref(false)
|
||||
|
||||
const createModalVisible = ref(false)
|
||||
const processModalVisible = ref(false)
|
||||
@@ -206,38 +213,58 @@ const getTypeText = (type) => {
|
||||
// 获取审批流程列表
|
||||
const fetchApprovalList = async () => {
|
||||
try {
|
||||
// 这里应该从API获取数据
|
||||
// 由于没有实际API,使用模拟数据
|
||||
approvalList.value = [
|
||||
{ id: 1, title: '食品经营许可证申请', type: 'license', applicant: '张三', create_time: '2024-01-10 09:00:00', status: 'pending', description: '申请食品经营许可证' },
|
||||
{ id: 2, title: '企业资质年审', type: 'enterprise', applicant: '李四', create_time: '2024-01-09 14:30:00', status: 'approved', description: '企业资质年度审核' },
|
||||
{ id: 3, title: '新药品研发项目', type: 'project', applicant: '王五', create_time: '2024-01-08 11:20:00', status: 'processing', description: '新型药品研发项目审批' },
|
||||
{ id: 4, title: '环保设施改造', type: 'project', applicant: '赵六', create_time: '2024-01-07 16:40:00', status: 'rejected', description: '工厂环保设施改造审批' },
|
||||
{ id: 5, title: '特殊行业许可证', type: 'license', applicant: '钱七', create_time: '2024-01-06 10:15:00', status: 'pending', description: '申请特殊行业经营许可证' },
|
||||
{ id: 6, title: '企业扩大经营规模', type: 'enterprise', applicant: '孙八', create_time: '2024-01-05 13:30:00', status: 'approved', description: '企业扩大生产经营规模审批' },
|
||||
{ id: 7, title: '新产品上市审批', type: 'other', applicant: '周九', create_time: '2024-01-04 09:45:00', status: 'pending', description: '新产品上市销售审批' },
|
||||
{ id: 8, title: '消防设施验收', type: 'project', applicant: '吴十', create_time: '2024-01-03 15:20:00', status: 'processing', description: '新建建筑消防设施验收' },
|
||||
{ id: 9, title: '卫生许可证换证', type: 'license', applicant: '郑一', create_time: '2024-01-02 11:00:00', status: 'approved', description: '卫生许可证到期换证' },
|
||||
{ id: 10, title: '临时占道经营', type: 'other', applicant: '王二', create_time: '2024-01-01 09:30:00', status: 'rejected', description: '临时占道经营活动审批' }
|
||||
]
|
||||
loading.value = true
|
||||
const params = {
|
||||
page: currentPage.value,
|
||||
pageSize: pageSize.value,
|
||||
status: activeTab.value === 'pending' ? 'pending' : activeTab.value === 'approved' ? 'approved' : undefined,
|
||||
applicant: searchInput.value
|
||||
}
|
||||
|
||||
const response = await approvalProcessApi.getApprovalProcesses(params)
|
||||
if (response.code === 200) {
|
||||
approvalList.value = response.data.list.map(item => ({
|
||||
...item,
|
||||
create_time: item.createdAt,
|
||||
farmName: item.farmName || '未填写'
|
||||
}))
|
||||
totalItems.value = response.data.total
|
||||
} else {
|
||||
message.error(response.message || '获取数据失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取审批流程列表失败:', error)
|
||||
message.error('获取审批流程列表失败,请稍后重试')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索审批
|
||||
const searchApproval = (value) => {
|
||||
message.info(`搜索关键词: ${value}`)
|
||||
// 这里应该根据搜索关键词过滤数据
|
||||
// 目前使用模拟数据,实际项目中需要调用API
|
||||
const onSearch = (value) => {
|
||||
searchInput.value = value
|
||||
currentPage.value = 1
|
||||
fetchApprovalList()
|
||||
}
|
||||
|
||||
// 查看审批详情
|
||||
const viewApprovalDetail = (id) => {
|
||||
message.info(`查看审批ID: ${id} 的详情`)
|
||||
// 这里可以跳转到详情页面
|
||||
// router.push(`/approval/detail/${id}`)
|
||||
const viewApprovalDetail = async (id) => {
|
||||
try {
|
||||
const response = await approvalProcessApi.getApprovalProcessById(id)
|
||||
if (response.code === 200) {
|
||||
currentApproval.value = {
|
||||
...response.data,
|
||||
create_time: response.data.createdAt,
|
||||
farmName: response.data.farmName || '未填写'
|
||||
}
|
||||
processModalVisible.value = true
|
||||
} else {
|
||||
message.error(response.message || '获取详情失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取审批详情失败:', error)
|
||||
message.error('获取详情失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑审批
|
||||
@@ -264,23 +291,31 @@ const processApproval = (id) => {
|
||||
}
|
||||
|
||||
// 通过审批
|
||||
const approveApproval = () => {
|
||||
const approveApproval = async () => {
|
||||
if (!currentApproval.value) return
|
||||
|
||||
message.success(`已通过审批: ${currentApproval.value.title}`)
|
||||
// 这里应该调用审批通过API
|
||||
|
||||
// 更新本地数据
|
||||
const index = approvalList.value.findIndex(item => item.id === currentApproval.value.id)
|
||||
if (index !== -1) {
|
||||
approvalList.value[index].status = 'approved'
|
||||
try {
|
||||
const response = await approvalProcessApi.processApproval(currentApproval.value.id, {
|
||||
action: 'approve',
|
||||
approvalComment: approvalComment.value,
|
||||
approver: '当前用户' // 这里应该从用户信息中获取
|
||||
})
|
||||
|
||||
if (response.code === 200) {
|
||||
message.success(`已通过审批: ${currentApproval.value.title}`)
|
||||
closeProcessModal()
|
||||
fetchApprovalList() // 重新加载数据
|
||||
} else {
|
||||
message.error(response.message || '审批失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('审批操作失败:', error)
|
||||
message.error('审批失败')
|
||||
}
|
||||
|
||||
closeProcessModal()
|
||||
}
|
||||
|
||||
// 拒绝审批
|
||||
const rejectApproval = () => {
|
||||
const rejectApproval = async () => {
|
||||
if (!currentApproval.value) return
|
||||
|
||||
if (!approvalComment.value.trim()) {
|
||||
@@ -288,16 +323,24 @@ const rejectApproval = () => {
|
||||
return
|
||||
}
|
||||
|
||||
message.success(`已拒绝审批: ${currentApproval.value.title}`)
|
||||
// 这里应该调用审批拒绝API
|
||||
|
||||
// 更新本地数据
|
||||
const index = approvalList.value.findIndex(item => item.id === currentApproval.value.id)
|
||||
if (index !== -1) {
|
||||
approvalList.value[index].status = 'rejected'
|
||||
try {
|
||||
const response = await approvalProcessApi.processApproval(currentApproval.value.id, {
|
||||
action: 'reject',
|
||||
approvalComment: approvalComment.value,
|
||||
approver: '当前用户' // 这里应该从用户信息中获取
|
||||
})
|
||||
|
||||
if (response.code === 200) {
|
||||
message.success(`已拒绝审批: ${currentApproval.value.title}`)
|
||||
closeProcessModal()
|
||||
fetchApprovalList() // 重新加载数据
|
||||
} else {
|
||||
message.error(response.message || '审批失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('审批操作失败:', error)
|
||||
message.error('审批失败')
|
||||
}
|
||||
|
||||
closeProcessModal()
|
||||
}
|
||||
|
||||
// 显示新建弹窗
|
||||
@@ -333,15 +376,25 @@ const submitCreateForm = async () => {
|
||||
|
||||
try {
|
||||
await createFormRef.value.validate()
|
||||
// 这里应该调用创建审批API
|
||||
|
||||
message.success('新建审批流程成功')
|
||||
closeCreateModal()
|
||||
const response = await approvalProcessApi.createApprovalProcess({
|
||||
title: createFormData.value.title,
|
||||
type: createFormData.value.type,
|
||||
applicant: createFormData.value.applicant,
|
||||
description: createFormData.value.description,
|
||||
files: createFormData.value.files
|
||||
})
|
||||
|
||||
// 重新加载数据
|
||||
fetchApprovalList()
|
||||
if (response.code === 201) {
|
||||
message.success('新建审批流程成功')
|
||||
closeCreateModal()
|
||||
fetchApprovalList() // 重新加载数据
|
||||
} else {
|
||||
message.error(response.message || '创建失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('表单验证失败:', error)
|
||||
message.error('创建失败')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,6 +415,19 @@ const exportApprovalList = () => {
|
||||
// 这里应该调用导出API
|
||||
}
|
||||
|
||||
// 标签页切换
|
||||
const handleTabChange = (key) => {
|
||||
activeTab.value = key
|
||||
currentPage.value = 1
|
||||
fetchApprovalList()
|
||||
}
|
||||
|
||||
// 分页变化
|
||||
const handlePageChange = (page) => {
|
||||
currentPage.value = page
|
||||
fetchApprovalList()
|
||||
}
|
||||
|
||||
// 组件挂载
|
||||
onMounted(() => {
|
||||
fetchApprovalList()
|
||||
@@ -491,4 +557,56 @@ onMounted(() => {
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
/* 卡片列表样式 */
|
||||
.card-list {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.approval-card {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.approval-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-title span {
|
||||
font-weight: 500;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.approval-card p {
|
||||
margin-bottom: 8px;
|
||||
line-height: 1.5;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.approval-card strong {
|
||||
color: #262626;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 空状态样式 */
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 60px 0;
|
||||
}
|
||||
|
||||
/* 分页容器样式 */
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 24px;
|
||||
}
|
||||
</style>
|
||||
@@ -2,108 +2,444 @@
|
||||
<div class="cattle-academy-container">
|
||||
<div class="header">
|
||||
<a-button type="primary" @click="handleNewInfo">新增资讯</a-button>
|
||||
<a-input-search
|
||||
placeholder="搜索标题或作者"
|
||||
style="width: 300px; margin-left: 16px;"
|
||||
@search="handleSearch"
|
||||
v-model:value="searchKeyword"
|
||||
/>
|
||||
</div>
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data-source="dataSource"
|
||||
:pagination="pagination"
|
||||
:loading="loading"
|
||||
row-key="id"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'coverImage'">
|
||||
<img :src="record.coverImage" alt="封面图" class="cover-image" />
|
||||
</template>
|
||||
<template v-if="column.key === 'status'">
|
||||
<a-switch :checked="record.status" />
|
||||
<a-switch
|
||||
:checked="record.status"
|
||||
@change="(checked) => handleToggleStatus(record, checked)"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="column.key === 'operations'">
|
||||
<a-space>
|
||||
<a @click="handleView(record)">查看</a>
|
||||
<a @click="handleEdit(record)">编辑</a>
|
||||
<a @click="handleDelete(record)">删除</a>
|
||||
<a @click="handleDelete(record)" style="color: #ff4d4f;">删除</a>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<!-- 新增/编辑表单 -->
|
||||
<a-modal
|
||||
v-model:open="isModalOpen"
|
||||
:title="currentInfo.id ? '编辑资讯' : '新增资讯'"
|
||||
@ok="handleSave"
|
||||
@cancel="handleCancel"
|
||||
:width="800"
|
||||
:confirm-loading="modalLoading"
|
||||
>
|
||||
<a-form
|
||||
:model="currentInfo"
|
||||
layout="vertical"
|
||||
:rules="formRules"
|
||||
ref="formRef"
|
||||
>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="标题" name="title">
|
||||
<a-input v-model:value="currentInfo.title" placeholder="请输入标题" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="分类" name="category">
|
||||
<a-select v-model:value="currentInfo.category" placeholder="请选择分类">
|
||||
<a-select-option value="技术资讯">技术资讯</a-select-option>
|
||||
<a-select-option value="养殖技术">养殖技术</a-select-option>
|
||||
<a-select-option value="健康管理">健康管理</a-select-option>
|
||||
<a-select-option value="营养管理">营养管理</a-select-option>
|
||||
<a-select-option value="智能设备">智能设备</a-select-option>
|
||||
<a-select-option value="环保管理">环保管理</a-select-option>
|
||||
<a-select-option value="繁殖技术">繁殖技术</a-select-option>
|
||||
<a-select-option value="经营管理">经营管理</a-select-option>
|
||||
<a-select-option value="市场分析">市场分析</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="作者" name="author">
|
||||
<a-input v-model:value="currentInfo.author" placeholder="请输入作者" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="排序" name="sort">
|
||||
<a-input-number v-model:value="currentInfo.sort" placeholder="请输入排序" style="width: 100%" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item label="封面图URL" name="coverImage">
|
||||
<a-input v-model:value="currentInfo.coverImage" placeholder="请输入封面图URL" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="摘要" name="summary">
|
||||
<a-textarea v-model:value="currentInfo.summary" placeholder="请输入摘要" :rows="3" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="内容" name="content">
|
||||
<a-textarea v-model:value="currentInfo.content" placeholder="请输入内容" :rows="6" />
|
||||
</a-form-item>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="8">
|
||||
<a-form-item label="是否置顶">
|
||||
<a-switch v-model:checked="currentInfo.isTop" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="是否推荐">
|
||||
<a-switch v-model:checked="currentInfo.isRecommend" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="状态">
|
||||
<a-switch v-model:checked="currentInfo.status" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item label="备注" name="remarks">
|
||||
<a-textarea v-model:value="currentInfo.remarks" placeholder="请输入备注" :rows="2" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
|
||||
<!-- 详情查看 -->
|
||||
<a-modal
|
||||
v-model:open="isDetailModalOpen"
|
||||
title="资讯详情"
|
||||
:footer="null"
|
||||
:width="800"
|
||||
>
|
||||
<a-descriptions :column="2" bordered>
|
||||
<a-descriptions-item label="标题">{{ detailData.title }}</a-descriptions-item>
|
||||
<a-descriptions-item label="分类">{{ detailData.category }}</a-descriptions-item>
|
||||
<a-descriptions-item label="作者">{{ detailData.author }}</a-descriptions-item>
|
||||
<a-descriptions-item label="排序">{{ detailData.sort }}</a-descriptions-item>
|
||||
<a-descriptions-item label="浏览次数">{{ detailData.viewCount }}</a-descriptions-item>
|
||||
<a-descriptions-item label="发布时间">{{ detailData.publishTime }}</a-descriptions-item>
|
||||
<a-descriptions-item label="是否置顶">
|
||||
<a-tag :color="detailData.isTop ? 'red' : 'default'">
|
||||
{{ detailData.isTop ? '是' : '否' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="是否推荐">
|
||||
<a-tag :color="detailData.isRecommend ? 'green' : 'default'">
|
||||
{{ detailData.isRecommend ? '是' : '否' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="状态">
|
||||
<a-tag :color="detailData.status ? 'green' : 'red'">
|
||||
{{ detailData.status ? '启用' : '禁用' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="创建时间">{{ detailData.createdAt }}</a-descriptions-item>
|
||||
<a-descriptions-item label="封面图" :span="2">
|
||||
<img v-if="detailData.coverImage" :src="detailData.coverImage" alt="封面图" class="cover-image" />
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="摘要" :span="2">{{ detailData.summary }}</a-descriptions-item>
|
||||
<a-descriptions-item label="内容" :span="2">{{ detailData.content }}</a-descriptions-item>
|
||||
<a-descriptions-item label="备注" :span="2">{{ detailData.remarks }}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import cattleAcademyApi from '@/utils/cattleAcademyApi';
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '标题',
|
||||
dataIndex: 'title',
|
||||
key: 'title',
|
||||
width: 200,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '封面图',
|
||||
dataIndex: 'coverImage',
|
||||
key: 'coverImage',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '分类',
|
||||
dataIndex: 'category',
|
||||
key: 'category',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '作者',
|
||||
dataIndex: 'author',
|
||||
key: 'author',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort',
|
||||
key: 'sort',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '浏览次数',
|
||||
dataIndex: 'viewCount',
|
||||
key: 'viewCount',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'creationTime',
|
||||
key: 'creationTime',
|
||||
dataIndex: 'createdAt',
|
||||
key: 'createdAt',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'operations',
|
||||
width: 150,
|
||||
fixed: 'right'
|
||||
},
|
||||
];
|
||||
|
||||
const dataSource = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: '新疆阿克苏地区电信5G数字乡村项目',
|
||||
coverImage: 'https://via.placeholder.com/100x50',
|
||||
sort: 100,
|
||||
status: true,
|
||||
creationTime: '2022-09-28 11:47:27',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '共享养牛,开启畜牧业财富之路',
|
||||
coverImage: 'https://via.placeholder.com/100x50',
|
||||
sort: 98,
|
||||
status: true,
|
||||
creationTime: '2023-08-28 15:38:35',
|
||||
},
|
||||
// ... more data
|
||||
]);
|
||||
const dataSource = ref([]);
|
||||
const loading = ref(false);
|
||||
const searchKeyword = ref('');
|
||||
|
||||
const pagination = ref({
|
||||
total: dataSource.value.length,
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total, range) => `第 ${range[0]}-${range[1]} 条,共 ${total} 条`
|
||||
});
|
||||
|
||||
// 模态框状态
|
||||
const isModalOpen = ref(false);
|
||||
const isDetailModalOpen = ref(false);
|
||||
const modalLoading = ref(false);
|
||||
|
||||
// 表单引用
|
||||
const formRef = ref(null);
|
||||
|
||||
// 当前编辑的资讯
|
||||
const currentInfo = reactive({
|
||||
id: '',
|
||||
title: '',
|
||||
coverImage: '',
|
||||
content: '',
|
||||
summary: '',
|
||||
category: '',
|
||||
sort: 0,
|
||||
status: true,
|
||||
author: '',
|
||||
publishTime: null,
|
||||
isTop: false,
|
||||
isRecommend: false,
|
||||
remarks: ''
|
||||
});
|
||||
|
||||
// 详情数据
|
||||
const detailData = reactive({});
|
||||
|
||||
// 表单验证规则
|
||||
const formRules = {
|
||||
title: [
|
||||
{ required: true, message: '请输入标题', trigger: 'blur' }
|
||||
],
|
||||
category: [
|
||||
{ required: true, message: '请选择分类', trigger: 'change' }
|
||||
],
|
||||
author: [
|
||||
{ required: true, message: '请输入作者', trigger: 'blur' }
|
||||
]
|
||||
};
|
||||
|
||||
// 获取资讯列表
|
||||
const fetchCattleAcademyList = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const params = {
|
||||
page: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
title: searchKeyword.value,
|
||||
author: searchKeyword.value
|
||||
};
|
||||
|
||||
const response = await cattleAcademyApi.getCattleAcademyList(params);
|
||||
if (response.code === 200) {
|
||||
dataSource.value = response.data.list;
|
||||
pagination.total = response.data.total;
|
||||
} else {
|
||||
message.error(response.message || '获取数据失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取资讯列表失败:', error);
|
||||
message.error('获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
pagination.current = 1;
|
||||
fetchCattleAcademyList();
|
||||
};
|
||||
|
||||
// 表格变化
|
||||
const handleTableChange = (pag) => {
|
||||
pagination.current = pag.current;
|
||||
pagination.pageSize = pag.pageSize;
|
||||
fetchCattleAcademyList();
|
||||
};
|
||||
|
||||
// 新增资讯
|
||||
const handleNewInfo = () => {
|
||||
console.log('New Info');
|
||||
};
|
||||
|
||||
const handleView = (record) => {
|
||||
console.log('View', record);
|
||||
Object.assign(currentInfo, {
|
||||
id: '',
|
||||
title: '',
|
||||
coverImage: '',
|
||||
content: '',
|
||||
summary: '',
|
||||
category: '',
|
||||
sort: 0,
|
||||
status: true,
|
||||
author: '',
|
||||
publishTime: new Date(),
|
||||
isTop: false,
|
||||
isRecommend: false,
|
||||
remarks: ''
|
||||
});
|
||||
isModalOpen.value = true;
|
||||
};
|
||||
|
||||
// 编辑资讯
|
||||
const handleEdit = (record) => {
|
||||
console.log('Edit', record);
|
||||
Object.assign(currentInfo, {
|
||||
...record,
|
||||
publishTime: record.publishTime ? new Date(record.publishTime) : new Date()
|
||||
});
|
||||
isModalOpen.value = true;
|
||||
};
|
||||
|
||||
const handleDelete = (record) => {
|
||||
console.log('Delete', record);
|
||||
// 查看详情
|
||||
const handleView = async (record) => {
|
||||
try {
|
||||
const response = await cattleAcademyApi.getCattleAcademyById(record.id);
|
||||
if (response.code === 200) {
|
||||
Object.assign(detailData, response.data);
|
||||
isDetailModalOpen.value = true;
|
||||
} else {
|
||||
message.error(response.message || '获取详情失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取详情失败:', error);
|
||||
message.error('获取详情失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 删除资讯
|
||||
const handleDelete = async (record) => {
|
||||
try {
|
||||
const response = await cattleAcademyApi.deleteCattleAcademy(record.id);
|
||||
if (response.code === 200) {
|
||||
message.success('删除成功');
|
||||
fetchCattleAcademyList();
|
||||
} else {
|
||||
message.error(response.message || '删除失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除资讯失败:', error);
|
||||
message.error('删除失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 切换状态
|
||||
const handleToggleStatus = async (record, checked) => {
|
||||
try {
|
||||
const response = await cattleAcademyApi.toggleCattleAcademyStatus(record.id, checked);
|
||||
if (response.code === 200) {
|
||||
message.success('状态更新成功');
|
||||
fetchCattleAcademyList();
|
||||
} else {
|
||||
message.error(response.message || '状态更新失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('切换状态失败:', error);
|
||||
message.error('状态更新失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 保存资讯
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
modalLoading.value = true;
|
||||
|
||||
const data = {
|
||||
...currentInfo,
|
||||
publishTime: currentInfo.publishTime ? currentInfo.publishTime.toISOString() : new Date().toISOString()
|
||||
};
|
||||
|
||||
let response;
|
||||
if (currentInfo.id) {
|
||||
response = await cattleAcademyApi.updateCattleAcademy(currentInfo.id, data);
|
||||
} else {
|
||||
response = await cattleAcademyApi.createCattleAcademy(data);
|
||||
}
|
||||
|
||||
if (response.code === 200 || response.code === 201) {
|
||||
message.success(currentInfo.id ? '更新成功' : '创建成功');
|
||||
isModalOpen.value = false;
|
||||
fetchCattleAcademyList();
|
||||
} else {
|
||||
message.error(response.message || '保存失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存资讯失败:', error);
|
||||
message.error('保存失败');
|
||||
} finally {
|
||||
modalLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
isModalOpen.value = false;
|
||||
};
|
||||
|
||||
// 组件挂载时获取数据
|
||||
onMounted(() => {
|
||||
fetchCattleAcademyList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -3,75 +3,199 @@
|
||||
<div class="header">
|
||||
<div class="title">设备预警</div>
|
||||
</div>
|
||||
|
||||
<!-- 预警统计卡片 -->
|
||||
<div class="stats-container">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">8056</div>
|
||||
<div class="stat-value">{{ warningStats.earTag }}</div>
|
||||
<div class="stat-label">耳标预警</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">1</div>
|
||||
<div class="stat-value">{{ warningStats.neckband }}</div>
|
||||
<div class="stat-label">项圈预警</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">61</div>
|
||||
<div class="stat-value">{{ warningStats.host }}</div>
|
||||
<div class="stat-label">主机预警</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-card :bordered="false">
|
||||
<!-- 设备类型标签页和搜索 -->
|
||||
<a-card :bordered="false" class="main-card">
|
||||
<div class="table-header">
|
||||
<a-tabs v-model:activeKey="activeTab">
|
||||
<a-tabs v-model:activeKey="activeTab" @change="handleTabChange">
|
||||
<a-tab-pane key="earTag" tab="智能耳标"></a-tab-pane>
|
||||
<a-tab-pane key="neckband" tab="智能项圈"></a-tab-pane>
|
||||
<a-tab-pane key="host" tab="智能主机"></a-tab-pane>
|
||||
</a-tabs>
|
||||
<a-input v-model:value="searchKeyword" placeholder="请输入养殖户" style="width: 200px;">
|
||||
<template #suffix>
|
||||
<span class="iconfont icon-sousuo"></span>
|
||||
</template>
|
||||
</a-input>
|
||||
<div class="search-container">
|
||||
<a-input
|
||||
v-model:value="searchKeyword"
|
||||
placeholder="请输入养殖户"
|
||||
style="width: 200px;"
|
||||
@pressEnter="handleSearch"
|
||||
>
|
||||
<template #suffix>
|
||||
<span class="iconfont icon-sousuo" @click="handleSearch"></span>
|
||||
</template>
|
||||
</a-input>
|
||||
<a-button type="primary" @click="handleSearch" style="margin-left: 8px;">Q 搜索</a-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data-source="tableData"
|
||||
:data-source="filteredTableData"
|
||||
:pagination="pagination"
|
||||
:loading="loading"
|
||||
row-key="id"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'alertType'">
|
||||
<a-tag :color="getAlertTypeColor(record.alertType)">
|
||||
{{ record.alertType }}
|
||||
</a-tag>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ref, reactive, computed, onMounted } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import deviceWarningApi from '@/utils/deviceWarningApi';
|
||||
|
||||
const activeTab = ref('earTag');
|
||||
const activeTab = ref('neckband');
|
||||
const searchKeyword = ref('');
|
||||
const loading = ref(false);
|
||||
const tableData = ref([]);
|
||||
const warningStats = ref({
|
||||
earTag: 0,
|
||||
neckband: 0,
|
||||
host: 0
|
||||
});
|
||||
|
||||
const columns = [
|
||||
{ title: '养殖场', dataIndex: 'farm', key: 'farm' },
|
||||
{ title: '养殖户', dataIndex: 'farmer', key: 'farmer' },
|
||||
{ title: '联系电话', dataIndex: 'phone', key: 'phone' },
|
||||
{ title: '设备类型', dataIndex: 'deviceType', key: 'deviceType' },
|
||||
{ title: '设备编号', dataIndex: 'deviceNumber', key: 'deviceNumber' },
|
||||
{ title: '预警类型', dataIndex: 'alertType', key: 'alertType' },
|
||||
{ title: '养殖场', dataIndex: 'farmName', key: 'farmName', width: 150 },
|
||||
{ title: '养殖户', dataIndex: 'farmerName', key: 'farmerName', width: 150 },
|
||||
{ title: '联系电话', dataIndex: 'phone', key: 'phone', width: 120 },
|
||||
{ title: '设备类型', dataIndex: 'deviceType', key: 'deviceType', width: 100 },
|
||||
{ title: '设备编号', dataIndex: 'deviceNumber', key: 'deviceNumber', width: 120 },
|
||||
{ title: '预警类型', dataIndex: 'alertType', key: 'alertType', width: 100 },
|
||||
];
|
||||
|
||||
const tableData = ref([
|
||||
{ id: '1', farm: '扎旗大数据中心', farmer: '扎旗大数据中心', phone: '132****9345', deviceType: '智能耳标', deviceNumber: '2407100002', alertType: '设备离线' },
|
||||
{ id: '2', farm: '扎旗大数据中心', farmer: '扎旗大数据中心', phone: '132****9345', deviceType: '智能耳标', deviceNumber: '2407100001', alertType: '设备离线' },
|
||||
{ id: '3', farm: '扎旗大数据中心', farmer: '扎旗大数据中心', phone: '132****9345', deviceType: '智能耳标', deviceNumber: '2407402678', alertType: '设备离线' },
|
||||
{ id: '4', farm: '扎旗大数据中心', farmer: '扎旗大数据中心', phone: '132****9345', deviceType: '智能耳标', deviceNumber: '2407402675', alertType: '设备离线' },
|
||||
{ id: '5', farm: '扎旗大数据中心', farmer: '扎旗大数据中心', phone: '132****9345', deviceType: '智能耳标', deviceNumber: '2407402674', alertType: '设备离线' },
|
||||
{ id: '6', farm: '139****8321_养殖场', farmer: '杜云鹏', phone: '139****8321', deviceType: '智能耳标', deviceNumber: '2404412397', alertType: '设备离线' },
|
||||
{ id: '7', farm: '139****8321_养殖场', farmer: '杜云鹏', phone: '139****8321', deviceType: '智能耳标', deviceNumber: '2404412404', alertType: '设备离线' },
|
||||
]);
|
||||
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: tableData.value.length,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total, range) => `共${total}条`
|
||||
});
|
||||
|
||||
// 根据当前标签页过滤数据
|
||||
const filteredTableData = computed(() => {
|
||||
let filtered = tableData.value;
|
||||
|
||||
// 根据设备类型过滤
|
||||
if (activeTab.value === 'earTag') {
|
||||
filtered = filtered.filter(item => item.deviceType === '智能耳标');
|
||||
} else if (activeTab.value === 'neckband') {
|
||||
filtered = filtered.filter(item => item.deviceType === '智能项圈');
|
||||
} else if (activeTab.value === 'host') {
|
||||
filtered = filtered.filter(item => item.deviceType === '智能主机');
|
||||
}
|
||||
|
||||
// 根据搜索关键词过滤
|
||||
if (searchKeyword.value) {
|
||||
filtered = filtered.filter(item =>
|
||||
item.farmerName.includes(searchKeyword.value) ||
|
||||
item.farmName.includes(searchKeyword.value)
|
||||
);
|
||||
}
|
||||
|
||||
pagination.total = filtered.length;
|
||||
return filtered;
|
||||
});
|
||||
|
||||
// 获取预警类型颜色
|
||||
const getAlertTypeColor = (alertType) => {
|
||||
const colorMap = {
|
||||
'设备离线': 'red',
|
||||
'电量不足': 'orange',
|
||||
'信号异常': 'yellow',
|
||||
'温度异常': 'purple',
|
||||
'其他': 'default'
|
||||
};
|
||||
return colorMap[alertType] || 'default';
|
||||
};
|
||||
|
||||
// 获取设备预警数据
|
||||
const fetchDeviceWarnings = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const params = {
|
||||
page: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
deviceType: activeTab.value === 'earTag' ? '智能耳标' :
|
||||
activeTab.value === 'neckband' ? '智能项圈' :
|
||||
activeTab.value === 'host' ? '智能主机' : undefined,
|
||||
farmerName: searchKeyword.value || undefined
|
||||
};
|
||||
|
||||
const response = await deviceWarningApi.getDeviceWarnings(params);
|
||||
if (response.code === 200) {
|
||||
tableData.value = response.data.list;
|
||||
pagination.total = response.data.total;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取设备预警数据失败:', error);
|
||||
message.error('获取设备预警数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取预警统计
|
||||
const fetchWarningStats = async () => {
|
||||
try {
|
||||
const response = await deviceWarningApi.getWarningStats();
|
||||
if (response.code === 200) {
|
||||
warningStats.value = response.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取预警统计失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 标签页切换
|
||||
const handleTabChange = (key) => {
|
||||
activeTab.value = key;
|
||||
pagination.current = 1;
|
||||
fetchDeviceWarnings();
|
||||
};
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
pagination.current = 1;
|
||||
fetchDeviceWarnings();
|
||||
};
|
||||
|
||||
// 表格变化
|
||||
const handleTableChange = (pag) => {
|
||||
pagination.current = pag.current;
|
||||
pagination.pageSize = pag.pageSize;
|
||||
fetchDeviceWarnings();
|
||||
};
|
||||
|
||||
// 组件挂载
|
||||
onMounted(() => {
|
||||
fetchDeviceWarnings();
|
||||
fetchWarningStats();
|
||||
});
|
||||
|
||||
</script>
|
||||
@@ -80,6 +204,7 @@ const pagination = reactive({
|
||||
.page-container {
|
||||
background-color: #f0f2f5;
|
||||
padding: 24px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -89,6 +214,7 @@ const pagination = reactive({
|
||||
.title {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #262626;
|
||||
}
|
||||
|
||||
.stats-container {
|
||||
@@ -99,22 +225,36 @@ const pagination = reactive({
|
||||
|
||||
.stat-card {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
padding: 24px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
border: 1px solid #f0f0f0;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.stat-card:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 28px;
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
color: #1890ff;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
font-size: 16px;
|
||||
color: #595959;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.main-card {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.table-header {
|
||||
@@ -122,6 +262,84 @@ const pagination = reactive({
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.search-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
:deep(.ant-tabs-tab) {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
padding: 12px 24px;
|
||||
}
|
||||
|
||||
:deep(.ant-tabs-tab-active) {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
:deep(.ant-tabs-ink-bar) {
|
||||
background-color: #1890ff;
|
||||
}
|
||||
|
||||
:deep(.ant-table-thead > tr > th) {
|
||||
background-color: #fafafa;
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
}
|
||||
|
||||
:deep(.ant-table-tbody > tr > td) {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
:deep(.ant-table-tbody > tr:hover > td) {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
:deep(.ant-pagination) {
|
||||
margin-top: 16px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
:deep(.ant-pagination-total-text) {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
:deep(.ant-input-affix-wrapper) {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
:deep(.ant-input-affix-wrapper:focus) {
|
||||
border-color: #1890ff;
|
||||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
||||
}
|
||||
|
||||
:deep(.ant-btn-primary) {
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
:deep(.ant-tag) {
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
|
||||
.icon-sousuo {
|
||||
cursor: pointer;
|
||||
color: #999;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.icon-sousuo:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.important-messages {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,626 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>生资认证管理</h1>
|
||||
|
||||
<!-- 搜索和操作栏 -->
|
||||
<a-card style="margin-bottom: 16px;">
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 16px; align-items: center;">
|
||||
<a-input v-model:value="searchKeyword" placeholder="输入生产资料名称或生产厂商" style="width: 250px;">
|
||||
<template #prefix>
|
||||
<span class="iconfont icon-sousuo"></span>
|
||||
</template>
|
||||
</a-input>
|
||||
|
||||
<a-select v-model:value="materialTypeFilter" placeholder="生产资料类型" style="width: 150px;">
|
||||
<a-select-option value="">全部</a-select-option>
|
||||
<a-select-option value="疫苗">疫苗</a-select-option>
|
||||
<a-select-option value="饲料">饲料</a-select-option>
|
||||
<a-select-option value="兽药">兽药</a-select-option>
|
||||
<a-select-option value="器械">器械</a-select-option>
|
||||
<a-select-option value="其他">其他</a-select-option>
|
||||
</a-select>
|
||||
|
||||
<a-select v-model:value="certificationTypeFilter" placeholder="认证类型" style="width: 150px;">
|
||||
<a-select-option value="">全部</a-select-option>
|
||||
<a-select-option value="兽药GMP认证">兽药GMP认证</a-select-option>
|
||||
<a-select-option value="饲料生产许可证">饲料生产许可证</a-select-option>
|
||||
<a-select-option value="医疗器械注册证">医疗器械注册证</a-select-option>
|
||||
<a-select-option value="其他认证">其他认证</a-select-option>
|
||||
</a-select>
|
||||
|
||||
<a-select v-model:value="statusFilter" placeholder="认证状态" style="width: 120px;">
|
||||
<a-select-option value="">全部</a-select-option>
|
||||
<a-select-option value="valid">有效</a-select-option>
|
||||
<a-select-option value="expired">过期</a-select-option>
|
||||
<a-select-option value="suspended">暂停</a-select-option>
|
||||
<a-select-option value="revoked">撤销</a-select-option>
|
||||
</a-select>
|
||||
|
||||
<a-button type="primary" @click="handleSearch" style="margin-left: auto;">
|
||||
<span class="iconfont icon-sousuo"></span> 搜索
|
||||
</a-button>
|
||||
|
||||
<a-button type="default" @click="handleReset">重置</a-button>
|
||||
|
||||
<a-button type="primary" danger @click="handleAddCertification">
|
||||
<span class="iconfont icon-tianjia"></span> 新增认证
|
||||
</a-button>
|
||||
</div>
|
||||
</a-card>
|
||||
|
||||
<!-- 数据列表 -->
|
||||
<a-card>
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data-source="certificationsData"
|
||||
row-key="id"
|
||||
:pagination="pagination"
|
||||
:loading="loading"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'certificationStatus'">
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<a-switch
|
||||
:checked="record.certificationStatus === 'valid'"
|
||||
size="small"
|
||||
@change="(checked) => handleToggleStatus(record, checked)"
|
||||
/>
|
||||
<span>{{ getStatusText(record.certificationStatus) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<div style="display: flex; gap: 8px;">
|
||||
<a-button size="small" type="primary" @click="handleEdit(record)">编辑</a-button>
|
||||
<a-button size="small" danger @click="handleDelete(record.id)">删除</a-button>
|
||||
<a-button size="small" @click="handleDetail(record)">详情</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
|
||||
<!-- 新增/编辑表单 -->
|
||||
<a-modal
|
||||
v-model:open="isModalOpen"
|
||||
:title="currentCertification.id ? '编辑生资认证' : '新增生资认证'"
|
||||
@ok="handleSave"
|
||||
@cancel="handleCancel"
|
||||
:width="600"
|
||||
:confirm-loading="modalLoading"
|
||||
>
|
||||
<a-form
|
||||
:model="currentCertification"
|
||||
layout="vertical"
|
||||
:rules="formRules"
|
||||
ref="formRef"
|
||||
>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="生产资料名称" name="materialName">
|
||||
<a-input v-model:value="currentCertification.materialName" placeholder="请输入生产资料名称" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="生产资料类型" name="materialType">
|
||||
<a-select v-model:value="currentCertification.materialType" placeholder="请选择生产资料类型">
|
||||
<a-select-option value="疫苗">疫苗</a-select-option>
|
||||
<a-select-option value="饲料">饲料</a-select-option>
|
||||
<a-select-option value="兽药">兽药</a-select-option>
|
||||
<a-select-option value="器械">器械</a-select-option>
|
||||
<a-select-option value="其他">其他</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="生产厂商" name="manufacturer">
|
||||
<a-input v-model:value="currentCertification.manufacturer" placeholder="请输入生产厂商" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="认证编号" name="certificationNumber">
|
||||
<a-input v-model:value="currentCertification.certificationNumber" placeholder="请输入认证编号" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="认证类型" name="certificationType">
|
||||
<a-select v-model:value="currentCertification.certificationType" placeholder="请选择认证类型">
|
||||
<a-select-option value="兽药GMP认证">兽药GMP认证</a-select-option>
|
||||
<a-select-option value="饲料生产许可证">饲料生产许可证</a-select-option>
|
||||
<a-select-option value="医疗器械注册证">医疗器械注册证</a-select-option>
|
||||
<a-select-option value="其他认证">其他认证</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="认证机构" name="certificationAuthority">
|
||||
<a-input v-model:value="currentCertification.certificationAuthority" placeholder="请输入认证机构" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="发证日期" name="issueDate">
|
||||
<a-date-picker v-model:value="currentCertification.issueDate" style="width: 100%" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="有效期至" name="expiryDate">
|
||||
<a-date-picker v-model:value="currentCertification.expiryDate" style="width: 100%" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item label="产品描述" name="description">
|
||||
<a-textarea v-model:value="currentCertification.description" placeholder="请输入产品描述" :rows="3" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="技术规格" name="specifications">
|
||||
<a-textarea v-model:value="currentCertification.specifications" placeholder="请输入技术规格" :rows="2" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="适用范围" name="applicableScope">
|
||||
<a-textarea v-model:value="currentCertification.applicableScope" placeholder="请输入适用范围" :rows="2" />
|
||||
</a-form-item>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="联系人" name="contactPerson">
|
||||
<a-input v-model:value="currentCertification.contactPerson" placeholder="请输入联系人" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="联系电话" name="contactPhone">
|
||||
<a-input v-model:value="currentCertification.contactPhone" placeholder="请输入联系电话" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item label="备注" name="remarks">
|
||||
<a-textarea v-model:value="currentCertification.remarks" placeholder="请输入备注" :rows="2" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
|
||||
<!-- 详情查看 -->
|
||||
<a-modal
|
||||
v-model:open="isDetailModalOpen"
|
||||
title="生资认证详情"
|
||||
:footer="null"
|
||||
:width="600"
|
||||
>
|
||||
<a-descriptions :column="2" bordered>
|
||||
<a-descriptions-item label="生产资料名称">{{ detailData.materialName }}</a-descriptions-item>
|
||||
<a-descriptions-item label="生产资料类型">{{ detailData.materialType }}</a-descriptions-item>
|
||||
<a-descriptions-item label="生产厂商">{{ detailData.manufacturer }}</a-descriptions-item>
|
||||
<a-descriptions-item label="认证编号">{{ detailData.certificationNumber }}</a-descriptions-item>
|
||||
<a-descriptions-item label="认证类型">{{ detailData.certificationType }}</a-descriptions-item>
|
||||
<a-descriptions-item label="认证机构">{{ detailData.certificationAuthority }}</a-descriptions-item>
|
||||
<a-descriptions-item label="发证日期">{{ detailData.issueDate }}</a-descriptions-item>
|
||||
<a-descriptions-item label="有效期至">{{ detailData.expiryDate }}</a-descriptions-item>
|
||||
<a-descriptions-item label="认证状态">
|
||||
<a-tag :color="getStatusColor(detailData.certificationStatus)">
|
||||
{{ getStatusText(detailData.certificationStatus) }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="联系人">{{ detailData.contactPerson }}</a-descriptions-item>
|
||||
<a-descriptions-item label="联系电话">{{ detailData.contactPhone }}</a-descriptions-item>
|
||||
<a-descriptions-item label="产品描述" :span="2">{{ detailData.description }}</a-descriptions-item>
|
||||
<a-descriptions-item label="技术规格" :span="2">{{ detailData.specifications }}</a-descriptions-item>
|
||||
<a-descriptions-item label="适用范围" :span="2">{{ detailData.applicableScope }}</a-descriptions-item>
|
||||
<a-descriptions-item label="备注" :span="2">{{ detailData.remarks }}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import productionMaterialCertificationApi from '@/utils/productionMaterialCertificationApi'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
// 搜索条件
|
||||
const searchKeyword = ref('')
|
||||
const materialTypeFilter = ref('')
|
||||
const certificationTypeFilter = ref('')
|
||||
const statusFilter = ref('')
|
||||
|
||||
// 分页配置
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total, range) => `第 ${range[0]}-${range[1]} 条,共 ${total} 条`
|
||||
})
|
||||
|
||||
// 模态框状态
|
||||
const isModalOpen = ref(false)
|
||||
const isDetailModalOpen = ref(false)
|
||||
const modalLoading = ref(false)
|
||||
|
||||
// 表单引用
|
||||
const formRef = ref(null)
|
||||
|
||||
// 当前编辑的认证
|
||||
const currentCertification = reactive({
|
||||
id: '',
|
||||
materialName: '',
|
||||
materialType: '',
|
||||
manufacturer: '',
|
||||
certificationNumber: '',
|
||||
certificationType: '',
|
||||
certificationAuthority: '',
|
||||
issueDate: null,
|
||||
expiryDate: null,
|
||||
certificationStatus: 'valid',
|
||||
description: '',
|
||||
specifications: '',
|
||||
applicableScope: '',
|
||||
contactPerson: '',
|
||||
contactPhone: '',
|
||||
remarks: ''
|
||||
})
|
||||
|
||||
// 详情数据
|
||||
const detailData = reactive({})
|
||||
|
||||
// 表单验证规则
|
||||
const formRules = {
|
||||
materialName: [
|
||||
{ required: true, message: '请输入生产资料名称', trigger: 'blur' }
|
||||
],
|
||||
materialType: [
|
||||
{ required: true, message: '请选择生产资料类型', trigger: 'change' }
|
||||
],
|
||||
manufacturer: [
|
||||
{ required: true, message: '请输入生产厂商', trigger: 'blur' }
|
||||
],
|
||||
certificationNumber: [
|
||||
{ required: true, message: '请输入认证编号', trigger: 'blur' }
|
||||
],
|
||||
certificationType: [
|
||||
{ required: true, message: '请选择认证类型', trigger: 'change' }
|
||||
],
|
||||
certificationAuthority: [
|
||||
{ required: true, message: '请输入认证机构', trigger: 'blur' }
|
||||
],
|
||||
issueDate: [
|
||||
{ required: true, message: '请选择发证日期', trigger: 'change' }
|
||||
],
|
||||
expiryDate: [
|
||||
{ required: true, message: '请选择有效期至', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
|
||||
// 认证列表数据
|
||||
const certificationsData = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
// 表格列定义
|
||||
const columns = [
|
||||
{
|
||||
title: '生产资料名称',
|
||||
dataIndex: 'materialName',
|
||||
key: 'materialName',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '生产资料类型',
|
||||
dataIndex: 'materialType',
|
||||
key: 'materialType',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '生产厂商',
|
||||
dataIndex: 'manufacturer',
|
||||
key: 'manufacturer',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '认证编号',
|
||||
dataIndex: 'certificationNumber',
|
||||
key: 'certificationNumber',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '认证类型',
|
||||
dataIndex: 'certificationType',
|
||||
key: 'certificationType',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '认证机构',
|
||||
dataIndex: 'certificationAuthority',
|
||||
key: 'certificationAuthority',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '发证日期',
|
||||
dataIndex: 'issueDate',
|
||||
key: 'issueDate',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '有效期至',
|
||||
dataIndex: 'expiryDate',
|
||||
key: 'expiryDate',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '认证状态',
|
||||
dataIndex: 'certificationStatus',
|
||||
key: 'certificationStatus',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
dataIndex: 'updatedAt',
|
||||
key: 'updatedAt',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 150,
|
||||
fixed: 'right'
|
||||
}
|
||||
]
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status) => {
|
||||
const statusMap = {
|
||||
'valid': '有效',
|
||||
'expired': '过期',
|
||||
'suspended': '暂停',
|
||||
'revoked': '撤销'
|
||||
}
|
||||
return statusMap[status] || status
|
||||
}
|
||||
|
||||
// 获取状态颜色
|
||||
const getStatusColor = (status) => {
|
||||
const colorMap = {
|
||||
'valid': 'green',
|
||||
'expired': 'red',
|
||||
'suspended': 'orange',
|
||||
'revoked': 'red'
|
||||
}
|
||||
return colorMap[status] || 'default'
|
||||
}
|
||||
|
||||
// 获取认证列表
|
||||
const fetchCertifications = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
const params = {
|
||||
page: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
materialName: searchKeyword.value,
|
||||
materialType: materialTypeFilter.value,
|
||||
certificationType: certificationTypeFilter.value,
|
||||
certificationStatus: statusFilter.value
|
||||
}
|
||||
|
||||
const response = await productionMaterialCertificationApi.getCertifications(params)
|
||||
if (response.code === 200) {
|
||||
certificationsData.value = response.data.list
|
||||
pagination.total = response.data.total
|
||||
} else {
|
||||
message.error(response.message || '获取数据失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取认证列表失败:', error)
|
||||
message.error('获取数据失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
pagination.current = 1
|
||||
fetchCertifications()
|
||||
}
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
searchKeyword.value = ''
|
||||
materialTypeFilter.value = ''
|
||||
certificationTypeFilter.value = ''
|
||||
statusFilter.value = ''
|
||||
pagination.current = 1
|
||||
fetchCertifications()
|
||||
}
|
||||
|
||||
// 表格变化
|
||||
const handleTableChange = (pag) => {
|
||||
pagination.current = pag.current
|
||||
pagination.pageSize = pag.pageSize
|
||||
fetchCertifications()
|
||||
}
|
||||
|
||||
// 新增认证
|
||||
const handleAddCertification = () => {
|
||||
Object.assign(currentCertification, {
|
||||
id: '',
|
||||
materialName: '',
|
||||
materialType: '',
|
||||
manufacturer: '',
|
||||
certificationNumber: '',
|
||||
certificationType: '',
|
||||
certificationAuthority: '',
|
||||
issueDate: null,
|
||||
expiryDate: null,
|
||||
certificationStatus: 'valid',
|
||||
description: '',
|
||||
specifications: '',
|
||||
applicableScope: '',
|
||||
contactPerson: '',
|
||||
contactPhone: '',
|
||||
remarks: ''
|
||||
})
|
||||
isModalOpen.value = true
|
||||
}
|
||||
|
||||
// 编辑认证
|
||||
const handleEdit = (record) => {
|
||||
Object.assign(currentCertification, {
|
||||
...record,
|
||||
issueDate: record.issueDate ? dayjs(record.issueDate) : null,
|
||||
expiryDate: record.expiryDate ? dayjs(record.expiryDate) : null
|
||||
})
|
||||
isModalOpen.value = true
|
||||
}
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = (record) => {
|
||||
Object.assign(detailData, record)
|
||||
isDetailModalOpen.value = true
|
||||
}
|
||||
|
||||
// 删除认证
|
||||
const handleDelete = async (id) => {
|
||||
try {
|
||||
const response = await productionMaterialCertificationApi.deleteCertification(id)
|
||||
if (response.code === 200) {
|
||||
message.success('删除成功')
|
||||
fetchCertifications()
|
||||
} else {
|
||||
message.error(response.message || '删除失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除认证失败:', error)
|
||||
message.error('删除失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 切换状态
|
||||
const handleToggleStatus = async (record, checked) => {
|
||||
try {
|
||||
const status = checked ? 'valid' : 'suspended'
|
||||
const response = await productionMaterialCertificationApi.toggleCertificationStatus(record.id, status)
|
||||
if (response.code === 200) {
|
||||
message.success('状态更新成功')
|
||||
fetchCertifications()
|
||||
} else {
|
||||
message.error(response.message || '状态更新失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('切换状态失败:', error)
|
||||
message.error('状态更新失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 保存认证
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
await formRef.value.validate()
|
||||
modalLoading.value = true
|
||||
|
||||
const data = {
|
||||
...currentCertification,
|
||||
issueDate: currentCertification.issueDate ? currentCertification.issueDate.format('YYYY-MM-DD') : null,
|
||||
expiryDate: currentCertification.expiryDate ? currentCertification.expiryDate.format('YYYY-MM-DD') : null
|
||||
}
|
||||
|
||||
let response
|
||||
if (currentCertification.id) {
|
||||
response = await productionMaterialCertificationApi.updateCertification(currentCertification.id, data)
|
||||
} else {
|
||||
response = await productionMaterialCertificationApi.createCertification(data)
|
||||
}
|
||||
|
||||
if (response.code === 200 || response.code === 201) {
|
||||
message.success(currentCertification.id ? '更新成功' : '创建成功')
|
||||
isModalOpen.value = false
|
||||
fetchCertifications()
|
||||
} else {
|
||||
message.error(response.message || '保存失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存认证失败:', error)
|
||||
message.error('保存失败')
|
||||
} finally {
|
||||
modalLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
isModalOpen.value = false
|
||||
}
|
||||
|
||||
// 组件挂载时获取数据
|
||||
onMounted(() => {
|
||||
fetchCertifications()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.ant-modal-content) {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
:deep(.ant-modal-header) {
|
||||
border-radius: 8px 8px 0 0;
|
||||
padding: 16px 24px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
:deep(.ant-modal-body) {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
:deep(.ant-form-item-label > label) {
|
||||
font-weight: 500;
|
||||
color: #262626;
|
||||
}
|
||||
|
||||
:deep(.ant-btn-primary) {
|
||||
background-color: #1890ff;
|
||||
border-color: #1890ff;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
:deep(.ant-btn-primary:hover) {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
}
|
||||
|
||||
:deep(.ant-btn-dangerous) {
|
||||
background-color: #ff4d4f;
|
||||
border-color: #ff4d4f;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
:deep(.ant-btn-dangerous:hover) {
|
||||
background-color: #ff7875;
|
||||
border-color: #ff7875;
|
||||
}
|
||||
|
||||
:deep(.ant-btn) {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
:deep(.ant-input) {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
:deep(.ant-select-selector) {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
:deep(.ant-picker) {
|
||||
border-radius: 6px;
|
||||
}
|
||||
</style>
|
||||
@@ -55,6 +55,11 @@ app.use('/api/harmless', require('./routes/harmless'));
|
||||
app.use('/api/harmless-place', require('./routes/harmlessPlace'));
|
||||
app.use('/api/epidemic-record', require('./routes/epidemicRecord'));
|
||||
app.use('/api/vaccine', require('./routes/vaccine'));
|
||||
app.use('/api/epidemic-activity', require('./routes/epidemicActivity'));
|
||||
app.use('/api/production-material-certification', require('./routes/productionMaterialCertification'));
|
||||
app.use('/api/approval-process', require('./routes/approvalProcess'));
|
||||
app.use('/api/cattle-academy', require('./routes/cattleAcademy'));
|
||||
app.use('/api/device-warning', require('./routes/deviceWarning'));
|
||||
|
||||
// 健康检查
|
||||
app.get('/health', (req, res) => {
|
||||
|
||||
286
government-backend/controllers/approvalProcessController.js
Normal file
286
government-backend/controllers/approvalProcessController.js
Normal file
@@ -0,0 +1,286 @@
|
||||
const ApprovalProcess = require('../models/ApprovalProcess');
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
// 获取审批流程列表
|
||||
const getApprovalProcesses = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
page = 1,
|
||||
pageSize = 9,
|
||||
status,
|
||||
applicant,
|
||||
type
|
||||
} = req.query;
|
||||
|
||||
const offset = (page - 1) * pageSize;
|
||||
const where = {};
|
||||
|
||||
// 构建查询条件
|
||||
if (status) {
|
||||
where.status = status;
|
||||
}
|
||||
if (applicant) {
|
||||
where.applicant = {
|
||||
[Op.like]: `%${applicant}%`
|
||||
};
|
||||
}
|
||||
if (type) {
|
||||
where.type = type;
|
||||
}
|
||||
|
||||
const { count, rows } = await ApprovalProcess.findAndCountAll({
|
||||
where,
|
||||
limit: parseInt(pageSize),
|
||||
offset: parseInt(offset),
|
||||
order: [['createdAt', 'DESC']]
|
||||
});
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: {
|
||||
list: rows,
|
||||
total: count,
|
||||
page: parseInt(page),
|
||||
pageSize: parseInt(pageSize)
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取审批流程列表失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 根据ID获取审批流程详情
|
||||
const getApprovalProcessById = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const approvalProcess = await ApprovalProcess.findByPk(id);
|
||||
|
||||
if (!approvalProcess) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '审批流程不存在'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: approvalProcess
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取审批流程详情失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 创建审批流程
|
||||
const createApprovalProcess = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
title,
|
||||
type,
|
||||
applicant,
|
||||
phone,
|
||||
farmName,
|
||||
quantity,
|
||||
description,
|
||||
files,
|
||||
remarks
|
||||
} = req.body;
|
||||
|
||||
const approvalProcess = await ApprovalProcess.create({
|
||||
title,
|
||||
type,
|
||||
applicant,
|
||||
phone,
|
||||
farmName,
|
||||
quantity,
|
||||
description,
|
||||
files,
|
||||
remarks,
|
||||
status: 'pending'
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
code: 201,
|
||||
message: '创建成功',
|
||||
data: approvalProcess
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('创建审批流程失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 更新审批流程
|
||||
const updateApprovalProcess = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const {
|
||||
title,
|
||||
type,
|
||||
applicant,
|
||||
phone,
|
||||
farmName,
|
||||
quantity,
|
||||
description,
|
||||
files,
|
||||
remarks
|
||||
} = req.body;
|
||||
|
||||
const approvalProcess = await ApprovalProcess.findByPk(id);
|
||||
if (!approvalProcess) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '审批流程不存在'
|
||||
});
|
||||
}
|
||||
|
||||
await approvalProcess.update({
|
||||
title,
|
||||
type,
|
||||
applicant,
|
||||
phone,
|
||||
farmName,
|
||||
quantity,
|
||||
description,
|
||||
files,
|
||||
remarks
|
||||
});
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '更新成功',
|
||||
data: approvalProcess
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新审批流程失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 删除审批流程
|
||||
const deleteApprovalProcess = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const approvalProcess = await ApprovalProcess.findByPk(id);
|
||||
|
||||
if (!approvalProcess) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '审批流程不存在'
|
||||
});
|
||||
}
|
||||
|
||||
await approvalProcess.destroy();
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '删除成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('删除审批流程失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 审批操作(通过/拒绝)
|
||||
const processApproval = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { action, approvalComment, approver } = req.body;
|
||||
|
||||
const approvalProcess = await ApprovalProcess.findByPk(id);
|
||||
if (!approvalProcess) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '审批流程不存在'
|
||||
});
|
||||
}
|
||||
|
||||
const status = action === 'approve' ? 'approved' : 'rejected';
|
||||
|
||||
await approvalProcess.update({
|
||||
status,
|
||||
approvalComment,
|
||||
approver,
|
||||
approvalTime: new Date()
|
||||
});
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: action === 'approve' ? '审批通过' : '审批拒绝',
|
||||
data: approvalProcess
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('审批操作失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 更新审批状态
|
||||
const updateApprovalStatus = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { status } = req.body;
|
||||
|
||||
const approvalProcess = await ApprovalProcess.findByPk(id);
|
||||
if (!approvalProcess) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '审批流程不存在'
|
||||
});
|
||||
}
|
||||
|
||||
await approvalProcess.update({ status });
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '状态更新成功',
|
||||
data: approvalProcess
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新审批状态失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getApprovalProcesses,
|
||||
getApprovalProcessById,
|
||||
createApprovalProcess,
|
||||
updateApprovalProcess,
|
||||
deleteApprovalProcess,
|
||||
processApproval,
|
||||
updateApprovalStatus
|
||||
};
|
||||
298
government-backend/controllers/cattleAcademyController.js
Normal file
298
government-backend/controllers/cattleAcademyController.js
Normal file
@@ -0,0 +1,298 @@
|
||||
const CattleAcademy = require('../models/CattleAcademy');
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
// 获取养牛学院资讯列表
|
||||
const getCattleAcademyList = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
page = 1,
|
||||
pageSize = 10,
|
||||
title,
|
||||
category,
|
||||
status,
|
||||
author
|
||||
} = req.query;
|
||||
|
||||
const offset = (page - 1) * pageSize;
|
||||
const where = {};
|
||||
|
||||
// 构建查询条件
|
||||
if (title) {
|
||||
where.title = {
|
||||
[Op.like]: `%${title}%`
|
||||
};
|
||||
}
|
||||
if (category) {
|
||||
where.category = category;
|
||||
}
|
||||
if (status !== undefined) {
|
||||
where.status = status === 'true' || status === true;
|
||||
}
|
||||
if (author) {
|
||||
where.author = {
|
||||
[Op.like]: `%${author}%`
|
||||
};
|
||||
}
|
||||
|
||||
const { count, rows } = await CattleAcademy.findAndCountAll({
|
||||
where,
|
||||
limit: parseInt(pageSize),
|
||||
offset: parseInt(offset),
|
||||
order: [['sort', 'DESC'], ['createdAt', 'DESC']]
|
||||
});
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: {
|
||||
list: rows,
|
||||
total: count,
|
||||
page: parseInt(page),
|
||||
pageSize: parseInt(pageSize)
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取养牛学院资讯列表失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 根据ID获取养牛学院资讯详情
|
||||
const getCattleAcademyById = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const cattleAcademy = await CattleAcademy.findByPk(id);
|
||||
|
||||
if (!cattleAcademy) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '资讯不存在'
|
||||
});
|
||||
}
|
||||
|
||||
// 增加浏览次数
|
||||
await cattleAcademy.increment('viewCount');
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: cattleAcademy
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取养牛学院资讯详情失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 创建养牛学院资讯
|
||||
const createCattleAcademy = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
title,
|
||||
coverImage,
|
||||
content,
|
||||
summary,
|
||||
category,
|
||||
tags,
|
||||
sort = 0,
|
||||
status = true,
|
||||
author,
|
||||
publishTime,
|
||||
isTop = false,
|
||||
isRecommend = false,
|
||||
remarks
|
||||
} = req.body;
|
||||
|
||||
const cattleAcademy = await CattleAcademy.create({
|
||||
title,
|
||||
coverImage,
|
||||
content,
|
||||
summary,
|
||||
category,
|
||||
tags,
|
||||
sort,
|
||||
status,
|
||||
author,
|
||||
publishTime: publishTime || new Date(),
|
||||
isTop,
|
||||
isRecommend,
|
||||
remarks
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
code: 201,
|
||||
message: '创建成功',
|
||||
data: cattleAcademy
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('创建养牛学院资讯失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 更新养牛学院资讯
|
||||
const updateCattleAcademy = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const {
|
||||
title,
|
||||
coverImage,
|
||||
content,
|
||||
summary,
|
||||
category,
|
||||
tags,
|
||||
sort,
|
||||
status,
|
||||
author,
|
||||
publishTime,
|
||||
isTop,
|
||||
isRecommend,
|
||||
remarks
|
||||
} = req.body;
|
||||
|
||||
const cattleAcademy = await CattleAcademy.findByPk(id);
|
||||
if (!cattleAcademy) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '资讯不存在'
|
||||
});
|
||||
}
|
||||
|
||||
await cattleAcademy.update({
|
||||
title,
|
||||
coverImage,
|
||||
content,
|
||||
summary,
|
||||
category,
|
||||
tags,
|
||||
sort,
|
||||
status,
|
||||
author,
|
||||
publishTime,
|
||||
isTop,
|
||||
isRecommend,
|
||||
remarks
|
||||
});
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '更新成功',
|
||||
data: cattleAcademy
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新养牛学院资讯失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 删除养牛学院资讯
|
||||
const deleteCattleAcademy = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const cattleAcademy = await CattleAcademy.findByPk(id);
|
||||
|
||||
if (!cattleAcademy) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '资讯不存在'
|
||||
});
|
||||
}
|
||||
|
||||
await cattleAcademy.destroy();
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '删除成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('删除养牛学院资讯失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 切换资讯状态
|
||||
const toggleCattleAcademyStatus = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { status } = req.body;
|
||||
|
||||
const cattleAcademy = await CattleAcademy.findByPk(id);
|
||||
if (!cattleAcademy) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '资讯不存在'
|
||||
});
|
||||
}
|
||||
|
||||
await cattleAcademy.update({ status });
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '状态更新成功',
|
||||
data: cattleAcademy
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('切换资讯状态失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 批量更新排序
|
||||
const updateSort = async (req, res) => {
|
||||
try {
|
||||
const { items } = req.body; // [{id, sort}, ...]
|
||||
|
||||
for (const item of items) {
|
||||
await CattleAcademy.update(
|
||||
{ sort: item.sort },
|
||||
{ where: { id: item.id } }
|
||||
);
|
||||
}
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '排序更新成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新排序失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getCattleAcademyList,
|
||||
getCattleAcademyById,
|
||||
createCattleAcademy,
|
||||
updateCattleAcademy,
|
||||
deleteCattleAcademy,
|
||||
toggleCattleAcademyStatus,
|
||||
updateSort
|
||||
};
|
||||
177
government-backend/controllers/deviceWarningController.js
Normal file
177
government-backend/controllers/deviceWarningController.js
Normal file
@@ -0,0 +1,177 @@
|
||||
const DeviceWarning = require('../models/DeviceWarning');
|
||||
const { Op, fn, col } = require('sequelize');
|
||||
const sequelize = require('../config/database');
|
||||
|
||||
// 获取设备预警列表
|
||||
exports.getDeviceWarnings = async (req, res) => {
|
||||
try {
|
||||
const { page = 1, pageSize = 20, deviceType, alertType, status, farmerName } = req.query;
|
||||
const limit = parseInt(pageSize);
|
||||
const offset = (parseInt(page) - 1) * limit;
|
||||
|
||||
const where = {};
|
||||
if (deviceType) {
|
||||
where.deviceType = deviceType;
|
||||
}
|
||||
if (alertType) {
|
||||
where.alertType = alertType;
|
||||
}
|
||||
if (status) {
|
||||
where.status = status;
|
||||
}
|
||||
if (farmerName) {
|
||||
where.farmerName = { [Op.like]: `%${farmerName}%` };
|
||||
}
|
||||
|
||||
const { count, rows } = await DeviceWarning.findAndCountAll({
|
||||
where,
|
||||
limit,
|
||||
offset,
|
||||
order: [['alertTime', 'DESC']],
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: {
|
||||
list: rows,
|
||||
total: count,
|
||||
page: parseInt(page),
|
||||
pageSize: limit,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取设备预警列表失败:', error);
|
||||
res.status(500).json({ code: 500, message: '获取设备预警列表失败', error: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
// 根据ID获取单个设备预警详情
|
||||
exports.getDeviceWarningById = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const warning = await DeviceWarning.findByPk(id);
|
||||
|
||||
if (!warning) {
|
||||
return res.status(404).json({ code: 404, message: '设备预警未找到' });
|
||||
}
|
||||
|
||||
res.status(200).json({ code: 200, message: '获取成功', data: warning });
|
||||
} catch (error) {
|
||||
console.error('获取设备预警详情失败:', error);
|
||||
res.status(500).json({ code: 500, message: '获取设备预警详情失败', error: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
// 创建新的设备预警
|
||||
exports.createDeviceWarning = async (req, res) => {
|
||||
try {
|
||||
const newWarning = await DeviceWarning.create(req.body);
|
||||
res.status(201).json({ code: 201, message: '创建成功', data: newWarning });
|
||||
} catch (error) {
|
||||
console.error('创建设备预警失败:', error);
|
||||
res.status(500).json({ code: 500, message: '创建设备预警失败', error: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
// 更新设备预警
|
||||
exports.updateDeviceWarning = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const [updatedRows] = await DeviceWarning.update(req.body, {
|
||||
where: { id },
|
||||
});
|
||||
|
||||
if (updatedRows === 0) {
|
||||
return res.status(404).json({ code: 404, message: '设备预警未找到或无更新' });
|
||||
}
|
||||
|
||||
const updatedWarning = await DeviceWarning.findByPk(id);
|
||||
res.status(200).json({ code: 200, message: '更新成功', data: updatedWarning });
|
||||
} catch (error) {
|
||||
console.error('更新设备预警失败:', error);
|
||||
res.status(500).json({ code: 500, message: '更新设备预警失败', error: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
// 删除设备预警
|
||||
exports.deleteDeviceWarning = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const deletedRows = await DeviceWarning.destroy({
|
||||
where: { id },
|
||||
});
|
||||
|
||||
if (deletedRows === 0) {
|
||||
return res.status(404).json({ code: 404, message: '设备预警未找到' });
|
||||
}
|
||||
|
||||
res.status(200).json({ code: 200, message: '删除成功' });
|
||||
} catch (error) {
|
||||
console.error('删除设备预警失败:', error);
|
||||
res.status(500).json({ code: 500, message: '删除设备预警失败', error: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
// 更新预警状态
|
||||
exports.updateWarningStatus = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { status, resolvedBy } = req.body;
|
||||
|
||||
const warning = await DeviceWarning.findByPk(id);
|
||||
if (!warning) {
|
||||
return res.status(404).json({ code: 404, message: '设备预警未找到' });
|
||||
}
|
||||
|
||||
warning.status = status;
|
||||
if (status === 'resolved') {
|
||||
warning.resolvedBy = resolvedBy;
|
||||
warning.resolvedAt = new Date();
|
||||
}
|
||||
await warning.save();
|
||||
|
||||
res.status(200).json({ code: 200, message: '状态更新成功', data: warning });
|
||||
} catch (error) {
|
||||
console.error('更新预警状态失败:', error);
|
||||
res.status(500).json({ code: 500, message: '更新预警状态失败', error: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
// 获取预警统计
|
||||
exports.getWarningStats = async (req, res) => {
|
||||
try {
|
||||
// 分别查询每种设备类型的活跃预警数量
|
||||
const earTagCount = await DeviceWarning.count({
|
||||
where: {
|
||||
deviceType: '智能耳标',
|
||||
status: 'active'
|
||||
}
|
||||
});
|
||||
|
||||
const neckbandCount = await DeviceWarning.count({
|
||||
where: {
|
||||
deviceType: '智能项圈',
|
||||
status: 'active'
|
||||
}
|
||||
});
|
||||
|
||||
const hostCount = await DeviceWarning.count({
|
||||
where: {
|
||||
deviceType: '智能主机',
|
||||
status: 'active'
|
||||
}
|
||||
});
|
||||
|
||||
const result = {
|
||||
earTag: earTagCount,
|
||||
neckband: neckbandCount,
|
||||
host: hostCount
|
||||
};
|
||||
|
||||
res.status(200).json({ code: 200, message: '获取成功', data: result });
|
||||
} catch (error) {
|
||||
console.error('获取预警统计失败:', error);
|
||||
res.status(500).json({ code: 500, message: '获取预警统计失败', error: error.message });
|
||||
}
|
||||
};
|
||||
242
government-backend/controllers/epidemicActivityController.js
Normal file
242
government-backend/controllers/epidemicActivityController.js
Normal file
@@ -0,0 +1,242 @@
|
||||
const EpidemicActivity = require('../models/EpidemicActivity');
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
// 获取防疫活动列表
|
||||
const getEpidemicActivities = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
page = 1,
|
||||
pageSize = 20,
|
||||
activityName,
|
||||
livestockCategory,
|
||||
diseaseCategory,
|
||||
activityStatus
|
||||
} = req.query;
|
||||
|
||||
const offset = (page - 1) * pageSize;
|
||||
const where = {};
|
||||
|
||||
// 构建查询条件
|
||||
if (activityName) {
|
||||
where.activityName = {
|
||||
[Op.like]: `%${activityName}%`
|
||||
};
|
||||
}
|
||||
if (livestockCategory) {
|
||||
where.livestockCategory = livestockCategory;
|
||||
}
|
||||
if (diseaseCategory) {
|
||||
where.diseaseCategory = diseaseCategory;
|
||||
}
|
||||
if (activityStatus) {
|
||||
where.activityStatus = activityStatus;
|
||||
}
|
||||
|
||||
const { count, rows } = await EpidemicActivity.findAndCountAll({
|
||||
where,
|
||||
limit: parseInt(pageSize),
|
||||
offset: parseInt(offset),
|
||||
order: [['updatedAt', 'DESC']]
|
||||
});
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: {
|
||||
list: rows,
|
||||
total: count,
|
||||
page: parseInt(page),
|
||||
pageSize: parseInt(pageSize)
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取防疫活动列表失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 根据ID获取防疫活动
|
||||
const getEpidemicActivityById = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const activity = await EpidemicActivity.findByPk(id);
|
||||
|
||||
if (!activity) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '防疫活动不存在'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: activity
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取防疫活动详情失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 创建防疫活动
|
||||
const createEpidemicActivity = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
activityName,
|
||||
livestockCategory,
|
||||
diseaseCategory,
|
||||
vaccineUsed,
|
||||
vaccineBatch,
|
||||
preventionDate,
|
||||
activityStatus = 'active'
|
||||
} = req.body;
|
||||
|
||||
const activity = await EpidemicActivity.create({
|
||||
activityName,
|
||||
livestockCategory,
|
||||
diseaseCategory,
|
||||
vaccineUsed,
|
||||
vaccineBatch,
|
||||
preventionDate,
|
||||
activityStatus
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
code: 201,
|
||||
message: '创建成功',
|
||||
data: activity
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('创建防疫活动失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 更新防疫活动
|
||||
const updateEpidemicActivity = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const {
|
||||
activityName,
|
||||
livestockCategory,
|
||||
diseaseCategory,
|
||||
vaccineUsed,
|
||||
vaccineBatch,
|
||||
preventionDate,
|
||||
activityStatus
|
||||
} = req.body;
|
||||
|
||||
const activity = await EpidemicActivity.findByPk(id);
|
||||
if (!activity) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '防疫活动不存在'
|
||||
});
|
||||
}
|
||||
|
||||
await activity.update({
|
||||
activityName,
|
||||
livestockCategory,
|
||||
diseaseCategory,
|
||||
vaccineUsed,
|
||||
vaccineBatch,
|
||||
preventionDate,
|
||||
activityStatus
|
||||
});
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '更新成功',
|
||||
data: activity
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新防疫活动失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 删除防疫活动
|
||||
const deleteEpidemicActivity = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const activity = await EpidemicActivity.findByPk(id);
|
||||
|
||||
if (!activity) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '防疫活动不存在'
|
||||
});
|
||||
}
|
||||
|
||||
await activity.destroy();
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '删除成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('删除防疫活动失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 切换活动状态
|
||||
const toggleActivityStatus = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const activity = await EpidemicActivity.findByPk(id);
|
||||
|
||||
if (!activity) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '防疫活动不存在'
|
||||
});
|
||||
}
|
||||
|
||||
const newStatus = activity.activityStatus === 'active' ? 'inactive' : 'active';
|
||||
await activity.update({ activityStatus: newStatus });
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '状态更新成功',
|
||||
data: activity
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('切换活动状态失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getEpidemicActivities,
|
||||
getEpidemicActivityById,
|
||||
createEpidemicActivity,
|
||||
updateEpidemicActivity,
|
||||
deleteEpidemicActivity,
|
||||
toggleActivityStatus
|
||||
};
|
||||
@@ -0,0 +1,280 @@
|
||||
const ProductionMaterialCertification = require('../models/ProductionMaterialCertification');
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
// 获取生资认证列表
|
||||
const getProductionMaterialCertifications = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
page = 1,
|
||||
pageSize = 20,
|
||||
materialName,
|
||||
materialType,
|
||||
manufacturer,
|
||||
certificationType,
|
||||
certificationStatus
|
||||
} = req.query;
|
||||
|
||||
const offset = (page - 1) * pageSize;
|
||||
const where = {};
|
||||
|
||||
// 构建查询条件
|
||||
if (materialName) {
|
||||
where.materialName = {
|
||||
[Op.like]: `%${materialName}%`
|
||||
};
|
||||
}
|
||||
if (materialType) {
|
||||
where.materialType = materialType;
|
||||
}
|
||||
if (manufacturer) {
|
||||
where.manufacturer = {
|
||||
[Op.like]: `%${manufacturer}%`
|
||||
};
|
||||
}
|
||||
if (certificationType) {
|
||||
where.certificationType = certificationType;
|
||||
}
|
||||
if (certificationStatus) {
|
||||
where.certificationStatus = certificationStatus;
|
||||
}
|
||||
|
||||
const { count, rows } = await ProductionMaterialCertification.findAndCountAll({
|
||||
where,
|
||||
limit: parseInt(pageSize),
|
||||
offset: parseInt(offset),
|
||||
order: [['updatedAt', 'DESC']]
|
||||
});
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: {
|
||||
list: rows,
|
||||
total: count,
|
||||
page: parseInt(page),
|
||||
pageSize: parseInt(pageSize)
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取生资认证列表失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 根据ID获取生资认证详情
|
||||
const getProductionMaterialCertificationById = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const certification = await ProductionMaterialCertification.findByPk(id);
|
||||
|
||||
if (!certification) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '生资认证不存在'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: certification
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取生资认证详情失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 创建生资认证
|
||||
const createProductionMaterialCertification = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
materialName,
|
||||
materialType,
|
||||
manufacturer,
|
||||
certificationNumber,
|
||||
certificationType,
|
||||
certificationAuthority,
|
||||
issueDate,
|
||||
expiryDate,
|
||||
certificationStatus = 'valid',
|
||||
description,
|
||||
specifications,
|
||||
applicableScope,
|
||||
contactPerson,
|
||||
contactPhone,
|
||||
remarks
|
||||
} = req.body;
|
||||
|
||||
const certification = await ProductionMaterialCertification.create({
|
||||
materialName,
|
||||
materialType,
|
||||
manufacturer,
|
||||
certificationNumber,
|
||||
certificationType,
|
||||
certificationAuthority,
|
||||
issueDate,
|
||||
expiryDate,
|
||||
certificationStatus,
|
||||
description,
|
||||
specifications,
|
||||
applicableScope,
|
||||
contactPerson,
|
||||
contactPhone,
|
||||
remarks
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
code: 201,
|
||||
message: '创建成功',
|
||||
data: certification
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('创建生资认证失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 更新生资认证
|
||||
const updateProductionMaterialCertification = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const {
|
||||
materialName,
|
||||
materialType,
|
||||
manufacturer,
|
||||
certificationNumber,
|
||||
certificationType,
|
||||
certificationAuthority,
|
||||
issueDate,
|
||||
expiryDate,
|
||||
certificationStatus,
|
||||
description,
|
||||
specifications,
|
||||
applicableScope,
|
||||
contactPerson,
|
||||
contactPhone,
|
||||
remarks
|
||||
} = req.body;
|
||||
|
||||
const certification = await ProductionMaterialCertification.findByPk(id);
|
||||
if (!certification) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '生资认证不存在'
|
||||
});
|
||||
}
|
||||
|
||||
await certification.update({
|
||||
materialName,
|
||||
materialType,
|
||||
manufacturer,
|
||||
certificationNumber,
|
||||
certificationType,
|
||||
certificationAuthority,
|
||||
issueDate,
|
||||
expiryDate,
|
||||
certificationStatus,
|
||||
description,
|
||||
specifications,
|
||||
applicableScope,
|
||||
contactPerson,
|
||||
contactPhone,
|
||||
remarks
|
||||
});
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '更新成功',
|
||||
data: certification
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新生资认证失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 删除生资认证
|
||||
const deleteProductionMaterialCertification = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const certification = await ProductionMaterialCertification.findByPk(id);
|
||||
|
||||
if (!certification) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '生资认证不存在'
|
||||
});
|
||||
}
|
||||
|
||||
await certification.destroy();
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '删除成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('删除生资认证失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 切换认证状态
|
||||
const toggleCertificationStatus = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { status } = req.body;
|
||||
|
||||
const certification = await ProductionMaterialCertification.findByPk(id);
|
||||
if (!certification) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '生资认证不存在'
|
||||
});
|
||||
}
|
||||
|
||||
await certification.update({ certificationStatus: status });
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
message: '状态更新成功',
|
||||
data: certification
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('切换认证状态失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器内部错误',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getProductionMaterialCertifications,
|
||||
getProductionMaterialCertificationById,
|
||||
createProductionMaterialCertification,
|
||||
updateProductionMaterialCertification,
|
||||
deleteProductionMaterialCertification,
|
||||
toggleCertificationStatus
|
||||
};
|
||||
93
government-backend/models/ApprovalProcess.js
Normal file
93
government-backend/models/ApprovalProcess.js
Normal file
@@ -0,0 +1,93 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../config/database');
|
||||
|
||||
const ApprovalProcess = sequelize.define('ApprovalProcess', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true
|
||||
},
|
||||
title: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: false,
|
||||
comment: '审批标题'
|
||||
},
|
||||
type: {
|
||||
type: DataTypes.ENUM('enterprise', 'license', 'project', 'other'),
|
||||
allowNull: false,
|
||||
comment: '审批类型'
|
||||
},
|
||||
applicant: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: false,
|
||||
comment: '申请人'
|
||||
},
|
||||
phone: {
|
||||
type: DataTypes.STRING(20),
|
||||
allowNull: true,
|
||||
comment: '联系电话'
|
||||
},
|
||||
farmName: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: true,
|
||||
comment: '养殖场名称'
|
||||
},
|
||||
quantity: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
comment: '认证数量'
|
||||
},
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: '审批说明'
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.ENUM('pending', 'approved', 'rejected', 'processing'),
|
||||
defaultValue: 'pending',
|
||||
comment: '审批状态'
|
||||
},
|
||||
approvalComment: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: '审批意见'
|
||||
},
|
||||
approver: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: true,
|
||||
comment: '审批人'
|
||||
},
|
||||
approvalTime: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
comment: '审批时间'
|
||||
},
|
||||
files: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: true,
|
||||
comment: '附件文件列表'
|
||||
},
|
||||
remarks: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: '备注'
|
||||
},
|
||||
createdAt: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '创建时间'
|
||||
},
|
||||
updatedAt: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '更新时间'
|
||||
}
|
||||
}, {
|
||||
tableName: 'approval_processes',
|
||||
timestamps: true,
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
paranoid: false
|
||||
});
|
||||
|
||||
module.exports = ApprovalProcess;
|
||||
98
government-backend/models/CattleAcademy.js
Normal file
98
government-backend/models/CattleAcademy.js
Normal file
@@ -0,0 +1,98 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../config/database');
|
||||
|
||||
const CattleAcademy = sequelize.define('CattleAcademy', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true
|
||||
},
|
||||
title: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: false,
|
||||
comment: '标题'
|
||||
},
|
||||
coverImage: {
|
||||
type: DataTypes.STRING(500),
|
||||
allowNull: true,
|
||||
comment: '封面图URL'
|
||||
},
|
||||
content: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: '内容'
|
||||
},
|
||||
summary: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: '摘要'
|
||||
},
|
||||
category: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: true,
|
||||
comment: '分类'
|
||||
},
|
||||
tags: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: true,
|
||||
comment: '标签'
|
||||
},
|
||||
sort: {
|
||||
type: DataTypes.INTEGER,
|
||||
defaultValue: 0,
|
||||
comment: '排序'
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: true,
|
||||
comment: '状态'
|
||||
},
|
||||
viewCount: {
|
||||
type: DataTypes.INTEGER,
|
||||
defaultValue: 0,
|
||||
comment: '浏览次数'
|
||||
},
|
||||
author: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: true,
|
||||
comment: '作者'
|
||||
},
|
||||
publishTime: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
comment: '发布时间'
|
||||
},
|
||||
isTop: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false,
|
||||
comment: '是否置顶'
|
||||
},
|
||||
isRecommend: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false,
|
||||
comment: '是否推荐'
|
||||
},
|
||||
remarks: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: '备注'
|
||||
},
|
||||
createdAt: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '创建时间'
|
||||
},
|
||||
updatedAt: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '更新时间'
|
||||
}
|
||||
}, {
|
||||
tableName: 'cattle_academy',
|
||||
timestamps: true,
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
paranoid: false
|
||||
});
|
||||
|
||||
module.exports = CattleAcademy;
|
||||
107
government-backend/models/DeviceWarning.js
Normal file
107
government-backend/models/DeviceWarning.js
Normal file
@@ -0,0 +1,107 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../config/database');
|
||||
|
||||
const DeviceWarning = sequelize.define('DeviceWarning', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
},
|
||||
farmName: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
comment: '养殖场名称',
|
||||
field: 'farmName'
|
||||
},
|
||||
farmerName: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
comment: '养殖户名称',
|
||||
field: 'farmerName'
|
||||
},
|
||||
phone: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
comment: '联系电话',
|
||||
field: 'phone'
|
||||
},
|
||||
deviceType: {
|
||||
type: DataTypes.ENUM('智能耳标', '智能项圈', '智能主机'),
|
||||
allowNull: false,
|
||||
comment: '设备类型',
|
||||
field: 'deviceType'
|
||||
},
|
||||
deviceNumber: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
comment: '设备编号',
|
||||
field: 'deviceNumber'
|
||||
},
|
||||
alertType: {
|
||||
type: DataTypes.ENUM('设备离线', '电量不足', '信号异常', '温度异常', '其他'),
|
||||
allowNull: false,
|
||||
comment: '预警类型',
|
||||
field: 'alertType'
|
||||
},
|
||||
alertLevel: {
|
||||
type: DataTypes.ENUM('high', 'medium', 'low'),
|
||||
allowNull: false,
|
||||
defaultValue: 'medium',
|
||||
comment: '预警级别 (高, 中, 低)',
|
||||
field: 'alertLevel'
|
||||
},
|
||||
alertTime: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '预警时间',
|
||||
field: 'alertTime'
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.ENUM('active', 'resolved', 'ignored'),
|
||||
allowNull: false,
|
||||
defaultValue: 'active',
|
||||
comment: '预警状态 (活跃, 已解决, 已忽略)',
|
||||
field: 'status'
|
||||
},
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
comment: '预警描述',
|
||||
},
|
||||
location: {
|
||||
type: DataTypes.STRING,
|
||||
comment: '设备位置',
|
||||
},
|
||||
batteryLevel: {
|
||||
type: DataTypes.INTEGER,
|
||||
comment: '电池电量百分比',
|
||||
},
|
||||
signalStrength: {
|
||||
type: DataTypes.INTEGER,
|
||||
comment: '信号强度',
|
||||
},
|
||||
temperature: {
|
||||
type: DataTypes.FLOAT,
|
||||
comment: '温度值',
|
||||
},
|
||||
resolvedBy: {
|
||||
type: DataTypes.STRING,
|
||||
comment: '解决人',
|
||||
},
|
||||
resolvedAt: {
|
||||
type: DataTypes.DATE,
|
||||
comment: '解决时间',
|
||||
},
|
||||
remarks: {
|
||||
type: DataTypes.TEXT,
|
||||
comment: '备注',
|
||||
},
|
||||
}, {
|
||||
tableName: 'device_warnings',
|
||||
timestamps: true,
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
paranoid: false,
|
||||
});
|
||||
|
||||
module.exports = DeviceWarning;
|
||||
63
government-backend/models/EpidemicActivity.js
Normal file
63
government-backend/models/EpidemicActivity.js
Normal file
@@ -0,0 +1,63 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../config/database');
|
||||
|
||||
const EpidemicActivity = sequelize.define('EpidemicActivity', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true
|
||||
},
|
||||
activityName: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: false,
|
||||
comment: '活动名称'
|
||||
},
|
||||
livestockCategory: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: true,
|
||||
comment: '防疫畜别'
|
||||
},
|
||||
diseaseCategory: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: true,
|
||||
comment: '疫病类别'
|
||||
},
|
||||
vaccineUsed: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: true,
|
||||
comment: '使用疫苗'
|
||||
},
|
||||
vaccineBatch: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: true,
|
||||
comment: '疫苗批次'
|
||||
},
|
||||
preventionDate: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: true,
|
||||
comment: '防疫日期'
|
||||
},
|
||||
activityStatus: {
|
||||
type: DataTypes.ENUM('active', 'inactive'),
|
||||
defaultValue: 'active',
|
||||
comment: '活动状态'
|
||||
},
|
||||
updatedAt: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '更新时间'
|
||||
},
|
||||
createdAt: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '创建时间'
|
||||
}
|
||||
}, {
|
||||
tableName: 'epidemic_activities',
|
||||
timestamps: true,
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
paranoid: false
|
||||
});
|
||||
|
||||
module.exports = EpidemicActivity;
|
||||
103
government-backend/models/ProductionMaterialCertification.js
Normal file
103
government-backend/models/ProductionMaterialCertification.js
Normal file
@@ -0,0 +1,103 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../config/database');
|
||||
|
||||
const ProductionMaterialCertification = sequelize.define('ProductionMaterialCertification', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true
|
||||
},
|
||||
materialName: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: false,
|
||||
comment: '生产资料名称'
|
||||
},
|
||||
materialType: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: false,
|
||||
comment: '生产资料类型'
|
||||
},
|
||||
manufacturer: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: false,
|
||||
comment: '生产厂商'
|
||||
},
|
||||
certificationNumber: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: false,
|
||||
comment: '认证编号'
|
||||
},
|
||||
certificationType: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: false,
|
||||
comment: '认证类型'
|
||||
},
|
||||
certificationAuthority: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: false,
|
||||
comment: '认证机构'
|
||||
},
|
||||
issueDate: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
comment: '发证日期'
|
||||
},
|
||||
expiryDate: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
comment: '有效期至'
|
||||
},
|
||||
certificationStatus: {
|
||||
type: DataTypes.ENUM('valid', 'expired', 'suspended', 'revoked'),
|
||||
defaultValue: 'valid',
|
||||
comment: '认证状态'
|
||||
},
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: '产品描述'
|
||||
},
|
||||
specifications: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: '技术规格'
|
||||
},
|
||||
applicableScope: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: '适用范围'
|
||||
},
|
||||
contactPerson: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: true,
|
||||
comment: '联系人'
|
||||
},
|
||||
contactPhone: {
|
||||
type: DataTypes.STRING(20),
|
||||
allowNull: true,
|
||||
comment: '联系电话'
|
||||
},
|
||||
remarks: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: '备注'
|
||||
},
|
||||
createdAt: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '创建时间'
|
||||
},
|
||||
updatedAt: {
|
||||
type: DataTypes.DATE,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '更新时间'
|
||||
}
|
||||
}, {
|
||||
tableName: 'production_material_certifications',
|
||||
timestamps: true,
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
paranoid: false
|
||||
});
|
||||
|
||||
module.exports = ProductionMaterialCertification;
|
||||
18
government-backend/routes/approvalProcess.js
Normal file
18
government-backend/routes/approvalProcess.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const approvalProcessController = require('../controllers/approvalProcessController');
|
||||
const authMiddleware = require('../middleware/auth');
|
||||
|
||||
// 暂时注释掉认证中间件用于测试
|
||||
// router.use(authMiddleware);
|
||||
|
||||
// 审批流程管理路由
|
||||
router.get('/', approvalProcessController.getApprovalProcesses);
|
||||
router.get('/:id', approvalProcessController.getApprovalProcessById);
|
||||
router.post('/', approvalProcessController.createApprovalProcess);
|
||||
router.put('/:id', approvalProcessController.updateApprovalProcess);
|
||||
router.delete('/:id', approvalProcessController.deleteApprovalProcess);
|
||||
router.post('/:id/process', approvalProcessController.processApproval);
|
||||
router.patch('/:id/status', approvalProcessController.updateApprovalStatus);
|
||||
|
||||
module.exports = router;
|
||||
18
government-backend/routes/cattleAcademy.js
Normal file
18
government-backend/routes/cattleAcademy.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const cattleAcademyController = require('../controllers/cattleAcademyController');
|
||||
const authMiddleware = require('../middleware/auth');
|
||||
|
||||
// 暂时注释掉认证中间件用于测试
|
||||
// router.use(authMiddleware);
|
||||
|
||||
// 养牛学院资讯管理路由
|
||||
router.get('/', cattleAcademyController.getCattleAcademyList);
|
||||
router.get('/:id', cattleAcademyController.getCattleAcademyById);
|
||||
router.post('/', cattleAcademyController.createCattleAcademy);
|
||||
router.put('/:id', cattleAcademyController.updateCattleAcademy);
|
||||
router.delete('/:id', cattleAcademyController.deleteCattleAcademy);
|
||||
router.patch('/:id/status', cattleAcademyController.toggleCattleAcademyStatus);
|
||||
router.patch('/sort', cattleAcademyController.updateSort);
|
||||
|
||||
module.exports = router;
|
||||
17
government-backend/routes/deviceWarning.js
Normal file
17
government-backend/routes/deviceWarning.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const deviceWarningController = require('../controllers/deviceWarningController');
|
||||
// const authMiddleware = require('../middleware/auth'); // 假设有认证中间件
|
||||
|
||||
// router.use(authMiddleware); // 暂时注释掉认证中间件用于测试
|
||||
|
||||
// 设备预警管理路由
|
||||
router.get('/', deviceWarningController.getDeviceWarnings);
|
||||
router.get('/stats', deviceWarningController.getWarningStats);
|
||||
router.get('/:id', deviceWarningController.getDeviceWarningById);
|
||||
router.post('/', deviceWarningController.createDeviceWarning);
|
||||
router.put('/:id', deviceWarningController.updateDeviceWarning);
|
||||
router.delete('/:id', deviceWarningController.deleteDeviceWarning);
|
||||
router.patch('/:id/status', deviceWarningController.updateWarningStatus);
|
||||
|
||||
module.exports = router;
|
||||
17
government-backend/routes/epidemicActivity.js
Normal file
17
government-backend/routes/epidemicActivity.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const epidemicActivityController = require('../controllers/epidemicActivityController');
|
||||
const authMiddleware = require('../middleware/auth');
|
||||
|
||||
// 暂时注释掉认证中间件用于测试
|
||||
// router.use(authMiddleware);
|
||||
|
||||
// 防疫活动管理路由
|
||||
router.get('/', epidemicActivityController.getEpidemicActivities);
|
||||
router.get('/:id', epidemicActivityController.getEpidemicActivityById);
|
||||
router.post('/', epidemicActivityController.createEpidemicActivity);
|
||||
router.put('/:id', epidemicActivityController.updateEpidemicActivity);
|
||||
router.delete('/:id', epidemicActivityController.deleteEpidemicActivity);
|
||||
router.patch('/:id/status', epidemicActivityController.toggleActivityStatus);
|
||||
|
||||
module.exports = router;
|
||||
17
government-backend/routes/productionMaterialCertification.js
Normal file
17
government-backend/routes/productionMaterialCertification.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const productionMaterialCertificationController = require('../controllers/productionMaterialCertificationController');
|
||||
const authMiddleware = require('../middleware/auth');
|
||||
|
||||
// 暂时注释掉认证中间件用于测试
|
||||
// router.use(authMiddleware);
|
||||
|
||||
// 生资认证管理路由
|
||||
router.get('/', productionMaterialCertificationController.getProductionMaterialCertifications);
|
||||
router.get('/:id', productionMaterialCertificationController.getProductionMaterialCertificationById);
|
||||
router.post('/', productionMaterialCertificationController.createProductionMaterialCertification);
|
||||
router.put('/:id', productionMaterialCertificationController.updateProductionMaterialCertification);
|
||||
router.delete('/:id', productionMaterialCertificationController.deleteProductionMaterialCertification);
|
||||
router.patch('/:id/status', productionMaterialCertificationController.toggleCertificationStatus);
|
||||
|
||||
module.exports = router;
|
||||
22
government-backend/sql/create_device_warnings_table.sql
Normal file
22
government-backend/sql/create_device_warnings_table.sql
Normal file
@@ -0,0 +1,22 @@
|
||||
CREATE TABLE IF NOT EXISTS `device_warnings` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`farmName` VARCHAR(255) NOT NULL COMMENT '养殖场名称',
|
||||
`farmerName` VARCHAR(255) NOT NULL COMMENT '养殖户名称',
|
||||
`phone` VARCHAR(255) NOT NULL COMMENT '联系电话',
|
||||
`deviceType` ENUM('智能耳标', '智能项圈', '智能主机') NOT NULL COMMENT '设备类型',
|
||||
`deviceNumber` VARCHAR(255) NOT NULL COMMENT '设备编号',
|
||||
`alertType` ENUM('设备离线', '电量不足', '信号异常', '温度异常', '其他') NOT NULL COMMENT '预警类型',
|
||||
`alertLevel` ENUM('high', 'medium', 'low') DEFAULT 'medium' NOT NULL COMMENT '预警级别 (高, 中, 低)',
|
||||
`alertTime` DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL COMMENT '预警时间',
|
||||
`status` ENUM('active', 'resolved', 'ignored') DEFAULT 'active' NOT NULL COMMENT '预警状态 (活跃, 已解决, 已忽略)',
|
||||
`description` TEXT COMMENT '预警描述',
|
||||
`location` VARCHAR(255) COMMENT '设备位置',
|
||||
`batteryLevel` INT COMMENT '电池电量百分比',
|
||||
`signalStrength` INT COMMENT '信号强度',
|
||||
`temperature` FLOAT COMMENT '温度值',
|
||||
`resolvedBy` VARCHAR(255) COMMENT '解决人',
|
||||
`resolvedAt` DATETIME COMMENT '解决时间',
|
||||
`remarks` TEXT COMMENT '备注',
|
||||
`createdAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updatedAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) COMMENT='设备预警管理表';
|
||||
26
government-backend/sql/create_epidemic_activities_table.sql
Normal file
26
government-backend/sql/create_epidemic_activities_table.sql
Normal file
@@ -0,0 +1,26 @@
|
||||
-- 创建防疫活动管理表
|
||||
CREATE TABLE IF NOT EXISTS `epidemic_activities` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`activity_name` varchar(255) NOT NULL COMMENT '活动名称',
|
||||
`livestock_category` varchar(100) DEFAULT NULL COMMENT '防疫畜别',
|
||||
`disease_category` varchar(100) DEFAULT NULL COMMENT '疫病类别',
|
||||
`vaccine_used` varchar(255) DEFAULT NULL COMMENT '使用疫苗',
|
||||
`vaccine_batch` varchar(100) DEFAULT NULL COMMENT '疫苗批次',
|
||||
`prevention_date` varchar(100) DEFAULT NULL COMMENT '防疫日期',
|
||||
`activity_status` enum('active','inactive') DEFAULT 'active' COMMENT '活动状态',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_activity_name` (`activity_name`),
|
||||
KEY `idx_livestock_category` (`livestock_category`),
|
||||
KEY `idx_disease_category` (`disease_category`),
|
||||
KEY `idx_activity_status` (`activity_status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='防疫活动管理表';
|
||||
|
||||
-- 插入测试数据
|
||||
INSERT INTO `epidemic_activities` (`activity_name`, `livestock_category`, `disease_category`, `vaccine_used`, `vaccine_batch`, `prevention_date`, `activity_status`) VALUES
|
||||
('春防', '牛', '口蹄疫', '口蹄疫O型灭活疫苗', '20230401', '2023-04-01至2023-08-01', 'active'),
|
||||
('秋防', '羊', '布鲁氏菌病', '布鲁氏菌病活疫苗', '20230901', '2023-09-01至2023-12-31', 'active'),
|
||||
('猪瘟防疫', '猪', '猪瘟', '猪瘟活疫苗', '20230501', '2023-05-01至2023-05-31', 'inactive'),
|
||||
('禽流感防疫', '鸡', '禽流感', '禽流感H5N1灭活疫苗', '20230601', '2023-06-01至2023-06-30', 'active'),
|
||||
('狂犬病防疫', '犬', '狂犬病', '狂犬病灭活疫苗', '20230701', '2023-07-01至2023-07-31', 'active');
|
||||
12
government-backend/sql/insert_cattle_academy_data.sql
Normal file
12
government-backend/sql/insert_cattle_academy_data.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
-- 插入养牛学院测试数据
|
||||
INSERT INTO cattle_academy (title, cover_image, content, summary, category, tags, sort, status, view_count, author, publish_time, is_top, is_recommend, remarks) VALUES
|
||||
('新疆阿克苏地区电信5G数字乡村项目', 'https://via.placeholder.com/100x50', '新疆阿克苏地区电信5G数字乡村项目详细内容...', '新疆阿克苏地区电信5G数字乡村项目介绍', '技术资讯', '["5G", "数字乡村", "电信"]', 100, 1, 156, '张专家', '2022-09-28 11:47:27', 1, 1, '重点项目'),
|
||||
('共享养牛,开启畜牧业财富之路', 'https://via.placeholder.com/100x50', '共享养牛模式详细介绍...', '共享养牛模式介绍', '养殖技术', '["共享养牛", "畜牧业", "财富"]', 98, 1, 234, '李专家', '2023-08-28 15:38:35', 0, 1, '热门推荐'),
|
||||
('现代化养牛场建设与管理', 'https://via.placeholder.com/100x50', '现代化养牛场建设与管理详细内容...', '现代化养牛场建设指南', '养殖技术', '["现代化", "养牛场", "管理"]', 95, 1, 189, '王专家', '2023-07-15 09:20:15', 0, 0, '技术指导'),
|
||||
('牛群健康管理与疾病防控', 'https://via.placeholder.com/100x50', '牛群健康管理与疾病防控详细内容...', '牛群健康管理指南', '健康管理', '["健康管理", "疾病防控", "牛群"]', 90, 1, 312, '赵专家', '2023-06-20 14:30:45', 0, 1, '重要技术'),
|
||||
('饲料营养配比与成本控制', 'https://via.placeholder.com/100x50', '饲料营养配比与成本控制详细内容...', '饲料营养配比指南', '营养管理', '["饲料", "营养", "成本控制"]', 85, 1, 267, '孙专家', '2023-05-10 16:45:30', 0, 0, '成本优化'),
|
||||
('智能养殖设备应用案例', 'https://via.placeholder.com/100x50', '智能养殖设备应用案例详细内容...', '智能养殖设备应用', '智能设备', '["智能设备", "养殖", "应用案例"]', 80, 1, 198, '周专家', '2023-04-25 11:15:20', 0, 0, '设备应用'),
|
||||
('养牛场环保与可持续发展', 'https://via.placeholder.com/100x50', '养牛场环保与可持续发展详细内容...', '环保可持续发展指南', '环保管理', '["环保", "可持续发展", "养牛场"]', 75, 1, 145, '吴专家', '2023-03-18 13:25:10', 0, 0, '环保理念'),
|
||||
('牛群繁殖技术与选育', 'https://via.placeholder.com/100x50', '牛群繁殖技术与选育详细内容...', '繁殖技术选育指南', '繁殖技术', '["繁殖技术", "选育", "牛群"]', 70, 1, 223, '郑专家', '2023-02-28 10:40:55', 0, 0, '繁殖技术'),
|
||||
('养牛场财务管理与投资分析', 'https://via.placeholder.com/100x50', '养牛场财务管理与投资分析详细内容...', '财务管理投资分析', '经营管理', '["财务管理", "投资分析", "养牛场"]', 65, 1, 178, '钱专家', '2023-01-15 15:50:25', 0, 0, '经营管理'),
|
||||
('养牛行业市场趋势分析', 'https://via.placeholder.com/100x50', '养牛行业市场趋势分析详细内容...', '市场趋势分析报告', '市场分析', '["市场趋势", "行业分析", "养牛"]', 60, 1, 201, '刘专家', '2022-12-30 12:35:40', 0, 0, '市场分析');
|
||||
16
government-backend/sql/insert_device_warning_data.sql
Normal file
16
government-backend/sql/insert_device_warning_data.sql
Normal file
@@ -0,0 +1,16 @@
|
||||
INSERT INTO `device_warnings` (`farmName`, `farmerName`, `phone`, `deviceType`, `deviceNumber`, `alertType`, `alertLevel`, `alertTime`, `status`, `description`, `location`, `batteryLevel`, `signalStrength`, `temperature`, `remarks`) VALUES
|
||||
('扎旗大数据中心', '扎旗大数据中心', '132****9345', '智能项圈', '24077000001', '设备离线', 'high', '2024-01-15 10:30:00', 'active', '设备长时间无信号', 'A区1号牛舍', 15, 0, 25.5, '需要检查设备连接'),
|
||||
('扎旗大数据中心', '扎旗大数据中心', '132****9345', '智能项圈', '24065000947', '设备离线', 'high', '2024-01-15 09:45:00', 'active', '设备长时间无信号', 'A区2号牛舍', 8, 0, 26.2, '需要检查设备连接'),
|
||||
('扎旗大数据中心', '扎旗大数据中心', '132****9345', '智能耳标', '2407100002', '设备离线', 'high', '2024-01-15 11:20:00', 'active', '设备长时间无信号', 'B区1号牛舍', 22, 0, 24.8, '需要检查设备连接'),
|
||||
('扎旗大数据中心', '扎旗大数据中心', '132****9345', '智能耳标', '2407100001', '设备离线', 'high', '2024-01-15 10:15:00', 'active', '设备长时间无信号', 'B区2号牛舍', 18, 0, 25.1, '需要检查设备连接'),
|
||||
('扎旗大数据中心', '扎旗大数据中心', '132****9345', '智能耳标', '2407402678', '设备离线', 'high', '2024-01-15 09:30:00', 'active', '设备长时间无信号', 'C区1号牛舍', 12, 0, 26.5, '需要检查设备连接'),
|
||||
('扎旗大数据中心', '扎旗大数据中心', '132****9345', '智能耳标', '2407402675', '设备离线', 'high', '2024-01-15 08:45:00', 'active', '设备长时间无信号', 'C区2号牛舍', 25, 0, 24.2, '需要检查设备连接'),
|
||||
('扎旗大数据中心', '扎旗大数据中心', '132****9345', '智能耳标', '2407402674', '设备离线', 'high', '2024-01-15 08:20:00', 'active', '设备长时间无信号', 'C区3号牛舍', 30, 0, 25.8, '需要检查设备连接'),
|
||||
('139****8321_养殖场', '杜云鹏', '139****8321', '智能耳标', '2404412397', '设备离线', 'high', '2024-01-15 07:30:00', 'active', '设备长时间无信号', 'D区1号牛舍', 5, 0, 27.1, '需要检查设备连接'),
|
||||
('139****8321_养殖场', '杜云鹏', '139****8321', '智能耳标', '2404412404', '设备离线', 'high', '2024-01-15 07:15:00', 'active', '设备长时间无信号', 'D区2号牛舍', 8, 0, 26.8, '需要检查设备连接'),
|
||||
('扎旗大数据中心', '扎旗大数据中心', '132****9345', '智能主机', 'HOST001', '设备离线', 'high', '2024-01-15 12:00:00', 'active', '主机设备离线', '机房A', 0, 0, 28.5, '需要检查主机连接'),
|
||||
('扎旗大数据中心', '扎旗大数据中心', '132****9345', '智能主机', 'HOST002', '设备离线', 'high', '2024-01-15 11:45:00', 'active', '主机设备离线', '机房B', 0, 0, 29.2, '需要检查主机连接'),
|
||||
('扎旗大数据中心', '扎旗大数据中心', '132****9345', '智能主机', 'HOST003', '设备离线', 'high', '2024-01-15 11:30:00', 'active', '主机设备离线', '机房C', 0, 0, 27.8, '需要检查主机连接'),
|
||||
('扎旗大数据中心', '扎旗大数据中心', '132****9345', '智能耳标', '2407100003', '电量不足', 'medium', '2024-01-15 13:20:00', 'active', '设备电量低于20%', 'A区3号牛舍', 18, 65, 25.3, '需要更换电池'),
|
||||
('扎旗大数据中心', '扎旗大数据中心', '132****9345', '智能项圈', '24077000002', '信号异常', 'medium', '2024-01-15 13:45:00', 'active', '信号强度不稳定', 'B区3号牛舍', 45, 25, 26.1, '需要检查信号接收'),
|
||||
('扎旗大数据中心', '扎旗大数据中心', '132****9345', '智能耳标', '2407100004', '温度异常', 'high', '2024-01-15 14:10:00', 'active', '温度超过正常范围', 'C区4号牛舍', 35, 80, 32.5, '需要检查牛只健康状况');
|
||||
132
government-backend/test-cattle-academy-api.js
Normal file
132
government-backend/test-cattle-academy-api.js
Normal file
@@ -0,0 +1,132 @@
|
||||
const axios = require('axios');
|
||||
|
||||
// 创建axios实例
|
||||
const api = axios.create({
|
||||
baseURL: 'http://localhost:5352/api/cattle-academy',
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer test-token'
|
||||
}
|
||||
});
|
||||
|
||||
// 测试获取养牛学院资讯列表
|
||||
async function testGetCattleAcademyList() {
|
||||
try {
|
||||
console.log('测试获取养牛学院资讯列表...');
|
||||
const response = await api.get('/');
|
||||
console.log('获取列表成功:', response.data);
|
||||
} catch (error) {
|
||||
console.error('获取列表失败:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 测试获取单个养牛学院资讯详情
|
||||
async function testGetCattleAcademyById() {
|
||||
try {
|
||||
console.log('测试获取养牛学院资讯详情...');
|
||||
const response = await api.get('/1');
|
||||
console.log('获取详情成功:', response.data);
|
||||
} catch (error) {
|
||||
console.error('获取详情失败:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 测试创建养牛学院资讯
|
||||
async function testCreateCattleAcademy() {
|
||||
try {
|
||||
console.log('测试创建养牛学院资讯...');
|
||||
const data = {
|
||||
title: '测试养牛学院资讯',
|
||||
coverImage: 'https://via.placeholder.com/100x50',
|
||||
content: '测试内容...',
|
||||
summary: '测试摘要',
|
||||
category: '技术资讯',
|
||||
sort: 50,
|
||||
status: true,
|
||||
author: '测试作者',
|
||||
publishTime: new Date().toISOString(),
|
||||
isTop: false,
|
||||
isRecommend: false,
|
||||
remarks: '测试备注'
|
||||
};
|
||||
const response = await api.post('/', data);
|
||||
console.log('创建成功:', response.data);
|
||||
} catch (error) {
|
||||
console.error('创建失败:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 测试更新养牛学院资讯
|
||||
async function testUpdateCattleAcademy() {
|
||||
try {
|
||||
console.log('测试更新养牛学院资讯...');
|
||||
const data = {
|
||||
title: '更新测试养牛学院资讯',
|
||||
coverImage: 'https://via.placeholder.com/100x50',
|
||||
content: '更新测试内容...',
|
||||
summary: '更新测试摘要',
|
||||
category: '养殖技术',
|
||||
sort: 60,
|
||||
status: true,
|
||||
author: '更新测试作者',
|
||||
publishTime: new Date().toISOString(),
|
||||
isTop: true,
|
||||
isRecommend: true,
|
||||
remarks: '更新测试备注'
|
||||
};
|
||||
const response = await api.put('/1', data);
|
||||
console.log('更新成功:', response.data);
|
||||
} catch (error) {
|
||||
console.error('更新失败:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 测试切换资讯状态
|
||||
async function testToggleStatus() {
|
||||
try {
|
||||
console.log('测试切换资讯状态...');
|
||||
const response = await api.patch('/1/status', { status: false });
|
||||
console.log('状态切换成功:', response.data);
|
||||
} catch (error) {
|
||||
console.error('状态切换失败:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 测试删除养牛学院资讯
|
||||
async function testDeleteCattleAcademy() {
|
||||
try {
|
||||
console.log('测试删除养牛学院资讯...');
|
||||
const response = await api.delete('/1');
|
||||
console.log('删除成功:', response.data);
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 运行所有测试
|
||||
async function runAllTests() {
|
||||
console.log('开始测试养牛学院API...\n');
|
||||
|
||||
await testGetCattleAcademyList();
|
||||
console.log('\n');
|
||||
|
||||
await testGetCattleAcademyById();
|
||||
console.log('\n');
|
||||
|
||||
await testCreateCattleAcademy();
|
||||
console.log('\n');
|
||||
|
||||
await testUpdateCattleAcademy();
|
||||
console.log('\n');
|
||||
|
||||
await testToggleStatus();
|
||||
console.log('\n');
|
||||
|
||||
await testDeleteCattleAcademy();
|
||||
console.log('\n');
|
||||
|
||||
console.log('所有测试完成');
|
||||
}
|
||||
|
||||
runAllTests();
|
||||
99
government-backend/test-device-warning-api.js
Normal file
99
government-backend/test-device-warning-api.js
Normal file
@@ -0,0 +1,99 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const API_BASE_URL = 'http://localhost:5352/api/device-warning';
|
||||
|
||||
const api = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer test-token'
|
||||
}
|
||||
});
|
||||
|
||||
async function testDeviceWarningAPI() {
|
||||
console.log('开始测试设备预警API...\n');
|
||||
|
||||
try {
|
||||
// 测试获取预警统计
|
||||
console.log('1. 测试获取预警统计...');
|
||||
const statsResponse = await api.get('/stats');
|
||||
console.log('预警统计:', statsResponse.data);
|
||||
console.log('✅ 获取预警统计成功\n');
|
||||
|
||||
// 测试获取设备预警列表
|
||||
console.log('2. 测试获取设备预警列表...');
|
||||
const listResponse = await api.get('/', {
|
||||
params: {
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
deviceType: '智能项圈'
|
||||
}
|
||||
});
|
||||
console.log('设备预警列表:', listResponse.data);
|
||||
console.log('✅ 获取设备预警列表成功\n');
|
||||
|
||||
// 测试根据ID获取详情
|
||||
if (listResponse.data.data && listResponse.data.data.list.length > 0) {
|
||||
const firstWarning = listResponse.data.data.list[0];
|
||||
console.log('3. 测试获取设备预警详情...');
|
||||
const detailResponse = await api.get(`/${firstWarning.id}`);
|
||||
console.log('设备预警详情:', detailResponse.data);
|
||||
console.log('✅ 获取设备预警详情成功\n');
|
||||
|
||||
// 测试更新预警状态
|
||||
console.log('4. 测试更新预警状态...');
|
||||
const updateResponse = await api.patch(`/${firstWarning.id}/status`, {
|
||||
status: 'resolved',
|
||||
resolvedBy: '测试用户'
|
||||
});
|
||||
console.log('更新预警状态:', updateResponse.data);
|
||||
console.log('✅ 更新预警状态成功\n');
|
||||
}
|
||||
|
||||
// 测试创建新的设备预警
|
||||
console.log('5. 测试创建设备预警...');
|
||||
const createData = {
|
||||
farmName: '测试养殖场',
|
||||
farmerName: '测试养殖户',
|
||||
phone: '138****8888',
|
||||
deviceType: '智能耳标',
|
||||
deviceNumber: 'TEST001',
|
||||
alertType: '设备离线',
|
||||
alertLevel: 'high',
|
||||
description: '测试预警',
|
||||
location: '测试位置',
|
||||
batteryLevel: 20,
|
||||
signalStrength: 30,
|
||||
temperature: 25.5
|
||||
};
|
||||
const createResponse = await api.post('/', createData);
|
||||
console.log('创建设备预警:', createResponse.data);
|
||||
console.log('✅ 创建设备预警成功\n');
|
||||
|
||||
// 测试更新设备预警
|
||||
if (createResponse.data.data) {
|
||||
console.log('6. 测试更新设备预警...');
|
||||
const updateData = {
|
||||
description: '更新后的测试预警',
|
||||
batteryLevel: 15
|
||||
};
|
||||
const updateResponse = await api.put(`/${createResponse.data.data.id}`, updateData);
|
||||
console.log('更新设备预警:', updateResponse.data);
|
||||
console.log('✅ 更新设备预警成功\n');
|
||||
|
||||
// 测试删除设备预警
|
||||
console.log('7. 测试删除设备预警...');
|
||||
const deleteResponse = await api.delete(`/${createResponse.data.data.id}`);
|
||||
console.log('删除设备预警:', deleteResponse.data);
|
||||
console.log('✅ 删除设备预警成功\n');
|
||||
}
|
||||
|
||||
console.log('🎉 所有设备预警API测试通过!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ API测试失败:', error.response ? error.response.data : error.message);
|
||||
}
|
||||
}
|
||||
|
||||
testDeviceWarningAPI();
|
||||
124
government-backend/test-epidemic-activity-api.js
Normal file
124
government-backend/test-epidemic-activity-api.js
Normal file
@@ -0,0 +1,124 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const BASE_URL = 'http://localhost:5352/api/epidemic-activity';
|
||||
|
||||
// 创建axios实例,添加认证头
|
||||
const api = axios.create({
|
||||
baseURL: BASE_URL,
|
||||
headers: {
|
||||
'Authorization': 'Bearer test-token', // 测试用的token
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
// 测试获取防疫活动列表
|
||||
async function testGetActivities() {
|
||||
try {
|
||||
console.log('测试获取防疫活动列表...');
|
||||
const response = await api.get('/');
|
||||
console.log('获取成功:', response.data);
|
||||
} catch (error) {
|
||||
console.error('获取失败:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 测试创建防疫活动
|
||||
async function testCreateActivity() {
|
||||
try {
|
||||
console.log('测试创建防疫活动...');
|
||||
const newActivity = {
|
||||
activityName: '测试防疫活动',
|
||||
livestockCategory: '牛',
|
||||
diseaseCategory: '口蹄疫',
|
||||
vaccineUsed: '测试疫苗',
|
||||
vaccineBatch: 'TEST001',
|
||||
preventionDate: '2023-12-01至2023-12-31',
|
||||
activityStatus: 'active'
|
||||
};
|
||||
|
||||
const response = await api.post('/', newActivity);
|
||||
console.log('创建成功:', response.data);
|
||||
return response.data.data.id;
|
||||
} catch (error) {
|
||||
console.error('创建失败:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 测试更新防疫活动
|
||||
async function testUpdateActivity(id) {
|
||||
try {
|
||||
console.log('测试更新防疫活动...');
|
||||
const updateData = {
|
||||
activityName: '更新后的防疫活动',
|
||||
livestockCategory: '羊',
|
||||
diseaseCategory: '布鲁氏菌病',
|
||||
vaccineUsed: '更新疫苗',
|
||||
vaccineBatch: 'UPDATE001',
|
||||
preventionDate: '2023-12-15至2024-01-15',
|
||||
activityStatus: 'inactive'
|
||||
};
|
||||
|
||||
const response = await api.put(`/${id}`, updateData);
|
||||
console.log('更新成功:', response.data);
|
||||
} catch (error) {
|
||||
console.error('更新失败:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 测试切换活动状态
|
||||
async function testToggleStatus(id) {
|
||||
try {
|
||||
console.log('测试切换活动状态...');
|
||||
const response = await api.patch(`/${id}/status`);
|
||||
console.log('状态切换成功:', response.data);
|
||||
} catch (error) {
|
||||
console.error('状态切换失败:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 测试删除防疫活动
|
||||
async function testDeleteActivity(id) {
|
||||
try {
|
||||
console.log('测试删除防疫活动...');
|
||||
const response = await api.delete(`/${id}`);
|
||||
console.log('删除成功:', response.data);
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 运行所有测试
|
||||
async function runTests() {
|
||||
console.log('开始测试防疫活动管理API...\n');
|
||||
|
||||
await testGetActivities();
|
||||
console.log('\n' + '='.repeat(50) + '\n');
|
||||
|
||||
const createdId = await testCreateActivity();
|
||||
console.log('\n' + '='.repeat(50) + '\n');
|
||||
|
||||
if (createdId) {
|
||||
await testUpdateActivity(createdId);
|
||||
console.log('\n' + '='.repeat(50) + '\n');
|
||||
|
||||
await testToggleStatus(createdId);
|
||||
console.log('\n' + '='.repeat(50) + '\n');
|
||||
|
||||
await testDeleteActivity(createdId);
|
||||
}
|
||||
|
||||
console.log('\n测试完成!');
|
||||
}
|
||||
|
||||
// 如果直接运行此文件
|
||||
if (require.main === module) {
|
||||
runTests();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
testGetActivities,
|
||||
testCreateActivity,
|
||||
testUpdateActivity,
|
||||
testToggleStatus,
|
||||
testDeleteActivity
|
||||
};
|
||||
@@ -53,7 +53,7 @@
|
||||
助力银行降低信贷风险,提高资产质量。
|
||||
</p>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="https://ad.ningmuyun.com" class="btn btn-light btn-lg" target="_blank">
|
||||
<a href="https://ad.ningmuyun.com/bank/" class="btn btn-light btn-lg" target="_blank">
|
||||
<i class="bi bi-box-arrow-up-right me-2"></i>立即体验
|
||||
</a>
|
||||
<a href="index.html#contact" class="btn btn-outline-light btn-lg">
|
||||
@@ -206,7 +206,7 @@
|
||||
<h2 class="mb-4">立即提升银行风控能力</h2>
|
||||
<p class="lead mb-4">选择专业的银行监管系统,让您的信贷风险管理更加智能、高效、可靠</p>
|
||||
<div class="d-flex gap-3 justify-content-center">
|
||||
<a href="https://ad.ningmuyun.com" class="btn btn-light btn-lg" target="_blank">
|
||||
<a href="https://ad.ningmuyun.com/bank/" class="btn btn-light btn-lg" target="_blank">
|
||||
<i class="bi bi-box-arrow-up-right me-2"></i>免费试用
|
||||
</a>
|
||||
<a href="index.html#contact" class="btn btn-outline-light btn-lg">
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
实现养殖过程的智能化、精细化和标准化管理。
|
||||
</p>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="https://ad.ningmuyun.com" class="btn btn-light btn-lg" target="_blank">
|
||||
<a href="https://ad.ningmuyun.com/farm/" class="btn btn-light btn-lg" target="_blank">
|
||||
<i class="bi bi-box-arrow-up-right me-2"></i>立即体验
|
||||
</a>
|
||||
<a href="index.html#contact" class="btn btn-outline-light btn-lg">
|
||||
@@ -206,7 +206,7 @@
|
||||
<h2 class="mb-4">立即开启数字化养殖管理之旅</h2>
|
||||
<p class="lead mb-4">选择专业的养殖管理系统,让您的养殖业务更加高效、安全、智能</p>
|
||||
<div class="d-flex gap-3 justify-content-center">
|
||||
<a href="https://ad.ningmuyun.com" class="btn btn-light btn-lg" target="_blank">
|
||||
<a href="https://ad.ningmuyun.com/farm/" class="btn btn-light btn-lg" target="_blank">
|
||||
<i class="bi bi-box-arrow-up-right me-2"></i>免费试用
|
||||
</a>
|
||||
<a href="index.html#contact" class="btn btn-outline-light btn-lg">
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
实现监管工作的智能化、规范化和高效化管理。
|
||||
</p>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="https://ad.ningmuyun.com" class="btn btn-light btn-lg" target="_blank">
|
||||
<a href="https://ad.ningmuyun.com/government/" class="btn btn-light btn-lg" target="_blank">
|
||||
<i class="bi bi-box-arrow-up-right me-2"></i>立即体验
|
||||
</a>
|
||||
<a href="index.html#contact" class="btn btn-outline-light btn-lg">
|
||||
@@ -206,7 +206,7 @@
|
||||
<h2 class="mb-4">立即提升政府监管效能</h2>
|
||||
<p class="lead mb-4">选择专业的政府监管系统,让您的监管工作更加高效、精准、规范</p>
|
||||
<div class="d-flex gap-3 justify-content-center">
|
||||
<a href="https://ad.ningmuyun.com" class="btn btn-light btn-lg" target="_blank">
|
||||
<a href="https://ad.ningmuyun.com/government/" class="btn btn-light btn-lg" target="_blank">
|
||||
<i class="bi bi-box-arrow-up-right me-2"></i>免费试用
|
||||
</a>
|
||||
<a href="index.html#contact" class="btn btn-outline-light btn-lg">
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
实现保险业务的智能化、规范化和高效化管理。
|
||||
</p>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="https://ad.ningmuyun.com" class="btn btn-light btn-lg" target="_blank">
|
||||
<a href="https://ad.ningmuyun.com/insurance/" class="btn btn-light btn-lg" target="_blank">
|
||||
<i class="bi bi-box-arrow-up-right me-2"></i>立即体验
|
||||
</a>
|
||||
<a href="index.html#contact" class="btn btn-outline-light btn-lg">
|
||||
@@ -206,7 +206,7 @@
|
||||
<h2 class="mb-4">立即优化保险业务管理</h2>
|
||||
<p class="lead mb-4">选择专业的保险监管系统,让您的保险业务更加高效、精准、可靠</p>
|
||||
<div class="d-flex gap-3 justify-content-center">
|
||||
<a href="https://ad.ningmuyun.com" class="btn btn-light btn-lg" target="_blank">
|
||||
<a href="https://ad.ningmuyun.com/insurance/" class="btn btn-light btn-lg" target="_blank">
|
||||
<i class="bi bi-box-arrow-up-right me-2"></i>免费试用
|
||||
</a>
|
||||
<a href="index.html#contact" class="btn btn-outline-light btn-lg">
|
||||
|
||||
Reference in New Issue
Block a user