完善保险项目和养殖端小程序
This commit is contained in:
341
backend/package-lock.json
generated
341
backend/package-lock.json
generated
@@ -29,7 +29,6 @@
|
||||
"redis": "^4.6.12",
|
||||
"sequelize": "^6.35.2",
|
||||
"sharp": "^0.33.2",
|
||||
"socket.io": "^4.7.4",
|
||||
"swagger-jsdoc": "^6.2.8",
|
||||
"swagger-ui-express": "^5.0.0",
|
||||
"winston": "^3.11.0",
|
||||
@@ -1821,11 +1820,6 @@
|
||||
"@sinonjs/commons": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@socket.io/component-emitter": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmmirror.com/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||
@@ -1867,14 +1861,6 @@
|
||||
"@babel/types": "^7.28.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cors": {
|
||||
"version": "2.8.19",
|
||||
"resolved": "https://registry.npmmirror.com/@types/cors/-/cors-2.8.19.tgz",
|
||||
"integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/debug": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.12.tgz",
|
||||
@@ -2472,14 +2458,6 @@
|
||||
"integrity": "sha512-AuTJkq9XmE6Vk0FJVNq5QxETrSA/vKHarWVBG5l/JbdCL1prJemiyJqUS0jrlXO0MftuPq4m3YVYhoNc5+aE/g==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/base64id": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/base64id/-/base64id-2.0.0.tgz",
|
||||
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
|
||||
"engines": {
|
||||
"node": "^4.5.0 || >= 5.9"
|
||||
}
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.8.4",
|
||||
"resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.8.4.tgz",
|
||||
@@ -3502,62 +3480,6 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io": {
|
||||
"version": "6.6.4",
|
||||
"resolved": "https://registry.npmmirror.com/engine.io/-/engine.io-6.6.4.tgz",
|
||||
"integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==",
|
||||
"dependencies": {
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/node": ">=10.0.0",
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "2.0.0",
|
||||
"cookie": "~0.7.2",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-parser": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
||||
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io/node_modules/cookie": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.7.2.tgz",
|
||||
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io/node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/error-ex": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.4.tgz",
|
||||
@@ -8529,107 +8451,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmmirror.com/socket.io/-/socket.io-4.8.1.tgz",
|
||||
"integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "~2.0.0",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io": "~6.6.0",
|
||||
"socket.io-adapter": "~2.5.2",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-adapter": {
|
||||
"version": "2.5.5",
|
||||
"resolved": "https://registry.npmmirror.com/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
|
||||
"integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
|
||||
"dependencies": {
|
||||
"debug": "~4.3.4",
|
||||
"ws": "~8.17.1"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-adapter/node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-adapter/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/socket.io-parser": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmmirror.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-parser/node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-parser/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/socket.io/node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
|
||||
@@ -9715,26 +9536,6 @@
|
||||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xlsx": {
|
||||
"version": "0.18.5",
|
||||
"resolved": "https://registry.npmmirror.com/xlsx/-/xlsx-0.18.5.tgz",
|
||||
@@ -11088,11 +10889,6 @@
|
||||
"@sinonjs/commons": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"@socket.io/component-emitter": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
|
||||
},
|
||||
"@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmmirror.com/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||
@@ -11134,14 +10930,6 @@
|
||||
"@babel/types": "^7.28.2"
|
||||
}
|
||||
},
|
||||
"@types/cors": {
|
||||
"version": "2.8.19",
|
||||
"resolved": "https://registry.npmmirror.com/@types/cors/-/cors-2.8.19.tgz",
|
||||
"integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/debug": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.12.tgz",
|
||||
@@ -11615,11 +11403,6 @@
|
||||
"integrity": "sha512-AuTJkq9XmE6Vk0FJVNq5QxETrSA/vKHarWVBG5l/JbdCL1prJemiyJqUS0jrlXO0MftuPq4m3YVYhoNc5+aE/g==",
|
||||
"optional": true
|
||||
},
|
||||
"base64id": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/base64id/-/base64id-2.0.0.tgz",
|
||||
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
|
||||
},
|
||||
"baseline-browser-mapping": {
|
||||
"version": "2.8.4",
|
||||
"resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.8.4.tgz",
|
||||
@@ -12367,47 +12150,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="
|
||||
},
|
||||
"engine.io": {
|
||||
"version": "6.6.4",
|
||||
"resolved": "https://registry.npmmirror.com/engine.io/-/engine.io-6.6.4.tgz",
|
||||
"integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==",
|
||||
"requires": {
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/node": ">=10.0.0",
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "2.0.0",
|
||||
"cookie": "~0.7.2",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"cookie": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.7.2.tgz",
|
||||
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"requires": {
|
||||
"ms": "^2.1.3"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"engine.io-parser": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
||||
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="
|
||||
},
|
||||
"error-ex": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.4.tgz",
|
||||
@@ -15990,83 +15732,6 @@
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"socket.io": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmmirror.com/socket.io/-/socket.io-4.8.1.tgz",
|
||||
"integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
|
||||
"requires": {
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "~2.0.0",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io": "~6.6.0",
|
||||
"socket.io-adapter": "~2.5.2",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"requires": {
|
||||
"ms": "^2.1.3"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"socket.io-adapter": {
|
||||
"version": "2.5.5",
|
||||
"resolved": "https://registry.npmmirror.com/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
|
||||
"integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
|
||||
"requires": {
|
||||
"debug": "~4.3.4",
|
||||
"ws": "~8.17.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"requires": {
|
||||
"ms": "^2.1.3"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"socket.io-parser": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmmirror.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||
"requires": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"requires": {
|
||||
"ms": "^2.1.3"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
|
||||
@@ -16858,12 +16523,6 @@
|
||||
"signal-exit": "^3.0.7"
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"requires": {}
|
||||
},
|
||||
"xlsx": {
|
||||
"version": "0.18.5",
|
||||
"resolved": "https://registry.npmmirror.com/xlsx/-/xlsx-0.18.5.tgz",
|
||||
|
||||
@@ -59,7 +59,6 @@
|
||||
"redis": "^4.6.12",
|
||||
"sequelize": "^6.35.2",
|
||||
"sharp": "^0.33.2",
|
||||
"socket.io": "^4.7.4",
|
||||
"swagger-jsdoc": "^6.2.8",
|
||||
"swagger-ui-express": "^5.0.0",
|
||||
"winston": "^3.11.0",
|
||||
|
||||
@@ -6,7 +6,6 @@ const multer = require('multer');
|
||||
const swaggerUi = require('swagger-ui-express');
|
||||
const swaggerSpec = require('./config/swagger');
|
||||
const { sequelize } = require('./config/database-simple');
|
||||
const webSocketManager = require('./utils/websocket');
|
||||
const logger = require('./utils/logger');
|
||||
const {
|
||||
apiRateLimiter,
|
||||
@@ -264,24 +263,23 @@ app.use((err, req, res, next) => {
|
||||
});
|
||||
|
||||
// 初始化WebSocket
|
||||
webSocketManager.init(server);
|
||||
// webSocketManager.init(server);
|
||||
|
||||
// 初始化实时数据推送服务
|
||||
const realtimeService = require('./services/realtimeService');
|
||||
// const realtimeService = require('./services/realtimeService');
|
||||
|
||||
// 启动服务器
|
||||
server.listen(PORT, '0.0.0.0', () => {
|
||||
console.log(`服务器运行在端口 ${PORT}`);
|
||||
console.log(`服务器监听所有网络接口 (0.0.0.0:${PORT})`);
|
||||
console.log(`API 文档地址: http://localhost:${PORT}/api-docs`);
|
||||
console.log(`WebSocket 服务已启动`);
|
||||
|
||||
// 启动实时数据推送服务
|
||||
realtimeService.start();
|
||||
console.log(`实时数据推送服务已启动`);
|
||||
// realtimeService.start();
|
||||
// console.log(`实时数据推送服务已启动`);
|
||||
|
||||
logger.info(`宁夏智慧养殖监管平台服务器启动成功,端口: ${PORT}`);
|
||||
});
|
||||
|
||||
// 导出app和webSocketManager供其他模块使用
|
||||
module.exports = { app, webSocketManager };
|
||||
// 导出app供其他模块使用
|
||||
module.exports = { app };
|
||||
@@ -1,364 +0,0 @@
|
||||
/**
|
||||
* 实时数据推送服务
|
||||
* @file realtimeService.js
|
||||
* @description 定期检查数据变化并通过WebSocket推送给客户端
|
||||
*/
|
||||
const cron = require('node-cron');
|
||||
const { Device, Alert, Animal, Farm } = require('../models');
|
||||
const { sequelize } = require('../config/database-simple');
|
||||
const webSocketManager = require('../utils/websocket');
|
||||
const notificationService = require('./notificationService');
|
||||
const logger = require('../utils/logger');
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
class RealtimeService {
|
||||
constructor() {
|
||||
this.isRunning = false;
|
||||
this.lastUpdateTimes = {
|
||||
devices: null,
|
||||
alerts: null,
|
||||
animals: null,
|
||||
stats: null
|
||||
};
|
||||
this.updateInterval = 30; // 30秒更新间隔,符合文档要求
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动实时数据推送服务
|
||||
*/
|
||||
start() {
|
||||
if (this.isRunning) {
|
||||
logger.warn('实时数据推送服务已在运行中');
|
||||
return;
|
||||
}
|
||||
|
||||
this.isRunning = true;
|
||||
|
||||
// 设备状态监控 - 每30秒检查一次
|
||||
cron.schedule(`*/${this.updateInterval} * * * * *`, () => {
|
||||
this.checkDeviceUpdates();
|
||||
});
|
||||
|
||||
// 预警监控 - 每10秒检查一次(预警更紧急)
|
||||
cron.schedule('*/10 * * * * *', () => {
|
||||
this.checkAlertUpdates();
|
||||
});
|
||||
|
||||
// 动物健康状态监控 - 每60秒检查一次
|
||||
cron.schedule('*/60 * * * * *', () => {
|
||||
this.checkAnimalUpdates();
|
||||
});
|
||||
|
||||
// 系统统计数据更新 - 每2分钟更新一次
|
||||
cron.schedule('*/120 * * * * *', () => {
|
||||
this.updateSystemStats();
|
||||
});
|
||||
|
||||
logger.info('实时数据推送服务已启动');
|
||||
console.log(`实时数据推送服务已启动,更新间隔: ${this.updateInterval}秒`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止实时数据推送服务
|
||||
*/
|
||||
stop() {
|
||||
this.isRunning = false;
|
||||
logger.info('实时数据推送服务已停止');
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查设备状态更新
|
||||
*/
|
||||
async checkDeviceUpdates() {
|
||||
try {
|
||||
const lastCheck = this.lastUpdateTimes.devices || new Date(Date.now() - 60000); // 默认检查最近1分钟
|
||||
|
||||
const updatedDevices = await Device.findAll({
|
||||
where: {
|
||||
updated_at: {
|
||||
[Op.gt]: lastCheck
|
||||
}
|
||||
},
|
||||
include: [{
|
||||
model: Farm,
|
||||
as: 'farm',
|
||||
attributes: ['id', 'name']
|
||||
}],
|
||||
order: [['updated_at', 'DESC']]
|
||||
});
|
||||
|
||||
if (updatedDevices.length > 0) {
|
||||
logger.info(`检测到 ${updatedDevices.length} 个设备状态更新`);
|
||||
|
||||
// 为每个更新的设备推送数据
|
||||
for (const device of updatedDevices) {
|
||||
webSocketManager.broadcastDeviceUpdate({
|
||||
id: device.id,
|
||||
name: device.name,
|
||||
type: device.type,
|
||||
status: device.status,
|
||||
farm_id: device.farm_id,
|
||||
farm_name: device.farm?.name,
|
||||
last_maintenance: device.last_maintenance,
|
||||
metrics: device.metrics,
|
||||
updated_at: device.updated_at
|
||||
});
|
||||
}
|
||||
|
||||
this.lastUpdateTimes.devices = new Date();
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('检查设备更新失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查预警更新
|
||||
*/
|
||||
async checkAlertUpdates() {
|
||||
try {
|
||||
const lastCheck = this.lastUpdateTimes.alerts || new Date(Date.now() - 30000); // 默认检查最近30秒
|
||||
|
||||
const newAlerts = await Alert.findAll({
|
||||
where: {
|
||||
created_at: {
|
||||
[Op.gt]: lastCheck
|
||||
}
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: Farm,
|
||||
as: 'farm',
|
||||
attributes: ['id', 'name', 'contact', 'phone']
|
||||
},
|
||||
{
|
||||
model: Device,
|
||||
as: 'device',
|
||||
attributes: ['id', 'name', 'type']
|
||||
}
|
||||
],
|
||||
order: [['created_at', 'DESC']]
|
||||
});
|
||||
|
||||
if (newAlerts.length > 0) {
|
||||
logger.info(`检测到 ${newAlerts.length} 个新预警`);
|
||||
|
||||
// 推送新预警
|
||||
for (const alert of newAlerts) {
|
||||
webSocketManager.broadcastAlert({
|
||||
id: alert.id,
|
||||
type: alert.type,
|
||||
level: alert.level,
|
||||
message: alert.message,
|
||||
status: alert.status,
|
||||
farm_id: alert.farm_id,
|
||||
farm_name: alert.farm?.name,
|
||||
device_id: alert.device_id,
|
||||
device_name: alert.device?.name,
|
||||
created_at: alert.created_at
|
||||
});
|
||||
|
||||
// 如果是高级或紧急预警,立即发送通知
|
||||
if (alert.level === 'high' || alert.level === 'critical') {
|
||||
await this.sendUrgentNotification(alert);
|
||||
}
|
||||
}
|
||||
|
||||
this.lastUpdateTimes.alerts = new Date();
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('检查预警更新失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查动物健康状态更新
|
||||
*/
|
||||
async checkAnimalUpdates() {
|
||||
try {
|
||||
const lastCheck = this.lastUpdateTimes.animals || new Date(Date.now() - 120000); // 默认检查最近2分钟
|
||||
|
||||
const updatedAnimals = await Animal.findAll({
|
||||
where: {
|
||||
updated_at: {
|
||||
[Op.gt]: lastCheck
|
||||
}
|
||||
},
|
||||
include: [{
|
||||
model: Farm,
|
||||
as: 'farm',
|
||||
attributes: ['id', 'name']
|
||||
}],
|
||||
order: [['updated_at', 'DESC']]
|
||||
});
|
||||
|
||||
if (updatedAnimals.length > 0) {
|
||||
logger.info(`检测到 ${updatedAnimals.length} 个动物健康状态更新`);
|
||||
|
||||
for (const animal of updatedAnimals) {
|
||||
webSocketManager.broadcastAnimalUpdate({
|
||||
id: animal.id,
|
||||
type: animal.type,
|
||||
count: animal.count,
|
||||
health_status: animal.health_status,
|
||||
farm_id: animal.farm_id,
|
||||
farm_name: animal.farm?.name,
|
||||
last_inspection: animal.last_inspection,
|
||||
updated_at: animal.updated_at
|
||||
});
|
||||
}
|
||||
|
||||
this.lastUpdateTimes.animals = new Date();
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('检查动物更新失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新系统统计数据
|
||||
*/
|
||||
async updateSystemStats() {
|
||||
try {
|
||||
const stats = await this.getSystemStats();
|
||||
webSocketManager.broadcastStatsUpdate(stats);
|
||||
|
||||
this.lastUpdateTimes.stats = new Date();
|
||||
logger.info('系统统计数据已推送');
|
||||
} catch (error) {
|
||||
logger.error('更新系统统计失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统统计数据
|
||||
* @returns {Promise<Object>} 统计数据
|
||||
*/
|
||||
async getSystemStats() {
|
||||
try {
|
||||
const [farmCount, deviceCount, animalCount, alertCount] = await Promise.all([
|
||||
Farm.count(),
|
||||
Device.count(),
|
||||
Animal.sum('count'),
|
||||
Alert.count({ where: { status: 'active' } })
|
||||
]);
|
||||
|
||||
const deviceStatusStats = await Device.findAll({
|
||||
attributes: [
|
||||
'status',
|
||||
[sequelize.fn('COUNT', sequelize.col('status')), 'count']
|
||||
],
|
||||
group: ['status']
|
||||
});
|
||||
|
||||
const alertLevelStats = await Alert.findAll({
|
||||
where: { status: 'active' },
|
||||
attributes: [
|
||||
'level',
|
||||
[sequelize.fn('COUNT', sequelize.col('level')), 'count']
|
||||
],
|
||||
group: ['level']
|
||||
});
|
||||
|
||||
return {
|
||||
farmCount: farmCount || 0,
|
||||
deviceCount: deviceCount || 0,
|
||||
animalCount: animalCount || 0,
|
||||
alertCount: alertCount || 0,
|
||||
deviceStatus: deviceStatusStats.reduce((acc, item) => {
|
||||
acc[item.status] = parseInt(item.dataValues.count);
|
||||
return acc;
|
||||
}, {}),
|
||||
alertLevels: alertLevelStats.reduce((acc, item) => {
|
||||
acc[item.level] = parseInt(item.dataValues.count);
|
||||
return acc;
|
||||
}, {}),
|
||||
timestamp: new Date()
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error('获取系统统计数据失败:', error);
|
||||
return {
|
||||
error: '获取统计数据失败',
|
||||
timestamp: new Date()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送紧急预警通知
|
||||
* @param {Object} alert 预警对象
|
||||
*/
|
||||
async sendUrgentNotification(alert) {
|
||||
try {
|
||||
logger.warn(`紧急预警: ${alert.message} (级别: ${alert.level})`);
|
||||
|
||||
// 发送实时WebSocket通知给管理员
|
||||
webSocketManager.broadcastAlert({
|
||||
id: alert.id,
|
||||
type: alert.type,
|
||||
level: alert.level,
|
||||
message: alert.message,
|
||||
farm_id: alert.farm_id,
|
||||
farm_name: alert.farm?.name,
|
||||
created_at: alert.created_at
|
||||
});
|
||||
|
||||
// 发送邮件/短信通知
|
||||
const isUrgent = alert.level === 'critical' || alert.level === 'high';
|
||||
await notificationService.sendAlertNotification(alert, [], {
|
||||
urgent: isUrgent,
|
||||
includeSMS: alert.level === 'critical', // 仅紧急预警发送短信
|
||||
maxResponseTime: 300000 // 5分钟响应时间
|
||||
});
|
||||
|
||||
logger.info(`预警通知已发送: 预警ID ${alert.id}, 紧急程度: ${isUrgent}`);
|
||||
} catch (error) {
|
||||
logger.error('发送紧急预警通知失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 模拟设备数据变化(用于演示)
|
||||
*/
|
||||
async simulateDeviceChange(deviceId) {
|
||||
try {
|
||||
const device = await Device.findByPk(deviceId);
|
||||
if (!device) return;
|
||||
|
||||
// 随机改变设备状态
|
||||
const statuses = ['online', 'offline', 'maintenance'];
|
||||
const randomStatus = statuses[Math.floor(Math.random() * statuses.length)];
|
||||
|
||||
await device.update({
|
||||
status: randomStatus,
|
||||
metrics: {
|
||||
temperature: Math.random() * 10 + 20, // 20-30度
|
||||
humidity: Math.random() * 20 + 50, // 50-70%
|
||||
lastUpdate: new Date()
|
||||
}
|
||||
});
|
||||
|
||||
logger.info(`模拟设备 ${deviceId} 状态变化为: ${randomStatus}`);
|
||||
} catch (error) {
|
||||
logger.error('模拟设备变化失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务状态
|
||||
* @returns {Object} 服务状态
|
||||
*/
|
||||
getStatus() {
|
||||
return {
|
||||
isRunning: this.isRunning,
|
||||
lastUpdateTimes: this.lastUpdateTimes,
|
||||
updateInterval: this.updateInterval,
|
||||
connectedClients: webSocketManager.getConnectionStats()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 创建单例实例
|
||||
const realtimeService = new RealtimeService();
|
||||
|
||||
module.exports = realtimeService;
|
||||
@@ -1,339 +0,0 @@
|
||||
/**
|
||||
* WebSocket实时通信系统
|
||||
* @file websocket.js
|
||||
* @description 实现实时数据推送,替代轮询机制
|
||||
*/
|
||||
const socketIO = require('socket.io');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const { User, Role } = require('../models');
|
||||
const logger = require('./logger');
|
||||
|
||||
class WebSocketManager {
|
||||
constructor() {
|
||||
this.io = null;
|
||||
this.connectedClients = new Map(); // 存储连接的客户端信息
|
||||
this.rooms = {
|
||||
admins: 'admin_room',
|
||||
users: 'user_room',
|
||||
farms: 'farm_', // farm_1, farm_2 等
|
||||
devices: 'device_', // device_1, device_2 等
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化WebSocket服务器
|
||||
* @param {Object} server HTTP服务器实例
|
||||
*/
|
||||
init(server) {
|
||||
this.io = socketIO(server, {
|
||||
cors: {
|
||||
origin: ["http://localhost:5300", "http://localhost:3000"],
|
||||
methods: ["GET", "POST"],
|
||||
credentials: true
|
||||
},
|
||||
pingTimeout: 60000,
|
||||
pingInterval: 25000
|
||||
});
|
||||
|
||||
// 中间件:认证
|
||||
this.io.use(async (socket, next) => {
|
||||
try {
|
||||
const token = socket.handshake.auth.token || socket.handshake.headers.authorization?.split(' ')[1];
|
||||
|
||||
if (!token) {
|
||||
return next(new Error('未提供认证令牌'));
|
||||
}
|
||||
|
||||
// 验证JWT令牌
|
||||
const decoded = jwt.verify(token, process.env.JWT_SECRET || 'your_jwt_secret_key');
|
||||
|
||||
// 获取用户信息和角色
|
||||
const user = await User.findByPk(decoded.id, {
|
||||
include: [{
|
||||
model: Role,
|
||||
as: 'role',
|
||||
attributes: ['name']
|
||||
}]
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return next(new Error('用户不存在'));
|
||||
}
|
||||
|
||||
// 将用户信息附加到socket
|
||||
socket.user = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
roles: user.role ? [user.role.name] : []
|
||||
};
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
logger.error('WebSocket认证失败:', error);
|
||||
next(new Error('认证失败'));
|
||||
}
|
||||
});
|
||||
|
||||
// 连接事件处理
|
||||
this.io.on('connection', (socket) => {
|
||||
this.handleConnection(socket);
|
||||
});
|
||||
|
||||
logger.info('WebSocket服务器初始化完成');
|
||||
return this.io;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理客户端连接
|
||||
* @param {Object} socket Socket实例
|
||||
*/
|
||||
handleConnection(socket) {
|
||||
const user = socket.user;
|
||||
|
||||
// 存储客户端信息
|
||||
this.connectedClients.set(socket.id, {
|
||||
userId: user.id,
|
||||
username: user.username,
|
||||
roles: user.roles,
|
||||
connectedAt: new Date()
|
||||
});
|
||||
|
||||
// 加入相应的房间
|
||||
this.joinRooms(socket, user);
|
||||
|
||||
logger.info(`用户 ${user.username} 已连接 WebSocket,连接ID: ${socket.id}`);
|
||||
|
||||
// 发送连接成功消息
|
||||
socket.emit('connected', {
|
||||
message: '实时连接已建立',
|
||||
timestamp: new Date(),
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username
|
||||
}
|
||||
});
|
||||
|
||||
// 处理客户端事件
|
||||
this.setupSocketEvents(socket);
|
||||
|
||||
// 断开连接处理
|
||||
socket.on('disconnect', () => {
|
||||
this.handleDisconnection(socket);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 让用户加入相应的房间
|
||||
* @param {Object} socket Socket实例
|
||||
* @param {Object} user 用户信息
|
||||
*/
|
||||
joinRooms(socket, user) {
|
||||
// 所有用户加入用户房间
|
||||
socket.join(this.rooms.users);
|
||||
|
||||
// 管理员加入管理员房间
|
||||
if (user.roles && user.roles.includes('admin')) {
|
||||
socket.join(this.rooms.admins);
|
||||
}
|
||||
|
||||
// 可以根据业务需求加入特定的农场或设备房间
|
||||
// 这里暂时加入全局房间,后续可以根据用户权限细化
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Socket事件监听
|
||||
* @param {Object} socket Socket实例
|
||||
*/
|
||||
setupSocketEvents(socket) {
|
||||
// 订阅特定农场的数据
|
||||
socket.on('subscribe_farm', (farmId) => {
|
||||
socket.join(`${this.rooms.farms}${farmId}`);
|
||||
logger.info(`用户 ${socket.user.username} 订阅农场 ${farmId} 的实时数据`);
|
||||
});
|
||||
|
||||
// 取消订阅农场数据
|
||||
socket.on('unsubscribe_farm', (farmId) => {
|
||||
socket.leave(`${this.rooms.farms}${farmId}`);
|
||||
logger.info(`用户 ${socket.user.username} 取消订阅农场 ${farmId} 的实时数据`);
|
||||
});
|
||||
|
||||
// 订阅特定设备的数据
|
||||
socket.on('subscribe_device', (deviceId) => {
|
||||
socket.join(`${this.rooms.devices}${deviceId}`);
|
||||
logger.info(`用户 ${socket.user.username} 订阅设备 ${deviceId} 的实时数据`);
|
||||
});
|
||||
|
||||
// 心跳检测
|
||||
socket.on('ping', () => {
|
||||
socket.emit('pong', { timestamp: new Date() });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理客户端断开连接
|
||||
* @param {Object} socket Socket实例
|
||||
*/
|
||||
handleDisconnection(socket) {
|
||||
const clientInfo = this.connectedClients.get(socket.id);
|
||||
|
||||
if (clientInfo) {
|
||||
logger.info(`用户 ${clientInfo.username} 断开 WebSocket 连接,连接ID: ${socket.id}`);
|
||||
this.connectedClients.delete(socket.id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 广播设备状态更新
|
||||
* @param {Object} deviceData 设备数据
|
||||
*/
|
||||
broadcastDeviceUpdate(deviceData) {
|
||||
if (!this.io) return;
|
||||
|
||||
// 向所有用户广播设备更新
|
||||
this.io.to(this.rooms.users).emit('device_update', {
|
||||
type: 'device_status',
|
||||
data: deviceData,
|
||||
timestamp: new Date()
|
||||
});
|
||||
|
||||
// 向特定设备的订阅者发送更新
|
||||
this.io.to(`${this.rooms.devices}${deviceData.id}`).emit('device_detail_update', {
|
||||
type: 'device_detail',
|
||||
data: deviceData,
|
||||
timestamp: new Date()
|
||||
});
|
||||
|
||||
logger.info(`设备状态更新已广播: 设备ID ${deviceData.id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 广播预警信息
|
||||
* @param {Object} alertData 预警数据
|
||||
*/
|
||||
broadcastAlert(alertData) {
|
||||
if (!this.io) return;
|
||||
|
||||
// 向管理员发送紧急预警
|
||||
if (alertData.level === 'critical' || alertData.level === 'high') {
|
||||
this.io.to(this.rooms.admins).emit('urgent_alert', {
|
||||
type: 'urgent_alert',
|
||||
data: alertData,
|
||||
timestamp: new Date()
|
||||
});
|
||||
}
|
||||
|
||||
// 向所有用户广播预警
|
||||
this.io.to(this.rooms.users).emit('alert_update', {
|
||||
type: 'new_alert',
|
||||
data: alertData,
|
||||
timestamp: new Date()
|
||||
});
|
||||
|
||||
// 向特定农场的订阅者发送预警
|
||||
if (alertData.farm_id) {
|
||||
this.io.to(`${this.rooms.farms}${alertData.farm_id}`).emit('farm_alert', {
|
||||
type: 'farm_alert',
|
||||
data: alertData,
|
||||
timestamp: new Date()
|
||||
});
|
||||
}
|
||||
|
||||
logger.info(`预警信息已广播: 预警ID ${alertData.id}, 级别: ${alertData.level}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 广播动物健康数据更新
|
||||
* @param {Object} animalData 动物数据
|
||||
*/
|
||||
broadcastAnimalUpdate(animalData) {
|
||||
if (!this.io) return;
|
||||
|
||||
this.io.to(this.rooms.users).emit('animal_update', {
|
||||
type: 'animal_health',
|
||||
data: animalData,
|
||||
timestamp: new Date()
|
||||
});
|
||||
|
||||
// 向特定农场的订阅者发送动物更新
|
||||
if (animalData.farm_id) {
|
||||
this.io.to(`${this.rooms.farms}${animalData.farm_id}`).emit('farm_animal_update', {
|
||||
type: 'farm_animal',
|
||||
data: animalData,
|
||||
timestamp: new Date()
|
||||
});
|
||||
}
|
||||
|
||||
logger.info(`动物健康数据更新已广播: 动物ID ${animalData.id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 广播系统统计数据更新
|
||||
* @param {Object} statsData 统计数据
|
||||
*/
|
||||
broadcastStatsUpdate(statsData) {
|
||||
if (!this.io) return;
|
||||
|
||||
this.io.to(this.rooms.users).emit('stats_update', {
|
||||
type: 'system_stats',
|
||||
data: statsData,
|
||||
timestamp: new Date()
|
||||
});
|
||||
|
||||
logger.info('系统统计数据更新已广播');
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送性能监控数据
|
||||
* @param {Object} performanceData 性能数据
|
||||
*/
|
||||
broadcastPerformanceUpdate(performanceData) {
|
||||
if (!this.io) return;
|
||||
|
||||
// 只向管理员发送性能数据
|
||||
this.io.to(this.rooms.admins).emit('performance_update', {
|
||||
type: 'system_performance',
|
||||
data: performanceData,
|
||||
timestamp: new Date()
|
||||
});
|
||||
|
||||
logger.info('性能监控数据已发送给管理员');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取连接统计信息
|
||||
* @returns {Object} 连接统计
|
||||
*/
|
||||
getConnectionStats() {
|
||||
return {
|
||||
totalConnections: this.connectedClients.size,
|
||||
connectedUsers: Array.from(this.connectedClients.values()).map(client => ({
|
||||
userId: client.userId,
|
||||
username: client.username,
|
||||
connectedAt: client.connectedAt
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 向特定用户发送消息
|
||||
* @param {number} userId 用户ID
|
||||
* @param {string} event 事件名称
|
||||
* @param {Object} data 数据
|
||||
*/
|
||||
sendToUser(userId, event, data) {
|
||||
if (!this.io) return;
|
||||
|
||||
for (const [socketId, clientInfo] of this.connectedClients.entries()) {
|
||||
if (clientInfo.userId === userId) {
|
||||
this.io.to(socketId).emit(event, data);
|
||||
logger.info(`消息已发送给用户 ${clientInfo.username}: ${event}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建单例实例
|
||||
const webSocketManager = new WebSocketManager();
|
||||
|
||||
module.exports = webSocketManager;
|
||||
Reference in New Issue
Block a user