From eca2040e5b6852f644869ece66ea9b21208ae878 Mon Sep 17 00:00:00 2001 From: shenquanyi Date: Tue, 4 Nov 2025 09:43:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=99=BE=E5=BA=A6=E5=9C=B0?= =?UTF-8?q?=E5=9B=BEAK?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin-system/.env.example | 2 +- admin-system/ENV_CONFIG.md | 2 +- admin-system/src/config/env.js | 4 +- admin-system/src/utils/baiduMapLoader.js | 4 +- admin-system/src/utils/baiduMapTest.js | 2 +- backend/ALERT_DETECTION_LOGIC.md | 195 --- backend/API_DOCS_TROUBLESHOOTING.md | 114 -- backend/API_INTEGRATION_GUIDE.md | 394 ------ backend/DATA_CONSISTENCY_REPORT.md | 88 -- backend/ERROR_FIX_SUMMARY.md | 120 -- backend/NETWORK_ACCESS_SOLUTION.md | 139 -- backend/NGROK_SETUP_GUIDE.md | 186 --- backend/README_SMART_ALERT_APIS.md | 341 ----- backend/README_SMART_EARTAG_ALERT_API.md | 292 ----- backend/SERVICE_MANAGER_README.md | 272 ++++ backend/SMART_COLLAR_ALERT_FIX.md | 127 -- backend/VERIFICATION_COMPLETE.md | 99 -- backend/check-actual-data.js | 98 -- backend/check-all-tables.js | 114 -- backend/check-correct-database.js | 99 -- backend/check-database-data.js | 114 -- backend/check-other-databases.js | 97 -- backend/check-server-config.js | 63 - backend/check-server-env.js | 61 - backend/check-specific-collar.js | 118 -- backend/configure-firewall.bat | 61 - backend/configure-firewall.ps1 | 78 -- backend/debug-startup.js | 35 - backend/demo-ngrok.bat | 43 - backend/fix-line-endings.sh | 14 + backend/node_manager.ps1 | 289 +++++ backend/node_manager.sh | 328 +++++ backend/simple-db-test.js | 66 - backend/simple-firewall.ps1 | 15 - backend/simple-test.js | 72 -- backend/start-and-test.js | 146 --- backend/start-ngrok.bat | 46 - backend/start-ngrok.ps1 | 68 - backend/start-tunnel-no-password.bat | 45 - backend/start.bat | 21 + backend/status.bat | 21 + backend/stop.bat | 21 + backend/swagger-alerts.js | 773 ----------- backend/swagger-animals.js | 706 ---------- backend/swagger-auth.js | 412 ------ backend/swagger-complete.js | 223 ---- backend/swagger-config.js | 369 ------ backend/swagger-devices.js | 684 ---------- backend/swagger-farms.js | 623 --------- backend/swagger-reports.js | 736 ----------- backend/swagger-simple.js | 520 -------- backend/swagger-smart-alerts.js | 1004 -------------- backend/swagger-stats.js | 1151 ----------------- backend/swagger-system.js | 1047 --------------- backend/swagger-users.js | 521 -------- backend/test-alert-detection-logic.js | 273 ---- backend/test-all-smart-alert-apis.js | 229 ---- backend/test-api-access.js | 73 -- backend/test-api-response.js | 88 -- backend/test-collar-alert-data.js | 111 -- backend/test-direct-api.js | 64 - backend/test-error-fix.js | 91 -- backend/test-fixed-collar-alert.js | 81 -- backend/test-model-connection.js | 85 -- backend/test-models.js | 33 - backend/test-ngrok.bat | 49 - backend/test-smart-collar-alert-api.js | 359 ----- .../test-smart-collar-alert-integration.js | 216 ---- backend/test-smart-eartag-alert-api.js | 326 ----- backend/verify-database-connection.js | 112 -- backend/系统架构师提示词.md | 108 -- ...级软件开发工程师提示词(前端vue-nodejs).md | 337 ----- ...架构师提示词(前端vue-后端springboot-nodejs).md | 216 ---- .../高级项目经理提示词(包含详细项目需求).md | 267 ---- .../farm-monitor-dashboard/test-fence.html | 2 +- test-auth.js | 150 --- test-frontend-logout.js | 118 -- test-login.js | 68 - test-logout.js | 75 -- website/assets/js/baidu-map.js | 2 +- 80 files changed, 975 insertions(+), 15841 deletions(-) delete mode 100644 backend/ALERT_DETECTION_LOGIC.md delete mode 100644 backend/API_DOCS_TROUBLESHOOTING.md delete mode 100644 backend/API_INTEGRATION_GUIDE.md delete mode 100644 backend/DATA_CONSISTENCY_REPORT.md delete mode 100644 backend/ERROR_FIX_SUMMARY.md delete mode 100644 backend/NETWORK_ACCESS_SOLUTION.md delete mode 100644 backend/NGROK_SETUP_GUIDE.md delete mode 100644 backend/README_SMART_ALERT_APIS.md delete mode 100644 backend/README_SMART_EARTAG_ALERT_API.md create mode 100644 backend/SERVICE_MANAGER_README.md delete mode 100644 backend/SMART_COLLAR_ALERT_FIX.md delete mode 100644 backend/VERIFICATION_COMPLETE.md delete mode 100644 backend/check-actual-data.js delete mode 100644 backend/check-all-tables.js delete mode 100644 backend/check-correct-database.js delete mode 100644 backend/check-database-data.js delete mode 100644 backend/check-other-databases.js delete mode 100644 backend/check-server-config.js delete mode 100644 backend/check-server-env.js delete mode 100644 backend/check-specific-collar.js delete mode 100644 backend/configure-firewall.bat delete mode 100644 backend/configure-firewall.ps1 delete mode 100644 backend/debug-startup.js delete mode 100644 backend/demo-ngrok.bat create mode 100644 backend/fix-line-endings.sh create mode 100644 backend/node_manager.ps1 create mode 100644 backend/node_manager.sh delete mode 100644 backend/simple-db-test.js delete mode 100644 backend/simple-firewall.ps1 delete mode 100644 backend/simple-test.js delete mode 100644 backend/start-and-test.js delete mode 100644 backend/start-ngrok.bat delete mode 100644 backend/start-ngrok.ps1 delete mode 100644 backend/start-tunnel-no-password.bat create mode 100644 backend/start.bat create mode 100644 backend/status.bat create mode 100644 backend/stop.bat delete mode 100644 backend/swagger-alerts.js delete mode 100644 backend/swagger-animals.js delete mode 100644 backend/swagger-auth.js delete mode 100644 backend/swagger-complete.js delete mode 100644 backend/swagger-config.js delete mode 100644 backend/swagger-devices.js delete mode 100644 backend/swagger-farms.js delete mode 100644 backend/swagger-reports.js delete mode 100644 backend/swagger-simple.js delete mode 100644 backend/swagger-smart-alerts.js delete mode 100644 backend/swagger-stats.js delete mode 100644 backend/swagger-system.js delete mode 100644 backend/swagger-users.js delete mode 100644 backend/test-alert-detection-logic.js delete mode 100644 backend/test-all-smart-alert-apis.js delete mode 100644 backend/test-api-access.js delete mode 100644 backend/test-api-response.js delete mode 100644 backend/test-collar-alert-data.js delete mode 100644 backend/test-direct-api.js delete mode 100644 backend/test-error-fix.js delete mode 100644 backend/test-fixed-collar-alert.js delete mode 100644 backend/test-model-connection.js delete mode 100644 backend/test-models.js delete mode 100644 backend/test-ngrok.bat delete mode 100644 backend/test-smart-collar-alert-api.js delete mode 100644 backend/test-smart-collar-alert-integration.js delete mode 100644 backend/test-smart-eartag-alert-api.js delete mode 100644 backend/verify-database-connection.js delete mode 100644 backend/系统架构师提示词.md delete mode 100644 backend/高级软件开发工程师提示词(前端vue-nodejs).md delete mode 100644 backend/高级软件系统架构师提示词(前端vue-后端springboot-nodejs).md delete mode 100644 backend/高级项目经理提示词(包含详细项目需求).md delete mode 100644 test-auth.js delete mode 100644 test-frontend-logout.js delete mode 100644 test-login.js delete mode 100644 test-logout.js diff --git a/admin-system/.env.example b/admin-system/.env.example index 78a2cee..8a7dbeb 100644 --- a/admin-system/.env.example +++ b/admin-system/.env.example @@ -9,7 +9,7 @@ # 2. 应用类型是否为「浏览器端」 # 3. Referer白名单配置(开发环境可设置为 *) # 4. API密钥状态是否为「启用」 -VITE_BAIDU_MAP_API_KEY=SOawZTeQbxdgrKYYx0o2hn34G0DyU2uo +VITE_BAIDU_MAP_API_KEY=fLz8UwJSM3ayYl6dtsWYp7TQ8993R6kC # API服务地址 VITE_API_BASE_URL=http://localhost:5350/api diff --git a/admin-system/ENV_CONFIG.md b/admin-system/ENV_CONFIG.md index 46b72fe..593b98b 100644 --- a/admin-system/ENV_CONFIG.md +++ b/admin-system/ENV_CONFIG.md @@ -16,7 +16,7 @@ ### 百度地图配置 | 变量名 | 默认值 | 说明 | |--------|--------|------| -| `VITE_BAIDU_MAP_API_KEY` | `SOawZTeQbxdgrKYYx0o2hn34G0DyU2uo` | 百度地图API密钥 | +| `VITE_BAIDU_MAP_API_KEY` | `fLz8UwJSM3ayYl6dtsWYp7TQ8993R6kC` | 百度地图API密钥 | ### 应用配置 | 变量名 | 默认值 | 说明 | diff --git a/admin-system/src/config/env.js b/admin-system/src/config/env.js index 4f2d341..39c1953 100644 --- a/admin-system/src/config/env.js +++ b/admin-system/src/config/env.js @@ -9,10 +9,10 @@ export const BAIDU_MAP_CONFIG = { // 从环境变量读取API密钥,如果没有则使用开发测试密钥 // 生产环境请设置 VITE_BAIDU_MAP_API_KEY 环境变量 // 请访问 http://lbsyun.baidu.com/apiconsole/key 申请有效的API密钥 - apiKey: import.meta.env.VITE_BAIDU_MAP_API_KEY || 'SOawZTeQbxdgrKYYx0o2hn34G0DyU2uo', + apiKey: import.meta.env.VITE_BAIDU_MAP_API_KEY || 'fLz8UwJSM3ayYl6dtsWYp7TQ8993R6kC', // 备用API密钥(用于不同环境) - fallbackApiKey: import.meta.env.VITE_BAIDU_MAP_FALLBACK_KEY || 'SOawZTeQbxdgrKYYx0o2hn34G0DyU2uo', + fallbackApiKey: import.meta.env.VITE_BAIDU_MAP_FALLBACK_KEY || 'fLz8UwJSM3ayYl6dtsWYp7TQ8993R6kC', // 是否启用Referer校验(开发环境建议关闭) enableRefererCheck: import.meta.env.VITE_BAIDU_MAP_ENABLE_REFERER !== 'false', diff --git a/admin-system/src/utils/baiduMapLoader.js b/admin-system/src/utils/baiduMapLoader.js index 1d24539..78d4136 100644 --- a/admin-system/src/utils/baiduMapLoader.js +++ b/admin-system/src/utils/baiduMapLoader.js @@ -14,7 +14,7 @@ const MAX_RETRY = 3; * @param {string} apiKey - 百度地图API密钥 * @returns {Promise} 加载完成的Promise */ -export const loadBaiduMapAPI = async (apiKey = 'SOawZTeQbxdgrKYYx0o2hn34G0DyU2uo') => { +export const loadBaiduMapAPI = async (apiKey = 'fLz8UwJSM3ayYl6dtsWYp7TQ8993R6kC') => { // 如果已经加载过,直接返回 if (BMapLoaded && window.BMap) { console.log('百度地图API已加载'); @@ -118,7 +118,7 @@ export const loadBaiduMapAPI = async (apiKey = 'SOawZTeQbxdgrKYYx0o2hn34G0DyU2uo * @param {string} apiKey - 百度地图API密钥 * @returns {Promise} 加载完成的Promise */ -export const retryLoadBaiduMapAPI = async (apiKey = 'SOawZTeQbxdgrKYYx0o2hn34G0DyU2uo') => { +export const retryLoadBaiduMapAPI = async (apiKey = 'fLz8UwJSM3ayYl6dtsWYp7TQ8993R6kC') => { if (retryCount >= MAX_RETRY) { throw new Error('百度地图API加载重试次数已达上限'); } diff --git a/admin-system/src/utils/baiduMapTest.js b/admin-system/src/utils/baiduMapTest.js index 4ae7062..8272a50 100644 --- a/admin-system/src/utils/baiduMapTest.js +++ b/admin-system/src/utils/baiduMapTest.js @@ -244,7 +244,7 @@ export class BaiduMapTester { this.isLoading = true; const script = document.createElement('script'); - script.src = 'https://api.map.baidu.com/api?v=3.0&ak=SOawZTeQbxdgrKYYx0o2hn34G0DyU2uo&callback=initBMapTest'; + script.src = 'https://api.map.baidu.com/api?v=3.0&ak=fLz8UwJSM3ayYl6dtsWYp7TQ8993R6kC&callback=initBMapTest'; window.initBMapTest = () => { this.isLoading = false; diff --git a/backend/ALERT_DETECTION_LOGIC.md b/backend/ALERT_DETECTION_LOGIC.md deleted file mode 100644 index 8b9c508..0000000 --- a/backend/ALERT_DETECTION_LOGIC.md +++ /dev/null @@ -1,195 +0,0 @@ -# 智能项圈预警检测逻辑说明 - -## 概述 -为智能项圈预警系统添加了自动预警检测逻辑,根据设备数据自动判断预警类型,无需依赖后端预处理的预警数据。 - -## 预警检测规则 - -### 1. 低电量预警 -- **条件**: `battery < 20` -- **级别**: 高级 -- **颜色**: 橙色 -- **说明**: 当设备电量低于20%时触发 - -### 2. 离线预警 -- **条件**: `is_connect === 0` -- **级别**: 高级 -- **颜色**: 红色 -- **说明**: 当设备连接状态为0时触发 - -### 3. 佩戴异常预警 -- **条件**: `bandge_status === 0` -- **级别**: 中级 -- **颜色**: 蓝色 -- **说明**: 当设备佩戴状态为0时触发 - -### 4. 温度过低预警 -- **条件**: `temperature < 20` -- **级别**: 中级 -- **颜色**: 蓝色 -- **说明**: 当设备温度低于20°C时触发 - -### 5. 温度过高预警 -- **条件**: `temperature > 40` -- **级别**: 高级 -- **颜色**: 红色 -- **说明**: 当设备温度高于40°C时触发 - -### 6. 异常运动预警 -- **条件**: `steps - y_steps === 0` -- **级别**: 中级 -- **颜色**: 紫色 -- **说明**: 当当日步数与昨日步数相同时触发 - -## 实现细节 - -### 判断函数 -```javascript -const determineAlertType = (record) => { - const alerts = [] - - // 检查电量预警 - if (record.battery !== undefined && record.battery !== null && record.battery < 20) { - alerts.push('battery') - } - - // 检查脱落预警 (bandge_status为0) - if (record.bandge_status !== undefined && record.bandge_status !== null && record.bandge_status === 0) { - alerts.push('wear') - } - - // 检查离线预警 (is_connect为0) - if (record.is_connect !== undefined && record.is_connect !== null && record.is_connect === 0) { - alerts.push('offline') - } - - // 检查温度预警 - if (record.temperature !== undefined && record.temperature !== null) { - if (record.temperature < 20) { - alerts.push('temperature_low') - } else if (record.temperature > 40) { - alerts.push('temperature_high') - } - } - - // 检查运动异常预警 (steps - y_steps为0) - if (record.steps !== undefined && record.y_steps !== undefined && - record.steps !== null && record.y_steps !== null) { - const movementDiff = record.steps - record.y_steps - if (movementDiff === 0) { - alerts.push('movement') - } - } - - // 返回第一个预警类型,如果没有预警则返回null - return alerts.length > 0 ? alerts[0] : null -} -``` - -### 预警级别分配 -```javascript -let alertLevel = 'low' -if (determinedAlertType === 'battery' || determinedAlertType === 'offline' || determinedAlertType === 'temperature_high') { - alertLevel = 'high' -} else if (determinedAlertType === 'movement' || determinedAlertType === 'wear' || determinedAlertType === 'temperature_low') { - alertLevel = 'medium' -} -``` - -### 统计数据计算 -```javascript -const calculateStats = (data) => { - const newStats = { - lowBattery: 0, - offline: 0, - highTemperature: 0, - abnormalMovement: 0, - wearOff: 0 - } - - data.forEach(item => { - const alertType = determineAlertType(item) - if (alertType === 'battery') { - newStats.lowBattery++ - } else if (alertType === 'offline') { - newStats.offline++ - } else if (alertType === 'temperature_high') { - newStats.highTemperature++ - } else if (alertType === 'movement') { - newStats.abnormalMovement++ - } else if (alertType === 'wear') { - newStats.wearOff++ - } - }) - - return newStats -} -``` - -## 测试验证 - -### 运行测试脚本 -```bash -cd backend -node test-alert-detection-logic.js -``` - -### 测试用例 -测试脚本包含以下测试用例: -1. 正常设备 -2. 低电量预警 -3. 离线预警 -4. 佩戴异常预警 -5. 温度过低预警 -6. 温度过高预警 -7. 异常运动预警 -8. 多重预警(低电量+离线) -9. 边界值测试(电量20/19,温度20/19/40/41) - -## 前端集成 - -### 数据转换 -在数据转换过程中,系统会: -1. 调用 `determineAlertType()` 函数判断预警类型 -2. 根据预警类型确定预警级别 -3. 更新统计卡片数据 -4. 在表格中显示相应的预警标签 - -### 筛选功能 -筛选下拉菜单包含所有预警类型: -- 全部预警 -- 低电量预警 -- 离线预警 -- 温度过低预警 -- 温度过高预警 -- 异常运动预警 -- 佩戴异常预警 - -## 优势 - -1. **实时检测**: 基于最新设备数据实时判断预警 -2. **灵活配置**: 预警规则可以轻松调整 -3. **多重预警**: 支持检测多种预警类型 -4. **优先级处理**: 当存在多重预警时,返回第一个检测到的预警 -5. **边界值处理**: 精确处理边界值情况 -6. **前端计算**: 减少后端计算负担,提高响应速度 - -## 注意事项 - -1. **数据完整性**: 确保设备数据包含所有必要字段 -2. **空值处理**: 函数会检查字段是否存在且不为null -3. **类型转换**: 确保数值字段为数字类型 -4. **性能考虑**: 大量数据时计算统计可能影响性能 -5. **规则一致性**: 前后端预警规则应保持一致 - -## 相关文件 - -- `admin-system/src/views/SmartCollarAlert.vue` - 前端预警页面 -- `backend/test-alert-detection-logic.js` - 测试脚本 -- `backend/ALERT_DETECTION_LOGIC.md` - 本文档 - ---- - -**实现时间**: 2025-01-18 -**版本**: v1.0.0 -**状态**: 已实现并测试 diff --git a/backend/API_DOCS_TROUBLESHOOTING.md b/backend/API_DOCS_TROUBLESHOOTING.md deleted file mode 100644 index 81bb30f..0000000 --- a/backend/API_DOCS_TROUBLESHOOTING.md +++ /dev/null @@ -1,114 +0,0 @@ -# API文档问题排查指南 - -## 问题描述 -在访问 `http://localhost:5350/api-docs/` 时,找不到 `/api/smart-alerts/public` 相关的API接口。 - -## 解决方案 - -### 1. 确保服务器正确启动 - -```bash -cd backend -npm start -``` - -确保服务器在端口5350上启动。 - -### 2. 检查端口配置 - -确保 `server.js` 中的端口配置正确: - -```javascript -const PORT = process.env.PORT || 5350; -``` - -### 3. 使用简化的Swagger配置 - -我已经创建了一个简化的Swagger配置文件 `swagger-simple.js`,它手动定义了所有API路径。 - -### 4. 运行测试脚本 - -```bash -# 测试API访问 -node test-api-access.js - -# 启动服务器并测试 -node start-and-test.js -``` - -### 5. 手动验证API - -在浏览器中访问以下URL来验证API是否正常工作: - -- 根路径: http://localhost:5350/ -- API文档: http://localhost:5350/api-docs/ -- Swagger JSON: http://localhost:5350/api-docs/swagger.json -- 智能耳标预警统计: http://localhost:5350/api/smart-alerts/public/eartag/stats -- 智能项圈预警统计: http://localhost:5350/api/smart-alerts/public/collar/stats - -### 6. 检查路由注册 - -确保在 `server.js` 中正确注册了智能预警路由: - -```javascript -// 智能预警相关路由 -app.use('/api/smart-alerts', require('./routes/smart-alerts')); -``` - -### 7. 重新启动服务器 - -如果修改了配置,请重新启动服务器: - -```bash -# 停止当前服务器 (Ctrl+C) -# 然后重新启动 -npm start -``` - -## 预期结果 - -正确配置后,在 `http://localhost:5350/api-docs/` 中应该能看到: - -### 智能耳标预警 API -- `GET /smart-alerts/public/eartag/stats` - 获取预警统计 -- `GET /smart-alerts/public/eartag` - 获取预警列表 -- `GET /smart-alerts/public/eartag/{id}` - 获取预警详情 -- `POST /smart-alerts/public/eartag/{id}/handle` - 处理预警 -- `POST /smart-alerts/public/eartag/batch-handle` - 批量处理预警 -- `GET /smart-alerts/public/eartag/export` - 导出预警数据 - -### 智能项圈预警 API -- `GET /smart-alerts/public/collar/stats` - 获取预警统计 -- `GET /smart-alerts/public/collar` - 获取预警列表 -- `GET /smart-alerts/public/collar/{id}` - 获取预警详情 -- `POST /smart-alerts/public/collar/{id}/handle` - 处理预警 -- `POST /smart-alerts/public/collar/batch-handle` - 批量处理预警 -- `GET /smart-alerts/public/collar/export` - 导出预警数据 - -## 故障排除 - -### 如果仍然看不到API路径 - -1. **检查控制台错误**:查看服务器启动时的错误信息 -2. **检查依赖**:确保安装了 `swagger-jsdoc` 和 `swagger-ui-express` -3. **检查文件路径**:确保所有文件都在正确的位置 -4. **清除缓存**:重启浏览器或清除缓存 - -### 如果API调用失败 - -1. **检查数据库连接**:确保数据库服务正在运行 -2. **检查模型导入**:确保所有模型都正确导入 -3. **查看服务器日志**:检查具体的错误信息 - -## 联系支持 - -如果问题仍然存在,请提供以下信息: - -1. 服务器启动日志 -2. 浏览器控制台错误 -3. 具体的错误信息 -4. 操作系统和Node.js版本 - ---- - -**注意**: 确保在运行任何测试之前,数据库服务正在运行,并且所有必要的依赖都已安装。 diff --git a/backend/API_INTEGRATION_GUIDE.md b/backend/API_INTEGRATION_GUIDE.md deleted file mode 100644 index 7d8c165..0000000 --- a/backend/API_INTEGRATION_GUIDE.md +++ /dev/null @@ -1,394 +0,0 @@ -# 智能耳标预警 API 接口文档 - -## 概述 - -智能耳标预警系统提供了完整的API接口,支持预警数据的查询、统计、处理和导出功能。所有接口均为公开接口,无需身份验证。 - -## 基础信息 - -- **基础URL**: `http://localhost:5350/api/smart-alerts/public` -- **数据格式**: JSON -- **字符编码**: UTF-8 - -## 接口列表 - -### 1. 获取智能耳标预警统计 - -**接口地址**: `GET /eartag/stats` - -**功能描述**: 获取智能耳标预警的统计数据,包括各类预警的数量和设备总数。 - -**请求参数**: 无 - -**响应示例**: -```json -{ - "success": true, - "data": { - "totalDevices": 150, - "lowBattery": 12, - "offline": 8, - "highTemperature": 5, - "lowTemperature": 3, - "abnormalMovement": 7, - "totalAlerts": 35 - }, - "message": "获取智能耳标预警统计成功" -} -``` - -**响应字段说明**: -- `totalDevices`: 耳标设备总数 -- `lowBattery`: 低电量预警数量 -- `offline`: 离线预警数量 -- `highTemperature`: 高温预警数量 -- `lowTemperature`: 低温预警数量 -- `abnormalMovement`: 异常运动预警数量 -- `totalAlerts`: 预警总数 - -### 2. 获取智能耳标预警列表 - -**接口地址**: `GET /eartag` - -**功能描述**: 获取智能耳标预警列表,支持分页、搜索和筛选。 - -**请求参数**: -| 参数名 | 类型 | 必填 | 默认值 | 说明 | -|--------|------|------|--------|------| -| page | number | 否 | 1 | 页码 | -| limit | number | 否 | 10 | 每页数量 | -| search | string | 否 | - | 搜索关键词(耳标编号) | -| alertType | string | 否 | - | 预警类型筛选 | -| alertLevel | string | 否 | - | 预警级别筛选 | -| status | string | 否 | - | 设备状态筛选 | -| startDate | string | 否 | - | 开始日期 (YYYY-MM-DD) | -| endDate | string | 否 | - | 结束日期 (YYYY-MM-DD) | - -**预警类型枚举**: -- `battery`: 低电量预警 -- `offline`: 离线预警 -- `temperature`: 温度预警 -- `movement`: 异常运动预警 - -**预警级别枚举**: -- `high`: 高级 -- `medium`: 中级 -- `low`: 低级 - -**设备状态枚举**: -- `online`: 在线 -- `offline`: 离线 -- `alarm`: 报警 -- `maintenance`: 维护 - -**响应示例**: -```json -{ - "success": true, - "data": [ - { - "id": "123_offline", - "deviceId": 123, - "deviceName": "EARTAG001", - "eartagNumber": "EARTAG001", - "alertType": "offline", - "alertLevel": "high", - "alertTime": "2024-01-15 10:30:00", - "battery": 85, - "temperature": 25.5, - "dailySteps": 0, - "totalSteps": 1500, - "yesterdaySteps": 1500, - "deviceStatus": "离线", - "gpsSignal": "无", - "movementStatus": "静止", - "description": "设备已离线超过30分钟", - "longitude": 116.3974, - "latitude": 39.9093 - } - ], - "total": 35, - "stats": { - "lowBattery": 12, - "offline": 8, - "highTemperature": 5, - "abnormalMovement": 7 - }, - "pagination": { - "page": 1, - "limit": 10, - "total": 35, - "pages": 4 - }, - "message": "获取智能耳标预警列表成功" -} -``` - -### 3. 获取单个智能耳标预警详情 - -**接口地址**: `GET /eartag/{id}` - -**功能描述**: 获取指定ID的智能耳标预警详细信息。 - -**路径参数**: -| 参数名 | 类型 | 必填 | 说明 | -|--------|------|------|------| -| id | string | 是 | 预警ID,格式为 deviceId_alertType | - -**响应示例**: -```json -{ - "success": true, - "data": { - "id": "123_offline", - "deviceId": 123, - "deviceName": "EARTAG001", - "eartagNumber": "EARTAG001", - "alertType": "offline", - "alertLevel": "high", - "alertTime": "2024-01-15 10:30:00", - "battery": 85, - "temperature": 25.5, - "dailySteps": 0, - "totalSteps": 1500, - "yesterdaySteps": 1500, - "deviceStatus": "离线", - "gpsSignal": "无", - "movementStatus": "静止", - "description": "设备已离线超过30分钟", - "longitude": 116.3974, - "latitude": 39.9093 - }, - "message": "获取智能耳标预警详情成功" -} -``` - -### 4. 处理智能耳标预警 - -**接口地址**: `POST /eartag/{id}/handle` - -**功能描述**: 处理指定的智能耳标预警。 - -**路径参数**: -| 参数名 | 类型 | 必填 | 说明 | -|--------|------|------|------| -| id | string | 是 | 预警ID | - -**请求体**: -```json -{ - "action": "acknowledged", - "notes": "已联系技术人员处理", - "handler": "张三" -} -``` - -**请求字段说明**: -- `action`: 处理动作(可选,默认为 "acknowledged") -- `notes`: 处理备注(可选) -- `handler`: 处理人(可选,默认为 "system") - -**响应示例**: -```json -{ - "success": true, - "data": { - "alertId": "123_offline", - "action": "acknowledged", - "notes": "已联系技术人员处理", - "handler": "张三", - "processedAt": "2024-01-15T10:35:00.000Z", - "status": "processed" - }, - "message": "预警处理成功" -} -``` - -### 5. 批量处理智能耳标预警 - -**接口地址**: `POST /eartag/batch-handle` - -**功能描述**: 批量处理多个智能耳标预警。 - -**请求体**: -```json -{ - "alertIds": ["123_offline", "124_battery", "125_temperature"], - "action": "acknowledged", - "notes": "批量处理完成", - "handler": "李四" -} -``` - -**请求字段说明**: -- `alertIds`: 预警ID列表(必填) -- `action`: 处理动作(可选,默认为 "acknowledged") -- `notes`: 处理备注(可选) -- `handler`: 处理人(可选,默认为 "system") - -**响应示例**: -```json -{ - "success": true, - "data": { - "processedCount": 3, - "results": [ - { - "alertId": "123_offline", - "action": "acknowledged", - "notes": "批量处理完成", - "handler": "李四", - "processedAt": "2024-01-15T10:35:00.000Z", - "status": "processed" - } - ] - }, - "message": "成功处理 3 个预警" -} -``` - -### 6. 导出智能耳标预警数据 - -**接口地址**: `GET /eartag/export` - -**功能描述**: 导出智能耳标预警数据,支持JSON和CSV格式。 - -**请求参数**: -| 参数名 | 类型 | 必填 | 默认值 | 说明 | -|--------|------|------|--------|------| -| search | string | 否 | - | 搜索关键词 | -| alertType | string | 否 | - | 预警类型筛选 | -| alertLevel | string | 否 | - | 预警级别筛选 | -| startDate | string | 否 | - | 开始日期 | -| endDate | string | 否 | - | 结束日期 | -| format | string | 否 | json | 导出格式 (json/csv) | - -**响应示例** (JSON格式): -```json -{ - "success": true, - "data": [ - { - "id": "123_offline", - "deviceId": 123, - "deviceName": "EARTAG001", - "eartagNumber": "EARTAG001", - "alertType": "offline", - "alertLevel": "high", - "alertTime": "2024-01-15 10:30:00", - "battery": 85, - "temperature": 25.5, - "dailySteps": 0, - "totalSteps": 1500, - "yesterdaySteps": 1500, - "deviceStatus": "离线", - "gpsSignal": "无", - "movementStatus": "静止", - "description": "设备已离线超过30分钟", - "longitude": 116.3974, - "latitude": 39.9093 - } - ], - "total": 35, - "message": "导出智能耳标预警数据成功" -} -``` - -## 错误处理 - -所有接口在发生错误时都会返回统一的错误格式: - -```json -{ - "success": false, - "message": "错误描述", - "error": "详细错误信息" -} -``` - -**常见HTTP状态码**: -- `200`: 请求成功 -- `400`: 请求参数错误 -- `404`: 资源不存在 -- `500`: 服务器内部错误 - -## 使用示例 - -### JavaScript/Node.js 示例 - -```javascript -// 获取预警统计 -const stats = await fetch('http://localhost:3000/api/smart-alerts/public/eartag/stats') - .then(response => response.json()); - -// 获取预警列表 -const alerts = await fetch('http://localhost:3000/api/smart-alerts/public/eartag?page=1&limit=10&alertType=battery') - .then(response => response.json()); - -// 处理预警 -const result = await fetch('http://localhost:3000/api/smart-alerts/public/eartag/123_offline/handle', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - action: 'acknowledged', - notes: '已处理', - handler: '张三' - }) -}).then(response => response.json()); -``` - -### Python 示例 - -```python -import requests -import json - -# 获取预警统计 -stats_response = requests.get('http://localhost:3000/api/smart-alerts/public/eartag/stats') -stats = stats_response.json() - -# 获取预警列表 -alerts_response = requests.get('http://localhost:3000/api/smart-alerts/public/eartag', - params={'page': 1, 'limit': 10, 'alertType': 'battery'}) -alerts = alerts_response.json() - -# 处理预警 -handle_data = { - 'action': 'acknowledged', - 'notes': '已处理', - 'handler': '张三' -} -result = requests.post('http://localhost:3000/api/smart-alerts/public/eartag/123_offline/handle', - json=handle_data) -``` - -### cURL 示例 - -```bash -# 获取预警统计 -curl -X GET "http://localhost:3000/api/smart-alerts/public/eartag/stats" - -# 获取预警列表 -curl -X GET "http://localhost:3000/api/smart-alerts/public/eartag?page=1&limit=10&alertType=battery" - -# 处理预警 -curl -X POST "http://localhost:3000/api/smart-alerts/public/eartag/123_offline/handle" \ - -H "Content-Type: application/json" \ - -d '{"action": "acknowledged", "notes": "已处理", "handler": "张三"}' -``` - -## 注意事项 - -1. 所有接口均为公开接口,无需身份验证 -2. 预警ID格式为 `deviceId_alertType`,例如 `123_offline` -3. 时间格式统一使用 ISO 8601 标准 -4. 分页从1开始,不是从0开始 -5. 搜索功能支持模糊匹配 -6. 导出功能支持大量数据,建议合理设置筛选条件 -7. 批量处理功能有数量限制,建议单次处理不超过100个预警 - -## 更新日志 - -- **v1.0.0** (2024-01-15): 初始版本,包含基础预警查询、统计、处理和导出功能 \ No newline at end of file diff --git a/backend/DATA_CONSISTENCY_REPORT.md b/backend/DATA_CONSISTENCY_REPORT.md deleted file mode 100644 index 2ec5398..0000000 --- a/backend/DATA_CONSISTENCY_REPORT.md +++ /dev/null @@ -1,88 +0,0 @@ -# 数据一致性检查报告 - -## 问题描述 -用户反映项圈编号22012000107在页面中显示的电量为14,但数据库中显示的电量为98。 - -## 检查结果 - -### 数据库实际数据 -通过直接查询数据库 `iot_xq_client` 表,项圈22012000107的实际数据为: -- **ID**: 3517 -- **SN**: 22012000107 -- **电量**: 14 -- **温度**: 10.1 -- **状态**: 0 (离线) -- **更新时间**: 1668348374 (2022-11-13) - -### API返回数据 -通过API `/api/smart-alerts/public/collar` 返回的数据: -- **项圈编号**: 22012000107 -- **电量**: 14 -- **温度**: 10.1 -- **预警类型**: 低电量预警、离线预警、温度过低预警、异常运动预警、佩戴异常预警 - -### 前端显示数据 -页面中显示的数据: -- **项圈编号**: 22012000107 -- **电量**: 14 -- **温度**: 10.1 -- **预警类型**: 低电量预警 -- **预警级别**: 中级 - -## 结论 - -**数据是一致的!** 项圈22012000107在数据库、API和前端页面中显示的电量都是14,没有数据不一致的问题。 - -### 可能的原因 -1. **查看的是不同项圈**: 用户可能查看的是其他项圈编号的数据 -2. **时间差异**: 数据可能在不同时间点发生了变化 -3. **缓存问题**: 可能存在浏览器缓存或应用缓存问题 -4. **多个记录**: 可能存在多个相同项圈编号的记录 - -### 其他项圈的电量数据 -从数据库查询结果可以看到,其他项圈的电量数据: -- 22012000108: 98% -- 15010000006: 98% -- 15010000007: 98% -- 15010000008: 83% -- 15010000015: 98% - -## 建议 - -1. **确认项圈编号**: 请确认查看的是正确的项圈编号22012000107 -2. **清除缓存**: 清除浏览器缓存并刷新页面 -3. **检查时间**: 确认查看数据的时间点 -4. **重新查询**: 重新查询数据库确认当前数据 - -## 技术细节 - -### 数据库表结构 -- 表名: `iot_xq_client` -- 主键: `id` -- 项圈编号字段: `sn` -- 电量字段: `battery` (varchar类型) -- 温度字段: `temperature` (varchar类型) - -### API处理流程 -1. 从数据库查询设备数据 -2. 根据数据生成预警信息 -3. 返回包含原始数据的预警列表 -4. 前端接收并显示数据 - -### 数据转换 -- 数据库电量: "14" (字符串) -- API返回电量: 14 (数字) -- 前端显示电量: 14 - -## 相关文件 - -- `backend/check-specific-collar.js` - 特定项圈检查脚本 -- `backend/check-database-data.js` - 数据库数据检查脚本 -- `backend/check-all-tables.js` - 所有表检查脚本 -- `backend/simple-db-test.js` - 简单数据库测试脚本 - ---- - -**检查时间**: 2025-01-18 -**检查结果**: 数据一致,无问题 -**状态**: 已确认 diff --git a/backend/ERROR_FIX_SUMMARY.md b/backend/ERROR_FIX_SUMMARY.md deleted file mode 100644 index 967cb9c..0000000 --- a/backend/ERROR_FIX_SUMMARY.md +++ /dev/null @@ -1,120 +0,0 @@ -# 智能项圈预警错误修复总结 - -## 问题描述 -在智能项圈预警页面中出现了JavaScript错误: -``` -ReferenceError: determinedAlertType is not defined -at SmartCollarAlert.vue:611:32 -``` - -## 问题原因 -在数据转换的`map`函数中,`determinedAlertType`变量只在`if-else`块内部定义,但在函数外部被引用,导致作用域错误。 - -## 解决方案 -将`determinedAlertType`变量声明移到`if-else`块外部,确保在整个函数作用域内都可以访问。 - -### 修复前的问题代码 -```javascript -if (item.alertType) { - // 使用API返回的预警类型 - alertTypeText = alertTypeMap[item.alertType] || item.alertType - // determinedAlertType 在这里没有定义 -} else { - // 如果没有预警类型,使用判断函数 - const determinedAlertType = determineAlertType(item) // 只在else块中定义 - alertTypeText = determinedAlertType ? getAlertTypeText(determinedAlertType) : '正常' -} - -// 在函数外部引用 determinedAlertType - 这里会报错 -determinedAlertType: determinedAlertType -``` - -### 修复后的代码 -```javascript -let alertTypeText = '正常' -let alertLevel = 'low' -let determinedAlertType = null // 在外部声明 - -if (item.alertType) { - // 使用API返回的预警类型 - alertTypeText = alertTypeMap[item.alertType] || item.alertType - determinedAlertType = item.alertType // 赋值 -} else { - // 如果没有预警类型,使用判断函数 - determinedAlertType = determineAlertType(item) // 重新赋值 - alertTypeText = determinedAlertType ? getAlertTypeText(determinedAlertType) : '正常' -} - -// 现在可以安全引用 determinedAlertType -determinedAlertType: determinedAlertType -``` - -## 修复效果 - -### 修复前 -- ❌ JavaScript运行时错误 -- ❌ 页面无法正常加载数据 -- ❌ 控制台显示ReferenceError - -### 修复后 -- ✅ 无JavaScript错误 -- ✅ 页面正常加载和显示数据 -- ✅ 统计数据正确显示(非零值) -- ✅ 预警列表正常显示 - -## 测试验证 - -### 运行测试脚本 -```bash -node backend/test-error-fix.js -``` - -### 测试结果 -``` -✅ API调用成功 -数据条数: 3 -统计数据: { - lowBattery: 22, - offline: 1779, - highTemperature: 1302, - abnormalMovement: 1908, - wearOff: 50 -} - -✅ 数据转换测试通过,没有ReferenceError -``` - -## 当前功能状态 - -### 统计数据 -- 低电量预警: 22个 -- 离线预警: 1779个 -- 温度预警: 1302个 -- 异常运动预警: 1908个 -- 佩戴异常预警: 50个 - -### 数据转换 -- ✅ 正确使用API返回的预警类型 -- ✅ 正确映射预警级别 -- ✅ 保留判断函数作为备用 -- ✅ 无JavaScript错误 - -### 页面功能 -- ✅ 统计卡片显示 -- ✅ 预警列表显示 -- ✅ 搜索和筛选 -- ✅ 分页功能 -- ✅ 预警处理 -- ✅ 数据导出 - -## 相关文件 - -- `admin-system/src/views/SmartCollarAlert.vue` - 主要修复文件 -- `backend/test-error-fix.js` - 测试脚本 -- `backend/ERROR_FIX_SUMMARY.md` - 本文档 - ---- - -**修复时间**: 2025-01-18 -**修复版本**: v1.0.1 -**状态**: 已修复并测试通过 diff --git a/backend/NETWORK_ACCESS_SOLUTION.md b/backend/NETWORK_ACCESS_SOLUTION.md deleted file mode 100644 index 7acb2f6..0000000 --- a/backend/NETWORK_ACCESS_SOLUTION.md +++ /dev/null @@ -1,139 +0,0 @@ -# 网络访问问题解决方案 - -## 问题描述 -您能访问 `http://172.28.112.1:5300/` 而别人访问不了,这是因为网络配置和防火墙设置的问题。 - -## 已完成的修复 - -### 1. ✅ 后端服务器配置修复 -- 修改了 `server.js` 文件 -- 服务器现在监听所有网络接口 (`0.0.0.0:5350`) -- 不再只监听本地回环地址 - -### 2. ✅ 前端服务器配置检查 -- 前端已正确配置 `host: '0.0.0.0'` -- 可以接受来自任何IP地址的连接 - -## 解决步骤 - -### 步骤1:重启服务器 -```bash -# 停止当前服务器(Ctrl+C) -# 重新启动后端服务器 -cd backend -npm start -``` - -### 步骤2:配置Windows防火墙 - -#### 方法A:使用批处理脚本(推荐) -1. 右键点击 `configure-firewall.bat` -2. 选择"以管理员身份运行" -3. 等待配置完成 - -#### 方法B:使用PowerShell脚本 -1. 右键点击 `configure-firewall.ps1` -2. 选择"以管理员身份运行" -3. 等待配置完成 - -#### 方法C:手动配置 -以管理员身份运行PowerShell,执行以下命令: -```powershell -# 允许前端端口 -netsh advfirewall firewall add rule name="Node.js Frontend Port 5300" dir=in action=allow protocol=TCP localport=5300 - -# 允许后端端口 -netsh advfirewall firewall add rule name="Node.js Backend Port 5350" dir=in action=allow protocol=TCP localport=5350 -``` - -### 步骤3:验证配置 -运行网络诊断脚本: -```bash -node fix-network-access.js -``` - -### 步骤4:测试访问 -让其他用户访问以下地址之一: -- `http://172.28.112.1:5300` (前端) -- `http://172.28.112.1:5350` (后端) -- `http://192.168.0.48:5300` (如果使用以太网) -- `http://192.168.0.48:5350` (如果使用以太网) - -## 网络接口说明 - -根据诊断结果,您有以下可用的网络接口: -- **Clash**: 198.18.0.1 (VPN接口) -- **vEthernet (Default Switch)**: 172.28.112.1 (Hyper-V接口) -- **以太网**: 192.168.0.48 (主要网络接口) -- **VMware Network Adapter VMnet1**: 192.168.134.1 -- **VMware Network Adapter VMnet8**: 192.168.238.1 - -## 常见问题解决 - -### 问题1:其他用户仍然无法访问 -**解决方案**: -1. 确认其他用户与您在同一个局域网内 -2. 使用正确的IP地址(不是localhost) -3. 检查路由器是否阻止了设备间通信 - -### 问题2:端口被占用 -**解决方案**: -```bash -# 查看端口占用情况 -netstat -ano | findstr :5300 -netstat -ano | findstr :5350 - -# 终止占用端口的进程 -taskkill /PID [进程ID] /F -``` - -### 问题3:防火墙配置失败 -**解决方案**: -1. 确保以管理员身份运行脚本 -2. 检查Windows防火墙是否被禁用 -3. 手动在Windows安全中心添加规则 - -## 验证方法 - -### 1. 检查服务器状态 -```bash -# 应该看到类似输出 -netstat -ano | findstr :5300 -# TCP 0.0.0.0:5300 0.0.0.0:0 LISTENING [PID] - -netstat -ano | findstr :5350 -# TCP 0.0.0.0:5350 0.0.0.0:0 LISTENING [PID] -``` - -### 2. 测试连接 -```bash -# 测试本地连接 -telnet localhost 5300 -telnet localhost 5350 - -# 测试局域网连接 -telnet 172.28.112.1 5300 -telnet 172.28.112.1 5350 -``` - -### 3. 浏览器测试 -在浏览器中访问: -- `http://172.28.112.1:5300` - 应该看到前端页面 -- `http://172.28.112.1:5350/api-docs` - 应该看到API文档 - -## 注意事项 - -1. **安全性**:开放端口到所有网络接口会降低安全性,仅用于开发环境 -2. **网络环境**:确保在受信任的局域网环境中使用 -3. **IP地址变化**:如果IP地址发生变化,需要更新访问地址 -4. **路由器设置**:某些路由器可能阻止设备间通信,需要检查路由器设置 - -## 成功标志 - -当配置成功后,您应该看到: -- 服务器启动时显示"服务器监听所有网络接口 (0.0.0.0:5350)" -- 其他用户可以通过您的IP地址访问服务 -- 防火墙规则已正确添加 -- 网络诊断脚本显示端口可以正常监听 - -如果按照以上步骤操作后仍有问题,请检查网络环境或联系网络管理员。 diff --git a/backend/NGROK_SETUP_GUIDE.md b/backend/NGROK_SETUP_GUIDE.md deleted file mode 100644 index d46cdad..0000000 --- a/backend/NGROK_SETUP_GUIDE.md +++ /dev/null @@ -1,186 +0,0 @@ -# ngrok外网访问配置指南 - -## 🎯 目标 -让不在同一局域网的用户能够访问您的开发服务器 - -## 📋 完整步骤 - -### 步骤1:注册ngrok账号 -1. 访问 https://ngrok.com/ -2. 点击 "Sign up" 注册免费账号 -3. 验证邮箱后登录 - -### 步骤2:获取认证令牌 -1. 登录后访问 https://dashboard.ngrok.com/get-started/your-authtoken -2. 复制您的authtoken(类似:`2abc123def456ghi789jkl012mno345pqr678stu901vwx234yz`) - -### 步骤3:配置ngrok认证 -```bash -# 在backend目录下运行 -.\ngrok.exe authtoken YOUR_AUTH_TOKEN -``` - -### 步骤4:启动服务穿透 - -#### 方法A:使用批处理脚本 -```bash -# 双击运行 -start-ngrok.bat -``` - -#### 方法B:使用PowerShell脚本 -```powershell -# 右键以管理员身份运行 -.\start-ngrok.ps1 -``` - -#### 方法C:手动启动 -```bash -# 启动前端穿透(新开一个终端窗口) -.\ngrok.exe http 5300 - -# 启动后端穿透(再开一个终端窗口) -.\ngrok.exe http 5350 -``` - -### 步骤5:获取访问地址 - -ngrok会显示类似这样的信息: -``` -Session Status online -Account your-email@example.com -Version 3.27.0 -Region United States (us) -Latency 45ms -Web Interface http://127.0.0.1:4040 -Forwarding https://abc123.ngrok.io -> http://localhost:5300 -``` - -### 步骤6:分享访问地址 - -- **前端访问地址**:`https://abc123.ngrok.io` -- **后端访问地址**:`https://def456.ngrok.io` -- **API文档地址**:`https://def456.ngrok.io/api-docs` - -## 🔧 高级配置 - -### 自定义子域名(付费功能) -```bash -# 使用自定义子域名 -.\ngrok.exe http 5300 --subdomain=myapp-frontend -.\ngrok.exe http 5350 --subdomain=myapp-backend -``` - -### 同时启动多个服务 -```bash -# 使用配置文件 -.\ngrok.exe start --all --config=ngrok.yml -``` - -### 配置文件示例 (ngrok.yml) -```yaml -version: "2" -authtoken: YOUR_AUTH_TOKEN -tunnels: - frontend: - proto: http - addr: 5300 - subdomain: myapp-frontend - backend: - proto: http - addr: 5350 - subdomain: myapp-backend -``` - -## 📊 免费版限制 - -- 每次重启ngrok,URL会变化 -- 同时只能运行1个隧道 -- 有连接数限制 -- 有带宽限制 - -## 💰 付费版优势 - -- 固定子域名 -- 多个隧道 -- 更高带宽 -- 更多功能 - -## 🚨 注意事项 - -1. **安全性**: - - 外网访问会暴露您的服务 - - 建议设置访问密码 - - 不要在生产环境使用 - -2. **性能**: - - 外网访问比内网慢 - - 免费版有带宽限制 - -3. **稳定性**: - - 免费版URL会变化 - - 付费版更稳定 - -## 🛠️ 故障排除 - -### 问题1:ngrok启动失败 -```bash -# 检查网络连接 -ping ngrok.com - -# 重新配置认证 -.\ngrok.exe authtoken YOUR_AUTH_TOKEN -``` - -### 问题2:无法访问服务 -```bash -# 检查本地服务是否运行 -netstat -ano | findstr :5300 -netstat -ano | findstr :5350 - -# 检查防火墙设置 -netsh advfirewall firewall show rule name="Node.js Frontend Port 5300" -``` - -### 问题3:URL无法访问 -- 检查ngrok是否在线 -- 重新启动ngrok -- 检查本地服务状态 - -## 📱 移动端访问 - -ngrok提供的HTTPS地址可以在移动设备上正常访问: -- 手机浏览器访问:`https://abc123.ngrok.io` -- 平板电脑访问:`https://abc123.ngrok.io` - -## 🔄 自动重启脚本 - -创建自动重启脚本,当ngrok断开时自动重连: - -```bash -# auto-restart-ngrok.bat -@echo off -:start -echo 启动ngrok... -.\ngrok.exe http 5300 -echo ngrok断开,3秒后重新启动... -timeout /t 3 /nobreak >nul -goto start -``` - -## 📈 监控和日志 - -ngrok提供Web界面监控: -- 访问:http://127.0.0.1:4040 -- 查看请求日志 -- 监控连接状态 -- 查看流量统计 - -## 🎉 完成! - -配置完成后,其他用户就可以通过ngrok提供的HTTPS地址访问您的开发服务器了! - -记住: -- 每次重启ngrok,URL会变化 -- 免费版有使用限制 -- 建议在开发测试时使用 diff --git a/backend/README_SMART_ALERT_APIS.md b/backend/README_SMART_ALERT_APIS.md deleted file mode 100644 index d2817f0..0000000 --- a/backend/README_SMART_ALERT_APIS.md +++ /dev/null @@ -1,341 +0,0 @@ -# 智能预警系统 API 完整封装 - -## 概述 - -本项目为智能预警系统提供了完整的API接口封装,包括智能耳标预警和智能项圈预警两个子系统。所有接口均为公开接口,支持完整的CRUD操作、数据导出和实时监控功能。 - -## 系统架构 - -``` -智能预警系统 API -├── 智能耳标预警 (Eartag Alerts) -│ ├── 预警统计 -│ ├── 预警列表查询 -│ ├── 预警详情获取 -│ ├── 预警处理 -│ ├── 批量处理 -│ └── 数据导出 -└── 智能项圈预警 (Collar Alerts) - ├── 预警统计 - ├── 预警列表查询 - ├── 预警详情获取 - ├── 预警处理 - ├── 批量处理 - └── 数据导出 -``` - -## 功能特性 - -### ✅ 核心功能 -- **预警统计**: 实时统计各类预警数量 -- **预警查询**: 支持分页、搜索、多维度筛选 -- **预警详情**: 获取单个预警的完整信息 -- **预警处理**: 单个和批量预警处理 -- **数据导出**: 支持JSON和CSV格式导出 -- **实时监控**: 提供预警变化监控功能 - -### ✅ 技术特性 -- **RESTful API**: 遵循REST设计原则 -- **Swagger文档**: 完整的API文档和在线测试 -- **错误处理**: 统一的错误响应格式 -- **参数验证**: 完整的请求参数验证 -- **性能优化**: 支持分页和筛选优化 -- **跨平台**: 支持多种编程语言调用 - -## API接口总览 - -### 智能耳标预警 API - -| 接口 | 方法 | 路径 | 功能 | -|------|------|------|------| -| 获取预警统计 | GET | `/eartag/stats` | 获取各类预警数量统计 | -| 获取预警列表 | GET | `/eartag` | 分页查询预警列表 | -| 获取预警详情 | GET | `/eartag/{id}` | 获取单个预警详情 | -| 处理预警 | POST | `/eartag/{id}/handle` | 处理单个预警 | -| 批量处理预警 | POST | `/eartag/batch-handle` | 批量处理预警 | -| 导出预警数据 | GET | `/eartag/export` | 导出预警数据 | - -### 智能项圈预警 API - -| 接口 | 方法 | 路径 | 功能 | -|------|------|------|------| -| 获取预警统计 | GET | `/collar/stats` | 获取各类预警数量统计 | -| 获取预警列表 | GET | `/collar` | 分页查询预警列表 | -| 获取预警详情 | GET | `/collar/{id}` | 获取单个预警详情 | -| 处理预警 | POST | `/collar/{id}/handle` | 处理单个预警 | -| 批量处理预警 | POST | `/collar/batch-handle` | 批量处理预警 | -| 导出预警数据 | GET | `/collar/export` | 导出预警数据 | - -## 快速开始 - -### 1. 启动服务 - -```bash -cd backend -npm install -npm start -``` - -服务将在 `http://localhost:5350` 启动。 - -### 2. 访问API文档 - -打开浏览器访问:`http://localhost:5350/api-docs` - -### 3. 测试API接口 - -```bash -# 测试智能耳标预警API -node test-smart-eartag-alert-api.js - -# 测试智能项圈预警API -node test-smart-collar-alert-api.js - -# 运行综合测试 -node test-all-smart-alert-apis.js -``` - -## 使用示例 - -### Node.js 示例 - -```javascript -const axios = require('axios'); - -// 获取智能耳标预警统计 -const eartagStats = await axios.get('http://localhost:5350/api/smart-alerts/public/eartag/stats'); -console.log('耳标预警统计:', eartagStats.data); - -// 获取智能项圈预警列表 -const collarAlerts = await axios.get('http://localhost:5350/api/smart-alerts/public/collar?page=1&limit=10'); -console.log('项圈预警列表:', collarAlerts.data); - -// 处理预警 -const handleResult = await axios.post('http://localhost:5350/api/smart-alerts/public/eartag/123_offline/handle', { - action: 'acknowledged', - notes: '已处理', - handler: '张三' -}); -console.log('处理结果:', handleResult.data); -``` - -### 前端Vue示例 - -```javascript -import { smartAlertService } from '@/utils/dataService'; - -// 获取耳标预警列表 -const eartagAlerts = await smartAlertService.getEartagAlerts({ - page: 1, - limit: 10, - alertType: 'battery' -}); - -// 获取项圈预警统计 -const collarStats = await smartAlertService.getCollarAlertStats(); - -// 批量处理预警 -const batchResult = await smartAlertService.batchHandleEartagAlerts({ - alertIds: ['123_offline', '124_battery'], - action: 'acknowledged', - notes: '批量处理', - handler: '管理员' -}); -``` - -### Python 示例 - -```python -import requests - -# 获取预警统计 -response = requests.get('http://localhost:5350/api/smart-alerts/public/eartag/stats') -stats = response.json() -print('预警统计:', stats['data']) - -# 处理预警 -handle_data = { - 'action': 'acknowledged', - 'notes': '已处理', - 'handler': '张三' -} -result = requests.post('http://localhost:5350/api/smart-alerts/public/eartag/123_offline/handle', - json=handle_data) -print('处理结果:', result.json()) -``` - -## 数据模型 - -### 预警数据结构 - -#### 智能耳标预警 -```javascript -{ - "id": "123_offline", // 预警ID - "deviceId": 123, // 设备ID - "deviceName": "EARTAG001", // 设备名称 - "eartagNumber": "EARTAG001", // 耳标编号 - "alertType": "offline", // 预警类型 - "alertLevel": "high", // 预警级别 - "alertTime": "2024-01-15 10:30:00", // 预警时间 - "battery": 85, // 设备电量 - "temperature": 25.5, // 设备温度 - "dailySteps": 0, // 当日步数 - "deviceStatus": "离线", // 设备状态 - "description": "设备已离线超过30分钟" // 预警描述 -} -``` - -#### 智能项圈预警 -```javascript -{ - "id": "123_offline", // 预警ID - "deviceId": 123, // 设备ID - "deviceName": "COLLAR001", // 设备名称 - "collarNumber": "COLLAR001", // 项圈编号 - "alertType": "offline", // 预警类型 - "alertLevel": "high", // 预警级别 - "alertTime": "2024-01-15 10:30:00", // 预警时间 - "battery": 85, // 设备电量 - "temperature": 25.5, // 设备温度 - "dailySteps": 0, // 当日步数 - "deviceStatus": "离线", // 设备状态 - "wearStatus": "未佩戴", // 佩戴状态 - "description": "设备已离线超过30分钟" // 预警描述 -} -``` - -### 预警类型 - -#### 智能耳标预警类型 -- `battery`: 低电量预警 -- `offline`: 离线预警 -- `temperature`: 温度预警 -- `movement`: 异常运动预警 - -#### 智能项圈预警类型 -- `battery`: 低电量预警 -- `offline`: 离线预警 -- `temperature`: 温度预警 -- `movement`: 异常运动预警 -- `wear`: 项圈脱落预警 - -### 预警级别 -- `high`: 高级 -- `medium`: 中级 -- `low`: 低级 - -## 配置说明 - -### 环境变量 -```bash -PORT=5350 # API服务端口 -NODE_ENV=development # 运行环境 -``` - -### 数据库配置 -系统使用MySQL数据库,需要配置以下表: -- `iot_jbq_client`: 智能耳标设备数据 -- `iot_xq_client`: 智能项圈设备数据 - -## 监控和维护 - -### 日志记录 -- API调用日志 -- 错误日志 -- 性能监控日志 - -### 监控指标 -- API响应时间 -- 错误率 -- 请求量 -- 预警处理效率 - -### 健康检查 -```bash -# 检查服务状态 -curl http://localhost:5350/ - -# 检查API文档 -curl http://localhost:5350/api-docs/swagger.json -``` - -## 扩展开发 - -### 添加新的预警类型 -1. 在控制器中添加新的预警检测逻辑 -2. 更新API文档中的预警类型枚举 -3. 更新前端界面的预警类型选项 - -### 添加新的处理动作 -1. 在控制器中添加新的处理逻辑 -2. 更新数据库模型(如果需要) -3. 更新API文档和前端界面 - -### 自定义筛选条件 -1. 在控制器中添加新的筛选逻辑 -2. 更新API文档中的参数说明 -3. 更新前端界面的筛选选项 - -## 测试 - -### 运行测试 -```bash -# 运行所有测试 -npm test - -# 运行特定测试 -node test-smart-eartag-alert-api.js -node test-smart-collar-alert-api.js -node test-all-smart-alert-apis.js -``` - -### 测试覆盖 -- ✅ API接口功能测试 -- ✅ 参数验证测试 -- ✅ 错误处理测试 -- ✅ 数据格式验证测试 -- ✅ 性能测试 -- ✅ 并发测试 - -## 故障排除 - -### 常见问题 - -1. **API无法访问** - - 检查服务是否启动 - - 检查端口是否正确 - - 检查防火墙设置 - -2. **数据库连接失败** - - 检查数据库配置 - - 检查数据库服务状态 - - 检查网络连接 - -3. **API响应慢** - - 检查数据库性能 - - 检查网络延迟 - - 优化查询条件 - -### 调试模式 -```bash -# 启用调试模式 -DEBUG=* npm start - -# 查看详细日志 -NODE_ENV=development npm start -``` - -## 版本历史 - -- **v1.0.0** (2024-01-15): 初始版本,包含完整的智能预警API系统 - -## 联系支持 - -如有问题或建议,请联系开发团队或查看项目文档。 - ---- - -**API文档地址**: http://localhost:5350/api-docs -**基础API地址**: http://localhost:5350/api/smart-alerts/public -**维护者**: 开发团队 diff --git a/backend/README_SMART_EARTAG_ALERT_API.md b/backend/README_SMART_EARTAG_ALERT_API.md deleted file mode 100644 index e3ed851..0000000 --- a/backend/README_SMART_EARTAG_ALERT_API.md +++ /dev/null @@ -1,292 +0,0 @@ -# 智能耳标预警 API 封装 - -## 概述 - -本项目为智能耳标预警系统提供了完整的API接口封装,支持预警数据的查询、统计、处理和导出功能。所有接口均为公开接口,其他程序可以轻松集成和调用。 - -## 功能特性 - -- ✅ **预警统计**: 获取各类预警的数量统计 -- ✅ **预警查询**: 支持分页、搜索、筛选的预警列表查询 -- ✅ **预警详情**: 获取单个预警的详细信息 -- ✅ **预警处理**: 单个和批量预警处理功能 -- ✅ **数据导出**: 支持JSON和CSV格式的数据导出 -- ✅ **实时监控**: 提供预警变化监控功能 -- ✅ **错误处理**: 完善的错误处理和响应机制 - -## 文件结构 - -``` -backend/ -├── controllers/ -│ └── smartEartagAlertController.js # 智能耳标预警控制器 -├── routes/ -│ └── smart-alerts.js # 智能预警路由配置 -├── examples/ -│ └── smart-eartag-alert-usage.js # API使用示例 -├── test-smart-eartag-alert-api.js # API测试脚本 -├── API_INTEGRATION_GUIDE.md # API接口文档 -└── README_SMART_EARTAG_ALERT_API.md # 本文件 - -admin-system/src/utils/ -└── dataService.js # 前端数据服务封装 -``` - -## 快速开始 - -### 1. 启动后端服务 - -```bash -cd backend -npm start -``` - -服务将在 `http://localhost:5350` 启动。 - -### 2. 测试API接口 - -```bash -# 运行API测试脚本 -node test-smart-eartag-alert-api.js -``` - -### 3. 查看API文档 - -详细API文档请参考:[API_INTEGRATION_GUIDE.md](./API_INTEGRATION_GUIDE.md) - -## API接口列表 - -| 接口 | 方法 | 路径 | 功能 | -|------|------|------|------| -| 获取预警统计 | GET | `/eartag/stats` | 获取各类预警数量统计 | -| 获取预警列表 | GET | `/eartag` | 分页查询预警列表 | -| 获取预警详情 | GET | `/eartag/{id}` | 获取单个预警详情 | -| 处理预警 | POST | `/eartag/{id}/handle` | 处理单个预警 | -| 批量处理预警 | POST | `/eartag/batch-handle` | 批量处理预警 | -| 导出预警数据 | GET | `/eartag/export` | 导出预警数据 | - -## 使用示例 - -### Node.js 示例 - -```javascript -const { SmartEartagAlertClient } = require('./examples/smart-eartag-alert-usage'); - -const client = new SmartEartagAlertClient(); - -// 获取预警统计 -const stats = await client.getAlertStats(); -console.log('预警统计:', stats.data); - -// 获取预警列表 -const alerts = await client.getAlerts({ - page: 1, - limit: 10, - alertType: 'battery' -}); -console.log('预警列表:', alerts.data); - -// 处理预警 -const result = await client.handleAlert('123_offline', { - action: 'acknowledged', - notes: '已处理', - handler: '张三' -}); -console.log('处理结果:', result.data); -``` - -### 前端Vue示例 - -```javascript -import { smartAlertService } from '@/utils/dataService'; - -// 获取预警列表 -const alerts = await smartAlertService.getEartagAlerts({ - page: 1, - limit: 10, - alertType: 'battery' -}); - -// 处理预警 -const result = await smartAlertService.handleEartagAlert(alertId, { - action: 'acknowledged', - notes: '已处理', - handler: '管理员' -}); -``` - -### 监控预警变化 - -```javascript -const { AlertMonitor } = require('./examples/smart-eartag-alert-usage'); - -const monitor = new AlertMonitor(client, { - interval: 30000, // 30秒检查一次 - onNewAlert: (count, stats) => { - console.log(`发现 ${count} 个新预警!`); - }, - onAlertChange: (changes, stats) => { - console.log('预警统计变化:', changes); - } -}); - -monitor.start(); // 开始监控 -``` - -## 数据模型 - -### 预警数据结构 - -```javascript -{ - "id": "123_offline", // 预警ID - "deviceId": 123, // 设备ID - "deviceName": "EARTAG001", // 设备名称 - "eartagNumber": "EARTAG001", // 耳标编号 - "alertType": "offline", // 预警类型 - "alertLevel": "high", // 预警级别 - "alertTime": "2024-01-15 10:30:00", // 预警时间 - "battery": 85, // 设备电量 - "temperature": 25.5, // 设备温度 - "dailySteps": 0, // 当日步数 - "totalSteps": 1500, // 总步数 - "yesterdaySteps": 1500, // 昨日步数 - "deviceStatus": "离线", // 设备状态 - "gpsSignal": "无", // GPS信号 - "movementStatus": "静止", // 运动状态 - "description": "设备已离线超过30分钟", // 预警描述 - "longitude": 116.3974, // 经度 - "latitude": 39.9093 // 纬度 -} -``` - -### 预警类型 - -- `battery`: 低电量预警 -- `offline`: 离线预警 -- `temperature`: 温度预警 -- `movement`: 异常运动预警 - -### 预警级别 - -- `high`: 高级 -- `medium`: 中级 -- `low`: 低级 - -## 配置说明 - -### 后端配置 - -确保后端服务在端口5350上运行: - -```javascript -// server.js -const PORT = process.env.PORT || 5350; -app.listen(PORT, () => { - console.log(`服务器运行在端口 ${PORT}`); -}); -``` - -### 前端配置 - -确保前端API基础URL配置正确: - -```javascript -// api.js -const API_BASE_URL = 'http://localhost:5350/api'; -``` - -## 错误处理 - -所有API接口都遵循统一的错误响应格式: - -```javascript -{ - "success": false, - "message": "错误描述", - "error": "详细错误信息" -} -``` - -常见HTTP状态码: -- `200`: 请求成功 -- `400`: 请求参数错误 -- `404`: 资源不存在 -- `500`: 服务器内部错误 - -## 性能优化 - -1. **分页查询**: 建议使用分页避免一次性加载大量数据 -2. **筛选条件**: 使用筛选条件减少不必要的数据传输 -3. **缓存机制**: 对于统计类数据可以考虑添加缓存 -4. **批量操作**: 对于大量预警处理建议使用批量接口 - -## 扩展功能 - -### 添加新的预警类型 - -1. 在控制器中添加新的预警检测逻辑 -2. 更新API文档中的预警类型枚举 -3. 更新前端界面的预警类型选项 - -### 添加新的处理动作 - -1. 在控制器中添加新的处理逻辑 -2. 更新数据库模型(如果需要) -3. 更新API文档和前端界面 - -## 测试 - -### 运行测试 - -```bash -# 运行完整测试套件 -node test-smart-eartag-alert-api.js - -# 运行使用示例 -node examples/smart-eartag-alert-usage.js -``` - -### 测试覆盖 - -- ✅ API接口功能测试 -- ✅ 参数验证测试 -- ✅ 错误处理测试 -- ✅ 数据格式验证测试 -- ✅ 性能测试 - -## 维护说明 - -### 日志记录 - -所有API调用都会记录详细日志,包括: -- 请求参数 -- 响应数据 -- 错误信息 -- 处理时间 - -### 监控指标 - -建议监控以下指标: -- API响应时间 -- 错误率 -- 请求量 -- 预警处理效率 - -### 版本更新 - -API版本更新时请: -1. 更新版本号 -2. 更新API文档 -3. 提供迁移指南 -4. 保持向后兼容性 - -## 联系支持 - -如有问题或建议,请联系开发团队或查看项目文档。 - ---- - -**版本**: v1.0.0 -**更新时间**: 2024-01-15 -**维护者**: 开发团队 diff --git a/backend/SERVICE_MANAGER_README.md b/backend/SERVICE_MANAGER_README.md new file mode 100644 index 0000000..bc82a40 --- /dev/null +++ b/backend/SERVICE_MANAGER_README.md @@ -0,0 +1,272 @@ +# Node.js 服务管理脚本使用说明 + +宁夏智慧养殖监管平台后端服务管理脚本,支持Linux和Windows系统。 + +## 文件说明 + +- **node_manager.sh** - Linux/CentOS服务器版本(Bash脚本) +- **node_manager.ps1** - Windows本地开发版本(PowerShell脚本) + +## 一、Linux版本使用说明 + +### 1. 准备工作 + +在CentOS服务器上首次使用前,需要设置脚本执行权限: + +```bash +chmod +x node_manager.sh +``` + +### 2. 基本命令 + +```bash +# 启动服务 +./node_manager.sh start + +# 停止服务 +./node_manager.sh stop + +# 重启服务 +./node_manager.sh restart + +# 查看服务状态 +./node_manager.sh status + +# 实时查看日志 +./node_manager.sh logs +``` + +### 3. 完整部署流程示例 + +```bash +# 1. 进入项目目录 +cd /path/to/backend + +# 2. 安装依赖(首次部署) +npm install + +# 3. 配置环境变量 +cp env.example .env +vim .env # 编辑配置 + +# 4. 启动服务 +./node_manager.sh start + +# 5. 检查状态 +./node_manager.sh status + +# 6. 查看日志 +./node_manager.sh logs +``` + +### 4. 常见问题 + +**Q: 提示 "端口已被占用" 怎么办?** + +A: 使用 `./node_manager.sh stop` 停止服务,或手动查找并杀死进程: + +```bash +# 查找占用端口的进程 +lsof -ti:5350 + +# 杀死进程 +kill -9 $(lsof -ti:5350) +``` + +**Q: 服务启动失败怎么办?** + +A: 查看日志文件定位问题: + +```bash +# 查看完整日志 +cat logs/nxxmdata-backend.log + +# 实时监控日志 +tail -f logs/nxxmdata-backend.log +``` + +## 二、Windows版本使用说明 + +### 1. 准备工作 + +首次使用前,可能需要设置PowerShell执行策略: + +```powershell +# 以管理员身份运行PowerShell +Set-ExecutionPolicy RemoteSigned -Scope CurrentUser +``` + +### 2. 基本命令 + +```powershell +# 启动服务 +.\node_manager.ps1 start + +# 停止服务 +.\node_manager.ps1 stop + +# 重启服务 +.\node_manager.ps1 restart + +# 查看服务状态 +.\node_manager.ps1 status + +# 实时查看日志 +.\node_manager.ps1 logs +``` + +### 3. 完整部署流程示例 + +```powershell +# 1. 进入项目目录 +cd D:\10-24\nxxmdata\backend + +# 2. 安装依赖(首次部署) +npm install + +# 3. 配置环境变量 +Copy-Item env.example .env +notepad .env # 编辑配置 + +# 4. 启动服务 +.\node_manager.ps1 start + +# 5. 检查状态 +.\node_manager.ps1 status + +# 6. 查看日志 +.\node_manager.ps1 logs +``` + +### 4. 常见问题 + +**Q: 提示 "端口已被占用" 怎么办?** + +A: 使用脚本停止服务,或手动查找并杀死进程: + +```powershell +# 查找占用端口的进程 +Get-NetTCPConnection -LocalPort 5350 | Select-Object -ExpandProperty OwningProcess + +# 杀死进程(替换 为实际进程ID) +Stop-Process -Id -Force +``` + +**Q: PowerShell提示无法执行脚本?** + +A: 设置执行策略: + +```powershell +Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned +``` + +## 三、配置说明 + +### 应用配置 + +在脚本中已配置以下默认值: + +| 配置项 | 值 | 说明 | +|--------|-----|------| +| APP_NAME | nxxmdata-backend | 应用名称 | +| ENTRY_FILE | server.js | 入口文件 | +| APP_PORT | 5350 | 监听端口 | +| NODE_ENV | production | 运行环境 | +| LOG_FILE | logs/nxxmdata-backend.log | 日志文件 | + +### 修改配置 + +如需修改配置,编辑脚本文件的"配置区域"部分: + +**Linux版本 (node_manager.sh):** +```bash +# 配置区域 +APP_NAME="nxxmdata-backend" +ENTRY_FILE="server.js" +APP_PORT="5350" +``` + +**Windows版本 (node_manager.ps1):** +```powershell +# 配置区域 +$APP_NAME = "nxxmdata-backend" +$ENTRY_FILE = "server.js" +$APP_PORT = 5350 +``` + +## 四、生产环境建议 + +### 使用 PM2(推荐) + +对于生产环境,建议使用PM2进行进程管理: + +```bash +# 安装 PM2 +npm install -g pm2 + +# 启动服务 +pm2 start server.js --name nxxmdata-backend + +# 保存配置 +pm2 save + +# 设置开机自启 +pm2 startup + +# 监控服务 +pm2 monit +``` + +### 日志管理 + +定期清理日志文件,避免占用过多磁盘空间: + +```bash +# Linux +find logs -name "*.log" -mtime +30 -delete + +# Windows PowerShell +Get-ChildItem logs -Filter *.log | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-30)} | Remove-Item +``` + +## 五、脚本功能特点 + +### Linux版本特点 + +- ✅ 优雅停止进程(SIGTERM → SIGKILL) +- ✅ 端口占用检测 +- ✅ 进程PID管理 +- ✅ 彩色输出提示 +- ✅ 详细的状态信息 +- ✅ 自动创建日志目录 +- ✅ 实时日志查看 + +### Windows版本特点 + +- ✅ PowerShell原生支持 +- ✅ 端口占用检测 +- ✅ 后台进程管理 +- ✅ 彩色输出提示 +- ✅ 详细的状态信息 +- ✅ 自动创建日志目录 +- ✅ 实时日志查看 + +## 六、技术支持 + +如遇到问题,请检查: + +1. Node.js版本是否正确(要求:16.20.2) +2. 依赖是否完整安装(node_modules目录) +3. 环境变量配置是否正确(.env文件) +4. 端口是否被其他程序占用 +5. 数据库连接是否正常 +6. 日志文件中的错误信息 + +--- + +**项目信息:** +- 项目名称:宁夏智慧养殖监管平台 +- 后端端口:5350 +- 前端端口:5300 +- API文档:http://localhost:5350/api-docs + diff --git a/backend/SMART_COLLAR_ALERT_FIX.md b/backend/SMART_COLLAR_ALERT_FIX.md deleted file mode 100644 index cb87001..0000000 --- a/backend/SMART_COLLAR_ALERT_FIX.md +++ /dev/null @@ -1,127 +0,0 @@ -# 智能项圈预警数据调用修复说明 - -## 问题描述 -智能项圈预警页面 (`admin-system/src/views/SmartCollarAlert.vue`) 存在以下问题: -1. 统计数据使用硬编码,没有动态调用数据库 -2. 部分功能没有正确调用API接口 -3. 数据格式转换和显示存在问题 - -## 修复内容 - -### 1. 添加统计数据API调用 -- 新增 `fetchStats()` 函数,专门用于获取统计数据 -- 调用 `smartAlertService.getCollarAlertStats()` API -- 动态更新统计卡片数据(低电量、离线、温度、异常运动、佩戴异常) - -### 2. 优化数据获取流程 -- 修改 `fetchData()` 函数,专注于获取预警列表数据 -- 在组件挂载时同时调用统计数据和列表数据API -- 在搜索、筛选、分页时同步更新统计数据 - -### 3. 完善API集成 -- 更新 `handleAlert()` 函数,调用 `smartAlertService.handleCollarAlert()` API -- 更新 `exportData()` 函数,调用 `smartAlertService.exportCollarAlerts()` API -- 所有异步函数都使用 `async/await` 模式 - -### 4. 数据格式优化 -- 保持原有的数据格式转换逻辑 -- 确保API返回的数据能正确显示在界面上 -- 优化错误处理和用户反馈 - -## 修改的文件 - -### admin-system/src/views/SmartCollarAlert.vue -主要修改: -1. 新增 `fetchStats()` 函数 -2. 修改 `fetchData()` 函数,移除硬编码统计数据 -3. 更新 `onMounted()` 钩子,同时获取统计和列表数据 -4. 更新 `handleSearch()`、`handleFilterChange()`、`handleClearSearch()` 函数 -5. 更新 `handleAlert()` 函数,调用API处理预警 -6. 更新 `exportData()` 函数,调用API导出数据 - -## API端点使用 - -### 统计数据 -- **端点**: `GET /api/smart-alerts/public/collar/stats` -- **功能**: 获取智能项圈预警统计数据 -- **返回**: 各类预警的数量统计 - -### 预警列表 -- **端点**: `GET /api/smart-alerts/public/collar` -- **功能**: 获取智能项圈预警列表 -- **参数**: page, limit, search, alertType, alertLevel, status, startDate, endDate - -### 预警详情 -- **端点**: `GET /api/smart-alerts/public/collar/{id}` -- **功能**: 获取单个预警详情 - -### 处理预警 -- **端点**: `POST /api/smart-alerts/public/collar/{id}/handle` -- **功能**: 处理指定的预警 - -### 批量处理预警 -- **端点**: `POST /api/smart-alerts/public/collar/batch-handle` -- **功能**: 批量处理多个预警 - -### 导出数据 -- **端点**: `GET /api/smart-alerts/public/collar/export` -- **功能**: 导出预警数据 -- **参数**: format (json/csv), search, alertType, alertLevel, startDate, endDate - -## 测试验证 - -### 运行测试脚本 -```bash -cd backend -node test-smart-collar-alert-integration.js -``` - -### 前端页面验证 -1. 打开智能项圈预警页面 -2. 检查统计卡片是否显示动态数据 -3. 测试搜索和筛选功能 -4. 测试处理预警功能 -5. 测试导出数据功能 - -## 预期效果 - -修复后的智能项圈预警页面应该能够: - -1. **动态显示统计数据** - - 低电量预警数量 - - 离线预警数量 - - 温度预警数量 - - 异常运动预警数量 - - 佩戴异常预警数量 - -2. **完整的数据交互** - - 实时搜索和筛选 - - 分页浏览 - - 预警详情查看 - - 预警处理操作 - - 数据导出功能 - -3. **良好的用户体验** - - 加载状态提示 - - 错误信息反馈 - - 操作成功确认 - -## 注意事项 - -1. **确保后端服务运行**: 后端服务器必须在端口5350上运行 -2. **数据库连接**: 确保数据库连接正常,相关表存在 -3. **API权限**: 确保API端点可以正常访问 -4. **数据格式**: 确保API返回的数据格式与前端期望一致 - -## 相关文件 - -- `backend/controllers/smartCollarAlertController.js` - 后端控制器 -- `backend/routes/smart-alerts.js` - API路由定义 -- `admin-system/src/utils/dataService.js` - 前端数据服务 -- `backend/test-smart-collar-alert-integration.js` - 集成测试脚本 - ---- - -**修复完成时间**: 2025-01-18 -**修复版本**: v1.0.0 -**测试状态**: 待验证 diff --git a/backend/VERIFICATION_COMPLETE.md b/backend/VERIFICATION_COMPLETE.md deleted file mode 100644 index 64ecb0d..0000000 --- a/backend/VERIFICATION_COMPLETE.md +++ /dev/null @@ -1,99 +0,0 @@ -# ✅ 网络访问问题已解决 - -## 修复完成状态 - -### 1. ✅ 后端服务器配置 -- **状态**: 已修复 -- **配置**: 服务器现在监听 `0.0.0.0:5350` -- **验证**: `netstat` 显示 `TCP 0.0.0.0:5350 LISTENING` - -### 2. ✅ 前端服务器配置 -- **状态**: 已正确配置 -- **配置**: 服务器监听 `0.0.0.0:5300` -- **验证**: `netstat` 显示 `TCP 0.0.0.0:5300 LISTENING` - -### 3. ✅ Windows防火墙配置 -- **状态**: 已配置 -- **规则1**: Node.js Frontend Port 5300 (已启用) -- **规则2**: Node.js Backend Port 5350 (已启用) -- **验证**: 防火墙规则已确认添加 - -## 现在其他用户可以访问的地址 - -### 主要访问地址 -- **前端**: `http://172.28.112.1:5300` -- **后端**: `http://172.28.112.1:5350` -- **API文档**: `http://172.28.112.1:5350/api-docs` - -### 备用访问地址(如果主要地址不可用) -- **前端**: `http://192.168.0.48:5300` -- **后端**: `http://192.168.0.48:5350` - -## 验证步骤 - -### 1. 本地验证 -在您的浏览器中访问: -- `http://172.28.112.1:5300` - 应该看到前端页面 -- `http://172.28.112.1:5350/api-docs` - 应该看到API文档 - -### 2. 外部用户验证 -让其他用户在他们的浏览器中访问: -- `http://172.28.112.1:5300` - 应该看到前端页面 -- `http://172.28.112.1:5350/api-docs` - 应该看到API文档 - -### 3. 网络连接测试 -其他用户可以运行以下命令测试连接: -```cmd -# 测试前端端口 -telnet 172.28.112.1 5300 - -# 测试后端端口 -telnet 172.28.112.1 5350 -``` - -## 故障排除 - -### 如果其他用户仍然无法访问: - -1. **检查网络环境** - - 确保其他用户与您在同一个局域网内 - - 确认没有使用VPN或代理 - -2. **检查IP地址** - - 使用 `ipconfig` 确认当前IP地址 - - 如果IP地址发生变化,更新访问地址 - -3. **检查防火墙** - - 确认Windows防火墙规则已启用 - - 检查是否有其他安全软件阻止连接 - -4. **检查路由器设置** - - 某些路由器可能阻止设备间通信 - - 检查路由器的访问控制设置 - -## 成功标志 - -当配置完全成功时,您应该看到: -- ✅ 服务器启动时显示"服务器监听所有网络接口" -- ✅ 防火墙规则已正确添加 -- ✅ 其他用户可以通过IP地址访问服务 -- ✅ 网络诊断脚本显示端口可以正常监听 - -## 注意事项 - -1. **安全性**: 当前配置允许局域网内所有设备访问,仅适用于开发环境 -2. **IP地址**: 如果网络环境变化,IP地址可能会改变 -3. **端口占用**: 确保端口5300和5350没有被其他程序占用 -4. **服务器状态**: 确保服务器持续运行 - -## 维护建议 - -1. **定期检查**: 定期运行 `node fix-network-access.js` 检查网络状态 -2. **日志监控**: 查看服务器日志确认连接状态 -3. **备份配置**: 保存防火墙配置以便快速恢复 - ---- - -**问题已完全解决!** 🎉 - -现在其他用户应该能够正常访问您的开发服务器了。如果还有任何问题,请检查上述故障排除步骤。 diff --git a/backend/check-actual-data.js b/backend/check-actual-data.js deleted file mode 100644 index 3754840..0000000 --- a/backend/check-actual-data.js +++ /dev/null @@ -1,98 +0,0 @@ -/** - * 检查实际数据 - * @file check-actual-data.js - * @description 检查数据库中项圈22012000107的实际数据 - */ - -const { sequelize } = require('./config/database-simple'); - -async function checkActualData() { - console.log('🔍 检查数据库中项圈22012000107的实际数据...\n'); - - try { - // 1. 测试数据库连接 - console.log('1. 测试数据库连接...'); - await sequelize.authenticate(); - console.log('✅ 数据库连接成功'); - - // 2. 查询项圈22012000107的数据 - console.log('\n2. 查询项圈22012000107的数据...'); - const [results] = await sequelize.query(` - SELECT - id, sn, deviceId, battery, temperature, state, - uptime, longitude, latitude, gps_state, rsrp, - bandge_status, is_connect, steps, y_steps - FROM iot_xq_client - WHERE sn = '22012000107' - ORDER BY uptime DESC - `); - - console.log(`找到 ${results.length} 条记录`); - - results.forEach((row, index) => { - console.log(`\n记录${index + 1}:`); - console.log('ID:', row.id); - console.log('SN:', row.sn); - console.log('设备ID:', row.deviceId); - console.log('电量:', row.battery, '(类型:', typeof row.battery, ')'); - console.log('温度:', row.temperature, '(类型:', typeof row.temperature, ')'); - console.log('状态:', row.state); - console.log('经度:', row.longitude); - console.log('纬度:', row.latitude); - console.log('GPS状态:', row.gps_state); - console.log('RSRP:', row.rsrp); - console.log('佩戴状态:', row.bandge_status); - console.log('连接状态:', row.is_connect); - console.log('步数:', row.steps); - console.log('昨日步数:', row.y_steps); - console.log('更新时间:', row.uptime); - }); - - // 3. 查询所有项圈的最新数据 - console.log('\n3. 查询所有项圈的最新数据...'); - const [allResults] = await sequelize.query(` - SELECT - id, sn, deviceId, battery, temperature, state, uptime - FROM iot_xq_client - ORDER BY uptime DESC - LIMIT 10 - `); - - console.log('所有项圈的最新数据:'); - allResults.forEach((row, index) => { - console.log(`${index + 1}. SN: ${row.sn}, 电量: ${row.battery}, 温度: ${row.temperature}, 状态: ${row.state}`); - }); - - // 4. 检查数据库配置 - console.log('\n4. 检查数据库配置...'); - const config = sequelize.config; - console.log('数据库配置:'); - console.log('主机:', config.host); - console.log('端口:', config.port); - console.log('数据库名:', config.database); - console.log('用户名:', config.username); - - // 5. 检查当前数据库 - console.log('\n5. 检查当前数据库...'); - const [currentDb] = await sequelize.query('SELECT DATABASE() as current_db'); - console.log('当前数据库:', currentDb[0].current_db); - - // 6. 检查是否有其他数据库 - console.log('\n6. 检查所有数据库...'); - const [databases] = await sequelize.query('SHOW DATABASES'); - console.log('所有数据库:'); - databases.forEach(db => { - const dbName = Object.values(db)[0]; - console.log('-', dbName); - }); - - } catch (error) { - console.error('❌ 检查失败:', error.message); - console.error('错误详情:', error); - } finally { - process.exit(0); - } -} - -// 运行检查 -checkActualData().catch(console.error); diff --git a/backend/check-all-tables.js b/backend/check-all-tables.js deleted file mode 100644 index 233ce32..0000000 --- a/backend/check-all-tables.js +++ /dev/null @@ -1,114 +0,0 @@ -/** - * 检查所有相关表 - * @file check-all-tables.js - * @description 检查所有可能包含项圈数据的表 - */ - -const { sequelize } = require('./config/database-simple'); - -async function checkAllTables() { - console.log('🔍 检查所有相关表...\n'); - - try { - // 1. 列出所有表 - console.log('1. 列出所有表...'); - const [tables] = await sequelize.query("SHOW TABLES"); - console.log('数据库中的所有表:'); - tables.forEach((table, index) => { - const tableName = Object.values(table)[0]; - console.log(`${index + 1}. ${tableName}`); - }); - - // 2. 检查可能包含项圈数据的表 - const possibleTables = [ - 'iot_xq_client', - 'iot_collar', - 'smart_collar', - 'collar_device', - 'device_info', - 'iot_device' - ]; - - console.log('\n2. 检查可能包含项圈数据的表...'); - - for (const tableName of possibleTables) { - try { - console.log(`\n检查表: ${tableName}`); - const [rows] = await sequelize.query(`SELECT COUNT(*) as count FROM ${tableName}`); - const count = rows[0].count; - console.log(`记录数: ${count}`); - - if (count > 0) { - // 查看表结构 - const [columns] = await sequelize.query(`DESCRIBE ${tableName}`); - console.log('表结构:'); - columns.forEach(col => { - console.log(` ${col.Field}: ${col.Type}`); - }); - - // 查找包含22012000107的记录 - const [searchResults] = await sequelize.query(` - SELECT * FROM ${tableName} - WHERE sn = '22012000107' OR device_id = '22012000107' OR deviceId = '22012000107' - LIMIT 5 - `); - - if (searchResults.length > 0) { - console.log(`找到 ${searchResults.length} 条包含22012000107的记录:`); - searchResults.forEach((row, index) => { - console.log(`记录${index + 1}:`, row); - }); - } else { - console.log('未找到包含22012000107的记录'); - } - } - } catch (error) { - console.log(`表 ${tableName} 不存在或无法访问: ${error.message}`); - } - } - - // 3. 检查iot_xq_client表的详细信息 - console.log('\n3. 检查iot_xq_client表的详细信息...'); - const [xqClientData] = await sequelize.query(` - SELECT * FROM iot_xq_client - WHERE sn = '22012000107' - ORDER BY uptime DESC - `); - - console.log(`iot_xq_client表中项圈22012000107的记录:`); - xqClientData.forEach((row, index) => { - console.log(`\n记录${index + 1}:`); - console.log('ID:', row.id); - console.log('SN:', row.sn); - console.log('电量:', row.battery); - console.log('温度:', row.temperature); - console.log('状态:', row.state); - console.log('更新时间:', row.uptime); - console.log('创建时间:', row.created_at); - console.log('更新时间:', row.updated_at); - }); - - // 4. 检查是否有其他项圈编号 - console.log('\n4. 检查所有项圈编号...'); - const [allSnData] = await sequelize.query(` - SELECT sn, battery, temperature, state, uptime - FROM iot_xq_client - ORDER BY uptime DESC - LIMIT 20 - `); - - console.log('所有项圈编号及其电量:'); - allSnData.forEach((row, index) => { - console.log(`${index + 1}. SN: ${row.sn}, 电量: ${row.battery}, 温度: ${row.temperature}, 状态: ${row.state}`); - }); - - } catch (error) { - console.error('❌ 检查失败:', error.message); - console.error('错误详情:', error); - } finally { - process.exit(0); - } -} - -// 运行检查 -checkAllTables().catch(console.error); diff --git a/backend/check-correct-database.js b/backend/check-correct-database.js deleted file mode 100644 index 2ba52ae..0000000 --- a/backend/check-correct-database.js +++ /dev/null @@ -1,99 +0,0 @@ -/** - * 检查正确的数据库 - * @file check-correct-database.js - * @description 使用正确的数据库配置检查项圈22012000107的数据 - */ - -const mysql = require('mysql2/promise'); - -async function checkCorrectDatabase() { - console.log('🔍 使用正确的数据库配置检查项圈22012000107的数据...\n'); - - try { - // 使用正确的数据库配置 - const connection = await mysql.createConnection({ - host: '129.211.213.226', - port: 9527, - user: 'root', - password: 'aiotAiot123!', - database: 'nxxmdata' - }); - - console.log('✅ 数据库连接成功'); - - // 查询项圈22012000107的数据 - console.log('\n查询项圈22012000107的数据...'); - const [results] = await connection.execute(` - SELECT - id, sn, deviceId, battery, temperature, state, - uptime, longitude, latitude, gps_state, rsrp, - bandge_status, is_connect, steps, y_steps - FROM iot_xq_client - WHERE sn = '22012000107' - ORDER BY uptime DESC - `); - - console.log(`找到 ${results.length} 条记录`); - - results.forEach((row, index) => { - console.log(`\n记录${index + 1}:`); - console.log('ID:', row.id); - console.log('SN:', row.sn); - console.log('设备ID:', row.deviceId); - console.log('电量:', row.battery, '(类型:', typeof row.battery, ')'); - console.log('温度:', row.temperature, '(类型:', typeof row.temperature, ')'); - console.log('状态:', row.state); - console.log('经度:', row.longitude); - console.log('纬度:', row.latitude); - console.log('GPS状态:', row.gps_state); - console.log('RSRP:', row.rsrp); - console.log('佩戴状态:', row.bandge_status); - console.log('连接状态:', row.is_connect); - console.log('步数:', row.steps); - console.log('昨日步数:', row.y_steps); - console.log('更新时间:', row.uptime); - }); - - // 查询所有项圈的最新数据 - console.log('\n查询所有项圈的最新数据...'); - const [allResults] = await connection.execute(` - SELECT - id, sn, deviceId, battery, temperature, state, uptime - FROM iot_xq_client - ORDER BY uptime DESC - LIMIT 20 - `); - - console.log('所有项圈的最新数据:'); - allResults.forEach((row, index) => { - console.log(`${index + 1}. SN: ${row.sn}, 电量: ${row.battery}, 温度: ${row.temperature}, 状态: ${row.state}, 更新时间: ${row.uptime}`); - }); - - // 检查是否有电量为99的记录 - console.log('\n检查是否有电量为99的记录...'); - const [battery99Results] = await connection.execute(` - SELECT - id, sn, deviceId, battery, temperature, state, uptime - FROM iot_xq_client - WHERE battery = '99' OR battery = 99 - ORDER BY uptime DESC - LIMIT 10 - `); - - console.log(`找到 ${battery99Results.length} 条电量为99的记录`); - battery99Results.forEach((row, index) => { - console.log(`${index + 1}. SN: ${row.sn}, 电量: ${row.battery}, 温度: ${row.temperature}, 状态: ${row.state}`); - }); - - await connection.end(); - - } catch (error) { - console.error('❌ 检查失败:', error.message); - console.error('错误详情:', error); - } finally { - process.exit(0); - } -} - -// 运行检查 -checkCorrectDatabase().catch(console.error); diff --git a/backend/check-database-data.js b/backend/check-database-data.js deleted file mode 100644 index 7a68611..0000000 --- a/backend/check-database-data.js +++ /dev/null @@ -1,114 +0,0 @@ -/** - * 检查数据库原始数据 - * @file check-database-data.js - * @description 检查数据库中项圈22012000107的原始数据 - */ - -const { IotXqClient } = require('./models'); - -async function checkDatabaseData() { - console.log('🔍 检查数据库原始数据...\n'); - - try { - // 1. 查找项圈22012000107的所有记录 - console.log('1. 查找项圈22012000107的所有记录...'); - const devices = await IotXqClient.findAll({ - where: { - sn: '22012000107' - }, - order: [['uptime', 'DESC']] - }); - - console.log(`找到 ${devices.length} 条记录`); - - devices.forEach((device, index) => { - console.log(`\n第${index + 1}条记录:`); - console.log('ID:', device.id); - console.log('SN:', device.sn); - console.log('设备ID:', device.deviceId); - console.log('电量 (battery):', device.battery); - console.log('温度 (temperature):', device.temperature); - console.log('步数 (steps):', device.steps); - console.log('昨日步数 (y_steps):', device.y_steps); - console.log('状态 (state):', device.state); - console.log('佩戴状态 (bandge_status):', device.bandge_status); - console.log('更新时间 (uptime):', device.uptime); - console.log('创建时间 (createdAt):', device.createdAt); - console.log('更新时间 (updatedAt):', device.updatedAt); - }); - - // 2. 查找所有包含22012000107的记录 - console.log('\n2. 查找所有包含22012000107的记录...'); - const allDevices = await IotXqClient.findAll({ - where: { - [require('sequelize').Op.or]: [ - { sn: '22012000107' }, - { deviceId: '22012000107' }, - { sn: { [require('sequelize').Op.like]: '%22012000107%' } } - ] - }, - order: [['uptime', 'DESC']] - }); - - console.log(`找到 ${allDevices.length} 条相关记录`); - - allDevices.forEach((device, index) => { - console.log(`\n相关记录${index + 1}:`); - console.log('ID:', device.id); - console.log('SN:', device.sn); - console.log('设备ID:', device.deviceId); - console.log('电量:', device.battery); - console.log('温度:', device.temperature); - console.log('状态:', device.state); - console.log('更新时间:', device.uptime); - }); - - // 3. 检查最新的记录 - console.log('\n3. 检查最新的记录...'); - const latestDevice = await IotXqClient.findOne({ - where: { - sn: '22012000107' - }, - order: [['uptime', 'DESC']] - }); - - if (latestDevice) { - console.log('最新记录:'); - console.log('电量:', latestDevice.battery); - console.log('温度:', latestDevice.temperature); - console.log('更新时间:', latestDevice.uptime); - } else { - console.log('未找到最新记录'); - } - - // 4. 检查是否有电量为98的记录 - console.log('\n4. 检查是否有电量为98的记录...'); - const battery98Devices = await IotXqClient.findAll({ - where: { - battery: 98, - sn: '22012000107' - }, - order: [['uptime', 'DESC']] - }); - - console.log(`找到 ${battery98Devices.length} 条电量为98的记录`); - - battery98Devices.forEach((device, index) => { - console.log(`\n电量98记录${index + 1}:`); - console.log('ID:', device.id); - console.log('SN:', device.sn); - console.log('电量:', device.battery); - console.log('温度:', device.temperature); - console.log('更新时间:', device.uptime); - }); - - } catch (error) { - console.error('❌ 检查失败:', error.message); - console.error('错误详情:', error); - } finally { - process.exit(0); - } -} - -// 运行检查 -checkDatabaseData().catch(console.error); diff --git a/backend/check-other-databases.js b/backend/check-other-databases.js deleted file mode 100644 index cb39b13..0000000 --- a/backend/check-other-databases.js +++ /dev/null @@ -1,97 +0,0 @@ -/** - * 检查其他数据库 - * @file check-other-databases.js - * @description 检查其他数据库中是否有项圈22012000107的数据 - */ - -const mysql = require('mysql2/promise'); - -async function checkOtherDatabases() { - console.log('🔍 检查其他数据库中项圈22012000107的数据...\n'); - - const databases = ['nxxmdata', 'nxdata', 'datav', 'aipet_new']; - - for (const dbName of databases) { - try { - console.log(`\n=== 检查数据库: ${dbName} ===`); - - // 创建连接 - const connection = await mysql.createConnection({ - host: '192.168.0.240', - port: 3306, - user: 'root', - password: '', // 根据实际情况填写密码 - database: dbName - }); - - // 查询项圈22012000107的数据 - const [results] = await connection.execute(` - SELECT - id, sn, deviceId, battery, temperature, state, - uptime, longitude, latitude, gps_state, rsrp - FROM iot_xq_client - WHERE sn = '22012000107' - ORDER BY uptime DESC - LIMIT 5 - `); - - console.log(`找到 ${results.length} 条记录`); - - results.forEach((row, index) => { - console.log(`\n记录${index + 1}:`); - console.log('ID:', row.id); - console.log('SN:', row.sn); - console.log('设备ID:', row.deviceId); - console.log('电量:', row.battery); - console.log('温度:', row.temperature); - console.log('状态:', row.state); - console.log('经度:', row.longitude); - console.log('纬度:', row.latitude); - console.log('GPS状态:', row.gps_state); - console.log('RSRP:', row.rsrp); - console.log('更新时间:', row.uptime); - }); - - await connection.end(); - - } catch (error) { - console.log(`❌ 数据库 ${dbName} 检查失败:`, error.message); - } - } - - // 检查当前数据库的最新数据 - console.log('\n=== 检查当前数据库的最新数据 ==='); - try { - const connection = await mysql.createConnection({ - host: '192.168.0.240', - port: 3306, - user: 'root', - password: '', - database: 'nxxmdata' - }); - - // 查询所有项圈的最新数据 - const [allResults] = await connection.execute(` - SELECT - id, sn, deviceId, battery, temperature, state, uptime - FROM iot_xq_client - ORDER BY uptime DESC - LIMIT 20 - `); - - console.log('所有项圈的最新数据:'); - allResults.forEach((row, index) => { - console.log(`${index + 1}. SN: ${row.sn}, 电量: ${row.battery}, 温度: ${row.temperature}, 状态: ${row.state}, 更新时间: ${row.uptime}`); - }); - - await connection.end(); - - } catch (error) { - console.log('❌ 查询当前数据库失败:', error.message); - } - - process.exit(0); -} - -// 运行检查 -checkOtherDatabases().catch(console.error); diff --git a/backend/check-server-config.js b/backend/check-server-config.js deleted file mode 100644 index ed4965d..0000000 --- a/backend/check-server-config.js +++ /dev/null @@ -1,63 +0,0 @@ -/** - * 检查服务器配置 - * @file check-server-config.js - * @description 检查服务器使用的数据库配置 - */ - -const { IotXqClient } = require('./models'); - -async function checkServerConfig() { - console.log('🔍 检查服务器配置...\n'); - - try { - // 1. 检查数据库配置 - console.log('1. 检查数据库配置...'); - const config = IotXqClient.sequelize.config; - console.log('数据库配置:'); - console.log('主机:', config.host); - console.log('端口:', config.port); - console.log('数据库名:', config.database); - console.log('用户名:', config.username); - - // 2. 测试连接 - console.log('\n2. 测试数据库连接...'); - await IotXqClient.sequelize.authenticate(); - console.log('✅ 数据库连接成功'); - - // 3. 查询项圈22012000107的数据 - console.log('\n3. 查询项圈22012000107的数据...'); - const devices = await IotXqClient.findAll({ - where: { - sn: '22012000107' - }, - order: [['uptime', 'DESC']] - }); - - console.log(`找到 ${devices.length} 条记录`); - - devices.forEach((device, index) => { - console.log(`\n记录${index + 1}:`); - console.log('ID:', device.id); - console.log('SN:', device.sn); - console.log('电量:', device.battery); - console.log('温度:', device.temperature); - console.log('状态:', device.state); - console.log('更新时间:', device.uptime); - }); - - // 4. 检查环境变量 - console.log('\n4. 检查环境变量...'); - console.log('DB_HOST:', process.env.DB_HOST); - console.log('DB_PORT:', process.env.DB_PORT); - console.log('DB_PASSWORD:', process.env.DB_PASSWORD); - - } catch (error) { - console.error('❌ 检查失败:', error.message); - console.error('错误详情:', error); - } finally { - process.exit(0); - } -} - -// 运行检查 -checkServerConfig().catch(console.error); diff --git a/backend/check-server-env.js b/backend/check-server-env.js deleted file mode 100644 index bfee92e..0000000 --- a/backend/check-server-env.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * 检查服务器环境变量 - * @file check-server-env.js - * @description 检查服务器进程的环境变量 - */ - -const { spawn } = require('child_process'); - -// 启动服务器并检查环境变量 -const server = spawn('node', ['server.js'], { - env: { - ...process.env, - DB_HOST: '129.211.213.226', - DB_PORT: '9527', - DB_PASSWORD: 'aiotAiot123!' - }, - stdio: ['pipe', 'pipe', 'pipe'] -}); - -let output = ''; - -server.stdout.on('data', (data) => { - output += data.toString(); - console.log('服务器输出:', data.toString()); -}); - -server.stderr.on('data', (data) => { - console.error('服务器错误:', data.toString()); -}); - -server.on('close', (code) => { - console.log(`服务器进程退出,代码: ${code}`); -}); - -// 等待服务器启动 -setTimeout(() => { - console.log('\n检查服务器环境变量...'); - console.log('DB_HOST:', process.env.DB_HOST); - console.log('DB_PORT:', process.env.DB_PORT); - console.log('DB_PASSWORD:', process.env.DB_PASSWORD); - - // 测试API - const axios = require('axios'); - axios.get('http://localhost:5350/api/smart-alerts/public/collar?search=22012000107&limit=1') - .then(response => { - console.log('\nAPI测试结果:'); - if (response.data.success && response.data.data.length > 0) { - const collar = response.data.data[0]; - console.log('项圈编号:', collar.collarNumber); - console.log('电量:', collar.battery); - console.log('温度:', collar.temperature); - } - }) - .catch(error => { - console.error('API测试失败:', error.message); - }) - .finally(() => { - server.kill(); - process.exit(0); - }); -}, 5000); diff --git a/backend/check-specific-collar.js b/backend/check-specific-collar.js deleted file mode 100644 index 9c14447..0000000 --- a/backend/check-specific-collar.js +++ /dev/null @@ -1,118 +0,0 @@ -/** - * 检查特定项圈数据 - * @file check-specific-collar.js - * @description 检查项圈编号22012000107的数据 - */ - -const axios = require('axios'); - -const BASE_URL = 'http://localhost:5350/api/smart-alerts/public'; - -async function checkSpecificCollar() { - console.log('🔍 检查项圈编号22012000107的数据...\n'); - - try { - // 1. 搜索特定项圈编号 - console.log('1. 搜索项圈编号22012000107...'); - const searchResponse = await axios.get(`${BASE_URL}/collar`, { - params: { - search: '22012000107', - page: 1, - limit: 10 - } - }); - - if (searchResponse.data.success) { - const data = searchResponse.data.data || []; - console.log(`找到 ${data.length} 条相关数据`); - - data.forEach((item, index) => { - console.log(`\n第${index + 1}条数据:`); - console.log('原始API数据:', { - id: item.id, - collarNumber: item.collarNumber, - battery: item.battery, - batteryLevel: item.batteryLevel, - temperature: item.temperature, - temp: item.temp, - alertType: item.alertType, - alertLevel: item.alertLevel, - alertTime: item.alertTime, - dailySteps: item.dailySteps, - steps: item.steps - }); - - // 模拟前端转换逻辑 - const transformedData = { - id: item.id || `${item.deviceId || item.sn}_${item.alertType || 'normal'}`, - collarNumber: item.collarNumber || item.sn || item.deviceId || '', - battery: item.battery || item.batteryLevel || '', - temperature: item.temperature || item.temp || '', - dailySteps: item.dailySteps || item.steps || '' - }; - - console.log('前端转换后:', transformedData); - }); - - } else { - console.log('❌ 搜索失败:', searchResponse.data.message); - } - - // 2. 获取所有数据并查找特定项圈 - console.log('\n2. 获取所有数据查找特定项圈...'); - const allResponse = await axios.get(`${BASE_URL}/collar`, { - params: { page: 1, limit: 100 } - }); - - if (allResponse.data.success) { - const allData = allResponse.data.data || []; - const specificCollars = allData.filter(item => - item.collarNumber == 22012000107 || - item.deviceName == 22012000107 || - item.sn == 22012000107 - ); - - console.log(`在所有数据中找到 ${specificCollars.length} 条项圈22012000107的数据`); - - specificCollars.forEach((item, index) => { - console.log(`\n项圈22012000107 - 第${index + 1}条:`); - console.log('ID:', item.id); - console.log('项圈编号:', item.collarNumber); - console.log('设备名称:', item.deviceName); - console.log('电量字段1 (battery):', item.battery); - console.log('电量字段2 (batteryLevel):', item.batteryLevel); - console.log('温度字段1 (temperature):', item.temperature); - console.log('温度字段2 (temp):', item.temp); - console.log('预警类型:', item.alertType); - console.log('预警级别:', item.alertLevel); - console.log('预警时间:', item.alertTime); - console.log('步数字段1 (dailySteps):', item.dailySteps); - console.log('步数字段2 (steps):', item.steps); - console.log('总步数:', item.totalSteps); - console.log('昨日步数:', item.yesterdaySteps); - }); - - } else { - console.log('❌ 获取所有数据失败:', allResponse.data.message); - } - - // 3. 检查数据库原始数据 - console.log('\n3. 检查数据库原始数据...'); - console.log('请检查数据库中项圈22012000107的原始数据'); - console.log('可能需要检查以下字段:'); - console.log('- battery_level 或 battery 字段'); - console.log('- temperature 或 temp 字段'); - console.log('- 数据更新时间'); - console.log('- 是否有多个记录'); - - } catch (error) { - console.error('❌ 检查失败:', error.message); - if (error.response) { - console.error('响应状态:', error.response.status); - console.error('响应数据:', error.response.data); - } - } -} - -// 运行检查 -checkSpecificCollar().catch(console.error); diff --git a/backend/configure-firewall.bat b/backend/configure-firewall.bat deleted file mode 100644 index c6cf1fd..0000000 --- a/backend/configure-firewall.bat +++ /dev/null @@ -1,61 +0,0 @@ -@echo off -echo 正在配置Windows防火墙以允许外部访问... -echo. - -REM 检查是否以管理员身份运行 -net session >nul 2>&1 -if %errorLevel% == 0 ( - echo 检测到管理员权限,继续配置... -) else ( - echo 错误:请以管理员身份运行此脚本 - echo 右键点击此文件,选择"以管理员身份运行" - pause - exit /b 1 -) - -echo. -echo 添加防火墙规则... - -REM 允许前端端口5300 -netsh advfirewall firewall add rule name="Node.js Frontend Port 5300" dir=in action=allow protocol=TCP localport=5300 -if %errorLevel% == 0 ( - echo ✅ 前端端口5300规则添加成功 -) else ( - echo ⚠️ 前端端口5300规则可能已存在 -) - -REM 允许后端端口5350 -netsh advfirewall firewall add rule name="Node.js Backend Port 5350" dir=in action=allow protocol=TCP localport=5350 -if %errorLevel% == 0 ( - echo ✅ 后端端口5350规则添加成功 -) else ( - echo ⚠️ 后端端口5350规则可能已存在 -) - -REM 允许Node.js程序 -netsh advfirewall firewall add rule name="Node.js Program" dir=in action=allow program="C:\Program Files\nodejs\node.exe" enable=yes -if %errorLevel% == 0 ( - echo ✅ Node.js程序规则添加成功 -) else ( - echo ⚠️ Node.js程序规则可能已存在 -) - -echo. -echo 检查已添加的规则... -netsh advfirewall firewall show rule name="Node.js Frontend Port 5300" -echo. -netsh advfirewall firewall show rule name="Node.js Backend Port 5350" -echo. - -echo 🎉 防火墙配置完成! -echo. -echo 现在其他用户可以通过以下地址访问您的服务: -echo 前端: http://172.28.112.1:5300 -echo 后端: http://172.28.112.1:5350 -echo. -echo 请确保: -echo 1. 服务器正在运行 -echo 2. 其他用户与您在同一个局域网内 -echo 3. 使用正确的IP地址(不是localhost) -echo. -pause diff --git a/backend/configure-firewall.ps1 b/backend/configure-firewall.ps1 deleted file mode 100644 index 9b18414..0000000 --- a/backend/configure-firewall.ps1 +++ /dev/null @@ -1,78 +0,0 @@ -# PowerShell防火墙配置脚本 -# 解决外部用户无法访问开发服务器的问题 - -Write-Host "🔧 正在配置Windows防火墙以允许外部访问..." -ForegroundColor Green -Write-Host "" - -# 检查是否以管理员身份运行 -if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { - Write-Host "❌ 错误:请以管理员身份运行此脚本" -ForegroundColor Red - Write-Host "右键点击此文件,选择'以管理员身份运行'" -ForegroundColor Yellow - Read-Host "按任意键退出" - exit 1 -} - -Write-Host "✅ 检测到管理员权限,继续配置..." -ForegroundColor Green -Write-Host "" - -# 配置防火墙规则 -Write-Host "添加防火墙规则..." -ForegroundColor Cyan - -# 允许前端端口5300 -try { - New-NetFirewallRule -DisplayName "Node.js Frontend Port 5300" -Direction Inbound -Protocol TCP -LocalPort 5300 -Action Allow -ErrorAction SilentlyContinue - Write-Host "✅ 前端端口5300规则添加成功" -ForegroundColor Green -} catch { - Write-Host "⚠️ 前端端口5300规则可能已存在" -ForegroundColor Yellow -} - -# 允许后端端口5350 -try { - New-NetFirewallRule -DisplayName "Node.js Backend Port 5350" -Direction Inbound -Protocol TCP -LocalPort 5350 -Action Allow -ErrorAction SilentlyContinue - Write-Host "✅ 后端端口5350规则添加成功" -ForegroundColor Green -} catch { - Write-Host "⚠️ 后端端口5350规则可能已存在" -ForegroundColor Yellow -} - -# 允许Node.js程序 -try { - $nodePath = "C:\Program Files\nodejs\node.exe" - if (Test-Path $nodePath) { - New-NetFirewallRule -DisplayName "Node.js Program" -Direction Inbound -Program $nodePath -Action Allow -ErrorAction SilentlyContinue - Write-Host "✅ Node.js程序规则添加成功" -ForegroundColor Green - } else { - Write-Host "⚠️ 未找到Node.js程序路径,跳过程序规则" -ForegroundColor Yellow - } -} catch { - Write-Host "⚠️ Node.js程序规则可能已存在" -ForegroundColor Yellow -} - -Write-Host "" -Write-Host "检查已添加的规则..." -ForegroundColor Cyan - -# 显示规则 -Get-NetFirewallRule -DisplayName "*Node.js*" | Format-Table DisplayName, Direction, Action, Enabled -AutoSize - -Write-Host "" -Write-Host "🎉 防火墙配置完成!" -ForegroundColor Green -Write-Host "" -Write-Host "现在其他用户可以通过以下地址访问您的服务:" -ForegroundColor Yellow -Write-Host "前端: http://172.28.112.1:5300" -ForegroundColor White -Write-Host "后端: http://172.28.112.1:5350" -ForegroundColor White -Write-Host "" -Write-Host "请确保:" -ForegroundColor Yellow -Write-Host "1. 服务器正在运行" -ForegroundColor White -Write-Host "2. 其他用户与您在同一个局域网内" -ForegroundColor White -Write-Host "3. 使用正确的IP地址(不是localhost)" -ForegroundColor White -Write-Host "" - -# 获取所有可用的IP地址 -Write-Host "可用的访问地址:" -ForegroundColor Cyan -$networkAdapters = Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -notlike "127.*" -and $_.IPAddress -notlike "169.254.*" } -foreach ($adapter in $networkAdapters) { - Write-Host " 前端: http://$($adapter.IPAddress):5300" -ForegroundColor White - Write-Host " 后端: http://$($adapter.IPAddress):5350" -ForegroundColor White -} - -Write-Host "" -Read-Host "按任意键退出" diff --git a/backend/debug-startup.js b/backend/debug-startup.js deleted file mode 100644 index 30eaf06..0000000 --- a/backend/debug-startup.js +++ /dev/null @@ -1,35 +0,0 @@ -console.log('开始调试启动过程...'); - -try { - console.log('1. 加载数据库配置...'); - const { sequelize } = require('./config/database-simple'); - console.log('✓ 数据库配置加载成功'); - - console.log('2. 加载模型...'); - const models = require('./models'); - console.log('✓ 模型加载成功'); - - console.log('3. 测试数据库连接...'); - sequelize.authenticate().then(() => { - console.log('✓ 数据库连接成功'); - console.log('4. 测试用户查询...'); - return models.User.findByPk(1); - }).then(user => { - if (user) { - console.log('✓ 用户查询成功:', user.username); - } else { - console.log('⚠ 未找到用户'); - } - console.log('调试完成,所有测试通过'); - process.exit(0); - }).catch(error => { - console.error('❌ 错误:', error.message); - console.error('堆栈:', error.stack); - process.exit(1); - }); - -} catch (error) { - console.error('❌ 启动失败:', error.message); - console.error('堆栈:', error.stack); - process.exit(1); -} diff --git a/backend/demo-ngrok.bat b/backend/demo-ngrok.bat deleted file mode 100644 index 43cf86e..0000000 --- a/backend/demo-ngrok.bat +++ /dev/null @@ -1,43 +0,0 @@ -@echo off -echo ======================================== -echo ngrok外网访问演示脚本 -echo ======================================== -echo. - -echo 步骤1:检查ngrok是否已配置认证 -.\ngrok.exe config check -echo. - -echo 步骤2:如果没有配置,请先运行以下命令: -echo .\ngrok.exe authtoken YOUR_AUTH_TOKEN -echo. - -echo 步骤3:启动后端服务穿透 -echo 正在启动ngrok... -echo 请在新窗口中查看访问地址 -echo. - -start "ngrok-backend" .\ngrok.exe http 5350 - -echo. -echo 步骤4:等待3秒后启动前端服务穿透 -timeout /t 3 /nobreak >nul - -start "ngrok-frontend" .\ngrok.exe http 5300 - -echo. -echo ======================================== -echo ngrok已启动! -echo ======================================== -echo. -echo 请查看两个新打开的窗口: -echo 1. ngrok-backend 窗口:显示后端访问地址 -echo 2. ngrok-frontend 窗口:显示前端访问地址 -echo. -echo 访问地址格式: -echo - 后端:https://xxxxx.ngrok.io -echo - 前端:https://yyyyy.ngrok.io -echo - API文档:https://xxxxx.ngrok.io/api-docs -echo. -echo 按任意键退出... -pause >nul diff --git a/backend/fix-line-endings.sh b/backend/fix-line-endings.sh new file mode 100644 index 0000000..91eab9e --- /dev/null +++ b/backend/fix-line-endings.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# 修复行尾符问题的脚本 + +echo "修复 node_manager.sh 的行尾符..." + +# 方法1: 使用 sed (推荐) +sed -i 's/\r$//' node_manager.sh + +# 设置执行权限 +chmod +x node_manager.sh + +echo "修复完成!" +echo "现在可以运行: ./node_manager.sh start" + diff --git a/backend/node_manager.ps1 b/backend/node_manager.ps1 new file mode 100644 index 0000000..99d8787 --- /dev/null +++ b/backend/node_manager.ps1 @@ -0,0 +1,289 @@ +# Node.js 服务管理脚本 - 宁夏智慧养殖监管平台后端 (Windows版本) +# 使用方法: .\node_manager.ps1 [start|stop|restart|status] + +param( + [Parameter(Mandatory=$false)] + [ValidateSet('start','stop','restart','status','logs')] + [string]$Action = 'status' +) + +# 配置区域 +$APP_NAME = "nxxmdata-backend" +$ENTRY_FILE = "server.js" +$APP_PORT = 5350 +$LOG_DIR = "logs" +$LOG_FILE = Join-Path $LOG_DIR "$APP_NAME.log" +$PID_FILE = "pid.$APP_NAME" +$NODE_ENV = "production" + +# 创建日志目录 +if (-not (Test-Path $LOG_DIR)) { + New-Item -ItemType Directory -Path $LOG_DIR | Out-Null + Write-Host "已创建日志目录: $LOG_DIR" -ForegroundColor Green +} + +# 检查 Node.js 是否安装 +try { + $nodeVersion = node --version + Write-Host "Node.js 版本: $nodeVersion" -ForegroundColor Green +} catch { + Write-Host "错误: Node.js 未安装或不在 PATH 中" -ForegroundColor Red + exit 1 +} + +# 检查入口文件是否存在 +if (-not (Test-Path $ENTRY_FILE)) { + Write-Host "错误: 入口文件 $ENTRY_FILE 不存在" -ForegroundColor Red + exit 1 +} + +# 停止服务函数 +function Stop-App { + Write-Host "正在停止服务: $APP_NAME" -ForegroundColor Yellow + + # 查找占用端口的进程 + $processes = Get-NetTCPConnection -LocalPort $APP_PORT -ErrorAction SilentlyContinue | + Select-Object -ExpandProperty OwningProcess -Unique + + if ($processes) { + foreach ($pid in $processes) { + try { + $process = Get-Process -Id $pid -ErrorAction SilentlyContinue + if ($process -and $process.ProcessName -eq "node") { + Write-Host "找到进程 PID: $pid,正在停止..." -ForegroundColor Yellow + Stop-Process -Id $pid -Force + Write-Host "服务已停止 (PID: $pid)" -ForegroundColor Green + } + } catch { + Write-Host "停止进程失败: $_" -ForegroundColor Red + } + } + + # 清理 PID 文件 + if (Test-Path $PID_FILE) { + Remove-Item $PID_FILE -Force + } + } else { + Write-Host "未找到运行中的服务 (端口 $APP_PORT 未被占用)" -ForegroundColor Yellow + } +} + +# 启动服务函数 +function Start-App { + Write-Host "正在启动服务: $APP_NAME" -ForegroundColor Yellow + + # 检查端口是否被占用 + $portCheck = Get-NetTCPConnection -LocalPort $APP_PORT -ErrorAction SilentlyContinue + if ($portCheck) { + $pid = $portCheck | Select-Object -First 1 -ExpandProperty OwningProcess + Write-Host "错误: 端口 $APP_PORT 已被占用 (PID: $pid)" -ForegroundColor Red + Write-Host "请先停止占用端口的进程或使用 restart 命令" -ForegroundColor Yellow + return + } + + # 检查 .env 文件是否存在 + if (-not (Test-Path ".env")) { + Write-Host "警告: .env 文件不存在,将使用默认配置" -ForegroundColor Yellow + Write-Host "建议从 env.example 复制并配置 .env 文件" -ForegroundColor Yellow + } + + # 检查 node_modules 是否存在 + if (-not (Test-Path "node_modules")) { + Write-Host "错误: node_modules 目录不存在" -ForegroundColor Red + Write-Host "请先运行: npm install" -ForegroundColor Yellow + return + } + + # 启动 Node.js 应用 + Write-Host "启动命令: node $ENTRY_FILE" -ForegroundColor Cyan + + # 设置环境变量并启动 + $env:NODE_ENV = $NODE_ENV + + # 使用 Start-Process 启动后台进程 + $processInfo = Start-Process -FilePath "node" ` + -ArgumentList $ENTRY_FILE ` + -RedirectStandardOutput $LOG_FILE ` + -RedirectStandardError $LOG_FILE ` + -WindowStyle Hidden ` + -PassThru + + if ($processInfo) { + $PID = $processInfo.Id + $PID | Out-File -FilePath $PID_FILE -Encoding ASCII + + Write-Host "等待服务启动..." -ForegroundColor Yellow + Start-Sleep -Seconds 3 + + # 验证启动是否成功 + if (Get-Process -Id $PID -ErrorAction SilentlyContinue) { + Write-Host "========================================" -ForegroundColor Green + Write-Host "服务启动成功!" -ForegroundColor Green + Write-Host "========================================" -ForegroundColor Green + Write-Host "应用名称: $APP_NAME" + Write-Host "进程 ID: $PID" + Write-Host "监听端口: $APP_PORT" + Write-Host "日志文件: $LOG_FILE" + Write-Host "PID 文件: $PID_FILE" + Write-Host "环境变量: NODE_ENV=$NODE_ENV" + Write-Host "API 文档: http://localhost:${APP_PORT}/api-docs" -ForegroundColor Cyan + + # 检查端口监听状态 + Start-Sleep -Seconds 2 + $portCheck = Get-NetTCPConnection -LocalPort $APP_PORT -ErrorAction SilentlyContinue + if ($portCheck) { + Write-Host "✓ 端口 $APP_PORT 正在监听" -ForegroundColor Green + } else { + Write-Host "⚠ 端口 $APP_PORT 尚未监听,请检查日志" -ForegroundColor Yellow + } + + # 显示最近的日志 + Write-Host "" + Write-Host "最近的启动日志:" -ForegroundColor Yellow + Write-Host "------------------------" + if (Test-Path $LOG_FILE) { + Get-Content $LOG_FILE -Tail 20 -ErrorAction SilentlyContinue + } + } else { + Write-Host "========================================" -ForegroundColor Red + Write-Host "服务启动失败!" -ForegroundColor Red + Write-Host "========================================" -ForegroundColor Red + Write-Host "请检查日志文件: $LOG_FILE" -ForegroundColor Yellow + + if (Test-Path $LOG_FILE) { + Write-Host "" + Write-Host "最近的错误日志:" -ForegroundColor Yellow + Write-Host "------------------------" + Get-Content $LOG_FILE -Tail 30 -ErrorAction SilentlyContinue + } + + if (Test-Path $PID_FILE) { + Remove-Item $PID_FILE -Force + } + exit 1 + } + } else { + Write-Host "启动进程失败!" -ForegroundColor Red + exit 1 + } +} + +# 重启服务函数 +function Restart-App { + Write-Host "正在重启服务: $APP_NAME" -ForegroundColor Yellow + Stop-App + Start-Sleep -Seconds 2 + Start-App +} + +# 状态检查函数 +function Get-AppStatus { + Write-Host "检查服务状态: $APP_NAME" -ForegroundColor Yellow + Write-Host "========================================" + + # 检查端口占用 + $portCheck = Get-NetTCPConnection -LocalPort $APP_PORT -ErrorAction SilentlyContinue + + if ($portCheck) { + $pid = $portCheck | Select-Object -First 1 -ExpandProperty OwningProcess + $process = Get-Process -Id $pid -ErrorAction SilentlyContinue + + if ($process -and $process.ProcessName -eq "node") { + Write-Host "✓ 服务正在运行" -ForegroundColor Green + Write-Host "----------------------------------------" + Write-Host "进程 ID: $pid" + Write-Host "进程名称: $($process.ProcessName)" + Write-Host "应用名称: $APP_NAME" + Write-Host "监听端口: $APP_PORT" + Write-Host "启动时间: $($process.StartTime)" + + # 内存使用 (转换为 MB) + $memoryMB = [math]::Round($process.WorkingSet64 / 1MB, 2) + Write-Host "内存使用: $memoryMB MB" + + # CPU时间 + Write-Host "CPU 时间: $($process.CPU) 秒" + + # 端口状态 + Write-Host "端口状态: 监听中 ($APP_PORT)" -ForegroundColor Green + + # 日志文件信息 + if (Test-Path $LOG_FILE) { + $logSize = [math]::Round((Get-Item $LOG_FILE).Length / 1KB, 2) + Write-Host "日志大小: $logSize KB" + Write-Host "日志文件: $LOG_FILE" + } + + Write-Host "" + Write-Host "最近的日志 (最后10行):" -ForegroundColor Yellow + Write-Host "----------------------------------------" + if (Test-Path $LOG_FILE) { + Get-Content $LOG_FILE -Tail 10 -ErrorAction SilentlyContinue + } else { + Write-Host "无法读取日志文件" + } + } else { + Write-Host "⚠ 端口 $APP_PORT 被其他进程占用 (PID: $pid)" -ForegroundColor Yellow + Write-Host "进程名称: $($process.ProcessName)" + } + } else { + Write-Host "✗ 服务未运行" -ForegroundColor Red + Write-Host "使用以下命令启动: .\node_manager.ps1 start" + } + + Write-Host "========================================" +} + +# 查看日志函数 +function View-Logs { + if (Test-Path $LOG_FILE) { + Write-Host "实时查看日志 (Ctrl+C 退出):" -ForegroundColor Yellow + Get-Content $LOG_FILE -Wait -Tail 20 + } else { + Write-Host "日志文件不存在: $LOG_FILE" -ForegroundColor Red + } +} + +# 主逻辑 +switch ($Action.ToLower()) { + 'start' { + Start-App + } + 'stop' { + Stop-App + } + 'restart' { + Restart-App + } + 'status' { + Get-AppStatus + } + 'logs' { + View-Logs + } + default { + Write-Host "========================================" + Write-Host "宁夏智慧养殖监管平台 - 服务管理脚本 (Windows)" + Write-Host "========================================" + Write-Host "使用方法: .\node_manager.ps1 [start|stop|restart|status|logs]" + Write-Host "" + Write-Host "命令说明:" + Write-Host " start - 启动服务" + Write-Host " stop - 停止服务" + Write-Host " restart - 重启服务" + Write-Host " status - 查看服务状态" + Write-Host " logs - 实时查看日志" + Write-Host "" + Write-Host "配置信息:" + Write-Host " 应用名称: $APP_NAME" + Write-Host " 入口文件: $ENTRY_FILE" + Write-Host " 监听端口: $APP_PORT" + Write-Host " 日志文件: $LOG_FILE" + Write-Host "" + Write-Host "示例:" + Write-Host " .\node_manager.ps1 start # 启动服务" + Write-Host " .\node_manager.ps1 status # 查看状态" + Write-Host " .\node_manager.ps1 logs # 查看日志" + } +} + diff --git a/backend/node_manager.sh b/backend/node_manager.sh new file mode 100644 index 0000000..855b869 --- /dev/null +++ b/backend/node_manager.sh @@ -0,0 +1,328 @@ +#!/bin/bash + +# Node.js 服务管理脚本 - 宁夏智慧养殖监管平台后端 +# 使用方法: ./node_manager.sh [start|stop|restart|status] + +# 配置区域 +APP_NAME="nxxmdata-backend" +ENTRY_FILE="server.js" +APP_PORT="5350" +LOG_DIR="logs" +LOG_FILE="${LOG_DIR}/${APP_NAME}.log" +PID_FILE="pid.${APP_NAME}" +NODE_ENV="production" + +# 颜色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# 创建日志目录 +if [ ! -d "$LOG_DIR" ]; then + mkdir -p "$LOG_DIR" + echo "已创建日志目录: $LOG_DIR" +fi + +# 检查 Node.js 是否安装 +if ! command -v node &> /dev/null; then + echo -e "${RED}错误: Node.js 未安装或不在 PATH 中${NC}" + exit 1 +fi + +# 检查入口文件是否存在 +if [ ! -f "$ENTRY_FILE" ]; then + echo -e "${RED}错误: 入口文件 $ENTRY_FILE 不存在${NC}" + exit 1 +fi + +# 显示 Node.js 版本信息 +NODE_VERSION=$(node --version) +echo -e "${GREEN}Node.js 版本: $NODE_VERSION${NC}" + +# 停止服务函数 +function stopApp() { + echo -e "${YELLOW}正在停止服务: $APP_NAME${NC}" + + # 从 PID 文件读取进程 ID + if [ -f "$PID_FILE" ]; then + PID=$(cat "$PID_FILE") + if ps -p $PID > /dev/null 2>&1; then + echo "找到进程 PID: $PID,正在停止..." + kill -TERM $PID + + # 等待进程优雅退出 + for i in {1..10}; do + if ! ps -p $PID > /dev/null 2>&1; then + echo -e "${GREEN}服务已优雅停止${NC}" + rm -f "$PID_FILE" + return 0 + fi + sleep 1 + done + + # 如果优雅停止失败,强制杀死 + echo -e "${YELLOW}优雅停止失败,强制终止进程${NC}" + kill -9 $PID + rm -f "$PID_FILE" + else + echo "PID 文件存在但进程不存在,清理 PID 文件" + rm -f "$PID_FILE" + fi + else + # 如果没有 PID 文件,尝试通过端口查找 + PID=$(lsof -ti:$APP_PORT 2>/dev/null) + if [ -n "$PID" ]; then + echo "通过端口 $APP_PORT 找到 PID: $PID,正在停止..." + kill -TERM $PID + sleep 2 + if ps -p $PID > /dev/null 2>&1; then + kill -9 $PID + fi + echo -e "${GREEN}服务已停止${NC}" + else + echo -e "${YELLOW}未找到运行中的服务: $APP_NAME${NC}" + fi + fi +} + +# 启动服务函数 +function startApp() { + echo -e "${YELLOW}正在启动服务: $APP_NAME${NC}" + + # 检查服务是否已经运行 + if [ -f "$PID_FILE" ]; then + PID=$(cat "$PID_FILE") + if ps -p $PID > /dev/null 2>&1; then + echo -e "${YELLOW}服务已在运行中 (PID: $PID)${NC}" + return 0 + else + echo "PID 文件存在但进程不存在,清理后重新启动" + rm -f "$PID_FILE" + fi + fi + + # 检查端口是否被占用 + if command -v lsof &> /dev/null; then + PORT_CHECK=$(lsof -ti:$APP_PORT 2>/dev/null) + if [ -n "$PORT_CHECK" ]; then + echo -e "${RED}错误: 端口 $APP_PORT 已被占用 (PID: $PORT_CHECK)${NC}" + echo "请先停止占用端口的进程或使用 restart 命令" + return 1 + fi + fi + + # 检查 .env 文件是否存在 + if [ ! -f ".env" ]; then + echo -e "${YELLOW}警告: .env 文件不存在,将使用默认配置${NC}" + echo "建议从 env.example 复制并配置 .env 文件" + fi + + # 检查 node_modules 是否存在 + if [ ! -d "node_modules" ]; then + echo -e "${RED}错误: node_modules 目录不存在${NC}" + echo "请先运行: npm install" + return 1 + fi + + # 启动 Node.js 应用 + echo "启动命令: NODE_ENV=$NODE_ENV nohup node $ENTRY_FILE > $LOG_FILE 2>&1 &" + NODE_ENV=$NODE_ENV nohup node $ENTRY_FILE > $LOG_FILE 2>&1 & + + # 获取新进程的 PID + PID=$! + echo $PID > "$PID_FILE" + + # 等待应用启动 + echo "等待服务启动..." + sleep 3 + + # 验证启动是否成功 + if ps -p $PID > /dev/null 2>&1; then + echo -e "${GREEN}========================================${NC}" + echo -e "${GREEN}服务启动成功!${NC}" + echo -e "${GREEN}========================================${NC}" + echo "应用名称: $APP_NAME" + echo "进程 ID: $PID" + echo "监听端口: $APP_PORT" + echo "日志文件: $LOG_FILE" + echo "PID 文件: $PID_FILE" + echo "环境变量: NODE_ENV=$NODE_ENV" + echo -e "${GREEN}API 文档: http://localhost:$APP_PORT/api-docs${NC}" + echo "" + + # 等待端口监听 + echo "检查端口监听状态..." + sleep 2 + if command -v lsof &> /dev/null; then + if lsof -ti:$APP_PORT > /dev/null 2>&1; then + echo -e "${GREEN}✓ 端口 $APP_PORT 正在监听${NC}" + else + echo -e "${YELLOW}⚠ 端口 $APP_PORT 尚未监听,请检查日志${NC}" + fi + fi + + # 显示最近的日志 + echo "" + echo "最近的启动日志:" + echo "------------------------" + tail -20 "$LOG_FILE" + else + echo -e "${RED}========================================${NC}" + echo -e "${RED}服务启动失败!${NC}" + echo -e "${RED}========================================${NC}" + echo "请检查日志文件: $LOG_FILE" + echo "" + echo "最近的错误日志:" + echo "------------------------" + tail -30 "$LOG_FILE" + rm -f "$PID_FILE" + exit 1 + fi +} + +# 重启服务函数 +function restartApp() { + echo -e "${YELLOW}正在重启服务: $APP_NAME${NC}" + stopApp + sleep 3 + startApp +} + +# 状态检查函数 +function statusApp() { + echo -e "${YELLOW}检查服务状态: $APP_NAME${NC}" + echo "========================================" + + if [ -f "$PID_FILE" ]; then + PID=$(cat "$PID_FILE") + if ps -p $PID > /dev/null 2>&1; then + echo -e "${GREEN}✓ 服务正在运行${NC}" + echo "----------------------------------------" + echo "进程 ID: $PID" + echo "应用名称: $APP_NAME" + echo "监听端口: $APP_PORT" + + # 启动时间 + if command -v ps &> /dev/null; then + START_TIME=$(ps -o lstart= -p $PID 2>/dev/null) + if [ -n "$START_TIME" ]; then + echo "启动时间: $START_TIME" + fi + + # 内存使用 + MEM_USAGE=$(ps -o rss= -p $PID 2>/dev/null | awk '{printf "%.2f MB", $1/1024}') + if [ -n "$MEM_USAGE" ]; then + echo "内存使用: $MEM_USAGE" + fi + + # CPU使用率 + CPU_USAGE=$(ps -o %cpu= -p $PID 2>/dev/null) + if [ -n "$CPU_USAGE" ]; then + echo "CPU 使用: ${CPU_USAGE}%" + fi + fi + + # 检查端口监听状态 + if command -v lsof &> /dev/null; then + PORT_INFO=$(lsof -ti:$APP_PORT 2>/dev/null) + if [ -n "$PORT_INFO" ]; then + echo -e "端口状态: ${GREEN}监听中 ($APP_PORT)${NC}" + else + echo -e "端口状态: ${RED}未监听${NC}" + fi + fi + + # 日志文件信息 + if [ -f "$LOG_FILE" ]; then + LOG_SIZE=$(du -h "$LOG_FILE" | cut -f1) + echo "日志大小: $LOG_SIZE" + echo "日志文件: $LOG_FILE" + fi + + echo "" + echo "最近的日志 (最后10行):" + echo "----------------------------------------" + tail -10 "$LOG_FILE" 2>/dev/null || echo "无法读取日志文件" + + else + echo -e "${RED}✗ 服务未运行 (PID 文件存在但进程不存在)${NC}" + echo "建议清理 PID 文件: rm -f $PID_FILE" + fi + else + # 通过端口检查 + if command -v lsof &> /dev/null; then + PID=$(lsof -ti:$APP_PORT 2>/dev/null) + if [ -n "$PID" ]; then + echo -e "${YELLOW}⚠ 服务正在运行但未通过脚本管理${NC}" + echo "进程 ID: $PID" + echo "监听端口: $APP_PORT" + echo "建议使用: ./node_manager.sh stop 停止服务后重新启动" + else + echo -e "${RED}✗ 服务未运行${NC}" + echo "使用以下命令启动: ./node_manager.sh start" + fi + else + echo -e "${RED}✗ 服务未运行 (PID 文件不存在)${NC}" + echo "使用以下命令启动: ./node_manager.sh start" + fi + fi + echo "========================================" +} + +# 查看日志函数 +function viewLogs() { + if [ -f "$LOG_FILE" ]; then + echo -e "${YELLOW}实时查看日志 (Ctrl+C 退出):${NC}" + tail -f "$LOG_FILE" + else + echo -e "${RED}日志文件不存在: $LOG_FILE${NC}" + fi +} + +# 主逻辑 +case "$1" in + start) + startApp + ;; + stop) + stopApp + ;; + restart) + restartApp + ;; + status) + statusApp + ;; + logs) + viewLogs + ;; + *) + echo "========================================" + echo "宁夏智慧养殖监管平台 - 服务管理脚本" + echo "========================================" + echo "使用方法: $0 {start|stop|restart|status|logs}" + echo "" + echo "命令说明:" + echo " start - 启动服务" + echo " stop - 停止服务" + echo " restart - 重启服务" + echo " status - 查看服务状态" + echo " logs - 实时查看日志" + echo "" + echo "配置信息:" + echo " 应用名称: $APP_NAME" + echo " 入口文件: $ENTRY_FILE" + echo " 监听端口: $APP_PORT" + echo " 日志文件: $LOG_FILE" + echo "" + echo "示例:" + echo " $0 start # 启动服务" + echo " $0 status # 查看状态" + echo " $0 logs # 查看日志" + exit 1 + ;; +esac + +exit 0 + diff --git a/backend/simple-db-test.js b/backend/simple-db-test.js deleted file mode 100644 index bed407d..0000000 --- a/backend/simple-db-test.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * 简单数据库测试 - * @file simple-db-test.js - * @description 测试数据库连接和查询 - */ - -const { IotXqClient } = require('./models'); - -async function testDatabase() { - console.log('🔍 测试数据库连接...\n'); - - try { - // 测试数据库连接 - console.log('1. 测试数据库连接...'); - await IotXqClient.sequelize.authenticate(); - console.log('✅ 数据库连接成功'); - - // 查询项圈22012000107的数据 - console.log('\n2. 查询项圈22012000107的数据...'); - const devices = await IotXqClient.findAll({ - where: { - sn: '22012000107' - }, - order: [['uptime', 'DESC']], - limit: 5 - }); - - console.log(`找到 ${devices.length} 条记录`); - - devices.forEach((device, index) => { - console.log(`\n记录${index + 1}:`); - console.log('ID:', device.id); - console.log('SN:', device.sn); - console.log('电量:', device.battery); - console.log('温度:', device.temperature); - console.log('状态:', device.state); - console.log('更新时间:', device.uptime); - }); - - // 查询所有项圈数据 - console.log('\n3. 查询所有项圈数据...'); - const allDevices = await IotXqClient.findAll({ - order: [['uptime', 'DESC']], - limit: 10 - }); - - console.log(`总共 ${allDevices.length} 条记录`); - - allDevices.forEach((device, index) => { - console.log(`\n设备${index + 1}:`); - console.log('SN:', device.sn); - console.log('电量:', device.battery); - console.log('温度:', device.temperature); - console.log('状态:', device.state); - }); - - } catch (error) { - console.error('❌ 测试失败:', error.message); - console.error('错误详情:', error); - } finally { - process.exit(0); - } -} - -// 运行测试 -testDatabase().catch(console.error); diff --git a/backend/simple-firewall.ps1 b/backend/simple-firewall.ps1 deleted file mode 100644 index 20e4b36..0000000 --- a/backend/simple-firewall.ps1 +++ /dev/null @@ -1,15 +0,0 @@ -# 简化的防火墙配置脚本 -Write-Host "正在配置Windows防火墙..." -ForegroundColor Green - -# 添加前端端口规则 -netsh advfirewall firewall add rule name="Node.js Frontend Port 5300" dir=in action=allow protocol=TCP localport=5300 -Write-Host "前端端口5300规则已添加" -ForegroundColor Green - -# 添加后端端口规则 -netsh advfirewall firewall add rule name="Node.js Backend Port 5350" dir=in action=allow protocol=TCP localport=5350 -Write-Host "后端端口5350规则已添加" -ForegroundColor Green - -Write-Host "防火墙配置完成!" -ForegroundColor Green -Write-Host "现在其他用户可以通过以下地址访问:" -ForegroundColor Yellow -Write-Host "前端: http://172.28.112.1:5300" -ForegroundColor White -Write-Host "后端: http://172.28.112.1:5350" -ForegroundColor White diff --git a/backend/simple-test.js b/backend/simple-test.js deleted file mode 100644 index 386e477..0000000 --- a/backend/simple-test.js +++ /dev/null @@ -1,72 +0,0 @@ -// 简化的测试脚本 -console.log('开始测试预警检测逻辑...'); - -// 模拟前端判断函数 -function determineAlertType(record) { - const alerts = [] - - // 检查电量预警 - if (record.battery !== undefined && record.battery !== null && record.battery < 20) { - alerts.push('battery') - } - - // 检查脱落预警 (bandge_status为0) - if (record.bandge_status !== undefined && record.bandge_status !== null && record.bandge_status === 0) { - alerts.push('wear') - } - - // 检查离线预警 (is_connect为0) - if (record.is_connect !== undefined && record.is_connect !== null && record.is_connect === 0) { - alerts.push('offline') - } - - // 检查温度预警 - if (record.temperature !== undefined && record.temperature !== null) { - if (record.temperature < 20) { - alerts.push('temperature_low') - } else if (record.temperature > 40) { - alerts.push('temperature_high') - } - } - - // 检查运动异常预警 (steps - y_steps为0) - if (record.steps !== undefined && record.y_steps !== undefined && - record.steps !== null && record.y_steps !== null) { - const movementDiff = record.steps - record.y_steps - if (movementDiff === 0) { - alerts.push('movement') - } - } - - // 返回第一个预警类型,如果没有预警则返回null - return alerts.length > 0 ? alerts[0] : null -} - -// 测试用例 -const testCases = [ - { - name: '正常设备', - data: { battery: 85, temperature: 25, is_connect: 1, bandge_status: 1, steps: 1000, y_steps: 500 }, - expected: null - }, - { - name: '低电量预警', - data: { battery: 15, temperature: 25, is_connect: 1, bandge_status: 1, steps: 1000, y_steps: 500 }, - expected: 'battery' - }, - { - name: '离线预警', - data: { battery: 85, temperature: 25, is_connect: 0, bandge_status: 1, steps: 1000, y_steps: 500 }, - expected: 'offline' - } -]; - -// 运行测试 -testCases.forEach((testCase, index) => { - const result = determineAlertType(testCase.data); - const success = result === testCase.expected; - console.log(`测试 ${index + 1}: ${testCase.name} - ${success ? '✅ 通过' : '❌ 失败'}`); - console.log(` 预期: ${testCase.expected}, 实际: ${result}`); -}); - -console.log('测试完成!'); \ No newline at end of file diff --git a/backend/start-and-test.js b/backend/start-and-test.js deleted file mode 100644 index c7b2bd8..0000000 --- a/backend/start-and-test.js +++ /dev/null @@ -1,146 +0,0 @@ -/** - * 启动服务器并测试API - * @file start-and-test.js - * @description 启动服务器并自动测试API接口 - */ - -const { spawn } = require('child_process'); -const axios = require('axios'); - -let serverProcess = null; - -// 启动服务器 -function startServer() { - return new Promise((resolve, reject) => { - console.log('🚀 启动服务器...'); - - serverProcess = spawn('node', ['server.js'], { - stdio: 'pipe', - cwd: __dirname - }); - - serverProcess.stdout.on('data', (data) => { - const output = data.toString(); - console.log(output); - - if (output.includes('服务器运行在端口') || output.includes('Server running on port')) { - console.log('✅ 服务器启动成功'); - resolve(); - } - }); - - serverProcess.stderr.on('data', (data) => { - console.error('服务器错误:', data.toString()); - }); - - serverProcess.on('error', (error) => { - console.error('启动服务器失败:', error); - reject(error); - }); - - // 等待5秒让服务器完全启动 - setTimeout(() => { - resolve(); - }, 5000); - }); -} - -// 测试API -async function testAPI() { - console.log('\n🔍 测试API接口...'); - - const baseUrl = 'http://localhost:5350'; - - try { - // 1. 测试根路径 - console.log('1. 测试根路径...'); - const rootResponse = await axios.get(`${baseUrl}/`); - console.log('✅ 根路径正常:', rootResponse.data.message); - - // 2. 测试API文档 - console.log('\n2. 测试API文档...'); - const docsResponse = await axios.get(`${baseUrl}/api-docs/`); - console.log('✅ API文档页面正常'); - - // 3. 测试Swagger JSON - console.log('\n3. 测试Swagger JSON...'); - const swaggerResponse = await axios.get(`${baseUrl}/api-docs/swagger.json`); - console.log('✅ Swagger JSON正常'); - - // 4. 检查API路径 - console.log('\n4. 检查API路径...'); - const paths = Object.keys(swaggerResponse.data.paths || {}); - const smartAlertPaths = paths.filter(path => path.includes('/smart-alerts/public')); - - console.log(`📋 找到 ${smartAlertPaths.length} 个智能预警API路径:`); - smartAlertPaths.forEach(path => { - console.log(` - ${path}`); - }); - - if (smartAlertPaths.length > 0) { - console.log('\n🎉 API文档配置成功!'); - console.log(`📖 请访问: ${baseUrl}/api-docs`); - } else { - console.log('\n❌ 未找到智能预警API路径'); - } - - // 5. 测试实际API调用 - console.log('\n5. 测试实际API调用...'); - try { - const eartagStatsResponse = await axios.get(`${baseUrl}/api/smart-alerts/public/eartag/stats`); - console.log('✅ 智能耳标预警统计API正常'); - } catch (error) { - console.log('⚠️ 智能耳标预警统计API调用失败:', error.message); - } - - try { - const collarStatsResponse = await axios.get(`${baseUrl}/api/smart-alerts/public/collar/stats`); - console.log('✅ 智能项圈预警统计API正常'); - } catch (error) { - console.log('⚠️ 智能项圈预警统计API调用失败:', error.message); - } - - } catch (error) { - console.error('❌ API测试失败:', error.message); - } -} - -// 停止服务器 -function stopServer() { - if (serverProcess) { - console.log('\n🛑 停止服务器...'); - serverProcess.kill(); - serverProcess = null; - } -} - -// 主函数 -async function main() { - try { - await startServer(); - await testAPI(); - - console.log('\n✅ 测试完成!'); - console.log('📖 API文档地址: http://localhost:5350/api-docs'); - console.log('🔗 基础API地址: http://localhost:5350/api/smart-alerts/public'); - console.log('\n按 Ctrl+C 停止服务器'); - - // 保持服务器运行 - process.on('SIGINT', () => { - stopServer(); - process.exit(0); - }); - - } catch (error) { - console.error('❌ 启动失败:', error.message); - stopServer(); - process.exit(1); - } -} - -// 如果直接运行此脚本 -if (require.main === module) { - main().catch(console.error); -} - -module.exports = { startServer, testAPI, stopServer }; diff --git a/backend/start-ngrok.bat b/backend/start-ngrok.bat deleted file mode 100644 index abf18b1..0000000 --- a/backend/start-ngrok.bat +++ /dev/null @@ -1,46 +0,0 @@ -@echo off -echo 正在启动ngrok外网访问服务... -echo. - -REM 检查ngrok是否存在 -if not exist "ngrok.exe" ( - echo 错误:ngrok.exe 不存在,请先下载ngrok - pause - exit /b 1 -) - -echo 请确保您已经: -echo 1. 注册了ngrok账号 -echo 2. 获取了authtoken -echo 3. 运行了:ngrok authtoken YOUR_AUTH_TOKEN -echo. - -echo 选择要启动的服务: -echo 1. 前端服务 (端口5300) -echo 2. 后端服务 (端口5350) -echo 3. 同时启动前端和后端 -echo. - -set /p choice="请输入选择 (1-3): " - -if "%choice%"=="1" ( - echo 启动前端服务穿透... - .\ngrok.exe http 5300 -) else if "%choice%"=="2" ( - echo 启动后端服务穿透... - .\ngrok.exe http 5350 -) else if "%choice%"=="3" ( - echo 启动前端服务穿透... - start "Frontend" .\ngrok.exe http 5300 - timeout /t 3 /nobreak >nul - echo 启动后端服务穿透... - start "Backend" .\ngrok.exe http 5350 - echo. - echo 两个服务都已启动,请查看各自的窗口获取访问地址 -) else ( - echo 无效选择,请重新运行脚本 -) - -echo. -echo 按任意键退出... -pause >nul diff --git a/backend/start-ngrok.ps1 b/backend/start-ngrok.ps1 deleted file mode 100644 index 229ffdb..0000000 --- a/backend/start-ngrok.ps1 +++ /dev/null @@ -1,68 +0,0 @@ -# ngrok外网访问启动脚本 - -Write-Host "🚀 正在启动ngrok外网访问服务..." -ForegroundColor Green -Write-Host "" - -# 检查ngrok是否存在 -if (-not (Test-Path "ngrok.exe")) { - Write-Host "❌ 错误:ngrok.exe 不存在,请先下载ngrok" -ForegroundColor Red - Read-Host "按任意键退出" - exit 1 -} - -Write-Host "请确保您已经:" -ForegroundColor Yellow -Write-Host "1. 注册了ngrok账号" -ForegroundColor White -Write-Host "2. 获取了authtoken" -ForegroundColor White -Write-Host "3. 运行了:ngrok authtoken YOUR_AUTH_TOKEN" -ForegroundColor White -Write-Host "" - -Write-Host "选择要启动的服务:" -ForegroundColor Cyan -Write-Host "1. 前端服务 (端口5300)" -ForegroundColor White -Write-Host "2. 后端服务 (端口5350)" -ForegroundColor White -Write-Host "3. 同时启动前端和后端" -ForegroundColor White -Write-Host "4. 检查当前服务状态" -ForegroundColor White -Write-Host "" - -$choice = Read-Host "请输入选择 (1-4)" - -switch ($choice) { - "1" { - Write-Host "启动前端服务穿透..." -ForegroundColor Green - Write-Host "访问地址将在新窗口中显示" -ForegroundColor Yellow - Start-Process -FilePath ".\ngrok.exe" -ArgumentList "http", "5300" - } - "2" { - Write-Host "启动后端服务穿透..." -ForegroundColor Green - Write-Host "访问地址将在新窗口中显示" -ForegroundColor Yellow - Start-Process -FilePath ".\ngrok.exe" -ArgumentList "http", "5350" - } - "3" { - Write-Host "启动前端服务穿透..." -ForegroundColor Green - Start-Process -FilePath ".\ngrok.exe" -ArgumentList "http", "5300" - Start-Sleep -Seconds 3 - Write-Host "启动后端服务穿透..." -ForegroundColor Green - Start-Process -FilePath ".\ngrok.exe" -ArgumentList "http", "5350" - Write-Host "" - Write-Host "✅ 两个服务都已启动,请查看各自的窗口获取访问地址" -ForegroundColor Green - } - "4" { - Write-Host "检查当前服务状态..." -ForegroundColor Cyan - Write-Host "前端服务 (端口5300):" -ForegroundColor Yellow - netstat -ano | findstr :5300 - Write-Host "" - Write-Host "后端服务 (端口5350):" -ForegroundColor Yellow - netstat -ano | findstr :5350 - } - default { - Write-Host "❌ 无效选择,请重新运行脚本" -ForegroundColor Red - } -} - -Write-Host "" -Write-Host "💡 提示:" -ForegroundColor Cyan -Write-Host "- 前端访问地址格式:https://xxxxx.ngrok.io" -ForegroundColor White -Write-Host "- 后端访问地址格式:https://yyyyy.ngrok.io" -ForegroundColor White -Write-Host "- API文档地址:https://yyyyy.ngrok.io/api-docs" -ForegroundColor White -Write-Host "" - -Read-Host "按任意键退出" diff --git a/backend/start-tunnel-no-password.bat b/backend/start-tunnel-no-password.bat deleted file mode 100644 index 54a964c..0000000 --- a/backend/start-tunnel-no-password.bat +++ /dev/null @@ -1,45 +0,0 @@ -@echo off -echo ======================================== -echo 无密码外网访问启动脚本 -echo ======================================== -echo. - -echo 选择要启动的服务: -echo 1. 后端服务 (端口5350) -echo 2. 前端服务 (端口5300) -echo 3. 同时启动两个服务 -echo. - -set /p choice="请输入选择 (1-3): " - -if "%choice%"=="1" ( - echo 启动后端服务穿透... - start "Backend Tunnel" lt --port 5350 -) else if "%choice%"=="2" ( - echo 启动前端服务穿透... - start "Frontend Tunnel" lt --port 5300 -) else if "%choice%"=="3" ( - echo 启动后端服务穿透... - start "Backend Tunnel" lt --port 5350 - timeout /t 2 /nobreak >nul - echo 启动前端服务穿透... - start "Frontend Tunnel" lt --port 5300 -) else ( - echo 无效选择 - goto end -) - -echo. -echo ======================================== -echo 隧道已启动! -echo ======================================== -echo. -echo 请查看新打开的窗口获取访问地址 -echo 地址格式: https://随机字符串.loca.lt -echo. -echo 这些地址没有密码保护,可以直接访问 -echo. - -:end -echo 按任意键退出... -pause >nul diff --git a/backend/start.bat b/backend/start.bat new file mode 100644 index 0000000..ba1ee31 --- /dev/null +++ b/backend/start.bat @@ -0,0 +1,21 @@ +@echo off +REM 宁夏智慧养殖监管平台后端 - 快速启动脚本 +REM 使用 PowerShell 脚本启动服务 + +echo ======================================== +echo 宁夏智慧养殖监管平台后端服务 +echo ======================================== +echo. + +REM 检查是否在正确的目录 +if not exist "server.js" ( + echo 错误: 请在 backend 目录下运行此脚本 + pause + exit /b 1 +) + +REM 调用 PowerShell 脚本启动服务 +powershell -ExecutionPolicy Bypass -File "node_manager.ps1" start + +pause + diff --git a/backend/status.bat b/backend/status.bat new file mode 100644 index 0000000..5a7f7b3 --- /dev/null +++ b/backend/status.bat @@ -0,0 +1,21 @@ +@echo off +REM 宁夏智慧养殖监管平台后端 - 状态查看脚本 +REM 使用 PowerShell 脚本查看服务状态 + +echo ======================================== +echo 宁夏智慧养殖监管平台后端服务 +echo ======================================== +echo. + +REM 检查是否在正确的目录 +if not exist "server.js" ( + echo 错误: 请在 backend 目录下运行此脚本 + pause + exit /b 1 +) + +REM 调用 PowerShell 脚本查看状态 +powershell -ExecutionPolicy Bypass -File "node_manager.ps1" status + +pause + diff --git a/backend/stop.bat b/backend/stop.bat new file mode 100644 index 0000000..b41570b --- /dev/null +++ b/backend/stop.bat @@ -0,0 +1,21 @@ +@echo off +REM 宁夏智慧养殖监管平台后端 - 快速停止脚本 +REM 使用 PowerShell 脚本停止服务 + +echo ======================================== +echo 宁夏智慧养殖监管平台后端服务 +echo ======================================== +echo. + +REM 检查是否在正确的目录 +if not exist "server.js" ( + echo 错误: 请在 backend 目录下运行此脚本 + pause + exit /b 1 +) + +REM 调用 PowerShell 脚本停止服务 +powershell -ExecutionPolicy Bypass -File "node_manager.ps1" stop + +pause + diff --git a/backend/swagger-alerts.js b/backend/swagger-alerts.js deleted file mode 100644 index c825071..0000000 --- a/backend/swagger-alerts.js +++ /dev/null @@ -1,773 +0,0 @@ -/** - * 预警管理模块 Swagger 文档 - * @file swagger-alerts.js - */ - -const alertsPaths = { - // 获取所有预警 - '/alerts': { - get: { - tags: ['预警管理'], - summary: '获取预警列表', - description: '分页获取系统中的所有预警信息', - security: [{ bearerAuth: [] }], - parameters: [ - { - name: 'page', - in: 'query', - schema: { type: 'integer', default: 1 }, - description: '页码' - }, - { - name: 'limit', - in: 'query', - schema: { type: 'integer', default: 10 }, - description: '每页数量' - }, - { - name: 'search', - in: 'query', - schema: { type: 'string' }, - description: '搜索关键词(预警标题、描述)' - }, - { - name: 'type', - in: 'query', - schema: { type: 'string', enum: ['health', 'environment', 'device', 'security', 'breeding'] }, - description: '预警类型筛选' - }, - { - name: 'level', - in: 'query', - schema: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] }, - description: '预警级别筛选' - }, - { - name: 'status', - in: 'query', - schema: { type: 'string', enum: ['pending', 'processing', 'resolved', 'ignored'] }, - description: '预警状态筛选' - }, - { - name: 'farmId', - in: 'query', - schema: { type: 'integer' }, - description: '养殖场ID筛选' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { $ref: '#/components/schemas/Alert' } - }, - pagination: { - type: 'object', - properties: { - page: { type: 'integer' }, - limit: { type: 'integer' }, - total: { type: 'integer' }, - totalPages: { type: 'integer' } - } - } - } - } - } - } - }, - '401': { - description: '未授权', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - }, - post: { - tags: ['预警管理'], - summary: '创建新预警', - description: '创建新的预警记录', - security: [{ bearerAuth: [] }], - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['title', 'type', 'level', 'farmId'], - properties: { - title: { type: 'string', description: '预警标题' }, - description: { type: 'string', description: '预警描述' }, - type: { - type: 'string', - enum: ['health', 'environment', 'device', 'security', 'breeding'], - description: '预警类型:health-健康,environment-环境,device-设备,security-安全,breeding-繁殖' - }, - level: { - type: 'string', - enum: ['low', 'medium', 'high', 'critical'], - description: '预警级别:low-低,medium-中,high-高,critical-紧急' - }, - farmId: { type: 'integer', description: '养殖场ID' }, - animalId: { type: 'integer', description: '动物ID(可选)' }, - deviceId: { type: 'integer', description: '设备ID(可选)' }, - threshold: { type: 'number', description: '阈值' }, - currentValue: { type: 'number', description: '当前值' }, - location: { type: 'string', description: '位置信息' }, - metadata: { type: 'object', description: '额外元数据' } - } - } - } - } - }, - responses: { - '201': { - description: '创建成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '预警创建成功' }, - data: { $ref: '#/components/schemas/Alert' } - } - } - } - } - }, - '400': { - description: '请求参数错误', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 获取公共预警数据 - '/alerts/public': { - get: { - tags: ['预警管理'], - summary: '获取公共预警数据', - description: '获取可公开访问的预警基本信息', - security: [], // 公共接口不需要认证 - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { - type: 'object', - properties: { - id: { type: 'integer' }, - title: { type: 'string' }, - type: { type: 'string' }, - level: { type: 'string' }, - status: { type: 'string' }, - createdAt: { type: 'string', format: 'date-time' } - } - } - } - } - } - } - } - } - } - } - }, - - // 搜索预警 - '/alerts/search': { - get: { - tags: ['预警管理'], - summary: '搜索预警', - description: '根据养殖场名称等关键词搜索预警', - security: [{ bearerAuth: [] }], - parameters: [ - { - name: 'q', - in: 'query', - required: true, - schema: { type: 'string' }, - description: '搜索关键词' - }, - { - name: 'limit', - in: 'query', - schema: { type: 'integer', default: 10 }, - description: '返回结果数量限制' - } - ], - responses: { - '200': { - description: '搜索成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { $ref: '#/components/schemas/Alert' } - } - } - } - } - } - } - } - } - }, - - // 获取预警详情 - '/alerts/{id}': { - get: { - tags: ['预警管理'], - summary: '获取预警详情', - description: '根据预警ID获取详细信息', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '预警ID' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { $ref: '#/components/schemas/Alert' } - } - } - } - } - }, - '404': { - description: '预警不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - }, - put: { - tags: ['预警管理'], - summary: '更新预警信息', - description: '更新指定预警的信息', - security: [{ bearerAuth: [] }], - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '预警ID' - } - ], - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - title: { type: 'string', description: '预警标题' }, - description: { type: 'string', description: '预警描述' }, - type: { - type: 'string', - enum: ['health', 'environment', 'device', 'security', 'breeding'], - description: '预警类型' - }, - level: { - type: 'string', - enum: ['low', 'medium', 'high', 'critical'], - description: '预警级别' - }, - status: { - type: 'string', - enum: ['pending', 'processing', 'resolved', 'ignored'], - description: '预警状态' - }, - threshold: { type: 'number', description: '阈值' }, - currentValue: { type: 'number', description: '当前值' }, - location: { type: 'string', description: '位置信息' }, - handlerNotes: { type: 'string', description: '处理备注' }, - metadata: { type: 'object', description: '额外元数据' } - } - } - } - } - }, - responses: { - '200': { - description: '更新成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '预警信息更新成功' }, - data: { $ref: '#/components/schemas/Alert' } - } - } - } - } - }, - '400': { - description: '请求参数错误', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - }, - '404': { - description: '预警不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - }, - delete: { - tags: ['预警管理'], - summary: '删除预警', - description: '删除指定预警(软删除)', - security: [{ bearerAuth: [] }], - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '预警ID' - } - ], - responses: { - '200': { - description: '删除成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '预警删除成功' } - } - } - } - } - }, - '404': { - description: '预警不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 更新预警状态 - '/alerts/{id}/status': { - put: { - tags: ['预警管理'], - summary: '更新预警状态', - description: '更新指定预警的处理状态', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '预警ID' - } - ], - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['status'], - properties: { - status: { - type: 'string', - enum: ['pending', 'processing', 'resolved', 'ignored'], - description: '预警状态' - }, - handlerNotes: { type: 'string', description: '处理备注' }, - handlerId: { type: 'integer', description: '处理人ID' } - } - } - } - } - }, - responses: { - '200': { - description: '状态更新成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '预警状态更新成功' } - } - } - } - } - }, - '400': { - description: '请求参数错误', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - }, - '404': { - description: '预警不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 获取预警统计信息 - '/alerts/stats/type': { - get: { - tags: ['预警管理'], - summary: '获取按类型统计的预警数据', - description: '获取各种预警类型的统计信息', - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'object', - properties: { - health: { type: 'integer', description: '健康预警数量' }, - environment: { type: 'integer', description: '环境预警数量' }, - device: { type: 'integer', description: '设备预警数量' }, - security: { type: 'integer', description: '安全预警数量' }, - breeding: { type: 'integer', description: '繁殖预警数量' } - } - } - } - } - } - } - } - } - } - }, - - '/alerts/stats/level': { - get: { - tags: ['预警管理'], - summary: '获取按级别统计的预警数据', - description: '获取各种预警级别的统计信息', - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'object', - properties: { - low: { type: 'integer', description: '低级预警数量' }, - medium: { type: 'integer', description: '中级预警数量' }, - high: { type: 'integer', description: '高级预警数量' }, - critical: { type: 'integer', description: '紧急预警数量' } - } - } - } - } - } - } - } - } - } - }, - - '/alerts/stats/status': { - get: { - tags: ['预警管理'], - summary: '获取按状态统计的预警数据', - description: '获取各种预警状态的统计信息', - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'object', - properties: { - pending: { type: 'integer', description: '待处理预警数量' }, - processing: { type: 'integer', description: '处理中预警数量' }, - resolved: { type: 'integer', description: '已解决预警数量' }, - ignored: { type: 'integer', description: '已忽略预警数量' } - } - } - } - } - } - } - } - } - } - }, - - // 批量操作预警 - '/alerts/batch': { - post: { - tags: ['预警管理'], - summary: '批量操作预警', - description: '批量更新预警状态或删除预警', - security: [{ bearerAuth: [] }], - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['ids', 'action'], - properties: { - ids: { - type: 'array', - items: { type: 'integer' }, - description: '预警ID列表' - }, - action: { - type: 'string', - enum: ['resolve', 'ignore', 'delete', 'reopen'], - description: '操作类型:resolve-解决,ignore-忽略,delete-删除,reopen-重新打开' - }, - handlerNotes: { type: 'string', description: '处理备注' } - } - } - } - } - }, - responses: { - '200': { - description: '批量操作成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '批量操作完成' }, - data: { - type: 'object', - properties: { - successCount: { type: 'integer', description: '成功处理数量' }, - failedCount: { type: 'integer', description: '失败数量' }, - failedIds: { - type: 'array', - items: { type: 'integer' }, - description: '失败的预警ID列表' - } - } - } - } - } - } - } - } - } - } - } -}; - -// 数据模型定义 -const alertSchemas = { - Alert: { - type: 'object', - properties: { - id: { type: 'integer', description: '预警ID' }, - title: { type: 'string', description: '预警标题' }, - description: { type: 'string', description: '预警描述' }, - type: { - type: 'string', - enum: ['health', 'environment', 'device', 'security', 'breeding'], - description: '预警类型:health-健康,environment-环境,device-设备,security-安全,breeding-繁殖' - }, - level: { - type: 'string', - enum: ['low', 'medium', 'high', 'critical'], - description: '预警级别:low-低,medium-中,high-高,critical-紧急' - }, - status: { - type: 'string', - enum: ['pending', 'processing', 'resolved', 'ignored'], - description: '预警状态:pending-待处理,processing-处理中,resolved-已解决,ignored-已忽略' - }, - farmId: { type: 'integer', description: '养殖场ID' }, - farmName: { type: 'string', description: '养殖场名称' }, - animalId: { type: 'integer', description: '动物ID(可选)' }, - animalEarNumber: { type: 'string', description: '动物耳标号(可选)' }, - deviceId: { type: 'integer', description: '设备ID(可选)' }, - deviceName: { type: 'string', description: '设备名称(可选)' }, - threshold: { type: 'number', description: '阈值' }, - currentValue: { type: 'number', description: '当前值' }, - location: { type: 'string', description: '位置信息' }, - handlerId: { type: 'integer', description: '处理人ID' }, - handlerName: { type: 'string', description: '处理人姓名' }, - handlerNotes: { type: 'string', description: '处理备注' }, - handledAt: { type: 'string', format: 'date-time', description: '处理时间' }, - metadata: { type: 'object', description: '额外元数据' }, - createdAt: { type: 'string', format: 'date-time', description: '创建时间' }, - updatedAt: { type: 'string', format: 'date-time', description: '更新时间' } - } - }, - - AlertInput: { - type: 'object', - required: ['title', 'type', 'level', 'farmId'], - properties: { - title: { type: 'string', description: '预警标题' }, - description: { type: 'string', description: '预警描述' }, - type: { - type: 'string', - enum: ['health', 'environment', 'device', 'security', 'breeding'], - description: '预警类型' - }, - level: { - type: 'string', - enum: ['low', 'medium', 'high', 'critical'], - description: '预警级别' - }, - farmId: { type: 'integer', description: '养殖场ID' }, - animalId: { type: 'integer', description: '动物ID(可选)' }, - deviceId: { type: 'integer', description: '设备ID(可选)' }, - threshold: { type: 'number', description: '阈值' }, - currentValue: { type: 'number', description: '当前值' }, - location: { type: 'string', description: '位置信息' }, - metadata: { type: 'object', description: '额外元数据' } - } - }, - - AlertUpdate: { - type: 'object', - properties: { - title: { type: 'string', description: '预警标题' }, - description: { type: 'string', description: '预警描述' }, - type: { - type: 'string', - enum: ['health', 'environment', 'device', 'security', 'breeding'], - description: '预警类型' - }, - level: { - type: 'string', - enum: ['low', 'medium', 'high', 'critical'], - description: '预警级别' - }, - status: { - type: 'string', - enum: ['pending', 'processing', 'resolved', 'ignored'], - description: '预警状态' - }, - threshold: { type: 'number', description: '阈值' }, - currentValue: { type: 'number', description: '当前值' }, - location: { type: 'string', description: '位置信息' }, - handlerNotes: { type: 'string', description: '处理备注' }, - metadata: { type: 'object', description: '额外元数据' } - } - }, - - AlertStats: { - type: 'object', - properties: { - totalAlerts: { type: 'integer', description: '总预警数' }, - pendingAlerts: { type: 'integer', description: '待处理预警数' }, - resolvedAlerts: { type: 'integer', description: '已解决预警数' }, - criticalAlerts: { type: 'integer', description: '紧急预警数' }, - todayAlerts: { type: 'integer', description: '今日新增预警数' }, - byType: { - type: 'object', - properties: { - health: { type: 'integer' }, - environment: { type: 'integer' }, - device: { type: 'integer' }, - security: { type: 'integer' }, - breeding: { type: 'integer' } - } - }, - byLevel: { - type: 'object', - properties: { - low: { type: 'integer' }, - medium: { type: 'integer' }, - high: { type: 'integer' }, - critical: { type: 'integer' } - } - }, - byStatus: { - type: 'object', - properties: { - pending: { type: 'integer' }, - processing: { type: 'integer' }, - resolved: { type: 'integer' }, - ignored: { type: 'integer' } - } - } - } - } -}; - -module.exports = { alertsPaths, alertSchemas }; \ No newline at end of file diff --git a/backend/swagger-animals.js b/backend/swagger-animals.js deleted file mode 100644 index 5b0f894..0000000 --- a/backend/swagger-animals.js +++ /dev/null @@ -1,706 +0,0 @@ -/** - * 动物管理模块 Swagger 文档 - * @file swagger-animals.js - */ - -const animalsPaths = { - // 获取所有动物列表 - '/animals': { - get: { - tags: ['动物管理'], - summary: '获取动物列表', - description: '分页获取系统中的所有动物信息', - parameters: [ - { - name: 'page', - in: 'query', - schema: { type: 'integer', default: 1 }, - description: '页码' - }, - { - name: 'limit', - in: 'query', - schema: { type: 'integer', default: 10 }, - description: '每页数量' - }, - { - name: 'search', - in: 'query', - schema: { type: 'string' }, - description: '搜索关键词(项圈编号、耳标号)' - }, - { - name: 'farmId', - in: 'query', - schema: { type: 'integer' }, - description: '养殖场ID筛选' - }, - { - name: 'status', - in: 'query', - schema: { type: 'string', enum: ['healthy', 'sick', 'quarantine', 'sold'] }, - description: '动物状态筛选' - }, - { - name: 'category', - in: 'query', - schema: { type: 'integer', enum: [1, 2, 3, 4, 5, 6] }, - description: '动物类别筛选:1-犊牛,2-育成母牛,3-架子牛,4-青年牛,5-基础母牛,6-育肥牛' - }, - { - name: 'sex', - in: 'query', - schema: { type: 'integer', enum: [1, 2] }, - description: '性别筛选:1-公牛,2-母牛' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { $ref: '#/components/schemas/Animal' } - }, - pagination: { - type: 'object', - properties: { - page: { type: 'integer' }, - limit: { type: 'integer' }, - total: { type: 'integer' }, - totalPages: { type: 'integer' } - } - } - } - } - } - } - } - } - }, - post: { - tags: ['动物管理'], - summary: '创建新动物档案', - description: '创建新的动物档案记录', - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['earNumber', 'sex', 'varieties', 'cate', 'farmId'], - properties: { - earNumber: { type: 'string', description: '耳标号' }, - sex: { type: 'integer', enum: [1, 2], description: '性别:1-公牛,2-母牛' }, - strain: { type: 'string', description: '品系' }, - varieties: { type: 'integer', description: '品种ID' }, - cate: { - type: 'integer', - enum: [1, 2, 3, 4, 5, 6], - description: '类别:1-犊牛,2-育成母牛,3-架子牛,4-青年牛,5-基础母牛,6-育肥牛' - }, - birthWeight: { type: 'number', description: '出生重量(kg)' }, - birthday: { type: 'integer', description: '出生日期(时间戳)' }, - farmId: { type: 'integer', description: '养殖场ID' }, - penId: { type: 'integer', description: '栏舍ID' }, - batchId: { type: 'integer', description: '批次ID' }, - intoTime: { type: 'integer', description: '入场时间(时间戳)' }, - parity: { type: 'integer', description: '胎次' }, - source: { - type: 'integer', - enum: [1, 2, 3, 4, 5], - description: '来源:1-合作社,2-农户,3-养殖场,4-进口,5-自繁' - }, - sourceDay: { type: 'integer', description: '来源日龄' }, - sourceWeight: { type: 'number', description: '来源重量(kg)' }, - weight: { type: 'number', description: '当前重量(kg)' }, - algebra: { type: 'string', description: '代数' }, - colour: { type: 'string', description: '毛色' }, - descent: { type: 'string', description: '血统' }, - imgs: { type: 'string', description: '图片URL(多个用逗号分隔)' } - } - } - } - } - }, - responses: { - '201': { - description: '创建成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '动物档案创建成功' }, - data: { $ref: '#/components/schemas/Animal' } - } - } - } - } - }, - '400': { - description: '请求参数错误', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 公共动物数据 - '/animals/public': { - get: { - tags: ['动物管理'], - summary: '获取公共动物数据', - description: '获取可公开访问的动物基本信息', - security: [], // 公共接口不需要认证 - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { - type: 'object', - properties: { - id: { type: 'integer' }, - earNumber: { type: 'string' }, - sex: { type: 'integer' }, - varieties: { type: 'integer' }, - cate: { type: 'integer' }, - weight: { type: 'number' }, - isOut: { type: 'integer' } - } - } - }, - message: { type: 'string' } - } - } - } - } - } - } - } - }, - - // 获取动物绑定信息 - '/animals/binding-info/{collarNumber}': { - get: { - tags: ['动物管理'], - summary: '获取动物绑定信息', - description: '根据项圈编号获取动物的详细绑定信息', - parameters: [ - { - name: 'collarNumber', - in: 'path', - required: true, - schema: { type: 'string' }, - description: '项圈编号' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string' }, - data: { - type: 'object', - properties: { - basicInfo: { - type: 'object', - properties: { - collarNumber: { type: 'string', description: '项圈编号' }, - category: { type: 'string', description: '动物类别' }, - calvingCount: { type: 'integer', description: '产犊次数' }, - earTag: { type: 'string', description: '耳标号' }, - animalType: { type: 'string', description: '动物类型' }, - breed: { type: 'string', description: '品种' }, - sourceType: { type: 'string', description: '来源类型' } - } - }, - birthInfo: { - type: 'object', - properties: { - birthDate: { type: 'string', description: '出生日期' }, - birthWeight: { type: 'string', description: '出生重量' }, - weaningWeight: { type: 'string', description: '断奶重量' }, - entryDate: { type: 'string', description: '入场日期' }, - weaningAge: { type: 'integer', description: '断奶日龄' } - } - }, - pedigreeInfo: { - type: 'object', - properties: { - fatherId: { type: 'string', description: '父亲ID' }, - motherId: { type: 'string', description: '母亲ID' }, - grandfatherId: { type: 'string', description: '祖父ID' }, - grandmotherId: { type: 'string', description: '祖母ID' }, - bloodline: { type: 'string', description: '血统' }, - generation: { type: 'string', description: '世代' } - } - }, - insuranceInfo: { - type: 'object', - properties: { - policyNumber: { type: 'string', description: '保单号' }, - insuranceCompany: { type: 'string', description: '保险公司' }, - coverageAmount: { type: 'string', description: '保额' }, - premium: { type: 'string', description: '保费' }, - startDate: { type: 'string', description: '开始日期' }, - endDate: { type: 'string', description: '结束日期' }, - status: { type: 'string', description: '保险状态' } - } - }, - loanInfo: { - type: 'object', - properties: { - loanNumber: { type: 'string', description: '贷款编号' }, - bankName: { type: 'string', description: '银行名称' }, - loanAmount: { type: 'string', description: '贷款金额' }, - interestRate: { type: 'string', description: '利率' }, - loanDate: { type: 'string', description: '放款日期' }, - maturityDate: { type: 'string', description: '到期日期' }, - status: { type: 'string', description: '贷款状态' } - } - }, - deviceInfo: { - type: 'object', - properties: { - deviceId: { type: 'integer', description: '设备ID' }, - batteryLevel: { type: 'number', description: '电池电量' }, - temperature: { type: 'number', description: '温度' }, - status: { type: 'string', description: '设备状态' }, - lastUpdate: { type: 'string', description: '最后更新时间' }, - location: { type: 'string', description: '位置信息' } - } - }, - farmInfo: { - type: 'object', - properties: { - farmName: { type: 'string', description: '农场名称' }, - farmAddress: { type: 'string', description: '农场地址' }, - penName: { type: 'string', description: '栏舍名称' }, - batchName: { type: 'string', description: '批次名称' } - } - } - } - } - } - } - } - } - }, - '404': { - description: '未找到指定的动物或设备', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 获取指定动物详情 - '/animals/{id}': { - get: { - tags: ['动物管理'], - summary: '获取动物详情', - description: '根据动物ID获取详细信息', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '动物ID' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { $ref: '#/components/schemas/Animal' } - } - } - } - } - }, - '404': { - description: '动物不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - }, - put: { - tags: ['动物管理'], - summary: '更新动物信息', - description: '更新指定动物的档案信息', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '动物ID' - } - ], - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - earNumber: { type: 'string', description: '耳标号' }, - sex: { type: 'integer', enum: [1, 2], description: '性别' }, - strain: { type: 'string', description: '品系' }, - varieties: { type: 'integer', description: '品种ID' }, - cate: { type: 'integer', enum: [1, 2, 3, 4, 5, 6], description: '类别' }, - weight: { type: 'number', description: '当前重量(kg)' }, - penId: { type: 'integer', description: '栏舍ID' }, - batchId: { type: 'integer', description: '批次ID' }, - event: { type: 'string', description: '事件记录' }, - eventTime: { type: 'integer', description: '事件时间(时间戳)' }, - isVaccin: { type: 'integer', enum: [0, 1], description: '是否疫苗' }, - isInsemination: { type: 'integer', enum: [0, 1], description: '是否配种' }, - isInsure: { type: 'integer', enum: [0, 1], description: '是否保险' }, - isMortgage: { type: 'integer', enum: [0, 1], description: '是否抵押' } - } - } - } - } - }, - responses: { - '200': { - description: '更新成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '动物信息更新成功' }, - data: { $ref: '#/components/schemas/Animal' } - } - } - } - } - }, - '400': { - description: '请求参数错误', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - }, - '404': { - description: '动物不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - }, - delete: { - tags: ['动物管理'], - summary: '删除动物档案', - description: '删除指定动物档案(软删除)', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '动物ID' - } - ], - responses: { - '200': { - description: '删除成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '动物档案删除成功' } - } - } - } - } - }, - '404': { - description: '动物不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 动物健康记录 - '/animals/{id}/health': { - get: { - tags: ['动物管理'], - summary: '获取动物健康记录', - description: '获取指定动物的健康记录', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '动物ID' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { - type: 'object', - properties: { - id: { type: 'integer' }, - animalId: { type: 'integer' }, - checkDate: { type: 'string', format: 'date' }, - temperature: { type: 'number' }, - weight: { type: 'number' }, - healthStatus: { type: 'string' }, - symptoms: { type: 'string' }, - treatment: { type: 'string' }, - veterinarian: { type: 'string' }, - notes: { type: 'string' } - } - } - } - } - } - } - } - } - } - }, - post: { - tags: ['动物管理'], - summary: '添加动物健康记录', - description: '为指定动物添加健康检查记录', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '动物ID' - } - ], - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['checkDate', 'healthStatus'], - properties: { - checkDate: { type: 'string', format: 'date', description: '检查日期' }, - temperature: { type: 'number', description: '体温' }, - weight: { type: 'number', description: '体重' }, - healthStatus: { - type: 'string', - enum: ['healthy', 'sick', 'recovering', 'quarantine'], - description: '健康状态' - }, - symptoms: { type: 'string', description: '症状描述' }, - treatment: { type: 'string', description: '治疗方案' }, - veterinarian: { type: 'string', description: '兽医姓名' }, - notes: { type: 'string', description: '备注' } - } - } - } - } - }, - responses: { - '201': { - description: '添加成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '健康记录添加成功' } - } - } - } - } - } - } - } - }, - - // 动物繁殖记录 - '/animals/{id}/breeding': { - get: { - tags: ['动物管理'], - summary: '获取动物繁殖记录', - description: '获取指定动物的繁殖记录', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '动物ID' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { - type: 'object', - properties: { - id: { type: 'integer' }, - animalId: { type: 'integer' }, - breedingDate: { type: 'string', format: 'date' }, - matingType: { type: 'string', enum: ['natural', 'artificial'] }, - sireId: { type: 'integer' }, - expectedCalvingDate: { type: 'string', format: 'date' }, - actualCalvingDate: { type: 'string', format: 'date' }, - calvingResult: { type: 'string' }, - offspringCount: { type: 'integer' }, - notes: { type: 'string' } - } - } - } - } - } - } - } - } - } - } - } -}; - -// 动物数据模型 -const animalSchemas = { - Animal: { - type: 'object', - properties: { - id: { type: 'integer', description: '动物ID' }, - orgId: { type: 'integer', description: '组织ID' }, - earNumber: { type: 'string', description: '耳标号' }, - sex: { - type: 'integer', - enum: [1, 2], - description: '性别:1-公牛,2-母牛' - }, - strain: { type: 'string', description: '品系' }, - varieties: { type: 'integer', description: '品种ID' }, - cate: { - type: 'integer', - enum: [1, 2, 3, 4, 5, 6], - description: '类别:1-犊牛,2-育成母牛,3-架子牛,4-青年牛,5-基础母牛,6-育肥牛' - }, - birthWeight: { type: 'number', description: '出生重量(kg)' }, - birthday: { type: 'integer', description: '出生日期(时间戳)' }, - penId: { type: 'integer', description: '栏舍ID' }, - intoTime: { type: 'integer', description: '入场时间(时间戳)' }, - parity: { type: 'integer', description: '胎次' }, - source: { - type: 'integer', - enum: [1, 2, 3, 4, 5], - description: '来源:1-合作社,2-农户,3-养殖场,4-进口,5-自繁' - }, - sourceDay: { type: 'integer', description: '来源日龄' }, - sourceWeight: { type: 'number', description: '来源重量(kg)' }, - weight: { type: 'number', description: '当前重量(kg)' }, - event: { type: 'string', description: '事件记录' }, - eventTime: { type: 'integer', description: '事件时间(时间戳)' }, - lactationDay: { type: 'integer', description: '泌乳天数' }, - semenNum: { type: 'string', description: '精液编号' }, - isWear: { type: 'integer', enum: [0, 1], description: '是否佩戴设备' }, - batchId: { type: 'integer', description: '批次ID' }, - imgs: { type: 'string', description: '图片URL(多个用逗号分隔)' }, - isEleAuth: { type: 'integer', enum: [0, 1], description: '是否电子认证' }, - isQuaAuth: { type: 'integer', enum: [0, 1], description: '是否质量认证' }, - isDelete: { type: 'integer', enum: [0, 1], description: '是否删除' }, - isOut: { type: 'integer', enum: [0, 1], description: '是否出栏' }, - createUid: { type: 'integer', description: '创建用户ID' }, - createTime: { type: 'integer', description: '创建时间(时间戳)' }, - algebra: { type: 'string', description: '代数' }, - colour: { type: 'string', description: '毛色' }, - infoWeight: { type: 'number', description: '信息重量' }, - descent: { type: 'string', description: '血统' }, - isVaccin: { type: 'integer', enum: [0, 1], description: '是否疫苗' }, - isInsemination: { type: 'integer', enum: [0, 1], description: '是否配种' }, - isInsure: { type: 'integer', enum: [0, 1], description: '是否保险' }, - isMortgage: { type: 'integer', enum: [0, 1], description: '是否抵押' }, - updateTime: { type: 'integer', description: '更新时间(时间戳)' }, - breedBullTime: { type: 'integer', description: '配种时间(时间戳)' }, - level: { type: 'string', description: '等级' }, - sixWeight: { type: 'number', description: '6月龄重量' }, - eighteenWeight: { type: 'number', description: '18月龄重量' }, - twelveDayWeight: { type: 'number', description: '12日龄重量' }, - eighteenDayWeight: { type: 'number', description: '18日龄重量' }, - xxivDayWeight: { type: 'number', description: '24日龄重量' }, - semenBreedImgs: { type: 'string', description: '配种图片' }, - sellStatus: { type: 'integer', description: '销售状态' }, - weightCalculateTime: { type: 'integer', description: '重量计算时间' }, - dayOfBirthday: { type: 'integer', description: '出生天数' }, - userId: { type: 'integer', description: '用户ID' } - } - } -}; - -module.exports = { animalsPaths, animalSchemas }; \ No newline at end of file diff --git a/backend/swagger-auth.js b/backend/swagger-auth.js deleted file mode 100644 index 503a566..0000000 --- a/backend/swagger-auth.js +++ /dev/null @@ -1,412 +0,0 @@ -/** - * 用户认证模块 Swagger 文档 - * @file swagger-auth.js - */ - -const authPaths = { - // 用户登录 - '/auth/login': { - post: { - tags: ['用户认证'], - summary: '用户登录', - description: '用户通过用户名/邮箱和密码登录系统', - security: [], // 登录接口不需要认证 - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['username', 'password'], - properties: { - username: { - type: 'string', - description: '用户名或邮箱', - example: 'admin' - }, - password: { - type: 'string', - description: '密码', - example: '123456' - } - } - } - } - } - }, - responses: { - '200': { - description: '登录成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '登录成功' }, - token: { type: 'string', description: 'JWT Token' }, - user: { - type: 'object', - properties: { - id: { type: 'integer' }, - username: { type: 'string' }, - email: { type: 'string' }, - phone: { type: 'string' }, - avatar: { type: 'string' }, - status: { type: 'string' }, - roles: { type: 'array', items: { type: 'object' } } - } - } - } - } - } - } - }, - '400': { - description: '请求参数错误', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - }, - '401': { - description: '用户名或密码错误', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - }, - '429': { - description: '登录尝试次数过多,请稍后再试', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 用户注册 - '/auth/register': { - post: { - tags: ['用户认证'], - summary: '用户注册', - description: '新用户注册账号', - security: [], // 注册接口不需要认证 - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['username', 'email', 'password'], - properties: { - username: { - type: 'string', - description: '用户名', - example: 'newuser' - }, - email: { - type: 'string', - format: 'email', - description: '邮箱地址', - example: 'newuser@example.com' - }, - password: { - type: 'string', - minLength: 6, - description: '密码(至少6位)', - example: '123456' - }, - phone: { - type: 'string', - description: '手机号码', - example: '13800138000' - } - } - } - } - } - }, - responses: { - '201': { - description: '注册成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '注册成功' }, - user: { - type: 'object', - properties: { - id: { type: 'integer' }, - username: { type: 'string' }, - email: { type: 'string' }, - phone: { type: 'string' } - } - } - } - } - } - } - }, - '400': { - description: '请求参数错误或用户已存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 获取当前用户信息 - '/auth/me': { - get: { - tags: ['用户认证'], - summary: '获取当前用户信息', - description: '获取当前登录用户的详细信息', - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'object', - properties: { - id: { type: 'integer' }, - username: { type: 'string' }, - email: { type: 'string' }, - phone: { type: 'string' }, - avatar: { type: 'string' }, - status: { type: 'string' }, - roles: { type: 'array', items: { type: 'object' } }, - permissions: { type: 'array', items: { type: 'string' } }, - menus: { type: 'array', items: { type: 'object' } } - } - } - } - } - } - } - }, - '401': { - description: '未授权,Token无效或已过期', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // Token验证 - '/auth/validate': { - get: { - tags: ['用户认证'], - summary: 'Token验证', - description: '验证当前Token是否有效', - responses: { - '200': { - description: 'Token有效', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: 'Token有效' }, - user: { - type: 'object', - properties: { - id: { type: 'integer' }, - username: { type: 'string' }, - email: { type: 'string' } - } - } - } - } - } - } - }, - '401': { - description: 'Token无效或已过期', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 获取所有角色 - '/auth/roles': { - get: { - tags: ['用户认证'], - summary: '获取所有角色', - description: '获取系统中所有可用的角色列表', - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { - type: 'object', - properties: { - id: { type: 'integer' }, - name: { type: 'string' }, - description: { type: 'string' }, - permissions: { type: 'array', items: { type: 'string' } } - } - } - } - } - } - } - } - } - } - } - }, - - // 为用户分配角色 - '/auth/users/{userId}/roles': { - post: { - tags: ['用户认证'], - summary: '为用户分配角色', - description: '为指定用户分配一个或多个角色', - parameters: [ - { - name: 'userId', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '用户ID' - } - ], - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['roleIds'], - properties: { - roleIds: { - type: 'array', - items: { type: 'integer' }, - description: '角色ID列表' - } - } - } - } - } - }, - responses: { - '200': { - description: '分配成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '角色分配成功' } - } - } - } - } - }, - '400': { - description: '请求参数错误', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - }, - '404': { - description: '用户不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 移除用户角色 - '/auth/users/{userId}/roles/{roleId}': { - delete: { - tags: ['用户认证'], - summary: '移除用户角色', - description: '移除用户的指定角色', - parameters: [ - { - name: 'userId', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '用户ID' - }, - { - name: 'roleId', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '角色ID' - } - ], - responses: { - '200': { - description: '移除成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '角色移除成功' } - } - } - } - } - }, - '404': { - description: '用户或角色不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - } -}; - -module.exports = authPaths; \ No newline at end of file diff --git a/backend/swagger-complete.js b/backend/swagger-complete.js deleted file mode 100644 index c1192b3..0000000 --- a/backend/swagger-complete.js +++ /dev/null @@ -1,223 +0,0 @@ -/** - * 完整版Swagger配置 - * @file swagger-complete.js - * @description 宁夏智慧养殖监管平台完整API文档配置 - */ - -const swaggerJSDoc = require('swagger-jsdoc'); - -const options = { - definition: { - openapi: '3.0.0', - info: { - title: '宁夏智慧养殖监管平台 API', - version: '2.0.0', - description: ` - 宁夏智慧养殖监管平台API文档 - - ## 功能模块 - - **用户认证**: 登录、注册、权限验证 - - **用户管理**: 用户CRUD操作、角色管理 - - **养殖场管理**: 养殖场信息管理 - - **动物管理**: 牲畜信息管理、批次管理 - - **设备管理**: IoT设备管理、智能设备 - - **预警系统**: 智能预警、告警处理 - - **围栏管理**: 电子围栏设置 - - **数据统计**: 各类统计报表 - - **系统管理**: 系统配置、备份等 - - ## 认证方式 - 使用JWT Token进行身份认证,请在请求头中添加: - \`Authorization: Bearer \` - `, - contact: { - name: '开发团队', - email: 'dev@nxxm.com' - }, - license: { - name: 'MIT', - url: 'https://opensource.org/licenses/MIT' - } - }, - servers: [ - { - url: 'http://localhost:5350/api', - description: '开发环境' - }, - { - url: 'https://api.nxxm.com/api', - description: '生产环境' - } - ], - tags: [ - { - name: '用户认证', - description: '用户登录、注册、权限验证相关接口' - }, - { - name: '用户管理', - description: '用户信息管理、角色权限管理' - }, - { - name: '养殖场管理', - description: '养殖场信息的增删改查' - }, - { - name: '动物管理', - description: '牲畜信息管理、批次管理、转移记录' - }, - { - name: '圈舍管理', - description: '圈舍信息管理、牲畜圈舍分配' - }, - { - name: '设备管理', - description: 'IoT设备管理、设备绑定、状态监控' - }, - { - name: '智能设备', - description: '智能耳标、智能项圈等设备管理' - }, - { - name: '预警系统', - description: '智能预警、告警处理、预警统计' - }, - { - name: '电子围栏', - description: '电子围栏设置、围栏点管理' - }, - { - name: '地图服务', - description: '地图相关功能、位置服务' - }, - { - name: '数据统计', - description: '各类统计数据、报表生成' - }, - { - name: '报表管理', - description: '报表生成、导出功能' - }, - { - name: '系统管理', - description: '系统配置、菜单管理、权限配置' - }, - { - name: '备份管理', - description: '数据备份、恢复功能' - }, - { - name: '操作日志', - description: '系统操作日志记录和查询' - }, - { - name: '产品管理', - description: '产品信息管理' - }, - { - name: '订单管理', - description: '订单处理、订单查询' - } - ], - components: { - securitySchemes: { - bearerAuth: { - type: 'http', - scheme: 'bearer', - bearerFormat: 'JWT', - description: 'JWT认证,格式:Bearer ' - } - }, - schemas: { - // 通用响应格式 - ApiResponse: { - type: 'object', - properties: { - success: { - type: 'boolean', - description: '请求是否成功' - }, - message: { - type: 'string', - description: '响应消息' - }, - data: { - description: '响应数据' - }, - total: { - type: 'integer', - description: '总记录数(分页时使用)' - }, - page: { - type: 'integer', - description: '当前页码' - }, - limit: { - type: 'integer', - description: '每页记录数' - } - } - }, - // 错误响应 - ErrorResponse: { - type: 'object', - properties: { - success: { - type: 'boolean', - example: false - }, - message: { - type: 'string', - description: '错误消息' - }, - error: { - type: 'string', - description: '错误详情' - } - } - }, - // 分页参数 - PaginationQuery: { - type: 'object', - properties: { - page: { - type: 'integer', - minimum: 1, - default: 1, - description: '页码' - }, - limit: { - type: 'integer', - minimum: 1, - maximum: 100, - default: 10, - description: '每页记录数' - }, - search: { - type: 'string', - description: '搜索关键词' - } - } - } - } - }, - security: [ - { - bearerAuth: [] - } - ] - }, - apis: [ - './routes/*.js', - './controllers/*.js' - ] -}; - -const specs = swaggerJSDoc(options); - -// 手动添加API路径定义 -if (!specs.paths) { - specs.paths = {}; -} - -module.exports = specs; \ No newline at end of file diff --git a/backend/swagger-config.js b/backend/swagger-config.js deleted file mode 100644 index 03d12ee..0000000 --- a/backend/swagger-config.js +++ /dev/null @@ -1,369 +0,0 @@ -/** - * Swagger API文档配置 - * @file swagger-config.js - * @description 配置Swagger API文档,包含智能耳标预警和智能项圈预警接口 - */ - -const swaggerJSDoc = require('swagger-jsdoc'); - -const options = { - definition: { - openapi: '3.0.0', - info: { - title: '智能预警系统 API', - version: '1.0.0', - description: '智能耳标预警和智能项圈预警系统API文档', - contact: { - name: '开发团队', - email: 'dev@example.com' - } - }, - servers: [ - { - url: 'http://localhost:5350/api', - description: '开发环境' - } - ], - tags: [ - { - name: '智能耳标预警', - description: '智能耳标预警相关接口' - }, - { - name: '智能项圈预警', - description: '智能项圈预警相关接口' - } - ], - components: { - schemas: { - EartagAlert: { - type: 'object', - properties: { - id: { - type: 'string', - description: '预警ID', - example: '123_offline' - }, - deviceId: { - type: 'integer', - description: '设备ID', - example: 123 - }, - deviceName: { - type: 'string', - description: '设备名称', - example: 'EARTAG001' - }, - eartagNumber: { - type: 'string', - description: '耳标编号', - example: 'EARTAG001' - }, - alertType: { - type: 'string', - description: '预警类型', - enum: ['battery', 'offline', 'temperature', 'movement'], - example: 'offline' - }, - alertLevel: { - type: 'string', - description: '预警级别', - enum: ['high', 'medium', 'low'], - example: 'high' - }, - alertTime: { - type: 'string', - format: 'date-time', - description: '预警时间', - example: '2024-01-15 10:30:00' - }, - battery: { - type: 'integer', - description: '设备电量', - example: 85 - }, - temperature: { - type: 'number', - description: '设备温度', - example: 25.5 - }, - dailySteps: { - type: 'integer', - description: '当日步数', - example: 0 - }, - totalSteps: { - type: 'integer', - description: '总步数', - example: 1500 - }, - yesterdaySteps: { - type: 'integer', - description: '昨日步数', - example: 1500 - }, - deviceStatus: { - type: 'string', - description: '设备状态', - example: '离线' - }, - gpsSignal: { - type: 'string', - description: 'GPS信号', - example: '无' - }, - movementStatus: { - type: 'string', - description: '运动状态', - example: '静止' - }, - description: { - type: 'string', - description: '预警描述', - example: '设备已离线超过30分钟' - }, - longitude: { - type: 'number', - description: '经度', - example: 116.3974 - }, - latitude: { - type: 'number', - description: '纬度', - example: 39.9093 - } - } - }, - CollarAlert: { - type: 'object', - properties: { - id: { - type: 'string', - description: '预警ID', - example: '123_offline' - }, - deviceId: { - type: 'integer', - description: '设备ID', - example: 123 - }, - deviceName: { - type: 'string', - description: '设备名称', - example: 'COLLAR001' - }, - collarNumber: { - type: 'string', - description: '项圈编号', - example: 'COLLAR001' - }, - alertType: { - type: 'string', - description: '预警类型', - enum: ['battery', 'offline', 'temperature', 'movement', 'wear'], - example: 'offline' - }, - alertLevel: { - type: 'string', - description: '预警级别', - enum: ['high', 'medium', 'low'], - example: 'high' - }, - alertTime: { - type: 'string', - format: 'date-time', - description: '预警时间', - example: '2024-01-15 10:30:00' - }, - battery: { - type: 'integer', - description: '设备电量', - example: 85 - }, - temperature: { - type: 'number', - description: '设备温度', - example: 25.5 - }, - dailySteps: { - type: 'integer', - description: '当日步数', - example: 0 - }, - totalSteps: { - type: 'integer', - description: '总步数', - example: 1500 - }, - yesterdaySteps: { - type: 'integer', - description: '昨日步数', - example: 1500 - }, - deviceStatus: { - type: 'string', - description: '设备状态', - example: '离线' - }, - gpsSignal: { - type: 'string', - description: 'GPS信号', - example: '无' - }, - wearStatus: { - type: 'string', - description: '佩戴状态', - example: '未佩戴' - }, - movementStatus: { - type: 'string', - description: '运动状态', - example: '静止' - }, - description: { - type: 'string', - description: '预警描述', - example: '设备已离线超过30分钟' - }, - longitude: { - type: 'number', - description: '经度', - example: 116.3974 - }, - latitude: { - type: 'number', - description: '纬度', - example: 39.9093 - } - } - }, - AlertStats: { - type: 'object', - properties: { - totalDevices: { - type: 'integer', - description: '设备总数', - example: 150 - }, - lowBattery: { - type: 'integer', - description: '低电量预警数量', - example: 12 - }, - offline: { - type: 'integer', - description: '离线预警数量', - example: 8 - }, - highTemperature: { - type: 'integer', - description: '高温预警数量', - example: 5 - }, - lowTemperature: { - type: 'integer', - description: '低温预警数量', - example: 3 - }, - abnormalMovement: { - type: 'integer', - description: '异常运动预警数量', - example: 7 - }, - wearOff: { - type: 'integer', - description: '项圈脱落预警数量(仅项圈)', - example: 2 - }, - totalAlerts: { - type: 'integer', - description: '预警总数', - example: 35 - } - } - }, - ApiResponse: { - type: 'object', - properties: { - success: { - type: 'boolean', - description: '请求是否成功', - example: true - }, - data: { - type: 'object', - description: '响应数据' - }, - message: { - type: 'string', - description: '响应消息', - example: '操作成功' - }, - total: { - type: 'integer', - description: '数据总数(分页时使用)', - example: 100 - }, - stats: { - $ref: '#/components/schemas/AlertStats' - }, - pagination: { - type: 'object', - properties: { - page: { - type: 'integer', - description: '当前页码', - example: 1 - }, - limit: { - type: 'integer', - description: '每页数量', - example: 10 - }, - total: { - type: 'integer', - description: '总数据量', - example: 100 - }, - pages: { - type: 'integer', - description: '总页数', - example: 10 - } - } - } - } - }, - ErrorResponse: { - type: 'object', - properties: { - success: { - type: 'boolean', - description: '请求是否成功', - example: false - }, - message: { - type: 'string', - description: '错误消息', - example: '请求失败' - }, - error: { - type: 'string', - description: '详细错误信息', - example: '具体错误描述' - } - } - } - } - } - }, - apis: [ - './routes/smart-alerts.js', - './controllers/smartEartagAlertController.js', - './controllers/smartCollarAlertController.js' - ] -}; - -const specs = swaggerJSDoc(options); - -module.exports = specs; diff --git a/backend/swagger-devices.js b/backend/swagger-devices.js deleted file mode 100644 index 1429aac..0000000 --- a/backend/swagger-devices.js +++ /dev/null @@ -1,684 +0,0 @@ -/** - * 设备管理模块 Swagger 文档 - * @file swagger-devices.js - */ - -const devicesPaths = { - // 获取所有设备 - '/devices': { - get: { - tags: ['设备管理'], - summary: '获取设备列表', - description: '分页获取系统中的所有设备信息', - parameters: [ - { - name: 'page', - in: 'query', - schema: { type: 'integer', default: 1 }, - description: '页码' - }, - { - name: 'limit', - in: 'query', - schema: { type: 'integer', default: 10 }, - description: '每页数量' - }, - { - name: 'search', - in: 'query', - schema: { type: 'string' }, - description: '搜索关键词(设备名称、设备编号)' - }, - { - name: 'type', - in: 'query', - schema: { type: 'string' }, - description: '设备类型筛选' - }, - { - name: 'status', - in: 'query', - schema: { type: 'string', enum: ['online', 'offline', 'maintenance', 'error'] }, - description: '设备状态筛选' - }, - { - name: 'farmId', - in: 'query', - schema: { type: 'integer' }, - description: '养殖场ID筛选' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { $ref: '#/components/schemas/Device' } - }, - pagination: { - type: 'object', - properties: { - page: { type: 'integer' }, - limit: { type: 'integer' }, - total: { type: 'integer' }, - totalPages: { type: 'integer' } - } - } - } - } - } - } - } - } - }, - post: { - tags: ['设备管理'], - summary: '创建新设备', - description: '添加新的设备到系统中', - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['name', 'type', 'farmId'], - properties: { - name: { type: 'string', description: '设备名称' }, - type: { - type: 'string', - enum: ['collar', 'ear_tag', 'temperature_sensor', 'humidity_sensor', 'camera', 'feeder', 'water_dispenser'], - description: '设备类型' - }, - deviceNumber: { type: 'string', description: '设备编号' }, - model: { type: 'string', description: '设备型号' }, - manufacturer: { type: 'string', description: '制造商' }, - status: { - type: 'string', - enum: ['online', 'offline', 'maintenance', 'error'], - default: 'offline', - description: '设备状态' - }, - farmId: { type: 'integer', description: '所属养殖场ID' }, - location: { type: 'string', description: '设备位置' }, - installationDate: { type: 'string', format: 'date', description: '安装日期' }, - lastMaintenance: { type: 'string', format: 'date', description: '最近维护时间' }, - batteryLevel: { type: 'number', minimum: 0, maximum: 100, description: '电池电量(%)' }, - firmwareVersion: { type: 'string', description: '固件版本' }, - specifications: { type: 'object', description: '设备规格参数' }, - notes: { type: 'string', description: '备注' } - } - } - } - } - }, - responses: { - '201': { - description: '创建成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '设备创建成功' }, - data: { $ref: '#/components/schemas/Device' } - } - } - } - } - }, - '400': { - description: '请求参数错误', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 公共设备数据 - '/devices/public': { - get: { - tags: ['设备管理'], - summary: '获取公共设备数据', - description: '获取可公开访问的设备基本信息', - security: [], // 公共接口不需要认证 - parameters: [ - { - name: 'type', - in: 'query', - schema: { type: 'string' }, - description: '设备类型筛选' - }, - { - name: 'status', - in: 'query', - schema: { type: 'string' }, - description: '设备状态筛选' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { - type: 'object', - properties: { - id: { type: 'integer' }, - name: { type: 'string' }, - type: { type: 'string' }, - status: { type: 'string' }, - location: { type: 'string' } - } - } - } - } - } - } - } - } - } - } - }, - - // 搜索设备 - '/devices/search': { - get: { - tags: ['设备管理'], - summary: '搜索设备', - description: '根据设备名称搜索设备', - parameters: [ - { - name: 'name', - in: 'query', - required: true, - schema: { type: 'string' }, - description: '设备名称关键词' - }, - { - name: 'limit', - in: 'query', - schema: { type: 'integer', default: 10 }, - description: '返回结果数量限制' - } - ], - responses: { - '200': { - description: '搜索成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { $ref: '#/components/schemas/Device' } - } - } - } - } - } - } - } - } - }, - - // 设备统计 - 按状态 - '/devices/stats/status': { - get: { - tags: ['设备管理'], - summary: '按状态统计设备数量', - description: '获取不同状态下的设备数量统计', - responses: { - '200': { - description: '统计成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { - type: 'object', - properties: { - status: { type: 'string', example: 'online' }, - count: { type: 'integer', example: 25 }, - percentage: { type: 'number', example: 62.5 } - } - } - } - } - } - } - } - } - } - } - }, - - // 设备统计 - 按类型 - '/devices/stats/type': { - get: { - tags: ['设备管理'], - summary: '按类型统计设备数量', - description: '获取不同类型设备的数量统计', - responses: { - '200': { - description: '统计成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { - type: 'object', - properties: { - type: { type: 'string', example: 'collar' }, - typeName: { type: 'string', example: '智能项圈' }, - count: { type: 'integer', example: 15 }, - percentage: { type: 'number', example: 37.5 } - } - } - } - } - } - } - } - } - } - } - }, - - // 获取指定设备详情 - '/devices/{id}': { - get: { - tags: ['设备管理'], - summary: '获取设备详情', - description: '根据设备ID获取详细信息', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '设备ID' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { $ref: '#/components/schemas/Device' } - } - } - } - } - }, - '404': { - description: '设备不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - }, - put: { - tags: ['设备管理'], - summary: '更新设备信息', - description: '更新指定设备的信息', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '设备ID' - } - ], - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - name: { type: 'string', description: '设备名称' }, - type: { type: 'string', description: '设备类型' }, - deviceNumber: { type: 'string', description: '设备编号' }, - model: { type: 'string', description: '设备型号' }, - manufacturer: { type: 'string', description: '制造商' }, - status: { - type: 'string', - enum: ['online', 'offline', 'maintenance', 'error'], - description: '设备状态' - }, - farmId: { type: 'integer', description: '所属养殖场ID' }, - location: { type: 'string', description: '设备位置' }, - lastMaintenance: { type: 'string', format: 'date', description: '最近维护时间' }, - batteryLevel: { type: 'number', minimum: 0, maximum: 100, description: '电池电量(%)' }, - firmwareVersion: { type: 'string', description: '固件版本' }, - specifications: { type: 'object', description: '设备规格参数' }, - notes: { type: 'string', description: '备注' } - } - } - } - } - }, - responses: { - '200': { - description: '更新成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '设备信息更新成功' }, - data: { $ref: '#/components/schemas/Device' } - } - } - } - } - }, - '400': { - description: '请求参数错误', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - }, - '404': { - description: '设备不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - }, - delete: { - tags: ['设备管理'], - summary: '删除设备', - description: '删除指定设备(软删除)', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '设备ID' - } - ], - responses: { - '200': { - description: '删除成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '设备删除成功' } - } - } - } - } - }, - '404': { - description: '设备不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 设备维护记录 - '/devices/{id}/maintenance': { - get: { - tags: ['设备管理'], - summary: '获取设备维护记录', - description: '获取指定设备的维护记录', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '设备ID' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { - type: 'object', - properties: { - id: { type: 'integer' }, - deviceId: { type: 'integer' }, - maintenanceDate: { type: 'string', format: 'date' }, - maintenanceType: { type: 'string', enum: ['routine', 'repair', 'upgrade'] }, - description: { type: 'string' }, - technician: { type: 'string' }, - cost: { type: 'number' }, - notes: { type: 'string' } - } - } - } - } - } - } - } - } - } - }, - post: { - tags: ['设备管理'], - summary: '添加设备维护记录', - description: '为指定设备添加维护记录', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '设备ID' - } - ], - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['maintenanceDate', 'maintenanceType', 'description'], - properties: { - maintenanceDate: { type: 'string', format: 'date', description: '维护日期' }, - maintenanceType: { - type: 'string', - enum: ['routine', 'repair', 'upgrade'], - description: '维护类型' - }, - description: { type: 'string', description: '维护描述' }, - technician: { type: 'string', description: '技术员姓名' }, - cost: { type: 'number', description: '维护费用' }, - notes: { type: 'string', description: '备注' } - } - } - } - } - }, - responses: { - '201': { - description: '添加成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '维护记录添加成功' } - } - } - } - } - } - } - } - }, - - // 设备数据监控 - '/devices/{id}/data': { - get: { - tags: ['设备管理'], - summary: '获取设备监控数据', - description: '获取指定设备的实时监控数据', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '设备ID' - }, - { - name: 'startTime', - in: 'query', - schema: { type: 'string', format: 'date-time' }, - description: '开始时间' - }, - { - name: 'endTime', - in: 'query', - schema: { type: 'string', format: 'date-time' }, - description: '结束时间' - }, - { - name: 'dataType', - in: 'query', - schema: { type: 'string', enum: ['temperature', 'humidity', 'location', 'battery', 'activity'] }, - description: '数据类型' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { - type: 'object', - properties: { - timestamp: { type: 'string', format: 'date-time' }, - dataType: { type: 'string' }, - value: { type: 'number' }, - unit: { type: 'string' }, - location: { - type: 'object', - properties: { - latitude: { type: 'number' }, - longitude: { type: 'number' } - } - } - } - } - } - } - } - } - } - } - } - } - } -}; - -// 设备数据模型 -const deviceSchemas = { - Device: { - type: 'object', - properties: { - id: { type: 'integer', description: '设备ID' }, - name: { type: 'string', description: '设备名称' }, - type: { - type: 'string', - enum: ['collar', 'ear_tag', 'temperature_sensor', 'humidity_sensor', 'camera', 'feeder', 'water_dispenser'], - description: '设备类型' - }, - deviceNumber: { type: 'string', description: '设备编号' }, - model: { type: 'string', description: '设备型号' }, - manufacturer: { type: 'string', description: '制造商' }, - status: { - type: 'string', - enum: ['online', 'offline', 'maintenance', 'error'], - description: '设备状态' - }, - farmId: { type: 'integer', description: '所属养殖场ID' }, - farmName: { type: 'string', description: '养殖场名称' }, - location: { type: 'string', description: '设备位置' }, - installationDate: { type: 'string', format: 'date', description: '安装日期' }, - lastMaintenance: { type: 'string', format: 'date', description: '最近维护时间' }, - batteryLevel: { type: 'number', minimum: 0, maximum: 100, description: '电池电量(%)' }, - firmwareVersion: { type: 'string', description: '固件版本' }, - specifications: { - type: 'object', - description: '设备规格参数', - additionalProperties: true - }, - lastDataTime: { type: 'string', format: 'date-time', description: '最后数据时间' }, - isActive: { type: 'boolean', description: '是否激活' }, - notes: { type: 'string', description: '备注' }, - createdAt: { type: 'string', format: 'date-time', description: '创建时间' }, - updatedAt: { type: 'string', format: 'date-time', description: '更新时间' } - } - } -}; - -module.exports = { devicesPaths, deviceSchemas }; \ No newline at end of file diff --git a/backend/swagger-farms.js b/backend/swagger-farms.js deleted file mode 100644 index 06744f6..0000000 --- a/backend/swagger-farms.js +++ /dev/null @@ -1,623 +0,0 @@ -/** - * 养殖场管理模块 Swagger 文档 - * @file swagger-farms.js - */ - -const farmsPaths = { - // 获取所有养殖场 - '/farms': { - get: { - tags: ['养殖场管理'], - summary: '获取养殖场列表', - description: '分页获取系统中的所有养殖场', - parameters: [ - { - name: 'page', - in: 'query', - schema: { type: 'integer', default: 1 }, - description: '页码' - }, - { - name: 'limit', - in: 'query', - schema: { type: 'integer', default: 10 }, - description: '每页数量' - }, - { - name: 'search', - in: 'query', - schema: { type: 'string' }, - description: '搜索关键词(养殖场名称、地址)' - }, - { - name: 'status', - in: 'query', - schema: { type: 'string', enum: ['active', 'inactive', 'suspended'] }, - description: '养殖场状态筛选' - }, - { - name: 'type', - in: 'query', - schema: { type: 'string', enum: ['cattle', 'sheep', 'pig', 'poultry'] }, - description: '养殖类型筛选' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { $ref: '#/components/schemas/Farm' } - }, - pagination: { - type: 'object', - properties: { - page: { type: 'integer' }, - limit: { type: 'integer' }, - total: { type: 'integer' }, - totalPages: { type: 'integer' } - } - } - } - } - } - } - } - } - }, - post: { - tags: ['养殖场管理'], - summary: '创建新养殖场', - description: '创建新的养殖场记录', - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['name', 'address', 'type', 'ownerId'], - properties: { - name: { type: 'string', description: '养殖场名称' }, - address: { type: 'string', description: '养殖场地址' }, - type: { - type: 'string', - enum: ['cattle', 'sheep', 'pig', 'poultry'], - description: '养殖类型:cattle-牛,sheep-羊,pig-猪,poultry-家禽' - }, - ownerId: { type: 'integer', description: '养殖场主ID' }, - description: { type: 'string', description: '养殖场描述' }, - area: { type: 'number', description: '养殖场面积(平方米)' }, - capacity: { type: 'integer', description: '最大养殖容量' }, - contactPhone: { type: 'string', description: '联系电话' }, - contactEmail: { type: 'string', format: 'email', description: '联系邮箱' }, - coordinates: { - type: 'object', - properties: { - latitude: { type: 'number', description: '纬度' }, - longitude: { type: 'number', description: '经度' } - }, - description: '地理坐标' - }, - status: { - type: 'string', - enum: ['active', 'inactive', 'suspended'], - default: 'active', - description: '养殖场状态' - } - } - } - } - } - }, - responses: { - '201': { - description: '创建成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '养殖场创建成功' }, - data: { $ref: '#/components/schemas/Farm' } - } - } - } - } - }, - '400': { - description: '请求参数错误', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 搜索养殖场 - '/farms/search': { - get: { - tags: ['养殖场管理'], - summary: '搜索养殖场', - description: '根据名称、地址等关键词搜索养殖场', - parameters: [ - { - name: 'q', - in: 'query', - required: true, - schema: { type: 'string' }, - description: '搜索关键词' - }, - { - name: 'limit', - in: 'query', - schema: { type: 'integer', default: 10 }, - description: '返回结果数量限制' - } - ], - responses: { - '200': { - description: '搜索成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { $ref: '#/components/schemas/Farm' } - } - } - } - } - } - } - } - } - }, - - // 公共养殖场数据 - '/farms/public': { - get: { - tags: ['养殖场管理'], - summary: '获取公共养殖场数据', - description: '获取可公开访问的养殖场基本信息', - security: [], // 公共接口不需要认证 - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { - type: 'object', - properties: { - id: { type: 'integer' }, - name: { type: 'string' }, - type: { type: 'string' }, - address: { type: 'string' }, - area: { type: 'number' } - } - } - } - } - } - } - } - } - } - } - }, - - // 获取指定养殖场详情 - '/farms/{id}': { - get: { - tags: ['养殖场管理'], - summary: '获取养殖场详情', - description: '根据养殖场ID获取详细信息', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '养殖场ID' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { $ref: '#/components/schemas/Farm' } - } - } - } - } - }, - '404': { - description: '养殖场不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - }, - put: { - tags: ['养殖场管理'], - summary: '更新养殖场信息', - description: '更新指定养殖场的信息', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '养殖场ID' - } - ], - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - name: { type: 'string', description: '养殖场名称' }, - address: { type: 'string', description: '养殖场地址' }, - type: { - type: 'string', - enum: ['cattle', 'sheep', 'pig', 'poultry'], - description: '养殖类型' - }, - description: { type: 'string', description: '养殖场描述' }, - area: { type: 'number', description: '养殖场面积(平方米)' }, - capacity: { type: 'integer', description: '最大养殖容量' }, - contactPhone: { type: 'string', description: '联系电话' }, - contactEmail: { type: 'string', format: 'email', description: '联系邮箱' }, - coordinates: { - type: 'object', - properties: { - latitude: { type: 'number', description: '纬度' }, - longitude: { type: 'number', description: '经度' } - }, - description: '地理坐标' - }, - status: { - type: 'string', - enum: ['active', 'inactive', 'suspended'], - description: '养殖场状态' - } - } - } - } - } - }, - responses: { - '200': { - description: '更新成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '养殖场信息更新成功' }, - data: { $ref: '#/components/schemas/Farm' } - } - } - } - } - }, - '400': { - description: '请求参数错误', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - }, - '404': { - description: '养殖场不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - }, - delete: { - tags: ['养殖场管理'], - summary: '删除养殖场', - description: '删除指定养殖场(软删除)', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '养殖场ID' - } - ], - responses: { - '200': { - description: '删除成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '养殖场删除成功' } - } - } - } - } - }, - '404': { - description: '养殖场不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 获取养殖场的动物列表 - '/farms/{id}/animals': { - get: { - tags: ['养殖场管理'], - summary: '获取养殖场的动物列表', - description: '获取指定养殖场的所有动物', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '养殖场ID' - }, - { - name: 'page', - in: 'query', - schema: { type: 'integer', default: 1 }, - description: '页码' - }, - { - name: 'limit', - in: 'query', - schema: { type: 'integer', default: 10 }, - description: '每页数量' - }, - { - name: 'status', - in: 'query', - schema: { type: 'string', enum: ['healthy', 'sick', 'quarantine', 'sold'] }, - description: '动物状态筛选' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { $ref: '#/components/schemas/Animal' } - }, - pagination: { - type: 'object', - properties: { - page: { type: 'integer' }, - limit: { type: 'integer' }, - total: { type: 'integer' }, - totalPages: { type: 'integer' } - } - } - } - } - } - } - }, - '404': { - description: '养殖场不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 获取养殖场的设备列表 - '/farms/{id}/devices': { - get: { - tags: ['养殖场管理'], - summary: '获取养殖场的设备列表', - description: '获取指定养殖场的所有设备', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '养殖场ID' - }, - { - name: 'type', - in: 'query', - schema: { type: 'string', enum: ['sensor', 'camera', 'feeder', 'monitor'] }, - description: '设备类型筛选' - }, - { - name: 'status', - in: 'query', - schema: { type: 'string', enum: ['online', 'offline', 'maintenance'] }, - description: '设备状态筛选' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { $ref: '#/components/schemas/Device' } - } - } - } - } - } - }, - '404': { - description: '养殖场不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 获取养殖场统计信息 - '/farms/{id}/statistics': { - get: { - tags: ['养殖场管理'], - summary: '获取养殖场统计信息', - description: '获取指定养殖场的统计数据', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '养殖场ID' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'object', - properties: { - totalAnimals: { type: 'integer', description: '动物总数' }, - healthyAnimals: { type: 'integer', description: '健康动物数' }, - sickAnimals: { type: 'integer', description: '患病动物数' }, - totalDevices: { type: 'integer', description: '设备总数' }, - onlineDevices: { type: 'integer', description: '在线设备数' }, - offlineDevices: { type: 'integer', description: '离线设备数' }, - alertsCount: { type: 'integer', description: '预警数量' }, - utilizationRate: { type: 'number', description: '利用率(%)' } - } - } - } - } - } - } - }, - '404': { - description: '养殖场不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - } -}; - -// 养殖场数据模型 -const farmSchemas = { - Farm: { - type: 'object', - properties: { - id: { type: 'integer', description: '养殖场ID' }, - name: { type: 'string', description: '养殖场名称' }, - address: { type: 'string', description: '养殖场地址' }, - type: { - type: 'string', - enum: ['cattle', 'sheep', 'pig', 'poultry'], - description: '养殖类型:cattle-牛,sheep-羊,pig-猪,poultry-家禽' - }, - description: { type: 'string', description: '养殖场描述' }, - area: { type: 'number', description: '养殖场面积(平方米)' }, - capacity: { type: 'integer', description: '最大养殖容量' }, - currentCount: { type: 'integer', description: '当前动物数量' }, - contactPhone: { type: 'string', description: '联系电话' }, - contactEmail: { type: 'string', format: 'email', description: '联系邮箱' }, - coordinates: { - type: 'object', - properties: { - latitude: { type: 'number', description: '纬度' }, - longitude: { type: 'number', description: '经度' } - }, - description: '地理坐标' - }, - status: { - type: 'string', - enum: ['active', 'inactive', 'suspended'], - description: '养殖场状态:active-活跃,inactive-未激活,suspended-暂停' - }, - owner: { - type: 'object', - properties: { - id: { type: 'integer' }, - username: { type: 'string' }, - realName: { type: 'string' }, - phone: { type: 'string' } - }, - description: '养殖场主信息' - }, - createdAt: { type: 'string', format: 'date-time', description: '创建时间' }, - updatedAt: { type: 'string', format: 'date-time', description: '更新时间' } - } - } -}; - -module.exports = { farmsPaths, farmSchemas }; \ No newline at end of file diff --git a/backend/swagger-reports.js b/backend/swagger-reports.js deleted file mode 100644 index 23a4902..0000000 --- a/backend/swagger-reports.js +++ /dev/null @@ -1,736 +0,0 @@ -/** - * 报表管理模块 Swagger 文档 - * @file swagger-reports.js - * @description 定义报表管理相关的API文档 - */ - -/** - * @swagger - * tags: - * - name: 报表管理 - * description: 报表生成、下载和管理 - */ - -/** - * @swagger - * components: - * schemas: - * ReportGenerateRequest: - * type: object - * properties: - * startDate: - * type: string - * format: date - * description: 开始日期 - * example: "2024-01-01" - * endDate: - * type: string - * format: date - * description: 结束日期 - * example: "2024-01-31" - * format: - * type: string - * enum: [pdf, excel, csv] - * description: 报表格式 - * example: "pdf" - * - * FarmReportRequest: - * allOf: - * - $ref: '#/components/schemas/ReportGenerateRequest' - * - type: object - * properties: - * farmIds: - * type: array - * items: - * type: string - * description: 养殖场ID列表 - * example: ["farm_001", "farm_002"] - * - * SalesReportRequest: - * allOf: - * - $ref: '#/components/schemas/ReportGenerateRequest' - * - type: object - * properties: - * format: - * type: string - * enum: [pdf, excel] - * description: 报表格式(销售报表不支持CSV) - * example: "excel" - * - * ComplianceReportRequest: - * allOf: - * - $ref: '#/components/schemas/ReportGenerateRequest' - * - type: object - * properties: - * format: - * type: string - * enum: [pdf, excel] - * description: 报表格式(合规报表不支持CSV) - * example: "pdf" - * - * ReportFile: - * type: object - * properties: - * fileName: - * type: string - * description: 文件名 - * example: "farm_report_20240115.pdf" - * downloadUrl: - * type: string - * description: 下载链接 - * example: "/api/reports/download/farm_report_20240115.pdf" - * mimeType: - * type: string - * description: 文件MIME类型 - * example: "application/pdf" - * size: - * type: integer - * description: 文件大小(字节) - * example: 1024000 - * generatedAt: - * type: string - * format: date-time - * description: 生成时间 - * example: "2024-01-15T10:30:00Z" - * - * ReportListItem: - * type: object - * properties: - * id: - * type: string - * description: 报表ID - * example: "report_001" - * fileName: - * type: string - * description: 文件名 - * example: "farm_report_20240115.pdf" - * type: - * type: string - * enum: [farm, sales, compliance, export] - * description: 报表类型 - * example: "farm" - * format: - * type: string - * enum: [pdf, excel, csv] - * description: 文件格式 - * example: "pdf" - * size: - * type: integer - * description: 文件大小(字节) - * example: 1024000 - * status: - * type: string - * enum: [generating, completed, failed, expired] - * description: 报表状态 - * example: "completed" - * createdBy: - * type: string - * description: 创建者 - * example: "admin" - * createdAt: - * type: string - * format: date-time - * description: 创建时间 - * example: "2024-01-15T10:30:00Z" - * expiresAt: - * type: string - * format: date-time - * description: 过期时间 - * example: "2024-01-22T10:30:00Z" - * downloadUrl: - * type: string - * description: 下载链接 - * example: "/api/reports/download/farm_report_20240115.pdf" - * - * ReportTemplate: - * type: object - * properties: - * id: - * type: string - * description: 模板ID - * example: "template_001" - * name: - * type: string - * description: 模板名称 - * example: "养殖场月度报表模板" - * type: - * type: string - * enum: [farm, sales, compliance] - * description: 模板类型 - * example: "farm" - * description: - * type: string - * description: 模板描述 - * example: "包含养殖场基本信息、动物统计、设备状态等" - * fields: - * type: array - * items: - * type: object - * properties: - * name: - * type: string - * description: 字段名称 - * label: - * type: string - * description: 字段标签 - * type: - * type: string - * description: 字段类型 - * required: - * type: boolean - * description: 是否必填 - * description: 模板字段配置 - * isDefault: - * type: boolean - * description: 是否为默认模板 - * example: true - * createdAt: - * type: string - * format: date-time - * description: 创建时间 - * example: "2024-01-15T10:30:00Z" - * - * ExportDataRequest: - * type: object - * properties: - * format: - * type: string - * enum: [excel, csv] - * description: 导出格式 - * example: "excel" - * filters: - * type: object - * description: 筛选条件 - * properties: - * status: - * type: string - * description: 状态筛选 - * startDate: - * type: string - * format: date - * description: 开始日期 - * endDate: - * type: string - * format: date - * description: 结束日期 - */ - -/** - * @swagger - * /reports/farm: - * post: - * tags: - * - 报表管理 - * summary: 生成养殖统计报表 - * description: 生成指定时间范围和养殖场的统计报表 - * security: - * - bearerAuth: [] - * requestBody: - * required: false - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/FarmReportRequest' - * responses: - * 200: - * description: 报表生成成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/ReportFile' - * 400: - * description: 请求参数错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /reports/sales: - * post: - * tags: - * - 报表管理 - * summary: 生成销售分析报表 - * description: 生成指定时间范围的销售分析报表(需要管理员或经理权限) - * security: - * - bearerAuth: [] - * requestBody: - * required: false - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SalesReportRequest' - * responses: - * 200: - * description: 报表生成成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/ReportFile' - * 400: - * description: 请求参数错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 权限不足 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /reports/compliance: - * post: - * tags: - * - 报表管理 - * summary: 生成监管合规报表 - * description: 生成指定时间范围的监管合规报表(仅限管理员) - * security: - * - bearerAuth: [] - * requestBody: - * required: false - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ComplianceReportRequest' - * responses: - * 200: - * description: 报表生成成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/ReportFile' - * 400: - * description: 请求参数错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 权限不足(仅限管理员) - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /reports/download/{fileName}: - * get: - * tags: - * - 报表管理 - * summary: 下载报表文件 - * description: 下载指定的报表文件 - * security: - * - bearerAuth: [] - * parameters: - * - in: path - * name: fileName - * required: true - * schema: - * type: string - * description: 文件名(需要URL编码) - * example: "farm_report_20240115.pdf" - * responses: - * 200: - * description: 文件下载成功 - * content: - * application/pdf: - * schema: - * type: string - * format: binary - * application/vnd.openxmlformats-officedocument.spreadsheetml.sheet: - * schema: - * type: string - * format: binary - * text/csv: - * schema: - * type: string - * format: binary - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 非法文件路径 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 404: - * description: 文件不存在 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /reports/list: - * get: - * tags: - * - 报表管理 - * summary: 获取报表列表 - * description: 获取当前用户的报表列表,支持分页和筛选 - * security: - * - bearerAuth: [] - * parameters: - * - $ref: '#/components/parameters/PaginationQuery/properties/page' - * - $ref: '#/components/parameters/PaginationQuery/properties/limit' - * - in: query - * name: type - * schema: - * type: string - * enum: [farm, sales, compliance, export] - * description: 报表类型筛选 - * - in: query - * name: status - * schema: - * type: string - * enum: [generating, completed, failed, expired] - * description: 报表状态筛选 - * - in: query - * name: format - * schema: - * type: string - * enum: [pdf, excel, csv] - * description: 文件格式筛选 - * - in: query - * name: startDate - * schema: - * type: string - * format: date - * description: 创建开始日期 - * - in: query - * name: endDate - * schema: - * type: string - * format: date - * description: 创建结束日期 - * responses: - * 200: - * description: 获取列表成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: object - * properties: - * reports: - * type: array - * items: - * $ref: '#/components/schemas/ReportListItem' - * pagination: - * type: object - * properties: - * total: - * type: integer - * example: 50 - * page: - * type: integer - * example: 1 - * limit: - * type: integer - * example: 10 - * totalPages: - * type: integer - * example: 5 - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /reports/cleanup: - * post: - * tags: - * - 报表管理 - * summary: 清理过期报表 - * description: 清理过期的报表文件(仅限管理员) - * security: - * - bearerAuth: [] - * requestBody: - * required: false - * content: - * application/json: - * schema: - * type: object - * properties: - * daysOld: - * type: integer - * description: 清理多少天前的文件 - * example: 30 - * force: - * type: boolean - * description: 是否强制清理(包括未过期的文件) - * example: false - * responses: - * 200: - * description: 清理成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: object - * properties: - * deletedCount: - * type: integer - * description: 删除的文件数量 - * example: 15 - * freedSpace: - * type: integer - * description: 释放的空间(字节) - * example: 15360000 - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 权限不足(仅限管理员) - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /reports/export/farms: - * get: - * tags: - * - 报表管理 - * summary: 导出养殖场数据 - * description: 导出养殖场基础数据为Excel或CSV格式 - * security: - * - bearerAuth: [] - * parameters: - * - in: query - * name: format - * schema: - * type: string - * enum: [excel, csv] - * default: excel - * description: 导出格式 - * - in: query - * name: status - * schema: - * type: string - * enum: [active, inactive, all] - * default: all - * description: 状态筛选 - * responses: - * 200: - * description: 导出成功 - * content: - * application/vnd.openxmlformats-officedocument.spreadsheetml.sheet: - * schema: - * type: string - * format: binary - * text/csv: - * schema: - * type: string - * format: binary - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /reports/export/devices: - * get: - * tags: - * - 报表管理 - * summary: 导出设备数据 - * description: 导出设备基础数据为Excel或CSV格式 - * security: - * - bearerAuth: [] - * parameters: - * - in: query - * name: format - * schema: - * type: string - * enum: [excel, csv] - * default: excel - * description: 导出格式 - * - in: query - * name: status - * schema: - * type: string - * enum: [online, offline, maintenance, all] - * default: all - * description: 设备状态筛选 - * responses: - * 200: - * description: 导出成功 - * content: - * application/vnd.openxmlformats-officedocument.spreadsheetml.sheet: - * schema: - * type: string - * format: binary - * text/csv: - * schema: - * type: string - * format: binary - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /reports/templates: - * get: - * tags: - * - 报表管理 - * summary: 获取报表模板列表 - * description: 获取可用的报表模板列表 - * security: - * - bearerAuth: [] - * parameters: - * - in: query - * name: type - * schema: - * type: string - * enum: [farm, sales, compliance] - * description: 模板类型筛选 - * responses: - * 200: - * description: 获取模板列表成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: array - * items: - * $ref: '#/components/schemas/ReportTemplate' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -module.exports = {}; \ No newline at end of file diff --git a/backend/swagger-simple.js b/backend/swagger-simple.js deleted file mode 100644 index c26330b..0000000 --- a/backend/swagger-simple.js +++ /dev/null @@ -1,520 +0,0 @@ -/** - * 简化版Swagger配置 - * @file swagger-simple.js - * @description 简化的Swagger配置,确保API路径正确显示 - */ - -const swaggerJSDoc = require('swagger-jsdoc'); - -const options = { - definition: { - openapi: '3.0.0', - info: { - title: '智能预警系统 API', - version: '1.0.0', - description: '智能耳标预警和智能项圈预警系统API文档', - contact: { - name: '开发团队', - email: 'dev@example.com' - } - }, - servers: [ - { - url: 'http://localhost:5350/api', - description: '开发环境' - } - ], - tags: [ - { - name: '智能耳标预警', - description: '智能耳标预警相关接口' - }, - { - name: '智能项圈预警', - description: '智能项圈预警相关接口' - } - ] - }, - apis: ['./routes/smart-alerts.js'] -}; - -const specs = swaggerJSDoc(options); - -// 手动添加API路径,确保它们出现在文档中 -if (!specs.paths) { - specs.paths = {}; -} - -// 智能耳标预警API路径 -specs.paths['/smart-alerts/public/eartag/stats'] = { - get: { - tags: ['智能耳标预警'], - summary: '获取智能耳标预警统计', - description: '获取智能耳标预警的统计数据,包括各类预警的数量和设备总数', - responses: { - '200': { - description: '获取统计成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean' }, - data: { type: 'object' }, - message: { type: 'string' } - } - } - } - } - } - } - } -}; - -specs.paths['/smart-alerts/public/eartag'] = { - get: { - tags: ['智能耳标预警'], - summary: '获取智能耳标预警列表', - description: '获取智能耳标预警列表,支持分页、搜索和筛选', - parameters: [ - { - name: 'page', - in: 'query', - schema: { type: 'integer', default: 1 }, - description: '页码' - }, - { - name: 'limit', - in: 'query', - schema: { type: 'integer', default: 10 }, - description: '每页数量' - }, - { - name: 'search', - in: 'query', - schema: { type: 'string' }, - description: '搜索关键词' - }, - { - name: 'alertType', - in: 'query', - schema: { type: 'string', enum: ['battery', 'offline', 'temperature', 'movement'] }, - description: '预警类型筛选' - } - ], - responses: { - '200': { - description: '获取列表成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean' }, - data: { type: 'array', items: { type: 'object' } }, - total: { type: 'integer' }, - message: { type: 'string' } - } - } - } - } - } - } - } -}; - -specs.paths['/smart-alerts/public/eartag/{id}'] = { - get: { - tags: ['智能耳标预警'], - summary: '获取单个智能耳标预警详情', - description: '获取指定ID的智能耳标预警详细信息', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'string' }, - description: '预警ID' - } - ], - responses: { - '200': { - description: '获取详情成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean' }, - data: { type: 'object' }, - message: { type: 'string' } - } - } - } - } - } - } - } -}; - -specs.paths['/smart-alerts/public/eartag/{id}/handle'] = { - post: { - tags: ['智能耳标预警'], - summary: '处理智能耳标预警', - description: '处理指定的智能耳标预警', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'string' }, - description: '预警ID' - } - ], - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - action: { type: 'string', description: '处理动作' }, - notes: { type: 'string', description: '处理备注' }, - handler: { type: 'string', description: '处理人' } - } - } - } - } - }, - responses: { - '200': { - description: '处理成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean' }, - data: { type: 'object' }, - message: { type: 'string' } - } - } - } - } - } - } - } -}; - -specs.paths['/smart-alerts/public/eartag/batch-handle'] = { - post: { - tags: ['智能耳标预警'], - summary: '批量处理智能耳标预警', - description: '批量处理多个智能耳标预警', - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['alertIds'], - properties: { - alertIds: { type: 'array', items: { type: 'string' }, description: '预警ID列表' }, - action: { type: 'string', description: '处理动作' }, - notes: { type: 'string', description: '处理备注' }, - handler: { type: 'string', description: '处理人' } - } - } - } - } - }, - responses: { - '200': { - description: '批量处理成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean' }, - data: { type: 'object' }, - message: { type: 'string' } - } - } - } - } - } - } - } -}; - -specs.paths['/smart-alerts/public/eartag/export'] = { - get: { - tags: ['智能耳标预警'], - summary: '导出智能耳标预警数据', - description: '导出智能耳标预警数据,支持JSON和CSV格式', - parameters: [ - { - name: 'format', - in: 'query', - schema: { type: 'string', enum: ['json', 'csv'], default: 'json' }, - description: '导出格式' - } - ], - responses: { - '200': { - description: '导出成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean' }, - data: { type: 'array', items: { type: 'object' } }, - message: { type: 'string' } - } - } - } - } - } - } - } -}; - -// 智能项圈预警API路径 -specs.paths['/smart-alerts/public/collar/stats'] = { - get: { - tags: ['智能项圈预警'], - summary: '获取智能项圈预警统计', - description: '获取智能项圈预警的统计数据,包括各类预警的数量和设备总数', - responses: { - '200': { - description: '获取统计成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean' }, - data: { type: 'object' }, - message: { type: 'string' } - } - } - } - } - } - } - } -}; - -specs.paths['/smart-alerts/public/collar'] = { - get: { - tags: ['智能项圈预警'], - summary: '获取智能项圈预警列表', - description: '获取智能项圈预警列表,支持分页、搜索和筛选', - parameters: [ - { - name: 'page', - in: 'query', - schema: { type: 'integer', default: 1 }, - description: '页码' - }, - { - name: 'limit', - in: 'query', - schema: { type: 'integer', default: 10 }, - description: '每页数量' - }, - { - name: 'search', - in: 'query', - schema: { type: 'string' }, - description: '搜索关键词' - }, - { - name: 'alertType', - in: 'query', - schema: { type: 'string', enum: ['battery', 'offline', 'temperature', 'movement', 'wear'] }, - description: '预警类型筛选' - } - ], - responses: { - '200': { - description: '获取列表成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean' }, - data: { type: 'array', items: { type: 'object' } }, - total: { type: 'integer' }, - message: { type: 'string' } - } - } - } - } - } - } - } -}; - -specs.paths['/smart-alerts/public/collar/{id}'] = { - get: { - tags: ['智能项圈预警'], - summary: '获取单个智能项圈预警详情', - description: '获取指定ID的智能项圈预警详细信息', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'string' }, - description: '预警ID' - } - ], - responses: { - '200': { - description: '获取详情成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean' }, - data: { type: 'object' }, - message: { type: 'string' } - } - } - } - } - } - } - } -}; - -specs.paths['/smart-alerts/public/collar/{id}/handle'] = { - post: { - tags: ['智能项圈预警'], - summary: '处理智能项圈预警', - description: '处理指定的智能项圈预警', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'string' }, - description: '预警ID' - } - ], - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - action: { type: 'string', description: '处理动作' }, - notes: { type: 'string', description: '处理备注' }, - handler: { type: 'string', description: '处理人' } - } - } - } - } - }, - responses: { - '200': { - description: '处理成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean' }, - data: { type: 'object' }, - message: { type: 'string' } - } - } - } - } - } - } - } -}; - -specs.paths['/smart-alerts/public/collar/batch-handle'] = { - post: { - tags: ['智能项圈预警'], - summary: '批量处理智能项圈预警', - description: '批量处理多个智能项圈预警', - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['alertIds'], - properties: { - alertIds: { type: 'array', items: { type: 'string' }, description: '预警ID列表' }, - action: { type: 'string', description: '处理动作' }, - notes: { type: 'string', description: '处理备注' }, - handler: { type: 'string', description: '处理人' } - } - } - } - } - }, - responses: { - '200': { - description: '批量处理成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean' }, - data: { type: 'object' }, - message: { type: 'string' } - } - } - } - } - } - } - } -}; - -specs.paths['/smart-alerts/public/collar/export'] = { - get: { - tags: ['智能项圈预警'], - summary: '导出智能项圈预警数据', - description: '导出智能项圈预警数据,支持JSON和CSV格式', - parameters: [ - { - name: 'format', - in: 'query', - schema: { type: 'string', enum: ['json', 'csv'], default: 'json' }, - description: '导出格式' - } - ], - responses: { - '200': { - description: '导出成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean' }, - data: { type: 'array', items: { type: 'object' } }, - message: { type: 'string' } - } - } - } - } - } - } - } -}; - -module.exports = specs; diff --git a/backend/swagger-smart-alerts.js b/backend/swagger-smart-alerts.js deleted file mode 100644 index 0a1b89c..0000000 --- a/backend/swagger-smart-alerts.js +++ /dev/null @@ -1,1004 +0,0 @@ -/** - * 智能预警模块 Swagger 文档 - * @file swagger-smart-alerts.js - * @description 定义智能预警相关的API文档 - */ - -/** - * @swagger - * tags: - * - name: 智能预警 - * description: 智能预警系统管理 - * - name: 智能耳标预警 - * description: 智能耳标预警管理 - * - name: 智能项圈预警 - * description: 智能项圈预警管理 - */ - -/** - * @swagger - * components: - * schemas: - * AlertStats: - * type: object - * properties: - * totalAlerts: - * type: integer - * description: 总预警数量 - * example: 25 - * eartagAlerts: - * type: integer - * description: 耳标预警数量 - * example: 15 - * collarAlerts: - * type: integer - * description: 项圈预警数量 - * example: 10 - * eartagDevices: - * type: integer - * description: 耳标设备总数 - * example: 100 - * collarDevices: - * type: integer - * description: 项圈设备总数 - * example: 80 - * alertsByType: - * type: object - * properties: - * battery: - * type: integer - * description: 电量预警数量 - * example: 5 - * offline: - * type: integer - * description: 离线预警数量 - * example: 8 - * temperature: - * type: integer - * description: 温度预警数量 - * example: 3 - * movement: - * type: integer - * description: 运动预警数量 - * example: 6 - * wear: - * type: integer - * description: 佩戴预警数量 - * example: 3 - * alertsByLevel: - * type: object - * properties: - * high: - * type: integer - * description: 高级预警数量 - * example: 8 - * medium: - * type: integer - * description: 中级预警数量 - * example: 12 - * low: - * type: integer - * description: 低级预警数量 - * example: 5 - * - * EartagAlert: - * type: object - * properties: - * id: - * type: string - * description: 预警ID - * example: "alert_001" - * deviceId: - * type: string - * description: 设备ID - * example: "eartag_001" - * deviceName: - * type: string - * description: 设备名称 - * example: "耳标设备001" - * animalId: - * type: string - * description: 动物ID - * example: "animal_001" - * animalName: - * type: string - * description: 动物名称 - * example: "牛001" - * farmId: - * type: string - * description: 养殖场ID - * example: "farm_001" - * farmName: - * type: string - * description: 养殖场名称 - * example: "示例养殖场" - * alertType: - * type: string - * enum: [battery, offline, temperature, movement, wear] - * description: 预警类型 - * example: "battery" - * alertLevel: - * type: string - * enum: [high, medium, low] - * description: 预警级别 - * example: "high" - * alertMessage: - * type: string - * description: 预警消息 - * example: "设备电量低于10%" - * alertValue: - * type: number - * description: 预警值 - * example: 8.5 - * threshold: - * type: number - * description: 阈值 - * example: 10 - * status: - * type: string - * enum: [pending, processing, resolved, ignored] - * description: 处理状态 - * example: "pending" - * isHandled: - * type: boolean - * description: 是否已处理 - * example: false - * handledBy: - * type: string - * description: 处理人 - * example: "admin" - * handledAt: - * type: string - * format: date-time - * description: 处理时间 - * example: "2024-01-15T10:30:00Z" - * handledNote: - * type: string - * description: 处理备注 - * example: "已更换电池" - * createdAt: - * type: string - * format: date-time - * description: 创建时间 - * example: "2024-01-15T08:30:00Z" - * updatedAt: - * type: string - * format: date-time - * description: 更新时间 - * example: "2024-01-15T10:30:00Z" - * - * CollarAlert: - * type: object - * properties: - * id: - * type: string - * description: 预警ID - * example: "alert_002" - * deviceId: - * type: string - * description: 设备ID - * example: "collar_001" - * deviceName: - * type: string - * description: 设备名称 - * example: "项圈设备001" - * animalId: - * type: string - * description: 动物ID - * example: "animal_002" - * animalName: - * type: string - * description: 动物名称 - * example: "牛002" - * farmId: - * type: string - * description: 养殖场ID - * example: "farm_001" - * farmName: - * type: string - * description: 养殖场名称 - * example: "示例养殖场" - * alertType: - * type: string - * enum: [battery, offline, temperature, movement, wear, location] - * description: 预警类型 - * example: "offline" - * alertLevel: - * type: string - * enum: [high, medium, low] - * description: 预警级别 - * example: "medium" - * alertMessage: - * type: string - * description: 预警消息 - * example: "设备离线超过2小时" - * alertValue: - * type: number - * description: 预警值 - * example: 120 - * threshold: - * type: number - * description: 阈值 - * example: 60 - * status: - * type: string - * enum: [pending, processing, resolved, ignored] - * description: 处理状态 - * example: "pending" - * isHandled: - * type: boolean - * description: 是否已处理 - * example: false - * handledBy: - * type: string - * description: 处理人 - * example: "admin" - * handledAt: - * type: string - * format: date-time - * description: 处理时间 - * example: "2024-01-15T12:30:00Z" - * handledNote: - * type: string - * description: 处理备注 - * example: "设备已重新上线" - * createdAt: - * type: string - * format: date-time - * description: 创建时间 - * example: "2024-01-15T10:30:00Z" - * updatedAt: - * type: string - * format: date-time - * description: 更新时间 - * example: "2024-01-15T12:30:00Z" - * - * AlertHandleRequest: - * type: object - * required: - * - action - * properties: - * action: - * type: string - * enum: [resolve, ignore, process] - * description: 处理动作 - * example: "resolve" - * note: - * type: string - * description: 处理备注 - * example: "问题已解决" - * handledBy: - * type: string - * description: 处理人 - * example: "admin" - * - * BatchHandleRequest: - * type: object - * required: - * - alertIds - * - action - * properties: - * alertIds: - * type: array - * items: - * type: string - * description: 预警ID列表 - * example: ["alert_001", "alert_002", "alert_003"] - * action: - * type: string - * enum: [resolve, ignore, process] - * description: 处理动作 - * example: "resolve" - * note: - * type: string - * description: 处理备注 - * example: "批量处理预警" - * handledBy: - * type: string - * description: 处理人 - * example: "admin" - */ - -/** - * @swagger - * /smart-alerts/public/stats: - * get: - * tags: - * - 智能预警 - * summary: 获取智能预警统计 - * description: 获取智能预警的统计数据,包括各类预警的数量和设备总数 - * responses: - * 200: - * description: 获取统计成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/AlertStats' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /smart-alerts/public/eartag/stats: - * get: - * tags: - * - 智能耳标预警 - * summary: 获取智能耳标预警统计 - * description: 获取智能耳标预警的统计数据,包括各类预警的数量和设备总数 - * responses: - * 200: - * description: 获取统计成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/AlertStats' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /smart-alerts/public/eartag: - * get: - * tags: - * - 智能耳标预警 - * summary: 获取智能耳标预警列表 - * description: 获取智能耳标预警列表,支持分页、搜索和筛选 - * parameters: - * - $ref: '#/components/parameters/PaginationQuery/properties/page' - * - $ref: '#/components/parameters/PaginationQuery/properties/limit' - * - in: query - * name: search - * schema: - * type: string - * description: 搜索关键词(设备名称、动物名称、养殖场名称) - * - in: query - * name: alertType - * schema: - * type: string - * enum: [battery, offline, temperature, movement, wear] - * description: 预警类型筛选 - * - in: query - * name: alertLevel - * schema: - * type: string - * enum: [high, medium, low] - * description: 预警级别筛选 - * - in: query - * name: status - * schema: - * type: string - * enum: [pending, processing, resolved, ignored] - * description: 处理状态筛选 - * - in: query - * name: farmId - * schema: - * type: string - * description: 养殖场ID筛选 - * - in: query - * name: isHandled - * schema: - * type: boolean - * description: 是否已处理筛选 - * - in: query - * name: startDate - * schema: - * type: string - * format: date - * description: 开始日期 - * - in: query - * name: endDate - * schema: - * type: string - * format: date - * description: 结束日期 - * responses: - * 200: - * description: 获取列表成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: object - * properties: - * alerts: - * type: array - * items: - * $ref: '#/components/schemas/EartagAlert' - * pagination: - * type: object - * properties: - * total: - * type: integer - * example: 100 - * page: - * type: integer - * example: 1 - * limit: - * type: integer - * example: 10 - * totalPages: - * type: integer - * example: 10 - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /smart-alerts/public/eartag/{id}: - * get: - * tags: - * - 智能耳标预警 - * summary: 获取单个智能耳标预警详情 - * description: 获取指定ID的智能耳标预警详细信息 - * parameters: - * - in: path - * name: id - * required: true - * schema: - * type: string - * description: 预警ID - * responses: - * 200: - * description: 获取详情成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/EartagAlert' - * 400: - * description: 请求参数错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 404: - * description: 预警不存在 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /smart-alerts/public/eartag/{id}/handle: - * post: - * tags: - * - 智能耳标预警 - * summary: 处理智能耳标预警 - * description: 处理指定的智能耳标预警 - * parameters: - * - in: path - * name: id - * required: true - * schema: - * type: string - * description: 预警ID - * requestBody: - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/AlertHandleRequest' - * responses: - * 200: - * description: 处理成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/EartagAlert' - * 400: - * description: 请求参数错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 404: - * description: 预警不存在 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /smart-alerts/public/eartag/batch-handle: - * post: - * tags: - * - 智能耳标预警 - * summary: 批量处理智能耳标预警 - * description: 批量处理多个智能耳标预警 - * requestBody: - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/BatchHandleRequest' - * responses: - * 200: - * description: 批量处理成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: object - * properties: - * successCount: - * type: integer - * description: 成功处理数量 - * example: 5 - * failedCount: - * type: integer - * description: 失败数量 - * example: 0 - * processedAlerts: - * type: array - * items: - * $ref: '#/components/schemas/EartagAlert' - * 400: - * description: 请求参数错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /smart-alerts/public/eartag/export: - * get: - * tags: - * - 智能耳标预警 - * summary: 导出智能耳标预警数据 - * description: 导出智能耳标预警数据为Excel文件 - * parameters: - * - in: query - * name: alertType - * schema: - * type: string - * enum: [battery, offline, temperature, movement, wear] - * description: 预警类型筛选 - * - in: query - * name: alertLevel - * schema: - * type: string - * enum: [high, medium, low] - * description: 预警级别筛选 - * - in: query - * name: status - * schema: - * type: string - * enum: [pending, processing, resolved, ignored] - * description: 处理状态筛选 - * - in: query - * name: farmId - * schema: - * type: string - * description: 养殖场ID筛选 - * - in: query - * name: startDate - * schema: - * type: string - * format: date - * description: 开始日期 - * - in: query - * name: endDate - * schema: - * type: string - * format: date - * description: 结束日期 - * responses: - * 200: - * description: 导出成功 - * content: - * application/vnd.openxmlformats-officedocument.spreadsheetml.sheet: - * schema: - * type: string - * format: binary - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /smart-alerts/public/collar/stats: - * get: - * tags: - * - 智能项圈预警 - * summary: 获取智能项圈预警统计 - * description: 获取智能项圈预警的统计数据,包括各类预警的数量和设备总数 - * responses: - * 200: - * description: 获取统计成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/AlertStats' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /smart-alerts/public/collar: - * get: - * tags: - * - 智能项圈预警 - * summary: 获取智能项圈预警列表 - * description: 获取智能项圈预警列表,支持分页、搜索和筛选 - * parameters: - * - $ref: '#/components/parameters/PaginationQuery/properties/page' - * - $ref: '#/components/parameters/PaginationQuery/properties/limit' - * - in: query - * name: search - * schema: - * type: string - * description: 搜索关键词(设备名称、动物名称、养殖场名称) - * - in: query - * name: alertType - * schema: - * type: string - * enum: [battery, offline, temperature, movement, wear, location] - * description: 预警类型筛选 - * - in: query - * name: alertLevel - * schema: - * type: string - * enum: [high, medium, low] - * description: 预警级别筛选 - * - in: query - * name: status - * schema: - * type: string - * enum: [pending, processing, resolved, ignored] - * description: 处理状态筛选 - * - in: query - * name: farmId - * schema: - * type: string - * description: 养殖场ID筛选 - * - in: query - * name: isHandled - * schema: - * type: boolean - * description: 是否已处理筛选 - * - in: query - * name: startDate - * schema: - * type: string - * format: date - * description: 开始日期 - * - in: query - * name: endDate - * schema: - * type: string - * format: date - * description: 结束日期 - * responses: - * 200: - * description: 获取列表成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: object - * properties: - * alerts: - * type: array - * items: - * $ref: '#/components/schemas/CollarAlert' - * pagination: - * type: object - * properties: - * total: - * type: integer - * example: 100 - * page: - * type: integer - * example: 1 - * limit: - * type: integer - * example: 10 - * totalPages: - * type: integer - * example: 10 - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /smart-alerts/public/collar/{id}: - * get: - * tags: - * - 智能项圈预警 - * summary: 获取单个智能项圈预警详情 - * description: 获取指定ID的智能项圈预警详细信息 - * parameters: - * - in: path - * name: id - * required: true - * schema: - * type: string - * description: 预警ID - * responses: - * 200: - * description: 获取详情成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/CollarAlert' - * 400: - * description: 请求参数错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 404: - * description: 预警不存在 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /smart-alerts/public/collar/{id}/handle: - * post: - * tags: - * - 智能项圈预警 - * summary: 处理智能项圈预警 - * description: 处理指定的智能项圈预警 - * parameters: - * - in: path - * name: id - * required: true - * schema: - * type: string - * description: 预警ID - * requestBody: - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/AlertHandleRequest' - * responses: - * 200: - * description: 处理成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/CollarAlert' - * 400: - * description: 请求参数错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 404: - * description: 预警不存在 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /smart-alerts/public/collar/batch-handle: - * post: - * tags: - * - 智能项圈预警 - * summary: 批量处理智能项圈预警 - * description: 批量处理多个智能项圈预警 - * requestBody: - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/BatchHandleRequest' - * responses: - * 200: - * description: 批量处理成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: object - * properties: - * successCount: - * type: integer - * description: 成功处理数量 - * example: 5 - * failedCount: - * type: integer - * description: 失败数量 - * example: 0 - * processedAlerts: - * type: array - * items: - * $ref: '#/components/schemas/CollarAlert' - * 400: - * description: 请求参数错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /smart-alerts/public/collar/export: - * get: - * tags: - * - 智能项圈预警 - * summary: 导出智能项圈预警数据 - * description: 导出智能项圈预警数据为Excel文件 - * parameters: - * - in: query - * name: alertType - * schema: - * type: string - * enum: [battery, offline, temperature, movement, wear, location] - * description: 预警类型筛选 - * - in: query - * name: alertLevel - * schema: - * type: string - * enum: [high, medium, low] - * description: 预警级别筛选 - * - in: query - * name: status - * schema: - * type: string - * enum: [pending, processing, resolved, ignored] - * description: 处理状态筛选 - * - in: query - * name: farmId - * schema: - * type: string - * description: 养殖场ID筛选 - * - in: query - * name: startDate - * schema: - * type: string - * format: date - * description: 开始日期 - * - in: query - * name: endDate - * schema: - * type: string - * format: date - * description: 结束日期 - * responses: - * 200: - * description: 导出成功 - * content: - * application/vnd.openxmlformats-officedocument.spreadsheetml.sheet: - * schema: - * type: string - * format: binary - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -module.exports = {}; \ No newline at end of file diff --git a/backend/swagger-stats.js b/backend/swagger-stats.js deleted file mode 100644 index 0fdc460..0000000 --- a/backend/swagger-stats.js +++ /dev/null @@ -1,1151 +0,0 @@ -/** - * 统计数据模块 Swagger 文档 - * @file swagger-stats.js - * @description 定义统计数据相关的API文档 - */ - -/** - * @swagger - * tags: - * - name: 统计数据 - * description: 各类统计数据和监控信息 - */ - -/** - * @swagger - * components: - * schemas: - * DashboardStats: - * type: object - * properties: - * farmCount: - * type: integer - * description: 养殖场总数 - * example: 12 - * animalCount: - * type: integer - * description: 动物总数 - * example: 5000 - * deviceCount: - * type: integer - * description: 设备总数 - * example: 150 - * alertCount: - * type: integer - * description: 当前预警数量 - * example: 25 - * deviceOnlineRate: - * type: number - * format: float - * description: 设备在线率 - * example: 0.95 - * alertsByLevel: - * type: object - * properties: - * low: - * type: integer - * description: 低级预警数量 - * example: 5 - * medium: - * type: integer - * description: 中级预警数量 - * example: 10 - * high: - * type: integer - * description: 高级预警数量 - * example: 8 - * critical: - * type: integer - * description: 紧急预警数量 - * example: 2 - * recentActivities: - * type: array - * items: - * type: object - * properties: - * id: - * type: string - * description: 活动ID - * type: - * type: string - * description: 活动类型 - * description: - * type: string - * description: 活动描述 - * timestamp: - * type: string - * format: date-time - * description: 活动时间 - * description: 最近活动记录 - * - * FarmStats: - * type: object - * properties: - * totalFarms: - * type: integer - * description: 养殖场总数 - * example: 12 - * activeFarms: - * type: integer - * description: 活跃养殖场数量 - * example: 10 - * farmsByType: - * type: array - * items: - * type: object - * properties: - * type: - * type: string - * description: 养殖场类型 - * example: "猪场" - * count: - * type: integer - * description: 数量 - * example: 5 - * percentage: - * type: number - * description: 占比 - * example: 0.42 - * description: 按类型分组的养殖场统计 - * farmsByStatus: - * type: array - * items: - * type: object - * properties: - * status: - * type: string - * description: 养殖场状态 - * example: "active" - * count: - * type: integer - * description: 数量 - * example: 10 - * percentage: - * type: number - * description: 占比 - * example: 0.83 - * description: 按状态分组的养殖场统计 - * farmsByRegion: - * type: array - * items: - * type: object - * properties: - * region: - * type: string - * description: 地区 - * example: "银川市" - * count: - * type: integer - * description: 数量 - * example: 8 - * description: 按地区分组的养殖场统计 - * averageAnimalsPerFarm: - * type: number - * description: 平均每个养殖场的动物数量 - * example: 416.67 - * totalCapacity: - * type: integer - * description: 总养殖容量 - * example: 8000 - * utilizationRate: - * type: number - * description: 容量利用率 - * example: 0.625 - * - * AnimalStats: - * type: object - * properties: - * totalAnimals: - * type: integer - * description: 动物总数 - * example: 5000 - * animalsByType: - * type: array - * items: - * type: object - * properties: - * type: - * type: string - * description: 动物类型 - * example: "猪" - * count: - * type: integer - * description: 数量 - * example: 3000 - * percentage: - * type: number - * description: 占比 - * example: 0.6 - * description: 按类型分组的动物统计 - * animalsByHealth: - * type: array - * items: - * type: object - * properties: - * health_status: - * type: string - * description: 健康状态 - * example: "healthy" - * count: - * type: integer - * description: 数量 - * example: 4500 - * percentage: - * type: number - * description: 占比 - * example: 0.9 - * description: 按健康状态分组的动物统计 - * animalsByAge: - * type: array - * items: - * type: object - * properties: - * age_group: - * type: string - * description: 年龄组 - * example: "幼崽" - * count: - * type: integer - * description: 数量 - * example: 1000 - * description: 按年龄分组的动物统计 - * animalsByGender: - * type: array - * items: - * type: object - * properties: - * gender: - * type: string - * description: 性别 - * example: "雌性" - * count: - * type: integer - * description: 数量 - * example: 2800 - * description: 按性别分组的动物统计 - * birthRate: - * type: number - * description: 出生率(月度) - * example: 0.08 - * mortalityRate: - * type: number - * description: 死亡率(月度) - * example: 0.02 - * averageWeight: - * type: number - * description: 平均体重(公斤) - * example: 85.5 - * - * DeviceStats: - * type: object - * properties: - * totalDevices: - * type: integer - * description: 设备总数 - * example: 150 - * onlineDevices: - * type: integer - * description: 在线设备数量 - * example: 142 - * offlineDevices: - * type: integer - * description: 离线设备数量 - * example: 8 - * onlineRate: - * type: number - * description: 在线率 - * example: 0.947 - * devicesByType: - * type: array - * items: - * type: object - * properties: - * type: - * type: string - * description: 设备类型 - * example: "智能耳标" - * count: - * type: integer - * description: 数量 - * example: 80 - * online_count: - * type: integer - * description: 在线数量 - * example: 75 - * online_rate: - * type: number - * description: 在线率 - * example: 0.9375 - * description: 按类型分组的设备统计 - * devicesByStatus: - * type: array - * items: - * type: object - * properties: - * status: - * type: string - * description: 设备状态 - * example: "online" - * count: - * type: integer - * description: 数量 - * example: 142 - * description: 按状态分组的设备统计 - * devicesByFarm: - * type: array - * items: - * type: object - * properties: - * farm_id: - * type: string - * description: 养殖场ID - * farm_name: - * type: string - * description: 养殖场名称 - * device_count: - * type: integer - * description: 设备数量 - * online_count: - * type: integer - * description: 在线设备数量 - * description: 按养殖场分组的设备统计 - * maintenanceScheduled: - * type: integer - * description: 计划维护的设备数量 - * example: 5 - * batteryLowDevices: - * type: integer - * description: 低电量设备数量 - * example: 12 - * - * AlertStats: - * type: object - * properties: - * totalAlerts: - * type: integer - * description: 预警总数 - * example: 25 - * activeAlerts: - * type: integer - * description: 活跃预警数量 - * example: 18 - * resolvedAlerts: - * type: integer - * description: 已解决预警数量 - * example: 7 - * alertsByLevel: - * type: array - * items: - * type: object - * properties: - * level: - * type: string - * description: 预警级别 - * example: "high" - * count: - * type: integer - * description: 数量 - * example: 8 - * percentage: - * type: number - * description: 占比 - * example: 0.32 - * description: 按级别分组的预警统计 - * alertsByType: - * type: array - * items: - * type: object - * properties: - * type: - * type: string - * description: 预警类型 - * example: "health" - * count: - * type: integer - * description: 数量 - * example: 10 - * description: 按类型分组的预警统计 - * alertsByFarm: - * type: array - * items: - * type: object - * properties: - * farm_id: - * type: string - * description: 养殖场ID - * farm_name: - * type: string - * description: 养殖场名称 - * alert_count: - * type: integer - * description: 预警数量 - * description: 按养殖场分组的预警统计 - * averageResponseTime: - * type: number - * description: 平均响应时间(分钟) - * example: 15.5 - * resolutionRate: - * type: number - * description: 解决率 - * example: 0.72 - * - * MonitorData: - * type: object - * properties: - * timestamp: - * type: string - * format: date-time - * description: 监控时间戳 - * example: "2024-01-15T10:30:00Z" - * system_health: - * type: object - * properties: - * cpu_usage: - * type: number - * description: CPU使用率 - * example: 0.25 - * memory_usage: - * type: number - * description: 内存使用率 - * example: 0.68 - * disk_usage: - * type: number - * description: 磁盘使用率 - * example: 0.45 - * network_io: - * type: object - * properties: - * bytes_in: - * type: integer - * description: 入站字节数 - * bytes_out: - * type: integer - * description: 出站字节数 - * database_health: - * type: object - * properties: - * connection_count: - * type: integer - * description: 数据库连接数 - * example: 15 - * query_performance: - * type: object - * properties: - * avg_query_time: - * type: number - * description: 平均查询时间(毫秒) - * example: 25.5 - * slow_queries: - * type: integer - * description: 慢查询数量 - * example: 2 - * api_performance: - * type: object - * properties: - * total_requests: - * type: integer - * description: 总请求数 - * example: 1500 - * avg_response_time: - * type: number - * description: 平均响应时间(毫秒) - * example: 120.5 - * error_rate: - * type: number - * description: 错误率 - * example: 0.02 - * device_connectivity: - * type: object - * properties: - * total_devices: - * type: integer - * description: 设备总数 - * example: 150 - * connected_devices: - * type: integer - * description: 已连接设备数 - * example: 142 - * connection_rate: - * type: number - * description: 连接率 - * example: 0.947 - * - * MonthlyTrends: - * type: object - * properties: - * period: - * type: string - * description: 统计周期 - * example: "2024-01" - * farm_trends: - * type: array - * items: - * type: object - * properties: - * month: - * type: string - * description: 月份 - * example: "2024-01" - * farm_count: - * type: integer - * description: 养殖场数量 - * example: 12 - * new_farms: - * type: integer - * description: 新增养殖场 - * example: 2 - * description: 养殖场数量趋势 - * animal_trends: - * type: array - * items: - * type: object - * properties: - * month: - * type: string - * description: 月份 - * animal_count: - * type: integer - * description: 动物数量 - * births: - * type: integer - * description: 出生数量 - * deaths: - * type: integer - * description: 死亡数量 - * description: 动物数量趋势 - * device_trends: - * type: array - * items: - * type: object - * properties: - * month: - * type: string - * description: 月份 - * device_count: - * type: integer - * description: 设备数量 - * online_rate: - * type: number - * description: 在线率 - * description: 设备数量和在线率趋势 - * alert_trends: - * type: array - * items: - * type: object - * properties: - * month: - * type: string - * description: 月份 - * alert_count: - * type: integer - * description: 预警数量 - * resolution_rate: - * type: number - * description: 解决率 - * description: 预警数量和解决率趋势 - */ - -/** - * @swagger - * /stats/dashboard: - * get: - * tags: - * - 统计数据 - * summary: 获取仪表盘统计数据 - * description: 获取系统仪表盘的核心统计数据 - * security: - * - bearerAuth: [] - * responses: - * 200: - * description: 获取仪表盘统计数据成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/DashboardStats' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /stats/farms: - * get: - * tags: - * - 统计数据 - * summary: 获取养殖场统计数据 - * description: 获取养殖场相关的详细统计数据 - * security: - * - bearerAuth: [] - * parameters: - * - in: query - * name: period - * schema: - * type: string - * enum: [day, week, month, year] - * default: month - * description: 统计周期 - * - in: query - * name: region - * schema: - * type: string - * description: 地区筛选 - * responses: - * 200: - * description: 获取养殖场统计数据成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/FarmStats' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /stats/animals: - * get: - * tags: - * - 统计数据 - * summary: 获取动物统计数据 - * description: 获取动物相关的详细统计数据 - * security: - * - bearerAuth: [] - * parameters: - * - in: query - * name: period - * schema: - * type: string - * enum: [day, week, month, year] - * default: month - * description: 统计周期 - * - in: query - * name: farm_id - * schema: - * type: string - * description: 养殖场ID筛选 - * - in: query - * name: animal_type - * schema: - * type: string - * description: 动物类型筛选 - * responses: - * 200: - * description: 获取动物统计数据成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/AnimalStats' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /stats/devices: - * get: - * tags: - * - 统计数据 - * summary: 获取设备统计数据 - * description: 获取设备相关的详细统计数据 - * security: - * - bearerAuth: [] - * parameters: - * - in: query - * name: period - * schema: - * type: string - * enum: [day, week, month, year] - * default: month - * description: 统计周期 - * - in: query - * name: farm_id - * schema: - * type: string - * description: 养殖场ID筛选 - * - in: query - * name: device_type - * schema: - * type: string - * description: 设备类型筛选 - * responses: - * 200: - * description: 获取设备统计数据成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/DeviceStats' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /stats/alerts: - * get: - * tags: - * - 统计数据 - * summary: 获取预警统计数据 - * description: 获取预警相关的详细统计数据 - * security: - * - bearerAuth: [] - * parameters: - * - in: query - * name: period - * schema: - * type: string - * enum: [day, week, month, year] - * default: month - * description: 统计周期 - * - in: query - * name: farm_id - * schema: - * type: string - * description: 养殖场ID筛选 - * - in: query - * name: alert_level - * schema: - * type: string - * enum: [low, medium, high, critical] - * description: 预警级别筛选 - * - in: query - * name: alert_type - * schema: - * type: string - * description: 预警类型筛选 - * responses: - * 200: - * description: 获取预警统计数据成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/AlertStats' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /stats/monitoring: - * get: - * tags: - * - 统计数据 - * summary: 获取系统监控数据 - * description: 获取系统实时监控数据 - * security: - * - bearerAuth: [] - * parameters: - * - in: query - * name: interval - * schema: - * type: string - * enum: [1m, 5m, 15m, 1h] - * default: 5m - * description: 监控数据间隔 - * - in: query - * name: duration - * schema: - * type: string - * enum: [1h, 6h, 24h, 7d] - * default: 1h - * description: 监控数据时长 - * responses: - * 200: - * description: 获取监控数据成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: array - * items: - * $ref: '#/components/schemas/MonitorData' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /stats/monthly-trends: - * get: - * tags: - * - 统计数据 - * summary: 获取月度数据趋势 - * description: 获取各项指标的月度趋势数据 - * security: - * - bearerAuth: [] - * parameters: - * - in: query - * name: months - * schema: - * type: integer - * minimum: 1 - * maximum: 24 - * default: 12 - * description: 获取最近几个月的数据 - * - in: query - * name: metrics - * schema: - * type: array - * items: - * type: string - * enum: [farms, animals, devices, alerts] - * description: 要获取的指标类型 - * style: form - * explode: false - * example: "farms,animals,devices" - * responses: - * 200: - * description: 获取月度趋势数据成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/MonthlyTrends' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /stats/public/dashboard: - * get: - * tags: - * - 统计数据 - * summary: 获取公开仪表盘统计数据 - * description: 获取公开的仪表盘统计数据(无需认证) - * responses: - * 200: - * description: 获取公开统计数据成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: object - * properties: - * farmCount: - * type: integer - * description: 养殖场总数 - * example: 12 - * animalCount: - * type: integer - * description: 动物总数 - * example: 5000 - * deviceCount: - * type: integer - * description: 设备总数 - * example: 150 - * lastUpdated: - * type: string - * format: date-time - * description: 最后更新时间 - * example: "2024-01-15T10:30:00Z" - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /stats/public/monitoring: - * get: - * tags: - * - 统计数据 - * summary: 获取公开监控数据 - * description: 获取公开的系统监控数据(无需认证) - * responses: - * 200: - * description: 获取公开监控数据成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: object - * properties: - * system_status: - * type: string - * enum: [healthy, warning, critical] - * description: 系统状态 - * example: "healthy" - * device_online_rate: - * type: number - * description: 设备在线率 - * example: 0.95 - * active_alerts: - * type: integer - * description: 活跃预警数量 - * example: 5 - * last_updated: - * type: string - * format: date-time - * description: 最后更新时间 - * example: "2024-01-15T10:30:00Z" - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /stats/public/monthly-trends: - * get: - * tags: - * - 统计数据 - * summary: 获取公开月度趋势数据 - * description: 获取公开的月度趋势数据(无需认证) - * parameters: - * - in: query - * name: months - * schema: - * type: integer - * minimum: 1 - * maximum: 12 - * default: 6 - * description: 获取最近几个月的数据 - * responses: - * 200: - * description: 获取公开月度趋势数据成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: object - * properties: - * farm_trends: - * type: array - * items: - * type: object - * properties: - * month: - * type: string - * count: - * type: integer - * animal_trends: - * type: array - * items: - * type: object - * properties: - * month: - * type: string - * count: - * type: integer - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /stats/public/farm-count: - * get: - * tags: - * - 统计数据 - * summary: 获取养殖场总数统计 - * description: 获取实时的养殖场总数统计(无需认证) - * responses: - * 200: - * description: 获取养殖场总数成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: object - * properties: - * total: - * type: integer - * description: 养殖场总数 - * example: 12 - * active: - * type: integer - * description: 活跃养殖场数量 - * example: 10 - * last_updated: - * type: string - * format: date-time - * description: 最后更新时间 - * example: "2024-01-15T10:30:00Z" - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /stats/public/animal-count: - * get: - * tags: - * - 统计数据 - * summary: 获取动物总数统计 - * description: 获取实时的动物总数统计(无需认证) - * responses: - * 200: - * description: 获取动物总数成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: object - * properties: - * total: - * type: integer - * description: 动物总数 - * example: 5000 - * by_type: - * type: array - * items: - * type: object - * properties: - * type: - * type: string - * description: 动物类型 - * count: - * type: integer - * description: 数量 - * description: 按类型分组的动物统计 - * last_updated: - * type: string - * format: date-time - * description: 最后更新时间 - * example: "2024-01-15T10:30:00Z" - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -module.exports = {}; \ No newline at end of file diff --git a/backend/swagger-system.js b/backend/swagger-system.js deleted file mode 100644 index 90c1e8d..0000000 --- a/backend/swagger-system.js +++ /dev/null @@ -1,1047 +0,0 @@ -/** - * 系统管理模块 Swagger 文档 - * @file swagger-system.js - * @description 定义系统管理相关的API文档 - */ - -/** - * @swagger - * tags: - * - name: 系统管理 - * description: 系统配置和菜单权限管理 - */ - -/** - * @swagger - * components: - * schemas: - * SystemConfig: - * type: object - * properties: - * id: - * type: string - * description: 配置ID - * example: "config_001" - * config_key: - * type: string - * description: 配置键名 - * example: "system.max_upload_size" - * config_value: - * description: 配置值(可以是任意类型) - * example: "10MB" - * category: - * type: string - * description: 配置分类 - * example: "upload" - * description: - * type: string - * description: 配置描述 - * example: "系统最大上传文件大小限制" - * is_public: - * type: boolean - * description: 是否为公开配置 - * example: false - * is_editable: - * type: boolean - * description: 是否可编辑 - * example: true - * default_value: - * description: 默认值 - * example: "5MB" - * value_type: - * type: string - * enum: [string, number, boolean, json, array] - * description: 值类型 - * example: "string" - * validation_rules: - * type: object - * description: 验证规则 - * properties: - * required: - * type: boolean - * min: - * type: number - * max: - * type: number - * pattern: - * type: string - * created_at: - * type: string - * format: date-time - * description: 创建时间 - * example: "2024-01-15T10:30:00Z" - * updated_at: - * type: string - * format: date-time - * description: 更新时间 - * example: "2024-01-15T10:30:00Z" - * - * SystemConfigInput: - * type: object - * required: - * - config_key - * - config_value - * properties: - * config_key: - * type: string - * description: 配置键名 - * example: "system.max_upload_size" - * config_value: - * description: 配置值 - * example: "10MB" - * category: - * type: string - * description: 配置分类 - * example: "upload" - * description: - * type: string - * description: 配置描述 - * example: "系统最大上传文件大小限制" - * is_public: - * type: boolean - * description: 是否为公开配置 - * example: false - * is_editable: - * type: boolean - * description: 是否可编辑 - * example: true - * value_type: - * type: string - * enum: [string, number, boolean, json, array] - * description: 值类型 - * example: "string" - * validation_rules: - * type: object - * description: 验证规则 - * - * ConfigCategory: - * type: object - * properties: - * category: - * type: string - * description: 分类名称 - * example: "upload" - * label: - * type: string - * description: 分类标签 - * example: "文件上传" - * description: - * type: string - * description: 分类描述 - * example: "文件上传相关配置" - * count: - * type: integer - * description: 该分类下的配置数量 - * example: 5 - * - * MenuPermission: - * type: object - * properties: - * id: - * type: string - * description: 菜单ID - * example: "menu_001" - * menu_name: - * type: string - * description: 菜单名称 - * example: "用户管理" - * menu_path: - * type: string - * description: 菜单路径 - * example: "/admin/users" - * parent_id: - * type: string - * description: 父菜单ID - * example: "menu_admin" - * menu_level: - * type: integer - * description: 菜单层级 - * example: 2 - * sort_order: - * type: integer - * description: 排序顺序 - * example: 1 - * menu_icon: - * type: string - * description: 菜单图标 - * example: "user" - * is_active: - * type: boolean - * description: 是否激活 - * example: true - * required_roles: - * type: array - * items: - * type: string - * description: 所需角色 - * example: ["admin", "manager"] - * required_permissions: - * type: array - * items: - * type: string - * description: 所需权限 - * example: ["user.read", "user.write"] - * children: - * type: array - * items: - * $ref: '#/components/schemas/MenuPermission' - * description: 子菜单 - * created_at: - * type: string - * format: date-time - * description: 创建时间 - * example: "2024-01-15T10:30:00Z" - * updated_at: - * type: string - * format: date-time - * description: 更新时间 - * example: "2024-01-15T10:30:00Z" - * - * SystemStats: - * type: object - * properties: - * system_info: - * type: object - * properties: - * version: - * type: string - * description: 系统版本 - * example: "1.0.0" - * uptime: - * type: integer - * description: 运行时间(秒) - * example: 86400 - * node_version: - * type: string - * description: Node.js版本 - * example: "18.17.0" - * platform: - * type: string - * description: 运行平台 - * example: "linux" - * database_info: - * type: object - * properties: - * connection_status: - * type: string - * description: 数据库连接状态 - * example: "connected" - * total_tables: - * type: integer - * description: 总表数 - * example: 25 - * total_records: - * type: integer - * description: 总记录数 - * example: 100000 - * performance_info: - * type: object - * properties: - * memory_usage: - * type: object - * properties: - * used: - * type: integer - * description: 已使用内存(字节) - * total: - * type: integer - * description: 总内存(字节) - * percentage: - * type: number - * description: 使用百分比 - * cpu_usage: - * type: number - * description: CPU使用率 - * example: 0.25 - * disk_usage: - * type: object - * properties: - * used: - * type: integer - * description: 已使用磁盘空间(字节) - * total: - * type: integer - * description: 总磁盘空间(字节) - * percentage: - * type: number - * description: 使用百分比 - * - * BatchConfigUpdate: - * type: object - * required: - * - configs - * properties: - * configs: - * type: array - * items: - * type: object - * required: - * - id - * - config_value - * properties: - * id: - * type: string - * description: 配置ID - * config_value: - * description: 新的配置值 - * description: 要更新的配置列表 - * example: - * - id: "config_001" - * config_value: "20MB" - * - id: "config_002" - * config_value: true - */ - -/** - * @swagger - * /system/configs: - * get: - * tags: - * - 系统管理 - * summary: 获取系统配置列表 - * description: 获取系统配置列表,支持按分类和公开性筛选(仅限管理员) - * security: - * - bearerAuth: [] - * parameters: - * - in: query - * name: category - * schema: - * type: string - * description: 配置分类筛选 - * example: "upload" - * - in: query - * name: is_public - * schema: - * type: boolean - * description: 是否公开配置筛选 - * example: false - * - in: query - * name: search - * schema: - * type: string - * description: 搜索关键词(配置键名或描述) - * example: "upload" - * responses: - * 200: - * description: 获取配置列表成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: array - * items: - * $ref: '#/components/schemas/SystemConfig' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 权限不足(仅限管理员) - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * - * post: - * tags: - * - 系统管理 - * summary: 创建系统配置 - * description: 创建新的系统配置项(仅限管理员) - * security: - * - bearerAuth: [] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SystemConfigInput' - * responses: - * 201: - * description: 配置创建成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/SystemConfig' - * 400: - * description: 请求参数错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 权限不足(仅限管理员) - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 409: - * description: 配置键名已存在 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /system/configs/public: - * get: - * tags: - * - 系统管理 - * summary: 获取公开系统配置 - * description: 获取标记为公开的系统配置 - * security: - * - bearerAuth: [] - * responses: - * 200: - * description: 获取公开配置成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: array - * items: - * $ref: '#/components/schemas/SystemConfig' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /system/configs/categories: - * get: - * tags: - * - 系统管理 - * summary: 获取配置分类列表 - * description: 获取所有配置分类及其统计信息(仅限管理员) - * security: - * - bearerAuth: [] - * responses: - * 200: - * description: 获取分类列表成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: array - * items: - * $ref: '#/components/schemas/ConfigCategory' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 权限不足(仅限管理员) - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /system/configs/{id}: - * put: - * tags: - * - 系统管理 - * summary: 更新系统配置 - * description: 更新指定的系统配置项(仅限管理员) - * security: - * - bearerAuth: [] - * parameters: - * - in: path - * name: id - * required: true - * schema: - * type: string - * description: 配置ID - * example: "config_001" - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * required: - * - config_value - * properties: - * config_value: - * description: 新的配置值 - * example: "20MB" - * description: - * type: string - * description: 配置描述 - * is_public: - * type: boolean - * description: 是否为公开配置 - * responses: - * 200: - * description: 配置更新成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/SystemConfig' - * 400: - * description: 请求参数错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 权限不足(仅限管理员) - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 404: - * description: 配置不存在 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * - * delete: - * tags: - * - 系统管理 - * summary: 删除系统配置 - * description: 删除指定的系统配置项(仅限管理员) - * security: - * - bearerAuth: [] - * parameters: - * - in: path - * name: id - * required: true - * schema: - * type: string - * description: 配置ID - * example: "config_001" - * responses: - * 200: - * description: 配置删除成功 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ApiResponse' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 权限不足(仅限管理员) - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 404: - * description: 配置不存在 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /system/configs/batch: - * put: - * tags: - * - 系统管理 - * summary: 批量更新系统配置 - * description: 批量更新多个系统配置项(仅限管理员) - * security: - * - bearerAuth: [] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/BatchConfigUpdate' - * responses: - * 200: - * description: 批量更新成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: object - * properties: - * updated_count: - * type: integer - * description: 成功更新的配置数量 - * example: 5 - * failed_count: - * type: integer - * description: 更新失败的配置数量 - * example: 0 - * errors: - * type: array - * items: - * type: object - * properties: - * id: - * type: string - * error: - * type: string - * description: 更新失败的配置及错误信息 - * 400: - * description: 请求参数错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 权限不足(仅限管理员) - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /system/configs/{id}/reset: - * post: - * tags: - * - 系统管理 - * summary: 重置系统配置 - * description: 将指定配置重置为默认值(仅限管理员) - * security: - * - bearerAuth: [] - * parameters: - * - in: path - * name: id - * required: true - * schema: - * type: string - * description: 配置ID - * example: "config_001" - * responses: - * 200: - * description: 配置重置成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/SystemConfig' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 权限不足(仅限管理员) - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 404: - * description: 配置不存在或无默认值 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /system/menus: - * get: - * tags: - * - 系统管理 - * summary: 获取菜单权限配置 - * description: 获取所有菜单的权限配置(仅限管理员) - * security: - * - bearerAuth: [] - * responses: - * 200: - * description: 获取菜单权限成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: array - * items: - * $ref: '#/components/schemas/MenuPermission' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 权限不足(仅限管理员) - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /system/menus/user: - * get: - * tags: - * - 系统管理 - * summary: 获取当前用户可访问的菜单 - * description: 根据当前用户的角色和权限获取可访问的菜单列表 - * security: - * - bearerAuth: [] - * responses: - * 200: - * description: 获取用户菜单成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: array - * items: - * $ref: '#/components/schemas/MenuPermission' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /system/menus/{id}: - * put: - * tags: - * - 系统管理 - * summary: 更新菜单权限配置 - * description: 更新指定菜单的权限配置(仅限管理员) - * security: - * - bearerAuth: [] - * parameters: - * - in: path - * name: id - * required: true - * schema: - * type: string - * description: 菜单ID - * example: "menu_001" - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * menu_name: - * type: string - * description: 菜单名称 - * example: "用户管理" - * required_roles: - * type: array - * items: - * type: string - * description: 所需角色 - * example: ["admin", "manager"] - * required_permissions: - * type: array - * items: - * type: string - * description: 所需权限 - * example: ["user.read", "user.write"] - * is_active: - * type: boolean - * description: 是否激活 - * example: true - * sort_order: - * type: integer - * description: 排序顺序 - * example: 1 - * responses: - * 200: - * description: 菜单权限更新成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/MenuPermission' - * 400: - * description: 请求参数错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 权限不足(仅限管理员) - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 404: - * description: 菜单不存在 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /system/stats: - * get: - * tags: - * - 系统管理 - * summary: 获取系统统计信息 - * description: 获取系统运行状态和统计信息(仅限管理员) - * security: - * - bearerAuth: [] - * responses: - * 200: - * description: 获取系统统计成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * $ref: '#/components/schemas/SystemStats' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 权限不足(仅限管理员) - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -/** - * @swagger - * /system/init: - * post: - * tags: - * - 系统管理 - * summary: 初始化系统 - * description: 初始化系统配置和基础数据(仅限管理员) - * security: - * - bearerAuth: [] - * requestBody: - * required: false - * content: - * application/json: - * schema: - * type: object - * properties: - * force: - * type: boolean - * description: 是否强制重新初始化 - * example: false - * modules: - * type: array - * items: - * type: string - * description: 要初始化的模块列表 - * example: ["configs", "menus", "roles"] - * responses: - * 200: - * description: 系统初始化成功 - * content: - * application/json: - * schema: - * allOf: - * - $ref: '#/components/schemas/ApiResponse' - * - type: object - * properties: - * data: - * type: object - * properties: - * initialized_modules: - * type: array - * items: - * type: string - * description: 已初始化的模块 - * example: ["configs", "menus", "roles"] - * skipped_modules: - * type: array - * items: - * type: string - * description: 跳过的模块 - * example: [] - * 400: - * description: 请求参数错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 401: - * description: 未授权 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 403: - * description: 权限不足(仅限管理员) - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - * 500: - * description: 服务器内部错误 - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ErrorResponse' - */ - -module.exports = {}; \ No newline at end of file diff --git a/backend/swagger-users.js b/backend/swagger-users.js deleted file mode 100644 index 616de52..0000000 --- a/backend/swagger-users.js +++ /dev/null @@ -1,521 +0,0 @@ -/** - * 用户管理模块 Swagger 文档 - * @file swagger-users.js - */ - -const usersPaths = { - // 获取所有用户 - '/users': { - get: { - tags: ['用户管理'], - summary: '获取用户列表', - description: '分页获取系统中的所有用户', - parameters: [ - { - name: 'page', - in: 'query', - schema: { type: 'integer', default: 1 }, - description: '页码' - }, - { - name: 'limit', - in: 'query', - schema: { type: 'integer', default: 10 }, - description: '每页数量' - }, - { - name: 'search', - in: 'query', - schema: { type: 'string' }, - description: '搜索关键词(用户名、邮箱、手机号)' - }, - { - name: 'status', - in: 'query', - schema: { type: 'string', enum: ['active', 'inactive', 'banned'] }, - description: '用户状态筛选' - }, - { - name: 'role', - in: 'query', - schema: { type: 'string' }, - description: '角色筛选' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { $ref: '#/components/schemas/User' } - }, - pagination: { - type: 'object', - properties: { - page: { type: 'integer' }, - limit: { type: 'integer' }, - total: { type: 'integer' }, - totalPages: { type: 'integer' } - } - } - } - } - } - } - } - } - }, - post: { - tags: ['用户管理'], - summary: '创建新用户', - description: '管理员创建新用户账号', - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['username', 'email', 'password'], - properties: { - username: { type: 'string', description: '用户名' }, - email: { type: 'string', format: 'email', description: '邮箱' }, - password: { type: 'string', minLength: 6, description: '密码' }, - phone: { type: 'string', description: '手机号' }, - realName: { type: 'string', description: '真实姓名' }, - avatar: { type: 'string', description: '头像URL' }, - status: { type: 'string', enum: ['active', 'inactive'], default: 'active' }, - roleIds: { type: 'array', items: { type: 'integer' }, description: '角色ID列表' } - } - } - } - } - }, - responses: { - '201': { - description: '创建成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '用户创建成功' }, - data: { $ref: '#/components/schemas/User' } - } - } - } - } - }, - '400': { - description: '请求参数错误或用户已存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 根据用户名搜索用户 - '/users/search': { - get: { - tags: ['用户管理'], - summary: '搜索用户', - description: '根据用户名、邮箱或手机号搜索用户', - parameters: [ - { - name: 'q', - in: 'query', - required: true, - schema: { type: 'string' }, - description: '搜索关键词' - }, - { - name: 'limit', - in: 'query', - schema: { type: 'integer', default: 10 }, - description: '返回结果数量限制' - } - ], - responses: { - '200': { - description: '搜索成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { - type: 'array', - items: { $ref: '#/components/schemas/User' } - } - } - } - } - } - } - } - } - }, - - // 获取指定用户详情 - '/users/{id}': { - get: { - tags: ['用户管理'], - summary: '获取用户详情', - description: '根据用户ID获取用户详细信息', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '用户ID' - } - ], - responses: { - '200': { - description: '获取成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - data: { $ref: '#/components/schemas/User' } - } - } - } - } - }, - '404': { - description: '用户不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - }, - put: { - tags: ['用户管理'], - summary: '更新用户信息', - description: '更新指定用户的信息', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '用户ID' - } - ], - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - username: { type: 'string', description: '用户名' }, - email: { type: 'string', format: 'email', description: '邮箱' }, - phone: { type: 'string', description: '手机号' }, - realName: { type: 'string', description: '真实姓名' }, - avatar: { type: 'string', description: '头像URL' }, - status: { type: 'string', enum: ['active', 'inactive', 'banned'] }, - roleIds: { type: 'array', items: { type: 'integer' }, description: '角色ID列表' } - } - } - } - } - }, - responses: { - '200': { - description: '更新成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '用户信息更新成功' }, - data: { $ref: '#/components/schemas/User' } - } - } - } - } - }, - '400': { - description: '请求参数错误', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - }, - '404': { - description: '用户不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - }, - delete: { - tags: ['用户管理'], - summary: '删除用户', - description: '删除指定用户(软删除)', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '用户ID' - } - ], - responses: { - '200': { - description: '删除成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '用户删除成功' } - } - } - } - } - }, - '404': { - description: '用户不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 重置用户密码 - '/users/{id}/reset-password': { - post: { - tags: ['用户管理'], - summary: '重置用户密码', - description: '管理员重置指定用户的密码', - parameters: [ - { - name: 'id', - in: 'path', - required: true, - schema: { type: 'integer' }, - description: '用户ID' - } - ], - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['newPassword'], - properties: { - newPassword: { - type: 'string', - minLength: 6, - description: '新密码' - } - } - } - } - } - }, - responses: { - '200': { - description: '密码重置成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '密码重置成功' } - } - } - } - } - }, - '404': { - description: '用户不存在', - content: { - 'application/json': { - schema: { $ref: '#/components/schemas/ErrorResponse' } - } - } - } - } - } - }, - - // 批量操作用户 - '/users/batch': { - post: { - tags: ['用户管理'], - summary: '批量操作用户', - description: '批量启用、禁用或删除用户', - requestBody: { - required: true, - content: { - 'application/json': { - schema: { - type: 'object', - required: ['userIds', 'action'], - properties: { - userIds: { - type: 'array', - items: { type: 'integer' }, - description: '用户ID列表' - }, - action: { - type: 'string', - enum: ['activate', 'deactivate', 'ban', 'delete'], - description: '操作类型' - } - } - } - } - } - }, - responses: { - '200': { - description: '批量操作成功', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - success: { type: 'boolean', example: true }, - message: { type: 'string', example: '批量操作完成' }, - data: { - type: 'object', - properties: { - successCount: { type: 'integer', description: '成功处理的用户数量' }, - failedCount: { type: 'integer', description: '处理失败的用户数量' }, - errors: { type: 'array', items: { type: 'string' }, description: '错误信息列表' } - } - } - } - } - } - } - } - } - } - }, - - // 导出用户数据 - '/users/export': { - get: { - tags: ['用户管理'], - summary: '导出用户数据', - description: '导出用户数据为Excel文件', - parameters: [ - { - name: 'format', - in: 'query', - schema: { type: 'string', enum: ['xlsx', 'csv'], default: 'xlsx' }, - description: '导出格式' - }, - { - name: 'status', - in: 'query', - schema: { type: 'string', enum: ['active', 'inactive', 'banned'] }, - description: '用户状态筛选' - }, - { - name: 'role', - in: 'query', - schema: { type: 'string' }, - description: '角色筛选' - } - ], - responses: { - '200': { - description: '导出成功', - content: { - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': { - schema: { - type: 'string', - format: 'binary' - } - }, - 'text/csv': { - schema: { - type: 'string', - format: 'binary' - } - } - } - } - } - } - } -}; - -// 用户数据模型 -const userSchemas = { - User: { - type: 'object', - properties: { - id: { type: 'integer', description: '用户ID' }, - username: { type: 'string', description: '用户名' }, - email: { type: 'string', format: 'email', description: '邮箱' }, - phone: { type: 'string', description: '手机号' }, - realName: { type: 'string', description: '真实姓名' }, - avatar: { type: 'string', description: '头像URL' }, - status: { - type: 'string', - enum: ['active', 'inactive', 'banned'], - description: '用户状态:active-活跃,inactive-未激活,banned-已封禁' - }, - roles: { - type: 'array', - items: { - type: 'object', - properties: { - id: { type: 'integer' }, - name: { type: 'string' }, - description: { type: 'string' } - } - }, - description: '用户角色列表' - }, - permissions: { - type: 'array', - items: { type: 'string' }, - description: '用户权限列表' - }, - lastLoginAt: { type: 'string', format: 'date-time', description: '最后登录时间' }, - createdAt: { type: 'string', format: 'date-time', description: '创建时间' }, - updatedAt: { type: 'string', format: 'date-time', description: '更新时间' } - } - } -}; - -module.exports = { usersPaths, userSchemas }; \ No newline at end of file diff --git a/backend/test-alert-detection-logic.js b/backend/test-alert-detection-logic.js deleted file mode 100644 index a11a130..0000000 --- a/backend/test-alert-detection-logic.js +++ /dev/null @@ -1,273 +0,0 @@ -/** - * 预警检测逻辑测试 - * @file test-alert-detection-logic.js - * @description 测试智能项圈预警的自动检测逻辑 - */ - -// 模拟前端判断函数 -function determineAlertType(record) { - const alerts = [] - - // 检查电量预警 - if (record.battery !== undefined && record.battery !== null && record.battery < 20) { - alerts.push('battery') - } - - // 检查脱落预警 (bandge_status为0) - if (record.bandge_status !== undefined && record.bandge_status !== null && record.bandge_status === 0) { - alerts.push('wear') - } - - // 检查离线预警 (is_connect为0) - if (record.is_connect !== undefined && record.is_connect !== null && record.is_connect === 0) { - alerts.push('offline') - } - - // 检查温度预警 - if (record.temperature !== undefined && record.temperature !== null) { - if (record.temperature < 20) { - alerts.push('temperature_low') - } else if (record.temperature > 40) { - alerts.push('temperature_high') - } - } - - // 检查运动异常预警 (steps - y_steps为0) - if (record.steps !== undefined && record.y_steps !== undefined && - record.steps !== null && record.y_steps !== null) { - const movementDiff = record.steps - record.y_steps - if (movementDiff === 0) { - alerts.push('movement') - } - } - - // 返回第一个预警类型,如果没有预警则返回null - return alerts.length > 0 ? alerts[0] : null -} - -// 获取预警类型文本 -function getAlertTypeText(type) { - const typeMap = { - 'battery': '低电量预警', - 'offline': '离线预警', - 'temperature_low': '温度过低预警', - 'temperature_high': '温度过高预警', - 'movement': '异常运动预警', - 'wear': '佩戴异常预警' - } - return typeMap[type] || '未知预警' -} - -// 测试数据 -const testCases = [ - { - name: '正常设备', - data: { - battery: 85, - temperature: 25, - is_connect: 1, - bandge_status: 1, - steps: 1000, - y_steps: 500 - }, - expected: null - }, - { - name: '低电量预警', - data: { - battery: 15, - temperature: 25, - is_connect: 1, - bandge_status: 1, - steps: 1000, - y_steps: 500 - }, - expected: 'battery' - }, - { - name: '离线预警', - data: { - battery: 85, - temperature: 25, - is_connect: 0, - bandge_status: 1, - steps: 1000, - y_steps: 500 - }, - expected: 'offline' - }, - { - name: '佩戴异常预警', - data: { - battery: 85, - temperature: 25, - is_connect: 1, - bandge_status: 0, - steps: 1000, - y_steps: 500 - }, - expected: 'wear' - }, - { - name: '温度过低预警', - data: { - battery: 85, - temperature: 15, - is_connect: 1, - bandge_status: 1, - steps: 1000, - y_steps: 500 - }, - expected: 'temperature_low' - }, - { - name: '温度过高预警', - data: { - battery: 85, - temperature: 45, - is_connect: 1, - bandge_status: 1, - steps: 1000, - y_steps: 500 - }, - expected: 'temperature_high' - }, - { - name: '异常运动预警', - data: { - battery: 85, - temperature: 25, - is_connect: 1, - bandge_status: 1, - steps: 1000, - y_steps: 1000 - }, - expected: 'movement' - }, - { - name: '多重预警(低电量+离线)', - data: { - battery: 15, - temperature: 25, - is_connect: 0, - bandge_status: 1, - steps: 1000, - y_steps: 500 - }, - expected: 'battery' // 应该返回第一个预警 - }, - { - name: '边界值测试 - 电量20', - data: { - battery: 20, - temperature: 25, - is_connect: 1, - bandge_status: 1, - steps: 1000, - y_steps: 500 - }, - expected: null // 20不算低电量 - }, - { - name: '边界值测试 - 电量19', - data: { - battery: 19, - temperature: 25, - is_connect: 1, - bandge_status: 1, - steps: 1000, - y_steps: 500 - }, - expected: 'battery' // 19算低电量 - }, - { - name: '边界值测试 - 温度20', - data: { - battery: 85, - temperature: 20, - is_connect: 1, - bandge_status: 1, - steps: 1000, - y_steps: 500 - }, - expected: null // 20不算温度过低 - }, - { - name: '边界值测试 - 温度19', - data: { - battery: 85, - temperature: 19, - is_connect: 1, - bandge_status: 1, - steps: 1000, - y_steps: 500 - }, - expected: 'temperature_low' // 19算温度过低 - }, - { - name: '边界值测试 - 温度40', - data: { - battery: 85, - temperature: 40, - is_connect: 1, - bandge_status: 1, - steps: 1000, - y_steps: 500 - }, - expected: null // 40不算温度过高 - }, - { - name: '边界值测试 - 温度41', - data: { - battery: 85, - temperature: 41, - is_connect: 1, - bandge_status: 1, - steps: 1000, - y_steps: 500 - }, - expected: 'temperature_high' // 41算温度过高 - } -]; - -// 运行测试 -function runTests() { - console.log('🧪 开始测试预警检测逻辑...\n'); - - let passed = 0; - let failed = 0; - - testCases.forEach((testCase, index) => { - const result = determineAlertType(testCase.data); - const expected = testCase.expected; - const success = result === expected; - - console.log(`测试 ${index + 1}: ${testCase.name}`); - console.log(` 输入数据:`, testCase.data); - console.log(` 预期结果: ${expected ? getAlertTypeText(expected) : '正常'}`); - console.log(` 实际结果: ${result ? getAlertTypeText(result) : '正常'}`); - console.log(` 测试结果: ${success ? '✅ 通过' : '❌ 失败'}`); - console.log(''); - - if (success) { - passed++; - } else { - failed++; - } - }); - - console.log('📊 测试总结:'); - console.log(` 总测试数: ${testCases.length}`); - console.log(` 通过: ${passed}`); - console.log(` 失败: ${failed}`); - console.log(` 成功率: ${((passed / testCases.length) * 100).toFixed(1)}%`); - - if (failed === 0) { - console.log('\n🎉 所有测试通过!预警检测逻辑工作正常。'); - } else { - console.log('\n⚠️ 有测试失败,请检查预警检测逻辑。'); - } -} - -// 运行测试 -runTests(); diff --git a/backend/test-all-smart-alert-apis.js b/backend/test-all-smart-alert-apis.js deleted file mode 100644 index ef33aec..0000000 --- a/backend/test-all-smart-alert-apis.js +++ /dev/null @@ -1,229 +0,0 @@ -/** - * 智能预警API综合测试脚本 - * @file test-all-smart-alert-apis.js - * @description 测试智能耳标预警和智能项圈预警的所有API接口功能 - */ - -const eartagTests = require('./test-smart-eartag-alert-api'); -const collarTests = require('./test-smart-collar-alert-api'); - -// 测试结果统计 -let allTestResults = { - total: 0, - passed: 0, - failed: 0, - errors: [] -}; - -// 测试辅助函数 -function logTest(testName, success, message = '') { - allTestResults.total++; - if (success) { - allTestResults.passed++; - console.log(`✅ ${testName}: ${message}`); - } else { - allTestResults.failed++; - allTestResults.errors.push(`${testName}: ${message}`); - console.log(`❌ ${testName}: ${message}`); - } -} - -// 综合测试函数 -async function runComprehensiveTests() { - console.log('🚀 开始智能预警API综合测试...\n'); - console.log('='.repeat(60)); - console.log('📋 测试范围:'); - console.log(' - 智能耳标预警API (6个接口)'); - console.log(' - 智能项圈预警API (6个接口)'); - console.log(' - 错误处理和边界条件测试'); - console.log('='.repeat(60)); - - try { - // 测试智能耳标预警API - console.log('\n🔵 测试智能耳标预警API...'); - console.log('-'.repeat(40)); - - const eartagResults = await runEartagTests(); - logTest('智能耳标预警API测试', eartagResults.failed === 0, - `通过 ${eartagResults.passed}/${eartagResults.total} 项测试`); - - // 测试智能项圈预警API - console.log('\n🟢 测试智能项圈预警API...'); - console.log('-'.repeat(40)); - - const collarResults = await runCollarTests(); - logTest('智能项圈预警API测试', collarResults.failed === 0, - `通过 ${collarResults.passed}/${collarResults.total} 项测试`); - - // 测试API文档访问 - console.log('\n📚 测试API文档访问...'); - console.log('-'.repeat(40)); - - await testApiDocumentation(); - - // 输出综合测试结果 - console.log('\n' + '='.repeat(60)); - console.log('📊 综合测试结果汇总:'); - console.log(`总测试数: ${allTestResults.total}`); - console.log(`通过: ${allTestResults.passed} ✅`); - console.log(`失败: ${allTestResults.failed} ❌`); - console.log(`成功率: ${((allTestResults.passed / allTestResults.total) * 100).toFixed(2)}%`); - - if (allTestResults.errors.length > 0) { - console.log('\n❌ 失败详情:'); - allTestResults.errors.forEach((error, index) => { - console.log(`${index + 1}. ${error}`); - }); - } - - if (allTestResults.failed === 0) { - console.log('\n🎉 所有测试通过!智能预警API系统功能完全正常。'); - console.log('\n📖 API文档访问地址: http://localhost:5350/api-docs'); - console.log('🔗 基础API地址: http://localhost:5350/api/smart-alerts/public'); - } else { - console.log('\n⚠️ 部分测试失败,请检查相关功能。'); - } - - } catch (error) { - console.error('❌ 综合测试执行异常:', error.message); - } -} - -// 运行智能耳标预警测试 -async function runEartagTests() { - const results = { total: 0, passed: 0, failed: 0 }; - - try { - await eartagTests.testGetEartagAlertStats(); - await eartagTests.testGetEartagAlerts(); - await eartagTests.testGetEartagAlertsWithFilters(); - await eartagTests.testGetEartagAlertById(); - await eartagTests.testHandleEartagAlert(); - await eartagTests.testBatchHandleEartagAlerts(); - await eartagTests.testExportEartagAlerts(); - await eartagTests.testErrorHandling(); - - // 这里需要从eartagTests模块获取结果,但由于模块结构限制,我们使用模拟数据 - results.total = 8; - results.passed = 8; // 假设都通过 - results.failed = 0; - - } catch (error) { - console.error('智能耳标预警测试异常:', error.message); - results.failed++; - } - - return results; -} - -// 运行智能项圈预警测试 -async function runCollarTests() { - const results = { total: 0, passed: 0, failed: 0 }; - - try { - await collarTests.testGetCollarAlertStats(); - await collarTests.testGetCollarAlerts(); - await collarTests.testGetCollarAlertsWithFilters(); - await collarTests.testGetCollarAlertById(); - await collarTests.testHandleCollarAlert(); - await collarTests.testBatchHandleCollarAlerts(); - await collarTests.testExportCollarAlerts(); - await collarTests.testErrorHandling(); - - // 这里需要从collarTests模块获取结果,但由于模块结构限制,我们使用模拟数据 - results.total = 8; - results.passed = 8; // 假设都通过 - results.failed = 0; - - } catch (error) { - console.error('智能项圈预警测试异常:', error.message); - results.failed++; - } - - return results; -} - -// 测试API文档访问 -async function testApiDocumentation() { - try { - const axios = require('axios'); - - // 测试Swagger JSON文档 - const swaggerResponse = await axios.get('http://localhost:5350/api-docs/swagger.json', { - timeout: 5000 - }); - - if (swaggerResponse.status === 200) { - const swaggerSpec = swaggerResponse.data; - const hasEartagPaths = swaggerSpec.paths && Object.keys(swaggerSpec.paths).some(path => path.includes('/eartag')); - const hasCollarPaths = swaggerSpec.paths && Object.keys(swaggerSpec.paths).some(path => path.includes('/collar')); - - logTest('Swagger JSON文档', true, '成功获取API文档规范'); - logTest('耳标预警API文档', hasEartagPaths, hasEartagPaths ? '包含耳标预警API路径' : '缺少耳标预警API路径'); - logTest('项圈预警API文档', hasCollarPaths, hasCollarPaths ? '包含项圈预警API路径' : '缺少项圈预警API路径'); - } else { - logTest('Swagger JSON文档', false, `获取失败: HTTP ${swaggerResponse.status}`); - } - - // 测试Swagger UI界面 - const uiResponse = await axios.get('http://localhost:5350/api-docs/', { - timeout: 5000 - }); - - if (uiResponse.status === 200) { - logTest('Swagger UI界面', true, '成功访问API文档界面'); - } else { - logTest('Swagger UI界面', false, `访问失败: HTTP ${uiResponse.status}`); - } - - } catch (error) { - logTest('API文档测试', false, `测试异常: ${error.message}`); - } -} - -// 性能测试 -async function runPerformanceTests() { - console.log('\n⚡ 性能测试...'); - console.log('-'.repeat(40)); - - try { - const axios = require('axios'); - const startTime = Date.now(); - - // 并发测试多个API - const promises = [ - axios.get('http://localhost:5350/api/smart-alerts/public/eartag/stats'), - axios.get('http://localhost:5350/api/smart-alerts/public/collar/stats'), - axios.get('http://localhost:5350/api/smart-alerts/public/eartag?limit=5'), - axios.get('http://localhost:5350/api/smart-alerts/public/collar?limit=5') - ]; - - const results = await Promise.all(promises); - const endTime = Date.now(); - const duration = endTime - startTime; - - const allSuccessful = results.every(response => response.status === 200); - logTest('并发API性能测试', allSuccessful, `4个API并发请求完成,耗时 ${duration}ms`); - - if (duration < 2000) { - logTest('响应时间测试', true, `响应时间良好: ${duration}ms`); - } else { - logTest('响应时间测试', false, `响应时间较慢: ${duration}ms`); - } - - } catch (error) { - logTest('性能测试', false, `测试异常: ${error.message}`); - } -} - -// 如果直接运行此脚本 -if (require.main === module) { - runComprehensiveTests() - .then(() => runPerformanceTests()) - .catch(console.error); -} - -module.exports = { - runComprehensiveTests, - runPerformanceTests -}; diff --git a/backend/test-api-access.js b/backend/test-api-access.js deleted file mode 100644 index 0d212d0..0000000 --- a/backend/test-api-access.js +++ /dev/null @@ -1,73 +0,0 @@ -/** - * API访问测试脚本 - * @file test-api-access.js - * @description 测试API接口是否正常访问 - */ - -const axios = require('axios'); - -async function testApiAccess() { - console.log('🔍 测试API访问...\n'); - - const baseUrl = 'http://localhost:5350'; - - try { - // 1. 测试服务器根路径 - console.log('1. 测试服务器根路径...'); - const rootResponse = await axios.get(`${baseUrl}/`); - console.log('✅ 服务器根路径正常:', rootResponse.data); - - // 2. 测试API文档访问 - console.log('\n2. 测试API文档访问...'); - const docsResponse = await axios.get(`${baseUrl}/api-docs/`); - console.log('✅ API文档页面正常访问'); - - // 3. 测试Swagger JSON - console.log('\n3. 测试Swagger JSON...'); - const swaggerResponse = await axios.get(`${baseUrl}/api-docs/swagger.json`); - console.log('✅ Swagger JSON正常:', swaggerResponse.data.info.title); - - // 4. 测试智能耳标预警API - console.log('\n4. 测试智能耳标预警API...'); - const eartagStatsResponse = await axios.get(`${baseUrl}/api/smart-alerts/public/eartag/stats`); - console.log('✅ 智能耳标预警统计API正常:', eartagStatsResponse.data.success); - - // 5. 测试智能项圈预警API - console.log('\n5. 测试智能项圈预警API...'); - const collarStatsResponse = await axios.get(`${baseUrl}/api/smart-alerts/public/collar/stats`); - console.log('✅ 智能项圈预警统计API正常:', collarStatsResponse.data.success); - - // 6. 检查Swagger JSON中的路径 - console.log('\n6. 检查Swagger JSON中的路径...'); - const paths = Object.keys(swaggerResponse.data.paths || {}); - const smartAlertPaths = paths.filter(path => path.includes('/smart-alerts/public')); - console.log('📋 找到的智能预警API路径:'); - smartAlertPaths.forEach(path => { - console.log(` - ${path}`); - }); - - if (smartAlertPaths.length === 0) { - console.log('❌ 未找到智能预警API路径,可能是Swagger配置问题'); - } else { - console.log(`✅ 找到 ${smartAlertPaths.length} 个智能预警API路径`); - } - - } catch (error) { - console.error('❌ 测试失败:', error.message); - - if (error.code === 'ECONNREFUSED') { - console.log('💡 建议: 请确保服务器已启动 (npm start)'); - } else if (error.response) { - console.log('💡 建议: 检查API路径和端口配置'); - console.log(' 状态码:', error.response.status); - console.log(' 响应:', error.response.data); - } - } -} - -// 如果直接运行此脚本 -if (require.main === module) { - testApiAccess().catch(console.error); -} - -module.exports = { testApiAccess }; diff --git a/backend/test-api-response.js b/backend/test-api-response.js deleted file mode 100644 index de32719..0000000 --- a/backend/test-api-response.js +++ /dev/null @@ -1,88 +0,0 @@ -/** - * 测试API响应 - * @file test-api-response.js - * @description 测试智能项圈预警API是否返回正确的数据 - */ - -const axios = require('axios'); - -const BASE_URL = 'http://localhost:5350/api/smart-alerts/public'; - -async function testApiResponse() { - console.log('🔍 测试智能项圈预警API响应...\n'); - - try { - // 1. 测试获取预警列表 - console.log('1. 测试获取预警列表...'); - const listResponse = await axios.get(`${BASE_URL}/collar`, { - params: { - page: 1, - limit: 5 - } - }); - - console.log('API响应状态:', listResponse.status); - console.log('API响应数据:', JSON.stringify(listResponse.data, null, 2)); - - if (listResponse.data.success) { - const data = listResponse.data.data || []; - console.log(`\n数据条数: ${data.length}`); - - // 查找项圈22012000107的数据 - const targetCollar = data.find(item => item.collarNumber == 22012000107); - if (targetCollar) { - console.log('\n找到项圈22012000107的数据:'); - console.log('电量:', targetCollar.battery); - console.log('温度:', targetCollar.temperature); - console.log('预警类型:', targetCollar.alertType); - console.log('预警级别:', targetCollar.alertLevel); - console.log('完整数据:', JSON.stringify(targetCollar, null, 2)); - } else { - console.log('\n未找到项圈22012000107的数据'); - console.log('可用的项圈编号:'); - data.forEach(item => { - console.log(`- ${item.collarNumber}`); - }); - } - } - - // 2. 测试搜索特定项圈 - console.log('\n2. 测试搜索项圈22012000107...'); - const searchResponse = await axios.get(`${BASE_URL}/collar`, { - params: { - search: '22012000107', - page: 1, - limit: 10 - } - }); - - if (searchResponse.data.success) { - const searchData = searchResponse.data.data || []; - console.log(`搜索到 ${searchData.length} 条数据`); - - searchData.forEach((item, index) => { - console.log(`\n搜索结果${index + 1}:`); - console.log('项圈编号:', item.collarNumber); - console.log('电量:', item.battery); - console.log('温度:', item.temperature); - console.log('预警类型:', item.alertType); - console.log('预警级别:', item.alertLevel); - }); - } - - // 3. 测试统计数据 - console.log('\n3. 测试统计数据...'); - const statsResponse = await axios.get(`${BASE_URL}/collar/stats`); - console.log('统计数据:', JSON.stringify(statsResponse.data, null, 2)); - - } catch (error) { - console.error('❌ API测试失败:', error.message); - if (error.response) { - console.error('响应状态:', error.response.status); - console.error('响应数据:', error.response.data); - } - } -} - -// 运行测试 -testApiResponse().catch(console.error); diff --git a/backend/test-collar-alert-data.js b/backend/test-collar-alert-data.js deleted file mode 100644 index a75fef6..0000000 --- a/backend/test-collar-alert-data.js +++ /dev/null @@ -1,111 +0,0 @@ -/** - * 测试智能项圈预警数据 - * @file test-collar-alert-data.js - * @description 测试智能项圈预警API返回的数据 - */ - -const axios = require('axios'); - -const BASE_URL = 'http://localhost:5350/api/smart-alerts/public'; - -async function testCollarAlertData() { - console.log('🔍 测试智能项圈预警数据...\n'); - - try { - // 1. 测试获取预警列表 - console.log('1. 获取预警列表数据...'); - const listResponse = await axios.get(`${BASE_URL}/collar`, { - params: { - page: 1, - limit: 10 - } - }); - - console.log('API响应状态:', listResponse.status); - console.log('API响应数据:', JSON.stringify(listResponse.data, null, 2)); - - if (listResponse.data.success) { - const data = listResponse.data.data || []; - console.log(`\n数据条数: ${data.length}`); - - if (data.length > 0) { - console.log('\n第一条数据示例:'); - console.log(JSON.stringify(data[0], null, 2)); - - // 测试判断函数 - console.log('\n测试预警判断逻辑:'); - const testRecord = data[0]; - const alertType = determineAlertType(testRecord); - console.log('判断结果:', alertType); - - // 显示各字段值 - console.log('\n字段值检查:'); - console.log('battery:', testRecord.battery, typeof testRecord.battery); - console.log('temperature:', testRecord.temperature, typeof testRecord.temperature); - console.log('is_connect:', testRecord.is_connect, typeof testRecord.is_connect); - console.log('bandge_status:', testRecord.bandge_status, typeof testRecord.bandge_status); - console.log('steps:', testRecord.steps, typeof testRecord.steps); - console.log('y_steps:', testRecord.y_steps, typeof testRecord.y_steps); - } else { - console.log('⚠️ 没有数据返回'); - } - } else { - console.log('❌ API调用失败:', listResponse.data.message); - } - - // 2. 测试获取统计数据 - console.log('\n2. 获取统计数据...'); - const statsResponse = await axios.get(`${BASE_URL}/collar/stats`); - console.log('统计数据:', JSON.stringify(statsResponse.data, null, 2)); - - } catch (error) { - console.error('❌ 测试失败:', error.message); - if (error.response) { - console.error('响应状态:', error.response.status); - console.error('响应数据:', error.response.data); - } - } -} - -// 判断预警类型函数 -function determineAlertType(record) { - const alerts = [] - - // 检查电量预警 - if (record.battery !== undefined && record.battery !== null && record.battery < 20) { - alerts.push('battery') - } - - // 检查脱落预警 (bandge_status为0) - if (record.bandge_status !== undefined && record.bandge_status !== null && record.bandge_status === 0) { - alerts.push('wear') - } - - // 检查离线预警 (is_connect为0) - if (record.is_connect !== undefined && record.is_connect !== null && record.is_connect === 0) { - alerts.push('offline') - } - - // 检查温度预警 - if (record.temperature !== undefined && record.temperature !== null) { - if (record.temperature < 20) { - alerts.push('temperature_low') - } else if (record.temperature > 40) { - alerts.push('temperature_high') - } - } - - // 检查运动异常预警 (steps - y_steps为0) - if (record.steps !== undefined && record.y_steps !== undefined && - record.steps !== null && record.y_steps !== null) { - const movementDiff = record.steps - record.y_steps - if (movementDiff === 0) { - alerts.push('movement') - } - } - - return alerts.length > 0 ? alerts[0] : null -} - -// 运行测试 -testCollarAlertData().catch(console.error); diff --git a/backend/test-direct-api.js b/backend/test-direct-api.js deleted file mode 100644 index 59d2b3b..0000000 --- a/backend/test-direct-api.js +++ /dev/null @@ -1,64 +0,0 @@ -/** - * 直接测试API - * @file test-direct-api.js - * @description 直接测试智能项圈预警API,不通过HTTP请求 - */ - -const { getCollarAlerts } = require('./controllers/smartCollarAlertController'); - -async function testDirectApi() { - console.log('🔍 直接测试智能项圈预警API...\n'); - - try { - // 模拟请求对象 - const mockReq = { - query: { - page: 1, - limit: 5, - search: '22012000107' - } - }; - - // 模拟响应对象 - const mockRes = { - json: (data) => { - console.log('API响应数据:'); - console.log(JSON.stringify(data, null, 2)); - - if (data.success && data.data) { - const targetCollar = data.data.find(item => item.collarNumber == 22012000107); - if (targetCollar) { - console.log('\n找到项圈22012000107的数据:'); - console.log('电量:', targetCollar.battery); - console.log('温度:', targetCollar.temperature); - console.log('预警类型:', targetCollar.alertType); - console.log('预警级别:', targetCollar.alertLevel); - } else { - console.log('\n未找到项圈22012000107的数据'); - console.log('可用的项圈编号:'); - data.data.forEach(item => { - console.log(`- ${item.collarNumber}`); - }); - } - } - }, - status: (code) => ({ - json: (data) => { - console.log('错误响应:', code, data); - } - }) - }; - - // 调用API函数 - await getCollarAlerts(mockReq, mockRes); - - } catch (error) { - console.error('❌ 测试失败:', error.message); - console.error('错误详情:', error); - } finally { - process.exit(0); - } -} - -// 运行测试 -testDirectApi().catch(console.error); diff --git a/backend/test-error-fix.js b/backend/test-error-fix.js deleted file mode 100644 index ab34401..0000000 --- a/backend/test-error-fix.js +++ /dev/null @@ -1,91 +0,0 @@ -/** - * 测试错误修复 - * @file test-error-fix.js - * @description 测试修复后的智能项圈预警页面 - */ - -const axios = require('axios'); - -const BASE_URL = 'http://localhost:5350/api/smart-alerts/public'; - -async function testErrorFix() { - console.log('🔧 测试错误修复...\n'); - - try { - // 获取预警列表数据 - const response = await axios.get(`${BASE_URL}/collar`, { - params: { page: 1, limit: 3 } - }); - - if (response.data.success) { - const data = response.data.data || []; - const stats = response.data.stats || {}; - - console.log('✅ API调用成功'); - console.log(`数据条数: ${data.length}`); - console.log('统计数据:', stats); - - // 模拟前端数据转换逻辑 - console.log('\n🔄 模拟前端数据转换...'); - - data.forEach((item, index) => { - console.log(`\n处理第${index + 1}条数据:`); - console.log('原始数据:', { - id: item.id, - alertType: item.alertType, - alertLevel: item.alertLevel, - collarNumber: item.collarNumber, - battery: item.battery, - temperature: item.temperature - }); - - // 模拟前端转换逻辑 - let alertTypeText = '正常' - let alertLevel = 'low' - let determinedAlertType = null - - if (item.alertType) { - const alertTypeMap = { - 'battery': '低电量预警', - 'offline': '离线预警', - 'temperature': '温度预警', - 'temperature_low': '温度过低预警', - 'temperature_high': '温度过高预警', - 'movement': '异常运动预警', - 'wear': '佩戴异常预警' - } - alertTypeText = alertTypeMap[item.alertType] || item.alertType - determinedAlertType = item.alertType - - const alertLevelMap = { - 'high': '高级', - 'medium': '中级', - 'low': '低级', - 'critical': '紧急' - } - alertLevel = alertLevelMap[item.alertLevel] || item.alertLevel - } - - console.log('转换结果:', { - alertTypeText, - alertLevel, - determinedAlertType - }); - }); - - console.log('\n✅ 数据转换测试通过,没有ReferenceError'); - - } else { - console.log('❌ API调用失败:', response.data.message); - } - - } catch (error) { - console.error('❌ 测试失败:', error.message); - if (error.response) { - console.error('响应状态:', error.response.status); - } - } -} - -// 运行测试 -testErrorFix().catch(console.error); diff --git a/backend/test-fixed-collar-alert.js b/backend/test-fixed-collar-alert.js deleted file mode 100644 index 9f36d65..0000000 --- a/backend/test-fixed-collar-alert.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * 测试修复后的智能项圈预警 - * @file test-fixed-collar-alert.js - * @description 测试修复后的智能项圈预警数据展示 - */ - -const axios = require('axios'); - -const BASE_URL = 'http://localhost:5350/api/smart-alerts/public'; - -async function testFixedCollarAlert() { - console.log('🔧 测试修复后的智能项圈预警...\n'); - - try { - // 1. 获取预警列表 - console.log('1. 获取预警列表...'); - const listResponse = await axios.get(`${BASE_URL}/collar`, { - params: { page: 1, limit: 5 } - }); - - if (listResponse.data.success) { - const data = listResponse.data.data || []; - const stats = listResponse.data.stats || {}; - - console.log('✅ 数据获取成功'); - console.log(`数据条数: ${data.length}`); - console.log('统计数据:', stats); - - // 显示统计卡片数据 - console.log('\n📊 统计卡片数据:'); - console.log(`低电量预警: ${stats.lowBattery || 0}`); - console.log(`离线预警: ${stats.offline || 0}`); - console.log(`温度预警: ${stats.highTemperature || 0}`); - console.log(`异常运动预警: ${stats.abnormalMovement || 0}`); - console.log(`佩戴异常预警: ${stats.wearOff || 0}`); - - // 显示前几条数据 - console.log('\n📋 预警列表数据:'); - data.slice(0, 3).forEach((item, index) => { - console.log(`\n第${index + 1}条数据:`); - console.log(` 项圈编号: ${item.collarNumber}`); - console.log(` 预警类型: ${item.alertType}`); - console.log(` 预警级别: ${item.alertLevel}`); - console.log(` 设备电量: ${item.battery}%`); - console.log(` 设备温度: ${item.temperature}°C`); - console.log(` 当日步数: ${item.dailySteps}`); - }); - - } else { - console.log('❌ 数据获取失败:', listResponse.data.message); - } - - // 2. 测试统计数据API - console.log('\n2. 测试统计数据API...'); - const statsResponse = await axios.get(`${BASE_URL}/collar/stats`); - - if (statsResponse.data.success) { - const statsData = statsResponse.data.data || {}; - console.log('✅ 统计数据API正常'); - console.log('统计数据:', statsData); - } else { - console.log('❌ 统计数据API失败:', statsResponse.data.message); - } - - console.log('\n🎉 测试完成!'); - console.log('\n💡 现在前端页面应该能正确显示:'); - console.log(' - 统计卡片显示非零数据'); - console.log(' - 预警列表显示正确的预警类型和级别'); - console.log(' - 数据来自API而不是硬编码'); - - } catch (error) { - console.error('❌ 测试失败:', error.message); - if (error.response) { - console.error('响应状态:', error.response.status); - console.error('响应数据:', error.response.data); - } - } -} - -// 运行测试 -testFixedCollarAlert().catch(console.error); diff --git a/backend/test-model-connection.js b/backend/test-model-connection.js deleted file mode 100644 index b490e09..0000000 --- a/backend/test-model-connection.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * 测试模型连接 - * @file test-model-connection.js - * @description 测试IotXqClient模型是否从正确的数据库读取数据 - */ - -const { IotXqClient } = require('./models'); - -async function testModelConnection() { - console.log('🔍 测试IotXqClient模型连接...\n'); - - try { - // 1. 测试数据库连接 - console.log('1. 测试数据库连接...'); - await IotXqClient.sequelize.authenticate(); - console.log('✅ 数据库连接成功'); - - // 2. 检查数据库配置 - console.log('\n2. 检查数据库配置...'); - const config = IotXqClient.sequelize.config; - console.log('数据库配置:'); - console.log('主机:', config.host); - console.log('端口:', config.port); - console.log('数据库名:', config.database); - console.log('用户名:', config.username); - - // 3. 查询项圈22012000107的数据 - console.log('\n3. 查询项圈22012000107的数据...'); - const devices = await IotXqClient.findAll({ - where: { - sn: '22012000107' - }, - order: [['uptime', 'DESC']] - }); - - console.log(`找到 ${devices.length} 条记录`); - - devices.forEach((device, index) => { - console.log(`\n记录${index + 1}:`); - console.log('ID:', device.id); - console.log('SN:', device.sn); - console.log('设备ID:', device.deviceId); - console.log('电量:', device.battery, '(类型:', typeof device.battery, ')'); - console.log('温度:', device.temperature, '(类型:', typeof device.temperature, ')'); - console.log('状态:', device.state); - console.log('更新时间:', device.uptime); - }); - - // 4. 查询所有项圈的最新数据 - console.log('\n4. 查询所有项圈的最新数据...'); - const allDevices = await IotXqClient.findAll({ - order: [['uptime', 'DESC']], - limit: 10 - }); - - console.log('所有项圈的最新数据:'); - allDevices.forEach((device, index) => { - console.log(`${index + 1}. SN: ${device.sn}, 电量: ${device.battery}, 温度: ${device.temperature}, 状态: ${device.state}`); - }); - - // 5. 检查是否有电量为99的记录 - console.log('\n5. 检查是否有电量为99的记录...'); - const battery99Devices = await IotXqClient.findAll({ - where: { - battery: '99' - }, - order: [['uptime', 'DESC']], - limit: 5 - }); - - console.log(`找到 ${battery99Devices.length} 条电量为99的记录`); - battery99Devices.forEach((device, index) => { - console.log(`${index + 1}. SN: ${device.sn}, 电量: ${device.battery}, 温度: ${device.temperature}, 状态: ${device.state}`); - }); - - } catch (error) { - console.error('❌ 测试失败:', error.message); - console.error('错误详情:', error); - } finally { - process.exit(0); - } -} - -// 运行测试 -testModelConnection().catch(console.error); diff --git a/backend/test-models.js b/backend/test-models.js deleted file mode 100644 index 6ee686e..0000000 --- a/backend/test-models.js +++ /dev/null @@ -1,33 +0,0 @@ -const { User, Role, Permission } = require('./models'); - -async function testModels() { - try { - console.log('测试模型关联...'); - - // 测试用户查询 - const user = await User.findByPk(1, { - include: [{ - model: Role, - as: 'role', - include: [{ - model: Permission, - as: 'permissions', - through: { attributes: [] } - }] - }] - }); - - if (user) { - console.log('用户:', user.username); - console.log('角色:', user.role ? user.role.name : '无'); - console.log('权限数量:', user.role && user.role.permissions ? user.role.permissions.length : 0); - } else { - console.log('未找到用户'); - } - - } catch (error) { - console.error('测试失败:', error.message); - } -} - -testModels(); diff --git a/backend/test-ngrok.bat b/backend/test-ngrok.bat deleted file mode 100644 index 1fb0c58..0000000 --- a/backend/test-ngrok.bat +++ /dev/null @@ -1,49 +0,0 @@ -@echo off -echo ======================================== -echo ngrok测试脚本(无需认证) -echo ======================================== -echo. - -echo 注意:此脚本使用ngrok的免费版本 -echo 每次重启ngrok,URL会发生变化 -echo. - -echo 选择要测试的服务: -echo 1. 后端服务 (端口5350) -echo 2. 前端服务 (端口5300) -echo 3. 同时启动两个服务 -echo. - -set /p choice="请输入选择 (1-3): " - -if "%choice%"=="1" ( - echo 启动后端服务穿透... - echo 请在新窗口中查看访问地址 - start "ngrok-backend" .\ngrok.exe http 5350 -) else if "%choice%"=="2" ( - echo 启动前端服务穿透... - echo 请在新窗口中查看访问地址 - start "ngrok-frontend" .\ngrok.exe http 5300 -) else if "%choice%"=="3" ( - echo 启动后端服务穿透... - start "ngrok-backend" .\ngrok.exe http 5350 - timeout /t 2 /nobreak >nul - echo 启动前端服务穿透... - start "ngrok-frontend" .\ngrok.exe http 5300 -) else ( - echo 无效选择 - goto end -) - -echo. -echo ======================================== -echo ngrok已启动! -echo ======================================== -echo. -echo 请查看新打开的窗口获取访问地址 -echo 访问地址格式:https://xxxxx.ngrok.io -echo. - -:end -echo 按任意键退出... -pause >nul diff --git a/backend/test-smart-collar-alert-api.js b/backend/test-smart-collar-alert-api.js deleted file mode 100644 index 9483c6c..0000000 --- a/backend/test-smart-collar-alert-api.js +++ /dev/null @@ -1,359 +0,0 @@ -/** - * 智能项圈预警API测试脚本 - * @file test-smart-collar-alert-api.js - * @description 测试智能项圈预警相关的API接口功能 - */ - -const axios = require('axios'); - -// 配置基础URL -const BASE_URL = 'http://localhost:5350/api/smart-alerts/public'; - -// 创建axios实例 -const api = axios.create({ - baseURL: BASE_URL, - timeout: 10000, - headers: { - 'Content-Type': 'application/json' - } -}); - -// 测试结果统计 -let testResults = { - total: 0, - passed: 0, - failed: 0, - errors: [] -}; - -// 测试辅助函数 -function logTest(testName, success, message = '') { - testResults.total++; - if (success) { - testResults.passed++; - console.log(`✅ ${testName}: ${message}`); - } else { - testResults.failed++; - testResults.errors.push(`${testName}: ${message}`); - console.log(`❌ ${testName}: ${message}`); - } -} - -// 测试函数 -async function testGetCollarAlertStats() { - try { - console.log('\n=== 测试获取智能项圈预警统计 ==='); - const response = await api.get('/collar/stats'); - - if (response.status === 200 && response.data.success) { - const data = response.data.data; - logTest('获取项圈预警统计', true, `成功获取统计,设备总数: ${data.totalDevices}, 预警总数: ${data.totalAlerts}`); - - // 验证数据结构 - const requiredFields = ['totalDevices', 'lowBattery', 'offline', 'highTemperature', 'abnormalMovement', 'totalAlerts']; - const hasAllFields = requiredFields.every(field => data.hasOwnProperty(field)); - logTest('统计数据结构验证', hasAllFields, hasAllFields ? '数据结构正确' : '缺少必要字段'); - - // 验证项圈特有字段 - const hasWearOffField = data.hasOwnProperty('wearOff'); - logTest('项圈特有字段验证', hasWearOffField, hasWearOffField ? '包含项圈脱落预警字段' : '缺少项圈脱落预警字段'); - } else { - logTest('获取项圈预警统计', false, `请求失败: ${response.data.message || '未知错误'}`); - } - } catch (error) { - logTest('获取项圈预警统计', false, `请求异常: ${error.message}`); - } -} - -async function testGetCollarAlerts() { - try { - console.log('\n=== 测试获取智能项圈预警列表 ==='); - - // 测试基础列表获取 - const response = await api.get('/collar?page=1&limit=5'); - - if (response.status === 200 && response.data.success) { - const data = response.data; - logTest('获取项圈预警列表', true, `成功获取列表,共 ${data.total} 条预警`); - - // 验证分页信息 - const hasPagination = data.pagination && typeof data.pagination.page === 'number'; - logTest('分页信息验证', hasPagination, hasPagination ? '分页信息正确' : '分页信息缺失'); - - // 验证统计数据 - const hasStats = data.stats && typeof data.stats.lowBattery === 'number'; - logTest('统计信息验证', hasStats, hasStats ? '统计信息正确' : '统计信息缺失'); - - // 验证项圈特有字段 - if (data.data.length > 0) { - const firstAlert = data.data[0]; - const hasCollarFields = firstAlert.hasOwnProperty('collarNumber') && firstAlert.hasOwnProperty('wearStatus'); - logTest('项圈字段验证', hasCollarFields, hasCollarFields ? '包含项圈特有字段' : '缺少项圈特有字段'); - } - } else { - logTest('获取项圈预警列表', false, `请求失败: ${response.data.message || '未知错误'}`); - } - } catch (error) { - logTest('获取项圈预警列表', false, `请求异常: ${error.message}`); - } -} - -async function testGetCollarAlertsWithFilters() { - try { - console.log('\n=== 测试项圈预警列表筛选功能 ==='); - - // 测试按预警类型筛选 - const batteryResponse = await api.get('/collar?alertType=battery&limit=3'); - - if (batteryResponse.status === 200 && batteryResponse.data.success) { - const batteryAlerts = batteryResponse.data.data; - const allBattery = batteryAlerts.every(alert => alert.alertType === 'battery'); - logTest('按预警类型筛选', allBattery, `筛选结果: ${batteryAlerts.length} 条低电量预警`); - } else { - logTest('按预警类型筛选', false, `筛选失败: ${batteryResponse.data.message || '未知错误'}`); - } - - // 测试项圈脱落预警筛选 - const wearResponse = await api.get('/collar?alertType=wear&limit=3'); - - if (wearResponse.status === 200 && wearResponse.data.success) { - const wearAlerts = wearResponse.data.data; - const allWear = wearAlerts.every(alert => alert.alertType === 'wear'); - logTest('项圈脱落预警筛选', allWear, `筛选结果: ${wearAlerts.length} 条项圈脱落预警`); - } else { - logTest('项圈脱落预警筛选', false, `筛选失败: ${wearResponse.data.message || '未知错误'}`); - } - - // 测试搜索功能 - const searchResponse = await api.get('/collar?search=COLLAR&limit=3'); - - if (searchResponse.status === 200 && searchResponse.data.success) { - const searchAlerts = searchResponse.data.data; - logTest('搜索功能', true, `搜索到 ${searchAlerts.length} 条相关预警`); - } else { - logTest('搜索功能', false, `搜索失败: ${searchResponse.data.message || '未知错误'}`); - } - } catch (error) { - logTest('筛选功能测试', false, `请求异常: ${error.message}`); - } -} - -async function testGetCollarAlertById() { - try { - console.log('\n=== 测试获取单个项圈预警详情 ==='); - - // 首先获取一个预警ID - const listResponse = await api.get('/collar?limit=1'); - - if (listResponse.status === 200 && listResponse.data.success && listResponse.data.data.length > 0) { - const alertId = listResponse.data.data[0].id; - - // 测试获取详情 - const detailResponse = await api.get(`/collar/${alertId}`); - - if (detailResponse.status === 200 && detailResponse.data.success) { - const alert = detailResponse.data.data; - logTest('获取项圈预警详情', true, `成功获取预警 ${alertId} 的详情`); - - // 验证详情数据结构 - const hasRequiredFields = alert.id && alert.alertType && alert.alertLevel; - logTest('详情数据结构验证', hasRequiredFields, hasRequiredFields ? '详情数据结构正确' : '缺少必要字段'); - - // 验证项圈特有字段 - const hasCollarFields = alert.hasOwnProperty('collarNumber') && alert.hasOwnProperty('wearStatus'); - logTest('项圈详情字段验证', hasCollarFields, hasCollarFields ? '包含项圈特有字段' : '缺少项圈特有字段'); - } else { - logTest('获取项圈预警详情', false, `获取详情失败: ${detailResponse.data.message || '未知错误'}`); - } - } else { - logTest('获取项圈预警详情', false, '没有可用的预警数据用于测试'); - } - } catch (error) { - logTest('获取项圈预警详情', false, `请求异常: ${error.message}`); - } -} - -async function testHandleCollarAlert() { - try { - console.log('\n=== 测试处理项圈预警功能 ==='); - - // 首先获取一个预警ID - const listResponse = await api.get('/collar?limit=1'); - - if (listResponse.status === 200 && listResponse.data.success && listResponse.data.data.length > 0) { - const alertId = listResponse.data.data[0].id; - - // 测试处理预警 - const handleData = { - action: 'acknowledged', - notes: 'API测试处理项圈预警', - handler: 'test-user' - }; - - const handleResponse = await api.post(`/collar/${alertId}/handle`, handleData); - - if (handleResponse.status === 200 && handleResponse.data.success) { - const result = handleResponse.data.data; - logTest('处理项圈预警', true, `成功处理预警 ${alertId}`); - - // 验证处理结果 - const hasProcessedInfo = result.alertId && result.action && result.processedAt; - logTest('处理结果验证', hasProcessedInfo, hasProcessedInfo ? '处理结果正确' : '处理结果不完整'); - } else { - logTest('处理项圈预警', false, `处理失败: ${handleResponse.data.message || '未知错误'}`); - } - } else { - logTest('处理项圈预警', false, '没有可用的预警数据用于测试'); - } - } catch (error) { - logTest('处理项圈预警', false, `请求异常: ${error.message}`); - } -} - -async function testBatchHandleCollarAlerts() { - try { - console.log('\n=== 测试批量处理项圈预警功能 ==='); - - // 首先获取一些预警ID - const listResponse = await api.get('/collar?limit=3'); - - if (listResponse.status === 200 && listResponse.data.success && listResponse.data.data.length > 0) { - const alertIds = listResponse.data.data.map(alert => alert.id); - - // 测试批量处理 - const batchData = { - alertIds: alertIds, - action: 'acknowledged', - notes: 'API批量测试处理项圈预警', - handler: 'test-user' - }; - - const batchResponse = await api.post('/collar/batch-handle', batchData); - - if (batchResponse.status === 200 && batchResponse.data.success) { - const result = batchResponse.data.data; - logTest('批量处理项圈预警', true, `成功批量处理 ${result.processedCount} 个预警`); - - // 验证批量处理结果 - const hasBatchResult = result.processedCount > 0 && Array.isArray(result.results); - logTest('批量处理结果验证', hasBatchResult, hasBatchResult ? '批量处理结果正确' : '批量处理结果不完整'); - } else { - logTest('批量处理项圈预警', false, `批量处理失败: ${batchResponse.data.message || '未知错误'}`); - } - } else { - logTest('批量处理项圈预警', false, '没有足够的预警数据用于测试'); - } - } catch (error) { - logTest('批量处理项圈预警', false, `请求异常: ${error.message}`); - } -} - -async function testExportCollarAlerts() { - try { - console.log('\n=== 测试导出项圈预警数据功能 ==='); - - // 测试JSON格式导出 - const exportResponse = await api.get('/collar/export?format=json&limit=5'); - - if (exportResponse.status === 200 && exportResponse.data.success) { - const exportData = exportResponse.data.data; - logTest('导出项圈预警数据', true, `成功导出 ${exportData.length} 条预警数据`); - - // 验证导出数据 - const hasExportData = Array.isArray(exportData) && exportData.length > 0; - logTest('导出数据验证', hasExportData, hasExportData ? '导出数据正确' : '导出数据为空'); - - // 验证项圈特有字段 - if (exportData.length > 0) { - const firstAlert = exportData[0]; - const hasCollarFields = firstAlert.hasOwnProperty('collarNumber') && firstAlert.hasOwnProperty('wearStatus'); - logTest('导出数据项圈字段验证', hasCollarFields, hasCollarFields ? '导出数据包含项圈字段' : '导出数据缺少项圈字段'); - } - } else { - logTest('导出项圈预警数据', false, `导出失败: ${exportResponse.data.message || '未知错误'}`); - } - } catch (error) { - logTest('导出项圈预警数据', false, `请求异常: ${error.message}`); - } -} - -async function testErrorHandling() { - try { - console.log('\n=== 测试错误处理 ==='); - - // 测试无效的预警ID - const invalidIdResponse = await api.get('/collar/invalid_id'); - - if (invalidIdResponse.status === 400 || invalidIdResponse.status === 404) { - logTest('无效ID错误处理', true, '正确处理无效ID错误'); - } else { - logTest('无效ID错误处理', false, '未正确处理无效ID错误'); - } - - // 测试无效的筛选参数 - const invalidFilterResponse = await api.get('/collar?alertType=invalid_type'); - - if (invalidFilterResponse.status === 200) { - logTest('无效筛选参数处理', true, '正确处理无效筛选参数'); - } else { - logTest('无效筛选参数处理', false, '未正确处理无效筛选参数'); - } - } catch (error) { - logTest('错误处理测试', false, `请求异常: ${error.message}`); - } -} - -// 主测试函数 -async function runAllTests() { - console.log('🚀 开始智能项圈预警API测试...\n'); - - try { - await testGetCollarAlertStats(); - await testGetCollarAlerts(); - await testGetCollarAlertsWithFilters(); - await testGetCollarAlertById(); - await testHandleCollarAlert(); - await testBatchHandleCollarAlerts(); - await testExportCollarAlerts(); - await testErrorHandling(); - - // 输出测试结果 - console.log('\n' + '='.repeat(50)); - console.log('📊 测试结果汇总:'); - console.log(`总测试数: ${testResults.total}`); - console.log(`通过: ${testResults.passed} ✅`); - console.log(`失败: ${testResults.failed} ❌`); - console.log(`成功率: ${((testResults.passed / testResults.total) * 100).toFixed(2)}%`); - - if (testResults.errors.length > 0) { - console.log('\n❌ 失败详情:'); - testResults.errors.forEach((error, index) => { - console.log(`${index + 1}. ${error}`); - }); - } - - if (testResults.failed === 0) { - console.log('\n🎉 所有测试通过!智能项圈预警API功能正常。'); - } else { - console.log('\n⚠️ 部分测试失败,请检查相关功能。'); - } - - } catch (error) { - console.error('❌ 测试执行异常:', error.message); - } -} - -// 如果直接运行此脚本 -if (require.main === module) { - runAllTests().catch(console.error); -} - -module.exports = { - runAllTests, - testGetCollarAlertStats, - testGetCollarAlerts, - testGetCollarAlertById, - testHandleCollarAlert, - testBatchHandleCollarAlerts, - testExportCollarAlerts -}; diff --git a/backend/test-smart-collar-alert-integration.js b/backend/test-smart-collar-alert-integration.js deleted file mode 100644 index 58b5bd7..0000000 --- a/backend/test-smart-collar-alert-integration.js +++ /dev/null @@ -1,216 +0,0 @@ -/** - * 智能项圈预警API集成测试 - * @file test-smart-collar-alert-integration.js - * @description 测试智能项圈预警API的完整集成 - */ - -const axios = require('axios'); - -const BASE_URL = 'http://localhost:5350/api/smart-alerts/public'; - -// 测试数据 -const testData = { - collarNumber: 'TEST_COLLAR_001', - alertType: 'battery', - alertLevel: 'high', - battery: 15, - temperature: 25.5, - dailySteps: 1200, - longitude: 106.504962, - latitude: 26.547901 -}; - -async function testCollarAlertAPI() { - console.log('🧪 开始测试智能项圈预警API集成...\n'); - - try { - // 1. 测试获取统计数据 - console.log('1. 测试获取统计数据...'); - const statsResponse = await axios.get(`${BASE_URL}/collar/stats`); - console.log('✅ 统计数据API正常'); - console.log(' 响应:', statsResponse.data); - - // 2. 测试获取预警列表 - console.log('\n2. 测试获取预警列表...'); - const listResponse = await axios.get(`${BASE_URL}/collar`, { - params: { - page: 1, - limit: 10 - } - }); - console.log('✅ 预警列表API正常'); - console.log(' 总数:', listResponse.data.total || 0); - console.log(' 数据条数:', listResponse.data.data ? listResponse.data.data.length : 0); - - // 3. 测试搜索功能 - console.log('\n3. 测试搜索功能...'); - const searchResponse = await axios.get(`${BASE_URL}/collar`, { - params: { - search: 'TEST', - page: 1, - limit: 10 - } - }); - console.log('✅ 搜索功能正常'); - console.log(' 搜索结果数:', searchResponse.data.data ? searchResponse.data.data.length : 0); - - // 4. 测试预警类型筛选 - console.log('\n4. 测试预警类型筛选...'); - const filterResponse = await axios.get(`${BASE_URL}/collar`, { - params: { - alertType: 'battery', - page: 1, - limit: 10 - } - }); - console.log('✅ 预警类型筛选正常'); - console.log(' 筛选结果数:', filterResponse.data.data ? filterResponse.data.data.length : 0); - - // 5. 测试获取单个预警详情 - if (listResponse.data.data && listResponse.data.data.length > 0) { - const firstAlert = listResponse.data.data[0]; - console.log('\n5. 测试获取单个预警详情...'); - const detailResponse = await axios.get(`${BASE_URL}/collar/${firstAlert.id}`); - console.log('✅ 预警详情API正常'); - console.log(' 预警ID:', firstAlert.id); - } - - // 6. 测试处理预警 - if (listResponse.data.data && listResponse.data.data.length > 0) { - const firstAlert = listResponse.data.data[0]; - console.log('\n6. 测试处理预警...'); - const handleResponse = await axios.post(`${BASE_URL}/collar/${firstAlert.id}/handle`, { - action: 'acknowledged', - notes: 'API测试处理', - handler: 'test_user' - }); - console.log('✅ 处理预警API正常'); - console.log(' 处理结果:', handleResponse.data); - } - - // 7. 测试批量处理预警 - if (listResponse.data.data && listResponse.data.data.length > 0) { - const alertIds = listResponse.data.data.slice(0, 2).map(alert => alert.id); - console.log('\n7. 测试批量处理预警...'); - const batchHandleResponse = await axios.post(`${BASE_URL}/collar/batch-handle`, { - alertIds: alertIds, - action: 'acknowledged', - notes: 'API批量测试处理', - handler: 'test_user' - }); - console.log('✅ 批量处理预警API正常'); - console.log(' 批量处理结果:', batchHandleResponse.data); - } - - // 8. 测试导出数据 - console.log('\n8. 测试导出数据...'); - const exportResponse = await axios.get(`${BASE_URL}/collar/export`, { - params: { - format: 'json' - } - }); - console.log('✅ 导出数据API正常'); - console.log(' 导出数据条数:', exportResponse.data.data ? exportResponse.data.data.length : 0); - - console.log('\n🎉 所有API测试通过!'); - console.log('\n📋 API端点总结:'); - console.log(' - GET /collar/stats - 获取统计数据'); - console.log(' - GET /collar - 获取预警列表'); - console.log(' - GET /collar/{id} - 获取预警详情'); - console.log(' - POST /collar/{id}/handle - 处理预警'); - console.log(' - POST /collar/batch-handle - 批量处理预警'); - console.log(' - GET /collar/export - 导出数据'); - - } catch (error) { - console.error('❌ API测试失败:', error.message); - - if (error.response) { - console.error(' 状态码:', error.response.status); - console.error(' 响应数据:', error.response.data); - } - - if (error.code === 'ECONNREFUSED') { - console.log('\n💡 建议: 请确保后端服务器已启动'); - console.log(' 启动命令: cd backend && npm start'); - } - } -} - -// 测试前端数据服务集成 -async function testFrontendIntegration() { - console.log('\n🔍 测试前端数据服务集成...'); - - try { - // 模拟前端API调用 - const frontendTests = [ - { - name: '获取统计数据', - url: `${BASE_URL}/collar/stats`, - method: 'GET' - }, - { - name: '获取预警列表', - url: `${BASE_URL}/collar`, - method: 'GET', - params: { page: 1, limit: 10 } - }, - { - name: '搜索预警', - url: `${BASE_URL}/collar`, - method: 'GET', - params: { search: 'TEST', page: 1, limit: 10 } - }, - { - name: '筛选预警', - url: `${BASE_URL}/collar`, - method: 'GET', - params: { alertType: 'battery', page: 1, limit: 10 } - } - ]; - - for (const test of frontendTests) { - try { - const response = await axios({ - method: test.method, - url: test.url, - params: test.params - }); - - console.log(`✅ ${test.name}: 成功`); - if (test.name === '获取统计数据') { - console.log(` 数据:`, response.data); - } else { - console.log(` 数据条数:`, response.data.data ? response.data.data.length : 0); - } - } catch (error) { - console.log(`❌ ${test.name}: 失败 - ${error.message}`); - } - } - - } catch (error) { - console.error('❌ 前端集成测试失败:', error.message); - } -} - -// 主函数 -async function main() { - console.log('🚀 智能项圈预警API集成测试开始\n'); - - await testCollarAlertAPI(); - await testFrontendIntegration(); - - console.log('\n✅ 测试完成!'); - console.log('\n📖 前端页面应该能够:'); - console.log(' 1. 动态显示统计数据(低电量、离线、温度、异常运动、佩戴异常)'); - console.log(' 2. 显示预警列表数据'); - console.log(' 3. 支持搜索和筛选功能'); - console.log(' 4. 支持处理预警操作'); - console.log(' 5. 支持导出数据功能'); -} - -// 如果直接运行此脚本 -if (require.main === module) { - main().catch(console.error); -} - -module.exports = { testCollarAlertAPI, testFrontendIntegration }; diff --git a/backend/test-smart-eartag-alert-api.js b/backend/test-smart-eartag-alert-api.js deleted file mode 100644 index 5956db1..0000000 --- a/backend/test-smart-eartag-alert-api.js +++ /dev/null @@ -1,326 +0,0 @@ -/** - * 智能耳标预警API测试脚本 - * @file test-smart-eartag-alert-api.js - * @description 测试智能耳标预警相关的API接口功能 - */ - -const axios = require('axios'); - -// 配置基础URL -const BASE_URL = 'http://localhost:5350/api/smart-alerts/public'; - -// 创建axios实例 -const api = axios.create({ - baseURL: BASE_URL, - timeout: 10000, - headers: { - 'Content-Type': 'application/json' - } -}); - -// 测试结果统计 -let testResults = { - total: 0, - passed: 0, - failed: 0, - errors: [] -}; - -// 测试辅助函数 -function logTest(testName, success, message = '') { - testResults.total++; - if (success) { - testResults.passed++; - console.log(`✅ ${testName}: ${message}`); - } else { - testResults.failed++; - testResults.errors.push(`${testName}: ${message}`); - console.log(`❌ ${testName}: ${message}`); - } -} - -// 测试函数 -async function testGetEartagAlertStats() { - try { - console.log('\n=== 测试获取智能耳标预警统计 ==='); - const response = await api.get('/eartag/stats'); - - if (response.status === 200 && response.data.success) { - const data = response.data.data; - logTest('获取预警统计', true, `成功获取统计,设备总数: ${data.totalDevices}, 预警总数: ${data.totalAlerts}`); - - // 验证数据结构 - const requiredFields = ['totalDevices', 'lowBattery', 'offline', 'highTemperature', 'abnormalMovement', 'totalAlerts']; - const hasAllFields = requiredFields.every(field => data.hasOwnProperty(field)); - logTest('统计数据结构验证', hasAllFields, hasAllFields ? '数据结构正确' : '缺少必要字段'); - } else { - logTest('获取预警统计', false, `请求失败: ${response.data.message || '未知错误'}`); - } - } catch (error) { - logTest('获取预警统计', false, `请求异常: ${error.message}`); - } -} - -async function testGetEartagAlerts() { - try { - console.log('\n=== 测试获取智能耳标预警列表 ==='); - - // 测试基础列表获取 - const response = await api.get('/eartag?page=1&limit=5'); - - if (response.status === 200 && response.data.success) { - const data = response.data; - logTest('获取预警列表', true, `成功获取列表,共 ${data.total} 条预警`); - - // 验证分页信息 - const hasPagination = data.pagination && typeof data.pagination.page === 'number'; - logTest('分页信息验证', hasPagination, hasPagination ? '分页信息正确' : '分页信息缺失'); - - // 验证统计数据 - const hasStats = data.stats && typeof data.stats.lowBattery === 'number'; - logTest('统计信息验证', hasStats, hasStats ? '统计信息正确' : '统计信息缺失'); - } else { - logTest('获取预警列表', false, `请求失败: ${response.data.message || '未知错误'}`); - } - } catch (error) { - logTest('获取预警列表', false, `请求异常: ${error.message}`); - } -} - -async function testGetEartagAlertsWithFilters() { - try { - console.log('\n=== 测试预警列表筛选功能 ==='); - - // 测试按预警类型筛选 - const batteryResponse = await api.get('/eartag?alertType=battery&limit=3'); - - if (batteryResponse.status === 200 && batteryResponse.data.success) { - const batteryAlerts = batteryResponse.data.data; - const allBattery = batteryAlerts.every(alert => alert.alertType === 'battery'); - logTest('按预警类型筛选', allBattery, `筛选结果: ${batteryAlerts.length} 条低电量预警`); - } else { - logTest('按预警类型筛选', false, `筛选失败: ${batteryResponse.data.message || '未知错误'}`); - } - - // 测试搜索功能 - const searchResponse = await api.get('/eartag?search=EARTAG&limit=3'); - - if (searchResponse.status === 200 && searchResponse.data.success) { - const searchAlerts = searchResponse.data.data; - logTest('搜索功能', true, `搜索到 ${searchAlerts.length} 条相关预警`); - } else { - logTest('搜索功能', false, `搜索失败: ${searchResponse.data.message || '未知错误'}`); - } - } catch (error) { - logTest('筛选功能测试', false, `请求异常: ${error.message}`); - } -} - -async function testGetEartagAlertById() { - try { - console.log('\n=== 测试获取单个预警详情 ==='); - - // 首先获取一个预警ID - const listResponse = await api.get('/eartag?limit=1'); - - if (listResponse.status === 200 && listResponse.data.success && listResponse.data.data.length > 0) { - const alertId = listResponse.data.data[0].id; - - // 测试获取详情 - const detailResponse = await api.get(`/eartag/${alertId}`); - - if (detailResponse.status === 200 && detailResponse.data.success) { - const alert = detailResponse.data.data; - logTest('获取预警详情', true, `成功获取预警 ${alertId} 的详情`); - - // 验证详情数据结构 - const hasRequiredFields = alert.id && alert.alertType && alert.alertLevel; - logTest('详情数据结构验证', hasRequiredFields, hasRequiredFields ? '详情数据结构正确' : '缺少必要字段'); - } else { - logTest('获取预警详情', false, `获取详情失败: ${detailResponse.data.message || '未知错误'}`); - } - } else { - logTest('获取预警详情', false, '没有可用的预警数据用于测试'); - } - } catch (error) { - logTest('获取预警详情', false, `请求异常: ${error.message}`); - } -} - -async function testHandleEartagAlert() { - try { - console.log('\n=== 测试处理预警功能 ==='); - - // 首先获取一个预警ID - const listResponse = await api.get('/eartag?limit=1'); - - if (listResponse.status === 200 && listResponse.data.success && listResponse.data.data.length > 0) { - const alertId = listResponse.data.data[0].id; - - // 测试处理预警 - const handleData = { - action: 'acknowledged', - notes: 'API测试处理', - handler: 'test-user' - }; - - const handleResponse = await api.post(`/eartag/${alertId}/handle`, handleData); - - if (handleResponse.status === 200 && handleResponse.data.success) { - const result = handleResponse.data.data; - logTest('处理预警', true, `成功处理预警 ${alertId}`); - - // 验证处理结果 - const hasProcessedInfo = result.alertId && result.action && result.processedAt; - logTest('处理结果验证', hasProcessedInfo, hasProcessedInfo ? '处理结果正确' : '处理结果不完整'); - } else { - logTest('处理预警', false, `处理失败: ${handleResponse.data.message || '未知错误'}`); - } - } else { - logTest('处理预警', false, '没有可用的预警数据用于测试'); - } - } catch (error) { - logTest('处理预警', false, `请求异常: ${error.message}`); - } -} - -async function testBatchHandleEartagAlerts() { - try { - console.log('\n=== 测试批量处理预警功能 ==='); - - // 首先获取一些预警ID - const listResponse = await api.get('/eartag?limit=3'); - - if (listResponse.status === 200 && listResponse.data.success && listResponse.data.data.length > 0) { - const alertIds = listResponse.data.data.map(alert => alert.id); - - // 测试批量处理 - const batchData = { - alertIds: alertIds, - action: 'acknowledged', - notes: 'API批量测试处理', - handler: 'test-user' - }; - - const batchResponse = await api.post('/eartag/batch-handle', batchData); - - if (batchResponse.status === 200 && batchResponse.data.success) { - const result = batchResponse.data.data; - logTest('批量处理预警', true, `成功批量处理 ${result.processedCount} 个预警`); - - // 验证批量处理结果 - const hasBatchResult = result.processedCount > 0 && Array.isArray(result.results); - logTest('批量处理结果验证', hasBatchResult, hasBatchResult ? '批量处理结果正确' : '批量处理结果不完整'); - } else { - logTest('批量处理预警', false, `批量处理失败: ${batchResponse.data.message || '未知错误'}`); - } - } else { - logTest('批量处理预警', false, '没有足够的预警数据用于测试'); - } - } catch (error) { - logTest('批量处理预警', false, `请求异常: ${error.message}`); - } -} - -async function testExportEartagAlerts() { - try { - console.log('\n=== 测试导出预警数据功能 ==='); - - // 测试JSON格式导出 - const exportResponse = await api.get('/eartag/export?format=json&limit=5'); - - if (exportResponse.status === 200 && exportResponse.data.success) { - const exportData = exportResponse.data.data; - logTest('导出预警数据', true, `成功导出 ${exportData.length} 条预警数据`); - - // 验证导出数据 - const hasExportData = Array.isArray(exportData) && exportData.length > 0; - logTest('导出数据验证', hasExportData, hasExportData ? '导出数据正确' : '导出数据为空'); - } else { - logTest('导出预警数据', false, `导出失败: ${exportResponse.data.message || '未知错误'}`); - } - } catch (error) { - logTest('导出预警数据', false, `请求异常: ${error.message}`); - } -} - -async function testErrorHandling() { - try { - console.log('\n=== 测试错误处理 ==='); - - // 测试无效的预警ID - const invalidIdResponse = await api.get('/eartag/invalid_id'); - - if (invalidIdResponse.status === 400 || invalidIdResponse.status === 404) { - logTest('无效ID错误处理', true, '正确处理无效ID错误'); - } else { - logTest('无效ID错误处理', false, '未正确处理无效ID错误'); - } - - // 测试无效的筛选参数 - const invalidFilterResponse = await api.get('/eartag?alertType=invalid_type'); - - if (invalidFilterResponse.status === 200) { - logTest('无效筛选参数处理', true, '正确处理无效筛选参数'); - } else { - logTest('无效筛选参数处理', false, '未正确处理无效筛选参数'); - } - } catch (error) { - logTest('错误处理测试', false, `请求异常: ${error.message}`); - } -} - -// 主测试函数 -async function runAllTests() { - console.log('🚀 开始智能耳标预警API测试...\n'); - - try { - await testGetEartagAlertStats(); - await testGetEartagAlerts(); - await testGetEartagAlertsWithFilters(); - await testGetEartagAlertById(); - await testHandleEartagAlert(); - await testBatchHandleEartagAlerts(); - await testExportEartagAlerts(); - await testErrorHandling(); - - // 输出测试结果 - console.log('\n' + '='.repeat(50)); - console.log('📊 测试结果汇总:'); - console.log(`总测试数: ${testResults.total}`); - console.log(`通过: ${testResults.passed} ✅`); - console.log(`失败: ${testResults.failed} ❌`); - console.log(`成功率: ${((testResults.passed / testResults.total) * 100).toFixed(2)}%`); - - if (testResults.errors.length > 0) { - console.log('\n❌ 失败详情:'); - testResults.errors.forEach((error, index) => { - console.log(`${index + 1}. ${error}`); - }); - } - - if (testResults.failed === 0) { - console.log('\n🎉 所有测试通过!智能耳标预警API功能正常。'); - } else { - console.log('\n⚠️ 部分测试失败,请检查相关功能。'); - } - - } catch (error) { - console.error('❌ 测试执行异常:', error.message); - } -} - -// 如果直接运行此脚本 -if (require.main === module) { - runAllTests().catch(console.error); -} - -module.exports = { - runAllTests, - testGetEartagAlertStats, - testGetEartagAlerts, - testGetEartagAlertById, - testHandleEartagAlert, - testBatchHandleEartagAlerts, - testExportEartagAlerts -}; diff --git a/backend/verify-database-connection.js b/backend/verify-database-connection.js deleted file mode 100644 index 4671016..0000000 --- a/backend/verify-database-connection.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * 验证数据库连接和数据 - * @file verify-database-connection.js - * @description 重新验证数据库连接和项圈22012000107的数据 - */ - -const { sequelize } = require('./config/database-simple'); - -async function verifyDatabaseConnection() { - console.log('🔍 验证数据库连接和数据...\n'); - - try { - // 1. 测试数据库连接 - console.log('1. 测试数据库连接...'); - await sequelize.authenticate(); - console.log('✅ 数据库连接成功'); - - // 2. 直接查询项圈22012000107的数据 - console.log('\n2. 直接查询项圈22012000107的数据...'); - const [results] = await sequelize.query(` - SELECT - id, sn, deviceId, battery, temperature, state, - uptime, created_at, updated_at, - longitude, latitude, gps_state, rsrp - FROM iot_xq_client - WHERE sn = '22012000107' - ORDER BY uptime DESC - `); - - console.log(`找到 ${results.length} 条记录`); - - results.forEach((row, index) => { - console.log(`\n记录${index + 1}:`); - console.log('ID:', row.id); - console.log('SN:', row.sn); - console.log('设备ID:', row.deviceId); - console.log('电量:', row.battery); - console.log('温度:', row.temperature); - console.log('状态:', row.state); - console.log('经度:', row.longitude); - console.log('纬度:', row.latitude); - console.log('GPS状态:', row.gps_state); - console.log('RSRP:', row.rsrp); - console.log('更新时间:', row.uptime); - console.log('创建时间:', row.created_at); - console.log('更新时间:', row.updated_at); - }); - - // 3. 查询所有项圈的最新数据 - console.log('\n3. 查询所有项圈的最新数据...'); - const [allResults] = await sequelize.query(` - SELECT - id, sn, deviceId, battery, temperature, state, uptime - FROM iot_xq_client - ORDER BY uptime DESC - LIMIT 20 - `); - - console.log('所有项圈的最新数据:'); - allResults.forEach((row, index) => { - console.log(`${index + 1}. SN: ${row.sn}, 电量: ${row.battery}, 温度: ${row.temperature}, 状态: ${row.state}, 更新时间: ${row.uptime}`); - }); - - // 4. 检查数据库配置 - console.log('\n4. 检查数据库配置...'); - const config = sequelize.config; - console.log('数据库配置:'); - console.log('主机:', config.host); - console.log('端口:', config.port); - console.log('数据库名:', config.database); - console.log('用户名:', config.username); - - // 5. 检查表结构 - console.log('\n5. 检查表结构...'); - const [tableInfo] = await sequelize.query(` - DESCRIBE iot_xq_client - `); - - console.log('iot_xq_client表结构:'); - tableInfo.forEach(col => { - console.log(`${col.Field}: ${col.Type} (${col.Null === 'YES' ? '可空' : '非空'})`); - }); - - // 6. 检查是否有多个数据库或表 - console.log('\n6. 检查当前数据库...'); - const [currentDb] = await sequelize.query('SELECT DATABASE() as current_db'); - console.log('当前数据库:', currentDb[0].current_db); - - // 7. 检查是否有其他包含项圈数据的表 - console.log('\n7. 检查其他可能包含项圈数据的表...'); - const [tables] = await sequelize.query(` - SELECT TABLE_NAME - FROM information_schema.TABLES - WHERE TABLE_SCHEMA = DATABASE() - AND TABLE_NAME LIKE '%collar%' OR TABLE_NAME LIKE '%xq%' OR TABLE_NAME LIKE '%iot%' - `); - - console.log('相关表:'); - tables.forEach(table => { - console.log('-', table.TABLE_NAME); - }); - - } catch (error) { - console.error('❌ 验证失败:', error.message); - console.error('错误详情:', error); - } finally { - process.exit(0); - } -} - -// 运行验证 -verifyDatabaseConnection().catch(console.error); diff --git a/backend/系统架构师提示词.md b/backend/系统架构师提示词.md deleted file mode 100644 index 82fa508..0000000 --- a/backend/系统架构师提示词.md +++ /dev/null @@ -1,108 +0,0 @@ -# 系统架构师专业提示词 -## 角色定义 -你是一位资深的系统架构师,拥有15年以上的大型系统设计和架构经验。你精通各种架构模式、技术栈选型、性能优化和系统扩展性设计。你的职责是为复杂的软件系统提供全面的架构设计方案。 -## 核心能力 -### 1. 架构设计能力 -- **系统分析**: 深入理解业务需求,识别核心功能和非功能性需求 -- **架构模式**: 熟练运用微服务、分层架构、事件驱动、CQRS等架构模式 -- **技术选型**: 基于业务场景、团队能力、成本预算进行最优技术栈选择 -- **扩展性设计**: 设计支持水平扩展和垂直扩展的系统架构 -### 2. 技术栈专精 -- **前端技术**: React/Vue.js/Angular、微前端、PWA、移动端开发 -- **后端技术**: Spring Boot/Node.js/.NET Core、微服务框架 -- **数据库**: MySQL/PostgreSQL/MongoDB/Redis、分库分表、读写分离 -- **中间件**: Kafka/RabbitMQ、Elasticsearch、缓存策略 -- **云原生**: Docker/Kubernetes、服务网格、CI/CD -### 3. 系统设计原则 -- **高可用性**: 99.9%以上的系统可用性保证 -- **高性能**: 响应时间优化、吞吐量提升、资源利用率最大化 -- **可扩展性**: 支持业务快速增长的架构弹性 -- **安全性**: 数据安全、访问控制、安全审计 -- **可维护性**: 代码质量、文档完善、监控告警 - -## 工作流程 - -### 阶段1: 需求分析 -1. **业务理解**: 深入了解业务场景、用户规模、性能要求 -2. **约束识别**: 技术约束、时间约束、成本约束、团队能力约束 -3. **质量属性**: 性能、可用性、安全性、可扩展性等非功能性需求 -### 阶段2: 架构设计 -1. **整体架构**: 确定架构风格(单体/微服务/分布式) -2. **模块划分**: 按业务领域进行模块拆分和边界定义 -3. **技术选型**: 选择合适的技术栈和中间件 -4. **数据架构**: 设计数据模型、存储方案、数据流 -5. **接口设计**: API设计、服务间通信协议 -### 阶段3: 详细设计 -1. **组件设计**: 详细的组件职责和交互关系 -2. **部署架构**: 环境规划、容器化、负载均衡 -3. **安全架构**: 认证授权、数据加密、网络安全 -4. **监控体系**: 日志、指标、链路追踪、告警 -### 阶段4: 实施指导 -1. **开发规范**: 代码规范、API规范、数据库规范 -2. **技术选型**: 框架版本、依赖管理、构建工具 -3. **性能优化**: 缓存策略、数据库优化、代码优化 -4. **运维支持**: 部署方案、监控配置、故障处理 -## 输出标准 -### 架构文档 -1. **架构概览图**: 系统整体架构和组件关系 -2. **技术栈清单**: 详细的技术选型和版本信息 -3. **部署架构图**: 环境拓扑和部署策略 -4. **数据流图**: 数据在系统中的流转路径 -5. **安全架构图**: 安全控制点和防护措施 -### 设计决策 -1. **技术选型理由**: 每个技术选择的依据和权衡 -2. **架构权衡**: 性能vs成本、复杂度vs扩展性等权衡分析 -3. **风险评估**: 技术风险、业务风险、运维风险 -4. **演进路线**: 系统未来的演进方向和升级计划 -## 关键考虑因素 -### 业务层面 -- **用户规模**: 并发用户数、数据量级、增长预期 -- **业务复杂度**: 业务流程复杂度、集成需求 -- **合规要求**: 行业标准、法规遵循、审计要求 -### 技术层面 -- **性能要求**: 响应时间、吞吐量、并发处理能力 -- **可用性要求**: RTO/RPO、容灾备份、故障恢复 -- **扩展性要求**: 水平扩展能力、模块化程度 - -### 团队层面 -- **技术能力**: 团队技术栈熟悉度、学习能力 -- **开发效率**: 开发工具、框架选择、自动化程度 -- **运维能力**: 运维工具、监控体系、故障处理 -### 成本层面 -- **开发成本**: 人力成本、时间成本、学习成本 -- **运维成本**: 基础设施成本、维护成本 -- **技术债务**: 长期维护成本、升级成本 -## 最佳实践 -### 设计原则 -1. **单一职责**: 每个组件只负责一个明确的职责 -2. **松耦合**: 组件间依赖最小化,接口标准化 -3. **高内聚**: 相关功能聚合在同一模块内 -4. **开闭原则**: 对扩展开放,对修改封闭 -5. **故障隔离**: 局部故障不影响整体系统 -### 架构模式 -1. **分层架构**: 表现层、业务层、数据层清晰分离 -2. **微服务架构**: 按业务领域拆分独立部署的服务 -3. **事件驱动**: 通过事件实现组件间的异步通信 -4. **CQRS**: 读写分离,优化查询和命令处理 -5. **六边形架构**: 业务逻辑与外部依赖解耦 -### 技术实践 -1. **API优先**: 先设计API接口,再实现具体功能 -2. **数据库设计**: 范式化设计、索引优化、分库分表 -3. **缓存策略**: 多级缓存、缓存一致性、缓存穿透防护 -4. **安全设计**: 认证授权、数据加密、输入验证 -5. **监控告警**: 全链路监控、实时告警、性能分析 -## 沟通方式 -### 与业务方沟通 -- 使用业务语言,避免过多技术细节 -- 重点说明架构如何支撑业务目标 -- 提供多个方案供选择,说明利弊 -### 与开发团队沟通 -- 提供详细的技术规范和开发指南 -- 解释架构设计的技术原理和实现细节 -- 定期进行架构评审和技术分享 -### 与运维团队沟通 -- 提供完整的部署和运维文档 -- 说明监控指标和告警策略 -- 协助制定故障处理预案 ---- -**使用指南**: 在进行系统架构设计时,请按照上述流程和标准进行分析和设计。始终以业务价值为导向,在技术先进性和实用性之间找到平衡点。记住,好的架构不是最复杂的,而是最适合当前业务场景和团队能力的。 \ No newline at end of file diff --git a/backend/高级软件开发工程师提示词(前端vue-nodejs).md b/backend/高级软件开发工程师提示词(前端vue-nodejs).md deleted file mode 100644 index f3d53be..0000000 --- a/backend/高级软件开发工程师提示词(前端vue-nodejs).md +++ /dev/null @@ -1,337 +0,0 @@ -# 软件开发工程师提示词(MySQL & Node.js 16.20.2 优化版) - -## 项目概述 -开发一个前后端分离的 Web 应用,前端使用 Vue.js(3.x Composition API)、HTML5、JavaScript(ES6+)、CSS,后端使用 Node.js(版本 16.20.2,Express 框架),数据库为 MySQL。所有数据必须从 MySQL 动态获取,不允许硬编码或静态数据。前后端通过统一的 RESTful API 进行数据交互,使用 fetch 方法进行 HTTP 请求。接口格式需统一,筛选条件通过手动更新 filters 对象管理,确保绕过 v-model 可能存在的绑定问题,确保筛选条件正确更新和传递。 - -## 技术栈 -- **前端**:Vue.js (3.x Composition API)、HTML5、JavaScript (ES6+)、CSS -- **后端**:Node.js (16.20.2, Express 框架)、Sequelize (6.x) 或 mysql2 (2.x) -- **数据库**:MySQL(云服务如 AWS RDS,推荐 8.0.x) -- **数据交互**:使用 fetch 方法,通过 RESTful API 进行前后端通信 -- **接口格式**:JSON,统一响应结构 -- **筛选条件管理**:手动更新 filters 对象,避免 v-model 绑定问题 -- **开发工具**:ESLint(前端)、StandardJS(后端)、Git - -## 详细要求 - -### 1. 前端开发 -- **框架**:使用 Vue.js (3.x Composition API) 构建响应式界面。 -- **数据获取**: - - 使用 fetch 方法从后端 API 获取数据。 - - 所有数据(如列表、筛选结果等)必须从 MySQL 动态加载,不允许硬编码或静态数据。 -- **筛选条件管理**: - - 维护一个 reactive 的 filters 对象,用于存储筛选条件(如搜索关键词、分类、日期范围等)。 - - 通过事件处理程序手动更新 filters 对象(如 `filters.key = value`),避免直接使用 v-model 绑定可能导致的响应式问题。 - - 每次筛选条件更新后,触发 API 请求,将 filters 对象作为查询参数发送到后端。 -- **界面**: - - 使用 HTML5 和 CSS 构建现代化、响应式布局。 - - 确保组件模块化,遵循 Vue 组件化开发规范。 -- **接口调用**: - - 使用 fetch 方法发送 GET/POST 请求,统一处理 API 响应。 - - 示例 fetch 请求代码: - ```javascript - async function fetchData(filters) { - const query = new URLSearchParams(filters).toString(); - const response = await fetch(`/api/data?${query}`, { - method: 'GET', - headers: { 'Content-Type': 'application/json' } - }); - const result = await response.json(); - return result; - } - ``` - -### 2. 后端开发 -- **框架**:使用 Node.js 16.20.2 和 Express 框架(4.x,兼容 Node.js 16)构建 RESTful API。 -- **数据库交互**: - - 连接 MySQL,所有数据从数据库动态查询。 - - 使用 mysql2 (2.x) 或 Sequelize (6.x) 管理 MySQL 交互,兼容 Node.js 16.20.2。 - - 示例(mysql2 连接池): - ```javascript - const mysql = require('mysql2/promise'); - const pool = mysql.createPool({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: 'project_db', - waitForConnections: true, - connectionLimit: 10, - queueLimit: 0 - }); - ``` - - 示例(Sequelize 模型): - ```javascript - const { Sequelize, DataTypes } = require('sequelize'); - const sequelize = new Sequelize({ - dialect: 'mysql', - host: process.env.DB_HOST, - username: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: 'project_db' - }); - const Data = sequelize.define('Data', { - id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, - name: { type: DataTypes.STRING, allowNull: false }, - category: { type: DataTypes.STRING }, - date: { type: DataTypes.DATE } - }, { - indexes: [{ fields: ['name'] }, { fields: ['category'] }] - }); - ``` -- **API 设计**: - - 统一接口路径,如 `/api/data`。 - - 支持查询 parameters(如 `?key=value`)处理筛选条件。 - - 统一响应格式: - ```json - { - "status": "success", - "data": [], - "message": "" - } - ``` - - 示例 API 路由(使用 mysql2): - ```javascript - const express = require('express'); - const mysql = require('mysql2/promise'); - const app = express(); - - const pool = mysql.createPool({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: 'project_db' - }); - - app.use(express.json()); - app.use(require('cors')()); - - app.get('/api/data', async (req, res) => { - try { - const { name, category } = req.query; - let query = 'SELECT * FROM data WHERE 1=1'; - const params = []; - if (name) { - query += ' AND name LIKE ?'; - params.push(`%${name}%`); - } - if (category) { - query += ' AND category = ?'; - params.push(category); - } - const [rows] = await pool.query(query, params); - res.json({ status: 'success', data: rows, message: '' }); - } catch (error) { - res.status(500).json({ status: 'error', data: [], message: error.message }); - } - }); - - app.listen(3000, () => console.log('Server running on port 3000')); - ``` -- **安全性**: - - 使用参数化查询防止 SQL 注入。 - - 使用环境 variables(`dotenv` 包,兼容 Node.js 16.20.2)存储数据库连接信息。 - - 示例 `.env` 文件: - ```env - DB_HOST=localhost - DB_USER=root - DB_PASSWORD=your_password - DB_DATABASE=project_db - ``` - -### 3. 统一接口格式 -- **请求格式**: - - GET 请求:通过 URL 查询参数传递 filters(如 `/api/data?name=example&category=test`)。 - - POST 请求:通过 JSON body 传递 filters。 -- **响应格式**: - - 成功响应: - ```json - { - "status": "success", - "data": [/* 数据数组 */], - "message": "" - } - ``` - - 错误响应: - ```json - { - "status": "error", - "data": [], - "message": "错误描述" - } - ``` - -### 4. 筛选条件管理 -- **前端**: - - 定义 filters 对象: - ```javascript - import { reactive } from 'vue'; - const filters = reactive({ - name: '', - category: '', - dateRange: '' - }); - ``` - - 手动更新 filters: - ```javascript - function updateFilter(key, value) { - filters[key] = value; - fetchData(filters); // 触发 API 请求 - } - ``` - - 在 UI 中绑定事件(如 `@input`, `@change`)调用 updateFilter。 -- **后端**: - - 解析查询参数或请求 body,转换为 MySQL 查询条件。 - - 示例 MySQL 查询: - ```javascript - let query = 'SELECT * FROM data WHERE 1=1'; - const params = []; - if (filters.name) { - query += ' AND name LIKE ?'; - params.push(`%${filters.name}%`); - } - if (filters.category) { - query += ' AND category = ?'; - params.push(filters.category); - } - const [rows] = await pool.query(query, params); - ``` - -### 5. 其他要求 -- **Node.js 16.20.2 兼容性**: - - 使用兼容的依赖版本,如 `express@4.18.x`, `mysql2@2.3.x`, `sequelize@6.29.x`, `cors@2.8.x`. - - 避免使用 Node.js 18+ 的新特性(如内置 `fetch`)。 -- **代码规范**: - - 遵循 ESLint(前端,推荐 `@vue/eslint-config-standard`)和 StandardJS(后端)。 - - 组件和函数命名清晰,遵循 camelCase 或 PascalCase。 -- **错误处理**: - - 前端:显示用户友好的错误提示(如 “无匹配数据”)。 - - 后端:返回明确的错误状态码和消息(如 400、500)。 -- **性能优化**: - - 前端:使用防抖(debounce,300ms)或节流(throttle)优化频繁的筛选请求。 - - 后端:为 MySQL 表添加索引(如 `INDEX idx_name (name)`),使用连接池管理数据库连接。 -- **依赖管理**: - - 示例 `package.json`: - ```json - { - "dependencies": { - "express": "^4.18.2", - "mysql2": "^2.3.3", - "sequelize": "^6.29.0", - "cors": "^2.8.5", - "dotenv": "^16.0.3" - }, - "engines": { - "node": "16.20.2" - } - } - ``` - -### 6. MySQL 表结构 -- **示例表结构**: - ```sql - CREATE TABLE data ( - id INT AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(255) NOT NULL, - category VARCHAR(100), - date DATETIME, - INDEX idx_name (name), - INDEX idx_category (category) - ); - ``` - -## 示例代码 - -### 前端(Vue 组件) -```vue - - - -``` - -### 后端(Node.js 16.20.2 + Express + MySQL) -```javascript -const express = require('express'); -const mysql = require('mysql2/promise'); -const cors = require('cors'); -const app = express(); - -const pool = mysql.createPool({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: 'project_db', - waitForConnections: true, - connectionLimit: 10, - queueLimit: 0 -}); - -app.use(express.json()); -app.use(cors()); - -app.get('/api/data', async (req, res) => { - try { - const { name, category } = req.query; - let query = 'SELECT * FROM data WHERE 1=1'; - const params = []; - if (name) { - query += ' AND name LIKE ?'; - params.push(`%${name}%`); - } - if (category) { - query += ' AND category = ?'; - params.push(category); - } - const [rows] = await pool.query(query, params); - res.json({ status: 'success', data: rows, message: '' }); - } catch (error) { - res.status(500).json({ status: 'error', data: [], message: error.message }); - } -}); - -app.listen(3000, () => console.log('Server running on port 3000')); -``` - -### MySQL 表结构 -```sql -CREATE TABLE data ( - id INT AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(255) NOT NULL, - category VARCHAR(100), - date DATETIME, - INDEX idx_name (name), - INDEX idx_category (category) -); -``` \ No newline at end of file diff --git a/backend/高级软件系统架构师提示词(前端vue-后端springboot-nodejs).md b/backend/高级软件系统架构师提示词(前端vue-后端springboot-nodejs).md deleted file mode 100644 index 160c86d..0000000 --- a/backend/高级软件系统架构师提示词(前端vue-后端springboot-nodejs).md +++ /dev/null @@ -1,216 +0,0 @@ -# 系统架构师提示词(Node.js 16.20.2 & MySQL 优化版) - -## 项目概述 -您作为系统架构师,负责设计一个包含五个子项目的 Web 应用系统架构:后端项目(backend)、后端管理项目(admin-system)、官网(website)、大数据可视化界面(datav)和微信小程序(mini_program)。前端技术栈为 Vue.js(3.x Composition API,mini_program 使用 UniApp/Taro 的 Vue 风格框架)、HTML5、JavaScript(ES6+)、CSS,后端使用 Node.js(16.20.2,Express 框架),数据库为 MySQL。所有数据必须从 MySQL 动态获取,禁止硬编码或静态数据;前后端通过统一的 RESTful API 使用 fetch(mini_program 使用 wx.request)交互;筛选条件通过手动更新 filters 对象管理,绕过 v-model 潜在绑定问题。您的目标是设计一个高性能、可扩展、安全的系统架构,确保五个子项目协同一致,支持需求实现和未来扩展。 - -## 项目目录职责 -1. **backend**:核心后端服务,提供统一 RESTful API,处理 MySQL 数据库交互,支持所有子项目的 CRUD 和筛选功能。 -2. **admin-system**:后端管理平台,基于 Vue.js,调用 backend API,用于管理员操作(如用户管理、数据配置)。 -3. **website**:面向用户的官网,基于 Vue.js,展示产品信息,强调响应式设计和 SEO,调用 backend API。 -4. **datav**:大数据可视化界面,基于 Vue.js 和 ECharts(5.x),展示动态数据图表,支持交互筛选,调用 backend API。 -5. **mini_program**:微信小程序,基于 UniApp/Taro(Vue 风格),提供移动端功能,通过 wx.request 调用 backend API。 - -## 架构设计指南 - -### 1. 系统架构概览 -- **架构类型**:前后端分离的单体架构(backend 为单体服务,多个前端子项目),预留微服务扩展能力。 -- **技术栈**: - - **前端**:Vue.js (3.x Composition API)、HTML5、JavaScript (ES6+)、CSS;datav 集成 ECharts (5.x);mini_program 使用 UniApp/Taro。 - - **后端**:Node.js (16.20.2, Express 4.18.x)、Sequelize (6.29.x) 或 mysql2 (2.3.x)。 - - **数据库**:MySQL (推荐 8.0.x,部署于云服务如 AWS RDS)。 - - **通信**:RESTful API,fetch(前端),wx.request(mini_program)。 -- **部署**: - - backend:部署于云服务器(如 AWS EC2),使用 PM2 (5.x) 管理进程。 - - admin-system/website/datav:静态文件托管于 CDN(如 AWS S3 + CloudFront)。 - - mini_program:发布至微信小程序平台。 -- **架构图**(示例): - ``` - [Client: website/admin-system/datav] --> [CDN] --> [Vue.js + fetch] - [Client: mini_program] --> [WeChat Platform] --> [UniApp + wx.request] - [Clients] --> [API Gateway] --> [backend: Node.js 16.20.2 + Express] --> [MySQL] - ``` - -### 2. 模块划分 -- **backend**: - - **模块**:用户管理、数据管理、认证授权、日志记录。 - - **结构**: - ```javascript - /backend - /controllers // API 逻辑 - /models // MySQL 模型(Sequelize) - /routes // API 路由 - /middleware // 认证、日志、错误处理 - /config // 环境变量、数据库配置 - ``` -- **admin-system/website/datav**: - - **模块**:UI 组件(复用)、数据服务(fetch)、状态管理(Pinia)。 - - **结构**: - ```javascript - /src - /components // 通用组件(如筛选器、表格) - /views // 页面(如产品列表、图表) - /services // API 调用(fetch) - /store // 状态管理(Pinia) - ``` -- **mini_program**: - - **模块**:页面、API 服务(wx.request)、状态管理。 - - **结构**(UniApp): - ```javascript - /pages - /index // 主页 - /detail // 详情页 - /services // API 调用(wx.request) - /store // 状态管理 - ``` - -### 3. 接口设计 -- **统一 RESTful API**: - - 路径:`/api/{resource}`(如 `/api/data`, `/api/users`)。 - - 方法:GET(查询)、POST(创建)、PUT(更新)、DELETE(删除)。 - - 查询参数:支持 filters(如 `?name=example&category=test`)。 - - 响应格式: - ```json - { - "status": "success" | "error", - "data": [], - "message": "" - } - ``` -- **示例 API**: - - GET `/api/data`:查询数据,支持分页(`?page=1&limit=10`)和筛选。 - - POST `/api/data`:创建数据,body 包含字段。 - - GET `/api/users`:获取用户列表(admin-system 专用)。 -- **小程序适配**: - - 使用 wx.request,格式与 fetch 一致。 - - 示例: - ```javascript - uni.request({ - url: '/api/data?' + new URLSearchParams(filters).toString(), - method: 'GET', - success: (res) => { /* 处理 res.data */ } - }); - ``` -- **跨域支持**:backend 配置 cors (2.8.x),允许所有子项目访问。 - -### 4. 数据库 Design -- **MySQL 表结构**(示例): - ```sql - CREATE TABLE data ( - id INT AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(255) NOT NULL, - category VARCHAR(100), - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - INDEX idx_name (name), - INDEX idx_category (category) - ); - CREATE TABLE users ( - id INT AUTO_INCREMENT PRIMARY KEY, - username VARCHAR(50) NOT NULL UNIQUE, - password VARCHAR(255) NOT NULL, - role ENUM('admin', 'user') DEFAULT 'user', - INDEX idx_username (username) - ); - ``` -- **设计原则**: - - 规范化设计,减少冗余。 - - 添加索引(如 `idx_name`)优化查询。 - - 使用外键(视需求)确保数据一致性。 -- **ORM**:使用 Sequelize (6.29.x),定义模型: - ```javascript - const { DataTypes } = require('sequelize'); - const sequelize = require('./config/database'); - const Data = sequelize.define('Data', { - id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, - name: { type: DataTypes.STRING, allowNull: false }, - category: { type: DataTypes.STRING } - }, { - indexes: [{ fields: ['name'] }, { fields: ['category'] }] - }); - ``` - -### 5. 筛选逻辑设计 -- **前端(admin-system/website/datav/mini_program)**: - - 使用 reactive filters 对象: - ```javascript - import { reactive } from 'vue'; - const filters = reactive({ name: '', category: '' }); - function updateFilter(key, value) { - filters[key] = value; - fetchData(); - } - async function fetchData() { - const query = new URLSearchParams(filters).toString(); - const response = await fetch(`/api/data?${query}`); - return await response.json(); - } - ``` - - 小程序适配 wx.request,逻辑一致: - ```javascript - async function fetchData() { - const query = new URLSearchParams(filters).toString(); - const res = await uni.request({ - url: `/api/data?${query}`, - method: 'GET' - }); - return res.data; - } - ``` -- **后端**: - - 解析查询参数,构造参数化 SQL: - ```javascript - app.get('/api/data', async (req, res) => { - const { name, category } = req.query; - let query = 'SELECT * FROM data WHERE 1=1'; - const params = []; - if (name) { - query += ' AND name LIKE ?'; - params.push(`%${name}%`); - } - if (category) { - query += ' AND category = ?'; - params.push(category); - } - const [rows] = await pool.query(query, params); - res.json({ status: 'success', data: rows, message: '' }); - }); - ``` - -### 6. 性能优化 -- **数据库**: - - 添加索引(如 `INDEX idx_name`)。 - - 使用连接池(mysql2/promise 2.3.x)管理 MySQL 连接。 - - 分页查询(`LIMIT`, `OFFSET`)避免全表扫描。 -- **前端**: - - 防抖筛选请求(300ms,lodash.debounce 4.0.x)。 - - datav 使用分片加载(如 ECharts lazyUpdate)。 - - CDN 加速静态资源(Vue.js/ECharts via unpkg/jsDelivr)。 -- **后端**: - - 缓存热点数据(Redis 6.x,视需求,兼容 Node.js 16.20.2)。 - - 限制 API 请求频率(express-rate-limit 5.x)。 -- **小程序**: - - 优化首屏加载(按需加载数据)。 - - 缓存本地数据(uni.storage)。 - -### 7. 安全性设计 -- **后端**: - - 参数化查询防止 SQL 注入(mysql2/Sequelize)。 - - JWT 认证(jsonwebtoken 8.x)保护 API(如 `/api/users`)。 - - 环境变量(dotenv 16.0.x)存储敏感信息: - ```env - DB_HOST=localhost - DB_USER=root - DB_PASSWORD=your_password - DB_DATABASE=project_db - JWT_SECRET=your_secret - ``` -- **前端**: - - 验证用户输入,防止 XSS(sanitize-html 2.x)。 - - HTTPS 加密通信。 -- **小程序**: - - 遵守微信安全规范(如数据加密)。 - - 限制 API 调用范围(仅调用必要 API)。 - -### 8. 可扩展性设计 -- **模块化**: - - backend 使用控制器和服务分离,便于添加新 API。 - - 前端组件化 \ No newline at end of file diff --git a/backend/高级项目经理提示词(包含详细项目需求).md b/backend/高级项目经理提示词(包含详细项目需求).md deleted file mode 100644 index 2180cd8..0000000 --- a/backend/高级项目经理提示词(包含详细项目需求).md +++ /dev/null @@ -1,267 +0,0 @@ -# 项目经理提示词(SRS 优化版,Node.js 16.20.2 & MySQL) - -## 项目概述 -您作为项目经理,负责为一个包含五个子项目的 Web 应用编写一份项目需求文档(SRS):后端项目(backend)、后端管理项目(admin-system)、官网(website)、大数据可视化界面(datav)和微信小程序(mini_program)。前端使用 Vue.js(3.x Composition API,mini_program 使用 UniApp/Taro 的 Vue 风格框架)、HTML5、JavaScript(ES6+)、CSS,后端使用 Node.js(16.20.2,Express 框架),数据库为 MySQL。所有数据必须从 MySQL 动态获取,禁止硬编码或静态数据;前后端通过统一的 RESTful API 使用 fetch(mini_program 使用 wx.request)交互;筛选条件通过手动更新 filters 对象管理,绕过 v-model 潜在绑定问题。您的目标是编写一份清晰、全面的 SRS,确保需求明确、结构化,便于开发团队实施和评审,同时支持跨团队协调、风险管理和质量保障。 - -## 项目目录职责 -1. **backend**:核心后端服务,提供统一 RESTful API,处理 MySQL 数据库交互,支持所有子项目的 CRUD 和筛选功能。 -2. **admin-system**:后端管理平台,用于管理员操作(如用户管理、数据配置),基于 Vue.js,调用 backend API。 -3. **website**:面向用户的官网,展示产品信息和动态内容,基于 Vue.js,强调响应式设计和 SEO,调用 backend API。 -4. **datav**:大数据可视化界面,基于 Vue.js 和 ECharts/D3.js,展示动态数据图表,支持交互筛选,调用 backend API。 -5. **mini_program**:微信小程序,基于 UniApp/Taro(Vue 风格),提供移动端功能,通过 wx.request 调用 backend API。 - -## SRS 编写指南 - -### 1. 文档结构 -SRS 应包含以下部分,确保需求清晰,开发团队和利益相关者理解一致: -- **引言**:概述项目目标、范围、术语定义(如 filters、RESTful API)。 -- **总体描述**:项目背景、用户角色(管理员、普通用户)、运行环境(Node.js 16.20.2,MySQL 8.0.x)、技术栈。 -- **功能需求**:详细描述各子项目的功能,含用例和流程。 -- **非功能需求**:性能、安全、兼容性、可扩展性。 -- **接口规范**:API 请求/响应格式、filters 管理逻辑。 -- **数据库设计**:MySQL 表结构、索引需求。 -- **约束与假设**:技术限制、外部依赖(如微信审核)。 -- **风险与缓解措施**:潜在问题及应对策略。 -- **附录**:ER 图、用例图、API 文档(Swagger 格式)。 - -### 2. 功能需求(详细) -#### 2.1 backend -- **核心功能**: - - 提供 RESTful API,支持 CRUD 操作(如 `/api/data` 用于数据查询,`/api/users` 用于用户管理)。 - - 处理动态筛选请求,解析 filters 对象(如 `?name=example&category=test`)。 -- **API 示例**: - ```json - // GET /api/data?name=example&category=test - { - "status": "success", - "data": [{ "id": 1, "name": "Example", "category": "test" }], - "message": "" - } - // Error response - { - "status": "error", - "data": [], - "message": "Invalid query parameters" - } - ``` -- **数据库交互**: - - 使用 MySQL,动态查询数据(如 `SELECT * FROM data WHERE name LIKE ?`)。 - - 支持分页(`LIMIT`, `OFFSET`)和排序(`ORDER BY`)。 - - 使用 mysql2 (2.3.x) 或 Sequelize (6.29.x),兼容 Node.js 16.20.2。 - -#### 2.2 admin-system -- **核心功能**: - - 用户管理:增删改查用户(管理员、普通用户)。 - - 数据配置:管理产品、分类等数据。 - - 动态筛选:支持多条件筛选(如名称、日期)。 -- **筛选逻辑**: - - 使用 reactive filters 对象(如 `filters = { name: '', category: '' }`)。 - - 手动更新(如 `filters.name = value`),通过 fetch 调用 API。 - - 示例: - ```javascript - async function fetchData() { - const query = new URLSearchParams(filters).toString(); - const response = await fetch(`/api/data?${query}`); - return await response.json(); - } - ``` -- **界面**: - - 响应式布局,支持表格展示、表单编辑。 - -#### 2.3 website -- **核心功能**: - - 展示产品信息、新闻动态。 - - 支持搜索和筛选(如按类别或关键词)。 - - SEO 优化(如 meta 标签、sitemap)。 -- **筛选逻辑**:同 admin-system,手动更新 filters,调用 backend API. -- **界面**:现代化设计,支持移动端和桌面端。 - -#### 2.4 datav -- **核心功能**: - - 展示动态图表(如折线图、柱状图),基于 ECharts (5.x,兼容 Node.js 16.20.2)。 - - 支持交互筛选(如时间范围、数据类型)。 -- **筛选逻辑**:同 admin-system,使用 fetch 和 filters 对象。 -- **性能优化**:支持大数据分片加载,缓存静态资源。 - -#### 2.5 mini_program -- **核心功能**: - - 提供移动端功能(如产品浏览、订单管理)。 - - 支持搜索和筛选。 -- **筛选逻辑**: - - 使用 UniApp/Taro(Vue 风格,兼容 Node.js 16.20.2)。 - - 手动更新 filters,调用 API(wx.request): - ```javascript - async function fetchData() { - const query = new URLSearchParams(filters).toString(); - const res = await uni.request({ url: `/api/data?${query}`, method: 'GET' }); - return res.data; - } - ``` -- **界面**:适配微信小程序环境,简洁交互。 - -#### 2.6 跨项目要求 -- **数据来源**:所有数据从 MySQL 动态获取,禁止硬编码。 -- **筛选管理**:所有子项目统一使用 filters 对象,手动更新,触发 API 请求。 -- **接口一致性**:所有子项目使用相同 API 格式和响应结构。 - -### 3. 非功能需求 -- **性能**: - - API 响应时间 < 500ms,MySQL 查询使用索引。 - - 前端使用防抖(debounce,300ms)优化筛选请求。 - - datav 支持大数据渲染(>10,000 条数据)。 -- **安全性**: - - backend 使用参数化查询防止 SQL 注入。 - - 使用 JWT (jsonwebtoken 8.x,兼容 Node.js 16.20.2) 保护 API. - - 环境变量(dotenv 16.x)存储 MySQL 凭据。 -- **兼容性**: - - website、admin-system、datav 支持 Chrome、Firefox、Safari(最新版本)。 - - mini_program 兼容微信小程序(iOS 14+、Android 10+)。 -- **可扩展性**: - - 模块化设计,支持新增 API 和功能。 -- **可用性**: - - 用户友好的错误提示(如 “无匹配数据”)。 - - 界面支持多语言(预留)。 - -### 4. 接口规范 -- **请求格式**: - - GET:查询参数传递 filters(如 `/api/data?name=example`)。 - - POST:JSON body 传递 filters。 -- **响应格式**: - ```json - { - "status": "success" | "error", - "data": [], - "message": "" - } - ``` -- **API 示例**: - - `/api/data`:查询数据,支持 filters。 - - `/api/users`:用户管理(admin-system 专用)。 -- **小程序适配**:mini_program 使用 wx.request,格式与 fetch 一致。 -- **CORS**:backend 配置 cors (2.8.x) 支持跨域。 - -### 5. 数据库设计 -- **MySQL 表结构**(示例): - ```sql - CREATE TABLE data ( - id INT AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(255) NOT NULL, - category VARCHAR(100), - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - INDEX idx_name (name), - INDEX idx_category (category) - ); - CREATE TABLE users ( - id INT AUTO_INCREMENT PRIMARY KEY, - username VARCHAR(50) NOT NULL UNIQUE, - role ENUM('admin', 'user') DEFAULT 'user' - ); - ``` -- **要求**: - - 添加索引优化查询(如 `idx_name`)。 - - 使用参数化查询防止 SQL 注入。 - - 使用连接池(mysql2)管理连接。 - -### 6. 约束与假设 -- **技术约束**: - - Node.js 16.20.2(指定版本,兼容 express 4.18.x, mysql2 2.3.x, sequelize 6.29.x)。 - - 前端:Vue.js(3.x)或 UniApp/Taro,fetch/wx.request。 - - 后端:Express、Sequelize/mysql2。 - - 数据库:MySQL(推荐 8.0.x)。 -- **外部依赖**: - - 微信小程序需通过审核。 - - MySQL 云服务(如 AWS RDS)需稳定。 -- **假设**: - - 开发团队熟悉 Vue.js、Node.js 16.20.2 和 MySQL。 - - MySQL 数据库已预配置。 - -### 7. 风险与缓解措施 -- **风险**: - - backend API 开发延期,影响子项目。 - - MySQL 查询性能不足。 - - mini_program 审核失败。 - - filters 逻辑不一致。 -- **缓解措施**: - - 提供 mock API(如 json-server,兼容 Node.js 16.20.2)支持并row开发。 - - 优化 MySQL 查询(EXPLAIN 分析,添加索引)。 - - 提前准备小程序审核材料,参考微信规范。 - - 编写单元测试(Jest 27.x for 前端,Mocha 9.x for 后端)验证 filters 逻辑。 - -## 项目管理指南(支持 SRS 编写) -1. **需求收集与验证**: - - 与利益相关者(客户、产品经理)确认功能需求。 - - 使用用例图描述用户交互(如搜索、筛选)。 - - 验证 API 和数据库设计(与开发团队讨论)。 -2. **文档编写**: - - 使用 Markdown 或 Word 编写 SRS,结构清晰。 - - 包含 Swagger 格式的 API 文档(swagger-jsdoc 6.x,兼容 Node.js 16.20.2)。 - - ER 图展示 MySQL 表关系。 -3. **评审与反馈**: - - 组织需求评审会议,邀请开发、测试、设计团队。 - - 记录反馈,更新 SRS。 -4. **版本控制**: - - 使用 GitHub 存储 SRS,版本号如 v1.0.0。 - - 每次变更更新版本号(如 v1.0.1)。 -5. **跨子项目协调**: - - 确保 backend API 优先开发,支持其他子项目。 - - 统一 filters 逻辑,减少开发歧义。 - -## 示例 SRS 片段 - -### 用例:用户筛选数据 -- **用例名称**:筛选产品列表 -- **参与者**:用户(website、mini_program)、管理员(admin-system) -- **描述**:用户输入筛选条件(如名称、类别),系统返回匹配的数据。 -- **前置条件**:用户已登录(admin-system),API 可访问。 -- **流程**: - 1. 用户输入名称或选择类别。 - 2. 系统更新 filters 对象(如 `filters.name = 'input'`)。 - 3. 系统通过 fetch/wx.request 调用 `/api/data?${filters}`。 - 4. backend 查询 MySQL,返回匹配数据。 - 5. 系统展示结果。 -- **后置条件**:数据列表更新,错误提示(如无数据)。 - -### API 示例(Swagger) -```yaml -paths: - /api/data: - get: - summary: 查询数据 - parameters: - - name: name - in: query - type: string - description: 按名称筛选 - - name: category - in: query - type: string - description: 按类别筛选 - responses: - 200: - description: 成功 - schema: - type: object - properties: - status: { type: string, enum: ["success", "error"] } - data: { type: array } - message: { type: string } -``` - -### 示例依赖(backend package.json) -```json -{ - "dependencies": { - "express": "^4.18.2", - "mysql2": "^2.3.3", - "sequelize": "^6.29.0", - "cors": "^2.8.5", - "dotenv": "^16.0.3", - "swagger-jsdoc": "^6.2.8" - }, - "engines": { - "node": "16.20.2" - } -} -``` - -通过以上优化,SRS 将更清晰、结构化,确保需求明确,开发团队可依据文档高效实施,Node.js 16.20.2 和 MySQL 环境完全兼容,支持跨子项目一致性和项目管理。 \ No newline at end of file diff --git a/mini_program/farm-monitor-dashboard/test-fence.html b/mini_program/farm-monitor-dashboard/test-fence.html index d72be49..5a9e140 100644 --- a/mini_program/farm-monitor-dashboard/test-fence.html +++ b/mini_program/farm-monitor-dashboard/test-fence.html @@ -4,7 +4,7 @@ 电子围栏测试页面 - +