Browse Source

添加检查流程的实现,能够向发后发送开始检查信息,打开设备等重要交互信息

sw 1 week ago
parent
commit
3b4c0ce745

+ 25 - 16
config/index.ts

@@ -4,7 +4,6 @@ import devConfig from './dev';
 import prodConfig from './prod';
 import path from 'path';
 import TerserPlugin from 'terser-webpack-plugin';
-import webpack, { DefinePlugin } from 'webpack';
 
 // https://taro-docs.jd.com/docs/next/config#defineconfig-辅助函数
 export default defineConfig<'webpack5'>(async (merge) => {
@@ -23,7 +22,11 @@ export default defineConfig<'webpack5'>(async (merge) => {
     plugins: ['@tarojs/plugin-http'],
     defineConstants: {
       // 开发环境下使用空字符串,实际请求会自动拼接当前域名
-      API_BASE_URL_FROM_WEBPACK: process.env.NODE_ENV === 'development' ? '""' : '"http://101.43.219.60:7700"'
+      API_BASE_URL_FROM_WEBPACK:
+        process.env.NODE_ENV === 'development'
+          ? '""'
+          : '"http://101.43.219.60:7700"',
+      MQTT_BROKER_URL_FROM_WEBPACK: '"ws://192.168.1.115:8083/mqtt"',
     },
     copy: {
       patterns: [],
@@ -82,11 +85,11 @@ export default defineConfig<'webpack5'>(async (merge) => {
         chain.output.path(path.resolve(__dirname, '../dist/h5'));
         chain.optimization.minimize(false); // 彻底关闭压缩
         // chain.resolve.plugin('tsconfig-paths').use(TsconfigPathsPlugin);
-        chain.resolve
-          .plugin('tsconfig-paths')
-          .use(TsconfigPathsPlugin, [{
+        chain.resolve.plugin('tsconfig-paths').use(TsconfigPathsPlugin, [
+          {
             configFile: path.resolve(__dirname, '../tsconfig.json'), // 必须指向存在的 tsconfig
-          }]);
+          },
+        ]);
         // 打开详细日志
         //chain.mode('production').stats('verbose');
         chain.merge({
@@ -99,25 +102,31 @@ export default defineConfig<'webpack5'>(async (merge) => {
             },
           },
         });
-        chain.optimization
-          .minimizer('terser')
-          .use(TerserPlugin, [{
-            parallel: false,           // 单线程,错误不会丢
+        chain.optimization.minimizer('terser').use(TerserPlugin, [
+          {
+            parallel: false, // 单线程,错误不会丢
             terserOptions: {
-              compress: false,         // 先不压缩,只混淆
+              compress: false, // 先不压缩,只混淆
               mangle: false,
               format: {
                 comments: false,
               },
             },
+            // eslint-disable-next-line
           } as any]);
-        chain.plugin('define-plugin')
+        chain
+          .plugin('define-plugin')
+          // eslint-disable-next-line
           .use(DefinePlugin as any, [{
-            'process.env.USE_MSW': JSON.stringify(process.env.USE_MSW || 'false'),
-            'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production'),
-          }]);
+              'process.env.USE_MSW': JSON.stringify(
+                process.env.USE_MSW || 'false'
+              ),
+              'process.env.NODE_ENV': JSON.stringify(
+                process.env.NODE_ENV || 'production'
+              ),
+            },
+          ]);
       },
-
     },
     rn: {
       appName: 'taroDemo',

+ 325 - 21
package-lock.json

@@ -34,6 +34,7 @@
         "axios": "^1.9.0",
         "dayjs": "^1.11.13",
         "dicomweb-client": "0.10.4",
+        "mqtt": "^5.14.0",
         "react": "^18.0.0",
         "react-dom": "^18.0.0",
         "react-intl": "^7.1.11",
@@ -1722,9 +1723,9 @@
       }
     },
     "node_modules/@babel/runtime": {
-      "version": "7.27.3",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.3.tgz",
-      "integrity": "sha512-7EYtGezsdiDMyY80+65EzwiGmcJqpmcZCojSXaRgdrBaGtWTgDZKq69cPIVped6MkIM78cTQ2GOiEYjwOlG4xw==",
+      "version": "7.28.2",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz",
+      "integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==",
       "engines": {
         "node": ">=6.9.0"
       }
@@ -6285,6 +6286,14 @@
         "csstype": "^3.0.2"
       }
     },
+    "node_modules/@types/readable-stream": {
+      "version": "4.0.21",
+      "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.21.tgz",
+      "integrity": "sha512-19eKVv9tugr03IgfXlA9UVUVRbW6IuqRO5B92Dl4a6pT7K8uaGrNS0GkxiZD0BOk6PLuXl5FhWl//eX/pzYdTQ==",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
     "node_modules/@types/responselike": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz",
@@ -6398,7 +6407,6 @@
       "version": "8.18.1",
       "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
       "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
-      "devOptional": true,
       "dependencies": {
         "@types/node": "*"
       }
@@ -6864,6 +6872,17 @@
       "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
       "dev": true
     },
+    "node_modules/abort-controller": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+      "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+      "dependencies": {
+        "event-target-shim": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=6.5"
+      }
+    },
     "node_modules/abortcontroller-polyfill": {
       "version": "1.7.8",
       "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.8.tgz",
@@ -7982,6 +8001,17 @@
         "node": ">=8"
       }
     },
+    "node_modules/broker-factory": {
+      "version": "3.1.8",
+      "resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.1.8.tgz",
+      "integrity": "sha512-xmVnYN0FZtynhPUmAnN+/MFRdbDi3syCuxWV7o7s78FcIN0pjDtn9mUrVqEgdjQkbfojRhlPWbYbXJkMCyddrg==",
+      "dependencies": {
+        "@babel/runtime": "^7.27.6",
+        "fast-unique-numbers": "^9.0.22",
+        "tslib": "^2.8.1",
+        "worker-factory": "^7.0.44"
+      }
+    },
     "node_modules/browserify-fs": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/browserify-fs/-/browserify-fs-1.0.0.tgz",
@@ -8858,6 +8888,11 @@
       "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
       "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
     },
+    "node_modules/commist": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz",
+      "integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw=="
+    },
     "node_modules/commondir": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@@ -11615,6 +11650,14 @@
         "node": ">= 0.6"
       }
     },
+    "node_modules/event-target-shim": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+      "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/eventemitter3": {
       "version": "4.0.7",
       "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
@@ -11848,6 +11891,18 @@
       "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
       "dev": true
     },
+    "node_modules/fast-unique-numbers": {
+      "version": "9.0.22",
+      "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-9.0.22.tgz",
+      "integrity": "sha512-dBR+30yHAqBGvOuxxQdnn2lTLHCO6r/9B+M4yF8mNrzr3u1yiF+YVJ6u3GTyPN/VRWqaE1FcscZDdBgVKmrmQQ==",
+      "dependencies": {
+        "@babel/runtime": "^7.27.6",
+        "tslib": "^2.8.1"
+      },
+      "engines": {
+        "node": ">=18.2.0"
+      }
+    },
     "node_modules/fast-uri": {
       "version": "3.0.6",
       "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
@@ -12829,6 +12884,11 @@
       "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==",
       "dev": true
     },
+    "node_modules/help-me": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
+      "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="
+    },
     "node_modules/highlight.js": {
       "version": "10.7.3",
       "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
@@ -13564,7 +13624,6 @@
       "version": "9.0.5",
       "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
       "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
-      "dev": true,
       "dependencies": {
         "jsbn": "1.1.0",
         "sprintf-js": "^1.1.3"
@@ -13576,8 +13635,7 @@
     "node_modules/ip-address/node_modules/sprintf-js": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
-      "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
-      "dev": true
+      "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
     },
     "node_modules/ipaddr.js": {
       "version": "2.2.0",
@@ -14104,6 +14162,15 @@
         "node": ">=14"
       }
     },
+    "node_modules/js-sdsl": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
+      "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/js-sdsl"
+      }
+    },
     "node_modules/js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -14124,8 +14191,7 @@
     "node_modules/jsbn": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
-      "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
-      "dev": true
+      "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
     },
     "node_modules/jsdom": {
       "version": "24.1.3",
@@ -16092,6 +16158,182 @@
       "resolved": "https://registry.npmjs.org/mobile-detect/-/mobile-detect-1.4.5.tgz",
       "integrity": "sha512-yc0LhH6tItlvfLBugVUEtgawwFU2sIe+cSdmRJJCTMZ5GEJyLxNyC/NIOAOGk67Fa8GNpOttO3Xz/1bHpXFD/g=="
     },
+    "node_modules/mqtt": {
+      "version": "5.14.0",
+      "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.14.0.tgz",
+      "integrity": "sha512-H7EmeCJhbGblbWjm6APF5sAH3SkdI7lxHw/UkblZp8fjSNl8b2MsLcdAkIaQKxvZYmiORkdAjffvKjqQWPkd6w==",
+      "dependencies": {
+        "@types/readable-stream": "^4.0.21",
+        "@types/ws": "^8.18.1",
+        "commist": "^3.2.0",
+        "concat-stream": "^2.0.0",
+        "debug": "^4.4.1",
+        "help-me": "^5.0.0",
+        "lru-cache": "^10.4.3",
+        "minimist": "^1.2.8",
+        "mqtt-packet": "^9.0.2",
+        "number-allocator": "^1.0.14",
+        "readable-stream": "^4.7.0",
+        "rfdc": "^1.4.1",
+        "socks": "^2.8.6",
+        "split2": "^4.2.0",
+        "worker-timers": "^8.0.23",
+        "ws": "^8.18.3"
+      },
+      "bin": {
+        "mqtt": "build/bin/mqtt.js",
+        "mqtt_pub": "build/bin/pub.js",
+        "mqtt_sub": "build/bin/sub.js"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
+    "node_modules/mqtt-packet": {
+      "version": "9.0.2",
+      "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.2.tgz",
+      "integrity": "sha512-MvIY0B8/qjq7bKxdN1eD+nrljoeaai+qjLJgfRn3TiMuz0pamsIWY2bFODPZMSNmabsLANXsLl4EMoWvlaTZWA==",
+      "dependencies": {
+        "bl": "^6.0.8",
+        "debug": "^4.3.4",
+        "process-nextick-args": "^2.0.1"
+      }
+    },
+    "node_modules/mqtt-packet/node_modules/bl": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-6.1.1.tgz",
+      "integrity": "sha512-yYc8UIHrd1ZTLgNBIE7JjMzUPZH+dec3q7nWkrSHEbtvkQ3h6WKC63W9K5jthcL5EXFyMuWYq+2pq5WMSIgFHw==",
+      "dependencies": {
+        "@types/readable-stream": "^4.0.0",
+        "buffer": "^6.0.3",
+        "inherits": "^2.0.4",
+        "readable-stream": "^4.2.0"
+      }
+    },
+    "node_modules/mqtt-packet/node_modules/buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
+    "node_modules/mqtt-packet/node_modules/readable-stream": {
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
+      "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
+      "dependencies": {
+        "abort-controller": "^3.0.0",
+        "buffer": "^6.0.3",
+        "events": "^3.3.0",
+        "process": "^0.11.10",
+        "string_decoder": "^1.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/mqtt-packet/node_modules/string_decoder": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "dependencies": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
+    "node_modules/mqtt/node_modules/buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
+    "node_modules/mqtt/node_modules/concat-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
+      "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
+      "engines": [
+        "node >= 6.0"
+      ],
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^3.0.2",
+        "typedarray": "^0.0.6"
+      }
+    },
+    "node_modules/mqtt/node_modules/concat-stream/node_modules/readable-stream": {
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/mqtt/node_modules/lru-cache": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+      "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
+    },
+    "node_modules/mqtt/node_modules/readable-stream": {
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
+      "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
+      "dependencies": {
+        "abort-controller": "^3.0.0",
+        "buffer": "^6.0.3",
+        "events": "^3.3.0",
+        "process": "^0.11.10",
+        "string_decoder": "^1.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/mqtt/node_modules/string_decoder": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "dependencies": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
     "node_modules/ms": {
       "version": "2.1.3",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -16522,6 +16764,15 @@
         "url": "https://github.com/fb55/nth-check?sponsor=1"
       }
     },
+    "node_modules/number-allocator": {
+      "version": "1.0.14",
+      "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz",
+      "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==",
+      "dependencies": {
+        "debug": "^4.3.1",
+        "js-sdsl": "4.3.0"
+      }
+    },
     "node_modules/nwsapi": {
       "version": "2.2.20",
       "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz",
@@ -18292,11 +18543,18 @@
         "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
       }
     },
+    "node_modules/process": {
+      "version": "0.11.10",
+      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+      "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
     "node_modules/process-nextick-args": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
-      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
-      "devOptional": true
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
     },
     "node_modules/promise-inflight": {
       "version": "1.0.1",
@@ -19646,8 +19904,7 @@
     "node_modules/rfdc": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
-      "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
-      "dev": true
+      "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="
     },
     "node_modules/rimraf": {
       "version": "3.0.2",
@@ -20569,7 +20826,6 @@
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
       "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
-      "dev": true,
       "engines": {
         "node": ">= 6.0.0",
         "npm": ">= 3.0.0"
@@ -20599,7 +20855,6 @@
       "version": "2.8.6",
       "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.6.tgz",
       "integrity": "sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA==",
-      "dev": true,
       "dependencies": {
         "ip-address": "^9.0.5",
         "smart-buffer": "^4.2.0"
@@ -20782,6 +21037,14 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/split2": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
+      "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
+      "engines": {
+        "node": ">= 10.x"
+      }
+    },
     "node_modules/sprintf-js": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -22424,8 +22687,7 @@
     "node_modules/typedarray": {
       "version": "0.0.6",
       "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
-      "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
-      "dev": true
+      "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
     },
     "node_modules/typedarray-to-buffer": {
       "version": "1.0.4",
@@ -23236,6 +23498,16 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/worker-factory": {
+      "version": "7.0.44",
+      "resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-7.0.44.tgz",
+      "integrity": "sha512-08AuUfWi+KeZI+KC7nU4pU/9tDeAFvE5NSWk+K9nIfuQc6UlOsZtjjeGVYVEn+DEchyXNJ5i10HCn0xRzFXEQA==",
+      "dependencies": {
+        "@babel/runtime": "^7.27.6",
+        "fast-unique-numbers": "^9.0.22",
+        "tslib": "^2.8.1"
+      }
+    },
     "node_modules/worker-loader": {
       "version": "3.0.8",
       "resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-3.0.8.tgz",
@@ -23272,6 +23544,39 @@
         "url": "https://opencollective.com/webpack"
       }
     },
+    "node_modules/worker-timers": {
+      "version": "8.0.23",
+      "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-8.0.23.tgz",
+      "integrity": "sha512-1BnWHNNiu5YEutgF7eVZEqNntAsij2oG0r66xDdScoY3fKGFrok2y0xA8OgG6FA+3srrmAplSY6JN5h9jV5D0w==",
+      "dependencies": {
+        "@babel/runtime": "^7.27.6",
+        "tslib": "^2.8.1",
+        "worker-timers-broker": "^8.0.9",
+        "worker-timers-worker": "^9.0.9"
+      }
+    },
+    "node_modules/worker-timers-broker": {
+      "version": "8.0.9",
+      "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-8.0.9.tgz",
+      "integrity": "sha512-WJsd7aIvu2GBTXp7IBGT1NKnt3ZbiJ2wqb7Pl4nFJXC8pek84+X68TJGVvvrqwHgHPNxSlzpU1nadhcW4PDD7A==",
+      "dependencies": {
+        "@babel/runtime": "^7.27.6",
+        "broker-factory": "^3.1.8",
+        "fast-unique-numbers": "^9.0.22",
+        "tslib": "^2.8.1",
+        "worker-timers-worker": "^9.0.9"
+      }
+    },
+    "node_modules/worker-timers-worker": {
+      "version": "9.0.9",
+      "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-9.0.9.tgz",
+      "integrity": "sha512-OOKTMdHbzx7FaXCW40RS8RxAqLF/R8xU5/YA7CFasDy+jBA5yQWUusSQJUFFTV2Z9ZOpnR+ZWgte/IuAqOAEVw==",
+      "dependencies": {
+        "@babel/runtime": "^7.27.6",
+        "tslib": "^2.8.1",
+        "worker-factory": "^7.0.44"
+      }
+    },
     "node_modules/wrap-ansi": {
       "version": "6.2.0",
       "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
@@ -23323,10 +23628,9 @@
       }
     },
     "node_modules/ws": {
-      "version": "8.18.2",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz",
-      "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==",
-      "devOptional": true,
+      "version": "8.18.3",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
+      "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
       "engines": {
         "node": ">=10.0.0"
       },

+ 1 - 0
package.json

@@ -69,6 +69,7 @@
     "axios": "^1.9.0",
     "dayjs": "^1.11.13",
     "dicomweb-client": "0.10.4",
+    "mqtt": "^5.14.0",
     "react": "^18.0.0",
     "react-dom": "^18.0.0",
     "react-intl": "^7.1.11",

+ 5 - 2
src/API/config.ts

@@ -1,2 +1,5 @@
-export const API_BASE_URL = `${API_BASE_URL_FROM_WEBPACK}/dr/api/v1/`;//'http://localhost:10086/dr/api/v1/';
-export const IP_PORT =`${API_BASE_URL_FROM_WEBPACK}`;
+export const API_BASE_URL = `${API_BASE_URL_FROM_WEBPACK}/dr/api/v1/`; //'http://localhost:10086/dr/api/v1/';
+export const IP_PORT = `${API_BASE_URL_FROM_WEBPACK}`;
+export const MQTT_BROKER_URL = `${MQTT_BROKER_URL_FROM_WEBPACK}`;
+console.log('API_BASE_URL', API_BASE_URL);
+console.log('MQTT_BROKER_URL', MQTT_BROKER_URL);

+ 36 - 0
src/API/exam/detectorAPI.ts

@@ -0,0 +1,36 @@
+import axiosInstance from '../interceptor';
+
+interface OpenDeviceResponse {
+  code: string;
+  description: string;
+  solution: string;
+  data: {
+    '@type': string;
+    value: null;
+  };
+}
+
+const openDetector = async (): Promise<OpenDeviceResponse> => {
+  const response = await axiosInstance.post('/auth/device/open', {
+    deviceUri: 'DIOS/DEVICE/Detector',
+  });
+  return response.data;
+};
+
+const prepareForAcquisition = async (
+  reqName: string,
+  reqParam: string,
+  reqTransaction: string,
+  reqClientID: string
+): Promise<OpenDeviceResponse> => {
+  const response = await axiosInstance.post('/api/v1/auth/device/action', {
+    deviceUri: 'DIOS/DEVICE/Detector',
+    reqName,
+    reqParam,
+    reqTransaction,
+    reqClientID,
+  });
+  return response.data;
+};
+
+export { openDetector, prepareForAcquisition };

+ 20 - 0
src/API/exam/generatorAPI.ts

@@ -0,0 +1,20 @@
+import axiosInstance from '../interceptor';
+
+interface OpenDeviceResponse {
+  code: string;
+  description: string;
+  solution: string;
+  data: {
+    '@type': string;
+    value: null;
+  };
+}
+
+const openGenerator = async (): Promise<OpenDeviceResponse> => {
+  const response = await axiosInstance.post('/auth/device/open', {
+    deviceUri: 'DIOS/DEVICE/Generator',
+  });
+  return response.data;
+};
+
+export { openGenerator };

+ 22 - 0
src/API/exam/startInspection.ts

@@ -0,0 +1,22 @@
+import axiosInstance from '../interceptor';
+
+interface StartAcquisitionResponse {
+  code: string;
+  description: string;
+  solution: string;
+  data: {
+    '@type': string;
+    value: null;
+  };
+}
+
+const startInspection = async (
+  instanceUid: string
+): Promise<StartAcquisitionResponse> => {
+  const response = await axiosInstance.post(`/auth/task/inspection/start`, {
+    instance_uid: instanceUid,
+  });
+  return response.data;
+};
+
+export { startInspection };

+ 25 - 0
src/API/exam/triggerInspection.ts

@@ -0,0 +1,25 @@
+import axiosInstance from '../interceptor';
+
+interface TriggerInspectionResponse {
+  code: string;
+  data: object;
+  description: string;
+  solution: string;
+}
+/**
+ * 触发软件曝光
+ * @returns A promise that resolves to the response data from the trigger inspection API.
+ * @throws An error if the request fails.
+ */
+const triggerInspection = async (): Promise<TriggerInspectionResponse> => {
+  const url = '/auth/task/inspection/trigger';
+
+  try {
+    const response = await axiosInstance.post(url, {});
+    return response.data;
+  } catch (error) {
+    throw new Error(error);
+  }
+};
+
+export default triggerInspection;

+ 23 - 0
src/domain/exam/prepare.ts

@@ -0,0 +1,23 @@
+import { startListening } from '../../domain/mqttService';
+import { openGenerator } from '../../API/exam/generatorAPI';
+import { openDetector } from '../../API/exam/detectorAPI';
+
+const prepare = async () => {
+  try {
+    console.log('Preparing for inspection...');
+    // Start listening for MQTT messages
+    startListening();
+    console.log('Started listening to MQTT messages.');
+    // Open the generator device
+    await openGenerator();
+    console.log('Generator device opened.');
+    // Open the detector device
+    await openDetector();
+    console.log('Detector device opened.');
+    console.log('Preparation for inspection completed.');
+  } catch (error) {
+    console.error('Failed to prepare for inspection:', error);
+  }
+};
+
+export default prepare;

+ 73 - 0
src/domain/mqttService.ts

@@ -0,0 +1,73 @@
+import mqtt from 'mqtt';
+import { MQTT_BROKER_URL } from '../API/config';
+
+interface MqttMessage {
+  dcm?: string;
+  message: string;
+  sop?: string;
+  status: string;
+  thumbnail?: string;
+}
+
+//const MQTT_BROKER_URL = 'ws://your-mqtt-broker-url'; // Replace with your actual MQTT broker URL
+const MQTT_TOPIC = 'MODULE/TASK/IMGPROC/PROGRESS';
+console.log('[mqttService] MQTT_BROKER_URL', MQTT_BROKER_URL);
+const options = {
+  clean: true, // true: 清除会话, false: 保留会话
+  connectTimeout: 4000, // 超时时间
+  // 认证信息
+  // clientId: 'mqttx_58db45cc7777',
+  username: 'mqttx1112',
+  password: '',
+};
+let mqttClient;
+
+const handleMqttMessage = (message: MqttMessage) => {
+  switch (message.status) {
+    case 'TASK_RecvRaw':
+      console.log('Task started: TASK_RecvRaw');
+      // Start loading or call the soft exposure interface
+      break;
+    case 'TASK_Success':
+      console.log('Task succeeded:', message);
+      // Handle success, e.g., process DCM and thumbnail files
+      break;
+    case 'TASK_Failure':
+      console.error('Task failed:', message.message);
+      // Handle failure
+      break;
+    default:
+      break;
+  }
+};
+
+const startListening = () => {
+  console.log(`startListening: ${MQTT_BROKER_URL}`);
+  mqttClient = mqtt.connect(MQTT_BROKER_URL, options);
+  mqttClient.on('connect', () => {
+    console.log('Connected to MQTT broker');
+    mqttClient.subscribe(MQTT_TOPIC, (err) => {
+      if (err) {
+        console.error('Failed to subscribe to topic', err);
+      }
+    });
+  });
+
+  mqttClient.on('error', (error) => {
+    console.log('连接失败:', error);
+  });
+
+  mqttClient.on('message', (topic, message) => {
+    if (topic === MQTT_TOPIC) {
+      const parsedMessage: MqttMessage = JSON.parse(message.toString());
+      handleMqttMessage(parsedMessage);
+    }
+  });
+};
+
+const stopListening = () => {
+  mqttClient.end();
+  console.log('Stopped listening to MQTT broker');
+};
+
+export { mqttClient, handleMqttMessage, startListening, stopListening };

+ 6 - 1
src/pages/exam/DeviceArea.tsx

@@ -4,12 +4,17 @@ import {
   CameraOutlined,
   TabletOutlined,
 } from '@ant-design/icons';
+import triggerInspection from '../../API/exam/triggerInspection';
 
 const DeviceArea = ({ className }: { className?: string }) => {
   return (
     <Flex justify="end" align="center" className={`w-full ${className}`}>
       <Button icon={<ToolOutlined />} title="发生器状态指示器" />
-      <Button icon={<CameraOutlined />} title="曝光指示器" />
+      <Button
+        icon={<CameraOutlined />}
+        title="曝光指示器"
+        onClick={triggerInspection}
+      />
       <Button icon={<TabletOutlined />} title="平板指示器" />
     </Flex>
   );

+ 1 - 1
src/states/BusinessFlowSlice.ts

@@ -1,6 +1,6 @@
 import { createSlice, PayloadAction } from '@reduxjs/toolkit';
 
-interface BusinessFlowState {
+export interface BusinessFlowState {
   currentKey: string;
 }
 

+ 3 - 0
src/states/businessFlowMiddleware.ts

@@ -0,0 +1,3 @@
+import businessFlowMiddlewareLogic from './businessFlowMiddlewareLogic';
+
+export default businessFlowMiddlewareLogic;

+ 19 - 0
src/states/businessFlowMiddlewareLogic.ts

@@ -0,0 +1,19 @@
+import { Middleware } from '@reduxjs/toolkit';
+import prepare from '../domain/exam/prepare';
+import { BusinessFlowState } from './BusinessFlowSlice';
+
+const businessFlowMiddlewareLogic: Middleware =
+  (store) => (next) => (action) => {
+    const result = next(action);
+
+    const state = store.getState().BusinessFlow as BusinessFlowState;
+    const currentKey = state.currentKey;
+    console.log(`[businessFlowMiddleware] currentKey: ${currentKey}`);
+    if (currentKey === 'exam') {
+      prepare();
+    }
+
+    return result;
+  };
+
+export default businessFlowMiddlewareLogic;

+ 3 - 1
src/states/store.ts

@@ -15,6 +15,7 @@ import bodyPositionListenerMiddleware from './exam/bodyPositionListener';
 import { aprMiddleware } from './exam/aprSlice';
 import functionAreaReducer from './view/functionAreaSlice';
 import searchReducer from './patient/worklist/slices/searchSlice';
+import businessFlowMiddleware from './businessFlowMiddleware';
 import {
   workEntitiesSlice,
   workFiltersSlice,
@@ -48,7 +49,8 @@ const store = configureStore({
   middleware: (getDefaultMiddleware) =>
     getDefaultMiddleware().concat(
       bodyPositionListenerMiddleware,
-      aprMiddleware
+      aprMiddleware,
+      businessFlowMiddleware
     ),
 });