From 5b615473e09cbaff3fcb414684faf2d19fe37525 Mon Sep 17 00:00:00 2001 From: xuqiuyun <1113560936@qq.com> Date: Sun, 28 Sep 2025 17:58:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin-system/.env.production | 2 +- admin-system/default.conf | 11 +- admin-system/public/login.html | 16 + admin-system/src/router/index.js | 8 +- admin-system/src/views/SmartCollarAlert.vue | 4 +- admin-system/src/views/SmartHost.vue | 9 +- admin-system/vite.config.js | 27 +- backend/routes/smart-devices.js | 29 +- insurance_admin-system/src/utils/request.js | 22 +- .../src/views/ApplicationManagement.vue | 99 +-- .../src/views/ClaimManagement.vue | 562 ++++++++++---- .../src/views/InsuranceTypeManagement.vue | 476 +++++++----- .../src/views/PolicyManagement.vue | 7 +- insurance_backend/config/swagger.js | 79 ++ .../controllers/insuranceTypeController.js | 85 ++- .../controllers/livestockClaimController.js | 217 +++++- .../docs/insurance-type-api-examples.md | 308 ++++++++ .../docs/insurance-type-api.yaml | 690 ++++++++++++++++++ insurance_backend/models/InsuranceType.js | 32 + insurance_backend/models/LivestockClaim.js | 85 ++- insurance_backend/models/index.js | 2 +- insurance_backend/routes/insuranceTypes.js | 318 +++++++- insurance_backend/routes/livestockClaims.js | 25 +- insurance_backend/test_params.js | 23 + .../tests/insurance-type-api-test.js | 282 +++++++ mini_program/farm-monitor-dashboard/app.json | 4 + .../pages/alert/alert.js | 133 +++- .../pages/alert/alert.wxml | 20 + .../pages/alert/alert.wxss | 70 ++ .../pages/cattle/batches/batches.js | 273 +++++++ .../pages/cattle/batches/batches.json | 4 + .../pages/cattle/batches/batches.wxml | 66 ++ .../pages/cattle/batches/batches.wxss | 119 +++ .../pages/cattle/cattle.js | 210 +++++- .../pages/cattle/cattle.wxml | 42 +- .../pages/cattle/cattle.wxss | 51 ++ .../pages/cattle/exit/exit.js | 258 +++++++ .../pages/cattle/exit/exit.json | 3 + .../pages/cattle/exit/exit.wxml | 51 ++ .../pages/cattle/exit/exit.wxss | 32 + .../pages/cattle/pens/pens.js | 285 ++++++++ .../pages/cattle/pens/pens.json | 4 + .../pages/cattle/pens/pens.wxml | 51 ++ .../pages/cattle/pens/pens.wxss | 27 + .../pages/cattle/transfer/transfer.js | 257 +++++++ .../pages/cattle/transfer/transfer.json | 3 + .../pages/cattle/transfer/transfer.wxml | 82 +++ .../pages/cattle/transfer/transfer.wxss | 211 ++++++ .../pages/device/collar/collar.js | 4 +- .../device/eartag-detail/eartag-detail.js | 2 +- .../pages/device/eartag/eartag.js | 6 +- .../pages/device/fence/fence.js | 2 +- .../pages/device/host/host.js | 4 +- .../farm-monitor-dashboard/pages/home/home.js | 56 +- .../pages/login/login.js | 2 +- .../pages/production/production.js | 89 +++ .../pages/production/production.wxml | 65 ++ .../pages/production/production.wxss | 5 + .../farm-monitor-dashboard/utils/api.js | 112 ++- 59 files changed, 5428 insertions(+), 593 deletions(-) create mode 100644 admin-system/public/login.html create mode 100644 insurance_backend/docs/insurance-type-api-examples.md create mode 100644 insurance_backend/docs/insurance-type-api.yaml create mode 100644 insurance_backend/test_params.js create mode 100644 insurance_backend/tests/insurance-type-api-test.js create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/batches/batches.js create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/batches/batches.json create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/batches/batches.wxml create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/batches/batches.wxss create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/exit/exit.js create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/exit/exit.json create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/exit/exit.wxml create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/exit/exit.wxss create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/pens/pens.js create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/pens/pens.json create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/pens/pens.wxml create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/pens/pens.wxss create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/transfer/transfer.js create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/transfer/transfer.json create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/transfer/transfer.wxml create mode 100644 mini_program/farm-monitor-dashboard/pages/cattle/transfer/transfer.wxss diff --git a/admin-system/.env.production b/admin-system/.env.production index 344f467..163eb0b 100644 --- a/admin-system/.env.production +++ b/admin-system/.env.production @@ -1,4 +1,4 @@ # 生产环境配置 VITE_API_BASE_URL=/api -VITE_API_FULL_URL=https://ad.ningmuyun.com/api +VITE_API_FULL_URL=https://ad.ningmuyun.com/farm/api VITE_USE_PROXY=false \ No newline at end of file diff --git a/admin-system/default.conf b/admin-system/default.conf index 9150bbc..3f954b2 100644 --- a/admin-system/default.conf +++ b/admin-system/default.conf @@ -19,13 +19,18 @@ server { access_log off; } - # 处理Vue Router的history模式 - location / { - try_files $uri $uri/ /index.html; + # 处理Vue Router的history模式 - 支持/farm/路径 + location /farm/ { + try_files $uri $uri/ /farm/index.html; add_header Cache-Control "no-cache, no-store, must-revalidate"; add_header Pragma "no-cache"; add_header Expires "0"; } + + # 根路径重定向到/farm/ + location = / { + return 301 /farm/; + } # API代理到后端服务 location /api/ { diff --git a/admin-system/public/login.html b/admin-system/public/login.html new file mode 100644 index 0000000..b2d0b3d --- /dev/null +++ b/admin-system/public/login.html @@ -0,0 +1,16 @@ + + + + + + 重定向中... + + + +

正在重定向到登录页面...

+

如果没有自动跳转,请点击 这里

+ + diff --git a/admin-system/src/router/index.js b/admin-system/src/router/index.js index fbf798b..fe24d34 100644 --- a/admin-system/src/router/index.js +++ b/admin-system/src/router/index.js @@ -4,7 +4,7 @@ import routes from './routes' // 创建路由实例 const router = createRouter({ - history: createWebHistory(), + history: createWebHistory('/farm/'), routes, scrollBehavior(to, from, savedPosition) { // 如果有保存的位置,则恢复到保存的位置 @@ -30,6 +30,12 @@ router.beforeEach(async (to, from, next) => { return } + // 处理根路径访问,重定向到仪表盘 + if (to.path === '/') { + next('/dashboard') + return + } + // 如果访问登录页面且已有有效token,重定向到仪表盘 if (to.path === '/login' && userStore.token && userStore.isLoggedIn) { const redirectPath = to.query.redirect || '/dashboard' diff --git a/admin-system/src/views/SmartCollarAlert.vue b/admin-system/src/views/SmartCollarAlert.vue index cb5473b..294e072 100644 --- a/admin-system/src/views/SmartCollarAlert.vue +++ b/admin-system/src/views/SmartCollarAlert.vue @@ -31,7 +31,7 @@
{{ stats.highTemperature }}
-
预警
+
温度预警
@@ -392,7 +392,7 @@ const getAlertTypeText = (type) => { 'movement': '异常运动预警', 'wear': '佩戴异常预警' } - return typeMap[type] || '未知预警' + return typeMap[type] || '温度预警' } // 获取预警类型颜色 diff --git a/admin-system/src/views/SmartHost.vue b/admin-system/src/views/SmartHost.vue index e184659..52c66d9 100644 --- a/admin-system/src/views/SmartHost.vue +++ b/admin-system/src/views/SmartHost.vue @@ -204,6 +204,7 @@ import { message } from 'ant-design-vue' import { SearchOutlined, ExportOutlined } from '@ant-design/icons-vue' import { ExportUtils } from '../utils/exportUtils' import { loadBMapScript, createMap } from '@/utils/mapService' +import { API_CONFIG } from '@/config/env.js' // 响应式数据 const hosts = ref([]) @@ -312,8 +313,8 @@ const fetchData = async (showMessage = false) => { console.log('搜索条件:', searchValue.value.trim()) } - // 调用API获取智能主机数据 - const apiUrl = `/api/smart-devices/hosts?${params}` + // 调用API获取智能主机数据(使用环境配置的基础URL,兼容生产 /farm/api 前缀) + const apiUrl = `${API_CONFIG.baseUrl}/smart-devices/hosts?${params}` console.log('API请求URL:', apiUrl) const response = await fetch(apiUrl, { @@ -610,8 +611,8 @@ const exportData = async () => { console.log('导出搜索条件:', searchValue.value.trim()) } - // 调用API获取所有智能主机数据 - const apiUrl = `/api/smart-devices/hosts?${params}` + // 调用API获取所有智能主机数据(使用环境配置的基础URL,兼容生产 /farm/api 前缀) + const apiUrl = `${API_CONFIG.baseUrl}/smart-devices/hosts?${params}` console.log('导出API请求URL:', apiUrl) const response = await fetch(apiUrl, { diff --git a/admin-system/vite.config.js b/admin-system/vite.config.js index 963fa2b..5664425 100644 --- a/admin-system/vite.config.js +++ b/admin-system/vite.config.js @@ -7,8 +7,22 @@ export default defineConfig(({ mode }) => { // 加载环境变量 const env = loadEnv(mode, process.cwd(), '') + // 自定义重定向插件 + const redirectPlugin = () => { + return { + name: 'redirect-plugin', + configureServer(server) { + server.middlewares.use('/login', (req, res, next) => { + res.writeHead(302, { Location: '/farm/login' }) + res.end() + }) + } + } + } + return { - plugins: [vue()], + base: '/farm/', + plugins: [vue(), redirectPlugin()], resolve: { alias: { '@': resolve(__dirname, 'src') @@ -23,6 +37,11 @@ export default defineConfig(({ mode }) => { changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '/api') } + }, + // 开发环境重定向配置 + middlewareMode: false, + fs: { + strict: false } }, build: { @@ -38,7 +57,11 @@ export default defineConfig(({ mode }) => { }, define: { // 将环境变量注入到应用中 - __APP_ENV__: JSON.stringify(env) + __APP_ENV__: JSON.stringify(env), + // 在生产环境中强制使用正确的API URL + 'import.meta.env.VITE_API_BASE_URL': JSON.stringify( + mode === 'production' ? 'https://ad.ningmuyun.com/farm/api' : (env.VITE_API_BASE_URL || '/api') + ) } } }) \ No newline at end of file diff --git a/backend/routes/smart-devices.js b/backend/routes/smart-devices.js index 064af5e..37dc408 100644 --- a/backend/routes/smart-devices.js +++ b/backend/routes/smart-devices.js @@ -7,7 +7,7 @@ const express = require('express'); const router = express.Router(); const { verifyToken, checkRole } = require('../middleware/auth'); const { requirePermission } = require('../middleware/permission'); -const { IotXqClient, IotJbqServer, IotJbqClient } = require('../models'); +const { IotXqClient, IotJbqServer, IotJbqClient, Farm } = require('../models'); const { Op } = require('sequelize'); const { createSuccessResponse, createErrorResponse, createPaginatedResponse, SUCCESS_MESSAGES, ERROR_CODES } = require('../utils/apiResponse'); @@ -1366,6 +1366,14 @@ router.get('/hosts', verifyToken, requirePermission('smart_host:view'), async (r ] }); + // 批量查询牧场信息,构建映射表 + const orgIds = [...new Set(rows.map(h => h.org_id).filter(id => id !== null && id !== undefined))]; + let farmMap = {}; + if (orgIds.length > 0) { + const farms = await Farm.findAll({ where: { id: orgIds } }); + farmMap = Object.fromEntries(farms.map(f => [f.id, f.name])); + } + // 格式化数据以匹配前端UI需求 const hosts = rows.map(host => ({ id: host.id, @@ -1383,6 +1391,9 @@ router.get('/hosts', verifyToken, requirePermission('smart_host:view'), async (r state: host.state, // 设备状态 title: host.title, // 设备标题 org_id: host.org_id, // 组织ID + farmId: host.org_id, // 牧场ID(与组织ID一致) + farmName: farmMap[host.org_id] || '-', // 牧场名称 + farm: { id: host.org_id, name: farmMap[host.org_id] || '-' }, uid: host.uid, // 用户ID fence_id: host.fence_id, // 围栏ID source_id: host.source_id, // 数据源ID @@ -1449,6 +1460,19 @@ router.get('/hosts/:id', verifyToken, requirePermission('smart_host:view'), asyn } // 格式化数据 + // 牧场信息 + let farmId = host.org_id; + let farmName = '-'; + if (farmId !== null && farmId !== undefined) { + try { + const farm = await Farm.findByPk(farmId); + if (farm && farm.name) { + farmName = farm.name; + } + } catch (e) { + // 牧场查询失败时忽略,不影响主机详情返回 + } + } const hostData = { id: host.id, deviceNumber: host.sid, @@ -1465,6 +1489,9 @@ router.get('/hosts/:id', verifyToken, requirePermission('smart_host:view'), asyn state: host.state, title: host.title, org_id: host.org_id, + farmId: farmId, + farmName: farmName, + farm: { id: farmId, name: farmName }, uid: host.uid, fence_id: host.fence_id, source_id: host.source_id, diff --git a/insurance_admin-system/src/utils/request.js b/insurance_admin-system/src/utils/request.js index 0974758..c4c7ced 100644 --- a/insurance_admin-system/src/utils/request.js +++ b/insurance_admin-system/src/utils/request.js @@ -116,8 +116,28 @@ const handleResponse = async (response) => { const fetchRequest = async (url, options = {}) => { const userStore = useUserStore() + // 处理查询参数 + let finalUrl = url.startsWith('http') ? url : `${API_CONFIG.baseURL}${url}` + + if (options.params) { + const searchParams = new URLSearchParams() + Object.keys(options.params).forEach(key => { + if (options.params[key] !== undefined && options.params[key] !== null) { + searchParams.append(key, options.params[key]) + } + }) + + const queryString = searchParams.toString() + if (queryString) { + finalUrl += (finalUrl.includes('?') ? '&' : '?') + queryString + } + + // 从options中移除params,避免传递给fetch + delete options.params + } + // 构建完整URL - const fullUrl = url.startsWith('http') ? url : `${API_CONFIG.baseURL}${url}` + const fullUrl = finalUrl // 对于登录、刷新token接口,跳过token检查 const skipTokenCheck = url.includes('/auth/login') || diff --git a/insurance_admin-system/src/views/ApplicationManagement.vue b/insurance_admin-system/src/views/ApplicationManagement.vue index 9d4d567..f2e35cd 100644 --- a/insurance_admin-system/src/views/ApplicationManagement.vue +++ b/insurance_admin-system/src/views/ApplicationManagement.vue @@ -10,14 +10,14 @@ > @@ -170,31 +170,31 @@ size="small" > - {{ selectedApplication.application_number }} + {{ selectedApplication.application_no }} {{ selectedApplication.insurance_category === 'individual' ? '个人参保' : '企业参保' }} - {{ selectedApplication.insurance_type }} + {{ selectedApplication.insurance_type?.name || selectedApplication.insurance_type_id }} - ¥{{ Number(selectedApplication.insurance_amount).toLocaleString() }} + ¥{{ Number(selectedApplication.application_amount).toLocaleString() }} {{ selectedApplication.insurance_period }}个月 - {{ selectedApplication.applicant_name }} + {{ selectedApplication.customer_name }} - {{ maskIdCard(selectedApplication.id_card) }} + {{ maskIdCard(selectedApplication.customer_id_card) }} - {{ maskPhone(selectedApplication.phone) }} + {{ maskPhone(selectedApplication.customer_phone) }} - {{ selectedApplication.address }} + {{ selectedApplication.customer_address }} {{ selectedApplication.application_date }} @@ -277,20 +277,20 @@ 企业参保 - - + + {{ type.name }} - + 36个月 - - + + - - + + - - + + - - + + @@ -347,8 +347,8 @@ const selectedApplication = ref(null) // 搜索表单 const searchForm = reactive({ - applicationNumber: '', - applicantName: '', + application_no: '', + customer_name: '', insuranceType: '', insuranceCategory: '', status: '' @@ -366,13 +366,13 @@ const reviewFormData = reactive({ // 新增申请表单 const createForm = reactive({ insurance_category: '', - insurance_type: '', - insurance_amount: null, + insurance_type_id: '', + application_amount: null, insurance_period: '', - applicant_name: '', - id_card: '', - phone: '', - address: '', + customer_name: '', + customer_id_card: '', + customer_phone: '', + customer_address: '', remarks: '' }) @@ -390,14 +390,14 @@ const pagination = reactive({ const columns = [ { title: '申请单号', - dataIndex: 'application_number', - key: 'application_number', + dataIndex: 'application_no', + key: 'application_no', width: 180, fixed: 'left' }, { title: '投保人姓名', - dataIndex: 'applicant_name', + dataIndex: 'customer_name', key: 'applicant_name', width: 120 }, @@ -409,14 +409,17 @@ const columns = [ }, { title: '参保险种', - dataIndex: 'insurance_type', - key: 'insurance_type', - width: 150 + dataIndex: 'insurance_type_id', + key: 'insurance_type_id', + width: 150, + customRender: ({ record }) => { + return record.insurance_type?.name || record.insurance_type_id + } }, { title: '保险金额', - dataIndex: 'insurance_amount', - key: 'insurance_amount', + dataIndex: 'application_amount', + key: 'application_amount', width: 120 }, { @@ -427,8 +430,8 @@ const columns = [ }, { title: '联系电话', - dataIndex: 'phone', - key: 'phone', + dataIndex: 'customer_phone', + key: 'customer_phone', width: 130 }, { @@ -517,8 +520,8 @@ const handleSearch = () => { const resetSearch = () => { Object.assign(searchForm, { - applicationNumber: '', - applicantName: '', + application_no: '', + customer_name: '', insuranceType: '', insuranceCategory: '', status: '' @@ -575,13 +578,13 @@ const showCreateModal = () => { isEdit.value = false Object.assign(createForm, { insurance_category: '', - insurance_type: '', - insurance_amount: null, + insurance_type_id: '', + application_amount: null, insurance_period: '', - applicant_name: '', - id_card: '', - phone: '', - address: '', + customer_name: '', + customer_id_card: '', + customer_phone: '', + customer_address: '', remarks: '' }) createModalVisible.value = true diff --git a/insurance_admin-system/src/views/ClaimManagement.vue b/insurance_admin-system/src/views/ClaimManagement.vue index 2184a78..ad34495 100644 --- a/insurance_admin-system/src/views/ClaimManagement.vue +++ b/insurance_admin-system/src/views/ClaimManagement.vue @@ -17,37 +17,74 @@ - + + + + + + + 全部 + 疾病 + 意外事故 + 自然灾害 + 盗窃 + 其他 + + 全部 - 待审核 + 待处理 + 调查中 已通过 已拒绝 - 处理中 - 已完成 + 已赔付 @@ -73,41 +110,62 @@ @change="handleTableChange" >