增加管理运行状态界面
This commit is contained in:
parent
4388a6ef49
commit
a9866d71e8
|
|
@ -6,7 +6,7 @@ VITE_PUBLIC_PATH = /
|
|||
|
||||
# 跨域代理,您可以配置多个 ,请注意,没有换行符
|
||||
VITE_PROXY = [["/jeecgboot","http://192.168.2.110:9999"],["/upload","http://192.168.2.110:3300/upload"]]
|
||||
VITE_PROXY = [["/jeecgboot","https://fxnsp.sxcooh.com/lh-api/"],["/upload","http://192.168.2.111:3300/upload"]]
|
||||
#VITE_PROXY = [["/jeecgboot","https://fxnsp.sxcooh.com/lh-api/"],["/upload","http://192.168.2.111:3300/upload"]]
|
||||
|
||||
# 控制台不输出
|
||||
VITE_DROP_CONSOLE = false
|
||||
|
|
@ -23,3 +23,8 @@ VITE_GLOB_API_URL_PREFIX=
|
|||
|
||||
#微前端qiankun应用,命名必须以VITE_APP_SUB_开头,jeecg-app-1为子应用的项目名称,也是子应用的路由父路径
|
||||
VITE_APP_SUB_jeecg-app-1 = '//localhost:8092'
|
||||
|
||||
# mqtt
|
||||
VITE_MQTT_BROKER_URL=ws://mqtt.ilhzn.cn:80/mqtt
|
||||
VITE_MQTT_USERNAME=lhzn.mqtt
|
||||
VITE_MQTT_PASSWORD=lhzn.2025
|
||||
|
|
|
|||
|
|
@ -36,3 +36,8 @@ VITE_USE_PWA = false
|
|||
|
||||
# 是否兼容旧浏览器
|
||||
VITE_LEGACY = false
|
||||
|
||||
# mqtt
|
||||
VITE_MQTT_BROKER_URL=ws://mqtt.ilhzn.cn:80/mqtt
|
||||
VITE_MQTT_USERNAME=lhzn.mqtt
|
||||
VITE_MQTT_PASSWORD=lhzn.2025
|
||||
|
|
|
|||
11
package.json
11
package.json
|
|
@ -48,7 +48,6 @@
|
|||
"@vueuse/shared": "^8.3.0",
|
||||
"@zxcvbn-ts/core": "^2.0.1",
|
||||
"ant-design-vue": "^3.2.12",
|
||||
"html2canvas": "1.4.1",
|
||||
"axios": "^0.26.1",
|
||||
"china-area-data": "^5.0.1",
|
||||
"clipboard": "^2.0.8",
|
||||
|
|
@ -62,11 +61,13 @@
|
|||
"emoji-mart-vue-fast": "^11.1.1",
|
||||
"enquire.js": "^2.1.6",
|
||||
"ezuikit-js": "^7.6.8",
|
||||
"html2canvas": "1.4.1",
|
||||
"intro.js": "^5.1.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lodash.get": "^4.4.2",
|
||||
"md5": "^2.3.0",
|
||||
"mockjs": "^1.1.0",
|
||||
"mqtt": "^5.15.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"path-to-regexp": "^6.2.0",
|
||||
"pinia": "2.0.12",
|
||||
|
|
@ -80,6 +81,9 @@
|
|||
"sortablejs": "^1.15.0",
|
||||
"tinymce": "^5.10.3",
|
||||
"vditor": "^3.8.13",
|
||||
"video.js": "^8.21.1",
|
||||
"videojs-contrib-hls": "^5.15.0",
|
||||
"videojs-vtt.js": "^0.15.5",
|
||||
"vue": "^3.2.33",
|
||||
"vue-cropper": "^0.5.6",
|
||||
"vue-cropperjs": "^5.0.0",
|
||||
|
|
@ -93,10 +97,7 @@
|
|||
"vxe-table": "4.1.0",
|
||||
"vxe-table-plugin-antd": "3.0.5",
|
||||
"xe-utils": "^3.3.1",
|
||||
"xss": "^1.0.13",
|
||||
"video.js": "^8.21.1",
|
||||
"videojs-contrib-hls": "^5.15.0",
|
||||
"videojs-vtt.js": "^0.15.5"
|
||||
"xss": "^1.0.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^16.2.3",
|
||||
|
|
|
|||
257
pnpm-lock.yaml
257
pnpm-lock.yaml
|
|
@ -114,6 +114,9 @@ importers:
|
|||
mockjs:
|
||||
specifier: ^1.1.0
|
||||
version: 1.1.0
|
||||
mqtt:
|
||||
specifier: ^5.15.1
|
||||
version: 5.15.1
|
||||
nprogress:
|
||||
specifier: ^0.2.0
|
||||
version: 0.2.0
|
||||
|
|
@ -1061,6 +1064,10 @@ packages:
|
|||
resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/runtime@7.29.2':
|
||||
resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/standalone@7.28.5':
|
||||
resolution: {integrity: sha512-1DViPYJpRU50irpGMfLBQ9B4kyfQuL6X7SS7pwTeWeZX0mNkjzPi0XFqxCjSdddZXUQy4AhnQnnesA/ZHnvAdw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
|
@ -1899,6 +1906,9 @@ packages:
|
|||
'@types/raf@3.4.3':
|
||||
resolution: {integrity: sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==}
|
||||
|
||||
'@types/readable-stream@4.0.23':
|
||||
resolution: {integrity: sha512-wwXrtQvbMHxCbBgjHaMGEmImFTQxxpfMOR/ZoQnXxB1woqkUbdLGFDgauo00Py9IudiaqSeiBiulSV9i6XIPig==}
|
||||
|
||||
'@types/resolve@1.17.1':
|
||||
resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
|
||||
|
||||
|
|
@ -1932,6 +1942,9 @@ packages:
|
|||
'@types/trusted-types@2.0.7':
|
||||
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
|
||||
|
||||
'@types/ws@8.18.1':
|
||||
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
|
||||
|
||||
'@types/yargs-parser@21.0.3':
|
||||
resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
|
||||
|
||||
|
|
@ -2254,6 +2267,10 @@ packages:
|
|||
resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
|
||||
deprecated: Use your platform's native atob() and btoa() methods instead
|
||||
|
||||
abort-controller@3.0.0:
|
||||
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
||||
engines: {node: '>=6.5'}
|
||||
|
||||
acorn-globals@6.0.0:
|
||||
resolution: {integrity: sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==}
|
||||
|
||||
|
|
@ -2600,6 +2617,9 @@ packages:
|
|||
bl@4.1.0:
|
||||
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
|
||||
|
||||
bl@6.1.6:
|
||||
resolution: {integrity: sha512-jLsPgN/YSvPUg9UX0Kd73CXpm2Psg9FxMeCSXnk3WBO3CMT10JMwijubhGfHCnFu6TPn1ei3b975dxv7K2pWVg==}
|
||||
|
||||
bluebird@3.7.2:
|
||||
resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
|
||||
|
||||
|
|
@ -2620,6 +2640,9 @@ packages:
|
|||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
broker-factory@3.1.14:
|
||||
resolution: {integrity: sha512-L45k5HMbPIrMid0nTOZ/UPXG/c0aRuQKVrSDFIb1zOkvfiyHgYmIjc3cSiN1KwQIvRDOtKE0tfb3I9EZ3CmpQQ==}
|
||||
|
||||
browser-process-hrtime@1.0.0:
|
||||
resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==}
|
||||
|
||||
|
|
@ -2658,6 +2681,9 @@ packages:
|
|||
buffer@5.7.1:
|
||||
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
|
||||
|
||||
buffer@6.0.3:
|
||||
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
|
||||
|
||||
builtin-modules@3.3.0:
|
||||
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
|
||||
engines: {node: '>=6'}
|
||||
|
|
@ -2917,6 +2943,9 @@ packages:
|
|||
resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
|
||||
engines: {node: ^12.20.0 || >=14}
|
||||
|
||||
commist@3.2.0:
|
||||
resolution: {integrity: sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==}
|
||||
|
||||
commitizen@4.2.4:
|
||||
resolution: {integrity: sha512-LlZChbDzg3Ir3O2S7jSo/cgWp5/QwylQVr59K4xayVq8S4/RdKzSyJkghAiZZHfhh5t4pxunUoyeg0ml1q/7aw==}
|
||||
engines: {node: '>= 10'}
|
||||
|
|
@ -2938,6 +2967,10 @@ packages:
|
|||
concat-map@0.0.1:
|
||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||
|
||||
concat-stream@2.0.0:
|
||||
resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==}
|
||||
engines: {'0': node >= 6.0}
|
||||
|
||||
config-chain@1.1.13:
|
||||
resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
|
||||
|
||||
|
|
@ -3854,9 +3887,17 @@ packages:
|
|||
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
event-target-shim@5.0.1:
|
||||
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
eventemitter3@4.0.7:
|
||||
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
|
||||
|
||||
events@3.3.0:
|
||||
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
||||
engines: {node: '>=0.8.x'}
|
||||
|
||||
exec-buffer@3.2.0:
|
||||
resolution: {integrity: sha512-wsiD+2Tp6BWHoVv3B+5Dcx6E7u5zky+hUwOHjuH2hKSLR3dvRmX8fk8UD8uqQixHs4Wk6eDmiegVrMPjKj7wpA==}
|
||||
engines: {node: '>=4'}
|
||||
|
|
@ -3948,6 +3989,10 @@ packages:
|
|||
fast-levenshtein@2.0.6:
|
||||
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
|
||||
|
||||
fast-unique-numbers@9.0.27:
|
||||
resolution: {integrity: sha512-nDA9ADeINN8SA2u2wCtU+siWFTTDqQR37XvgPIDDmboWQeExz7X0mImxuaN+kJddliIqy2FpVRmnvRZ+j8i1/A==}
|
||||
engines: {node: '>=18.2.0'}
|
||||
|
||||
fast-uri@3.1.0:
|
||||
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
|
||||
|
||||
|
|
@ -4416,6 +4461,9 @@ packages:
|
|||
header-case@2.0.4:
|
||||
resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==}
|
||||
|
||||
help-me@5.0.0:
|
||||
resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==}
|
||||
|
||||
homedir-polyfill@1.0.3:
|
||||
resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
|
@ -4618,6 +4666,10 @@ packages:
|
|||
intro.js@5.1.0:
|
||||
resolution: {integrity: sha512-zwWl/duTh00eeNcZRU4o4/xxloNYPFKs4n4lMRDNx59jZr+qRI0jSOnzqYMOuVftD4beGrmxBHz4k8qp9/dCMA==}
|
||||
|
||||
ip-address@10.1.0:
|
||||
resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==}
|
||||
engines: {node: '>= 12'}
|
||||
|
||||
is-accessor-descriptor@1.0.1:
|
||||
resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
|
@ -5112,6 +5164,9 @@ packages:
|
|||
js-base64@2.6.4:
|
||||
resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==}
|
||||
|
||||
js-sdsl@4.3.0:
|
||||
resolution: {integrity: sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==}
|
||||
|
||||
js-tokens@4.0.0:
|
||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||
|
||||
|
|
@ -5368,6 +5423,9 @@ packages:
|
|||
engines: {node: '>=0.10.0'}
|
||||
hasBin: true
|
||||
|
||||
lru-cache@10.4.3:
|
||||
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
||||
|
||||
lru-cache@4.1.5:
|
||||
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
|
||||
|
||||
|
|
@ -5573,6 +5631,14 @@ packages:
|
|||
resolution: {integrity: sha512-1FuyEWI5k2HcmhS1HkKnUAQV7yFPfXPht2DnRRGtoiiAAW+ESTbtEXIDpRkwdU+XyrQuwrIym7UkoPKsZ0SyFw==}
|
||||
hasBin: true
|
||||
|
||||
mqtt-packet@9.0.2:
|
||||
resolution: {integrity: sha512-MvIY0B8/qjq7bKxdN1eD+nrljoeaai+qjLJgfRn3TiMuz0pamsIWY2bFODPZMSNmabsLANXsLl4EMoWvlaTZWA==}
|
||||
|
||||
mqtt@5.15.1:
|
||||
resolution: {integrity: sha512-V1WnkGuJh3ec9QXzy5Iylw8OOBK+Xu1WhxcQ9mMpLThG+/JZIMV1PgLNRgIiqXhZnvnVLsuyxHl5A/3bHHbcAA==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
hasBin: true
|
||||
|
||||
mri@1.2.0:
|
||||
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
||||
engines: {node: '>=4'}
|
||||
|
|
@ -5693,6 +5759,9 @@ packages:
|
|||
nth-check@2.1.1:
|
||||
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
||||
|
||||
number-allocator@1.0.14:
|
||||
resolution: {integrity: sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==}
|
||||
|
||||
nwsapi@2.2.22:
|
||||
resolution: {integrity: sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ==}
|
||||
|
||||
|
|
@ -6283,6 +6352,10 @@ packages:
|
|||
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
readable-stream@4.7.0:
|
||||
resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
|
||||
readdirp@3.6.0:
|
||||
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
||||
engines: {node: '>=8.10.0'}
|
||||
|
|
@ -6654,6 +6727,10 @@ packages:
|
|||
resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
smart-buffer@4.2.0:
|
||||
resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
|
||||
engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
|
||||
|
||||
snake-case@3.0.4:
|
||||
resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==}
|
||||
|
||||
|
|
@ -6669,6 +6746,10 @@ packages:
|
|||
resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
socks@2.8.7:
|
||||
resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==}
|
||||
engines: {node: '>= 10.0.0', npm: '>= 3.0.0'}
|
||||
|
||||
sort-keys-length@1.0.1:
|
||||
resolution: {integrity: sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
|
@ -6749,6 +6830,10 @@ packages:
|
|||
split2@3.2.2:
|
||||
resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==}
|
||||
|
||||
split2@4.2.0:
|
||||
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
|
||||
engines: {node: '>= 10.x'}
|
||||
|
||||
split@1.0.1:
|
||||
resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==}
|
||||
|
||||
|
|
@ -7262,6 +7347,9 @@ packages:
|
|||
resolution: {integrity: sha512-q7QNVDGTdl702bVFiI5eY4l/HkgCM6at9KhcFbgUAzezHFbOVy4+0O/lCjsABEQwbZPravVfBIiBVGo89yzHFg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
typedarray@0.0.6:
|
||||
resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
|
||||
|
||||
typescript@4.6.3:
|
||||
resolution: {integrity: sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==}
|
||||
engines: {node: '>=4.2.0'}
|
||||
|
|
@ -7836,6 +7924,18 @@ packages:
|
|||
workbox-window@6.6.0:
|
||||
resolution: {integrity: sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==}
|
||||
|
||||
worker-factory@7.0.49:
|
||||
resolution: {integrity: sha512-lW7tpgy6aUv2dFsQhv1yv+XFzdkCf/leoKRTGMPVK5/die6RrUjqgJHJf556qO+ZfytNG6wPXc17E8zzsOLUDw==}
|
||||
|
||||
worker-timers-broker@8.0.16:
|
||||
resolution: {integrity: sha512-JyP3AvUGyPGbBGW7XiUewm2+0pN/aYo1QpVf5kdXAfkDZcN3p7NbWrG6XnyDEpDIvfHk/+LCnOW/NsuiU9riYA==}
|
||||
|
||||
worker-timers-worker@9.0.14:
|
||||
resolution: {integrity: sha512-/qF06C60sXmSLfUl7WglvrDIbspmPOM8UrG63Dnn4bi2x4/DfqHS/+dxF5B+MdHnYO5tVuZYLHdAodrKdabTIg==}
|
||||
|
||||
worker-timers@8.0.31:
|
||||
resolution: {integrity: sha512-ngkq5S6JuZyztom8tDgBzorLo9byhBMko/sXfgiUD945AuzKGg1GCgDMCC3NaYkicLpGKXutONM36wEX8UbBCA==}
|
||||
|
||||
wrap-ansi@6.2.0:
|
||||
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
|
||||
engines: {node: '>=8'}
|
||||
|
|
@ -7866,6 +7966,18 @@ packages:
|
|||
utf-8-validate:
|
||||
optional: true
|
||||
|
||||
ws@8.20.0:
|
||||
resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==}
|
||||
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
|
||||
|
||||
xe-utils@3.3.1:
|
||||
resolution: {integrity: sha512-OdQgl9WPV9dK3/djneFPrGX8z1M4neX+VOkzra5oONjoNsCKQhwdiut99WlxceNMQ5vXDv4EQ/wKA2fux3Gdug==}
|
||||
|
||||
|
|
@ -8709,6 +8821,8 @@ snapshots:
|
|||
|
||||
'@babel/runtime@7.28.4': {}
|
||||
|
||||
'@babel/runtime@7.29.2': {}
|
||||
|
||||
'@babel/standalone@7.28.5': {}
|
||||
|
||||
'@babel/template@7.27.2':
|
||||
|
|
@ -9795,6 +9909,10 @@ snapshots:
|
|||
'@types/raf@3.4.3':
|
||||
optional: true
|
||||
|
||||
'@types/readable-stream@4.0.23':
|
||||
dependencies:
|
||||
'@types/node': 17.0.25
|
||||
|
||||
'@types/resolve@1.17.1':
|
||||
dependencies:
|
||||
'@types/node': 17.0.25
|
||||
|
|
@ -9827,6 +9945,10 @@ snapshots:
|
|||
|
||||
'@types/trusted-types@2.0.7': {}
|
||||
|
||||
'@types/ws@8.18.1':
|
||||
dependencies:
|
||||
'@types/node': 17.0.25
|
||||
|
||||
'@types/yargs-parser@21.0.3': {}
|
||||
|
||||
'@types/yargs@16.0.11':
|
||||
|
|
@ -10284,6 +10406,10 @@ snapshots:
|
|||
|
||||
abab@2.0.6: {}
|
||||
|
||||
abort-controller@3.0.0:
|
||||
dependencies:
|
||||
event-target-shim: 5.0.1
|
||||
|
||||
acorn-globals@6.0.0:
|
||||
dependencies:
|
||||
acorn: 7.4.1
|
||||
|
|
@ -10671,6 +10797,13 @@ snapshots:
|
|||
inherits: 2.0.4
|
||||
readable-stream: 3.6.2
|
||||
|
||||
bl@6.1.6:
|
||||
dependencies:
|
||||
'@types/readable-stream': 4.0.23
|
||||
buffer: 6.0.3
|
||||
inherits: 2.0.4
|
||||
readable-stream: 4.7.0
|
||||
|
||||
bluebird@3.7.2: {}
|
||||
|
||||
boolbase@1.0.0: {}
|
||||
|
|
@ -10703,6 +10836,13 @@ snapshots:
|
|||
dependencies:
|
||||
fill-range: 7.1.1
|
||||
|
||||
broker-factory@3.1.14:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.2
|
||||
fast-unique-numbers: 9.0.27
|
||||
tslib: 2.8.1
|
||||
worker-factory: 7.0.49
|
||||
|
||||
browser-process-hrtime@1.0.0: {}
|
||||
|
||||
browserslist@4.28.0:
|
||||
|
|
@ -10741,6 +10881,11 @@ snapshots:
|
|||
base64-js: 1.5.1
|
||||
ieee754: 1.2.1
|
||||
|
||||
buffer@6.0.3:
|
||||
dependencies:
|
||||
base64-js: 1.5.1
|
||||
ieee754: 1.2.1
|
||||
|
||||
builtin-modules@3.3.0: {}
|
||||
|
||||
builtins@4.1.0:
|
||||
|
|
@ -11034,6 +11179,8 @@ snapshots:
|
|||
|
||||
commander@9.5.0: {}
|
||||
|
||||
commist@3.2.0: {}
|
||||
|
||||
commitizen@4.2.4(@types/node@17.0.25)(typescript@4.6.3):
|
||||
dependencies:
|
||||
cachedir: 2.2.0
|
||||
|
|
@ -11067,6 +11214,13 @@ snapshots:
|
|||
|
||||
concat-map@0.0.1: {}
|
||||
|
||||
concat-stream@2.0.0:
|
||||
dependencies:
|
||||
buffer-from: 1.1.2
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.2
|
||||
typedarray: 0.0.6
|
||||
|
||||
config-chain@1.1.13:
|
||||
dependencies:
|
||||
ini: 1.3.8
|
||||
|
|
@ -12089,8 +12243,12 @@ snapshots:
|
|||
|
||||
etag@1.8.1: {}
|
||||
|
||||
event-target-shim@5.0.1: {}
|
||||
|
||||
eventemitter3@4.0.7: {}
|
||||
|
||||
events@3.3.0: {}
|
||||
|
||||
exec-buffer@3.2.0:
|
||||
dependencies:
|
||||
execa: 0.7.0
|
||||
|
|
@ -12233,6 +12391,11 @@ snapshots:
|
|||
|
||||
fast-levenshtein@2.0.6: {}
|
||||
|
||||
fast-unique-numbers@9.0.27:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.2
|
||||
tslib: 2.8.1
|
||||
|
||||
fast-uri@3.1.0: {}
|
||||
|
||||
fast-xml-parser@4.5.3:
|
||||
|
|
@ -12767,6 +12930,8 @@ snapshots:
|
|||
capital-case: 1.0.4
|
||||
tslib: 2.8.1
|
||||
|
||||
help-me@5.0.0: {}
|
||||
|
||||
homedir-polyfill@1.0.3:
|
||||
dependencies:
|
||||
parse-passwd: 1.0.0
|
||||
|
|
@ -13031,6 +13196,8 @@ snapshots:
|
|||
|
||||
intro.js@5.1.0: {}
|
||||
|
||||
ip-address@10.1.0: {}
|
||||
|
||||
is-accessor-descriptor@1.0.1:
|
||||
dependencies:
|
||||
hasown: 2.0.2
|
||||
|
|
@ -13712,6 +13879,8 @@ snapshots:
|
|||
|
||||
js-base64@2.6.4: {}
|
||||
|
||||
js-sdsl@4.3.0: {}
|
||||
|
||||
js-tokens@4.0.0: {}
|
||||
|
||||
js-yaml@3.14.2:
|
||||
|
|
@ -14002,6 +14171,8 @@ snapshots:
|
|||
longest: 1.0.1
|
||||
meow: 3.7.0
|
||||
|
||||
lru-cache@10.4.3: {}
|
||||
|
||||
lru-cache@4.1.5:
|
||||
dependencies:
|
||||
pseudomap: 1.0.2
|
||||
|
|
@ -14233,6 +14404,37 @@ snapshots:
|
|||
'@xmldom/xmldom': 0.8.11
|
||||
global: 4.4.0
|
||||
|
||||
mqtt-packet@9.0.2:
|
||||
dependencies:
|
||||
bl: 6.1.6
|
||||
debug: 4.4.3(supports-color@9.4.0)
|
||||
process-nextick-args: 2.0.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mqtt@5.15.1:
|
||||
dependencies:
|
||||
'@types/readable-stream': 4.0.23
|
||||
'@types/ws': 8.18.1
|
||||
commist: 3.2.0
|
||||
concat-stream: 2.0.0
|
||||
debug: 4.4.3(supports-color@9.4.0)
|
||||
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.7
|
||||
split2: 4.2.0
|
||||
worker-timers: 8.0.31
|
||||
ws: 8.20.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
mri@1.2.0: {}
|
||||
|
||||
ms@2.0.0: {}
|
||||
|
|
@ -14368,6 +14570,13 @@ snapshots:
|
|||
dependencies:
|
||||
boolbase: 1.0.0
|
||||
|
||||
number-allocator@1.0.14:
|
||||
dependencies:
|
||||
debug: 4.4.3(supports-color@9.4.0)
|
||||
js-sdsl: 4.3.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
nwsapi@2.2.22: {}
|
||||
|
||||
object-assign@4.1.1: {}
|
||||
|
|
@ -14922,6 +15131,14 @@ snapshots:
|
|||
string_decoder: 1.3.0
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
readable-stream@4.7.0:
|
||||
dependencies:
|
||||
abort-controller: 3.0.0
|
||||
buffer: 6.0.3
|
||||
events: 3.3.0
|
||||
process: 0.11.10
|
||||
string_decoder: 1.3.0
|
||||
|
||||
readdirp@3.6.0:
|
||||
dependencies:
|
||||
picomatch: 2.3.1
|
||||
|
|
@ -15305,6 +15522,8 @@ snapshots:
|
|||
ansi-styles: 6.2.3
|
||||
is-fullwidth-code-point: 4.0.0
|
||||
|
||||
smart-buffer@4.2.0: {}
|
||||
|
||||
snake-case@3.0.4:
|
||||
dependencies:
|
||||
dot-case: 3.0.4
|
||||
|
|
@ -15333,6 +15552,11 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
socks@2.8.7:
|
||||
dependencies:
|
||||
ip-address: 10.1.0
|
||||
smart-buffer: 4.2.0
|
||||
|
||||
sort-keys-length@1.0.1:
|
||||
dependencies:
|
||||
sort-keys: 1.1.2
|
||||
|
|
@ -15404,6 +15628,8 @@ snapshots:
|
|||
dependencies:
|
||||
readable-stream: 3.6.2
|
||||
|
||||
split2@4.2.0: {}
|
||||
|
||||
split@1.0.1:
|
||||
dependencies:
|
||||
through: 2.3.8
|
||||
|
|
@ -16002,6 +16228,8 @@ snapshots:
|
|||
typed-array-buffer: 1.0.3
|
||||
typed-array-byte-offset: 1.0.4
|
||||
|
||||
typedarray@0.0.6: {}
|
||||
|
||||
typescript@4.6.3: {}
|
||||
|
||||
uglify-js@3.19.3:
|
||||
|
|
@ -16754,6 +16982,33 @@ snapshots:
|
|||
'@types/trusted-types': 2.0.7
|
||||
workbox-core: 6.6.0
|
||||
|
||||
worker-factory@7.0.49:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.2
|
||||
fast-unique-numbers: 9.0.27
|
||||
tslib: 2.8.1
|
||||
|
||||
worker-timers-broker@8.0.16:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.2
|
||||
broker-factory: 3.1.14
|
||||
fast-unique-numbers: 9.0.27
|
||||
tslib: 2.8.1
|
||||
worker-timers-worker: 9.0.14
|
||||
|
||||
worker-timers-worker@9.0.14:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.2
|
||||
tslib: 2.8.1
|
||||
worker-factory: 7.0.49
|
||||
|
||||
worker-timers@8.0.31:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.2
|
||||
tslib: 2.8.1
|
||||
worker-timers-broker: 8.0.16
|
||||
worker-timers-worker: 9.0.14
|
||||
|
||||
wrap-ansi@6.2.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
|
|
@ -16782,6 +17037,8 @@ snapshots:
|
|||
|
||||
ws@7.5.10: {}
|
||||
|
||||
ws@8.20.0: {}
|
||||
|
||||
xe-utils@3.3.1: {}
|
||||
|
||||
xhr@2.4.0:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,312 @@
|
|||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import mqtt, { MqttClient, IClientOptions } from 'mqtt';
|
||||
import { mqttConfig } from '@/config/mqtt';
|
||||
|
||||
export function useMqtt() {
|
||||
// 状态
|
||||
const client = ref<MqttClient | null>(null);
|
||||
const isConnected = ref(false);
|
||||
const isConnecting = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
const messages = ref<Array<{ topic: string; payload: string; timestamp: number }>>([]);
|
||||
|
||||
// 消息处理器映射
|
||||
const messageHandlers = new Map<string, (payload: string, topic: string) => void>();
|
||||
|
||||
/**
|
||||
* 连接 MQTT
|
||||
*/
|
||||
const connect = () => {
|
||||
if (client.value && isConnected.value) {
|
||||
console.warn('MQTT 已经连接');
|
||||
return;
|
||||
}
|
||||
|
||||
if (isConnecting.value) {
|
||||
console.warn('MQTT 正在连接中');
|
||||
return;
|
||||
}
|
||||
|
||||
isConnecting.value = true;
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
console.log('开始连接 MQTT...', mqttConfig.brokerUrl);
|
||||
|
||||
// 创建客户端
|
||||
client.value = mqtt.connect(mqttConfig.brokerUrl, mqttConfig.options);
|
||||
|
||||
// 连接成功
|
||||
client.value.on('connect', () => {
|
||||
console.log('MQTT 连接成功');
|
||||
isConnected.value = true;
|
||||
isConnecting.value = false;
|
||||
error.value = null;
|
||||
|
||||
// 订阅主题
|
||||
subscribeTopics();
|
||||
});
|
||||
|
||||
// 连接错误
|
||||
client.value.on('error', (err) => {
|
||||
console.error('MQTT 连接错误:', err);
|
||||
error.value = err.message;
|
||||
isConnected.value = false;
|
||||
isConnecting.value = false;
|
||||
});
|
||||
|
||||
// 连接关闭
|
||||
client.value.on('close', () => {
|
||||
console.log('MQTT 连接关闭');
|
||||
isConnected.value = false;
|
||||
isConnecting.value = false;
|
||||
});
|
||||
|
||||
// 收到消息
|
||||
client.value.on('message', (topic, message) => {
|
||||
const payload = message.toString();
|
||||
console.log('收到消息:', topic, payload);
|
||||
|
||||
// 存储消息
|
||||
messages.value.unshift({
|
||||
topic,
|
||||
payload,
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
// 限制消息数量
|
||||
if (messages.value.length > 100) {
|
||||
messages.value.pop();
|
||||
}
|
||||
|
||||
// 调用对应的处理器
|
||||
const handler = messageHandlers.get(topic);
|
||||
if (handler) {
|
||||
handler(payload, topic);
|
||||
}
|
||||
|
||||
// 通配符匹配
|
||||
for (const [pattern, handler] of messageHandlers.entries()) {
|
||||
if (pattern.includes('+') || pattern.includes('#')) {
|
||||
if (matchTopic(pattern, topic)) {
|
||||
handler(payload, topic);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 重连
|
||||
client.value.on('reconnect', () => {
|
||||
console.log('MQTT 正在重连...');
|
||||
});
|
||||
|
||||
// 离线
|
||||
client.value.on('offline', () => {
|
||||
console.log('MQTT 离线');
|
||||
isConnected.value = false;
|
||||
});
|
||||
} catch (err: any) {
|
||||
console.error('创建 MQTT 客户端失败:', err);
|
||||
error.value = err.message;
|
||||
isConnecting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 订阅主题
|
||||
*/
|
||||
const subscribeTopics = () => {
|
||||
if (!client.value || !isConnected.value) {
|
||||
console.warn('MQTT 未连接,无法订阅');
|
||||
return;
|
||||
}
|
||||
|
||||
mqttConfig.topics.forEach(({ topic, qos }) => {
|
||||
client.value!.subscribe(topic, { qos }, (err) => {
|
||||
if (err) {
|
||||
console.error(`订阅主题失败: ${topic}`, err);
|
||||
} else {
|
||||
console.log(`订阅主题成功: ${topic} (QoS: ${qos})`);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 订阅单个主题
|
||||
*/
|
||||
const subscribe = (topic: string, qos: number = 1): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!client.value || !isConnected.value) {
|
||||
reject(new Error('MQTT 未连接'));
|
||||
return;
|
||||
}
|
||||
|
||||
client.value.subscribe(topic, { qos }, (err) => {
|
||||
if (err) {
|
||||
console.error(`订阅主题失败: ${topic}`, err);
|
||||
reject(err);
|
||||
} else {
|
||||
console.log(`订阅主题成功: ${topic}`);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消订阅
|
||||
*/
|
||||
const unsubscribe = (topic: string): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!client.value || !isConnected.value) {
|
||||
reject(new Error('MQTT 未连接'));
|
||||
return;
|
||||
}
|
||||
|
||||
client.value.unsubscribe(topic, (err) => {
|
||||
if (err) {
|
||||
console.error(`取消订阅失败: ${topic}`, err);
|
||||
reject(err);
|
||||
} else {
|
||||
console.log(`取消订阅成功: ${topic}`);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 发布消息
|
||||
*/
|
||||
const publish = (topic: string, payload: string | object, qos: number = 1, retain: boolean = false): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!client.value || !isConnected.value) {
|
||||
reject(new Error('MQTT 未连接'));
|
||||
return;
|
||||
}
|
||||
|
||||
let message: string;
|
||||
if (typeof payload === 'object') {
|
||||
message = JSON.stringify(payload);
|
||||
} else {
|
||||
message = payload;
|
||||
}
|
||||
|
||||
client.value.publish(topic, message, { qos, retain }, (err) => {
|
||||
if (err) {
|
||||
console.error(`发布消息失败: ${topic}`, err);
|
||||
reject(err);
|
||||
} else {
|
||||
console.log(`发布消息成功: ${topic}`);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 发送设备控制指令
|
||||
*/
|
||||
const sendDeviceCommand = (deviceId: string, command: string, params?: any): Promise<void> => {
|
||||
const topic = `lanhai/device/${deviceId}/command`;
|
||||
const payload = {
|
||||
command,
|
||||
params: params || {},
|
||||
timestamp: Date.now(),
|
||||
requestId: generateRequestId(),
|
||||
};
|
||||
return publish(topic, payload, 1, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* 注册消息处理器
|
||||
*/
|
||||
const onMessage = (topic: string, handler: (payload: string, topic: string) => void) => {
|
||||
messageHandlers.set(topic, handler);
|
||||
};
|
||||
|
||||
/**
|
||||
* 移除消息处理器
|
||||
*/
|
||||
const offMessage = (topic: string) => {
|
||||
messageHandlers.delete(topic);
|
||||
};
|
||||
|
||||
/**
|
||||
* 清空消息记录
|
||||
*/
|
||||
const clearMessages = () => {
|
||||
messages.value = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* 断开连接
|
||||
*/
|
||||
const disconnect = () => {
|
||||
if (client.value) {
|
||||
client.value.end();
|
||||
client.value = null;
|
||||
isConnected.value = false;
|
||||
messageHandlers.clear();
|
||||
console.log('MQTT 已断开连接');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 生成请求ID
|
||||
*/
|
||||
const generateRequestId = (): string => {
|
||||
return `${Date.now()}-${Math.random().toString(36).substring(2, 10)}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* 主题匹配(支持通配符)
|
||||
*/
|
||||
const matchTopic = (pattern: string, topic: string): boolean => {
|
||||
const patternParts = pattern.split('/');
|
||||
const topicParts = topic.split('/');
|
||||
|
||||
if (patternParts.length > topicParts.length && patternParts[patternParts.length - 1] !== '#') {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < patternParts.length; i++) {
|
||||
if (patternParts[i] === '+') continue;
|
||||
if (patternParts[i] === '#') return true;
|
||||
if (patternParts[i] !== topicParts[i]) return false;
|
||||
}
|
||||
|
||||
return patternParts.length === topicParts.length;
|
||||
};
|
||||
|
||||
// 自动连接
|
||||
onMounted(() => {
|
||||
connect();
|
||||
});
|
||||
|
||||
// 断开连接
|
||||
onUnmounted(() => {
|
||||
disconnect();
|
||||
});
|
||||
|
||||
return {
|
||||
// 状态
|
||||
client,
|
||||
isConnected,
|
||||
isConnecting,
|
||||
error,
|
||||
messages,
|
||||
|
||||
// 方法
|
||||
connect,
|
||||
disconnect,
|
||||
publish,
|
||||
subscribe,
|
||||
unsubscribe,
|
||||
sendDeviceCommand,
|
||||
onMessage,
|
||||
offMessage,
|
||||
clearMessages,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
import { ref, onMounted, onUnmounted, type Ref } from 'vue';
|
||||
import mqtt, { MqttClient } from 'mqtt';
|
||||
|
||||
interface MqttOptions {
|
||||
brokerUrl: string;
|
||||
clientId?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
keepalive?: number;
|
||||
reconnectPeriod?: number;
|
||||
}
|
||||
|
||||
export function usePageMqtt(options: MqttOptions) {
|
||||
// 状态
|
||||
const client = ref<MqttClient | null>(null);
|
||||
const isConnected = ref(false);
|
||||
const isConnecting = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
|
||||
// 消息处理器
|
||||
let messageHandler: ((payload: string, topic: string) => void) | null = null;
|
||||
let currentTopic: string | null = null;
|
||||
|
||||
/**
|
||||
* 连接 MQTT 并订阅主题
|
||||
*/
|
||||
const connectAndSubscribe = (topic: string, handler: (payload: string, topic: string) => void) => {
|
||||
if (client.value && isConnected.value) {
|
||||
console.warn('MQTT 已连接,直接订阅');
|
||||
subscribeTopic(topic, handler);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isConnecting.value) {
|
||||
console.warn('MQTT 正在连接中');
|
||||
return;
|
||||
}
|
||||
|
||||
currentTopic = topic;
|
||||
messageHandler = handler;
|
||||
isConnecting.value = true;
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
// 生成唯一客户端ID
|
||||
const clientId = options.clientId || `page-${Date.now()}-${Math.random().toString(16).substring(2, 8)}`;
|
||||
|
||||
// 连接配置
|
||||
const connectOptions = {
|
||||
clientId,
|
||||
username: options.username,
|
||||
password: options.password,
|
||||
keepalive: options.keepalive || 60,
|
||||
clean: true,
|
||||
reconnectPeriod: options.reconnectPeriod || 5000,
|
||||
connectTimeout: 30 * 1000,
|
||||
};
|
||||
|
||||
console.log('开始连接 MQTT...', options.brokerUrl);
|
||||
|
||||
// 创建客户端
|
||||
client.value = mqtt.connect(options.brokerUrl, connectOptions);
|
||||
|
||||
// 连接成功
|
||||
client.value.on('connect', () => {
|
||||
console.log('MQTT 连接成功');
|
||||
isConnected.value = true;
|
||||
isConnecting.value = false;
|
||||
|
||||
// 订阅主题
|
||||
if (currentTopic && messageHandler) {
|
||||
subscribeTopic(currentTopic, messageHandler);
|
||||
}
|
||||
});
|
||||
|
||||
// 连接错误
|
||||
client.value.on('error', (err) => {
|
||||
console.error('MQTT 连接错误:', err);
|
||||
error.value = err.message;
|
||||
isConnected.value = false;
|
||||
isConnecting.value = false;
|
||||
});
|
||||
|
||||
// 连接关闭
|
||||
client.value.on('close', () => {
|
||||
console.log('MQTT 连接关闭');
|
||||
isConnected.value = false;
|
||||
});
|
||||
|
||||
// 收到消息
|
||||
client.value.on('message', (topic, message) => {
|
||||
const payload = message.toString();
|
||||
console.log('收到消息:', topic, payload);
|
||||
|
||||
// 调用消息处理器
|
||||
if (messageHandler) {
|
||||
messageHandler(payload, topic);
|
||||
}
|
||||
});
|
||||
|
||||
// 重连
|
||||
client.value.on('reconnect', () => {
|
||||
console.log('MQTT 正在重连...');
|
||||
});
|
||||
|
||||
// 离线
|
||||
client.value.on('offline', () => {
|
||||
console.log('MQTT 离线');
|
||||
isConnected.value = false;
|
||||
});
|
||||
} catch (err: any) {
|
||||
console.error('创建 MQTT 客户端失败:', err);
|
||||
error.value = err.message;
|
||||
isConnecting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 订阅主题
|
||||
*/
|
||||
const subscribeTopic = (topic: string, handler: (payload: string, topic: string) => void) => {
|
||||
if (!client.value || !isConnected.value) {
|
||||
console.warn('MQTT 未连接,无法订阅');
|
||||
return;
|
||||
}
|
||||
|
||||
messageHandler = handler;
|
||||
currentTopic = topic;
|
||||
|
||||
client.value.subscribe(topic, { qos: 1 }, (err) => {
|
||||
if (err) {
|
||||
console.error(`订阅主题失败: ${topic}`, err);
|
||||
error.value = `订阅失败: ${err.message}`;
|
||||
} else {
|
||||
console.log(`订阅主题成功: ${topic}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 发布消息
|
||||
*/
|
||||
const publish = (topic: string, payload: string | object, qos: number = 1): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!client.value || !isConnected.value) {
|
||||
reject(new Error('MQTT 未连接'));
|
||||
return;
|
||||
}
|
||||
|
||||
const message = typeof payload === 'object' ? JSON.stringify(payload) : payload;
|
||||
|
||||
client.value.publish(topic, message, { qos }, (err) => {
|
||||
if (err) {
|
||||
console.error(`发布消息失败: ${topic}`, err);
|
||||
reject(err);
|
||||
} else {
|
||||
console.log(`发布消息成功: ${topic}`);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 断开连接并销毁
|
||||
*/
|
||||
const disconnect = () => {
|
||||
if (client.value) {
|
||||
// 取消订阅
|
||||
if (currentTopic) {
|
||||
client.value.unsubscribe(currentTopic, (err) => {
|
||||
if (err) {
|
||||
console.error(`取消订阅失败: ${currentTopic}`, err);
|
||||
} else {
|
||||
console.log(`取消订阅成功: ${currentTopic}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 断开连接
|
||||
client.value.end(true, () => {
|
||||
console.log('MQTT 连接已关闭');
|
||||
});
|
||||
|
||||
client.value = null;
|
||||
isConnected.value = false;
|
||||
messageHandler = null;
|
||||
currentTopic = null;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
// 状态
|
||||
isConnected,
|
||||
isConnecting,
|
||||
error,
|
||||
|
||||
// 方法
|
||||
connectAndSubscribe,
|
||||
publish,
|
||||
disconnect,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
export const mqttConfig = {
|
||||
// MQTT 服务器地址
|
||||
brokerUrl: 'ws://mqtt.ilhzn.cn:10007', // WebSocket 连接
|
||||
// brokerUrl: 'wss://mqtt.example.com:8084/mqtt', // 使用 SSL
|
||||
|
||||
// 连接选项
|
||||
options: {
|
||||
clientId: `vue3-mqtt-${Math.random().toString(16).substring(2, 8)}`,
|
||||
username: 'lhzn.mqtt',
|
||||
password: 'lhzn.2025',
|
||||
keepalive: 60,
|
||||
clean: true,
|
||||
reconnectPeriod: 5000, // 自动重连间隔(ms)
|
||||
connectTimeout: 30 * 1000,
|
||||
|
||||
// SSL 配置(如果使用 wss)
|
||||
// rejectUnauthorized: false,
|
||||
|
||||
// 遗嘱消息
|
||||
will: {
|
||||
topic: 'app/status',
|
||||
payload: 'offline',
|
||||
qos: 1,
|
||||
retain: true,
|
||||
},
|
||||
},
|
||||
|
||||
// 订阅主题
|
||||
topics: [
|
||||
{ topic: 'app/receive', qos: 1 },
|
||||
{ topic: 'app/status', qos: 0 },
|
||||
{ topic: 'lanhai/device/+/command', qos: 1 },
|
||||
],
|
||||
};
|
||||
|
|
@ -4,8 +4,7 @@
|
|||
<div class="jeecg-basic-table-form-container">
|
||||
<a-form ref="formRef" @keyup.enter.native="searchQuery" :model="queryParam" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-row :gutter="24">
|
||||
|
||||
<a-col :xs="24" :sm="8" :md="6" :lg="8" :xl="6" :xxl="6" style="margin-left:-10px;margin-top: 16px;">
|
||||
<a-col :xs="24" :sm="8" :md="6" :lg="8" :xl="6" :xxl="6" style="margin-left: -10px; margin-top: 16px">
|
||||
<a-form-item label="选择监测站" name="stationCode">
|
||||
<ApiSelect
|
||||
:api="getStationList"
|
||||
|
|
@ -20,7 +19,7 @@
|
|||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :xs="24" :sm="8" :md="6" :lg="8" :xl="6" :xxl="6" style="margin-left:-10px;margin-top: 16px;">
|
||||
<a-col :xs="24" :sm="8" :md="6" :lg="8" :xl="6" :xxl="6" style="margin-left: -10px; margin-top: 16px">
|
||||
<a-form-item label="选择设备类型" name="deployType">
|
||||
<ApiSelect
|
||||
:api="getDeviceCateList"
|
||||
|
|
@ -35,14 +34,14 @@
|
|||
</a-form-item>
|
||||
</a-col>
|
||||
<template v-if="toggleSearchStatus">
|
||||
<a-col :xs="24" :sm="8" :md="6" :lg="8" :xl="6" :xxl="6" style="margin-left:-10px;margin-top: 16px;">
|
||||
<a-col :xs="24" :sm="8" :md="6" :lg="8" :xl="6" :xxl="6" style="margin-left: -10px; margin-top: 16px">
|
||||
<a-form-item label="设备部署编号" name="deployCode">
|
||||
<a-input placeholder="请输入部署编号查询" v-model:value="queryParam.deployCode"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</template>
|
||||
<span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
|
||||
<a-col :xs="24" :sm="8" :md="6" :lg="8" :xl="6" :xxl="6" style="margin-left:-10px;margin-top: 16px;">
|
||||
<a-col :xs="24" :sm="8" :md="6" :lg="8" :xl="6" :xxl="6" style="margin-left: -10px; margin-top: 16px">
|
||||
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
|
||||
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
|
||||
<a @click="toggleSearchStatus = !toggleSearchStatus" style="margin-left: 8px">
|
||||
|
|
@ -70,27 +69,27 @@
|
|||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button>批量操作
|
||||
<a-button
|
||||
>批量操作
|
||||
<Icon icon="mdi:chevron-down"></Icon>
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
|
||||
|
||||
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
|
||||
</template>
|
||||
<!--字段回显插槽-->
|
||||
<template #htmlSlot="{text}">
|
||||
<template #htmlSlot="{ text }">
|
||||
<div v-html="text"></div>
|
||||
</template>
|
||||
<!--省市区字段回显插槽-->
|
||||
<template #pcaSlot="{text}">
|
||||
<template #pcaSlot="{ text }">
|
||||
{{ getAreaTextByCode(text) }}
|
||||
</template>
|
||||
|
||||
<template #fileSlot="{text}">
|
||||
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
|
||||
<template #fileSlot="{ text }">
|
||||
<span v-if="!text" style="font-size: 12px; font-style: italic">无文件</span>
|
||||
<a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
|
@ -102,6 +101,8 @@
|
|||
<ZhiBiaoList @register="registerDrawer" />
|
||||
<SetupList @register="registerSetupDrawer" />
|
||||
<RelayGroupList @register="registerGroupDrawer" />
|
||||
<SetupRunList @register="registerSetupRunDrawer" />
|
||||
<RunGroupList @register="registerRunGroupDrawer" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -110,16 +111,18 @@
|
|||
import { BasicTable, useTable, TableAction } from '/@/components/Table';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { columns } from './SurvDeviceDeploy.data';
|
||||
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl,deviceInit,getDeviceCateList,relaySync} from './SurvDeviceDeploy.api';
|
||||
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl, deviceInit, getDeviceCateList, relaySync } from './SurvDeviceDeploy.api';
|
||||
import { downloadFile } from '/@/utils/common/renderUtils';
|
||||
import SurvDeviceDeployModal from './components/SurvDeviceDeployModal.vue'
|
||||
import ControlModal from './components/ControlModal.vue'
|
||||
import { ApiSelect} from '/@/components/Form/index';
|
||||
import { getStationList } from '../station/SurvStationInfo.api'
|
||||
import SurvDeviceDeployModal from './components/SurvDeviceDeployModal.vue';
|
||||
import ControlModal from './components/ControlModal.vue';
|
||||
import { ApiSelect } from '/@/components/Form/index';
|
||||
import { getStationList } from '../station/SurvStationInfo.api';
|
||||
import { useDrawer } from '/@/components/Drawer';
|
||||
import ZhiBiaoList from './components/ZhiBiaoList.vue';
|
||||
import SetupList from './components/SetupList.vue';
|
||||
import RelayGroupList from './components/RelayGroupList.vue';
|
||||
import SetupRunList from './components/SetupRunList.vue';
|
||||
import RunGroupList from './components/RunGroupList.vue';
|
||||
|
||||
//指标drawer
|
||||
const [registerDrawer, { openDrawer }] = useDrawer();
|
||||
|
|
@ -131,6 +134,8 @@
|
|||
const open = ref<boolean>(false);
|
||||
const [registerSetupDrawer, { openDrawer: openDrawerSetup }] = useDrawer();
|
||||
const [registerGroupDrawer, { openDrawer: openDrawerGroup }] = useDrawer();
|
||||
const [registerSetupRunDrawer, { openDrawer: openDrawerRunSetup }] = useDrawer();
|
||||
const [registerRunGroupDrawer, { openDrawer: openDrawerRunGroup }] = useDrawer();
|
||||
|
||||
//注册table数据
|
||||
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
|
||||
|
|
@ -138,7 +143,7 @@
|
|||
title: 'surv_device_deploy',
|
||||
api: list,
|
||||
columns,
|
||||
canResize:false,
|
||||
canResize: false,
|
||||
useSearchForm: false,
|
||||
actionColumn: {
|
||||
width: 260,
|
||||
|
|
@ -149,16 +154,17 @@
|
|||
},
|
||||
},
|
||||
exportConfig: {
|
||||
name: "surv_device_deploy",
|
||||
name: 'surv_device_deploy',
|
||||
url: getExportUrl,
|
||||
params: queryParam,
|
||||
},
|
||||
importConfig: {
|
||||
url: getImportUrl,
|
||||
success: handleSuccess
|
||||
success: handleSuccess,
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] =
|
||||
tableContext;
|
||||
const labelCol = reactive({
|
||||
xs: { span: 24 },
|
||||
sm: { span: 7 },
|
||||
|
|
@ -222,7 +228,6 @@
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 球阀控制
|
||||
*/
|
||||
|
|
@ -230,10 +235,11 @@
|
|||
qiuFaModal.value.disableSubmit = false;
|
||||
qiuFaModal.value.showup({
|
||||
deployId: record.id,
|
||||
receiveTopic: record.deviceReverseIotUrl,
|
||||
sendTopic: record.deviceIotUrl,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化设备
|
||||
*/
|
||||
|
|
@ -241,46 +247,44 @@
|
|||
await deviceInit({ ids: record.id }, handleSuccess);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
|
||||
if(record.deployType =="water_orient" || record.deployType =="water_live"){
|
||||
if (record.deployType == 'water_orient' || record.deployType == 'water_live') {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},{
|
||||
},
|
||||
{
|
||||
label: '指标配置',
|
||||
onClick: handleItem.bind(null, record),
|
||||
},{
|
||||
},
|
||||
{
|
||||
label: '球阀控制',
|
||||
onClick: handleControl.bind(null, record),
|
||||
},
|
||||
];
|
||||
}else{
|
||||
} else {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},{
|
||||
},
|
||||
{
|
||||
label: '指标配置',
|
||||
onClick: handleItem.bind(null, record),
|
||||
}
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 下拉操作栏
|
||||
*/
|
||||
function getDropDownAction(record) {
|
||||
|
||||
if(record.deployType == 'air'||record.deployType == 'soil'||record.deployType == '6_water'){
|
||||
if (record.deployType == 'air' || record.deployType == 'soil' || record.deployType == '6_water') {
|
||||
return [
|
||||
{
|
||||
label: '初始化设备',
|
||||
|
|
@ -289,17 +293,17 @@
|
|||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
}, {
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
placement: "leftBottom",
|
||||
placement: 'leftBottom',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
else if(record.deployType == 'control_cab' ){
|
||||
},
|
||||
},
|
||||
];
|
||||
} else if (record.deployType == 'control_cab') {
|
||||
return [
|
||||
{
|
||||
label: '继电器同步',
|
||||
|
|
@ -312,17 +316,17 @@
|
|||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
}, {
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
placement: "leftBottom",
|
||||
placement: 'leftBottom',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
else if(record.deployType =="water_orient" || record.deployType =="water_live"){
|
||||
},
|
||||
},
|
||||
];
|
||||
} else if (record.deployType == 'water_orient' || record.deployType == 'water_live') {
|
||||
return [
|
||||
{
|
||||
label: '控制配置',
|
||||
|
|
@ -333,38 +337,46 @@
|
|||
// onClick: handleRelay.bind(null, record),
|
||||
// },
|
||||
{
|
||||
label: '继电器分组',
|
||||
label: '控制分组',
|
||||
onClick: handleRelayGroup.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '运行状态配置',
|
||||
onClick: handleRunDetail.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '运行状态分组',
|
||||
onClick: handleRunGroup.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
}, {
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
placement: "leftBottom",
|
||||
placement: 'leftBottom',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
else{
|
||||
},
|
||||
},
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
}, {
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 继电器明细
|
||||
|
|
@ -384,6 +396,24 @@
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 继电器明细
|
||||
*/
|
||||
async function handleRunDetail(record: Recordable) {
|
||||
openDrawerRunSetup(true, {
|
||||
id: record.id,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 继电器分组
|
||||
*/
|
||||
async function handleRunGroup(record: Recordable) {
|
||||
openDrawerRunGroup(true, {
|
||||
id: record.id,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 继电器同步
|
||||
*/
|
||||
|
|
@ -407,10 +437,6 @@
|
|||
//刷新数据
|
||||
reload();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
@ -420,14 +446,14 @@
|
|||
margin-bottom: 24px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.query-group-cust{
|
||||
.query-group-cust {
|
||||
width: calc(50% - 15px);
|
||||
min-width: 100px !important;
|
||||
}
|
||||
.query-group-split-cust{
|
||||
.query-group-split-cust {
|
||||
width: 30px;
|
||||
display: inline-block;
|
||||
text-align: center
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@
|
|||
:labelStyle="{ fontWeight: 'bold', textAlign: 'center' }"
|
||||
:contentStyle="{ textAlign: 'center' }"
|
||||
>
|
||||
<a-descriptions-item :label="item.moduleName" v-for="item in formState.runList" :key="item.id">
|
||||
<span style="color: red">停止</span>
|
||||
<a-descriptions-item :label="item.runName" v-for="item in formState.runList" :key="item.id">
|
||||
<span style="color: red" v-if="item.value == '0'">停止</span>
|
||||
<span style="color: green" v-else-if="item.value == '1'">运行</span>
|
||||
<span style="color: orange" v-else>待同步</span>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
|
||||
|
|
@ -23,11 +25,13 @@
|
|||
<a-col :span="8" v-for="group in formState.moduleList" :key="group.id" class="card-col">
|
||||
<a-card :title="group.groupName" :bordered="true">
|
||||
<!-- <template #extra><a href="#">一键启动</a></template>-->
|
||||
<a-form-item :label="item.moduleName" v-for="item in group.modules" :key="item.id">
|
||||
<a-form-item :label="item.relayName" v-for="item in group.relayList" :key="item.id">
|
||||
<a-switch
|
||||
v-model:checked="formState[item.id]"
|
||||
v-model:checked="item.value"
|
||||
checked-children="打开"
|
||||
un-checked-children="关闭"
|
||||
:checked-value="'1'"
|
||||
:un-checked-value="'0'"
|
||||
@change="(checked) => switchChange(checked, item)"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
|
@ -42,10 +46,138 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, reactive, nextTick, defineExpose } from 'vue';
|
||||
import { onMounted, onUnmounted, ref, reactive, nextTick, defineExpose } from 'vue';
|
||||
import type { UnwrapRef } from 'vue';
|
||||
import { getValveStatus, sendDeviceCmd, getRelayList } from '../SurvDeviceDeploy.api';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { usePageMqtt } from '/@/components/mqtt/usePageMqtt';
|
||||
|
||||
// MQTT 配置
|
||||
const mqttOptions = {
|
||||
brokerUrl: import.meta.env.VITE_MQTT_BROKER_URL || 'ws://localhost:8083/mqtt',
|
||||
username: import.meta.env.VITE_MQTT_USERNAME || 'admin',
|
||||
password: import.meta.env.VITE_MQTT_PASSWORD || 'admin123',
|
||||
keepalive: 60,
|
||||
reconnectPeriod: 5000,
|
||||
};
|
||||
// 使用页面级 MQTT
|
||||
const { isConnected, isConnecting, error, connectAndSubscribe, publish, disconnect } = usePageMqtt(mqttOptions);
|
||||
|
||||
// 设备数据
|
||||
const deviceData = reactive({
|
||||
temperature: 0,
|
||||
humidity: 0,
|
||||
status: 'offline',
|
||||
lastUpdate: 0,
|
||||
});
|
||||
|
||||
// 消息日志
|
||||
interface LogEntry {
|
||||
id: number;
|
||||
topic: string;
|
||||
message: string;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
const logs = ref<LogEntry[]>([]);
|
||||
let logId = 0;
|
||||
|
||||
// 格式化时间
|
||||
const formatTime = (timestamp: number) => {
|
||||
if (!timestamp) return '--:--:--';
|
||||
return new Date(timestamp).toLocaleTimeString();
|
||||
};
|
||||
|
||||
// 添加日志
|
||||
const addLog = (topic: string, message: string) => {
|
||||
logs.value.unshift({
|
||||
id: logId++,
|
||||
topic,
|
||||
message: typeof message === 'object' ? JSON.stringify(message) : message,
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
// 保留最近100条日志
|
||||
if (logs.value.length > 100) {
|
||||
logs.value.pop();
|
||||
}
|
||||
};
|
||||
|
||||
// 处理接收到的消息
|
||||
const handleMessage = (payload: string, topic: string) => {
|
||||
// console.log('处理消息:', topic, payload);
|
||||
|
||||
try {
|
||||
const data = JSON.parse(payload);
|
||||
|
||||
// 添加日志
|
||||
addLog(topic, payload);
|
||||
|
||||
if (data.rw_prot !== undefined) {
|
||||
if (data.rw_prot.r_data !== undefined) {
|
||||
// 先构建源数据的 Map
|
||||
const sourceMap = data.rw_prot.r_data.reduce((map, item) => {
|
||||
map[item.name] = item.value;
|
||||
return map;
|
||||
}, {});
|
||||
|
||||
// 然后遍历目标数组赋值
|
||||
// 1.状态部分
|
||||
formState.runList.forEach((target) => {
|
||||
const source = sourceMap[target.runKey];
|
||||
if (source) {
|
||||
Object.assign(target, {
|
||||
value: source,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 2.控制项部分
|
||||
formState.moduleList.forEach((target) => {
|
||||
if (target.relayList) {
|
||||
// 遍历内层数组
|
||||
target.relayList.forEach((member) => {
|
||||
const source = sourceMap[member.relayKey];
|
||||
if (source) {
|
||||
Object.assign(member, {
|
||||
value: source,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
console.log('check-----', formState.moduleList);
|
||||
deviceData.temperature = data.temperature;
|
||||
}
|
||||
} catch (e) {
|
||||
// 非 JSON 格式,直接作为文本处理
|
||||
addLog(topic, payload);
|
||||
}
|
||||
};
|
||||
|
||||
// 发送设备控制指令
|
||||
const sendCommand = async (topic: string, command: string) => {
|
||||
if (!isConnected.value) {
|
||||
addLog('system', 'MQTT未连接,无法发送指令');
|
||||
return;
|
||||
}
|
||||
|
||||
// const payload = {
|
||||
// command,
|
||||
// timestamp: Date.now(),
|
||||
// requestId: `${Date.now()}-${Math.random().toString(36).substring(2, 10)}`,
|
||||
// };
|
||||
const payload = command;
|
||||
console.log('sendCommand===', topic, command);
|
||||
try {
|
||||
await publish(topic, payload);
|
||||
addLog(topic, `发送指令: ${command}`);
|
||||
} catch (err) {
|
||||
console.error('发送指令失败:', err);
|
||||
addLog(topic, `指令发送失败: ${command}`);
|
||||
}
|
||||
};
|
||||
|
||||
const bodystyle = {
|
||||
height: '1000px',
|
||||
|
|
@ -60,6 +192,7 @@
|
|||
dataTime: string;
|
||||
moduleList: [];
|
||||
runList: [];
|
||||
deployInfo: {};
|
||||
}
|
||||
const formState: UnwrapRef<FormState> = reactive({
|
||||
deployCode: '',
|
||||
|
|
@ -68,6 +201,7 @@
|
|||
dataTime: '',
|
||||
moduleList: [],
|
||||
runList: [],
|
||||
deployInfo: {},
|
||||
});
|
||||
|
||||
const labelCol = { style: { width: '150px' } };
|
||||
|
|
@ -84,22 +218,36 @@
|
|||
message.loading({ content: '发送指令中', key, duration: 7 });
|
||||
};
|
||||
|
||||
// 页面进入时连接 MQTT
|
||||
onMounted(() => {});
|
||||
|
||||
// 页面关闭时断开连接
|
||||
onUnmounted(() => {
|
||||
console.log('页面卸载,断开 MQTT...');
|
||||
disconnect();
|
||||
});
|
||||
|
||||
function switchChange(checked, relay) {
|
||||
openMessage();
|
||||
let ops = '';
|
||||
if (checked === true) {
|
||||
ops = '1';
|
||||
} else if (checked === false) {
|
||||
ops = '0';
|
||||
let ops = checked;
|
||||
// if (checked === true) {
|
||||
// ops = '1';
|
||||
// } else if (checked === false) {
|
||||
// ops = '0';
|
||||
// }
|
||||
// let parmas = { relayId: relay.id, ops: ops };
|
||||
// sendDeviceCmd(parmas).then((res) => {
|
||||
// if (res.code == 500) {
|
||||
// //操作失败
|
||||
// formState[relay.id] = false;
|
||||
// message.error({ content: res.message, key, duration: 2 });
|
||||
// }
|
||||
// });
|
||||
if ('1' == ops) {
|
||||
sendCommand(formState.deployInfo.sendTopic, relay.registerCmdOn);
|
||||
} else if ('0' == ops) {
|
||||
sendCommand(formState.deployInfo.sendTopic, relay.registerCmdOff);
|
||||
}
|
||||
let parmas = { relayId: relay.id, ops: ops };
|
||||
sendDeviceCmd(parmas).then((res) => {
|
||||
if (res.code == 500) {
|
||||
//操作失败
|
||||
formState[relay.id] = false;
|
||||
message.error({ content: res.message, key, duration: 2 });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function on1SwitchChange(checked) {
|
||||
|
|
@ -151,6 +299,15 @@
|
|||
formState.moduleList = [];
|
||||
formState.runList = [];
|
||||
formState.dataTime = '';
|
||||
formState.deployInfo = record;
|
||||
console.log(record);
|
||||
console.log('页面加载,连接 MQTT...', formState.deployInfo.receiveTopic);
|
||||
|
||||
// 需要订阅的主题
|
||||
const subscribeTopic = formState.deployInfo.receiveTopic; // 传感器数据主题
|
||||
|
||||
// 连接并订阅
|
||||
connectAndSubscribe(subscribeTopic, handleMessage);
|
||||
getRelayList({ deployId: record.deployId }).then((res) => {
|
||||
if (res.code == 200) {
|
||||
formState.moduleList = res.result.moduleList;
|
||||
|
|
@ -211,6 +368,7 @@
|
|||
*/
|
||||
function handleCancel() {
|
||||
visible.value = false;
|
||||
disconnect();
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ export const dictItemColumns: BasicColumn[] = [
|
|||
export const dictItemSearchFormSchema: FormSchema[] = [
|
||||
{
|
||||
label: '名称',
|
||||
field: 'relayName',
|
||||
field: 'groupName',
|
||||
component: 'Input',
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<BasicDrawer v-bind="$attrs" @register="registerDrawer" title="指标列表" width="800px">
|
||||
<BasicDrawer v-bind="$attrs" @register="registerDrawer" title="分组列表" width="800px">
|
||||
<BasicTable @register="registerTable" :rowClassName="getRowClassName">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" @click="handleCreate"> 新增</a-button>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,121 @@
|
|||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { useMessage } from "/@/hooks/web/useMessage";
|
||||
|
||||
const { createConfirm } = useMessage();
|
||||
|
||||
enum Api {
|
||||
list = '/appmana/survDeviceDeployRungroup/list',
|
||||
save='/appmana/survDeviceDeployRungroup/add',
|
||||
edit='/appmana/survDeviceDeployRungroup/edit',
|
||||
deleteOne = '/appmana/survDeviceDeployRungroup/delete',
|
||||
deleteBatch = '/appmana/survDeviceDeployRungroup/deleteBatch',
|
||||
importExcel = '/appmana/survDeviceDeployRungroup/importExcel',
|
||||
exportXls = '/appmana/survDeviceDeployRungroup/exportXls',
|
||||
itemList = '/appmana/survDeviceDeployRungroup/list',
|
||||
deleteItem = '/appmana/survDeviceDeployRungroup/delete',
|
||||
itemSave = '/appmana/survDeviceDeployRungroup/add',
|
||||
itemEdit = '/appmana/survDeviceDeployRungroup/edit',
|
||||
itemCheck ='/appmana/survDeviceDeployRungroup/itemCheck',
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出api
|
||||
* @param params
|
||||
*/
|
||||
export const getExportUrl = Api.exportXls;
|
||||
|
||||
/**
|
||||
* 导入api
|
||||
*/
|
||||
export const getImportUrl = Api.importExcel;
|
||||
|
||||
/**
|
||||
* 列表接口
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
|
||||
/**
|
||||
* 删除单个
|
||||
* @param params
|
||||
* @param handleSuccess
|
||||
*/
|
||||
export const deleteOne = (params,handleSuccess) => {
|
||||
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
* @param params
|
||||
* @param handleSuccess
|
||||
*/
|
||||
export const batchDelete = (params, handleSuccess) => {
|
||||
createConfirm({
|
||||
iconType: 'warning',
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
* @param isUpdate
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url: url, params }, { isTransformResponse: false });
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存或者更新配置
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdateDictItem = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.itemEdit : Api.itemSave;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdateDict = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 校验数据值
|
||||
* @param params
|
||||
*/
|
||||
export const itemCheck = (params) => defHttp.get({ url: Api.itemCheck, params }, { isTransformResponse: false });
|
||||
|
||||
/**
|
||||
* 列表
|
||||
* @param params
|
||||
*/
|
||||
export const itemList = (params) => defHttp.get({ url: Api.itemList, params });
|
||||
/**
|
||||
* 删除
|
||||
* @param params
|
||||
*/
|
||||
export const deleteItem = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteItem, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
import {BasicColumn} from '/@/components/Table';
|
||||
import {FormSchema} from '/@/components/Table';
|
||||
import { rules} from '/@/utils/helper/validator';
|
||||
import { render } from '/@/utils/common/renderUtils';
|
||||
import { itemCheck} from './RunGroup.api';
|
||||
|
||||
|
||||
//列表数据
|
||||
export const columns: BasicColumn[] = [
|
||||
{
|
||||
title: '创建者',
|
||||
align: "center",
|
||||
dataIndex: 'createId'
|
||||
},
|
||||
{
|
||||
title: '更新者',
|
||||
align: "center",
|
||||
dataIndex: 'updateId'
|
||||
},
|
||||
{
|
||||
title: '设备主键',
|
||||
align: "center",
|
||||
dataIndex: 'equId'
|
||||
},
|
||||
{
|
||||
title: '指标code',
|
||||
align: "center",
|
||||
dataIndex: 'code'
|
||||
},
|
||||
{
|
||||
title: '指标名称',
|
||||
align: "center",
|
||||
dataIndex: 'name'
|
||||
},
|
||||
{
|
||||
title: '低阈值',
|
||||
align: "center",
|
||||
dataIndex: 'valLow'
|
||||
},
|
||||
{
|
||||
title: '高阈值',
|
||||
align: "center",
|
||||
dataIndex: 'valHeight'
|
||||
},
|
||||
{
|
||||
title: '计量单位',
|
||||
align: "center",
|
||||
dataIndex: 'nuit'
|
||||
},
|
||||
];
|
||||
|
||||
//查询数据
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
];
|
||||
|
||||
//表单数据
|
||||
export const formSchema: FormSchema[] = [
|
||||
{
|
||||
label: '创建者',
|
||||
field: 'createId',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '更新者',
|
||||
field: 'updateId',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '设备主键',
|
||||
field: 'equId',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '指标code',
|
||||
field: 'code',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '指标名称',
|
||||
field: 'name',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '低阈值',
|
||||
field: 'valLow',
|
||||
component: 'InputNumber',
|
||||
},
|
||||
{
|
||||
label: '高阈值',
|
||||
field: 'valHeight',
|
||||
component: 'InputNumber',
|
||||
},
|
||||
{
|
||||
label: '计量单位',
|
||||
field: 'nuit',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '排序',
|
||||
field: 'sortNo',
|
||||
component: 'InputNumber',
|
||||
},
|
||||
// TODO 主键隐藏字段,目前写死为ID
|
||||
{
|
||||
label: '',
|
||||
field: 'id',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
|
||||
export const itemFormSchema: FormSchema[] = [
|
||||
{
|
||||
label: '',
|
||||
field: 'id',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
field: 'deployId',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: '分组名称',
|
||||
field: 'groupName',
|
||||
component: 'Input',
|
||||
dynamicRules: ({ values, model }) => {
|
||||
return [
|
||||
{
|
||||
required: true,
|
||||
validator: (_, value) => {
|
||||
if (!value) {
|
||||
return Promise.reject('请输入属性编码');
|
||||
}
|
||||
if (new RegExp("[`~!@#$^&*()=|{}'.<>《》/?!¥()—【】‘;:”“。,、?]").test(value)) {
|
||||
return Promise.reject('数据值不能包含特殊字符!');
|
||||
}
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
console.log('wwwwwww',model)
|
||||
let params = {
|
||||
deployId: model.deployId,
|
||||
groupName: value,
|
||||
id:model.id
|
||||
};
|
||||
itemCheck(params)
|
||||
.then((res) => {
|
||||
res.success ? resolve() : reject(res.message || '校验失败');
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err.message || '验证失败');
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '分组种类',
|
||||
field: 'groupType',
|
||||
required: true,
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'iot_run_group_type',
|
||||
placeholder: '请选择分组种类',
|
||||
stringToNumber: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'isEnable',
|
||||
label: '是否启用',
|
||||
defaultValue: 1,
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
type: 'radioButton',
|
||||
dictCode: 'yn',
|
||||
stringToNumber: true,
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
label: '备注',
|
||||
field: 'groupNotes',
|
||||
required: false,
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '排序',
|
||||
field: 'sortNo',
|
||||
required: false,
|
||||
component: 'InputNumber',
|
||||
defaultValue: 1
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
export const dictItemColumns: BasicColumn[] = [
|
||||
{
|
||||
title: '分组名称',
|
||||
dataIndex: 'groupName',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '分组类别',
|
||||
dataIndex: 'groupTypeName',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '是否启用',
|
||||
dataIndex: 'isEnable',
|
||||
width: 80,
|
||||
customRender: ({ text }) => {
|
||||
const color = text == '1' ? 'green' : text == '0' ? 'red' : 'gray';
|
||||
return render.renderTag(render.renderDict(text, 'dict_item_status'), color);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sortNo',
|
||||
width: 80,
|
||||
},
|
||||
];
|
||||
|
||||
export const dictItemSearchFormSchema: FormSchema[] = [
|
||||
{
|
||||
label: '名称',
|
||||
field: 'groupName',
|
||||
component: 'Input',
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
<template>
|
||||
<BasicDrawer v-bind="$attrs" @register="registerDrawer" title="状态分组列表" width="800px">
|
||||
<BasicTable @register="registerTable" :rowClassName="getRowClassName">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" @click="handleCreate"> 新增</a-button>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
</BasicDrawer>
|
||||
<RelayModal @register="registerModal" @success="reload" :deployId="deployId" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, unref } from 'vue';
|
||||
import { BasicDrawer, useDrawerInner } from '/src/components/Drawer';
|
||||
import { BasicTable, useTable, TableAction } from '/src/components/Table';
|
||||
import { useModal } from '/src/components/Modal';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import RelayModal from './RunGroupModal.vue';
|
||||
import { dictItemColumns, dictItemSearchFormSchema } from './RunGroup.data';
|
||||
import { itemList, deleteItem } from './RunGroup.api';
|
||||
import { ColEx } from '/@/components/Form/src/types';
|
||||
|
||||
const { prefixCls } = useDesign('row-invalid');
|
||||
const deployId = ref('');
|
||||
//协议配置model
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const [registerDrawer] = useDrawerInner(async (data) => {
|
||||
deployId.value = data.id;
|
||||
setProps({ searchInfo: { deployId: unref(deployId) } });
|
||||
reload();
|
||||
});
|
||||
// 自适应列配置
|
||||
const adaptiveColProps: Partial<ColEx> = {
|
||||
xs: 24, // <576px
|
||||
sm: 24, // ≥576px
|
||||
md: 24, // ≥768px
|
||||
lg: 12, // ≥992px
|
||||
xl: 12, // ≥1200px
|
||||
xxl: 8, // ≥1600px
|
||||
};
|
||||
const [registerTable, { reload, setProps }] = useTable({
|
||||
api: itemList,
|
||||
columns: dictItemColumns,
|
||||
formConfig: {
|
||||
baseColProps: adaptiveColProps,
|
||||
labelAlign: 'right',
|
||||
labelCol: {
|
||||
offset: 1,
|
||||
xs: 24,
|
||||
sm: 24,
|
||||
md: 24,
|
||||
lg: 9,
|
||||
xl: 7,
|
||||
xxl: 4,
|
||||
},
|
||||
wrapperCol: {},
|
||||
schemas: dictItemSearchFormSchema,
|
||||
autoSubmitOnEnter: true,
|
||||
},
|
||||
striped: true,
|
||||
useSearchForm: true,
|
||||
bordered: true,
|
||||
showIndexColumn: false,
|
||||
canResize: false,
|
||||
immediate: false,
|
||||
actionColumn: {
|
||||
width: 100,
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
slots: { customRender: 'action' },
|
||||
fixed: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
function handleCreate() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
function handleEdit(record) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
async function handleDelete(record) {
|
||||
await deleteItem({ id: record.id }, reload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
function getRowClassName(record) {
|
||||
return record.status == 0 ? prefixCls : '';
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
@prefix-cls: ~'@{namespace}-row-invalid';
|
||||
|
||||
:deep(.@{prefix-cls}) {
|
||||
background: #f4f4f4;
|
||||
color: #bababa;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit" width="800px">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, ref, computed, unref, reactive } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/src/components/Modal';
|
||||
import { BasicForm, useForm } from '/src/components/Form';
|
||||
import { itemFormSchema } from './RunGroup.data';
|
||||
import { saveOrUpdateDictItem } from './RunGroup.api';
|
||||
import { stringify } from 'querystring';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
const props = defineProps({ deployId: String });
|
||||
const isUpdate = ref(true);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
schemas: itemFormSchema,
|
||||
showActionButtonGroup: false,
|
||||
mergeDynamicData: props,
|
||||
labelCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 4 },
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 18 },
|
||||
},
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
//表单赋值
|
||||
await setFieldsValue({
|
||||
...data.record,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//设置标题
|
||||
const getTitle = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
|
||||
//表单提交事件
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
values.deployId = props.deployId;
|
||||
setModalProps({ confirmLoading: true });
|
||||
//提交表单
|
||||
await saveOrUpdateDictItem(values, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { useMessage } from "/@/hooks/web/useMessage";
|
||||
|
||||
const { createConfirm } = useMessage();
|
||||
|
||||
enum Api {
|
||||
list = '/appmana/survDeviceDeployRun/list',
|
||||
save='/appmana/survDeviceDeployRun/add',
|
||||
edit='/appmana/survDeviceDeployRun/edit',
|
||||
deleteOne = '/appmana/survDeviceDeployRun/delete',
|
||||
deleteBatch = '/appmana/survDeviceDeployRun/deleteBatch',
|
||||
importExcel = '/appmana/survDeviceDeployRun/importExcel',
|
||||
exportXls = '/appmana/survDeviceDeployRun/exportXls',
|
||||
itemList = '/appmana/survDeviceDeployRun/list',
|
||||
deleteItem = '/appmana/survDeviceDeployRun/delete',
|
||||
itemSave = '/appmana/survDeviceDeployRun/add',
|
||||
itemEdit = '/appmana/survDeviceDeployRun/edit',
|
||||
relayItemCheck ='/appmana/survDeviceDeployRun/relayItemCheck',
|
||||
allRelay = '/appmana/survDeviceDeployRun/getRelayType'
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出api
|
||||
* @param params
|
||||
*/
|
||||
export const getExportUrl = Api.exportXls;
|
||||
|
||||
/**
|
||||
* 导入api
|
||||
*/
|
||||
export const getImportUrl = Api.importExcel;
|
||||
|
||||
/**
|
||||
* 列表接口
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
|
||||
/**
|
||||
* 删除单个
|
||||
* @param params
|
||||
* @param handleSuccess
|
||||
*/
|
||||
export const deleteOne = (params,handleSuccess) => {
|
||||
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
* @param params
|
||||
* @param handleSuccess
|
||||
*/
|
||||
export const batchDelete = (params, handleSuccess) => {
|
||||
createConfirm({
|
||||
iconType: 'warning',
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
* @param isUpdate
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url: url, params }, { isTransformResponse: false });
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存或者更新配置
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdateDictItem = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.itemEdit : Api.itemSave;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdateDict = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 校验数据值
|
||||
* @param params
|
||||
*/
|
||||
export const relayItemCheck = (params) => defHttp.get({ url: Api.relayItemCheck, params }, { isTransformResponse: false });
|
||||
|
||||
/**
|
||||
* 列表
|
||||
* @param params
|
||||
*/
|
||||
export const itemList = (params) => defHttp.get({ url: Api.itemList, params });
|
||||
/**
|
||||
* 删除
|
||||
* @param params
|
||||
*/
|
||||
export const deleteItem = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteItem, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 所有继电器类型
|
||||
* @param params
|
||||
*/
|
||||
export const relayTypeList = (params) => defHttp.get({ url: Api.allRelay, params });
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
import {BasicColumn} from '/@/components/Table';
|
||||
import {FormSchema} from '/@/components/Table';
|
||||
import { rules} from '/@/utils/helper/validator';
|
||||
import { render } from '/@/utils/common/renderUtils';
|
||||
import { relayItemCheck,relayTypeList} from './SetupRun.api';
|
||||
|
||||
|
||||
//列表数据
|
||||
export const columns: BasicColumn[] = [
|
||||
{
|
||||
title: '创建者',
|
||||
align: "center",
|
||||
dataIndex: 'createId'
|
||||
},
|
||||
{
|
||||
title: '更新者',
|
||||
align: "center",
|
||||
dataIndex: 'updateId'
|
||||
},
|
||||
{
|
||||
title: '设备主键',
|
||||
align: "center",
|
||||
dataIndex: 'equId'
|
||||
},
|
||||
{
|
||||
title: '指标code',
|
||||
align: "center",
|
||||
dataIndex: 'code'
|
||||
},
|
||||
{
|
||||
title: '指标名称',
|
||||
align: "center",
|
||||
dataIndex: 'name'
|
||||
},
|
||||
{
|
||||
title: '低阈值',
|
||||
align: "center",
|
||||
dataIndex: 'valLow'
|
||||
},
|
||||
{
|
||||
title: '高阈值',
|
||||
align: "center",
|
||||
dataIndex: 'valHeight'
|
||||
},
|
||||
{
|
||||
title: '计量单位',
|
||||
align: "center",
|
||||
dataIndex: 'nuit'
|
||||
},
|
||||
];
|
||||
|
||||
//查询数据
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
];
|
||||
|
||||
//表单数据
|
||||
export const formSchema: FormSchema[] = [
|
||||
{
|
||||
label: '创建者',
|
||||
field: 'createId',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '更新者',
|
||||
field: 'updateId',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '设备主键',
|
||||
field: 'equId',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '指标code',
|
||||
field: 'code',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '指标名称',
|
||||
field: 'name',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '低阈值',
|
||||
field: 'valLow',
|
||||
component: 'InputNumber',
|
||||
},
|
||||
{
|
||||
label: '高阈值',
|
||||
field: 'valHeight',
|
||||
component: 'InputNumber',
|
||||
},
|
||||
{
|
||||
label: '计量单位',
|
||||
field: 'nuit',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '排序',
|
||||
field: 'sortNo',
|
||||
component: 'InputNumber',
|
||||
},
|
||||
// TODO 主键隐藏字段,目前写死为ID
|
||||
{
|
||||
label: '',
|
||||
field: 'id',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
|
||||
export const itemFormSchema: FormSchema[] = [
|
||||
{
|
||||
label: '',
|
||||
field: 'id',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
field: 'deployId',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: '状态名称',
|
||||
field: 'runName',
|
||||
required: true,
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '状态编码',
|
||||
field: 'runKey',
|
||||
component: 'Input',
|
||||
dynamicRules: ({ values, model }) => {
|
||||
return [
|
||||
{
|
||||
required: true,
|
||||
validator: (_, value) => {
|
||||
if (!value) {
|
||||
return Promise.reject('请输入属性编码');
|
||||
}
|
||||
if (new RegExp("[`~!@#$^&*()=|{}'.<>《》/?!¥()—【】‘;:”“。,、?]").test(value)) {
|
||||
return Promise.reject('数据值不能包含特殊字符!');
|
||||
}
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let params = {
|
||||
deployId: model.deployId,
|
||||
relayKey: value,
|
||||
id: model.id,
|
||||
};
|
||||
relayItemCheck(params)
|
||||
.then((res) => {
|
||||
res.success ? resolve() : reject(res.message || '校验失败');
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err.message || '验证失败');
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '状态种类',
|
||||
field: 'runType',
|
||||
required: true,
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'iot_run_type',
|
||||
placeholder: '请选择状态种类',
|
||||
stringToNumber: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '状态类别',
|
||||
field: 'runCate',
|
||||
required: true,
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'iot_run_cate',
|
||||
placeholder: '请选择状态类别',
|
||||
stringToNumber: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '所属分组',
|
||||
field: 'groupId',
|
||||
defaultValue: '',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: ({ schema, formModel }) => {
|
||||
return {
|
||||
dictCode: 'surv_device_deploy_rungroup,GROUP_NAME,ID,IS_ENABLE = 1 and DEPLOY_ID=' + formModel.deployId,
|
||||
dict: 'surv_device_deploy_rungroup,GROUP_NAME,ID,IS_ENABLE = 1 and DEPLOY_ID=' + formModel.deployId,
|
||||
};
|
||||
},
|
||||
},
|
||||
// {
|
||||
// label: '分组编码',
|
||||
// field: 'groupCode',
|
||||
// required: false,
|
||||
// component: 'Input',
|
||||
// },
|
||||
|
||||
{
|
||||
label: '开状态值',
|
||||
field: 'registerOn',
|
||||
required: false,
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '关状态值',
|
||||
field: 'registerOff',
|
||||
required: false,
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '停状态值',
|
||||
field: 'registerStop',
|
||||
required: false,
|
||||
component: 'Input',
|
||||
},
|
||||
|
||||
{
|
||||
field: 'isEnable',
|
||||
label: '是否启用',
|
||||
defaultValue: 1,
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
type: 'radioButton',
|
||||
dictCode: 'yn',
|
||||
stringToNumber: true,
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
label: '排序',
|
||||
field: 'sortNo',
|
||||
required: false,
|
||||
component: 'InputNumber',
|
||||
defaultValue: 1,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
export const dictItemColumns: BasicColumn[] = [
|
||||
{
|
||||
title: '状态编号',
|
||||
dataIndex: 'runKey',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '状态名称',
|
||||
dataIndex: 'runName',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '分组名称',
|
||||
dataIndex: 'groupNameStr',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '状态类别',
|
||||
dataIndex: 'runCateName',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '状态种类',
|
||||
dataIndex: 'runTypeName',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sortNo',
|
||||
width: 80,
|
||||
},
|
||||
];
|
||||
|
||||
export const dictItemSearchFormSchema: FormSchema[] = [
|
||||
{
|
||||
label: '名称',
|
||||
field: 'runName',
|
||||
component: 'Input',
|
||||
},
|
||||
];
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
<template>
|
||||
<BasicDrawer v-bind="$attrs" @register="registerDrawer" title="运行状态列表" width="800px">
|
||||
<BasicTable @register="registerTable" :rowClassName="getRowClassName">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" @click="handleCreate"> 新增</a-button>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
</BasicDrawer>
|
||||
<SetupModal @register="registerModal" @success="reload" :deployId="deployId" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, unref } from 'vue';
|
||||
import { BasicDrawer, useDrawerInner } from '/src/components/Drawer';
|
||||
import { BasicTable, useTable, TableAction } from '/src/components/Table';
|
||||
import { useModal } from '/src/components/Modal';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import SetupModal from './SetupRunModal.vue';
|
||||
import { dictItemColumns, dictItemSearchFormSchema } from './SetupRun.data';
|
||||
import { itemList, deleteItem } from './SetupRun.api';
|
||||
import { ColEx } from '/@/components/Form/src/types';
|
||||
|
||||
const { prefixCls } = useDesign('row-invalid');
|
||||
const deployId = ref('');
|
||||
//协议配置model
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const [registerDrawer] = useDrawerInner(async (data) => {
|
||||
deployId.value = data.id;
|
||||
setProps({ searchInfo: { deployId: unref(deployId) } });
|
||||
reload();
|
||||
});
|
||||
// 自适应列配置
|
||||
const adaptiveColProps: Partial<ColEx> = {
|
||||
xs: 24, // <576px
|
||||
sm: 24, // ≥576px
|
||||
md: 24, // ≥768px
|
||||
lg: 12, // ≥992px
|
||||
xl: 12, // ≥1200px
|
||||
xxl: 8, // ≥1600px
|
||||
};
|
||||
const [registerTable, { reload, setProps }] = useTable({
|
||||
api: itemList,
|
||||
columns: dictItemColumns,
|
||||
formConfig: {
|
||||
baseColProps: adaptiveColProps,
|
||||
labelAlign: 'right',
|
||||
labelCol: {
|
||||
offset: 1,
|
||||
xs: 24,
|
||||
sm: 24,
|
||||
md: 24,
|
||||
lg: 9,
|
||||
xl: 7,
|
||||
xxl: 4,
|
||||
},
|
||||
wrapperCol: {},
|
||||
schemas: dictItemSearchFormSchema,
|
||||
autoSubmitOnEnter: true,
|
||||
},
|
||||
striped: true,
|
||||
useSearchForm: true,
|
||||
bordered: true,
|
||||
showIndexColumn: false,
|
||||
canResize: false,
|
||||
immediate: false,
|
||||
actionColumn: {
|
||||
width: 100,
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
slots: { customRender: 'action' },
|
||||
fixed: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
function handleCreate() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
function handleEdit(record) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
async function handleDelete(record) {
|
||||
await deleteItem({ id: record.id }, reload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
function getRowClassName(record) {
|
||||
return record.status == 0 ? prefixCls : '';
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
@prefix-cls: ~'@{namespace}-row-invalid';
|
||||
|
||||
:deep(.@{prefix-cls}) {
|
||||
background: #f4f4f4;
|
||||
color: #bababa;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit" width="800px">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, ref, computed, unref, reactive } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/src/components/Modal';
|
||||
import { BasicForm, useForm } from '/src/components/Form';
|
||||
import { itemFormSchema } from './SetupRun.data';
|
||||
import { saveOrUpdateDictItem } from './SetupRun.api';
|
||||
import { stringify } from 'querystring';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
const props = defineProps({ deployId: String });
|
||||
const isUpdate = ref(true);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
schemas: itemFormSchema,
|
||||
showActionButtonGroup: false,
|
||||
mergeDynamicData: props,
|
||||
labelCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 4 },
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 18 },
|
||||
},
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
//表单赋值
|
||||
await setFieldsValue({
|
||||
...data.record,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//设置标题
|
||||
const getTitle = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
|
||||
//表单提交事件
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
values.deployId = props.deployId;
|
||||
setModalProps({ confirmLoading: true });
|
||||
//提交表单
|
||||
await saveOrUpdateDictItem(values, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Loading…
Reference in New Issue