|
|
@@ -107,188 +107,188 @@
|
|
|
<div class="temp-warn">
|
|
|
<div class="warn-item">
|
|
|
<div class="item-basic">
|
|
|
- <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
|
|
|
+ <a-checkbox v-model:checked="formData.findFire"></a-checkbox>
|
|
|
<div style="margin-right: 10px;">热源功能 </div>
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
- <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
|
|
|
+ <a-checkbox v-model:checked="formData.findMove"></a-checkbox>
|
|
|
<div style="margin-right: 10px;">闯入功能 </div>
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
- <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
|
|
|
+ <a-checkbox v-model:checked="formData.fireTrace"></a-checkbox>
|
|
|
<div style="margin-right: 10px;">热源跟踪 </div>
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
- <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
|
|
|
+ <a-checkbox v-model:checked="formData.findDxm"></a-checkbox>
|
|
|
<div style="margin-right: 10px;">低小慢 </div>
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
- <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
|
|
|
+ <a-checkbox v-model:checked="formData.camZoomCapture"></a-checkbox>
|
|
|
<div style="margin-right: 10px;">高清推倍抓拍 </div>
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
- <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
|
|
|
+ <a-checkbox v-model:checked="formData.fireMeasureTemp"></a-checkbox>
|
|
|
<div style="margin-right: 10px;">热源测温 </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="warn-item">
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">告警阈值 : </div>
|
|
|
- <a-input style="width: 150px;" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input style="width: 150px;" v-model:value="formData.fireMinThreshold" placeholder="请输入" size="small" />
|
|
|
<span style="margin: 0 12px;">~</span>
|
|
|
- <a-input style="width: 150px;" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input style="width: 150px;" v-model:value="formData.fireMaxThreshold" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">告警面积矢量 : </div>
|
|
|
- <a-input style="width: 150px;" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input style="width: 150px;" v-model:value="formData.fireMinArea" placeholder="请输入" size="small" />
|
|
|
<span style="margin: 0 11px;">~</span>
|
|
|
- <a-input style="width: 150px;" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input style="width: 150px;" v-model:value="formData.fireMaxArea" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="warn-item">
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">辐射量平衡系数 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.radiation" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">材质发射率 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.emissivity" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">环境温度 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.environmentTemp" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="warn-item">
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">灰度值偏值 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.grayOffset" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">多热源区分阈值 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.fireRadius" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">动态屏蔽灵敏度 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.shakeRadius" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="warn-item">
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">报警最小静止时长 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.stillDuration" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">半圈时长 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.ptzSemiCircleDuration" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">停留时长 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.stayDuration" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="warn-item">
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">低小慢尾长 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.dxmLength" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">低小慢范围 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.dxmRadius" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">设备号 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.deviceId" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="warn-item">
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">设备名称 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.deviceName" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">红外IP : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.ip" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">子网掩码 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.subnetMask" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="warn-item">
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">网关 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.gateway" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">通讯端口号 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.cmdPort" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">告警端口号 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.alarmPort" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="warn-item">
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">横向视场角 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.horFov" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">纵向视场角: </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.verFov" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">主码分辨率: </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.majorStreamReso" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="warn-item">
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">子码分辨率 : </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.minorStreamReso" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">服务器IP: </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.srvCenterIp" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
<div class="item-label1">服务器端口: </div>
|
|
|
- <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
|
|
|
+ <a-input class="item-input" v-model:value="formData.srvCenterPort" placeholder="请输入" size="small" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="warn-item">
|
|
|
<div class="item-basic">
|
|
|
- <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
|
|
|
+ <a-checkbox v-model:checked="formData.showMaxTemp"></a-checkbox>
|
|
|
<div style="margin-right: 10px;">显示最高温 </div>
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
- <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
|
|
|
+ <a-checkbox v-model:checked="formData.showMinTemp"></a-checkbox>
|
|
|
<div style="margin-right: 10px;">显示最低温 </div>
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
- <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
|
|
|
+ <a-checkbox v-model:checked="formData.showAvgTemp"></a-checkbox>
|
|
|
<div style="margin-right: 10px;">显示平均温 </div>
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
- <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
|
|
|
+ <a-checkbox v-model:checked="formData.showRunMode"></a-checkbox>
|
|
|
<div style="margin-right: 10px;">显示运行模式 </div>
|
|
|
</div>
|
|
|
<div class="item-basic">
|
|
|
- <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
|
|
|
+ <a-checkbox v-model:checked="formData.showRunStatus"></a-checkbox>
|
|
|
<div style="margin-right: 10px;">显示运行状态 </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="warn-item">
|
|
|
<div class="item-basic">
|
|
|
- <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
|
|
|
+ <a-checkbox v-model:checked="formData.enableCenterService"></a-checkbox>
|
|
|
<div>开启中心服务</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="btn-box">
|
|
|
- <div class="baisc-btn">获取</div>
|
|
|
- <div class="baisc-btn">
|
|
|
+ <div class="baisc-btn" :class="{ disabled: sysCfgLoading }" @click="onFetchSysCfg">获取</div>
|
|
|
+ <div class="baisc-btn" :class="{ disabled: sysCfgLoading }" @click="onSetSysCfg">
|
|
|
<div class="btn-item">设置</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -331,93 +331,411 @@
|
|
|
</basicBorder>
|
|
|
|
|
|
</div>
|
|
|
- <div class="basic-box2">
|
|
|
+ <!-- <div class="basic-box2">
|
|
|
<basicBorder title="【操作】">
|
|
|
<div class="btn-box">
|
|
|
<div class="baisc-btn-save">重启前端</div>
|
|
|
- <div class="baisc-btn-save">
|
|
|
+ <div class="baisc-btn-save" @click="onRestoreDefaultCfg">
|
|
|
<div class="btn-item">恢复前端默认配置</div>
|
|
|
</div>
|
|
|
<div class="baisc-btn-save">保存前端配置</div>
|
|
|
</div>
|
|
|
</basicBorder>
|
|
|
|
|
|
- </div>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <!-- 未选设备提示弹窗 -->
|
|
|
+ <Teleport to="body">
|
|
|
+ <div v-if="deviceTipVisible" class="device-tip-mask" @click.self="closeDeviceTip">
|
|
|
+ <div class="device-tip-panel">
|
|
|
+ <div class="device-tip-frame">
|
|
|
+ <div class="device-tip-title-tab">提示</div>
|
|
|
+ <div class="device-tip-body">请选择设备!</div>
|
|
|
+ <div class="device-tip-footer">
|
|
|
+ <button type="button" class="device-tip-btn" @click="closeDeviceTip">确定</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Teleport>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { onUnmounted, reactive, ref, watch, onMounted } from 'vue'
|
|
|
+import { reactive, ref, watch } from 'vue'
|
|
|
import basicBorder from './basicBorder.vue'
|
|
|
-import { SvgIcon } from '/@/components/Icon';
|
|
|
-import { autoLogList, dscAlarmLogList } from '../hsqHome.api.js'
|
|
|
-import { dscAlarmLogColumns } from '../hsqHome.data.js'
|
|
|
-import dayjs from 'dayjs';
|
|
|
+import {hsqComControl, getSysCfg, setSysCfg, managesysList, monitorSystem } from '../hsqHome.api'
|
|
|
+import { useMessage } from '/@/hooks/web/useMessage'
|
|
|
+
|
|
|
+/** 前端配置表单(与 ZC_SYSTEM_CFG_S 字段对应) */
|
|
|
+interface SysCfgForm {
|
|
|
+ findFire: boolean
|
|
|
+ findMove: boolean
|
|
|
+ fireTrace: boolean
|
|
|
+ findDxm: boolean
|
|
|
+ camZoomCapture: boolean
|
|
|
+ fireMeasureTemp: boolean
|
|
|
+ fireMinThreshold: string | number
|
|
|
+ fireMaxThreshold: string | number
|
|
|
+ fireMinArea: string | number
|
|
|
+ fireMaxArea: string | number
|
|
|
+ radiation: string | number
|
|
|
+ emissivity: string | number
|
|
|
+ environmentTemp: string | number
|
|
|
+ grayOffset: string | number
|
|
|
+ fireRadius: string | number
|
|
|
+ shakeRadius: string | number
|
|
|
+ stillDuration: string | number
|
|
|
+ ptzSemiCircleDuration: string | number
|
|
|
+ stayDuration: string | number
|
|
|
+ dxmLength: string | number
|
|
|
+ dxmRadius: string | number
|
|
|
+ deviceId: string | number
|
|
|
+ deviceName: string
|
|
|
+ ip: string
|
|
|
+ subnetMask: string
|
|
|
+ gateway: string
|
|
|
+ cmdPort: string | number
|
|
|
+ alarmPort: string | number
|
|
|
+ horFov: string | number
|
|
|
+ verFov: string | number
|
|
|
+ majorStreamReso: string | number
|
|
|
+ minorStreamReso: string | number
|
|
|
+ srvCenterIp: string
|
|
|
+ srvCenterPort: string | number
|
|
|
+ showMaxTemp: boolean
|
|
|
+ showMinTemp: boolean
|
|
|
+ showAvgTemp: boolean
|
|
|
+ showRunMode: boolean
|
|
|
+ showRunStatus: boolean
|
|
|
+ enableCenterService: boolean
|
|
|
+ /** 版本区占位字段(未改版本获取逻辑) */
|
|
|
+ ld: string
|
|
|
+}
|
|
|
|
|
|
+const BOOL_KEYS = [
|
|
|
+ 'findFire',
|
|
|
+ 'findMove',
|
|
|
+ 'fireTrace',
|
|
|
+ 'findDxm',
|
|
|
+ 'camZoomCapture',
|
|
|
+ 'fireMeasureTemp',
|
|
|
+ 'showMaxTemp',
|
|
|
+ 'showMinTemp',
|
|
|
+ 'showAvgTemp',
|
|
|
+ 'showRunMode',
|
|
|
+ 'showRunStatus',
|
|
|
+ 'enableCenterService',
|
|
|
+] as const
|
|
|
+
|
|
|
+const NUMBER_KEYS = [
|
|
|
+ 'fireMinThreshold',
|
|
|
+ 'fireMaxThreshold',
|
|
|
+ 'fireMinArea',
|
|
|
+ 'fireMaxArea',
|
|
|
+ 'radiation',
|
|
|
+ 'emissivity',
|
|
|
+ 'environmentTemp',
|
|
|
+ 'grayOffset',
|
|
|
+ 'fireRadius',
|
|
|
+ 'shakeRadius',
|
|
|
+ 'stillDuration',
|
|
|
+ 'ptzSemiCircleDuration',
|
|
|
+ 'stayDuration',
|
|
|
+ 'dxmLength',
|
|
|
+ 'dxmRadius',
|
|
|
+ 'deviceId',
|
|
|
+ 'cmdPort',
|
|
|
+ 'alarmPort',
|
|
|
+ 'horFov',
|
|
|
+ 'verFov',
|
|
|
+ 'majorStreamReso',
|
|
|
+ 'minorStreamReso',
|
|
|
+ 'srvCenterPort',
|
|
|
+] as const
|
|
|
+
|
|
|
+const STRING_KEYS = [
|
|
|
+ 'deviceName',
|
|
|
+ 'ip',
|
|
|
+ 'subnetMask',
|
|
|
+ 'gateway',
|
|
|
+ 'srvCenterIp',
|
|
|
+] as const
|
|
|
+
|
|
|
+function createEmptyForm(): SysCfgForm {
|
|
|
+ return {
|
|
|
+ findFire: false,
|
|
|
+ findMove: false,
|
|
|
+ fireTrace: false,
|
|
|
+ findDxm: false,
|
|
|
+ camZoomCapture: false,
|
|
|
+ fireMeasureTemp: false,
|
|
|
+ fireMinThreshold: '',
|
|
|
+ fireMaxThreshold: '',
|
|
|
+ fireMinArea: '',
|
|
|
+ fireMaxArea: '',
|
|
|
+ radiation: '',
|
|
|
+ emissivity: '',
|
|
|
+ environmentTemp: '',
|
|
|
+ grayOffset: '',
|
|
|
+ fireRadius: '',
|
|
|
+ shakeRadius: '',
|
|
|
+ stillDuration: '',
|
|
|
+ ptzSemiCircleDuration: '',
|
|
|
+ stayDuration: '',
|
|
|
+ dxmLength: '',
|
|
|
+ dxmRadius: '',
|
|
|
+ deviceId: '',
|
|
|
+ deviceName: '',
|
|
|
+ ip: '',
|
|
|
+ subnetMask: '',
|
|
|
+ gateway: '',
|
|
|
+ cmdPort: '',
|
|
|
+ alarmPort: '',
|
|
|
+ horFov: '',
|
|
|
+ verFov: '',
|
|
|
+ majorStreamReso: '',
|
|
|
+ minorStreamReso: '',
|
|
|
+ srvCenterIp: '',
|
|
|
+ srvCenterPort: '',
|
|
|
+ showMaxTemp: false,
|
|
|
+ showMinTemp: false,
|
|
|
+ showAvgTemp: false,
|
|
|
+ showRunMode: false,
|
|
|
+ showRunStatus: false,
|
|
|
+ enableCenterService: false,
|
|
|
+ ld: '',
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-const DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss'
|
|
|
-let props = defineProps({
|
|
|
+const props = defineProps({
|
|
|
detailData: {
|
|
|
type: Object,
|
|
|
- default: () => { },
|
|
|
+ default: () => ({}),
|
|
|
},
|
|
|
})
|
|
|
|
|
|
-let detailDatas = ref<any>({})
|
|
|
-let tableData = ref<any[]>([])
|
|
|
-/** 时间范围:[开始时间, 结束时间],默认当天 0 点至当前时间 */
|
|
|
-const timeRange = ref<[string, string]>([
|
|
|
- dayjs().startOf('day').format(DATE_FORMAT),
|
|
|
- dayjs().format(DATE_FORMAT),
|
|
|
-])
|
|
|
-let formData = ref<any>({})
|
|
|
-
|
|
|
-// https获取监测数据
|
|
|
-let timer: null | NodeJS.Timeout = null;
|
|
|
-
|
|
|
-/**
|
|
|
- * 定时获取监测数据
|
|
|
- * 通过定时器循环调用数据获取方法,更新表格数据
|
|
|
- *
|
|
|
- * @param flag - 是否立即执行(首次调用时传true跳过延时)
|
|
|
- */
|
|
|
-function getMonitor(flag?: boolean) {
|
|
|
- timer = setTimeout(async () => {
|
|
|
- await getDscAlarmLogList();
|
|
|
- if (timer) {
|
|
|
- timer = null;
|
|
|
+const { createMessage } = useMessage()
|
|
|
+const formData = reactive<SysCfgForm>(createEmptyForm())
|
|
|
+/** 最近一次 getSysCfg 原始配置,设置时合并未展示字段 */
|
|
|
+const rawSysCfg = ref<Record<string, any>>({})
|
|
|
+const currentDeviceId = ref('')
|
|
|
+const sysCfgLoading = ref(false)
|
|
|
+/** 未选设备提示 */
|
|
|
+const deviceTipVisible = ref(false)
|
|
|
+/** 列表「恢复默认配置」时跳过一次 detailData watch,避免重复请求 */
|
|
|
+const skipDetailWatchOnce = ref(false)
|
|
|
+
|
|
|
+function closeDeviceTip() {
|
|
|
+ deviceTipVisible.value = false
|
|
|
+}
|
|
|
+
|
|
|
+function toBool(value: unknown) {
|
|
|
+ if (typeof value === 'boolean') return value
|
|
|
+ const num = Number(value)
|
|
|
+ if (Number.isFinite(num)) return num !== 0
|
|
|
+ return Boolean(value)
|
|
|
+}
|
|
|
+
|
|
|
+function toDisplayValue(value: unknown) {
|
|
|
+ if (value == null) return ''
|
|
|
+ return value as string | number
|
|
|
+}
|
|
|
+
|
|
|
+function toIntFlag(checked: boolean) {
|
|
|
+ return checked ? 1 : 0
|
|
|
+}
|
|
|
+
|
|
|
+function toNumberOrKeep(value: string | number) {
|
|
|
+ if (value === '' || value == null) return value
|
|
|
+ const num = Number(value)
|
|
|
+ return Number.isFinite(num) ? num : value
|
|
|
+}
|
|
|
+
|
|
|
+/** 解析 getSysCfg 返回对象 */
|
|
|
+function normalizeSysCfg(res: Record<string, any> | null | undefined) {
|
|
|
+ if (!res || typeof res !== 'object') return {}
|
|
|
+ if (res.data && typeof res.data === 'object' && !Array.isArray(res.data)) {
|
|
|
+ return { ...res.data }
|
|
|
+ }
|
|
|
+ return { ...res }
|
|
|
+}
|
|
|
+
|
|
|
+/** 将配置回填到表单 */
|
|
|
+function applyCfgToForm(cfg: Record<string, any>) {
|
|
|
+ const next = createEmptyForm()
|
|
|
+ BOOL_KEYS.forEach((key) => {
|
|
|
+ if (key === 'enableCenterService') {
|
|
|
+ next.enableCenterService = toBool(
|
|
|
+ cfg.enableCenterService ?? cfg.openCenterService ?? cfg.centerServiceEnable ?? 0,
|
|
|
+ )
|
|
|
+ return
|
|
|
}
|
|
|
- getMonitor();
|
|
|
- }, flag ? 0 : 10000);
|
|
|
+ next[key] = toBool(cfg[key])
|
|
|
+ })
|
|
|
+ NUMBER_KEYS.forEach((key) => {
|
|
|
+ next[key] = toDisplayValue(cfg[key])
|
|
|
+ })
|
|
|
+ STRING_KEYS.forEach((key) => {
|
|
|
+ next[key] = cfg[key] != null ? String(cfg[key]) : ''
|
|
|
+ })
|
|
|
+ Object.assign(formData, next)
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * 获取双光谱摄像机报警记录-分页列表查询
|
|
|
- * 调用 dscAlarmLogList 接口获取双光谱摄像机报警记录分页列表,
|
|
|
- * 并将返回数据赋值给 warnList
|
|
|
- */
|
|
|
-async function getDscAlarmLogList() {
|
|
|
- const res = await dscAlarmLogList({ pageNo: 1, pageSize: 1000, startTime: timeRange.value?.[0], endTime: timeRange.value?.[1] });
|
|
|
- if (res && res.records) {
|
|
|
- tableData.value = res.records.map(el => ({
|
|
|
- ...el,
|
|
|
- eventTypeC: el.eventType == '10001' ? '热源报警' : el.eventType == '10002' ? '闯入报警' : '-',
|
|
|
- }))
|
|
|
+/** 由表单生成 setSysCfg 的 data 载荷(仅表单字段) */
|
|
|
+function buildSysCfgPayload() {
|
|
|
+ const payload: Record<string, any> = {}
|
|
|
+ BOOL_KEYS.forEach((key) => {
|
|
|
+ if (key === 'enableCenterService') {
|
|
|
+ payload.enableCenterService = toIntFlag(formData.enableCenterService)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ payload[key] = toIntFlag(formData[key])
|
|
|
+ })
|
|
|
+ NUMBER_KEYS.forEach((key) => {
|
|
|
+ payload[key] = toNumberOrKeep(formData[key])
|
|
|
+ })
|
|
|
+ STRING_KEYS.forEach((key) => {
|
|
|
+ payload[key] = formData[key] ?? ''
|
|
|
+ })
|
|
|
+ return payload
|
|
|
+}
|
|
|
+
|
|
|
+/** 从设备对象解析 SDK deviceid */
|
|
|
+function resolveDeviceIdFromDevice(device: Record<string, any> | null | undefined) {
|
|
|
+ if (!device) return ''
|
|
|
+ const raw =
|
|
|
+ device.deviceID ??
|
|
|
+ device.deviceid ??
|
|
|
+ device.deviceId ??
|
|
|
+ device.devId ??
|
|
|
+ device.id ??
|
|
|
+ ''
|
|
|
+ return raw != null && String(raw).trim() !== '' ? String(raw).trim() : ''
|
|
|
+}
|
|
|
+
|
|
|
+/** 解析当前可用设备 ID:优先 props,其次列表首台设备 */
|
|
|
+async function ensureDeviceId() {
|
|
|
+ const fromProp = resolveDeviceIdFromDevice(props.detailData as Record<string, any>)
|
|
|
+ if (fromProp) {
|
|
|
+ currentDeviceId.value = fromProp
|
|
|
+ return fromProp
|
|
|
+ }
|
|
|
+ if (currentDeviceId.value) return currentDeviceId.value
|
|
|
+
|
|
|
+ try {
|
|
|
+ const sysRes = await managesysList({ strtype: 'sys_openair_fire', pagetype: 'normal' })
|
|
|
+ const systemId = sysRes?.records?.[0]?.id
|
|
|
+ if (!systemId) return ''
|
|
|
+ const res = await monitorSystem({ type: 'all', systemID: systemId, devicetype: '' })
|
|
|
+ const list = res?.deviceInfo?.duaSpeCamera?.datalist || []
|
|
|
+ const firstId = resolveDeviceIdFromDevice(list[0])
|
|
|
+ currentDeviceId.value = firstId
|
|
|
+ return firstId
|
|
|
+ } catch (e) {
|
|
|
+ console.error('解析设备 ID 失败', e)
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** 调用 getSysCfg 并回显 */
|
|
|
+async function fetchSysCfg(showTip = false) {
|
|
|
+ if (sysCfgLoading.value) return
|
|
|
+ const deviceid = await ensureDeviceId()
|
|
|
+ if (!deviceid) {
|
|
|
+ createMessage.warning('未找到可用设备,无法获取前端配置')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ sysCfgLoading.value = true
|
|
|
+ try {
|
|
|
+ const res = await getSysCfg({
|
|
|
+ deviceid,
|
|
|
+ paramcode: 'getSysCfg',
|
|
|
+ noCheckPassword: true,
|
|
|
+ })
|
|
|
+ const cfg = normalizeSysCfg(res as Record<string, any>)
|
|
|
+ rawSysCfg.value = cfg
|
|
|
+ applyCfgToForm(cfg)
|
|
|
+ if (showTip) createMessage.success('获取前端配置成功')
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取前端配置失败', e)
|
|
|
+ createMessage.error('获取前端配置失败')
|
|
|
+ } finally {
|
|
|
+ sysCfgLoading.value = false
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-watch(() => props.detailData, (newVal, oldVal) => {
|
|
|
- detailDatas.value = Object.assign({}, newVal.readData, newVal,)
|
|
|
-}, { immediate: true })
|
|
|
+/** 点击获取 */
|
|
|
+function onFetchSysCfg() {
|
|
|
+ fetchSysCfg(true)
|
|
|
+}
|
|
|
+
|
|
|
+/** 点击设置:先 setSysCfg,成功后再 getSysCfg 刷新 */
|
|
|
+async function onSetSysCfg() {
|
|
|
+ if (sysCfgLoading.value) return
|
|
|
+ const deviceid = await ensureDeviceId()
|
|
|
+ if (!deviceid) {
|
|
|
+ createMessage.warning('未找到可用设备,无法设置前端配置')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ sysCfgLoading.value = true
|
|
|
+ try {
|
|
|
+ const data = buildSysCfgPayload()
|
|
|
+ await hsqComControl({
|
|
|
+ deviceid,
|
|
|
+ paramcode: 'setSysCfg',
|
|
|
+ noCheckPassword: true,
|
|
|
+ data,
|
|
|
+ })
|
|
|
+ createMessage.success('设置前端配置成功')
|
|
|
+ sysCfgLoading.value = false
|
|
|
+ await fetchSysCfg(false)
|
|
|
+ } catch (e) {
|
|
|
+ console.error('设置前端配置失败', e)
|
|
|
+ createMessage.error('设置前端配置失败')
|
|
|
+ sysCfgLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-onMounted(() => {
|
|
|
- getMonitor(true);
|
|
|
-});
|
|
|
-onUnmounted(() => {
|
|
|
- if (timer) {
|
|
|
- clearTimeout(timer);
|
|
|
+/** 恢复前端默认配置:未选设备提示;已选则重新 getSysCfg 回填重置 */
|
|
|
+function onRestoreDefaultCfg(device?: Record<string, any>) {
|
|
|
+ if (sysCfgLoading.value) return
|
|
|
+ const deviceid = resolveDeviceIdFromDevice(
|
|
|
+ (device || props.detailData) as Record<string, any>,
|
|
|
+ )
|
|
|
+ if (!deviceid) {
|
|
|
+ deviceTipVisible.value = true
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (device) {
|
|
|
+ skipDetailWatchOnce.value = true
|
|
|
}
|
|
|
-});
|
|
|
+ currentDeviceId.value = deviceid
|
|
|
+ fetchSysCfg(true)
|
|
|
+}
|
|
|
+
|
|
|
+/** 点击设备列表「详情」后由父组件更新 detailData,再拉取前端配置 */
|
|
|
+watch(
|
|
|
+ () => props.detailData,
|
|
|
+ (val) => {
|
|
|
+ const id = resolveDeviceIdFromDevice(val as Record<string, any>)
|
|
|
+ if (!id) return
|
|
|
+ if (skipDetailWatchOnce.value) {
|
|
|
+ skipDetailWatchOnce.value = false
|
|
|
+ currentDeviceId.value = id
|
|
|
+ return
|
|
|
+ }
|
|
|
+ currentDeviceId.value = id
|
|
|
+ fetchSysCfg(false)
|
|
|
+ },
|
|
|
+ { deep: true },
|
|
|
+)
|
|
|
+
|
|
|
+defineExpose({
|
|
|
+ onRestoreDefaultCfg,
|
|
|
+})
|
|
|
</script>
|
|
|
<style lang="less" scoped>
|
|
|
@import '/@/design/theme.less';
|
|
|
@@ -510,19 +828,19 @@ onUnmounted(() => {
|
|
|
|
|
|
.basic-box {
|
|
|
position: relative;
|
|
|
- height: 480px;
|
|
|
+ height: 575px;
|
|
|
margin-bottom: 10px;
|
|
|
}
|
|
|
|
|
|
.basic-box1 {
|
|
|
// height: calc(100% - 230px);
|
|
|
height: 125px;
|
|
|
- margin-bottom: 10px;
|
|
|
+ // margin-bottom: 10px;
|
|
|
}
|
|
|
|
|
|
- .basic-box2 {
|
|
|
- height: 85px;
|
|
|
- }
|
|
|
+ // .basic-box2 {
|
|
|
+ // height: 85px;
|
|
|
+ // }
|
|
|
|
|
|
.temp-warn {
|
|
|
position: relative;
|
|
|
@@ -537,7 +855,7 @@ onUnmounted(() => {
|
|
|
align-items: center;
|
|
|
height: 32px;
|
|
|
background: linear-gradient(to right, #134c77, transparent);
|
|
|
- margin-bottom: 10px;
|
|
|
+ margin-bottom: 9px;
|
|
|
padding: 0px 10px;
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
@@ -597,6 +915,12 @@ onUnmounted(() => {
|
|
|
border-radius: 4px;
|
|
|
padding: 3px;
|
|
|
cursor: pointer;
|
|
|
+
|
|
|
+ &.disabled {
|
|
|
+ opacity: 0.55;
|
|
|
+ cursor: not-allowed;
|
|
|
+ pointer-events: none;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.baisc-btn-save {
|
|
|
@@ -869,4 +1193,111 @@ onUnmounted(() => {
|
|
|
display: none;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+/* 未选设备提示弹窗(风格对齐视频预览提示) */
|
|
|
+.device-tip-mask {
|
|
|
+ position: fixed;
|
|
|
+ inset: 0;
|
|
|
+ z-index: 2200;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background: rgba(0, 8, 20, 0.55);
|
|
|
+}
|
|
|
+
|
|
|
+.device-tip-panel {
|
|
|
+ width: min(360px, calc(100vw - 48px));
|
|
|
+}
|
|
|
+
|
|
|
+.device-tip-frame {
|
|
|
+ position: relative;
|
|
|
+ padding: 36px 20px 18px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background: linear-gradient(180deg, rgba(6, 28, 48, 0.98) 0%, rgba(4, 16, 32, 0.98) 100%);
|
|
|
+ border: 1px solid rgba(0, 210, 255, 0.85);
|
|
|
+ box-shadow:
|
|
|
+ 0 0 0 2px rgba(8, 40, 70, 0.95),
|
|
|
+ 0 0 22px rgba(0, 200, 255, 0.35),
|
|
|
+ inset 0 0 0 1px rgba(0, 180, 255, 0.35);
|
|
|
+ clip-path: polygon(
|
|
|
+ 10px 0,
|
|
|
+ calc(100% - 10px) 0,
|
|
|
+ 100% 10px,
|
|
|
+ 100% calc(100% - 10px),
|
|
|
+ calc(100% - 10px) 100%,
|
|
|
+ 10px 100%,
|
|
|
+ 0 calc(100% - 10px),
|
|
|
+ 0 10px
|
|
|
+ );
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.device-tip-title-tab {
|
|
|
+ position: absolute;
|
|
|
+ top: -1px;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ min-width: 112px;
|
|
|
+ height: 28px;
|
|
|
+ padding: 0 28px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ color: #fff;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ letter-spacing: 2px;
|
|
|
+ background: linear-gradient(180deg, #2ad4e8 0%, #1498b8 55%, #0c6f8a 100%);
|
|
|
+ clip-path: polygon(12px 0, calc(100% - 12px) 0, 100% 100%, 0 100%);
|
|
|
+ box-shadow: 0 0 10px rgba(0, 200, 255, 0.45);
|
|
|
+ z-index: 2;
|
|
|
+}
|
|
|
+
|
|
|
+.device-tip-body {
|
|
|
+ min-height: 72px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ color: #e8f4ff;
|
|
|
+ font-size: 16px;
|
|
|
+ letter-spacing: 1px;
|
|
|
+ padding: 12px 8px 8px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.device-tip-footer {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 4px 0 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.device-tip-btn {
|
|
|
+ min-width: 96px;
|
|
|
+ height: 32px;
|
|
|
+ padding: 0 22px;
|
|
|
+ border: 1px solid rgba(0, 210, 255, 0.75);
|
|
|
+ border-radius: 2px;
|
|
|
+ background: linear-gradient(180deg, rgba(20, 100, 140, 0.85) 0%, rgba(10, 60, 95, 0.9) 100%);
|
|
|
+ color: #fff;
|
|
|
+ font-size: 14px;
|
|
|
+ letter-spacing: 2px;
|
|
|
+ cursor: pointer;
|
|
|
+ box-shadow: 0 0 8px rgba(0, 183, 255, 0.25);
|
|
|
+ transition: color 0.2s, border-color 0.2s, background 0.2s, box-shadow 0.2s;
|
|
|
+
|
|
|
+ &:hover,
|
|
|
+ &:focus {
|
|
|
+ border-color: #01fefc;
|
|
|
+ color: #01fefc;
|
|
|
+ background: rgba(0, 90, 140, 0.55);
|
|
|
+ box-shadow: 0 0 10px rgba(1, 254, 252, 0.35);
|
|
|
+ outline: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:active {
|
|
|
+ transform: translateY(1px);
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|