增加新监控界面

This commit is contained in:
zy 2025-11-18 18:14:45 +08:00
parent b1e3b2c232
commit 513410f78a
27 changed files with 1771 additions and 92 deletions

View File

@ -92,7 +92,10 @@
"vxe-table": "4.1.0",
"vxe-table-plugin-antd": "3.0.5",
"xe-utils": "^3.3.1",
"xss": "^1.0.13"
"xss": "^1.0.13",
"video.js": "^8.21.1",
"videojs-contrib-hls": "^5.15.0",
"videojs-vtt.js": "^0.15.5"
},
"devDependencies": {
"@commitlint/cli": "^16.2.3",

View File

@ -150,6 +150,15 @@ importers:
vditor:
specifier: ^3.8.13
version: 3.8.13
video.js:
specifier: ^8.21.1
version: 8.23.4
videojs-contrib-hls:
specifier: ^5.15.0
version: 5.15.0
videojs-vtt.js:
specifier: ^0.15.5
version: 0.15.5
vue:
specifier: ^3.2.33
version: 3.2.33
@ -2015,6 +2024,19 @@ packages:
resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
'@videojs/http-streaming@3.17.2':
resolution: {integrity: sha512-VBQ3W4wnKnVKb/limLdtSD2rAd5cmHN70xoMf4OmuDd0t2kfJX04G+sfw6u2j8oOm2BXYM9E1f4acHruqKnM1g==}
engines: {node: '>=8', npm: '>=5'}
peerDependencies:
video.js: ^8.19.0
'@videojs/vhs-utils@4.1.1':
resolution: {integrity: sha512-5iLX6sR2ownbv4Mtejw6Ax+naosGvoT9kY+gcuHzANyUZZ+4NpeNdKMUhb6ag0acYej1Y7cmr/F2+4PrggMiVA==}
engines: {node: '>=8', npm: '>=5'}
'@videojs/xhr@2.7.0':
resolution: {integrity: sha512-giab+EVRanChIupZK7gXjHy90y3nncA2phIOyG3Ne5fvpiMJzvqYwiTOnEVW2S4CoYcuKJkomat7bMXA/UoUZQ==}
'@vitejs/plugin-legacy@2.0.0':
resolution: {integrity: sha512-cuc45C4BQo2VlOsHZML4fc3MPfSjOEFeezHxr+WWlOOmi+muy1rz2snnFiePtyjVc1CYGTsnxk13cXpzQvMZaw==}
engines: {node: '>=14.18.0'}
@ -2214,6 +2236,10 @@ packages:
'@windicss/plugin-utils@1.8.7':
resolution: {integrity: sha512-dfj95olNZyGFDPFMBvE5oq8hA5f0ooUJZjVdWlthS4ek4W1/xNOHDxB6ygWR8LE9zCOXZykApjt1LOhy9Ky2QA==}
'@xmldom/xmldom@0.8.11':
resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==}
engines: {node: '>=10.0.0'}
'@zxcvbn-ts/core@2.0.1':
resolution: {integrity: sha512-i3viYattwORK5liqS/d9WaIWSLki75oKVog5Elg9Ls9d8L6zKLwpAkj6PT/P4LZqJHIVRPnKjgajpP6SLerr6Q==}
@ -2263,6 +2289,12 @@ packages:
resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==}
engines: {node: '>=0.8'}
aes-decrypter@1.0.3:
resolution: {integrity: sha512-rsx8pfx7wJsn+ziYbpJ8XA5c93hKAtBCrfydxJqJCMT+qfjipd/B5wC2xHtBcoxyvlqJcpeAo3K55t0lXOn9yQ==}
aes-decrypter@4.0.2:
resolution: {integrity: sha512-lc+/9s6iJvuaRe5qDlMTpCFjnwpkeOXp8qP3oiZ5jsj1MRg+SBVUmmICrhxHvc8OELSmc+fEyyxAuppY6hrWzw==}
agent-base@6.0.2:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
engines: {node: '>= 6.0.0'}
@ -3353,6 +3385,9 @@ packages:
dom-serializer@1.4.1:
resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
dom-walk@0.1.2:
resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==}
domelementtype@1.3.1:
resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==}
@ -3527,6 +3562,10 @@ packages:
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
engines: {node: '>= 0.4'}
es5-shim@4.6.7:
resolution: {integrity: sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==}
engines: {node: '>=0.4.0'}
esbuild-android-64@0.14.54:
resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==}
engines: {node: '>=12'}
@ -4244,6 +4283,12 @@ packages:
resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==}
engines: {node: '>=6'}
global@4.3.2:
resolution: {integrity: sha512-/4AybdwIDU4HkCUbJkZdWpe4P6vuw/CUtu+0I1YlLIPe7OlUO7KNJ+q/rO70CW2/NW6Jc6I62++Hzsf5Alu6rQ==}
global@4.4.0:
resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==}
globals@13.24.0:
resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
engines: {node: '>=8'}
@ -4534,6 +4579,9 @@ packages:
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
engines: {node: '>=8'}
individual@2.0.0:
resolution: {integrity: sha512-pWt8hBCqJsUWI/HtcfWod7+N9SgAqyPEaF7JQjwzjn5vGrpg6aQ5qeAFQ7dx//UH4J1O+7xqew+gCeeFt6xN/g==}
inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
@ -4676,6 +4724,9 @@ packages:
resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
engines: {node: '>=12'}
is-function@1.0.2:
resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==}
is-generator-fn@2.1.0:
resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
engines: {node: '>=6'}
@ -5327,6 +5378,12 @@ packages:
luxon@1.28.1:
resolution: {integrity: sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==}
m3u8-parser@2.1.0:
resolution: {integrity: sha512-WbEpQ2FUaNGbJ0YanSeyj9D9ruu4FUvz+ZvebIzI2bSME+PUwcPXO1kKXZkjcPUAFruDikoOI5fWQNIA6JCCOQ==}
m3u8-parser@7.2.0:
resolution: {integrity: sha512-CRatFqpjVtMiMaKXxNvuI3I++vUumIXVVT/JpCpdU/FynV/ceVw1qpPyyBNindL+JlPMSesx+WX1QJaZEJSaMQ==}
magic-string@0.25.9:
resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
@ -5455,6 +5512,9 @@ packages:
resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==}
engines: {node: '>=4'}
min-document@2.19.2:
resolution: {integrity: sha512-8S5I8db/uZN8r9HSLFVWPdJCvYOejMcEC82VIzNUc6Zkklf/d1gg2psfE79/vyhWOj4+J8MtwmoOz3TmvaGu5A==}
min-indent@1.0.1:
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
engines: {node: '>=4'}
@ -5506,6 +5566,10 @@ packages:
engines: {node: '>=10'}
hasBin: true
mpd-parser@1.3.1:
resolution: {integrity: sha512-1FuyEWI5k2HcmhS1HkKnUAQV7yFPfXPht2DnRRGtoiiAAW+ESTbtEXIDpRkwdU+XyrQuwrIym7UkoPKsZ0SyFw==}
hasBin: true
mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
@ -5526,6 +5590,14 @@ packages:
mute-stream@0.0.8:
resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
mux.js@4.3.2:
resolution: {integrity: sha512-g0q6DPdvb3yYcoK7ElBGobdSSrhY/RjPt19U7uUc733aqvc5bCS/aCvL9z+448y+IoCZnYDwyZfQBBXMSmGOaQ==}
mux.js@7.1.0:
resolution: {integrity: sha512-NTxawK/BBELJrYsZThEulyUMDVlLizKdxyAsMuzoCD1eFj97BVaA8D/CvKsKu6FOLYkFojN5CbM9h++ZTZtknA==}
engines: {node: '>=8', npm: '>=5'}
hasBin: true
nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@ -5788,6 +5860,9 @@ packages:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
parse-headers@2.0.6:
resolution: {integrity: sha512-Tz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A==}
parse-json@2.2.0:
resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==}
engines: {node: '>=0.10.0'}
@ -5932,6 +6007,15 @@ packages:
resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
engines: {node: '>= 6'}
pkcs7@0.2.3:
resolution: {integrity: sha512-kJRwmADEQUg+qJyRgWLtpEL9q9cFjZschejTEK3GRjKvnsU9G5WWoe/wKqRgbBoqWdVSeTUKP6vIA3Y72M3rWA==}
engines: {node: ^0.10, npm: ^1.4.6}
hasBin: true
pkcs7@1.0.4:
resolution: {integrity: sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==}
hasBin: true
pkg-dir@4.2.0:
resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
engines: {node: '>=8'}
@ -6078,6 +6162,14 @@ packages:
process-nextick-args@2.0.1:
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
process@0.11.10:
resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
engines: {node: '>= 0.6.0'}
process@0.5.2:
resolution: {integrity: sha512-oNpcutj+nYX2FjdEW7PGltWhXulAnFlM0My/k48L90hARCOJtvBbQXc/6itV2jDvU5xAAtonP+r6wmQgCcbAUA==}
engines: {node: '>= 0.6.0'}
prompts@2.4.2:
resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
engines: {node: '>= 6'}
@ -6378,6 +6470,9 @@ packages:
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
rust-result@1.0.0:
resolution: {integrity: sha512-6cJzSBU+J/RJCF063onnQf0cDUOHs9uZI1oroSGnHOph+CQTIJ5Pp2hK5kEQq1+7yE/EEWfulSNXAQ2jikPthA==}
rxjs@6.6.7:
resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==}
engines: {npm: '>=2.0.0'}
@ -6395,6 +6490,9 @@ packages:
safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
safe-json-parse@4.0.0:
resolution: {integrity: sha512-RjZPPHugjK0TOzFrLZ8inw44s9bKox99/0AZW9o/BEQVrJfhI+fIHMErnPyRa89/yRXUUr93q+tiN6zhoVV4wQ==}
safe-push-apply@1.0.0:
resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
engines: {node: '>= 0.4'}
@ -7089,6 +7187,10 @@ packages:
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
tsml@1.0.1:
resolution: {integrity: sha512-3KmepnH9SUsoOVtg013CRrL7c+AK7ECaquAsJdvu4288EDJuraqBlP4PDXT/rLEJ9YDn4jqLAzRJsnFPx+V6lg==}
deprecated: no longer maintained
tsutils@3.21.0:
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'}
@ -7270,6 +7372,9 @@ packages:
resolution: {integrity: sha512-0kQLIzG4fdk/G5NONku64rSH/x32NOA39LVQqlK8Le6lvTF6GGRJpqaQFGgU+CLwySIqBSMdwYM0sYcW9f6P4A==}
engines: {node: '>= 4'}
url-toolkit@2.2.5:
resolution: {integrity: sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg==}
use@3.1.1:
resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==}
engines: {node: '>=0.10.0'}
@ -7309,6 +7414,40 @@ packages:
vditor@3.8.13:
resolution: {integrity: sha512-vp6OF1n9wIduKtLvvTYtn+7Gr1Az6MqDIEBpLzik+PTQ208YjrcQ+Ba4AHXMMvJgDtbYP3PdY8OixWKecFzo2A==}
video.js@6.13.0:
resolution: {integrity: sha512-36/JR/GhPQSZj0o+GNbhcEYv/b0SkV9SQsjlodAnzMQYN0TA7VhmqrKPYMCi1NGRYu7S9W3OaFCFoUxkYfSVlg==}
video.js@8.23.4:
resolution: {integrity: sha512-qI0VTlYmKzEqRsz1Nppdfcaww4RSxZAq77z2oNSl3cNg2h6do5C8Ffl0KqWQ1OpD8desWXsCrde7tKJ9gGTEyQ==}
videojs-contrib-hls@5.15.0:
resolution: {integrity: sha512-18zbMYZ0XRBKTPEayA9bFTWWrqhT9b4G8+zf0czJLD7Epe5PcK1I/3dflTHQeQ5rwlWir+/XnFU3sMg/B2MMcw==}
engines: {node: '>= 0.10.12'}
videojs-contrib-media-sources@4.7.2:
resolution: {integrity: sha512-e6iCHWBFuV05EGo7v+pS9iepObXnJ9joms467gzi8ZjpKVb3ifha9M0Ja24Rd8JfvYpzjltsgDVtGFDvIg4hQQ==}
videojs-contrib-quality-levels@4.1.0:
resolution: {integrity: sha512-TfrXJJg1Bv4t6TOCMEVMwF/CoS8iENYsWNKip8zfhB5kTcegiFYezEA0eHAJPU64ZC8NQbxQgOwAsYU8VXbOWA==}
engines: {node: '>=16', npm: '>=8'}
peerDependencies:
video.js: ^8
videojs-font@2.1.0:
resolution: {integrity: sha512-zFqWpLrXf1q8NtYx5qtZhMC6SLUFScDmR6j+UGPogobxR21lvXShhnzcNNMdOxJUuFLiToJ/BPpFUQwX4xhpvA==}
videojs-font@4.2.0:
resolution: {integrity: sha512-YPq+wiKoGy2/M7ccjmlvwi58z2xsykkkfNMyIg4xb7EZQQNwB71hcSsB3o75CqQV7/y5lXkXhI/rsGAS7jfEmQ==}
videojs-ie8@1.1.2:
resolution: {integrity: sha512-0Zb2T4MLkpfZbeGMK/Z93b8Lrepr+rLFoHgQV1CoDeFqXvH7b+Vsd/VHoILGxQrgCSHFQ7mAODR6oyMjuiD4/g==}
videojs-vtt.js@0.12.6:
resolution: {integrity: sha512-XFXeGBQiljnElMhwCcZst0RDbZn2n8LU7ZScXryd3a00OaZsHAjdZu/7/RdSr7Z1jHphd45FnOvOQkGK4YrWCQ==}
videojs-vtt.js@0.15.5:
resolution: {integrity: sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ==}
vite-plugin-compression@0.5.1:
resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==}
peerDependencies:
@ -7572,6 +7711,9 @@ packages:
resolution: {integrity: sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==}
engines: {node: '>=10.4'}
webwackify@0.1.6:
resolution: {integrity: sha512-pGcw1T3HpNnM/UTRQqqRkkkzythSLts05mB+7Gr00B+0VbL0m39dFL5g20rSIEUt9Wrpw+/8k+snxRlUFHhcqA==}
whatwg-encoding@1.0.5:
resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==}
@ -7724,6 +7866,9 @@ packages:
xe-utils@3.3.1:
resolution: {integrity: sha512-OdQgl9WPV9dK3/djneFPrGX8z1M4neX+VOkzra5oONjoNsCKQhwdiut99WlxceNMQ5vXDv4EQ/wKA2fux3Gdug==}
xhr@2.4.0:
resolution: {integrity: sha512-TUbBsdAuJbX8olk9hsDwGK8P1ri1XlV+PdEWkYw+HQQbpkiBR8PLgD1F3kQDPBs9l4Px34hP9rCYAZOCCAENbw==}
xlsx@0.17.5:
resolution: {integrity: sha512-lXNU0TuYsvElzvtI6O7WIVb9Zar1XYw7Xb3VAx2wn8N/n0whBYrCnHMxtFyIiUU1Wjf09WzmLALDfBO5PqTb1g==}
engines: {node: '>=0.8'}
@ -9810,6 +9955,28 @@ snapshots:
'@typescript-eslint/types': 5.62.0
eslint-visitor-keys: 3.4.3
'@videojs/http-streaming@3.17.2(video.js@8.23.4)':
dependencies:
'@babel/runtime': 7.28.4
'@videojs/vhs-utils': 4.1.1
aes-decrypter: 4.0.2
global: 4.4.0
m3u8-parser: 7.2.0
mpd-parser: 1.3.1
mux.js: 7.1.0
video.js: 8.23.4
'@videojs/vhs-utils@4.1.1':
dependencies:
'@babel/runtime': 7.28.4
global: 4.4.0
'@videojs/xhr@2.7.0':
dependencies:
'@babel/runtime': 7.28.4
global: 4.4.0
is-function: 1.0.2
'@vitejs/plugin-legacy@2.0.0(terser@5.44.1)(vite@3.0.2(less@4.1.2)(sass@1.66.1)(terser@5.44.1))':
dependencies:
'@babel/standalone': 7.28.5
@ -10101,6 +10268,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@xmldom/xmldom@0.8.11': {}
'@zxcvbn-ts/core@2.0.1':
dependencies:
fastest-levenshtein: 1.0.12
@ -10140,6 +10309,17 @@ snapshots:
adler-32@1.3.1: {}
aes-decrypter@1.0.3:
dependencies:
pkcs7: 0.2.3
aes-decrypter@4.0.2:
dependencies:
'@babel/runtime': 7.28.4
'@videojs/vhs-utils': 4.1.1
global: 4.4.0
pkcs7: 1.0.4
agent-base@6.0.2:
dependencies:
debug: 4.4.3(supports-color@9.4.0)
@ -11379,6 +11559,8 @@ snapshots:
domhandler: 4.3.1
entities: 2.2.0
dom-walk@0.1.2: {}
domelementtype@1.3.1: {}
domelementtype@2.3.0: {}
@ -11615,6 +11797,8 @@ snapshots:
is-date-object: 1.1.0
is-symbol: 1.1.1
es5-shim@4.6.7: {}
esbuild-android-64@0.14.54:
optional: true
@ -12411,6 +12595,16 @@ snapshots:
kind-of: 6.0.3
which: 1.3.1
global@4.3.2:
dependencies:
min-document: 2.19.2
process: 0.5.2
global@4.4.0:
dependencies:
min-document: 2.19.2
process: 0.11.10
globals@13.24.0:
dependencies:
type-fest: 0.20.2
@ -12774,6 +12968,8 @@ snapshots:
indent-string@4.0.0: {}
individual@2.0.0: {}
inflight@1.0.6:
dependencies:
once: 1.4.0
@ -12937,6 +13133,8 @@ snapshots:
is-fullwidth-code-point@4.0.0: {}
is-function@1.0.2: {}
is-generator-fn@2.1.0: {}
is-generator-function@1.1.2:
@ -13816,6 +14014,14 @@ snapshots:
luxon@1.28.1: {}
m3u8-parser@2.1.0: {}
m3u8-parser@7.2.0:
dependencies:
'@babel/runtime': 7.28.4
'@videojs/vhs-utils': 4.1.1
global: 4.4.0
magic-string@0.25.9:
dependencies:
sourcemap-codec: 1.4.8
@ -13967,6 +14173,10 @@ snapshots:
mimic-response@1.0.1: {}
min-document@2.19.2:
dependencies:
dom-walk: 0.1.2
min-indent@1.0.1: {}
minimatch@10.1.1:
@ -14013,6 +14223,13 @@ snapshots:
bin-build: 3.0.0
bin-wrapper: bin-wrapper-china@0.1.0
mpd-parser@1.3.1:
dependencies:
'@babel/runtime': 7.28.4
'@videojs/vhs-utils': 4.1.1
'@xmldom/xmldom': 0.8.11
global: 4.4.0
mri@1.2.0: {}
ms@2.0.0: {}
@ -14031,6 +14248,13 @@ snapshots:
mute-stream@0.0.8: {}
mux.js@4.3.2: {}
mux.js@7.1.0:
dependencies:
'@babel/runtime': 7.28.4
global: 4.4.0
nanoid@3.3.11: {}
nanomatch@1.2.13:
@ -14311,6 +14535,8 @@ snapshots:
dependencies:
callsites: 3.1.0
parse-headers@2.0.6: {}
parse-json@2.2.0:
dependencies:
error-ex: 1.3.4
@ -14416,6 +14642,12 @@ snapshots:
pirates@4.0.7: {}
pkcs7@0.2.3: {}
pkcs7@1.0.4:
dependencies:
'@babel/runtime': 7.28.4
pkg-dir@4.2.0:
dependencies:
find-up: 4.1.0
@ -14553,6 +14785,10 @@ snapshots:
process-nextick-args@2.0.1: {}
process@0.11.10: {}
process@0.5.2: {}
prompts@2.4.2:
dependencies:
kleur: 3.0.3
@ -14865,6 +15101,10 @@ snapshots:
dependencies:
queue-microtask: 1.2.3
rust-result@1.0.0:
dependencies:
individual: 2.0.0
rxjs@6.6.7:
dependencies:
tslib: 1.14.1
@ -14885,6 +15125,10 @@ snapshots:
safe-buffer@5.2.1: {}
safe-json-parse@4.0.0:
dependencies:
rust-result: 1.0.0
safe-push-apply@1.0.0:
dependencies:
es-errors: 1.3.0
@ -15676,6 +15920,8 @@ snapshots:
tslib@2.8.1: {}
tsml@1.0.1: {}
tsutils@3.21.0(typescript@4.6.3):
dependencies:
tslib: 1.14.1
@ -15852,6 +16098,8 @@ snapshots:
url-to-options@1.0.1: {}
url-toolkit@2.2.5: {}
use@3.1.1: {}
util-deprecate@1.0.2: {}
@ -15885,6 +16133,71 @@ snapshots:
dependencies:
diff-match-patch: 1.0.5
video.js@6.13.0:
dependencies:
babel-runtime: 6.26.0
global: 4.3.2
safe-json-parse: 4.0.0
tsml: 1.0.1
videojs-font: 2.1.0
videojs-ie8: 1.1.2
videojs-vtt.js: 0.12.6
xhr: 2.4.0
video.js@8.23.4:
dependencies:
'@babel/runtime': 7.28.4
'@videojs/http-streaming': 3.17.2(video.js@8.23.4)
'@videojs/vhs-utils': 4.1.1
'@videojs/xhr': 2.7.0
aes-decrypter: 4.0.2
global: 4.4.0
m3u8-parser: 7.2.0
mpd-parser: 1.3.1
mux.js: 7.1.0
videojs-contrib-quality-levels: 4.1.0(video.js@8.23.4)
videojs-font: 4.2.0
videojs-vtt.js: 0.15.5
videojs-contrib-hls@5.15.0:
dependencies:
aes-decrypter: 1.0.3
global: 4.4.0
m3u8-parser: 2.1.0
mux.js: 4.3.2
url-toolkit: 2.2.5
video.js: 6.13.0
videojs-contrib-media-sources: 4.7.2
webwackify: 0.1.6
videojs-contrib-media-sources@4.7.2:
dependencies:
global: 4.4.0
mux.js: 4.3.2
video.js: 6.13.0
webwackify: 0.1.6
videojs-contrib-quality-levels@4.1.0(video.js@8.23.4):
dependencies:
global: 4.4.0
video.js: 8.23.4
videojs-font@2.1.0: {}
videojs-font@4.2.0: {}
videojs-ie8@1.1.2:
dependencies:
es5-shim: 4.6.7
videojs-vtt.js@0.12.6:
dependencies:
global: 4.4.0
videojs-vtt.js@0.15.5:
dependencies:
global: 4.4.0
vite-plugin-compression@0.5.1(vite@3.0.2(less@4.1.2)(sass@1.66.1)(terser@5.44.1)):
dependencies:
chalk: 4.1.2
@ -16235,6 +16548,8 @@ snapshots:
webidl-conversions@6.1.0: {}
webwackify@0.1.6: {}
whatwg-encoding@1.0.5:
dependencies:
iconv-lite: 0.4.24
@ -16466,6 +16781,13 @@ snapshots:
xe-utils@3.3.1: {}
xhr@2.4.0:
dependencies:
global: 4.3.2
is-function: 1.0.2
parse-headers: 2.0.6
xtend: 4.0.2
xlsx@0.17.5:
dependencies:
adler-32: 1.2.0

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
public/camera/step_down.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

BIN
public/camera/step_left.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

BIN
public/camera/step_up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
public/camera/videoback.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -16,6 +16,9 @@ enum Api {
sendDeviceCmd= '/appmana/survDeviceDeploy/sendDeviceCmd',
initDevice = '/appmana/survDeviceDeploy/initDevice',
getDeviceData='/appmana/fDictDeviceDetail/getDeviceData',
getCamraInfo = '/appmana/survDeviceDeploy/stationInfoWithCamera',
cameraStartApi = '/appmana/survDeviceDeploy/cameraStart',
cameraStopApi = '/appmana/survDeviceDeploy/cameraStop',
}
/**
@ -86,6 +89,15 @@ export const getYsToken = () => {
return defHttp.post({ url: Api.getYsToken }, { isTransformResponse: false });
}
/**
* token
* @param params
* @param isUpdate
*/
export const getCamList = () => {
return defHttp.post({ url: Api.getCamraInfo }, { isTransformResponse: false });
}
/**
*
@ -134,3 +146,20 @@ export const deviceInit = (params, handleSuccess) => {
* @param params
*/
export const getDeviceData = (params) => defHttp.get({ url: Api.getDeviceData, params }, { isTransformResponse: false });
/**
*
* @param params
*/
export const cameraStart = (params) => {
return defHttp.post({ url: Api.cameraStartApi, params }, { isTransformResponse: false });
}
/**
*
* @param params
*/
export const cameraStop = (params) => {
return defHttp.post({ url: Api.cameraStopApi, params }, { isTransformResponse: false });
}

View File

@ -0,0 +1,516 @@
<template>
<a-modal :title="title" :width="width" :visible="visible" footer="" @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭">
<div class="video_screen" style="height: 600px; display: flex; flex: 1">
<div style="width: 100%;height: 600px" id="parent2"></div>
<div class="control_panel"
v-if="playerType = 'ys' && (camType == 'ball' || camType == 'halfball')">
<div class="control_header">云台控制</div>
<div class="ptz-block ptz-block-fs">
<!-- v-if="player.show" -->
<div class="ptz-close">
<!-- @click="close(index)" -->
<i class="el-icon-circle-close"></i>
</div>
<div class="ptz-cell ptz-up" @mousedown.prevent="ptzControl('0')" command="up" title="上">
<i class="fa fa-chevron-up"></i>
</div>
<div class="ptz-cell ptz-left" @mousedown.prevent="ptzControl('2')" command="left" title="左">
<i class="fa fa-chevron-left"></i>
</div>
<div class="ptz-cell ptz-center" title="云台控制">
<i class="fa fa-arrows"></i>
</div>
<div class="ptz-cell ptz-right" @mousedown.prevent="ptzControl('3')" command="right" title="右">
<i class="fa fa-chevron-right"></i>
</div>
<div class="ptz-cell ptz-down" @mousedown.prevent="ptzControl('1')" command="down" title="下">
<i class="fa fa-chevron-down"></i>
</div>
<div class="ptz-cell ptz-zoomin" @mousedown.prevent="ptzControl('8')" command="zoomin"
title="放大">
<i class="fa fa-plus-circle"></i>
</div>
<div class="ptz-cell ptz-zoomout" @mousedown.prevent="ptzControl('9')" command="zoomout"
title="缩小">
<i class="fa fa-minus-circle"></i>
</div>
</div>
</div>
</div>
</a-modal>
</template>
<script lang="ts" setup>
import { ref, nextTick, defineExpose } from 'vue';
import { cameraStart,cameraStop } from '../deploy/SurvDeviceDeploy.api';
import EZUIKit from "ezuikit-js";
import videojs from 'video.js'
import 'video.js/dist/video-js.css'
const title = ref<string>('');
const width = ref<number>(800);
const visible = ref<boolean>(false);
const disableSubmit = ref<boolean>(false);
const registerForm = ref();
const emit = defineEmits(['register', 'success']);
const player= ref();
const playerType = ref();
const camType = ref();
const cameraInfo = ref();
/**
* 新增
*/
function statistic(record) {
title.value = '监控查看';
visible.value = true;
camType.value = record.deploySecondaryType;
cameraInfo.value = record;
if(camType.value == 'ball' || camType.value === 'halfball') {
width.value = 1000;
}
console.log('xxxx',record.deviceIotUrl);
if(record.deviceIotUrl && record.deviceIotUrl != ''){
let videohtml =
`<div style="width: 100%;height: 600px;margin:auto;"><div id="videos" style="width: 100%; height: 100%"></div></div>`
nextTick(() => {
let dom = document.querySelector('#parent2')
dom.innerHTML = videohtml
player.value = new EZUIKit.EZUIKitPlayer({
id: 'videos', // ID
accessToken: record.ysToken,
url: record.deviceIotUrl,
audio: 0,
autoplay: true,
// simple: ; pcLive: pc; pcRec: pc; mobileLive: ; mobileRec: ;security: ; voice: ;
template: 'security',
// themeData: this.themeData,
plugin: ['expend'], // talk-
height: 600,
showStreamInfo:false,
})
playerType.value = 'ys';
const videosWrap = document.getElementById('videos-wrap');
videosWrap.style.height = '100%';
})
}else if(record.deviceUrl && record.deviceUrl !=''){
let video = document.createElement('video');
video.id = `videos`;
video.className = `video-js example-video vjs-default-skin vjs-big-play-centered`;
video.autoplay = 'autoplay';
video.controls = 'controls';
video.style = `object-fit: fill;width:100%;height:100%`;
video.preload = `auto`;
video.muted = `muted`;
nextTick(() => {
let dom = document.querySelector('#parent2')
dom.innerHTML = '';//
dom.appendChild(video)
player.value = videojs(`videos`, {
autoplay:true,
bigPlayButton: true,
textTrackDisplay: true,
posterImage: true,
errorDisplay: false,
controlBar: true,
height: 600,
preload:'metadata' ,
userActions: {
hotkeys: false //
},
sources:[{
src:record.deviceUrl,
type:'application/x-mpegURL'
}]
});
playerType.value = 'm3u8';
player.value.play();
})
}
}
/**
* 编辑
* @param record
*/
function edit(record) {
title.value = disableSubmit.value ? '详情' : '编辑';
visible.value = true;
nextTick(() => {
registerForm.value.edit(record);
});
}
/**
* 监控
* @param record
*/
function monitor(record) {
title.value = '监控查看';
visible.value = true;
// nextTick(() => {
// registerForm.value.add();
// });
}
/**
* 确定按钮点击事件
*/
function handleOk() {
registerForm.value.submitForm();
}
/**
* form保存回调事件
*/
function submitCallback() {
handleCancel();
emit('success');
}
/**
* 取消按钮回调事件
*/
function handleCancel() {
visible.value = false;
//
if(playerType.value == 'ys'){
player.value.destroy()
}else if(playerType.value == 'm3u8'){
player.value.dispose();
}
}
function ptzControl(direction) {
cameraStart({
cameraId: cameraInfo.value.id,
direction: direction,
}).then((res) => {})
setTimeout(() => {
cameraStop({
cameraId: cameraInfo.value.id,
direction: '',
}).then((res) => {})
}, 500)
}
defineExpose({
statistic,
edit,
disableSubmit,
});
</script>
<style>
/**隐藏样式-modal确定按钮 */
.jee-hidden {
display: none !important;
}
::-webkit-scrollbar {
width: 0 !important;
}
::-webkit-scrollbar {
width: 0 !important;height: 0;
}
.full-modal {
.ant-modal {
max-width: 100%;
top: 0;
padding-bottom: 0;
margin: 0;
}
.ant-modal-content {
display: flex;
flex-direction: column;
}
.ant-modal-body {
flex: 1;
}
}
.control_panel {
margin-left: 20px;
height: 100%;
padding: 0 20px;
box-sizing: border-box;
background: linear-gradient(to bottom, #3c424e, #20252c);
border-radius: 4px;
position: relative;
.control_header {
margin: 34px auto 0;
width: 138px;
height: 42px;
border-radius: 4px;
border: 1px solid #040404;
background: linear-gradient(to bottom, #242932, #1e2326);
color: #6b7280;
font-size: 16px;
line-height: 42px;
text-align: center;
}
}
.ptz-block {
width: 96px;
height: 180px;
margin: 0 auto;
text-align: center;
position: relative;
font-size: 24px;
.ptz-close {
position: absolute;
top: -20px;
right: -15px;
width: 24px;
height: 24px;
border-radius: 50%;
z-index: 99;
background: rgba(85, 85, 85, 0.5);
display: none;
i {
color: #fff;
font-size: 24px;
}
}
.ptz-cell {
width: 50px;
height: 50px;
line-height: 50px;
position: absolute;
background: green;
}
.ptz-cell.active {
color: #ccc;
font-size: 26px;
}
.ptz-cell.readonly {
color: #ddd;
}
.fa-microphone.active {
color: #fff;
}
.fa-microphone.readonly {
color: #ddd;
}
.fa-microphone-slash.readonly {
color: #ddd;
}
.mic-level-bar {
position: absolute;
transform: rotate(-90deg);
width: 100%;
top: 70px;
left: -80px;
}
.ptz-center {
left: 0;
right: 0;
margin: auto;
width: 96px;
border-radius: 54px;
height: 96px;
background: url('/camera/main_control_bg.png') no-repeat center;
background-size: 100% 100%;
box-shadow: 0 8px 26px 1px rgba(0, 0, 0, 0.3);
}
.ptz-up {
top: 0;
left: 0;
right: 0;
margin: auto;
z-index: 10;
width: 30px;
height: 30px;
background: url('/camera/step_up.png') no-repeat center;
}
.ptz-left {
z-index: 10;
width: 30px;
height: 30px;
background: url('/camera/step_left.png') no-repeat center;
top: 33px;
left: 0;
}
.ptz-right {
z-index: 10;
width: 30px;
height: 30px;
background: url('/camera/step_right.png') no-repeat center;
top: 33px;
right: 0;
}
.ptz-down {
z-index: 10;
left: 0;
right: 0;
margin: auto;
top: 66px;
width: 30px;
height: 30px;
background: url('/camera/step_down.png') no-repeat center;
}
.ptz-up:active {
background: url(/camera/step_up_hover.png) no-repeat center;
}
.ptz-left:active {
background: url(/camera/step_left_hover.png) no-repeat center;
}
.ptz-right:active {
background: url(/camera/step_right_hover.png) no-repeat center;
}
.ptz-down:active {
background: url(/camera/step_down_hover.png) no-repeat center;
}
.ptz-zoomin:active {
background: url(/camera/video_ctrl.png) no-repeat -88px center;
}
.ptz-zoomout:active {
background: url(/camera/video_ctrl.png) no-repeat -130px center;
}
.ptz-zoomin {
position: absolute;
top: 100px;
left: 13px;
width: 34px;
border-radius: 20px;
height: 34px;
background: url('/camera/video_ctrl.png') no-repeat 0px center;
background-size: 400% auto;
box-shadow: 0 8px 26px 1px rgba(0, 0, 0, 0.3);
}
.ptz-zoomout {
position: absolute;
top: 100px;
left: 13px;
width: 34px;
border-radius: 20px;
height: 34px;
background: url('/camera/video_ctrl.png') no-repeat -34px center;
background-size: 400% auto;
box-shadow: 0 8px 26px 1px rgba(0, 0, 0, 0.3);
}
.ptz-talk {
top: 150px;
left: 50px;
}
.ptz-up,
.ptz-left,
.ptz-right,
.ptz-down,
.ptz-center>.fa-microphone,
.ptz-zoomin,
.ptz-talk>.fa-microphone,
.ptz-zoomout {
cursor: pointer;
&.readonly {
cursor: auto;
}
}
}
.ptz-block-fs {
position: absolute;
margin: 0;
margin-bottom: 50px;
top: 120px;
right: 0;
left: 0;
margin: auto;
height: 150px;
.ptz-center {
cursor: move;
position: absolute;
}
.fa-microphone.active {
color: #ccc;
}
.ptz-zoomin {
left: 0;
}
.ptz-zoomout {
left: 66px;
}
}
.ptz-block {
.mic-level-bar {
.el-progress-bar__outer {
background-color: #ddd !important;
}
}
}
.view-list {
.video-show {
:not(:fullscreen) {
.video.active .video-inner {
border: 2px solid red;
}
}
}
}
.fullscreen {
&>.video {
&.col-sm-12 {
height: 100%;
}
&.col-sm-6 {
height: 50%;
}
&.col-sm-4 {
height: 33.33%;
}
&.col-sm-3 {
height: 25%;
}
&>.player-wrapper {
height: 100%;
.video-wrapper {
padding-bottom: 0 !important;
height: 100%;
overflow: visible;
}
}
}
}
</style>

View File

@ -1,62 +1,91 @@
<template>
<a-row v-for="value in formData.item" :key="value.id">
<a-col :span="24">
<a-card :title="value.stationName" style="width: 100%" size="default">
<a-row :gutter="16">
<a-col class="gutter-row" :span="12" v-for="value2 in value.deviceList" :key="value2.id">
<div class="gutter-box" :id="value2.deployCode" style="height:700px" >
<div class="gutter-box" :id="value2.deployCode" style="width: 100%;text-align: center;">
<div class="video_head" style="">
{{value2.deployDes}}
</div>
<div style="cursor:pointer" @click="handleMonitor(value2)">
<img src="/resource/img/cameras.jpg" class="app-loading-logo" alt="Logo" style="width: 100%;text-align: center;"/>
</div>
</div>
</a-col>
</a-row>
</a-card>
</a-col>
</a-row>
<!--监控-->
<MonitorDetailModal ref="monitorRegisterModal" @success="handleSuccess"/>
</template>
<script lang="ts" setup>
import EZUIKit from 'ezuikit-js';
import { ref, onMounted,reactive } from 'vue'
import { getYsToken} from '../deploy/SurvDeviceDeploy.api';
import { ref, onMounted, reactive } from 'vue';
import MonitorDetailModal from './MonitorModal.vue';
import { getCamList } from '../deploy/SurvDeviceDeploy.api';
const ysToken = ref('');
const formData = reactive<Record<string, any>>({
item: [],
});
//model
const monitorRegisterModal = ref();
onMounted(() => {
getYsInfo();
getCams();
});
/**
* 查看监控
*/
function handleMonitor(record) {
// monitorRegisterModal.value.disableSubmit = false;
monitorRegisterModal.value.statistic(record);
}
/**
* 获取萤石token
* 获取设备列表
*/
function getYsInfo() {
getYsToken().then((res) => {
function getCams() {
getCamList().then((res) => {
if (res.code == 200) {
formData.item = res.result;
console.log("====")
res.result.forEach((val) => {
val.deviceList.forEach((itm) => {
var player = new EZUIKit.EZUIKitPlayer({
id: itm.deployCode, // ID
accessToken: itm.ysToken,
url: itm.deviceUrl,
})
})
})
} else {
});
});
}
})
});
}
</script>
<style lang="less" scoped>
.video_head {
border: 1px solid #eee;
border-radius: 4px 4px 0 0;
padding: 0 12px;
box-sizing: border-box;
height: 40px;
line-height: 40px;
font-size: 16px;
color: #333;
display: flex;
justify-content: center;
align-items: center;
.video_tit {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.video_ctl {
width: 24px;
height: 40px;
cursor: pointer;
background: url('../../assets/video_icon.png') no-repeat right center;
}
}
</style>

View File

@ -0,0 +1,60 @@
<template>
<a-row v-for="value in formData.item" :key="value.id">
<a-col :span="24">
<a-card :title="value.stationName" style="width: 100%" size="default">
<a-row :gutter="16">
<a-col class="gutter-row" :span="12" v-for="value2 in value.deviceList" :key="value2.id">
<div class="gutter-box" :id="value2.deployCode" style="height:700px" >
</div>
</a-col>
</a-row>
</a-card>
</a-col>
</a-row>
</template>
<script lang="ts" setup>
import EZUIKit from 'ezuikit-js';
import { ref, onMounted,reactive } from 'vue'
import { getYsToken} from '../deploy/SurvDeviceDeploy.api';
const ysToken = ref('');
const formData = reactive<Record<string, any>>({
item: [],
});
onMounted(() => {
getYsInfo();
});
/**
* 获取萤石token
*/
function getYsInfo() {
getYsToken().then((res) => {
if (res.code == 200) {
formData.item= res.result;
res.result.forEach((val) => {
val.deviceList.forEach((itm) => {
var player = new EZUIKit.EZUIKitPlayer({
id: itm.deployCode, // ID
accessToken: itm.ysToken,
url: itm.deviceUrl,
})
})
})
} else {
}
})
}
</script>

View File

@ -10,7 +10,7 @@ export const columns: BasicColumn[] = [
dataIndex: 'stationName'
},
{
title: '运维项',
title: '监测情况',
align: "center",
dataIndex: 'maintainData1'
},
@ -20,7 +20,7 @@ export const columns: BasicColumn[] = [
// dataIndex: 'omName'
// },
{
title: '维时间',
title: '时间',
align: "center",
dataIndex: 'maintainTime'
},
@ -30,7 +30,7 @@ export const columns: BasicColumn[] = [
dataIndex: 'maintainNote'
},
{
title: '运维人员',
title: '负责人',
align: "center",
dataIndex: 'maintainPerson'
},
@ -53,7 +53,7 @@ export const formSchema: FormSchema[] = [
component: 'Input',
},
{
label: '维时间',
label: '时间',
field: 'maintainTime',
component: 'Input',
},
@ -63,7 +63,7 @@ export const formSchema: FormSchema[] = [
component: 'Input',
},
{
label: '运维人员',
label: '负责人',
field: 'maintainPerson',
component: 'Input',
},

View File

@ -19,15 +19,15 @@
</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-form-item label="维时间" name="maintainTime">
<a-form-item label="时间" name="maintainTime">
<a-date-picker placeholder="" v-model:value="queryParam.maintainTime" value-format="YYYY-MM-DD" style="width: 100%" />
</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-form-item label="运维人员" name="maintainPerson">
<a-input placeholder="请输入运维人员查询" v-model:value="queryParam.maintainPerson"></a-input>
<a-form-item label="负责人" name="maintainPerson">
<a-input placeholder="请输入负责人" v-model:value="queryParam.maintainPerson"></a-input>
</a-form-item>
</a-col>
</template>

View File

@ -18,8 +18,23 @@
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="运维项" v-bind="validateInfos.maintainData1">
<a-input v-model:value="formData.maintainData1" placeholder="请输入运维项" :disabled="disabled"></a-input>
<a-form-item label="站点位置" v-bind="validateInfos.maintainData3">
<a-input v-model:value="formData.maintainData3" placeholder="请输入站点位置" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="负责人" v-bind="validateInfos.maintainPerson">
<a-input v-model:value="formData.maintainPerson" placeholder="请输入负责人" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="联系方式" v-bind="validateInfos.maintainData2">
<a-input v-model:value="formData.maintainData2" placeholder="请输入联系方式" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="监测情况" v-bind="validateInfos.maintainData1">
<a-input v-model:value="formData.maintainData1" placeholder="请输入监测情况" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<!-- <a-col :span="24">
@ -38,7 +53,7 @@
</a-form-item>
</a-col> -->
<a-col :span="24">
<a-form-item label="维时间" v-bind="validateInfos.maintainTime">
<a-form-item label="时间" v-bind="validateInfos.maintainTime">
<a-date-picker placeholder="" v-model:value="formData.maintainTime" value-format="YYYY-MM-DD" style="width: 100%" />
</a-form-item>
</a-col>
@ -47,11 +62,7 @@
<a-input v-model:value="formData.maintainNote" placeholder="请输入备注" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="运维人员" v-bind="validateInfos.maintainPerson">
<a-input v-model:value="formData.maintainPerson" placeholder="请输入运维人员" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<!-- <a-col :span="24">
<a-form-item label="预留项2" v-bind="validateInfos.maintainData2">
@ -91,6 +102,7 @@
maintainPerson: '',
maintainData1: '',
maintainData2: '',
maintainData3: '',
tenantId: '',
reVision: undefined,
createdBy: '',
@ -104,10 +116,10 @@
const confirmLoading = ref<boolean>(false);
//
const validatorRules = {
maintainTime: [{ required: true, message: '维时间不能为空', trigger: 'blur' }],
maintainPerson: [{ required: true, message: '运维人员不能为空', trigger: 'blur' }],
maintainTime: [{ required: true, message: '时间不能为空', trigger: 'blur' }],
maintainPerson: [{ required: true, message: '负责人不能为空', trigger: 'blur' }],
stationCode: [{ required: true, message: '站点不能为空', trigger: 'blur' }],
itemId: [{ required: true, message: '运维项不能为空', trigger: 'blur' }],
itemId: [{ required: true, message: '监测情况不能为空', trigger: 'blur' }],
};
const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: true });

View File

@ -0,0 +1,72 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/appmana/survConfig/list',
save = '/appmana/survConfig/add',
edit = '/appmana/survConfig/edit',
deleteOne = '/appmana/survConfig/delete',
deleteBatch = '/appmana/survConfig/deleteBatch',
importExcel = '/appmana/survConfig/importExcel',
exportXls = '/appmana/survConfig/exportXls',
}
/**
* 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 });
}

View File

@ -0,0 +1,116 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
//列表数据
export const columns: BasicColumn[] = [
// {
// title: '所属主体',
// align: 'center',
// width: 200,
// dataIndex: 'tenantId_dictText'
// },
{
title: '参数类型',
align: 'center',
width: 200,
dataIndex: 'configTypeName'
},
{
title: '参数名称',
align: 'center',
width: 200,
dataIndex: 'configName'
},
{
title: '参数键名',
align: 'center',
width: 150,
dataIndex: 'configKey'
},
{
title: '参数键值',
align: 'center',
width: 270,
dataIndex: 'configValue'
},
{
title: '创建时间',
align: 'center',
width: 120,
dataIndex: 'createTime',
customRender:({text}) =>{
return !text?'':(text.length>10?text.substr(0,10):text);
},
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '参数名称',
field: 'configName',
component: 'Input',
},
{
label: '参数键名',
field: 'configKey',
component: 'Input',
},
{
label: '参数键值',
field: 'configValue',
component: 'Input',
},
{
label: '系统内置',
field: 'configType',
component: 'Input',
},
{
label: '备注',
field: 'configRemark',
component: 'Input',
},
{
label: '租户号',
field: 'tenantId',
component: 'Input',
},
{
label: '乐观锁',
field: 'reVision',
component: 'InputNumber',
},
{
label: '创建人',
field: 'createdBy',
component: 'Input',
},
{
label: '更新人',
field: 'updatedBy',
component: 'Input',
},
{
label: '逻辑删除',
field: 'isDel',
component: 'InputNumber',
},
{
label: '更新时间',
field: 'updatedTime',
component: 'DatePicker',
},
// TODO 主键隐藏字段目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];

View File

@ -0,0 +1,249 @@
<template>
<div>
<!--查询区域-->
<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:-35px;margin-top: 16px;">-->
<!-- <a-form-item label="主体名称" name="tenantId">-->
<!-- <j-search-select v-model:value="queryParam.tenantId" dict="f_company,company_name,company_id" placeholder="请选择主体名称" />-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<a-col :xs="24" :sm="8" :md="6" :lg="8" :xl="6" :xxl="6" style="margin-left:-35px;margin-top: 16px;">
<a-form-item label="参数类型" name="configType">
<j-search-select v-model:value="queryParam.configType" dict="apply_config_type" placeholder="请选择参数类型" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="6" :lg="8" :xl="6" :xxl="6" style="margin-left:-35px;margin-top: 16px;">
<a-form-item label="配置项名称" name="configName">
<a-input placeholder="配置项名称" v-model:value="queryParam.configName"></a-input>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="6" :lg="8" :xl="6" :xxl="6" style="margin-left:-35px;margin-top: 16px;">
<span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
<a-col :lg="6">
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
<a-button type="primary" preIcon="ic:baseline-restart-alt" @click="searchReset" style="margin-left: 8px;color:black;background-color: white;">重置</a-button>
</a-col>
</span>
</a-col>
</a-row>
</a-form>
</div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<!-- <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> -->
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button>批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
</template>
<!--字段回显插槽-->
<template #htmlSlot="{text}">
<div v-html="text"></div>
</template>
<!--省市区字段回显插槽-->
<template #pcaSlot="{text}">
{{ getAreaTextByCode(text) }}
</template>
<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>
<!-- 表单区域 -->
<FSurvConfigModal ref="registerModal" @success="handleSuccess"></FSurvConfigModal>
</div>
</template>
<script lang="ts" name="farm-fSurvConfig" setup>
import { ref, reactive } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns } from './FSurvConfig.data';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './FSurvConfig.api';
import { downloadFile } from '/@/utils/common/renderUtils';
import JSearchSelect from '/@/components/Form/src/jeecg/components/JSearchSelect.vue'
import FSurvConfigModal from './components/FSurvConfigModal.vue'
const formRef = ref();
const queryParam = reactive<any>({});
const toggleSearchStatus = ref<boolean>(false);
const registerModal = ref();
//table
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
tableProps: {
title: 'farm',
api: list,
columns,
canResize:false,
useSearchForm: false,
actionColumn: {
width: 150,
fixed: 'right',
},
beforeFetch: (params) => {
return Object.assign(params, queryParam);
},
},
exportConfig: {
name: "farm",
url: getExportUrl,
params: queryParam,
},
importConfig: {
url: getImportUrl,
success: handleSuccess
},
});
const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] = tableContext;
const labelCol = reactive({
xs: { span: 24 },
sm: { span: 7 },
});
const wrapperCol = reactive({
xs: { span: 24 },
sm: { span: 16 },
});
/**
* 新增事件
*/
function handleAdd() {
registerModal.value.disableSubmit = false;
registerModal.value.add();
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
registerModal.value.disableSubmit = false;
registerModal.value.edit(record);
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
registerModal.value.disableSubmit = true;
registerModal.value.edit(record);
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({ id: record.id }, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
},
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},{
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
}
},
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
]
}
/**
* 查询
*/
function searchQuery() {
reload();
}
/**
* 重置
*/
function searchReset() {
formRef.value.resetFields();
selectedRowKeys.value = [];
//
reload();
}
</script>
<style lang="less" scoped>
.jeecg-basic-table-form-container {
.table-page-search-submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
.query-group-cust{
width: calc(50% - 15px);
min-width: 100px !important;
}
.query-group-split-cust{
width: 30px;
display: inline-block;
text-align: center
}
}
</style>

View File

@ -0,0 +1,196 @@
<template>
<a-spin :spinning="confirmLoading">
<a-form ref="formRef" class="antd-modal-form" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-row>
<!-- <a-col :span="24">-->
<!-- <a-form-item label="所属主体" v-bind="validateInfos.tenantId">-->
<!-- <JDictSelectTag type="select" v-model:value="formData.tenantId" dictCode="f_company,company_name,company_id" placeholder="请选择所属主体" />-->
<!-- </a-form-item>-->
<!-- </a-col>-->
<a-col :span="24">
<a-form-item label="参数类型" v-bind="validateInfos.configType">
<JDictSelectTag type="select" v-model:value="formData.configType" dictCode="apply_config_type" placeholder="请选择参数类型" />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="参数名称" v-bind="validateInfos.configName">
<a-input v-model:value="formData.configName" placeholder="请输入参数名称" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="参数Key" v-bind="validateInfos.configKey">
<a-input v-model:value="formData.configKey" placeholder="请输入参数Key" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="参数键值" v-bind="validateInfos.configValue">
<a-input v-model:value="formData.configValue" placeholder="请输入参数键值" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="参数键值2" v-bind="validateInfos.configValueSe">
<a-input v-model:value="formData.configValueSe" placeholder="" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="参数键值3" v-bind="validateInfos.configValueSe2">
<a-input v-model:value="formData.configValueSe2" placeholder="" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="参数键值4" v-bind="validateInfos.configValueSe3">
<a-input v-model:value="formData.configValueSe3" placeholder="" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="参数键值5" v-bind="validateInfos.configValueSe4">
<a-input v-model:value="formData.configValueSe4" placeholder="" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="自定义配置" v-bind="validateInfos.configJsonStr">
<a-textarea v-model:value="formData.configJsonStr" placeholder="自定义配置" :disabled="disabled"></a-textarea>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="备注" v-bind="validateInfos.configRemark">
<a-input v-model:value="formData.configRemark" placeholder="请输入备注" :disabled="disabled"></a-input>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-spin>
</template>
<script lang="ts" setup>
import { ref, reactive, defineExpose, nextTick, defineProps, computed, onMounted } from 'vue';
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import { getValueType } from '/@/utils';
import { saveOrUpdate } from '../FSurvConfig.api';
import { Form } from 'ant-design-vue';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
const props = defineProps({
formDisabled: { type: Boolean, default: false },
formData: { type: Object, default: ()=>{} },
formBpm: { type: Boolean, default: true }
});
const formRef = ref();
const useForm = Form.useForm;
const emit = defineEmits(['register', 'ok']);
const formData = reactive<Record<string, any>>({
id: '',
configName: '',
configKey: '',
configValue: '',
configValueSe:'',
configValueSe2:'',
configValueSe3:'',
configValueSe4:'',
configJsonStr:'',
configType: '',
configRemark: '',
tenantId: '',
reVision: undefined,
createdBy: '',
updatedBy: '',
isDel: undefined,
updatedTime: '',
});
const { createMessage } = useMessage();
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 5 } });
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
const confirmLoading = ref<boolean>(false);
//
const validatorRules = {
tenantId: [{ required: true, message: '主体不能为空', trigger: 'blur' }],
configName: [{ required: true, message: '参数名称不能为空', trigger: 'blur' }],
configType: [{ required: true, message: '参数类型不能为空', trigger: 'blur' }],
};
const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: true });
//
const disabled = computed(()=>{
if(props.formBpm === true){
if(props.formData.disabled === false){
return false;
}else{
return true;
}
}
return props.formDisabled;
});
/**
* 新增
*/
function add() {
edit({});
}
/**
* 编辑
*/
function edit(record) {
nextTick(() => {
resetFields();
//
Object.assign(formData, record);
});
}
/**
* 提交数据
*/
async function submitForm() {
//
await validate();
confirmLoading.value = true;
const isUpdate = ref<boolean>(false);
//
let model = formData;
if (model.id) {
isUpdate.value = true;
}
//
for (let data in model) {
//
if (model[data] instanceof Array) {
let valueType = getValueType(formRef.value.getProps, data);
//
if (valueType === 'string') {
model[data] = model[data].join(',');
}
}
}
await saveOrUpdate(model, isUpdate.value)
.then((res) => {
if (res.success) {
createMessage.success(res.message);
emit('ok');
} else {
createMessage.warning(res.message);
}
})
.finally(() => {
confirmLoading.value = false;
});
}
defineExpose({
add,
edit,
submitForm,
});
</script>
<style lang="less" scoped>
.antd-modal-form {
min-height: 350px !important;
overflow-y: auto;
padding: 24px 24px 24px 24px;
}
</style>

View File

@ -0,0 +1,75 @@
<template>
<a-modal :title="title" :width="width" :visible="visible" @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭">
<FSurvConfigForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"></FSurvConfigForm>
</a-modal>
</template>
<script lang="ts" setup>
import { ref, nextTick, defineExpose } from 'vue';
import FSurvConfigForm from './FSurvConfigForm.vue'
const title = ref<string>('');
const width = ref<number>(800);
const visible = ref<boolean>(false);
const disableSubmit = ref<boolean>(false);
const registerForm = ref();
const emit = defineEmits(['register', 'success']);
/**
* 新增
*/
function add() {
title.value = '新增设备连接配置';
visible.value = true;
nextTick(() => {
registerForm.value.add();
});
}
/**
* 编辑
* @param record
*/
function edit(record) {
title.value = disableSubmit.value ? '设备连接配置详情' : '编辑设备连接配置';
visible.value = true;
nextTick(() => {
registerForm.value.edit(record);
});
}
/**
* 确定按钮点击事件
*/
function handleOk() {
registerForm.value.submitForm();
}
/**
* form保存回调事件
*/
function submitCallback() {
handleCancel();
emit('success');
}
/**
* 取消按钮回调事件
*/
function handleCancel() {
visible.value = false;
}
defineExpose({
add,
edit,
disableSubmit,
});
</script>
<style>
/**隐藏样式-modal确定按钮 */
.jee-hidden {
display: none !important;
}
</style>