From f6fda99aa2732c1883a388db556ef0820738e8ca Mon Sep 17 00:00:00 2001 From: ila <2+ila@noreply.git.ilapage.cn> Date: Thu, 13 Aug 2026 12:23:58 +0800 Subject: [PATCH] feat: complete split camera credentials (#50) --- Sense/ui/src/views/sense/device/Devices.vue | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Sense/ui/src/views/sense/device/Devices.vue b/Sense/ui/src/views/sense/device/Devices.vue index 9c27d89..43b4090 100644 --- a/Sense/ui/src/views/sense/device/Devices.vue +++ b/Sense/ui/src/views/sense/device/Devices.vue @@ -14,7 +14,7 @@ - + @@ -33,8 +33,13 @@ - - + + + RTSP 与 ONVIF 使用相同账号 + @@ -54,18 +59,18 @@ const editing = ref(null), credentialTarget = ref(null), deviceFormRef = ref(), const query = reactive({ keyword: '', page: 1, page_size: 20 }) const page = reactive({ items: [], total: 0 }) const deviceForm = reactive({ name: '', location: '', modality: 'video', capabilities: ['video'] }) -const credentialForm = reactive({ username: '', password: '' }) +const credentialForm = reactive({ onvif_username: '', onvif_password: '', rtsp_same_as_onvif: true, rtsp_username: '', rtsp_password: '' }) const deviceRules = { name: [{ required: true, message: '请输入设备名称', trigger: 'blur' }], modality: [{ required: true, message: '请选择类型', trigger: 'change' }] } -const credentialRules = { username: [{ required: true, message: '请输入用户名', trigger: 'blur' }], password: [{ required: true, message: '请输入密码', trigger: 'blur' }] } +const credentialRules = { onvif_username: [{ required: true, message: '请输入 ONVIF 用户名', trigger: 'blur' }], onvif_password: [{ required: true, message: '请输入 ONVIF 密码', trigger: 'blur' }], rtsp_username: [{ validator: (_r, value, done) => !credentialForm.rtsp_same_as_onvif && !value ? done(new Error('请输入 RTSP 用户名')) : done(), trigger: 'blur' }], rtsp_password: [{ validator: (_r, value, done) => !credentialForm.rtsp_same_as_onvif && !value ? done(new Error('请输入 RTSP 密码')) : done(), trigger: 'blur' }] } const canWrite = computed(() => store.getters['sense-identity/hasPermission']?.('device.write')) function statusLabel(value) { return ({ pending: '待接入', active: '正常', offline: '离线', disabled: '已停用' })[value] || value } async function load() { loading.value = true; try { Object.assign(page, await listDevices(query)) } finally { loading.value = false } } function reset() { Object.assign(query, { keyword: '', page: 1, page_size: 20 }); load() } function openCreate() { editing.value = null; Object.assign(deviceForm, { name: '', location: '', modality: 'video', capabilities: ['video'] }); deviceDialog.value = true } function openEdit(row) { editing.value = row; Object.assign(deviceForm, { name: row.name, location: row.location, modality: row.modality, capabilities: row.capabilities }); deviceDialog.value = true } -function openCredential(row) { credentialTarget.value = row; Object.assign(credentialForm, { username: '', password: '' }); credentialDialog.value = true } +function openCredential(row) { credentialTarget.value = row; Object.assign(credentialForm, { onvif_username: '', onvif_password: '', rtsp_same_as_onvif: row.rtsp_credential_same_as_onvif !== false, rtsp_username: '', rtsp_password: '' }); credentialDialog.value = true } async function saveDevice() { const valid = await deviceFormRef.value?.validate().catch(() => false); if (!valid) return; saving.value = true; try { if (editing.value) await updateDevice(editing.value.id, { ...deviceForm, version: editing.value.version }); else await createDevice(deviceForm); ElMessage.success('设备已保存'); deviceDialog.value = false; await load() } catch (error) { ElMessage.error(error.message || '保存失败') } finally { saving.value = false } } -async function saveCredential() { const valid = await credentialFormRef.value?.validate().catch(() => false); if (!valid) return; saving.value = true; try { await updateCredential(credentialTarget.value.id, credentialForm); Object.assign(credentialForm, { username: '', password: '' }); ElMessage.success('凭据已安全更新'); credentialDialog.value = false; await load() } catch (error) { ElMessage.error(error.message || '更新失败') } finally { saving.value = false } } +async function saveCredential() { const valid = await credentialFormRef.value?.validate().catch(() => false); if (!valid) return; saving.value = true; try { await updateCredential(credentialTarget.value.id, credentialForm); Object.assign(credentialForm, { onvif_username: '', onvif_password: '', rtsp_same_as_onvif: true, rtsp_username: '', rtsp_password: '' }); ElMessage.success('ONVIF 与 RTSP 凭据已安全更新'); credentialDialog.value = false; await load() } catch (error) { ElMessage.error(error.message || '更新失败') } finally { saving.value = false } } async function disable(row) { await ElMessageBox.confirm(`停用“${row.name}”后将停止后续接入,设备记录和审计仍保留。`, '确认停用', { type: 'warning' }); await disableDevice(row.id, row.version); ElMessage.success('设备已停用'); await load() } onMounted(load) @@ -73,3 +78,4 @@ onMounted(load) +