|
@@ -340,7 +340,7 @@
|
|
|
<el-table-column prop="name" label="名称" min-width="100" show-overflow-tooltip />
|
|
<el-table-column prop="name" label="名称" min-width="100" show-overflow-tooltip />
|
|
|
<el-table-column label="状态(心跳)" min-width="140">
|
|
<el-table-column label="状态(心跳)" min-width="140">
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
- <span :class="['status-text', row.status === 'ONLINE' ? 'status-active' : 'status-dead']">
|
|
|
|
|
|
|
+ <span :class="['status-text', row.status === 'active' ? 'status-active' : 'status-dead']">
|
|
|
{{ formatCameraStatus(row) }}
|
|
{{ formatCameraStatus(row) }}
|
|
|
</span>
|
|
</span>
|
|
|
</template>
|
|
</template>
|
|
@@ -370,7 +370,13 @@
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
<el-button type="primary" link :icon="Edit" @click="handleEditCamera(row)" />
|
|
<el-button type="primary" link :icon="Edit" @click="handleEditCamera(row)" />
|
|
|
<el-button type="danger" link :icon="Delete" @click="handleDeleteCamera(row)" />
|
|
<el-button type="danger" link :icon="Delete" @click="handleDeleteCamera(row)" />
|
|
|
- <el-button type="primary" link :icon="Cross" @click="handleViewCamera(row)" />
|
|
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ link
|
|
|
|
|
+ :class="['crosshairs-btn', { active: activeCameraId === row.id }]"
|
|
|
|
|
+ @click="handleViewCamera(row)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <Icon icon="mdi:crosshairs" />
|
|
|
|
|
+ </el-button>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
</el-table>
|
|
</el-table>
|
|
@@ -442,20 +448,45 @@
|
|
|
<!-- <el-form-item label="IP 地址" prop="ip">
|
|
<!-- <el-form-item label="IP 地址" prop="ip">
|
|
|
<el-input v-model="cameraForm.ip" :disabled="isEditCamera" placeholder="请输入 IP 地址" />
|
|
<el-input v-model="cameraForm.ip" :disabled="isEditCamera" placeholder="请输入 IP 地址" />
|
|
|
</el-form-item> -->
|
|
</el-form-item> -->
|
|
|
- <el-form-item label="摄像头型号" prop="cameraId">
|
|
|
|
|
|
|
+ <el-form-item label="设备ID" prop="cameraId">
|
|
|
|
|
+ <el-input v-model="cameraForm.cameraId" placeholder="请输入设备ID" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="设备名称" prop="cameraName">
|
|
|
|
|
+ <el-input v-model="cameraForm.cameraName" placeholder="请输入设备名称" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="厂商" prop="vendorName">
|
|
|
<el-select
|
|
<el-select
|
|
|
- v-model="cameraForm.selectedVendorId"
|
|
|
|
|
|
|
+ v-model="cameraForm.vendorName"
|
|
|
placeholder="请选择摄像头"
|
|
placeholder="请选择摄像头"
|
|
|
style="width: 100%"
|
|
style="width: 100%"
|
|
|
filterable
|
|
filterable
|
|
|
@change="handleVendorSelect"
|
|
@change="handleVendorSelect"
|
|
|
>
|
|
>
|
|
|
- <el-option v-for="vendor in cameraVendorList" :key="vendor.id" :label="vendor.name" :value="vendor.id" />
|
|
|
|
|
|
|
+ <el-option
|
|
|
|
|
+ v-for="vendor in [
|
|
|
|
|
+ { id: 'hikvision', name: '海康威视' },
|
|
|
|
|
+ { id: 'dahua', name: '大华' },
|
|
|
|
|
+ { id: 'uniview', name: '宇视' },
|
|
|
|
|
+ { id: 'other', name: '其他' }
|
|
|
|
|
+ ]"
|
|
|
|
|
+ :key="vendor.id"
|
|
|
|
|
+ :label="vendor.name"
|
|
|
|
|
+ :value="vendor.id"
|
|
|
|
|
+ />
|
|
|
</el-select>
|
|
</el-select>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
- <el-form-item label="名称" prop="name">
|
|
|
|
|
- <el-input v-model="cameraForm.name" placeholder="请输入名称" />
|
|
|
|
|
|
|
+ <el-form-item label="型号" prop="model">
|
|
|
|
|
+ <el-input v-model="cameraForm.model" placeholder="请输入型号" />
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
|
|
+ <!-- <el-form-item label="摄像头型号" prop="cameraId">
|
|
|
|
|
+ <el-select v-model="cameraForm.selectedVendorId" placeholder="请选择摄像头" style="width: 100%" filterable
|
|
|
|
|
+ @change="handleVendorSelect">
|
|
|
|
|
+ <el-option v-for="vendor in cameraVendorList" :key="vendor.id" :label="vendor.name" :value="vendor.id" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item> -->
|
|
|
|
|
+ <!-- <el-form-item label="名称" prop="name">
|
|
|
|
|
+ <el-input v-model="cameraForm.name" placeholder="请输入名称" />
|
|
|
|
|
+ </el-form-item> -->
|
|
|
<!-- <el-form-item label="端口" prop="port">
|
|
<!-- <el-form-item label="端口" prop="port">
|
|
|
<el-input-number v-model="cameraForm.port" :min="1" :max="65535" style="width: 100%" />
|
|
<el-input-number v-model="cameraForm.port" :min="1" :max="65535" style="width: 100%" />
|
|
|
</el-form-item> -->
|
|
</el-form-item> -->
|
|
@@ -547,16 +578,14 @@ const { t } = useI18n({ useScope: 'global' })
|
|
|
// 格式化状态显示
|
|
// 格式化状态显示
|
|
|
function formatStatus(status: LssNodeStatus | undefined): string {
|
|
function formatStatus(status: LssNodeStatus | undefined): string {
|
|
|
switch (status) {
|
|
switch (status) {
|
|
|
- case 'ONLINE':
|
|
|
|
|
|
|
+ case 'active':
|
|
|
return '在线'
|
|
return '在线'
|
|
|
- case 'OFFLINE':
|
|
|
|
|
|
|
+ case 'hold':
|
|
|
|
|
+ return '离线'
|
|
|
|
|
+ case 'dead':
|
|
|
return '离线'
|
|
return '离线'
|
|
|
- case 'BUSY':
|
|
|
|
|
- return '繁忙'
|
|
|
|
|
- case 'MAINTENANCE':
|
|
|
|
|
- return '维护中'
|
|
|
|
|
default:
|
|
default:
|
|
|
- return '-'
|
|
|
|
|
|
|
+ return '离线'
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -584,15 +613,29 @@ function formatTime(time: string | undefined): string {
|
|
|
|
|
|
|
|
// 格式化摄像头状态
|
|
// 格式化摄像头状态
|
|
|
function formatCameraStatus(row: CameraInfoDTO): string {
|
|
function formatCameraStatus(row: CameraInfoDTO): string {
|
|
|
- if (row.status === 'ONLINE') {
|
|
|
|
|
|
|
+ if (row.status === 'active') {
|
|
|
|
|
+ // 大约5秒钟
|
|
|
return `active [${formatTime(row.updatedAt)}]`
|
|
return `active [${formatTime(row.updatedAt)}]`
|
|
|
|
|
+ } else if (row.status === 'hold') {
|
|
|
|
|
+ // 大约5分钟没有返回
|
|
|
|
|
+ return `hold [${formatTime(row.updatedAt)}]`
|
|
|
} else {
|
|
} else {
|
|
|
|
|
+ // 大约10分钟没有返回
|
|
|
return `dead (离线)`
|
|
return `dead (离线)`
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 当前激活的摄像头 ID
|
|
|
|
|
+const activeCameraId = ref<number | null>(null)
|
|
|
|
|
+
|
|
|
function handleViewCamera(row: CameraInfoDTO) {
|
|
function handleViewCamera(row: CameraInfoDTO) {
|
|
|
- console.log(row)
|
|
|
|
|
|
|
+ // 切换激活状态
|
|
|
|
|
+ if (activeCameraId.value === row.id) {
|
|
|
|
|
+ activeCameraId.value = null
|
|
|
|
|
+ } else {
|
|
|
|
|
+ activeCameraId.value = row.id
|
|
|
|
|
+ }
|
|
|
|
|
+ console.log('Camera active:', row.id, activeCameraId.value === row.id)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 格式化品牌
|
|
// 格式化品牌
|
|
@@ -638,7 +681,7 @@ function handleViewConfig(row: CameraInfoDTO) {
|
|
|
paramsCamera.value = row
|
|
paramsCamera.value = row
|
|
|
paramsDialogType.value = 'config'
|
|
paramsDialogType.value = 'config'
|
|
|
paramsDialogTitle.value = `参数配置 - ${row.name}`
|
|
paramsDialogTitle.value = `参数配置 - ${row.name}`
|
|
|
- paramsContent.value = row.configParams || ''
|
|
|
|
|
|
|
+ paramsContent.value = row.paramConfig || ''
|
|
|
paramsDialogVisible.value = true
|
|
paramsDialogVisible.value = true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -647,7 +690,7 @@ function handleViewRunParams(row: CameraInfoDTO) {
|
|
|
paramsCamera.value = row
|
|
paramsCamera.value = row
|
|
|
paramsDialogType.value = 'run'
|
|
paramsDialogType.value = 'run'
|
|
|
paramsDialogTitle.value = `运行参数 - ${row.name}`
|
|
paramsDialogTitle.value = `运行参数 - ${row.name}`
|
|
|
- paramsContent.value = row.runParams || ''
|
|
|
|
|
|
|
+ paramsContent.value = row.runtimeParams || ''
|
|
|
paramsDialogVisible.value = true
|
|
paramsDialogVisible.value = true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -744,7 +787,9 @@ const paramsCamera = ref<CameraInfoDTO | null>(null)
|
|
|
const cameraForm = reactive({
|
|
const cameraForm = reactive({
|
|
|
selectedVendorId: null as number | null,
|
|
selectedVendorId: null as number | null,
|
|
|
cameraId: '',
|
|
cameraId: '',
|
|
|
- name: '',
|
|
|
|
|
|
|
+ cameraName: '',
|
|
|
|
|
+ vendorName: '',
|
|
|
|
|
+ model: '',
|
|
|
ip: '',
|
|
ip: '',
|
|
|
port: 80,
|
|
port: 80,
|
|
|
username: '',
|
|
username: '',
|
|
@@ -752,7 +797,6 @@ const cameraForm = reactive({
|
|
|
brand: '',
|
|
brand: '',
|
|
|
capability: 'switch_only' as 'switch_only' | 'ptz_enabled',
|
|
capability: 'switch_only' as 'switch_only' | 'ptz_enabled',
|
|
|
rtspUrl: '',
|
|
rtspUrl: '',
|
|
|
- model: '',
|
|
|
|
|
channelNo: '',
|
|
channelNo: '',
|
|
|
remark: '',
|
|
remark: '',
|
|
|
enabled: true,
|
|
enabled: true,
|
|
@@ -761,12 +805,7 @@ const cameraForm = reactive({
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
// 摄像头表单验证规则(动态)
|
|
// 摄像头表单验证规则(动态)
|
|
|
-const cameraRules = computed<FormRules>(() => ({
|
|
|
|
|
- selectedVendorId: isEditCamera.value ? [] : [{ required: true, message: '请选择厂商', trigger: 'change' }],
|
|
|
|
|
- cameraId: isEditCamera.value ? [] : [{ required: true, message: '请输入摄像头 ID', trigger: 'blur' }],
|
|
|
|
|
- ip: isEditCamera.value ? [] : [{ required: true, message: '请输入 IP 地址', trigger: 'blur' }],
|
|
|
|
|
- name: [{ required: true, message: '请输入名称', trigger: 'blur' }]
|
|
|
|
|
-}))
|
|
|
|
|
|
|
+const cameraRules = computed<FormRules>(() => ({}))
|
|
|
|
|
|
|
|
// 排序状态
|
|
// 排序状态
|
|
|
const sortState = reactive<{
|
|
const sortState = reactive<{
|
|
@@ -959,7 +998,9 @@ function handleCameraReset() {
|
|
|
function resetCameraForm() {
|
|
function resetCameraForm() {
|
|
|
cameraForm.selectedVendorId = null
|
|
cameraForm.selectedVendorId = null
|
|
|
cameraForm.cameraId = ''
|
|
cameraForm.cameraId = ''
|
|
|
- cameraForm.name = ''
|
|
|
|
|
|
|
+ cameraForm.cameraName = ''
|
|
|
|
|
+ cameraForm.vendorName = ''
|
|
|
|
|
+ cameraForm.model = ''
|
|
|
cameraForm.ip = ''
|
|
cameraForm.ip = ''
|
|
|
cameraForm.port = 80
|
|
cameraForm.port = 80
|
|
|
cameraForm.username = ''
|
|
cameraForm.username = ''
|
|
@@ -1023,7 +1064,9 @@ async function handleEditCamera(row: CameraInfoDTO) {
|
|
|
currentCamera.value = camera
|
|
currentCamera.value = camera
|
|
|
cameraForm.selectedVendorId = null
|
|
cameraForm.selectedVendorId = null
|
|
|
cameraForm.cameraId = camera.cameraId
|
|
cameraForm.cameraId = camera.cameraId
|
|
|
- cameraForm.name = camera.name
|
|
|
|
|
|
|
+ cameraForm.cameraName = camera.cameraName
|
|
|
|
|
+ cameraForm.vendorName = camera.vendorName || ''
|
|
|
|
|
+ cameraForm.model = camera.model || ''
|
|
|
cameraForm.ip = camera.ip
|
|
cameraForm.ip = camera.ip
|
|
|
cameraForm.port = camera.port || 80
|
|
cameraForm.port = camera.port || 80
|
|
|
cameraForm.username = camera.username || ''
|
|
cameraForm.username = camera.username || ''
|
|
@@ -1062,7 +1105,9 @@ async function handleSubmitCamera() {
|
|
|
}
|
|
}
|
|
|
const data: CameraUpdateRequest = {
|
|
const data: CameraUpdateRequest = {
|
|
|
id: currentCamera.value.id,
|
|
id: currentCamera.value.id,
|
|
|
- name: cameraForm.name,
|
|
|
|
|
|
|
+ cameraName: cameraForm.cameraName,
|
|
|
|
|
+ vendorName: cameraForm.vendorName,
|
|
|
|
|
+ model: cameraForm.model,
|
|
|
port: cameraForm.port,
|
|
port: cameraForm.port,
|
|
|
username: cameraForm.username,
|
|
username: cameraForm.username,
|
|
|
brand: cameraForm.brand,
|
|
brand: cameraForm.brand,
|
|
@@ -1285,6 +1330,24 @@ onMounted(() => {
|
|
|
font-size: 12px;
|
|
font-size: 12px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 十字瞄准按钮样式
|
|
|
|
|
+.crosshairs-btn {
|
|
|
|
|
+ color: #909399;
|
|
|
|
|
+ transition: color 0.2s;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.active {
|
|
|
|
|
+ color: #67c23a;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ color: #85ce61;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
.status-active {
|
|
.status-active {
|
|
|
color: #67c23a;
|
|
color: #67c23a;
|
|
|
}
|
|
}
|