From 2079a63bdca1842114f1c3a34f6cb9ef957ea417 Mon Sep 17 00:00:00 2001 From: zhoulexin Date: Tue, 26 May 2026 16:49:57 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E4=BC=98=E5=8C=96=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 1 + public/favicon.png | Bin 0 -> 3938 bytes public/favicon.svg | 1 + src/components/WebRtcPlayer.vue | 37 +++++++++++++ src/layout/index.vue | 4 +- src/stores/user.js | 14 ++++- src/views/detail/index.vue | 7 +-- .../components/AiChatPanel.vue | 5 +- src/views/login/index.vue | 51 ++++++++++-------- 9 files changed, 88 insertions(+), 32 deletions(-) create mode 100644 public/favicon.png create mode 100644 public/favicon.svg diff --git a/index.html b/index.html index aa34e5c..c09c3ba 100644 --- a/index.html +++ b/index.html @@ -2,6 +2,7 @@ + 智能视觉管理平台 diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..00d66353e7da8e13aa886321e0415b1785a156f9 GIT binary patch literal 3938 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 literal 0 HcmV?d00001 diff --git a/public/favicon.svg b/public/favicon.svg new file mode 100644 index 0000000..58f5a93 --- /dev/null +++ b/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/WebRtcPlayer.vue b/src/components/WebRtcPlayer.vue index 3ca190a..44f7ef8 100644 --- a/src/components/WebRtcPlayer.vue +++ b/src/components/WebRtcPlayer.vue @@ -8,6 +8,12 @@ class="video-player" > + +
+ + 连接中... +
+
录制中 {{ recordTime }}s @@ -36,6 +42,7 @@ const emit = defineEmits(['record-status-change','record-complete']); const videoRef = ref(null); const error = ref(''); +const loading = ref(false); let pc = null; // --- 录屏相关状态 --- @@ -59,6 +66,8 @@ const disconnect = () => { // 2. 连接 WebRTC const connect = async () => { + loading.value = true; + error.value = ''; try { pc = new RTCPeerConnection(); pc.ontrack = (event) => { @@ -85,6 +94,11 @@ const connect = async () => { } catch (e) { error.value = '连接失败,请检查视频地址'; console.error(e); + } finally { + let timeout = setTimeout(() => { + loading.value = false; + clearTimeout(timeout); + }, 1500); } }; @@ -215,6 +229,29 @@ defineExpose({ .video-player { width: 100%; height: 100%; object-fit: contain; } .error-overlay { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: white; } +.loading-overlay { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: rgba(255, 255, 255, 0.85); + font-size: 14px; + display: flex; + align-items: center; + gap: 8px; +} +.spinner { + width: 20px; + height: 20px; + border: 2px solid rgba(255, 255, 255, 0.3); + border-top-color: #409eff; + border-radius: 50%; + animation: spin 0.8s linear infinite; +} +@keyframes spin { + to { transform: rotate(360deg); } +} + .recording-indicator { position: absolute; top: 10px; diff --git a/src/layout/index.vue b/src/layout/index.vue index c3b4a89..c4c130d 100644 --- a/src/layout/index.vue +++ b/src/layout/index.vue @@ -2,10 +2,8 @@ { const token = ref(localStorage.getItem('token') || '') @@ -36,15 +36,25 @@ export const useUserStore = defineStore('user', () => { const logout = async () => { if (isLoggingOut.value) return isLoggingOut.value = true - + const params = { + "session": 2878481200, + "id": 2, + "call": { + "service": "rpc", + "method": "logout" + } + } try { await logoutApi() + // 退出后台吊舱登录 + await newPodApi(params) } catch (e) { // 忽略logout接口错误 } finally { token.value = '' userInfo.value = null localStorage.removeItem('token') + localStorage.removeItem('newPodSession') isLoggingOut.value = false } } diff --git a/src/views/detail/index.vue b/src/views/detail/index.vue index 8734ce3..6d86dd4 100644 --- a/src/views/detail/index.vue +++ b/src/views/detail/index.vue @@ -192,8 +192,9 @@ const podInfo = async () => { } } // 控制设备 +const newPodSession = localStorage.getItem('newPodSession') const params = { - "session": 671150784, + "session": Number(newPodSession), "id": 2, "call": { "service": "ptz", @@ -278,7 +279,7 @@ const aperture = async(val) => { const wiperCtrl = ref(false) const wiper = () => { const reqParams = { - "session": 671150784, + "session": Number(newPodSession), "id": 2, "call": { "service": "ptz", @@ -295,7 +296,7 @@ const initialization = ref(false) const lensInitialization = async() => { initialization.value = true const reqParams = { - "session": 671150784, + "session": Number(newPodSession), "id": 2, "call": { "service": "ptz", diff --git a/src/views/face-recognition/components/AiChatPanel.vue b/src/views/face-recognition/components/AiChatPanel.vue index 22ef717..36d7305 100644 --- a/src/views/face-recognition/components/AiChatPanel.vue +++ b/src/views/face-recognition/components/AiChatPanel.vue @@ -97,12 +97,13 @@ @keydown.enter.exact.prevent="handleSend" />
- +
+ 取消 清空 确定
diff --git a/src/views/login/index.vue b/src/views/login/index.vue index 5756147..04c908f 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -176,32 +176,20 @@ const loginRules = { ] } const generateRandomString = (length = 6) => { - const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - let result = '' + // 定义字符集:数字 + 大写字母 (去除了易混淆的 I, O 等,可根据需求调整) + const chars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'; + + let result = ''; + const charsLength = chars.length; + for (let i = 0; i < length; i++) { - result += chars.charAt(Math.floor(Math.random() * chars.length)) + const randomIndex = Math.floor(Math.random() * charsLength); + result += chars[randomIndex]; } - return result + + return result; } const handleLogin = async () => { - // const random = generateRandomString() - // const podLogin = await newPodApi({ - // "session": 0, - // "id": 2, - // "call": { - // "service": "rpc", - // "method": "login" - // }, - // "params": { - // "userName": "admin", - // "password": sha256(md5('abcd1234')+random), - // "random": random, - // "ip": "127.0.0.1", - // "port": 80, - // "encryptType": 1 - // } - // }) - // return; if (!loginFormRef.value) return await loginFormRef.value.validate(async (valid) => { @@ -210,6 +198,25 @@ const handleLogin = async () => { try { const res = await userStore.login(loginForm) if (res.success) { + // 登录后台吊舱管理 + const random = generateRandomString() + const podLogin = await newPodApi({ + "session": 0, + "id": 2, + "call": { + "service": "rpc", + "method": "login" + }, + "params": { + "userName": "admin", + "password": sha256(sha256('abcd1234') + random), + "random": random, + "ip": "127.0.0.1", + "port": 80, + "encryptType": 1 + } + }) + localStorage.setItem('newPodSession', podLogin.params.session) // 处理记住密码 if (rememberMe.value) { saveCredentials()