视频播放调试完成
This commit is contained in:
parent
a40836ea9b
commit
8cc362bc82
|
|
@ -9,11 +9,13 @@
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kjgl77/datav-vue3": "^1.7.4",
|
"@kjgl77/datav-vue3": "^1.7.4",
|
||||||
|
"@vueuse/core": "^13.4.0",
|
||||||
"axios": "1.7.7",
|
"axios": "1.7.7",
|
||||||
"codess": "^1.1.5",
|
"codess": "^1.1.5",
|
||||||
"copy-to-clipboard": "3.3.3",
|
"copy-to-clipboard": "3.3.3",
|
||||||
"cropperjs": "1.6.2",
|
"cropperjs": "1.6.2",
|
||||||
"echarts": "5.5.1",
|
"echarts": "5.5.1",
|
||||||
|
"flv.js": "^1.6.2",
|
||||||
"glob": "11.0.0",
|
"glob": "11.0.0",
|
||||||
"mime": "4.0.4",
|
"mime": "4.0.4",
|
||||||
"mitt": "3.0.1",
|
"mitt": "3.0.1",
|
||||||
|
|
@ -31,6 +33,7 @@
|
||||||
"vuedraggable": "4.1.0"
|
"vuedraggable": "4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@vicons/ionicons5": "^0.13.0",
|
||||||
"@vitejs/plugin-vue": "5.1.2",
|
"@vitejs/plugin-vue": "5.1.2",
|
||||||
"naive-ui": "^2.42.0",
|
"naive-ui": "^2.42.0",
|
||||||
"vite": "5.4.1"
|
"vite": "5.4.1"
|
||||||
|
|
@ -627,6 +630,74 @@
|
||||||
"@vueuse/core": "^10.11.1"
|
"@vueuse/core": "^10.11.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@kjgl77/datav-vue3/node_modules/@types/web-bluetooth": {
|
||||||
|
"version": "0.0.20",
|
||||||
|
"resolved": "https://repo.huaweicloud.com/repository/npm/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
|
||||||
|
"integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@kjgl77/datav-vue3/node_modules/@vueuse/core": {
|
||||||
|
"version": "10.11.1",
|
||||||
|
"resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/core/-/core-10.11.1.tgz",
|
||||||
|
"integrity": "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/web-bluetooth": "^0.0.20",
|
||||||
|
"@vueuse/metadata": "10.11.1",
|
||||||
|
"@vueuse/shared": "10.11.1",
|
||||||
|
"vue-demi": ">=0.14.8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@kjgl77/datav-vue3/node_modules/@vueuse/metadata": {
|
||||||
|
"version": "10.11.1",
|
||||||
|
"resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/metadata/-/metadata-10.11.1.tgz",
|
||||||
|
"integrity": "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@kjgl77/datav-vue3/node_modules/@vueuse/shared": {
|
||||||
|
"version": "10.11.1",
|
||||||
|
"resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/shared/-/shared-10.11.1.tgz",
|
||||||
|
"integrity": "sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"vue-demi": ">=0.14.8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@kjgl77/datav-vue3/node_modules/vue-demi": {
|
||||||
|
"version": "0.14.10",
|
||||||
|
"resolved": "https://repo.huaweicloud.com/repository/npm/vue-demi/-/vue-demi-0.14.10.tgz",
|
||||||
|
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||||
|
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@vue/composition-api": "^1.0.0-rc.1",
|
||||||
|
"vue": "^3.0.0-0 || ^2.6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@vue/composition-api": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@nodelib/fs.scandir": {
|
"node_modules/@nodelib/fs.scandir": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||||
|
|
@ -914,9 +985,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/web-bluetooth": {
|
"node_modules/@types/web-bluetooth": {
|
||||||
"version": "0.0.20",
|
"version": "0.0.21",
|
||||||
"resolved": "https://repo.huaweicloud.com/repository/npm/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
|
"resolved": "https://repo.huaweicloud.com/repository/npm/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
|
||||||
"integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==",
|
"integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@vicons/ionicons5": {
|
||||||
|
"version": "0.13.0",
|
||||||
|
"resolved": "https://repo.huaweicloud.com/repository/npm/@vicons/ionicons5/-/ionicons5-0.13.0.tgz",
|
||||||
|
"integrity": "sha512-zvZKBPjEXKN7AXNo2Na2uy+nvuv6SP4KAMQxpKL2vfHMj0fSvuw7JZcOPCjQC3e7ayssKnaoFVAhbYcW6v41qQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@vitejs/plugin-vue": {
|
"node_modules/@vitejs/plugin-vue": {
|
||||||
|
|
@ -1029,90 +1107,41 @@
|
||||||
"integrity": "sha512-L2MCDD8l7yC62Te5UUyPVpmexhL9ipVnYRw9CsWfm/BGRL5FwDX4a25bcJ/OJSD3+Hx+k/a8LDKcG2AFdJV3BA=="
|
"integrity": "sha512-L2MCDD8l7yC62Te5UUyPVpmexhL9ipVnYRw9CsWfm/BGRL5FwDX4a25bcJ/OJSD3+Hx+k/a8LDKcG2AFdJV3BA=="
|
||||||
},
|
},
|
||||||
"node_modules/@vueuse/core": {
|
"node_modules/@vueuse/core": {
|
||||||
"version": "10.11.1",
|
"version": "13.4.0",
|
||||||
"resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/core/-/core-10.11.1.tgz",
|
"resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/core/-/core-13.4.0.tgz",
|
||||||
"integrity": "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==",
|
"integrity": "sha512-OnK7zW3bTq/QclEk17+vDFN3tuAm8ONb9zQUIHrYQkkFesu3WeGUx/3YzpEp+ly53IfDAT9rsYXgGW6piNZC5w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/web-bluetooth": "^0.0.20",
|
"@types/web-bluetooth": "^0.0.21",
|
||||||
"@vueuse/metadata": "10.11.1",
|
"@vueuse/metadata": "13.4.0",
|
||||||
"@vueuse/shared": "10.11.1",
|
"@vueuse/shared": "13.4.0"
|
||||||
"vue-demi": ">=0.14.8"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/antfu"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@vueuse/core/node_modules/vue-demi": {
|
|
||||||
"version": "0.14.10",
|
|
||||||
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz",
|
|
||||||
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"bin": {
|
|
||||||
"vue-demi-fix": "bin/vue-demi-fix.js",
|
|
||||||
"vue-demi-switch": "bin/vue-demi-switch.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/antfu"
|
"url": "https://github.com/sponsors/antfu"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@vue/composition-api": "^1.0.0-rc.1",
|
"vue": "^3.5.0"
|
||||||
"vue": "^3.0.0-0 || ^2.6.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"@vue/composition-api": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vueuse/metadata": {
|
"node_modules/@vueuse/metadata": {
|
||||||
"version": "10.11.1",
|
"version": "13.4.0",
|
||||||
"resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/metadata/-/metadata-10.11.1.tgz",
|
"resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/metadata/-/metadata-13.4.0.tgz",
|
||||||
"integrity": "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==",
|
"integrity": "sha512-CPDQ/IgOeWbqItg1c/pS+Ulum63MNbpJ4eecjFJqgD/JUCJ822zLfpw6M9HzSvL6wbzMieOtIAW/H8deQASKHg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/antfu"
|
"url": "https://github.com/sponsors/antfu"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vueuse/shared": {
|
"node_modules/@vueuse/shared": {
|
||||||
"version": "10.11.1",
|
"version": "13.4.0",
|
||||||
"resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/shared/-/shared-10.11.1.tgz",
|
"resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/shared/-/shared-13.4.0.tgz",
|
||||||
"integrity": "sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==",
|
"integrity": "sha512-+AxuKbw8R1gYy5T21V5yhadeNM7rJqb4cPaRI9DdGnnNl3uqXh+unvQ3uCaA2DjYLbNr1+l7ht/B4qEsRegX6A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
|
||||||
"vue-demi": ">=0.14.8"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/antfu"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@vueuse/shared/node_modules/vue-demi": {
|
|
||||||
"version": "0.14.10",
|
|
||||||
"resolved": "https://repo.huaweicloud.com/repository/npm/vue-demi/-/vue-demi-0.14.10.tgz",
|
|
||||||
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"vue-demi-fix": "bin/vue-demi-fix.js",
|
|
||||||
"vue-demi-switch": "bin/vue-demi-switch.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/antfu"
|
"url": "https://github.com/sponsors/antfu"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@vue/composition-api": "^1.0.0-rc.1",
|
"vue": "^3.5.0"
|
||||||
"vue": "^3.0.0-0 || ^2.6.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"@vue/composition-api": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
|
|
@ -1869,6 +1898,12 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/es6-promise": {
|
||||||
|
"version": "4.2.8",
|
||||||
|
"resolved": "https://repo.huaweicloud.com/repository/npm/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||||
|
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.21.5",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.21.5.tgz",
|
||||||
|
|
@ -2014,6 +2049,16 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/flv.js": {
|
||||||
|
"version": "1.6.2",
|
||||||
|
"resolved": "https://repo.huaweicloud.com/repository/npm/flv.js/-/flv.js-1.6.2.tgz",
|
||||||
|
"integrity": "sha512-xre4gUbX1MPtgQRKj2pxJENp/RnaHaxYvy3YToVVCrSmAWUu85b9mug6pTXF6zakUjNP2lFWZ1rkSX7gxhB/2A==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"es6-promise": "^4.2.8",
|
||||||
|
"webworkify-webpack": "^2.1.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.9",
|
"version": "1.15.9",
|
||||||
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||||
|
|
@ -4464,6 +4509,12 @@
|
||||||
"resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
|
"resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
|
||||||
"integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="
|
"integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/webworkify-webpack": {
|
||||||
|
"version": "2.1.5",
|
||||||
|
"resolved": "https://repo.huaweicloud.com/repository/npm/webworkify-webpack/-/webworkify-webpack-2.1.5.tgz",
|
||||||
|
"integrity": "sha512-2akF8FIyUvbiBBdD+RoHpoTbHMQF2HwjcxfDvgztAX5YwbZNyrtfUMgvfgFVsgDhDPVTlkbb5vyasqDHfIDPQw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz",
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,13 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kjgl77/datav-vue3": "^1.7.4",
|
"@kjgl77/datav-vue3": "^1.7.4",
|
||||||
|
"@vueuse/core": "^13.4.0",
|
||||||
"axios": "1.7.7",
|
"axios": "1.7.7",
|
||||||
"codess": "^1.1.5",
|
"codess": "^1.1.5",
|
||||||
"copy-to-clipboard": "3.3.3",
|
"copy-to-clipboard": "3.3.3",
|
||||||
"cropperjs": "1.6.2",
|
"cropperjs": "1.6.2",
|
||||||
"echarts": "5.5.1",
|
"echarts": "5.5.1",
|
||||||
|
"flv.js": "^1.6.2",
|
||||||
"glob": "11.0.0",
|
"glob": "11.0.0",
|
||||||
"mime": "4.0.4",
|
"mime": "4.0.4",
|
||||||
"mitt": "3.0.1",
|
"mitt": "3.0.1",
|
||||||
|
|
@ -34,6 +36,7 @@
|
||||||
"vuedraggable": "4.1.0"
|
"vuedraggable": "4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@vicons/ionicons5": "^0.13.0",
|
||||||
"@vitejs/plugin-vue": "5.1.2",
|
"@vitejs/plugin-vue": "5.1.2",
|
||||||
"naive-ui": "^2.42.0",
|
"naive-ui": "^2.42.0",
|
||||||
"vite": "5.4.1"
|
"vite": "5.4.1"
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
|
|
@ -0,0 +1,73 @@
|
||||||
|
<template>
|
||||||
|
<!-- 模态框通用样式 -->
|
||||||
|
<n-card
|
||||||
|
size="huge"
|
||||||
|
role="dialog"
|
||||||
|
aria-modal="true"
|
||||||
|
:bordered="false"
|
||||||
|
class="modal-container"
|
||||||
|
:style="{ width: width, height: height }"
|
||||||
|
>
|
||||||
|
<n-flex justify="space-between" style="height: 40px">
|
||||||
|
<n-gradient-text
|
||||||
|
style="font-size: 20px; font-weight: 600; letter-spacing: 2px"
|
||||||
|
gradient="linear-gradient(90deg, #CDF7FD 0%, #DAFAFE 20%, #CDF7FD 40%, #DAFAFE 60%, #CDF7FD 80%, #DAFAFE 100%)"
|
||||||
|
>
|
||||||
|
{{ modalTitle }}
|
||||||
|
</n-gradient-text>
|
||||||
|
|
||||||
|
<img
|
||||||
|
class="close-icon"
|
||||||
|
src="@/assets/home-imgs/close.png"
|
||||||
|
@click="onHandleCloseModal"
|
||||||
|
/>
|
||||||
|
</n-flex>
|
||||||
|
|
||||||
|
<div class="modal-content">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</n-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '80%',
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
modalTitle: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const emits = defineEmits(['onHandleCloseModal'])
|
||||||
|
|
||||||
|
// 关闭模态框
|
||||||
|
const onHandleCloseModal = () => {
|
||||||
|
emits('onHandleCloseModal')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.modal-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: url('@/assets/home-imgs/modal-bg.png') no-repeat center center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
flex: 1;
|
||||||
|
height: calc(100% - 40px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
<template>
|
||||||
|
<!-- 视频播放器 Flv格式视频 -->
|
||||||
|
<video
|
||||||
|
:id="videoId"
|
||||||
|
autoplay
|
||||||
|
controls
|
||||||
|
@timeupdate="progress($event)"
|
||||||
|
style="width: 100%; height: 100%; border-radius: 12px"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import flv from 'flv.js'
|
||||||
|
import { ref, watch, nextTick } from 'vue'
|
||||||
|
|
||||||
|
let flvPlayerList = []
|
||||||
|
let replayCount = 0
|
||||||
|
|
||||||
|
let errorMsg = ref('')
|
||||||
|
const playUrl = ref('')
|
||||||
|
const dfp = defineProps({
|
||||||
|
cameraNode: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
steamType: {
|
||||||
|
type: String,
|
||||||
|
default: 'HTTP-FLV',
|
||||||
|
},
|
||||||
|
videoId: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const playvideo = () => {
|
||||||
|
errorMsg.value = ''
|
||||||
|
if (flv.isSupported()) {
|
||||||
|
stopvideo()
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
let videoElement = document.getElementById(dfp.videoId)
|
||||||
|
|
||||||
|
console.log(videoElement, 'videoElement')
|
||||||
|
videoElement.contorls = true
|
||||||
|
let flvPlayer = flv.createPlayer({
|
||||||
|
type: 'flv',
|
||||||
|
isLive: true,
|
||||||
|
hasAudio: false,
|
||||||
|
url: playUrl.value,
|
||||||
|
})
|
||||||
|
flvPlayer.attachMediaElement(videoElement)
|
||||||
|
flvPlayer.load()
|
||||||
|
setTimeout(function () {
|
||||||
|
flvPlayer.play()
|
||||||
|
}, 100)
|
||||||
|
flvPlayer.on('error', function (error) {
|
||||||
|
errorMsg.value = error
|
||||||
|
if (replayCount > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
replayCount++
|
||||||
|
setTimeout(function () {
|
||||||
|
console.log('flvjs replayCount', replayCount)
|
||||||
|
playvideo()
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
|
flvPlayer.on('scriptdata_arrived', function (e) {
|
||||||
|
errorMsg.value = ''
|
||||||
|
flvPlayerList.push(flvPlayer)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ElMessage({
|
||||||
|
message: '当前浏览器不支持flvjs播放',
|
||||||
|
type: 'error',
|
||||||
|
duration: 2000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const stopvideo = async () => {
|
||||||
|
if (flvPlayerList.length) {
|
||||||
|
flvPlayerList.forEach((item) => {
|
||||||
|
if (item) {
|
||||||
|
item.unload()
|
||||||
|
item.detachMediaElement()
|
||||||
|
item.destroy()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
flvPlayerList = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const progress = (e) => {
|
||||||
|
let self = this
|
||||||
|
var bf = e.srcElement.buffered
|
||||||
|
var currentTime = e.srcElement.currentTime
|
||||||
|
if (bf.length > 0) {
|
||||||
|
let end = bf.end(0)
|
||||||
|
if (end - currentTime > 10) {
|
||||||
|
e.srcElement.currentTime = end - 0.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => dfp.cameraNode,
|
||||||
|
() => {
|
||||||
|
errorMsg.value = ''
|
||||||
|
console.log(dfp.cameraNode, 'dfp.cameraNode')
|
||||||
|
if (dfp.cameraNode.steamURL) {
|
||||||
|
playUrl.value =
|
||||||
|
dfp.cameraNode.steamURL +
|
||||||
|
'&puid=' +
|
||||||
|
dfp.cameraNode.puid +
|
||||||
|
'&idx=' +
|
||||||
|
dfp.cameraNode.idx +
|
||||||
|
'&stream=' +
|
||||||
|
dfp.cameraNode.stream
|
||||||
|
|
||||||
|
// console.log(dfp.cameraNode.steamURL, 'playUrl.value')
|
||||||
|
console.log(playUrl.value, 'playUrl.value')
|
||||||
|
playvideo()
|
||||||
|
} else {
|
||||||
|
stopvideo()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{ deep: true },
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
#video {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: fill;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -11,7 +11,7 @@ const timeout = 13000 //api请求超时时间
|
||||||
|
|
||||||
export const service = axios.create({
|
export const service = axios.create({
|
||||||
//可创建多个 axios实例
|
//可创建多个 axios实例
|
||||||
baseURL: baseApiURL, //设置公共的请求前缀
|
baseURL: '', //设置公共的请求前缀
|
||||||
timeout: timeout, //超时终止请求
|
timeout: timeout, //超时终止请求
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -38,10 +38,11 @@ service.interceptors.response.use(
|
||||||
msg: '请求发生错误',
|
msg: '请求发生错误',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const status = data.status
|
const status = data?.status || response.status
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 200:
|
case 200:
|
||||||
return data
|
// return data
|
||||||
|
return Promise.resolve(response)
|
||||||
case 401: //表示需要重新登录
|
case 401: //表示需要重新登录
|
||||||
if (!modelShow) {
|
if (!modelShow) {
|
||||||
modelShow = true
|
modelShow = true
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
/** 用户全局数据 */
|
/** 用户全局数据 */
|
||||||
|
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia'
|
||||||
import allStorage from '@/action/storageManage';
|
import allStorage from '@/action/storageManage'
|
||||||
|
|
||||||
export const userDataStore = defineStore('userDataStore', {
|
export const userDataStore = defineStore('userDataStore', {
|
||||||
state: () => {
|
state: () => {
|
||||||
const userStorage = allStorage.userStorage();
|
const userStorage = allStorage.userStorage()
|
||||||
/** 校验数据 */
|
/** 校验数据 */
|
||||||
let userInfo = userStorage.value;
|
let userInfo = userStorage.value
|
||||||
if (typeof userInfo !== 'object') {
|
if (typeof userInfo !== 'object') {
|
||||||
userInfo = {};
|
userInfo = {}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
userInfo: userInfo || {}, //当前登录用户的基础数据
|
userInfo: userInfo || {}, //当前登录用户的基础数据
|
||||||
|
|
@ -18,30 +18,30 @@ export const userDataStore = defineStore('userDataStore', {
|
||||||
userMenuList: [], //用于展示的菜单列表,结构树形化
|
userMenuList: [], //用于展示的菜单列表,结构树形化
|
||||||
tagsMap: {}, // 页面标签MAP,layoutName为键名
|
tagsMap: {}, // 页面标签MAP,layoutName为键名
|
||||||
iframeList: [], //iframe 数组,iframe也属于标签,跟标签挂钩
|
iframeList: [], //iframe 数组,iframe也属于标签,跟标签挂钩
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
getters: {},
|
getters: {},
|
||||||
actions: {
|
actions: {
|
||||||
setUserInfo(value) {
|
setUserInfo(value) {
|
||||||
this.userInfo = value || {};
|
this.userInfo = value || {}
|
||||||
/** 存入缓存 */
|
/** 存入缓存 */
|
||||||
const userStorage = allStorage.userStorage();
|
const userStorage = allStorage.userStorage()
|
||||||
userStorage.value = value;
|
userStorage.value = value
|
||||||
},
|
},
|
||||||
setUserMenuConfigNameMap(value) {
|
setUserMenuConfigNameMap(value) {
|
||||||
this.userMenuConfigNameMap = value || {};
|
this.userMenuConfigNameMap = value || {}
|
||||||
},
|
},
|
||||||
setUserMenuConfigPathMap(value) {
|
setUserMenuConfigPathMap(value) {
|
||||||
this.userMenuConfigPathMap = value || {};
|
this.userMenuConfigPathMap = value || {}
|
||||||
},
|
},
|
||||||
setUserMenuList(value) {
|
setUserMenuList(value) {
|
||||||
this.userMenuList = value || [];
|
this.userMenuList = value || []
|
||||||
},
|
},
|
||||||
setTagsMap(value) {
|
setTagsMap(value) {
|
||||||
this.tagsMap = value || {};
|
this.tagsMap = value || {}
|
||||||
},
|
},
|
||||||
setIframeList(value) {
|
setIframeList(value) {
|
||||||
this.iframeList = value || [];
|
this.iframeList = value || []
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { service } from '@/http/request'
|
||||||
|
// 初始化登录
|
||||||
|
export const initLoginApi = (data) => {
|
||||||
|
return service.post('/third-party/login', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取设备的URL地址
|
||||||
|
export const getDeviceUrlApi = (data) => {
|
||||||
|
return service.post('/third-party/stream/live', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调整设备的摄像机视角
|
||||||
|
export const changeDeviceCameraApi = (data) => {
|
||||||
|
return service.post('/third-party/ptz/start/turn', data)
|
||||||
|
}
|
||||||
|
// 停止设备的摄像机视角
|
||||||
|
export const stopDeviceCameraApi = (data) => {
|
||||||
|
return service.post('/third-party/ptz/stop/turn', data)
|
||||||
|
}
|
||||||
|
|
@ -1,16 +1,33 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- 中一 ---- 自巡检视角 -->
|
<!-- 中一 ---- 自巡检视角 -->
|
||||||
<div class="center-one child-container">
|
<div class="center-one child-container">
|
||||||
<div class="view-title">自巡检视角</div>
|
<div class="view-title" v-if="!fullScreenVisible">自巡检视角</div>
|
||||||
<div class="video-container">
|
<div class="video-container">
|
||||||
<video controls style="width: 100%; height: 100%; border-radius: 12px" autoplay>
|
<!-- <video controls style="width: 100%; height: 100%; border-radius: 12px" autoplay>
|
||||||
<source src="@/assets/video/测试.mp4" type="video/mp4" autoplay />
|
<source src="@/assets/video/测试.mp4" type="video/mp4" autoplay />
|
||||||
</video>
|
</video> -->
|
||||||
|
<FlvPlayer :cameraNode="cameraNode_2" :videoId="props.videoId" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup></script>
|
<script setup>
|
||||||
|
import FlvPlayer from '@/components/FlvPlayer/index.vue'
|
||||||
|
const props = defineProps({
|
||||||
|
cameraNode_2: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
videoId: {
|
||||||
|
type: String,
|
||||||
|
default: 'video-5',
|
||||||
|
},
|
||||||
|
fullScreenVisible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.center-one {
|
.center-one {
|
||||||
|
|
|
||||||
|
|
@ -45,25 +45,29 @@
|
||||||
class="arrow-top hand-direction"
|
class="arrow-top hand-direction"
|
||||||
src="@/assets/home-imgs/control-2-arrow.png"
|
src="@/assets/home-imgs/control-2-arrow.png"
|
||||||
alt=""
|
alt=""
|
||||||
|
@click="handleChangeCamera('TurnUp')"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
class="arrow-right hand-direction"
|
class="arrow-right hand-direction"
|
||||||
src="@/assets/home-imgs/control-2-arrow.png"
|
src="@/assets/home-imgs/control-2-arrow.png"
|
||||||
alt=""
|
alt=""
|
||||||
|
@click="handleChangeCamera('TurnRight')"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
class="arrow-bottom hand-direction"
|
class="arrow-bottom hand-direction"
|
||||||
src="@/assets/home-imgs/control-2-arrow.png"
|
src="@/assets/home-imgs/control-2-arrow.png"
|
||||||
alt=""
|
alt=""
|
||||||
|
@click="handleChangeCamera('TurnDown')"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
class="arrow-left hand-direction"
|
class="arrow-left hand-direction"
|
||||||
src="@/assets/home-imgs/control-2-arrow.png"
|
src="@/assets/home-imgs/control-2-arrow.png"
|
||||||
alt=""
|
alt=""
|
||||||
|
@click="handleChangeCamera('TurnLeft')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 中间的按钮 -->
|
<!-- 中间的按钮 -->
|
||||||
<div class="row-3-item-1-center">
|
<div class="row-3-item-1-center" @click="handleStopCamera">
|
||||||
<img
|
<img
|
||||||
class="center-icon"
|
class="center-icon"
|
||||||
src="@/assets/home-imgs/control-2-stop.png"
|
src="@/assets/home-imgs/control-2-stop.png"
|
||||||
|
|
@ -84,8 +88,13 @@
|
||||||
style="margin-bottom: 2px"
|
style="margin-bottom: 2px"
|
||||||
src="@/assets/home-imgs/control-2-add.png"
|
src="@/assets/home-imgs/control-2-add.png"
|
||||||
alt=""
|
alt=""
|
||||||
|
@click="handleChangeCamera('ZoomIn')"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
src="@/assets/home-imgs/control-2-reduce.png"
|
||||||
|
alt=""
|
||||||
|
@click="handleChangeCamera('ZoomOut')"
|
||||||
/>
|
/>
|
||||||
<img src="@/assets/home-imgs/control-2-reduce.png" alt="" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</n-grid-item>
|
</n-grid-item>
|
||||||
|
|
@ -245,6 +254,8 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
|
|
||||||
|
import { changeDeviceCameraApi, stopDeviceCameraApi } from '@/utils/initLogin'
|
||||||
|
|
||||||
const upDownHeight = ref(30)
|
const upDownHeight = ref(30)
|
||||||
const container = ref(null)
|
const container = ref(null)
|
||||||
const draggable = ref(null)
|
const draggable = ref(null)
|
||||||
|
|
@ -333,6 +344,28 @@ const handleChange4 = (e) => {
|
||||||
const formatTooltip = (value) => {
|
const formatTooltip = (value) => {
|
||||||
return `${value}%`
|
return `${value}%`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleChangeCamera = async (direction) => {
|
||||||
|
// console.log(direction)
|
||||||
|
const res = await changeDeviceCameraApi({
|
||||||
|
token: localStorage.getItem('token'),
|
||||||
|
puid: '201115200268437643',
|
||||||
|
idx: 1,
|
||||||
|
motion: direction,
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(res, '调整位置---')
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleStopCamera = async () => {
|
||||||
|
const res = await stopDeviceCameraApi({
|
||||||
|
token: localStorage.getItem('token'),
|
||||||
|
puid: '201115200268437643',
|
||||||
|
idx: 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(res, '停止位置---')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.control-deck {
|
.control-deck {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,12 @@
|
||||||
<!-- 左侧盒子1 -->
|
<!-- 左侧盒子1 -->
|
||||||
<div class="left-one child-container">
|
<div class="left-one child-container">
|
||||||
<n-flex justify="space-between" v-if="isShowAllBtns">
|
<n-flex justify="space-between" v-if="isShowAllBtns">
|
||||||
|
<div class="btns" @click="onHandlePresetSetting" v-if="!fullScreenVisible">
|
||||||
|
预置位配置
|
||||||
|
</div>
|
||||||
|
<div class="btns" @click="onHandleInspectionTask" v-if="!fullScreenVisible">
|
||||||
|
巡视任务
|
||||||
|
</div>
|
||||||
<div class="btns" @click="onHandleOperationPanel" v-if="!fullScreenVisible">
|
<div class="btns" @click="onHandleOperationPanel" v-if="!fullScreenVisible">
|
||||||
操作面板
|
操作面板
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -21,15 +27,43 @@
|
||||||
</n-flex>
|
</n-flex>
|
||||||
|
|
||||||
<div class="video-container" :style="{ marginTop: isShowAllBtns ? '24px' : '0' }">
|
<div class="video-container" :style="{ marginTop: isShowAllBtns ? '24px' : '0' }">
|
||||||
<video controls style="width: 100%; height: 100%; border-radius: 12px" autoplay>
|
<FlvPlayer :cameraNode="cameraNode" :videoId="props.videoId" />
|
||||||
<source src="@/assets/video/测试.mp4" type="video/mp4" autoplay />
|
|
||||||
</video>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 预置位配置 -->
|
||||||
|
<n-modal v-model:show="presetSettingVisible">
|
||||||
|
<PresetSetting
|
||||||
|
v-if="showModal === 1"
|
||||||
|
@onHandleCloseModal="onHandleCloseModal"
|
||||||
|
:presetSettingVisible="presetSettingVisible"
|
||||||
|
/>
|
||||||
|
<InspectionTask
|
||||||
|
v-if="showModal === 2"
|
||||||
|
@onHandleCloseModal="onHandleCloseModal"
|
||||||
|
@onHandleAddInspectionTask="onHandleAddInspectionTask"
|
||||||
|
/>
|
||||||
|
</n-modal>
|
||||||
|
|
||||||
|
<!-- 新增巡视任务 -->
|
||||||
|
<n-modal v-model:show="addInspectionTaskVisible">
|
||||||
|
<AddOrEditForm
|
||||||
|
v-if="addInspectionTaskVisible"
|
||||||
|
@onHandleCloseModalInner="onHandleCloseModalInner"
|
||||||
|
/>
|
||||||
|
</n-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
import PresetSetting from './modal-content/preset-setting.vue'
|
||||||
|
import InspectionTask from './modal-content/inspection-task.vue'
|
||||||
|
import AddOrEditForm from './modal-content/add-or-edit-form.vue'
|
||||||
|
|
||||||
|
import FlvPlayer from '@/components/FlvPlayer/index.vue'
|
||||||
|
const presetSettingVisible = ref(false)
|
||||||
|
const addInspectionTaskVisible = ref(false)
|
||||||
|
const showModal = ref(1)
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
fullScreenVisible: {
|
fullScreenVisible: {
|
||||||
|
|
@ -40,8 +74,49 @@ const props = defineProps({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
cameraNode: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
videoId: {
|
||||||
|
type: String,
|
||||||
|
default: 'video-1',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
const emits = defineEmits(['onHandleOperationPanel', 'onHandleFullScreen'])
|
const emits = defineEmits([
|
||||||
|
'onHandleOperationPanel',
|
||||||
|
'onHandleFullScreen',
|
||||||
|
'onHandleFullScreenToggle',
|
||||||
|
'onHandleChangeView',
|
||||||
|
])
|
||||||
|
|
||||||
|
// 预置位配置
|
||||||
|
const onHandlePresetSetting = () => {
|
||||||
|
showModal.value = 1
|
||||||
|
presetSettingVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭预置位配置
|
||||||
|
const onHandleCloseModal = () => {
|
||||||
|
showModal.value = null
|
||||||
|
presetSettingVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 巡视任务
|
||||||
|
const onHandleInspectionTask = () => {
|
||||||
|
showModal.value = 2
|
||||||
|
presetSettingVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增巡视任务
|
||||||
|
const onHandleAddInspectionTask = () => {
|
||||||
|
addInspectionTaskVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭新增或修改巡视任务
|
||||||
|
const onHandleCloseModalInner = () => {
|
||||||
|
addInspectionTaskVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
// 打开操作面板
|
// 打开操作面板
|
||||||
const onHandleOperationPanel = () => {
|
const onHandleOperationPanel = () => {
|
||||||
|
|
@ -59,7 +134,9 @@ const onHandleBackFullScreen = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 视角切换
|
// 视角切换
|
||||||
const onHandleChangeView = () => {}
|
const onHandleChangeView = () => {
|
||||||
|
emits('onHandleChangeView')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
@ -69,12 +146,14 @@ const onHandleChangeView = () => {}
|
||||||
height: 100%; /* 确保容器有高度 */
|
height: 100%; /* 确保容器有高度 */
|
||||||
|
|
||||||
.btns {
|
.btns {
|
||||||
width: 160px;
|
// width: 90px;
|
||||||
height: 50px;
|
padding: 0 10px;
|
||||||
|
height: 36px;
|
||||||
background: url('@/assets/home-imgs/button-bg.png') no-repeat center center;
|
background: url('@/assets/home-imgs/button-bg.png') no-repeat center center;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
line-height: 50px;
|
line-height: 36px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,194 @@
|
||||||
|
<template>
|
||||||
|
<!-- 新增或编辑弹框 -->
|
||||||
|
<DialogModal
|
||||||
|
:width="`60%`"
|
||||||
|
:height="`100vh`"
|
||||||
|
:modalTitle="addOrEditTitle"
|
||||||
|
@onHandleCloseModal="onHandleCloseModalInner"
|
||||||
|
>
|
||||||
|
<n-form ref="addOrEditFormRef" size="small" label-placement="left" style="margin-top: 10px">
|
||||||
|
<n-grid x-gap="24" :cols="24">
|
||||||
|
<n-gi :span="6">
|
||||||
|
<n-form-item label="设备名称">
|
||||||
|
<n-input
|
||||||
|
v-model:value="deviceName"
|
||||||
|
placeholder="任务名称"
|
||||||
|
clearable
|
||||||
|
style="width: 240px"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
</n-gi>
|
||||||
|
<n-gi :span="6">
|
||||||
|
<n-form-item label="底盘名称">
|
||||||
|
<n-input
|
||||||
|
v-model:value="deviceName"
|
||||||
|
placeholder="任务名称"
|
||||||
|
clearable
|
||||||
|
style="width: 240px"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
</n-gi>
|
||||||
|
<n-gi :span="6">
|
||||||
|
<n-form-item label="任务地图">
|
||||||
|
<n-input
|
||||||
|
v-model:value="deviceName"
|
||||||
|
placeholder="任务名称"
|
||||||
|
clearable
|
||||||
|
style="width: 240px"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
</n-gi>
|
||||||
|
|
||||||
|
<n-gi :span="6">
|
||||||
|
<n-form-item label="巡检次数">
|
||||||
|
<n-input
|
||||||
|
v-model:value="deviceName"
|
||||||
|
placeholder="任务名称"
|
||||||
|
clearable
|
||||||
|
style="width: 240px"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
</n-gi>
|
||||||
|
</n-grid>
|
||||||
|
<n-grid x-gap="24" :cols="24">
|
||||||
|
<n-gi :span="6">
|
||||||
|
<n-form-item label="智能事件">
|
||||||
|
<n-input
|
||||||
|
v-model:value="deviceName"
|
||||||
|
placeholder="任务名称"
|
||||||
|
clearable
|
||||||
|
style="width: 240px"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
</n-gi>
|
||||||
|
<n-gi :span="6">
|
||||||
|
<n-form-item label="任务名称">
|
||||||
|
<n-input
|
||||||
|
v-model:value="deviceName"
|
||||||
|
placeholder="任务名称"
|
||||||
|
clearable
|
||||||
|
style="width: 240px"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
</n-gi>
|
||||||
|
<n-gi :span="6">
|
||||||
|
<n-form-item label="任务周期">
|
||||||
|
<n-input
|
||||||
|
v-model:value="deviceName"
|
||||||
|
placeholder="任务名称"
|
||||||
|
clearable
|
||||||
|
style="width: 240px"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
</n-gi>
|
||||||
|
<n-gi :span="6">
|
||||||
|
<n-form-item label="开始时间">
|
||||||
|
<n-button type="info" @click="onHandleOpenTimePicker">
|
||||||
|
<template #icon>
|
||||||
|
<NIcon>
|
||||||
|
<AddCircleSharp />
|
||||||
|
</NIcon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
</n-form-item>
|
||||||
|
</n-gi>
|
||||||
|
</n-grid>
|
||||||
|
<n-grid
|
||||||
|
x-gap="24"
|
||||||
|
:cols="24"
|
||||||
|
v-for="(item, index) in timeSelectList"
|
||||||
|
:key="item.week"
|
||||||
|
style="margin-bottom: 10px"
|
||||||
|
>
|
||||||
|
<n-gi :span="6">
|
||||||
|
<n-time-picker
|
||||||
|
clearable
|
||||||
|
@confirm="handleConfirm"
|
||||||
|
default-formatted-value="00:00:00"
|
||||||
|
/>
|
||||||
|
</n-gi>
|
||||||
|
<n-gi :span="6">
|
||||||
|
<n-select v-model:value="item.week" :options="options" />
|
||||||
|
</n-gi>
|
||||||
|
<n-gi :span="6" v-if="index > 0">
|
||||||
|
<n-button quaternary @click="onHandleDeleteTimeSelect(index)">
|
||||||
|
<template #icon>
|
||||||
|
<NIcon color="#F90202">
|
||||||
|
<TrashSharp />
|
||||||
|
</NIcon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
</n-gi>
|
||||||
|
</n-grid>
|
||||||
|
</n-form>
|
||||||
|
</DialogModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import DialogModal from '@/components/DialogModal/index.vue'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { NIcon, useMessage } from 'naive-ui'
|
||||||
|
import { AddCircleSharp, TrashSharp } from '@vicons/ionicons5'
|
||||||
|
const message = useMessage()
|
||||||
|
const addOrEditTitle = ref('新增巡视任务') // 新增或编辑弹框标题
|
||||||
|
const value = ref('1')
|
||||||
|
const deviceName = ref('')
|
||||||
|
const timeSelectList = ref([{ times: '00:00:00', week: '' }])
|
||||||
|
const options = ref([
|
||||||
|
{
|
||||||
|
label: '星期一',
|
||||||
|
value: '1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '星期二',
|
||||||
|
value: '2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '星期三',
|
||||||
|
value: '3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '星期四',
|
||||||
|
value: '4',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '星期五',
|
||||||
|
value: '5',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '星期六',
|
||||||
|
value: '6',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '星期日 ',
|
||||||
|
value: '7',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
const emits = defineEmits(['onHandleCloseModalInner'])
|
||||||
|
// 关闭弹框
|
||||||
|
const onHandleCloseModalInner = () => {
|
||||||
|
emits('onHandleCloseModalInner')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增时间选择器
|
||||||
|
const onHandleOpenTimePicker = () => {
|
||||||
|
console.log('新增时间选择器')
|
||||||
|
if (timeSelectList.value.length < 7) {
|
||||||
|
timeSelectList.value.push({ times: '00:00:00', week: '' })
|
||||||
|
} else {
|
||||||
|
// 先清除之前的消失提示防止重复提示
|
||||||
|
message.warning('最多添加7个开始时间', { duration: 1000 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除时间选择器
|
||||||
|
const onHandleDeleteTimeSelect = (index) => {
|
||||||
|
timeSelectList.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleConfirm = (value) => {
|
||||||
|
console.log(value)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
|
|
@ -0,0 +1,242 @@
|
||||||
|
<template>
|
||||||
|
<!-- 巡视任务 -->
|
||||||
|
<DialogModal
|
||||||
|
@onHandleCloseModal="onHandleCloseModal"
|
||||||
|
:modalTitle="modalTitle"
|
||||||
|
:height="`90vh`"
|
||||||
|
:width="`90%`"
|
||||||
|
>
|
||||||
|
<!-- 巡视任务-->
|
||||||
|
<div class="inspection-task-container" ref="inspectionTaskContainer">
|
||||||
|
<n-form
|
||||||
|
inline
|
||||||
|
ref="formRef"
|
||||||
|
size="small"
|
||||||
|
label-placement="left"
|
||||||
|
style="margin-top: 10px"
|
||||||
|
>
|
||||||
|
<n-form-item>
|
||||||
|
<n-input placeholder="任务名称" clearable style="width: 240px" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-button type="info"> 查询</n-button>
|
||||||
|
<n-button color="#6E90A9" style="margin-left: 8px" @click="onHandleAdd">
|
||||||
|
新增
|
||||||
|
</n-button>
|
||||||
|
</n-form>
|
||||||
|
|
||||||
|
<n-data-table :columns="columns" :data="data" />
|
||||||
|
|
||||||
|
<div style="margin-top: 10px; display: flex; justify-content: flex-end">
|
||||||
|
<n-pagination
|
||||||
|
:page-count="100"
|
||||||
|
show-size-picker
|
||||||
|
v-model:page="page"
|
||||||
|
v-model:page-size="pageSize"
|
||||||
|
:page-sizes="[10, 20, 30, 40]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DialogModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import DialogModal from '@/components/DialogModal/index.vue'
|
||||||
|
import { AddCircleSharp } from '@vicons/ionicons5'
|
||||||
|
import { NIcon } from 'naive-ui'
|
||||||
|
import { NButton, NSwitch } from 'naive-ui'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const emits = defineEmits(['onHandleCloseModal', 'onHandleAddInspectionTask'])
|
||||||
|
const modalTitle = ref('巡视任务') // 弹框标题
|
||||||
|
const addOrEditVisible = ref(false) // 新增或编辑弹框
|
||||||
|
const addOrEditTitle = ref('新增巡视任务') // 新增或编辑弹框标题
|
||||||
|
const page = ref(1)
|
||||||
|
const pageSize = ref(10)
|
||||||
|
|
||||||
|
const btnList = [
|
||||||
|
{
|
||||||
|
label: '编辑',
|
||||||
|
type: 'info',
|
||||||
|
btnType: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '立即执行',
|
||||||
|
type: 'info',
|
||||||
|
btnType: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '下发',
|
||||||
|
type: 'info',
|
||||||
|
btnType: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '删除',
|
||||||
|
type: 'info',
|
||||||
|
btnType: 4,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const columns = ref([
|
||||||
|
{
|
||||||
|
title: '任务ID',
|
||||||
|
key: 'age',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '任务名',
|
||||||
|
key: 'tags',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '设备名称',
|
||||||
|
key: 'age',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '地盘名称',
|
||||||
|
key: 'age',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '任务频次',
|
||||||
|
key: 'age',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '执行时间',
|
||||||
|
key: 'age',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '任务状态',
|
||||||
|
key: 'age',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: '启用',
|
||||||
|
key: 'age',
|
||||||
|
align: 'center',
|
||||||
|
render(row) {
|
||||||
|
return h(NSwitch, {
|
||||||
|
value: row.isEnable,
|
||||||
|
onChange: (value) => onHandleSwitch(row, value),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'age',
|
||||||
|
align: 'center',
|
||||||
|
width: 260,
|
||||||
|
render(row) {
|
||||||
|
const buttonS = btnList.map((btn) => {
|
||||||
|
return h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
size: 'small',
|
||||||
|
onClick: () => onHandleBtn(row, btn.btnType),
|
||||||
|
type: btn.type,
|
||||||
|
style: {
|
||||||
|
marginRight: '4px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => btn.label },
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return buttonS
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
const data = ref([
|
||||||
|
{
|
||||||
|
age: '2025-06-01 10:00:00',
|
||||||
|
tags: ['nice'],
|
||||||
|
isEnable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
age: '2025-06-01 10:00:00',
|
||||||
|
tags: ['nice'],
|
||||||
|
isEnable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
age: '2025-06-01 10:00:00',
|
||||||
|
tags: ['nice'],
|
||||||
|
isEnable: false,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
// 新增按钮
|
||||||
|
const onHandleAdd = () => {
|
||||||
|
console.log('新增')
|
||||||
|
// addOrEditVisible.value = true
|
||||||
|
// addOrEditTitle.value = '新增巡视任务'
|
||||||
|
emits('onHandleAddInspectionTask')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按钮操作组
|
||||||
|
const onHandleBtn = (row, type) => {
|
||||||
|
console.log(row, type)
|
||||||
|
// 1. 编辑 2. 立即执行 3. 下发 4. 删除
|
||||||
|
switch (type) {
|
||||||
|
case 1:
|
||||||
|
onHandleEditTable(row)
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
onHandleImmediateExecution(row)
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
onHandleSend(row)
|
||||||
|
break
|
||||||
|
case 4:
|
||||||
|
onHandleDelete(row)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑
|
||||||
|
const onHandleEditTable = (row) => {
|
||||||
|
console.log(row)
|
||||||
|
addOrEditVisible.value = true
|
||||||
|
addOrEditTitle.value = '编辑巡视任务'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 立即执行
|
||||||
|
const onHandleImmediateExecution = (row) => {
|
||||||
|
console.log(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下发
|
||||||
|
const onHandleSend = (row) => {
|
||||||
|
console.log(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
const onHandleDelete = (row) => {
|
||||||
|
console.log(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭弹框外层
|
||||||
|
const onHandleCloseModal = () => {
|
||||||
|
emits('onHandleCloseModal')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭弹框内层
|
||||||
|
const onHandleCloseModalInner = () => {
|
||||||
|
addOrEditVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启用开关
|
||||||
|
const onHandleSwitch = (row, value) => {
|
||||||
|
console.log(row, value)
|
||||||
|
|
||||||
|
row.isEnable = value
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.plane-map-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,258 @@
|
||||||
|
<template>
|
||||||
|
<!-- 预置位配置 -->
|
||||||
|
<DialogModal @onHandleCloseModal="onHandleCloseModal" :modalTitle="modalTitle" :height="`90vh`">
|
||||||
|
<!-- 平面图操作区域 -->
|
||||||
|
<div class="plane-map-container" ref="planeMapContainer">
|
||||||
|
<svg
|
||||||
|
ref="svgMap"
|
||||||
|
class="floor-plan"
|
||||||
|
:viewBox="`${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`"
|
||||||
|
preserveAspectRatio="xMidYMid meet"
|
||||||
|
@click="handleMapClick"
|
||||||
|
>
|
||||||
|
<!-- 平面图背景 -->
|
||||||
|
<image
|
||||||
|
v-if="imgLoaded"
|
||||||
|
:href="demoImg"
|
||||||
|
:width="viewBox.width"
|
||||||
|
:height="viewBox.height"
|
||||||
|
preserveAspectRatio="xMidYMid slice"
|
||||||
|
style="object-fit: cover"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 动态渲染标记点 -->
|
||||||
|
<circle
|
||||||
|
v-for="(point, index) in points"
|
||||||
|
:key="index"
|
||||||
|
:cx="point.x"
|
||||||
|
:cy="point.y"
|
||||||
|
r="8"
|
||||||
|
fill="red"
|
||||||
|
@click.stop="selectPoint(index)"
|
||||||
|
@mousedown="startDrag(index, $event)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 动态渲染连线 -->
|
||||||
|
<line
|
||||||
|
v-for="(line, index) in lines"
|
||||||
|
:key="'line-' + index"
|
||||||
|
:x1="line.start.x"
|
||||||
|
:y1="line.start.y"
|
||||||
|
:x2="line.end.x"
|
||||||
|
:y2="line.end.y"
|
||||||
|
stroke="blue"
|
||||||
|
stroke-width="2"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<div class="map-control-container">
|
||||||
|
<n-button type="info" @click="handleZoomIn">放大</n-button>
|
||||||
|
<n-button type="info" @click="handleZoomOut">缩小</n-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DialogModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import DialogModal from '@/components/DialogModal/index.vue'
|
||||||
|
import { refThrottled, useMouseInElement } from '@vueuse/core'
|
||||||
|
import { ref, onMounted, nextTick, watch } from 'vue'
|
||||||
|
// import { CashOutline as CashIcon } from '@vicons/ionicons5'
|
||||||
|
import { NIcon } from 'naive-ui'
|
||||||
|
import demoImg from '@/assets/demo.png'
|
||||||
|
|
||||||
|
const emits = defineEmits(['onHandleCloseModal'])
|
||||||
|
const modalTitle = ref('预置位配置')
|
||||||
|
const svgMap = refThrottled(null)
|
||||||
|
const points = ref([])
|
||||||
|
const lines = ref([])
|
||||||
|
const imgLoaded = ref(false)
|
||||||
|
const imgNaturalSize = ref({ width: 0, height: 0 })
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
presetSettingVisible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// 新增:响应式 viewBox 控制
|
||||||
|
const viewBox = ref({
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 新增:容器尺寸跟踪
|
||||||
|
const containerSize = ref({ width: 0, height: 0 })
|
||||||
|
const planeMapContainer = ref(null)
|
||||||
|
|
||||||
|
// 关闭模态框
|
||||||
|
const onHandleCloseModal = () => {
|
||||||
|
emits('onHandleCloseModal')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖拽标记点
|
||||||
|
const startDrag = (index, e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
const { x: startX, y: startY } = points.value[index]
|
||||||
|
const onMove = (moveEvent) => {
|
||||||
|
const rect = svgMap.value.getBoundingClientRect()
|
||||||
|
points.value[index] = {
|
||||||
|
x: moveEvent.clientX - rect.left,
|
||||||
|
y: moveEvent.clientY - rect.top,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onUp = () => {
|
||||||
|
window.removeEventListener('mousemove', onMove)
|
||||||
|
window.removeEventListener('mouseup', onUp)
|
||||||
|
}
|
||||||
|
window.addEventListener('mousemove', onMove)
|
||||||
|
window.addEventListener('mouseup', onUp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 连线示例(假设连接第一个和第二个点)
|
||||||
|
const connectPoints = () => {
|
||||||
|
if (points.value.length >= 2) {
|
||||||
|
lines.value.push({
|
||||||
|
start: points.value[0],
|
||||||
|
end: points.value[1],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 监听容器尺寸变化
|
||||||
|
nextTick(() => {
|
||||||
|
const resizeObserver = new ResizeObserver((entries) => {
|
||||||
|
if (entries[0]) {
|
||||||
|
containerSize.value = {
|
||||||
|
width: entries[0].contentRect.width,
|
||||||
|
height: entries[0].contentRect.height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (planeMapContainer.value) {
|
||||||
|
resizeObserver.observe(planeMapContainer.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 修改点击事件处理(考虑缩放后的坐标)
|
||||||
|
const handleMapClick = (e) => {
|
||||||
|
if (!svgMap.value) return
|
||||||
|
|
||||||
|
const pt = svgMap.value.createSVGPoint()
|
||||||
|
pt.x = e.clientX
|
||||||
|
pt.y = e.clientY
|
||||||
|
const svgPt = pt.matrixTransform(svgMap.value.getScreenCTM().inverse())
|
||||||
|
|
||||||
|
points.value.push({
|
||||||
|
x: svgPt.x,
|
||||||
|
y: svgPt.y,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.presetSettingVisible,
|
||||||
|
(newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
nextTick(() => {
|
||||||
|
loadImage()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
const initMapSize = () => {
|
||||||
|
if (!planeMapContainer.value) return
|
||||||
|
|
||||||
|
containerSize.value = {
|
||||||
|
width: planeMapContainer.value.clientWidth,
|
||||||
|
height: planeMapContainer.value.clientHeight,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化 viewBox(根据您的业务逻辑调整)
|
||||||
|
viewBox.value.width = containerSize.value.width
|
||||||
|
viewBox.value.height = containerSize.value.height
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载图片并获取真实尺寸
|
||||||
|
const loadImage = () => {
|
||||||
|
const img = new Image()
|
||||||
|
img.onload = () => {
|
||||||
|
imgNaturalSize.value = {
|
||||||
|
width: img.naturalWidth,
|
||||||
|
height: img.naturalHeight,
|
||||||
|
}
|
||||||
|
imgLoaded.value = true
|
||||||
|
adjustViewBox()
|
||||||
|
}
|
||||||
|
img.onerror = () => {
|
||||||
|
console.error('图片加载失败,请检查路径:', demoImg)
|
||||||
|
}
|
||||||
|
img.src = demoImg // 使用导入的图片路径
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调整viewBox
|
||||||
|
const adjustViewBox = () => {
|
||||||
|
if (!planeMapContainer.value || !imgNaturalSize.value.width) return
|
||||||
|
|
||||||
|
const container = planeMapContainer.value
|
||||||
|
const containerRatio = container.clientWidth / container.clientHeight
|
||||||
|
const imgRatio = imgNaturalSize.value.width / imgNaturalSize.value.height
|
||||||
|
|
||||||
|
if (containerRatio > imgRatio) {
|
||||||
|
// 容器更宽,按高度适配
|
||||||
|
viewBox.value = {
|
||||||
|
x: (imgNaturalSize.value.width - imgNaturalSize.value.height * containerRatio) / 2,
|
||||||
|
y: 0,
|
||||||
|
width: imgNaturalSize.value.height * containerRatio,
|
||||||
|
height: imgNaturalSize.value.height,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 容器更高,按宽度适配
|
||||||
|
viewBox.value = {
|
||||||
|
x: 0,
|
||||||
|
y: (imgNaturalSize.value.height - imgNaturalSize.value.width / containerRatio) / 2,
|
||||||
|
width: imgNaturalSize.value.width,
|
||||||
|
height: imgNaturalSize.value.width / containerRatio,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleZoomIn = () => {
|
||||||
|
console.log('放大')
|
||||||
|
viewBox.value.width = viewBox.value.width * 1.1
|
||||||
|
viewBox.value.height = viewBox.value.height * 1.1
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleZoomOut = () => {
|
||||||
|
console.log('缩小')
|
||||||
|
viewBox.value.width = viewBox.value.width * 0.9
|
||||||
|
viewBox.value.height = viewBox.value.height * 0.9
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.plane-map-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.map-control-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
z-index: 1000;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,258 @@
|
||||||
|
<template>
|
||||||
|
<!-- 预置位配置 -->
|
||||||
|
<DialogModal @onHandleCloseModal="onHandleCloseModal" :modalTitle="modalTitle" :height="`90vh`">
|
||||||
|
<!-- 平面图操作区域 -->
|
||||||
|
<div class="plane-map-container" ref="planeMapContainer">
|
||||||
|
<svg
|
||||||
|
ref="svgMap"
|
||||||
|
class="floor-plan"
|
||||||
|
:viewBox="`${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`"
|
||||||
|
preserveAspectRatio="xMidYMid meet"
|
||||||
|
@click="handleMapClick"
|
||||||
|
>
|
||||||
|
<!-- 平面图背景 -->
|
||||||
|
<image
|
||||||
|
v-if="imgLoaded"
|
||||||
|
:href="demoImg"
|
||||||
|
:width="viewBox.width"
|
||||||
|
:height="viewBox.height"
|
||||||
|
preserveAspectRatio="xMidYMid slice"
|
||||||
|
style="object-fit: cover"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 动态渲染标记点 -->
|
||||||
|
<circle
|
||||||
|
v-for="(point, index) in points"
|
||||||
|
:key="index"
|
||||||
|
:cx="point.x"
|
||||||
|
:cy="point.y"
|
||||||
|
r="8"
|
||||||
|
fill="red"
|
||||||
|
@click.stop="selectPoint(index)"
|
||||||
|
@mousedown="startDrag(index, $event)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 动态渲染连线 -->
|
||||||
|
<line
|
||||||
|
v-for="(line, index) in lines"
|
||||||
|
:key="'line-' + index"
|
||||||
|
:x1="line.start.x"
|
||||||
|
:y1="line.start.y"
|
||||||
|
:x2="line.end.x"
|
||||||
|
:y2="line.end.y"
|
||||||
|
stroke="blue"
|
||||||
|
stroke-width="2"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<div class="map-control-container">
|
||||||
|
<n-button type="info" @click="handleZoomIn">放大</n-button>
|
||||||
|
<n-button type="info" @click="handleZoomOut">缩小</n-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DialogModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import DialogModal from '@/components/DialogModal/index.vue'
|
||||||
|
import { refThrottled, useMouseInElement } from '@vueuse/core'
|
||||||
|
import { ref, onMounted, nextTick, watch } from 'vue'
|
||||||
|
// import { CashOutline as CashIcon } from '@vicons/ionicons5'
|
||||||
|
import { NIcon } from 'naive-ui'
|
||||||
|
import demoImg from '@/assets/demo.png'
|
||||||
|
|
||||||
|
const emits = defineEmits(['onHandleCloseModal'])
|
||||||
|
const modalTitle = ref('预置位配置')
|
||||||
|
const svgMap = refThrottled(null)
|
||||||
|
const points = ref([])
|
||||||
|
const lines = ref([])
|
||||||
|
const imgLoaded = ref(false)
|
||||||
|
const imgNaturalSize = ref({ width: 0, height: 0 })
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
presetSettingVisible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// 新增:响应式 viewBox 控制
|
||||||
|
const viewBox = ref({
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 新增:容器尺寸跟踪
|
||||||
|
const containerSize = ref({ width: 0, height: 0 })
|
||||||
|
const planeMapContainer = ref(null)
|
||||||
|
|
||||||
|
// 关闭模态框
|
||||||
|
const onHandleCloseModal = () => {
|
||||||
|
emits('onHandleCloseModal')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖拽标记点
|
||||||
|
const startDrag = (index, e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
const { x: startX, y: startY } = points.value[index]
|
||||||
|
const onMove = (moveEvent) => {
|
||||||
|
const rect = svgMap.value.getBoundingClientRect()
|
||||||
|
points.value[index] = {
|
||||||
|
x: moveEvent.clientX - rect.left,
|
||||||
|
y: moveEvent.clientY - rect.top,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onUp = () => {
|
||||||
|
window.removeEventListener('mousemove', onMove)
|
||||||
|
window.removeEventListener('mouseup', onUp)
|
||||||
|
}
|
||||||
|
window.addEventListener('mousemove', onMove)
|
||||||
|
window.addEventListener('mouseup', onUp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 连线示例(假设连接第一个和第二个点)
|
||||||
|
const connectPoints = () => {
|
||||||
|
if (points.value.length >= 2) {
|
||||||
|
lines.value.push({
|
||||||
|
start: points.value[0],
|
||||||
|
end: points.value[1],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 监听容器尺寸变化
|
||||||
|
nextTick(() => {
|
||||||
|
const resizeObserver = new ResizeObserver((entries) => {
|
||||||
|
if (entries[0]) {
|
||||||
|
containerSize.value = {
|
||||||
|
width: entries[0].contentRect.width,
|
||||||
|
height: entries[0].contentRect.height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (planeMapContainer.value) {
|
||||||
|
resizeObserver.observe(planeMapContainer.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 修改点击事件处理(考虑缩放后的坐标)
|
||||||
|
const handleMapClick = (e) => {
|
||||||
|
if (!svgMap.value) return
|
||||||
|
|
||||||
|
const pt = svgMap.value.createSVGPoint()
|
||||||
|
pt.x = e.clientX
|
||||||
|
pt.y = e.clientY
|
||||||
|
const svgPt = pt.matrixTransform(svgMap.value.getScreenCTM().inverse())
|
||||||
|
|
||||||
|
points.value.push({
|
||||||
|
x: svgPt.x,
|
||||||
|
y: svgPt.y,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.presetSettingVisible,
|
||||||
|
(newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
nextTick(() => {
|
||||||
|
loadImage()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
const initMapSize = () => {
|
||||||
|
if (!planeMapContainer.value) return
|
||||||
|
|
||||||
|
containerSize.value = {
|
||||||
|
width: planeMapContainer.value.clientWidth,
|
||||||
|
height: planeMapContainer.value.clientHeight,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化 viewBox(根据您的业务逻辑调整)
|
||||||
|
viewBox.value.width = containerSize.value.width
|
||||||
|
viewBox.value.height = containerSize.value.height
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载图片并获取真实尺寸
|
||||||
|
const loadImage = () => {
|
||||||
|
const img = new Image()
|
||||||
|
img.onload = () => {
|
||||||
|
imgNaturalSize.value = {
|
||||||
|
width: img.naturalWidth,
|
||||||
|
height: img.naturalHeight,
|
||||||
|
}
|
||||||
|
imgLoaded.value = true
|
||||||
|
adjustViewBox()
|
||||||
|
}
|
||||||
|
img.onerror = () => {
|
||||||
|
console.error('图片加载失败,请检查路径:', demoImg)
|
||||||
|
}
|
||||||
|
img.src = demoImg // 使用导入的图片路径
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调整viewBox
|
||||||
|
const adjustViewBox = () => {
|
||||||
|
if (!planeMapContainer.value || !imgNaturalSize.value.width) return
|
||||||
|
|
||||||
|
const container = planeMapContainer.value
|
||||||
|
const containerRatio = container.clientWidth / container.clientHeight
|
||||||
|
const imgRatio = imgNaturalSize.value.width / imgNaturalSize.value.height
|
||||||
|
|
||||||
|
if (containerRatio > imgRatio) {
|
||||||
|
// 容器更宽,按高度适配
|
||||||
|
viewBox.value = {
|
||||||
|
x: (imgNaturalSize.value.width - imgNaturalSize.value.height * containerRatio) / 2,
|
||||||
|
y: 0,
|
||||||
|
width: imgNaturalSize.value.height * containerRatio,
|
||||||
|
height: imgNaturalSize.value.height,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 容器更高,按宽度适配
|
||||||
|
viewBox.value = {
|
||||||
|
x: 0,
|
||||||
|
y: (imgNaturalSize.value.height - imgNaturalSize.value.width / containerRatio) / 2,
|
||||||
|
width: imgNaturalSize.value.width,
|
||||||
|
height: imgNaturalSize.value.width / containerRatio,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleZoomIn = () => {
|
||||||
|
console.log('放大')
|
||||||
|
viewBox.value.width = viewBox.value.width * 1.1
|
||||||
|
viewBox.value.height = viewBox.value.height * 1.1
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleZoomOut = () => {
|
||||||
|
console.log('缩小')
|
||||||
|
viewBox.value.width = viewBox.value.width * 0.9
|
||||||
|
viewBox.value.height = viewBox.value.height * 0.9
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.plane-map-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.map-control-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
z-index: 1000;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
>
|
>
|
||||||
<template #error>
|
<template #error>
|
||||||
<n-icon :size="100" color="lightGrey">
|
<n-icon :size="100" color="lightGrey">
|
||||||
<ImageOutlineIcon />
|
<!-- <ImageOutlineIcon /> -->
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</template>
|
</template>
|
||||||
</n-image>
|
</n-image>
|
||||||
|
|
|
||||||
|
|
@ -4,54 +4,56 @@
|
||||||
<!-- 机器人首页 -->
|
<!-- 机器人首页 -->
|
||||||
<!-- 使用grid布局 -->
|
<!-- 使用grid布局 -->
|
||||||
<!-- 非全屏模式 -->
|
<!-- 非全屏模式 -->
|
||||||
<div class="robot-container" v-if="!fullScreenVisible">
|
<div class="robot-container">
|
||||||
<!-- 左一 -->
|
<!-- 左一 -->
|
||||||
<div class="robot-1">
|
<div
|
||||||
|
:style="{
|
||||||
|
gridColumn: fullScreenVisible ? '1 / 9' : '1 / 4',
|
||||||
|
gridRow: fullScreenVisible ? '1 / 13' : '1 / 7',
|
||||||
|
}"
|
||||||
|
>
|
||||||
<LeftOne
|
<LeftOne
|
||||||
|
:videoId="'video-1'"
|
||||||
|
:cameraNode="cameraNode_1"
|
||||||
|
:fullScreenVisible="fullScreenVisible"
|
||||||
|
@onHandleChangeView="onHandleChangeView"
|
||||||
@onHandleOperationPanel="onHandleOperationPanel"
|
@onHandleOperationPanel="onHandleOperationPanel"
|
||||||
@onHandleFullScreenToggle="onHandleFullScreenToggle"
|
@onHandleFullScreenToggle="onHandleFullScreenToggleL"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- 左二 -->
|
<!-- 左二 -->
|
||||||
<div class="robot-2">
|
<div class="robot-2" v-if="!fullScreenVisible">
|
||||||
<LeftTwo />
|
<LeftTwo />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 中一 -->
|
<!-- 中一 -->
|
||||||
<div class="robot-3">
|
<div
|
||||||
<CenterOne />
|
:style="{
|
||||||
|
gridColumn: fullScreenVisible ? '9 / 13' : '4 / 10',
|
||||||
|
gridRow: fullScreenVisible ? '1 / 6' : '1 / 8',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<CenterOne
|
||||||
|
:videoId="'video-2'"
|
||||||
|
:cameraNode_2="cameraNode_2"
|
||||||
|
:fullScreenVisible="fullScreenVisible"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- 中二 -->
|
<!-- 中二 -->
|
||||||
<div class="robot-4">
|
<div class="robot-4" v-if="!fullScreenVisible">
|
||||||
<CenterTwo />
|
<CenterTwo />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 右一 -->
|
<!-- 右一 -->
|
||||||
<div class="robot-5">
|
<div class="robot-5" v-if="!fullScreenVisible">
|
||||||
<RightOne />
|
<RightOne />
|
||||||
</div>
|
</div>
|
||||||
<!-- 右二 -->
|
<!-- 右二 -->
|
||||||
<div class="robot-6">
|
<div class="robot-6" v-if="!fullScreenVisible">
|
||||||
<RightTwo />
|
<RightTwo />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 全屏模式 -->
|
<div class="robot-7" v-if="fullScreenVisible">
|
||||||
<div class="full-screen-container" v-if="fullScreenVisible">
|
|
||||||
<div class="full-screen-left1">
|
|
||||||
<LeftOne
|
|
||||||
:fullScreenVisible="fullScreenVisible"
|
|
||||||
@onHandleFullScreenToggle="onHandleFullScreenToggle"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="full-screen-right1">
|
|
||||||
<LeftOne
|
|
||||||
:isShowAllBtns="false"
|
|
||||||
:fullScreenVisible="fullScreenVisible"
|
|
||||||
@onHandleFullScreenToggle="onHandleFullScreenToggle"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="full-screen-right2">
|
|
||||||
<ControlDeck />
|
<ControlDeck />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -69,6 +71,7 @@
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||||
|
import { initLoginApi, getDeviceUrlApi } from '@/utils/initLogin'
|
||||||
import { useScale } from '@/hooks/useScale' // 引入自定义 Hook
|
import { useScale } from '@/hooks/useScale' // 引入自定义 Hook
|
||||||
import LeftOne from './components/left-one.vue'
|
import LeftOne from './components/left-one.vue'
|
||||||
import LeftTwo from './components/left-two.vue'
|
import LeftTwo from './components/left-two.vue'
|
||||||
|
|
@ -84,6 +87,25 @@ const fullScreenVisible = ref(false) // 全屏状态
|
||||||
// 使用 useScale Hook(直接调用,无需在 setup() 里)
|
// 使用 useScale Hook(直接调用,无需在 setup() 里)
|
||||||
const { baseWidth, baseHeight, scale } = useScale(appRef)
|
const { baseWidth, baseHeight, scale } = useScale(appRef)
|
||||||
|
|
||||||
|
const cameraNode_1 = ref({
|
||||||
|
puid: '201115200268437643',
|
||||||
|
idx: 0,
|
||||||
|
stream: 0,
|
||||||
|
name: '',
|
||||||
|
operateType: 1,
|
||||||
|
steamCode: '',
|
||||||
|
steamURL: '',
|
||||||
|
})
|
||||||
|
const cameraNode_2 = ref({
|
||||||
|
puid: '201115200268437643',
|
||||||
|
idx: 1,
|
||||||
|
stream: 0,
|
||||||
|
name: '',
|
||||||
|
operateType: 1,
|
||||||
|
steamCode: '',
|
||||||
|
steamURL: '',
|
||||||
|
})
|
||||||
|
|
||||||
const operationPanelVisible = ref(false) // 操作面板是否显示
|
const operationPanelVisible = ref(false) // 操作面板是否显示
|
||||||
|
|
||||||
// 打开操作面板
|
// 打开操作面板
|
||||||
|
|
@ -91,9 +113,63 @@ const onHandleOperationPanel = (visible) => {
|
||||||
operationPanelVisible.value = visible
|
operationPanelVisible.value = visible
|
||||||
}
|
}
|
||||||
// 全屏控制
|
// 全屏控制
|
||||||
const onHandleFullScreenToggle = (visible) => {
|
const onHandleFullScreenToggleL = (visible) => {
|
||||||
fullScreenVisible.value = visible
|
fullScreenVisible.value = visible
|
||||||
}
|
}
|
||||||
|
// 视角切换
|
||||||
|
const onHandleChangeView = () => {
|
||||||
|
const tempIdx = cameraNode_1.value.idx
|
||||||
|
cameraNode_1.value.idx = cameraNode_2.value.idx
|
||||||
|
cameraNode_2.value.idx = tempIdx
|
||||||
|
const temp = cameraNode_1.value.steamURL
|
||||||
|
cameraNode_1.value.steamURL = cameraNode_2.value.steamURL
|
||||||
|
cameraNode_2.value.steamURL = temp
|
||||||
|
}
|
||||||
|
|
||||||
|
const loginParams = ref({
|
||||||
|
// - 登录平台IP
|
||||||
|
address: '60.168.132.97',
|
||||||
|
port: '49988',
|
||||||
|
// - 登录平台用户名
|
||||||
|
user: 'admin',
|
||||||
|
// - 登录平台密码
|
||||||
|
password: 'Aa123456',
|
||||||
|
// - 登录平台企业ID
|
||||||
|
epid: 'YDJFXK',
|
||||||
|
// - 登录平台是否通过网闸模式
|
||||||
|
bfix: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 初始化登录
|
||||||
|
const initLoginData = async () => {
|
||||||
|
initLoginApi(loginParams.value).then((res) => {
|
||||||
|
localStorage.setItem('token', res?.data?.token)
|
||||||
|
getDeviceData()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取视频地址
|
||||||
|
const getDeviceData = async () => {
|
||||||
|
const { data: res } = await getDeviceUrlApi({
|
||||||
|
token: localStorage.getItem('token'),
|
||||||
|
puid: '201115200268437643',
|
||||||
|
idx: 0,
|
||||||
|
stream: 0,
|
||||||
|
type: 'HTTP-FLV',
|
||||||
|
})
|
||||||
|
const { data: res2 } = await getDeviceUrlApi({
|
||||||
|
token: localStorage.getItem('token'),
|
||||||
|
puid: '201115200268437643',
|
||||||
|
idx: 1,
|
||||||
|
stream: 0,
|
||||||
|
type: 'HTTP-FLV',
|
||||||
|
})
|
||||||
|
|
||||||
|
cameraNode_1.value.steamURL = res?.streamUrl
|
||||||
|
cameraNode_2.value.steamURL = res2?.streamUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
initLoginData()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
@ -138,6 +214,11 @@ const onHandleFullScreenToggle = (visible) => {
|
||||||
grid-row: 8 / 13;
|
grid-row: 8 / 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.robot-7 {
|
||||||
|
grid-column: 9 / 13;
|
||||||
|
grid-row: 6 / 13;
|
||||||
|
}
|
||||||
|
|
||||||
.full-screen-left1 {
|
.full-screen-left1 {
|
||||||
grid-column: 1 / 9;
|
grid-column: 1 / 9;
|
||||||
grid-row: 1 / 13;
|
grid-row: 1 / 13;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue