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 0000000..00d6635 Binary files /dev/null and b/public/favicon.png differ 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()