yanghao il y a 2 semaines
Parent
commit
2da5ca52b7

+ 1 - 1
.env.local

@@ -4,7 +4,7 @@ NODE_ENV=development
 VITE_DEV=true
 
 # 请求路径
-VITE_BASE_URL='http://192.168.188.149:48080' # 192.168.188.149:48080 https://iot.deepoil.cc
+VITE_BASE_URL='https://iot.deepoil.cc' # 192.168.188.149:48080 https://iot.deepoil.cc
 
 # MQTT服务地址
 VITE_MQTT_SERVER_URL = 'ws://localhost:8083/mqtt'

+ 2 - 2
src/api/pms/video/channel.ts

@@ -3,7 +3,7 @@ import request from '@/config/axios'
 // 查询监控设备通道信息列表
 export async function listChannel(query) {
   return await request.get({
-    url: '/sip/channel/list',
+    url: '/rq/yf-sip-device-channel/list',
     params: query
   })
 }
@@ -18,7 +18,7 @@ export function getChannel(channelId) {
 // 新增监控设备通道信息
 export function addChannel(createNum, data) {
   return request.post({
-    url: '/sip/channel/' + createNum,
+    url: '/rq/yf-sip-device-channel/' + createNum,
 
     data
   })

+ 5 - 5
src/api/pms/video/device.ts

@@ -47,7 +47,7 @@ export function listAllDeviceShort() {
 // 查询设备详细
 export function getDevice(deviceId) {
     return request.get({
-        url: '/iot/device/' + deviceId,
+        url: '/rq/yf-iot-device/' + deviceId,
         
     });
 }
@@ -135,7 +135,7 @@ export function getDeviceThingsModelValue(deviceId) {
 // 新增设备
 export function addDevice(data) {
     return request.post({
-        url: '/iot/device',
+        url: '/rq/yf-iot-device',
         
         data: data,
     });
@@ -144,7 +144,7 @@ export function addDevice(data) {
 // 修改设备
 export function updateDevice(data) {
     return request.put({
-        url: '/iot/device',
+        url: '/rq/yf-iot-device',
        
         data: data,
     });
@@ -153,7 +153,7 @@ export function updateDevice(data) {
 // 删除设备
 export function delDevice(deviceId) {
     return request.delete({
-        url: '/iot/device/' + deviceId,
+        url: '/rq/yf-iot-device/' + deviceId,
        
     });
 }
@@ -161,7 +161,7 @@ export function delDevice(deviceId) {
 // 生成设备编号
 export function generatorDeviceNum(params) {
     return request.get({
-        url: '/iot/device/generator',
+        url: '/rq/yf-iot-device/generator',
         
         params: params,
     });

+ 6 - 6
src/api/pms/video/mediaServer.ts

@@ -3,7 +3,7 @@ import request from '@/config/axios'
 // 查询流媒体服务器配置列表
 export function listmediaServer(query) {
   return request.get({
-    url: '/sip/mediaserver/list',
+    url: '/rq/yf-media-server/page',
    
     params: query
   })
@@ -12,7 +12,7 @@ export function listmediaServer(query) {
 // 查询流媒体服务器配置详细
 export function getmediaServer() {
   return request.get({
-    url: '/sip/mediaserver/',
+    url: '/rq/yf-media-server/',
     
   })
 }
@@ -20,7 +20,7 @@ export function getmediaServer() {
 // 新增流媒体服务器配置
 export function addmediaServer(data) {
   return request.post({
-    url: '/sip/mediaserver',
+    url: '/rq/yf-media-server/create',
     
     data: data
   })
@@ -29,7 +29,7 @@ export function addmediaServer(data) {
 // 修改流媒体服务器配置
 export function updatemediaServer(data) {
   return request.put({
-    url: '/sip/mediaserver',
+    url: '/rq/yf-media-server/update',
     
     data: data
   })
@@ -38,14 +38,14 @@ export function updatemediaServer(data) {
 // 删除流媒体服务器配置
 export function delmediaServer(id) {
   return request.delete({
-    url: '/sip/mediaserver/' + id,
+    url: '/rq/yf-media-server/' + id,
    
   })
 }
 
 export function checkmediaServer(query) {
   return request.get({
-    url: '/sip/mediaserver/check' ,
+    url: '/rq/yf-media-server/check' ,
     
     params: query
   })

+ 88 - 0
src/api/pms/video/record.ts

@@ -0,0 +1,88 @@
+import request from '@/config/axios'
+
+export function getDevRecord(deviceId,channelId,query) {
+  return request.get({
+    url: '/sip/record/devquery/' + deviceId + "/" + channelId,
+ 
+    params: query
+  })
+}
+
+export function getRecord(channelId,sn) {
+  return request.get({
+    url: '/sip/record/query/' + channelId + "/" + sn,
+   
+  })
+}
+
+export function getServerRecord(query) {
+  return request.get({
+    url: '/sip/record/serverRecord/list',
+  
+    params: query
+  })
+}
+
+export function getServerRecordByDate(query) {
+  return request.get({
+    url: '/sip/record/serverRecord/date/list',
+ 
+    params: query
+  })
+}
+
+export function getServerRecordByStream(query) {
+  return request.get({
+    url: '/sip/record/serverRecord/stream/list',
+   
+    params: query
+  })
+}
+
+export function getServerRecordByApp(query) {
+  return request.get({
+    url: '/sip/record/serverRecord/app/list',
+   
+    params: query
+  })
+}
+
+export function getServerRecordByFile(query) {
+  return request.get({
+    url: '/sip/record/serverRecord/file/list',
+   
+    params: query
+  })
+}
+
+export function getServerRecordByDevice(query) {
+  return request.get({
+    url: '/sip/record/serverRecord/device/list',
+   
+    params: query
+  })
+}
+
+export function startPlayRecord(deviceId, channelId) {
+  return request.get({
+    url: '/sip/record/play/' + deviceId + "/" + channelId,
+   
+  })
+}
+
+export function startDownloadRecord(deviceId, channelId, query) {
+  return request.get({
+    url: '/sip/record/download/' + deviceId + "/" + channelId,
+ 
+    params: query
+  })
+}
+
+
+export function uploadRecord(query) {
+  return request.get({
+    url: '/sip/record/upload',
+    
+    params: query
+  })
+}

BIN
src/assets/imgs/qrcode.png


BIN
src/assets/imgs/wifi-die.png


BIN
src/assets/imgs/wifi-live.png


+ 848 - 0
src/locales/zh-CN.ts

@@ -1830,6 +1830,854 @@ export default {
   "category142342-8": "是否确认删除产品分类编号为{0}的数据项?",
   "product-scada034908-0": "创建组态"
   },
+  device:{
+  "allot-import-dialog060657-0": "产品",
+  "allot-import-dialog060657-1": "请选择产品",
+  "allot-import-dialog060657-2": "目标机构",
+  "allot-import-dialog060657-3": "请选择目标机构",
+  "allot-import-dialog060657-7": "1.仅允许导入xls、xlsx格式文件。",
+  "allot-import-dialog060657-8": "2.单次最多分配1000个设备,单次设备较多时需要较长的校验、导入时间。",
+  "allot-import-dialog060657-9": "3.上传文件并分配后,可到设备列表-更多操作-设备导入记录中查看上传失败的设备详情信息。",
+  "allot-import-dialog060657-10": "设备分配模板",
+  "allot-import-dialog060657-12": "确认分配",
+  "allot-import-dialog060657-13": "导入分配",
+  "allot-import-dialog060657-14": "产品不能为空",
+  "allot-import-dialog060657-15": "目标机构不能为空",
+  "allot-import-dialog060657-17": "导入结果",
+  "allot-record155854-0": "设备分配记录",
+  "allot-record155854-1": "归属机构",
+  "allot-record155854-2": "产品名称",
+  "allot-record155854-5": "设备被分配前的归属机构",
+  "allot-record155854-7": "设备被分配后的归属机构",
+  "allot-record155854-8": "分配总数",
+  "allot-record155854-9": "分配成功",
+  "allot-record155854-10": "分配失败",
+  "allot-record155854-11": "分配状态",
+  "allot-record155854-12": "分配方式",
+  "allot-record155854-13": "分配时间",
+  "allot-record155854-15": "下载明细",
+  "batch-import-dialog850870-5": "提示:仅允许导入xls、xlsx格式文件。",
+  "batch-import-dialog850870-6": "下载设备导入模板",
+  "device-edit148398-0": "* 基本信息",
+  "device-edit148398-1": "设备名称",
+  "device-edit148398-2": "请输入设备名称",
+  "device-edit148398-3": "摘要",
+  "device-edit148398-4": "所属产品",
+  "device-edit148398-5": "产品名称",
+  "device-edit148398-6": "选择",
+  "device-edit148398-7": "设备编号",
+  "device-edit148398-8": "请输入设备编号",
+  "device-edit148398-9": "生成",
+  "device-edit148398-10": "当前选择TCP协议,设备编号生成为HEX格式",
+  "device-edit148398-11": "当前选择的产品属于modbus协议,将在网关设备创建后根据采集点模板生成子设备",
+  "device-edit148398-12": "固件版本",
+  "device-edit148398-13": "请输入固件版本",
+  "device-edit148398-14": "模拟设备",
+  "device-edit148398-15": "设备影子",
+  "device-edit148398-16": "禁用设备",
+  "device-edit148398-17": "备注信息",
+  "device-edit148398-18": "请输入备注信息",
+  "device-edit148398-19": "定位方式",
+  "device-edit148398-20": "请选择设备状态",
+  "device-edit148398-21": "设备经度",
+  "device-edit148398-22": "请输入设备经度",
+  "device-edit148398-23": "坐标拾取",
+  "device-edit148398-24": "设备纬度",
+  "device-edit148398-25": "请输入设备纬度",
+  "device-edit148398-26": "所在地址",
+  "device-edit148398-27": "请输入设备所在地址",
+  "device-edit148398-28": "入网地址",
+  "device-edit148398-29": "设备入网IP",
+  "device-edit148398-30": "激活时间",
+  "device-edit148398-31": "设备激活时间",
+  "device-edit148398-32": "设备信号",
+  "device-edit148398-33": "设备信号强度",
+  "device-edit148398-34": "其他信息",
+  "device-edit148398-35": "认证信息",
+  "device-edit148398-36": "二维码",
+  "device-edit148398-37": "地图展示区域,新增后显示",
+  "device-edit148398-38": "修",
+  "device-edit148398-39": "改",
+  "device-edit148398-40": "新",
+  "device-edit148398-41": "增",
+  "device-edit148398-42": "运行状态",
+  "device-edit148398-43": "子设备",
+  "device-edit148398-44": "设备通道",
+  "device-edit148398-45": "设备直播",
+  "device-edit148398-46": "直播录像",
+  "device-edit148398-47": "设备定时",
+  "device-edit148398-48": "设备分享",
+  "device-edit148398-49": "事件日志",
+  "device-edit148398-50": "指令日志",
+  "device-edit148398-51": "实时监测",
+  "device-edit148398-52": "监测统计",
+  "device-edit148398-53": "返回列表",
+  "device-edit148398-54": "摘要(设备上传的只读数据)",
+  "device-edit148398-55": "复制",
+  "device-edit148398-56": "设备二维码",
+  "device-edit148398-57": "关 闭",
+  "device-edit148398-58": "Mqtt连接参数",
+  "device-edit148398-59": "一键复制",
+  "device-edit148398-60": "设备名称不能为空",
+  "device-edit148398-61": "设备名称长度在 2 到 32 个字符",
+  "device-edit148398-62": "固件版本不能为空",
+  "device-edit148398-63": "接收到【设备状态-详情】主题:",
+  "device-edit148398-64": "接收到【设备状态-详情】内容:",
+  "device-edit148398-65": "设备编号不能为空",
+  "device-edit148398-66": "设备编号只能是字母和数字",
+  "device-edit148398-67": "所属产品不能为空",
+  "device-edit148398-68": "修改成功",
+  "device-edit148398-69": "设备编号已经存在,添加设备失败",
+  "device-edit148398-70": "添加设备成功",
+  "device-edit148398-71": "复制成功",
+  "device-edit148398-72": "请先选择产品",
+  "device-edit148398-73": "组态应用",
+  "device-edit148398-74": "数据采集",
+  "device-edit148398-75": "视频监控",
+  "device-edit148398-76": "数据调试",
+  "device-edit148398-77": "轮询任务",
+  "device-edit148398-78": "网关",
+  "device-edit148398-79": "云端录像",
+  "device-edit148398-80": "告警用户",
+  "device-edit148398-81": "设备告警",
+  "device-functionlog399522-0": "请选择设备从机:",
+  "device-functionlog399522-1": "请选择设备从机",
+  "device-functionlog399522-2": "从机地址:$",
+  "device-functionlog399522-3": "日志类型",
+  "device-functionlog399522-4": "请选择类型",
+  "device-functionlog399522-5": "标识符",
+  "device-functionlog399522-6": "请输入标识符",
+  "device-functionlog399522-7": "时间范围",
+  "device-functionlog399522-8": "开始日期",
+  "device-functionlog399522-9": "结束日期",
+  "device-functionlog399522-10": "搜索",
+  "device-functionlog399522-11": "重置",
+  "device-functionlog399522-12": "指令类型",
+  "device-functionlog399522-13": "设置值",
+  "device-functionlog399522-15": "下发时间",
+  "device-functionlog399522-16": "下发结果描述",
+  "device-functionlog399522-18": "删除",
+  "device-functionlog399522-19": "寄存器地址",
+  "device-functionlog399522-20": "标识符不能为空",
+  "device-functionlog399522-21": "1==服务下发,2=属性获取,3.OTA升级不能为空",
+  "device-functionlog399522-22": "日志值不能为空",
+  "device-functionlog399522-23": "设备编号不能为空",
+  "device-functionlog399522-24": "是否确认删除设备服务下发日志编号为{0}的数据项?",
+  "device-functionlog399522-26": "删除成功",
+  "device-linkage188958-0": "请输入机构名称",
+  "device-linkage188958-1": "全部",
+  "device-linkage188958-2": "在线",
+  "device-linkage188958-3": "离线",
+  "device-linkage188958-5": "设备列表",
+  "device-linkage188958-25": "请选择设备状态",
+  "device-linkage188958-26": "设备经度",
+  "device-linkage188958-27": "请输入设备经度",
+  "device-linkage188958-28": "坐标拾取",
+  "device-linkage188958-29": "设备纬度",
+  "device-linkage188958-30": "请输入设备纬度",
+  "device-linkage188958-31": "所在地址",
+  "device-linkage188958-32": "请输入设备所在地址",
+  "device-linkage188958-33": "入网地址",
+  "device-linkage188958-34": "设备入网IP",
+  "device-linkage188958-35": "激活时间",
+  "device-linkage188958-36": "设备激活时间",
+  "device-linkage188958-37": "设备信号",
+  "device-linkage188958-38": "设备信号强度",
+  "device-linkage188958-39": "其他信息",
+  "device-linkage188958-40": "认证信息",
+  "device-linkage188958-41": "二维码",
+  "device-linkage188958-42": "地图展示区域,新增后显示",
+  "device-linkage188958-43": "运行状态",
+  "device-linkage188958-44": "子设备",
+  "device-linkage188958-45": "设备通道",
+  "device-linkage188958-46": "设备直播",
+  "device-linkage188958-47": "直播录像",
+  "device-linkage188958-48": "设备定时",
+  "device-linkage188958-49": "设备分享",
+  "device-linkage188958-50": "事件日志",
+  "device-linkage188958-51": "指令日志",
+  "device-linkage188958-52": "实时监测",
+  "device-linkage188958-53": "监测统计",
+  "device-linkage188958-54": "摘要(设备上传的只读数据)",
+  "device-linkage188958-55": "复制",
+  "device-linkage188958-56": "设备二维码",
+  "device-linkage188958-57": "关 闭",
+  "device-linkage188958-58": "Mqtt连接参数",
+  "device-linkage188958-59": "一键复制",
+  "device-linkage188958-60": "设备名称不能为空",
+  "device-linkage188958-61": "设备名称长度在 2 到 32 个字符",
+  "device-linkage188958-62": "固件版本不能为空",
+  "device-linkage188958-63": "接收到【设备状态-详情】主题:",
+  "device-linkage188958-64": "接收到【设备状态-详情】内容:",
+  "device-linkage188958-65": "设备编号不能为空",
+  "device-linkage188958-66": "设备编号只能是字母和数字",
+  "device-linkage188958-67": "所属产品不能为空",
+  "device-linkage188958-68": "修改成功",
+  "device-linkage188958-69": "设备编号已经存在,添加设备失败",
+  "device-linkage188958-70": "添加设备成功",
+  "device-linkage188958-71": "复制成功",
+  "device-linkage188958-72": "请先选择产品",
+  "device-linkage188958-73": "告警用户",
+  "device-log798283-0": "日志类型",
+  "device-log798283-1": "请选择类型",
+  "device-log798283-2": "标识符",
+  "device-log798283-3": "请输入标识符",
+  "device-log798283-4": "时间范围",
+  "device-log798283-5": "开始日期",
+  "device-log798283-6": "结束日期",
+  "device-log798283-7": "搜索",
+  "device-log798283-8": "重置",
+  "device-log798283-9": "类型",
+  "device-log798283-10": "模式",
+  "device-log798283-11": "影子模式",
+  "device-log798283-12": "在线模式",
+  "device-log798283-13": "其他信息",
+  "device-log798283-14": "时间",
+  "device-log798283-15": "动作",
+  "device-log798283-16": "备注",
+  "device-log798283-17": "无",
+  "device-log798283-18": "设备升级",
+  "device-log798283-19": "设备上线",
+  "device-log798283-20": "设备离线",
+  "device-log798283-21": "元素",
+  "device-monitor817489-0": "监测间隔",
+  "device-monitor817489-1": "取值范围500-10000毫秒",
+  "device-monitor817489-2": "请输入监测间隔",
+  "device-monitor817489-3": "监测次数",
+  "device-monitor817489-4": "取值方位1-300",
+  "device-monitor817489-5": "请输入监测次数",
+  "device-monitor817489-6": "开始监测",
+  "device-monitor817489-7": "停止监测",
+  "device-monitor817489-8": "正在接收设备数据,请耐心等待......",
+  "device-monitor817489-9": "接收到【设备状态】主题:",
+  "device-monitor817489-10": "接收到【设备状态】内容:",
+  "device-monitor817489-11": "接收到【实时监测】主题:",
+  "device-monitor817489-12": "接收到【实时监测】内容:",
+  "device-monitor817489-13": "设备不在线,下发指令失败",
+  "device-monitor817489-14": "实时监测的间隔范围500-10000毫秒",
+  "device-monitor817489-15": "实时监测数量范围1-300",
+  "device-monitor817489-16": "更新实时监测",
+  "device-monitor817489-17": "关闭实时监测",
+  "device-monitor817489-18": "(单位",
+  "device-monitor817489-19": "无",
+  "device-recycle864193-0": "设备回收",
+  "device-recycle864193-1": "回收机构",
+  "device-recycle864193-2": "请选择回收机构",
+  "device-recycle864193-5": "查询",
+  "device-recycle864193-6": "重置",
+  "device-recycle864193-7": "所有设备",
+  "device-recycle864193-8": "暂无数据",
+  "device-recycle864193-12": "已选设备",
+  "device-recycle864193-13": "确定回收",
+  "device-recycle864193-14": "回收机构不能为空",
+  "device-select-allot.903153-0": "分配设备",
+  "device-select-allot.903153-4": "查询",
+  "device-select-allot.903153-5": "重置",
+  "device-select-allot.903153-6": "所有设备",
+  "device-select-allot.903153-7": "暂无数据",
+  "device-select-allot.903153-11": "已选设备",
+  "device-select-allot.903153-14": "确定分配",
+  "device-statistic932674-0": "请选择设备从机:",
+  "device-statistic932674-1": "请选择设备从机",
+  "device-statistic932674-2": "时间范围",
+  "device-statistic932674-3": "开始日期",
+  "device-statistic932674-4": "结束日期",
+  "device-statistic932674-5": "查询",
+  "device-statistic932674-6": "统计 (单位",
+  "device-statistic932674-7": "无",
+  "device-sub299018-2": "设备状态",
+  "device-sub299018-3": "请选择设备状态",
+  "device-sub299018-4": "搜索",
+  "device-sub299018-5": "重置",
+  "device-sub299018-7": "网关编码",
+  "device-sub299018-8": "从机地址",
+  "device-sub299018-10": "激活时间",
+  "device-sub299018-11": "创建时间",
+  "device-sub299018-13": "修改",
+  "device-sub299018-14": "设备名",
+  "device-sub299018-15": "请输入设备名",
+  "device-sub299018-19": "设备名不能为空",
+  "device-sub299018-20": "固件版本不能为空",
+  "device-sub299018-21": "添加设备",
+  "device-sub299018-22": "修改设备",
+  "device-sub299018-23": "修改成功",
+  "device-sub299018-24": "新增成功",
+  "device-sub299018-25": "是否确认删除设备编号为{0}的数据项?",
+  "device-sub299018-27": "删除成功",
+  "device-sub299018-28": "绑定的子设备默认子设备地址继承产品",
+  "device-user037521-0": "刷新",
+  "device-user037521-1": "用户编号",
+  "device-user037521-2": "用户名称",
+  "device-user037521-3": "手机号码",
+  "device-user037521-4": "用户类型",
+  "device-user037521-5": "拥有者",
+  "device-user037521-6": "分享",
+  "device-user037521-7": "分享时间",
+  "device-user037521-8": "备注",
+  "device-user037521-10": "查看",
+  "device-user037521-11": "取消分享",
+  "device-user037521-12": "设备分享",
+  "device-user037521-13": "请输入用户手机号码",
+  "device-user037521-14": "查询用户",
+  "device-user037521-15": "用户信息",
+  "device-user037521-16": "用户ID:",
+  "device-user037521-17": "手机号码:",
+  "device-user037521-18": "用户名称:",
+  "device-user037521-19": "设置用户权限",
+  "device-user037521-20": "权限名称",
+  "device-user037521-21": "权限标识",
+  "device-user037521-24": "修改",
+  "device-user037521-25": "关 闭",
+  "device-user037521-26": "手机号码不能为空",
+  "device-user037521-27": "手机号码长度为11位",
+  "device-user037521-28": "确认取消分享设备?",
+  "device-user037521-29": "取消分享成功",
+  "device-user037521-30": "查询不到设备信息,请刷新后重试",
+  "device-user037521-31": "查询不到用户信息,或者该用户已经是设备用户",
+  "device-user037521-32": "设备升级",
+  "device-user037521-33": "设备OTA升级",
+  "device-user037521-34": "设备定时",
+  "device-user037521-35": "定时执行任务",
+  "device-user037521-36": "设备日志",
+  "device-user037521-37": "包含事件日志和指令日志",
+  "device-user037521-38": "实时监测",
+  "device-user037521-39": "下发实时监测指令后,图表实时显示设备上报数据",
+  "device-user037521-40": "监测统计",
+  "device-user037521-41": "图表显示存储的历史监测数据",
+  "device-user037521-42": "更新成功",
+  "device-user037521-43": "新增成功",
+  "device-timer433369-0": "定时名称",
+  "device-timer433369-1": "请输入定时名称",
+  "device-timer433369-2": "定时状态",
+  "device-timer433369-3": "请选择定时状态",
+  "device-timer433369-4": "搜索",
+  "device-timer433369-5": "重置",
+  "device-timer433369-6": "新增",
+  "device-timer433369-7": "名称",
+  "device-timer433369-8": "描述",
+  "device-timer433369-9": "CRON表达式",
+  "device-timer433369-10": "动作",
+  "device-timer433369-11": "状态",
+  "device-timer433369-12": "启用",
+  "device-timer433369-14": "查看",
+  "device-timer433369-15": "定时详细",
+  "device-timer433369-16": "删除",
+  "device-timer433369-17": "执行一次",
+  "device-timer433369-18": "执行时间",
+  "device-timer433369-19": "选择时间",
+  "device-timer433369-20": "选择星期",
+  "device-timer433369-21": "请选择",
+  "device-timer433369-22": "cron表达式",
+  "device-timer433369-23": "cron执行表达式",
+  "device-timer433369-24": "生成表达式",
+  "device-timer433369-25": "自定义表达式",
+  "device-timer433369-26": "执行动作",
+  "device-timer433369-27": "请选择类型",
+  "device-timer433369-28": "请选择父级物模型",
+  "device-timer433369-29": "值",
+  "device-timer433369-30": "请输入字符串",
+  "device-timer433369-31": "添加执行动作",
+  "device-timer433369-32": "新 增",
+  "device-timer433369-33": "修 改",
+  "device-timer433369-35": "Cron表达式生成器",
+  "device-timer433369-36": "定时编号:",
+  "device-timer433369-37": "定时名称:",
+  "device-timer433369-38": "定时分组:",
+  "device-timer433369-39": "创建时间:",
+  "device-timer433369-40": "是否并发:",
+  "device-timer433369-41": "允许",
+  "device-timer433369-42": "禁止",
+  "device-timer433369-43": "cron表达式:",
+  "device-timer433369-44": "执行策略:",
+  "device-timer433369-45": "默认策略",
+  "device-timer433369-46": "立即执行",
+  "device-timer433369-47": "放弃执行",
+  "device-timer433369-48": "下次执行时间:",
+  "device-timer433369-49": "定时状态:",
+  "device-timer433369-50": "正常",
+  "device-timer433369-51": "暂停",
+  "device-timer433369-52": "执行动作:",
+  "device-timer433369-53": "关 闭",
+  "device-timer433369-54": "周一",
+  "device-timer433369-55": "周二",
+  "device-timer433369-56": "周三",
+  "device-timer433369-57": "周四",
+  "device-timer433369-58": "周五",
+  "device-timer433369-59": "周六",
+  "device-timer433369-60": "周日",
+  "device-timer433369-61": "属性",
+  "device-timer433369-62": "功能",
+  "device-timer433369-63": "定时名称不能为空",
+  "device-timer433369-64": "停用",
+  "device-timer433369-65": "确认要{0}定时吗?",
+  "device-timer433369-67": "成功",
+  "device-timer433369-68": "确认要立即执行一次{0}",
+  "device-timer433369-69": "执行成功",
+  "device-timer433369-70": "添加定时",
+  "device-timer433369-71": "修改定时",
+  "device-timer433369-72": "无单位",
+  "device-timer433369-73": "是否确认删除定时定时编号为{0}的数据项?",
+  "device-timer433369-75": "删除成功",
+  "device-timer433369-76": "时间",
+  "device-timer433369-77": "每天",
+  "device-timer433369-78": "周一、",
+  "device-timer433369-79": "周二、",
+  "device-timer433369-80": "周三、",
+  "device-timer433369-81": "周四、",
+  "device-timer433369-82": "周五、",
+  "device-timer433369-83": "周六、",
+  "device-timer433369-84": "周日、",
+  "device-timer433369-85": "自定义Cron表达式",
+  "device-timer433369-86": "无",
+  "device-timer433369-87": "执行时间不能空",
+  "device-timer433369-88": "请选择要执行的星期",
+  "device-timer433369-89": "cron表达式不能为空",
+  "device-timer433369-90": "执行动作中的选项和值不能为空",
+  "device-timer433369-91": "修改成功",
+  "device-timer433369-92": "新增成功",
+  "import-record086254-0": "设备导入记录",
+  "import-record086254-2": "批次任务状态",
+  "import-record086254-3": "开始日期",
+  "import-record086254-4": "结束日期",
+  "import-record086254-5": "搜索",
+  "import-record086254-6": "重置",
+  "import-record086254-7": "批次号",
+  "import-record086254-8": "设备总数",
+  "import-record086254-9": "成功数量",
+  "import-record086254-10": "失败数量",
+  "import-record086254-11": "任务状态",
+  "import-record086254-12": "完成时间",
+  "import-record086254-13": "产品名称",
+  "device-modbus.433390-1": "新增轮询任务",
+  "index.105953-0": "设备名称",
+  "index.105953-1": "请输入设备名称",
+  "index.105953-2": "设备编号",
+  "index.105953-3": "请输入设备编号",
+  "index.105953-4": "设备状态",
+  "index.105953-5": "请选择设备状态",
+  "index.105953-6": "我的分组",
+  "index.105953-7": "请选择我的分组",
+  "index.105953-8": "搜索",
+  "index.105953-9": "重置",
+  "index.105953-10": "新增设备",
+  "index.105953-11": "手动添加",
+  "index.105953-12": "批量导入",
+  "index.105953-13": "分配设备",
+  "index.105953-14": "选择分配",
+  "index.105953-15": "导入分配",
+  "index.105953-16": "回收设备",
+  "index.105953-17": "切换展示",
+  "index.105953-18": "显示下级机构数据",
+  "index.105953-19": "选中后,本级可以看下级的数据",
+  "index.105953-20": "编号",
+  "index.105953-21": "产品",
+  "index.105953-22": "协议",
+  "index.105953-23": "通讯协议",
+  "index.105953-24": "子设备数",
+  "index.105953-26": "启用",
+  "index.105953-27": "禁用",
+  "index.105953-28": "状态",
+  "index.105953-29": "信号",
+  "index.105953-32": "激活时间",
+  "index.105953-33": "创建时间",
+  "index.105953-35": "删除",
+  "index.105953-36": "查看",
+  "index.105953-37": "二维码",
+  "index.105953-38": "分享的设备",
+  "index.105953-39": "产品",
+  "index.105953-40": "运行状态",
+  "index.105953-41": "暂无数据,请添加设备",
+  "index.105953-42": "设备二维码",
+  "index.105953-43": "接收到【设备状态】主题:",
+  "index.105953-44": "接收到【设备状态】内容:",
+  "index.105953-45": "是否确认删除设备编号为{0}的数据项?",
+  "index.105953-47": "删除成功",
+  "index.105953-48": "更多操作",
+  "index.105953-49": "导入记录",
+  "index.105953-50": "生成设备编号",
+  "index.105953-51": "设备回收记录",
+  "index.105953-52": "设备分配记录",
+  "index.105953-53": "告警:",
+  "index.105953-54": "生成设备编号",
+  "index.105953-55": "生成数量",
+  "index.105953-56": "确 定",
+  "index.105953-57": "关 闭",
+  "index.105953-58": "暂无组态,请先配置模板组态!",
+  "product-list.058448-0": "选择产品",
+  "product-list.058448-2": "请输入产品名称",
+  "product-list.058448-3": "搜索",
+  "product-list.058448-4": "重置",
+  "product-list.058448-6": "分类名称",
+  "product-list.058448-7": "租户名称",
+  "product-list.058448-8": "授权码",
+  "product-list.058448-9": "启用",
+  "product-list.058448-10": "未启用",
+  "product-list.058448-11": "认证方式",
+  "product-list.058448-12": "联网方式",
+  "product-list.058448-13": "创建时间",
+  "product-list.058448-14": "确定",
+  "product-list.058448-15": "关 闭",
+  "realTime-status099127-0": "从机实时状态",
+  "realTime-status099127-1": "属性上报",
+  "realTime-status099127-2": "时间:",
+  "realTime-status099127-3": "服务下发",
+  "realTime-status099127-4": "发送",
+  "realTime-status099127-5": "设 备 指 令",
+  "realTime-status099127-6": "服务下发:",
+  "realTime-status099127-7": "设备应答:",
+  "realTime-status099127-8": "暂无数据",
+  "realTime-status099127-9": "请选择设备从机",
+  "realTime-status099127-10": "网关实时状态",
+  "realTime-status099127-11": "设备模式",
+  "realTime-status099127-12": "请选择",
+  "realTime-status099127-13": "请输入字符串",
+  "realTime-status099127-14": "请输入字符串,单位:{0}",
+  "realTime-status099127-15": "指令发送",
+  "realTime-status099127-16": "设备离线时状态",
+  "realTime-status099127-17": "请输入小数",
+  "realTime-status099127-18": "请输入整数",
+  "realTime-status099127-19": "服务调用",
+  "realTime-status099127-20": "数据范围:",
+  "realTime-status099127-21": "取消",
+  "realTime-status099127-22": "确认",
+  "realTime-status099127-23": "在线模式",
+  "realTime-status099127-24": "影子模式",
+  "realTime-status099127-25": "离线模式",
+  "realTime-status099127-26": "下发指令",
+  "realTime-status099127-27": "服务调用成功!",
+  "realTime-status099127-28": "接收到【设备状态-运行】主题:",
+  "realTime-status099127-29": "接收到【设备状态-运行】内容:",
+  "realTime-status099127-30": "接收到【物模型】主题1:",
+  "realTime-status099127-31": "接收到【物模型】内容:",
+  "recycle-record.845969-0": "设备回收记录",
+  "recycle-record.845969-1": "机构名称",
+  "recycle-record.845969-4": "搜索",
+  "recycle-record.845969-5": "重置",
+  "recycle-record.845969-6": "被回收机构名称",
+  "recycle-record.845969-8": "回收时间",
+  "user-list.041943-0": "选择用户",
+  "user-list.041943-1": "手机号码",
+  "user-list.041943-2": "请输入用户手机号码",
+  "user-list.041943-3": "查询",
+  "user-list.041943-5": "用户编号",
+  "user-list.041943-6": "用户名称",
+  "user-list.041943-7": "用户昵称",
+  "user-list.041943-8": "创建时间",
+  "user-list.041943-9": "分享",
+  "user-list.041943-10": "关 闭",
+  "user-list.041943-11": "手机号码不能为空",
+  "user-list.041943-12": "手机号码长度为11位",
+  "user-list.041943-13": "新增成功",
+  "running-status866086-0": "设备模式",
+  "running-status866086-1": "OTA升级",
+  "running-status866086-2": "检查更新",
+  "running-status866086-3": "请选择",
+  "running-status866086-4": "请输入字符串",
+  "running-status866086-5": "请输入字符串,单位:{0}",
+  "running-status866086-6": "指令发送",
+  "running-status866086-7": "请输入小数",
+  "running-status866086-8": "请输入整数",
+  "running-status866086-9": "设备离线时状态",
+  "running-status866086-10": "设备固件升级",
+  "running-status866086-11": "已经是最新版本,不需要升级",
+  "running-status866086-12": "可以升级到以下版本",
+  "running-status866086-13": "固件名称",
+  "running-status866086-16": "下载地址",
+  "running-status866086-17": "固件描述",
+  "running-status866086-18": "升 级",
+  "running-status866086-20": "设备控制",
+  "running-status866086-21": "接收到【设备状态-运行】主题:",
+  "running-status866086-22": "接收到【设备状态-运行】内容:",
+  "running-status866086-23": "接收到【物模型】主题1:",
+  "running-status866086-24": "接收到【物模型】内容:",
+  "running-status866086-25": "服务调用成功!",
+  "running-status866086-26": "在线模式",
+  "running-status866086-27": "影子模式",
+  "running-status866086-28": "离线模式",
+  "running-status866086-29": "元素个数不匹配,数组元素个数为",
+  "running-status866086-30": "个,以英文逗号分隔。",
+  "running-status866086-31": "设备升级",
+  "sub.083943-0": "添加子设备",
+  "sub.083943-1": "移除子设备",
+  "sub.083943-2": "设置子设备地址",
+  "sub.083943-3": "子设备地址",
+  "sub.083943-4": "是否确认删除设备编号为{0]的数据项?",
+  "sub.083943-5": "保存成功",
+  "sub-device-list323213-0": "选择设备",
+  "sub-device-list323213-1": "请输入子设备编号",
+  "sub-device-list323213-2": "名称",
+  "sub-device-list323213-3": "请输入子设备名称",
+  "sub-device-list323213-4": "添加子设备成功",
+  "scada.789543-0": "暂无组态",
+  "variable-case347856-0": "变量类型",
+  "variable-case347856-1": "请选择变量",
+  "variable-case347856-2": "变量名称",
+  "variable-case347856-3": "请输入变量名称",
+  "variable-case347856-4": "搜素",
+  "variable-case347856-5": "重置",
+  "variable-case347856-6": "变量ID",
+  "variable-case347856-7": "变量类型",
+  "variable-case347856-8": "变量名称",
+  "variable-case347856-9": "更新时间",
+  "variable-case347856-10": "当前值",
+  "variable-case347856-11": "操作",
+  "variable-case347856-12": "历史查询",
+  "variable-case347856-13": "主动采集",
+  "variable-case347856-14": "下发指令主动采集变量,是否继续?",
+  "variable-case347856-15": "提示",
+  "variable-case347856-16": "采集所有",
+  "inline-video986754-0": "暂无视频",
+  "iot.group.index.637432-0": "分组名称",
+  "iot.group.index.637432-1": "请输入分组名称",
+  "iot.group.index.637432-2": "我的分组",
+  "iot.group.index.637432-3": "搜索",
+  "iot.group.index.637432-4": "重置",
+  "iot.group.index.637432-5": "新增",
+  "iot.group.index.637432-6": "分组排序",
+  "iot.group.index.637432-7": "创建时间",
+  "iot.group.index.637432-8": "所属用户",
+  "iot.group.index.637432-9": "备注",
+  "iot.group.index.637432-10": "操作",
+  "iot.group.index.637432-11": "查看设备",
+  "iot.group.index.637432-12": "添加设备",
+  "iot.group.index.637432-13": "查看",
+  "iot.group.index.637432-14": "删除",
+  "iot.group.index.637432-15": "请输入分组排序",
+  "iot.group.index.637432-16": "请输入内容",
+  "iot.group.index.637432-17": "修 改",
+  "iot.group.index.637432-18": "新 增",
+  "iot.group.index.637432-19": "取 消",
+  "iot.group.index.637432-20": "分组名称不能为空",
+  "iot.group.index.637432-21": "分组排序不能为空,最大值为99",
+  "iot.group.index.637432-22": "添加设备分组",
+  "iot.group.index.637432-23": "修改设备分组",
+  "iot.group.index.637432-24": "修改成功",
+  "iot.group.index.637432-25": "新增成功",
+  "iot.group.index.637432-26": "是否确认删除设备分组编号为{0}的数据项?",
+  "iot.group.index.637432-27": "删除成功",
+  "iot.group.device-list.849593-0": "选择设备",
+  "iot.group.device-list.849593-1": "设备名称",
+  "iot.group.device-list.849593-2": "请输入设备名称",
+  "iot.group.device-list.849593-3": "搜索",
+  "iot.group.device-list.849593-4": "设备名称",
+  "iot.group.device-list.849593-5": "设备编号",
+  "iot.group.device-list.849593-6": "产品名称",
+  "iot.group.device-list.849593-7": "设备类型",
+  "iot.group.device-list.849593-8": "分享",
+  "iot.group.device-list.849593-9": "拥有",
+  "iot.group.device-list.849593-10": "设备状态",
+  "iot.group.device-list.849593-11": "确 定",
+  "iot.group.device-list.849593-12": "取 消",
+  "iot.group.device-list.849593-13": "更新分组下的设备成功",
+  "instruction-parsing830424-0": "下发设备号:",
+  "instruction-parsing830424-1": "手动下发",
+  "instruction-parsing830424-2": "设备返回",
+  "instruction-parsing830424-3": "设备上报",
+  "instruction-parsing830424-4": "解析数据",
+  "instruction-parsing830424-5": "已解析",
+  "instruction-parsing830424-6": "物模型名称:",
+  "instruction-parsing830424-7": "标识符:",
+  "instruction-parsing830424-8": "数据值:",
+  "instruction-parsing830424-9": "更多解析",
+  "instruction-parsing830424-10": "请输入内容",
+  "instruction-parsing830424-11": "请选择",
+  "instruction-parsing830424-12": "下发",
+  "instruction-parsing830424-13": "上报",
+  "instruction-parsing830424-14": "发送",
+  "instruction-parsing830424-15": "常用快捷指令",
+  "instruction-parsing830424-16": "指令生成",
+  "instruction-parsing830424-17": "添加至常用快捷键",
+  "instruction-parsing830424-18": "生成指令数据",
+  "instruction-parsing830424-19": "从机地址",
+  "instruction-parsing830424-20": "指令类型",
+  "instruction-parsing830424-21": "功能码",
+  "instruction-parsing830424-22": "起始寄存器地址",
+  "instruction-parsing830424-23": "寄存器值",
+  "instruction-parsing830424-24": "寄存器值",
+  "instruction-parsing830424-25": "线圈状态值",
+  "instruction-parsing830424-26": "点击生成预览",
+  "instruction-parsing830424-27": "添加至常用",
+  "instruction-parsing830424-28": "复制数据",
+  "instruction-parsing830424-29": "指令名称",
+  "instruction-parsing830424-30": "请输入",
+  "instruction-parsing830424-31": "指令数据",
+  "instruction-parsing830424-32": "取消",
+  "instruction-parsing830424-33": "确定",
+  "instruction-parsing830424-34": "删除常用快捷键",
+  "instruction-parsing830424-35": "确认删除",
+  "instruction-parsing830424-36": "吗?",
+  "instruction-parsing830424-37": "取消",
+  "instruction-parsing830424-38": "确定",
+  "instruction-parsing830424-39": "更多解析",
+  "instruction-parsing830424-40": "序号",
+  "instruction-parsing830424-41": "物模型名称",
+  "instruction-parsing830424-42": "标识符",
+  "instruction-parsing830424-43": "数据值",
+  "instruction-parsing830424-44": "线圈个数",
+  "instruction-parsing830424-45": "寄存器个数",
+  "instruction-parsing830424-46": "线圈值",
+  "instruction-parsing830424-47": "寄存器值",
+  "instruction-parsing830424-48": "01 读取线圈状态",
+  "instruction-parsing830424-49": "02 读取输入状态",
+  "instruction-parsing830424-50": "03 读取保存寄存器",
+  "instruction-parsing830424-51": "04 读取输入寄存器",
+  "instruction-parsing830424-52": "05 写入单个线圈寄存器",
+  "instruction-parsing830424-53": "06 写入单个保存寄存器",
+  "instruction-parsing830424-54": "15 写入多个线圈状态",
+  "instruction-parsing830424-55": "16 写入多个保存寄存器",
+  "instruction-parsing830424-56": "下发",
+  "instruction-parsing830424-57": "上报",
+  "instruction-parsing830424-58": "编辑",
+  "instruction-parsing830424-59": "新增",
+  "instruction-parsing830424-60": "快捷指令成功",
+  "instruction-parsing830424-61": "快捷指令失败",
+  "instruction-parsing830424-62": "编码失败",
+  "instruction-parsing830424-63": "指令不能为空",
+  "instruction-parsing830424-64": "发送失败",
+  "instruction-parsing830424-65": "解析为空",
+  "instruction-parsing830424-66": "编码失败",
+  "instruction-parsing830424-67": "编辑",
+  "instruction-parsing830424-68": "删除",
+  "instruction-parsing830424-69": "删除指令成功",
+  "instruction-parsing830424-70": "删除指令失败",
+  "device-modbus-task384302-0": "定时名称",
+  "device-modbus-task384302-1": "请输入定时名称",
+  "device-modbus-task384302-2": "定时状态",
+  "device-modbus-task384302-3": "请选择定时状态",
+  "device-modbus-task384302-4": "搜索",
+  "device-modbus-task384302-5": "重置",
+  "device-modbus-task384302-6": "新增",
+  "device-modbus-task384302-7": "名称",
+  "device-modbus-task384302-8": "描述",
+  "device-modbus-task384302-9": "CRON表达式",
+  "device-modbus-task384302-10": "动作",
+  "device-modbus-task384302-11": "删除",
+  "device-modbus-task384302-12": "添加至常用快捷键",
+  "device-modbus-task384302-13": "生成指令数据",
+  "device-modbus-task384302-14": "从机地址",
+  "device-modbus-task384302-15": "功能码",
+  "device-modbus-task384302-16": "起始寄存器地址",
+  "device-modbus-task384302-17": "寄存器值",
+  "device-modbus-task384302-18": "线圈状态值",
+  "device-modbus-task384302-19": "时间周期",
+  "device-modbus-task384302-20": "周期循环",
+  "device-modbus-task384302-21": "适用周期规则的场景,自然日固定周期循环轮询一次。",
+  "device-modbus-task384302-22": "例如:每天07点轮询一次(取值时间范围:今日07点-昨日07点)",
+  "device-modbus-task384302-23": "每",
+  "device-modbus-task384302-24": "轮询一次",
+  "device-modbus-task384302-25": "点击生成预览",
+  "device-modbus-task384302-26": "复制数据",
+  "device-modbus-task384302-27": "取消",
+  "device-modbus-task384302-28": "确定",
+  "device-modbus-task384302-29": "线圈个数",
+  "device-modbus-task384302-30": "寄存器个数",
+  "device-modbus-task384302-31": "线圈值",
+  "device-modbus-task384302-32": "寄存器值",
+  "device-modbus-task384302-33": "01 读取线圈状态",
+  "device-modbus-task384302-34": "02 读取输入状态",
+  "device-modbus-task384302-35": "03 读取保存寄存器",
+  "device-modbus-task384302-36": "04 读取输入寄存器",
+  "device-modbus-task384302-37": "05 写入单个线圈寄存器",
+  "device-modbus-task384302-38": "06 写入单个保存寄存器",
+  "device-modbus-task384302-39": "15 写入多个线圈状态",
+  "device-modbus-task384302-40": "16 写入多个保存寄存器",
+  "device-modbus-task384302-41": "编码失败",
+  "device-modbus-task384302-42": "启用",
+  "device-modbus-task384302-43": "停用",
+  "device-modbus-task384302-44": "确认要{0}定时吗?",
+  "device-modbus-task384302-45": "成功",
+  "device-modbus-task384302-46": "时间",
+  "device-modbus-task384302-47": "每天",
+  "device-modbus-task384302-48": "周一、",
+  "device-modbus-task384302-49": "周二、",
+  "device-modbus-task384302-50": "周三、",
+  "device-modbus-task384302-51": "周四、",
+  "device-modbus-task384302-52": "周五、",
+  "device-modbus-task384302-53": "周六、",
+  "device-modbus-task384302-54": "周日、",
+  "device-modbus-task384302-55": "自定义Cron表达式",
+  "device-modbus-task384302-56": "任务id",
+  "device-modbus-task384302-57": "指令",
+  "device-modbus-task384302-58": "状态",
+  "device-modbus-task384302-59": "定时时间",
+  "device-modbus-task384302-60": "操作",
+  "device-modbus-task384302-61": "删除",
+  "device-modbus-task384302-62": "修改成功",
+  "device-modbus-task384302-63": "新增成功",
+  "device-modbus-task384302-64": "是否确认删除轮训任务列编号为{0}的数据项?",
+  "device-modbus-task384302-65": "删除成功",
+  "order.index.045965-1": "添加指令权限控制",
+  "order.index.045965-2": "修改指令权限控制",
+  "order.index.045965-3": "是否确认删除指令权限控制编号为{0}的数据项?",
+  "order.index.045965-4": "指令",
+  "order.index.045965-5": "设备",
+  "order.index.045965-6": "用户",
+  "order.index.045965-7": "可操作次数",
+  "order.index.045965-8": "开始时间",
+  "order.index.045965-9": "结束时间",
+  "order.index.045965-10": "选择设备",
+  "order.index.045965-11": "选择用户",
+  "order.index.045965-12": "指令配置",
+  "order.index.045965-13": "全选",
+  "order.index.045965-14": "操作次数",
+  "order.index.045965-15": "开始时间",
+  "order.index.045965-16": "请选择开始时间",
+  "order.index.045965-17": "结束时间",
+  "order.index.045965-18": "请选择结束时间",
+  "order.index.045965-19": "选择文件",
+  "order.index.045965-20": "图片",
+  "order.index.045965-21": "备注",
+  "order.index.045965-22": "请输入内容",
+  "order.index.045965-23": "确 定",
+  "order.index.045965-24": "取 消",
+  "order.index.045965-25": "请选择设备",
+  "order.index.045965-26": "请选择用户",
+  "order.index.045965-27": "操作次数不能为空",
+  "order.index.045965-28": "请选择开始时间",
+  "order.index.045965-29": "请选择结束时间",
+  "order.index.045965-30": "至少选择一个指令",
+  "device-alert309509-0": "告警名称",
+  "device-alert309509-1": "请输入告警名称",
+  "device-alert309509-2": "告警级别",
+  "device-alert309509-3": "请选择告警级别",
+  "device-alert309509-4": "处理状态",
+  "device-alert309509-5": "请选择处理状态",
+  "device-alert309509-6": "搜索",
+  "device-alert309509-7": "重置",
+  "device-alert309509-8": "告警来源",
+  "device-alert309509-9": "告警时间",
+  "device-alert309509-10": "数据",
+  "device-alert309509-11": "处理状态",
+  "device-alert309509-12": "操作",
+  "device-alert309509-13": "处理",
+  "device-alert309509-14": "处理结果",
+  "device-alert309509-15": "请输入内容",
+  "device-alert309509-16": "确 定",
+  "device-alert309509-17": "取 消",
+  "device-alert309509-18": "处理内容不能为空",
+  "device-alert309509-19": "修改设备告警",
+  "device-alert309509-20": "修改成功",
+  "device-alert309509-21": "新增成功",
+  "device-variable930930-0": "设备未激活",
+  "device-variable930930-1": "设备处于禁用状态",
+  "device-variable930930-2": "设备处于离线状态",
+  "device-variable930930-3": "下发成功",
+  "device-variable930930-4": "请输入数据",
+  "device-variable930930-5": "编辑",
+  "device-variable930930-6": "确定",
+  "device-variable930930-7": "取消",
+  "device-variable930930-8": "请输入数据",
+  "device-variable930930-9": "设备未激活",
+  "device-variable930930-10": "设备处于禁用状态",
+  "device-variable930930-11": "设备处于离线状态",
+  "realTime-status845353-0": "编辑",
+  "realTime-status845353-1": "下发指令",
+  "realTime-status845353-2": "上报时间:",
+  "realTime-status845353-3": "下发指令",
+  "realTime-status845353-4": "取消",
+  "realTime-status845353-5": "确定",
+  "realTime-status845353-6": "下发成功"
+},
 
 
   'OAuth 2.0': 'OAuth 2.0' // 避免菜单名是 OAuth 2.0 时,一直 warn 报错

+ 2 - 1
src/router/modules/remaining.ts

@@ -2102,7 +2102,8 @@ const remainingRouter: AppRouteRecordRaw[] = [
         meta: {
           title: '设备管理',
           hidden: false,
-          icon: 'ep:monitor'
+          icon: 'ep:monitor',
+          noCache: false
         }
       },
       // 新增/编辑 设备

+ 10 - 1
src/utils/dict.ts

@@ -299,5 +299,14 @@ export enum DICT_TYPE {
   PMS_PROJECT_WELL_CONTROL_LEVEL = 'rq_iot_well_control_level',  // 井控级别
   PMS_PROJECT_RD_STATUS = 'rdStatus',                  // 瑞都 施工状态
   PMS_PROJECT_CASING_PIPE_SIZE = 'rq_iot_casing_pipe_size',    // 日报 套生段产管尺寸
-  PMS_PROJECT_RD_TECHNOLOGY = 'rq_iot_project_technology_rd'   // 瑞都施工工艺
+  PMS_PROJECT_RD_TECHNOLOGY = 'rq_iot_project_technology_rd',   // 瑞都施工工艺
+
+  // 视频中心
+
+  VIDEO_CENTER_LOCATION_WAY = 'iot_location_way', // 定位方式
+  VIDEO_CENTER_TRANSPORT_TYPE = 'iot_transport_type', // 传输方式
+  VIDEO_CENTER_VERTIFICATE_METHOD = 'iot_vertificate_method', // 认证方式
+  VIDEO_CENTER_NETWORK_METHOD = 'iot_network_method', // 联网方式
+
+
 }

+ 2 - 2
src/views/pms/video_center/device/batch-import-dialog.vue

@@ -172,10 +172,10 @@ function handleFileSuccess(response, file, fileList) {
 /** 查询产品列表 */
 function getProductList() {
   const params = {
-    pageSize: 999
+    pageSize: 20
   }
   listProduct(params).then((response) => {
-    productList.value = response.rows.map((item) => {
+    productList.value = response.list.map((item) => {
       return { value: item.productId, label: item.productName }
     })
   })

+ 195 - 132
src/views/pms/video_center/device/device-edit.vue

@@ -38,10 +38,7 @@
                     :disabled="form.status !== 1"
                   >
                     <template #append>
-                      <el-button
-                        @click="selectProduct()"
-                        :disabled="form.status !== 1"
-                      >
+                      <el-button @click="selectProduct" :disabled="form.status !== 1">
                         {{ t('device.device-edit148398-6') }}
                       </el-button>
                     </template>
@@ -64,15 +61,13 @@
                         @click="generateNum"
                         :loading="genDisabled"
                         :disabled="form.status !== 1"
-                   
                       >
                         {{ t('device.device-edit148398-9') }}
                       </el-button>
                       <el-button
                         v-if="form.deviceType === 3"
-                        @click="genSipID()"
+                        @click="genSipID"
                         :disabled="form.status !== 1"
-                    
                       >
                         {{ t('device.device-edit148398-9') }}
                       </el-button>
@@ -80,11 +75,7 @@
                   </el-input>
                 </el-form-item>
                 <el-form-item v-if="openServerTip">
-                  <el-alert
-                    type="info"
-                    show-icon
-                    :description="t('device.device-edit148398-10')"
-                  />
+                  <el-alert type="info" show-icon :description="t('device.device-edit148398-10')" />
                 </el-form-item>
                 <el-form-item v-if="openTip">
                   <el-alert
@@ -146,7 +137,7 @@
                     :disabled="form.deviceType === 3"
                   >
                     <el-option
-                      v-for="dict in dict.type.iot_location_way"
+                      v-for="dict in iot_location_way"
                       :key="dict.value"
                       :label="dict.label"
                       :value="Number(dict.value)"
@@ -229,7 +220,7 @@
                   v-if="form.deviceId !== 0"
                 >
                   <dict-tag
-                    :options="dict.type.iot_device_status"
+                    :options="iot_device_status"
                     :value="form.status"
                     style="display: inline-block; margin-right: 8px"
                   />
@@ -261,20 +252,10 @@
 
           <el-form label-width="100px" style="margin-top: 50px">
             <el-form-item style="text-align: center; margin-left: -100px; margin-top: 10px">
-              <el-button
-                type="primary"
-                @click="submitForm"
-                
-                v-show="form.deviceId !== 0"
-              >
+              <el-button type="primary" @click="submitForm" v-show="form.deviceId != 0">
                 {{ t('device.device-edit148398-38') }} {{ t('device.device-edit148398-39') }}
               </el-button>
-              <el-button
-                type="primary"
-                @click="submitForm"
-             
-                v-show="form.deviceId === 0"
-              >
+              <el-button type="primary" @click="submitForm" v-show="form.deviceId == 0">
                 {{ t('device.device-edit148398-40') }} {{ t('device.device-edit148398-41') }}
               </el-button>
             </el-form-item>
@@ -290,7 +271,7 @@
           <sipid ref="sipidGenRef" :product="form" @add-gen-event="getSipIDData" />
         </el-tab-pane>
 
-        <el-tab-pane name="runningStatus" v-if="form.deviceType !== 3">
+        <!-- <el-tab-pane name="runningStatus" v-if="form.deviceType !== 3">
           <template #label>{{ t('device.device-edit148398-42') }}</template>
           <running-status
             ref="runningStatusRef"
@@ -304,7 +285,7 @@
             :device="form"
             @status-event="getDeviceStatusData"
           />
-        </el-tab-pane>
+        </el-tab-pane> -->
 
         <el-tab-pane
           name="sipChannel"
@@ -326,7 +307,7 @@
           <device-live-stream ref="deviceLiveStreamRef" :device="form" />
         </el-tab-pane>
 
-        <el-tab-pane
+        <!-- <el-tab-pane
           name="sipVideo"
           :disabled="form.deviceId === 0"
           v-if="form.deviceType === 3"
@@ -334,14 +315,14 @@
         >
           <template #label>{{ t('device.device-edit148398-46') }}</template>
           <device-video ref="deviceVideoRef" :device="form" />
-        </el-tab-pane>
+        </el-tab-pane> -->
 
-        <el-tab-pane name="ossRecord" :disabled="form.deviceId === 0" v-if="form.deviceType === 3">
+        <!-- <el-tab-pane name="ossRecord" :disabled="form.deviceId === 0" v-if="form.deviceType === 3">
           <template #label>{{ t('device.device-edit148398-79') }}</template>
           <oss-record ref="OssRecordRef" :device="form" />
-        </el-tab-pane>
+        </el-tab-pane> -->
 
-        <el-tab-pane
+        <!-- <el-tab-pane
           name="deviceTimer"
           :disabled="form.deviceId === 0"
           v-if="form.deviceType !== 3"
@@ -349,14 +330,14 @@
         >
           <template #label>{{ t('device.device-edit148398-47') }}</template>
           <device-timer ref="deviceTimerRef" :device="form" />
-        </el-tab-pane>
-
+        </el-tab-pane> -->
+        <!-- 
         <el-tab-pane name="deviceUser" :disabled="form.deviceId === 0" lazy>
           <template #label>{{ t('device.device-edit148398-48') }}</template>
           <device-user ref="deviceUserRef" :device="form" @user-event="getUserData" />
-        </el-tab-pane>
+        </el-tab-pane> -->
 
-        <el-tab-pane
+        <!-- <el-tab-pane
           name="deviceLog"
           :disabled="form.deviceId === 0"
           v-if="form.deviceType !== 3"
@@ -364,19 +345,19 @@
         >
           <template #label>{{ t('device.device-edit148398-49') }}</template>
           <device-log ref="deviceLogRef" :device="form" />
-        </el-tab-pane>
+        </el-tab-pane> -->
 
-        <el-tab-pane name="alertUser" :disabled="form.deviceId === 0" v-if="form.deviceType !== 3">
+        <!-- <el-tab-pane name="alertUser" :disabled="form.deviceId === 0" v-if="form.deviceType !== 3">
           <template #label>{{ t('device.device-edit148398-80') }}</template>
           <alert-user ref="alertUserRef" :device="form" />
-        </el-tab-pane>
-        
-        <el-tab-pane name="deviceAlert" :disabled="form.deviceId === 0">
+        </el-tab-pane> -->
+
+        <!-- <el-tab-pane name="deviceAlert" :disabled="form.deviceId === 0">
           <template #label>{{ t('device.device-edit148398-81') }}</template>
           <device-alert ref="deviceAlertRef" :device="form" />
-        </el-tab-pane>
+        </el-tab-pane> -->
 
-        <el-tab-pane
+        <!-- <el-tab-pane
           name="deviceFuncLog"
           :disabled="form.deviceId === 0"
           v-if="form.deviceType !== 3"
@@ -384,8 +365,8 @@
         >
           <template #label>{{ t('device.device-edit148398-50') }}</template>
           <device-func ref="deviceFuncLogRef" :device="form" />
-        </el-tab-pane>
-
+        </el-tab-pane> -->
+        <!-- 
         <el-tab-pane
           name="deviceMonitor"
           :disabled="form.deviceId === 0"
@@ -393,17 +374,17 @@
         >
           <template #label>{{ t('device.device-edit148398-51') }}</template>
           <device-monitor ref="deviceMonitorRef" :device="form" />
-        </el-tab-pane>
+        </el-tab-pane> -->
 
-        <el-tab-pane
+        <!-- <el-tab-pane
           name="deviceStastic"
           :disabled="form.deviceId === 0"
           v-if="form.deviceType !== 3"
         >
           <template #label>{{ t('device.device-edit148398-52') }}</template>
           <device-statistic ref="deviceStatisticRef" :device="form" />
-        </el-tab-pane>
-
+        </el-tab-pane> -->
+        <!-- 
         <el-tab-pane
           name="deviceModbusTask"
           :disabled="form.deviceId === 0"
@@ -411,9 +392,9 @@
         >
           <template #label>{{ t('device.device-edit148398-77') }}</template>
           <device-modbus-task ref="deviceModbusTaskRef" :device="form" />
-        </el-tab-pane>
+        </el-tab-pane> -->
 
-        <el-tab-pane
+        <!-- <el-tab-pane
           name="instructionParsing"
           :disabled="form.deviceId === 0"
           v-if="form.deviceType !== 3"
@@ -421,9 +402,9 @@
         >
           <template #label>{{ t('device.device-edit148398-76') }}</template>
           <instruction-parsing ref="instructionParsingRef" :device="form" />
-        </el-tab-pane>
+        </el-tab-pane> -->
 
-        <el-tab-pane
+        <!-- <el-tab-pane
           name="scada"
           :disabled="form.deviceId === 0"
           v-if="form.deviceType !== 3 && isShowScada === true"
@@ -431,9 +412,9 @@
         >
           <template #label>{{ t('device.device-edit148398-73') }}</template>
           <device-scada ref="deviceScadaRef" :device="form" />
-        </el-tab-pane>
+        </el-tab-pane> -->
 
-        <el-tab-pane
+        <!-- <el-tab-pane
           name="variable"
           :disabled="form.deviceId === 0"
           v-if="form.deviceType !== 3"
@@ -441,9 +422,9 @@
         >
           <template #label>{{ t('device.device-edit148398-74') }}</template>
           <device-variable ref="deviceVariableRef" :device="form" />
-        </el-tab-pane>
+        </el-tab-pane> -->
 
-        <el-tab-pane
+        <!-- <el-tab-pane
           name="inlineVideo"
           :disabled="form.deviceId === 0"
           v-if="form.deviceType === 3"
@@ -451,7 +432,7 @@
         >
           <template #label>{{ t('device.device-edit148398-75') }}</template>
           <device-inline-video ref="deviceInlineVideoRef" :sip-relation-list="form.sipRelationList" />
-        </el-tab-pane>
+        </el-tab-pane> -->
 
         <!-- 用于设置间距 -->
         <el-tab-pane disabled>
@@ -502,7 +483,6 @@
                 margin-top: -10px;
               "
             >
-              
               <Vue3NextQrcode :text="qrText" :size="200" />
               <div style="padding-bottom: 10px">{{ t('device.device-edit148398-56') }}</div>
             </div>
@@ -516,7 +496,7 @@
           </div>
         </template>
       </el-dialog>
-     
+
       <el-dialog v-model="openCode" width="300px" append-to-body>
         <div
           style="
@@ -531,7 +511,7 @@
           <div style="padding-bottom: 10px">{{ t('device.device-edit148398-56') }}</div>
         </div>
       </el-dialog>
-      
+
       <el-dialog
         :title="t('device.device-edit148398-58')"
         v-model="openViewMqtt"
@@ -550,20 +530,10 @@
             <el-input v-model="listQuery.username" disabled style="width: 80%" />
           </el-form-item>
           <el-form-item label="passwd" prop="passwd">
-            <el-input 
-              clearable 
-              v-model="listQuery.passwd" 
-              disabled 
-              style="width: 80%"
-            />
+            <el-input clearable v-model="listQuery.passwd" disabled style="width: 80%" />
           </el-form-item>
           <el-form-item label="port" prop="port">
-            <el-input 
-              clearable 
-              v-model="listQuery.port" 
-              disabled 
-              style="width: 80%"
-            />
+            <el-input clearable v-model="listQuery.port" disabled style="width: 80%" />
           </el-form-item>
           <el-form-item label="发布" prop="port">
             <el-input
@@ -612,34 +582,34 @@
 </template>
 
 <script setup>
-import { ref, reactive, computed, onMounted, onActivated, onUnmounted, nextTick } from 'vue'
+import { ref,unref ,reactive, computed, onMounted, onActivated, onUnmounted, nextTick } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import JsonViewer from 'vue-json-viewer/ssr'
 import productList from './product-list.vue'
-import deviceLog from './device-log.vue'
-import deviceAlert from './device-alert.vue'
-import alertUser from './alert-user.vue'
-import deviceUser from './device-user.vue'
-import runningStatus from './running-status.vue'
-import deviceMonitor from './device-monitor.vue'
-import deviceStatistic from './device-statistic.vue'
-import instructionParsing from './instruction-parsing.vue'
-import deviceModbusTask from './device-modbus-task.vue'
-import deviceTimer from './device-timer.vue'
+// import deviceLog from './device-log.vue'
+// import deviceAlert from './device-alert.vue'
+// import alertUser from './alert-user.vue'
+// import deviceUser from './device-user.vue'
+// import runningStatus from './running-status.vue'
+// import deviceMonitor from './device-monitor.vue'
+// import deviceStatistic from './device-statistic.vue'
+// import instructionParsing from './instruction-parsing.vue'
+// import deviceModbusTask from './device-modbus-task.vue'
+// import deviceTimer from './device-timer.vue'
 import channel from '../sip/channel.vue'
-import deviceVideo from '@/views/components/player/deviceVideo.vue'
-import OssRecord from '@/views/iot/record/record-oss.vue'
-import deviceLiveStream from '@/views/components/player/deviceLiveStream.vue'
+// import deviceVideo from '@/views/components/player/deviceVideo.vue'
+// import OssRecord from '@/views/iot/record/record-oss.vue'
+import deviceLiveStream from '../sip/components/player/deviceLiveStream.vue'
 import sipid from '../sip/sipidGen.vue'
-import deviceScada from './device-scada.vue'
-import deviceVariable from './device-variable.vue'
-import deviceInlineVideo from './device-inline-video.vue'
-import deviceFuncLog from './device-functionlog.vue'
-import realTimeStatus from '@/views/iot/device/realTime-status.vue'
+// import deviceScada from './device-scada.vue'
+// import deviceVariable from './device-variable.vue'
+// import deviceInlineVideo from './device-inline-video.vue'
+// import deviceFuncLog from './device-functionlog.vue'
+// import realTimeStatus from '@/views/iot/device/realTime-status.vue'
 import { Vue3NextQrcode } from 'vue3-next-qrcode'
 import 'vue3-next-qrcode/es/style.css'
-import { loadBMap } from '@/utils/map.js'
+// import { loadBMap } from '@/utils/map.js'
 import {
   addDevice,
   deviceSynchronization,
@@ -650,16 +620,17 @@ import {
   updateDevice,
   updateMqttConnectData
 } from '@/api/pms/video/device'
-import { getDeviceUser } from '@/api/iot/deviceuser'
-import { getUserId } from '@/utils/auth'
-import { cacheJsonThingsModel } from '@/api/iot/model'
-import { clientOut } from '@/api/iot/netty'
-import defaultSettings from '@/settings'
+// import { getDeviceUser } from '@/api/iot/deviceuser'
+// import { getUserId } from '@/utils/auth'
+// import { cacheJsonThingsModel } from '@/api/iot/model'
+// import { clientOut } from '@/api/iot/netty'
+import { useTagsViewStore } from '@/store/modules/tagsView'
+import { getDicts } from '@/api/pms/video/dicts'
+
 
 // i18n
 const { t } = useI18n()
 
-// Router and route
 const route = useRoute()
 const router = useRouter()
 
@@ -724,14 +695,17 @@ const openServerTip = ref(false)
 const serverType = ref(1)
 const isSubDev = ref(false)
 const summary = ref([])
-const baseUrl = import.meta.env.VITE_BASE_URl
+const baseUrl = import.meta.env.VITE_BASE_URL
 const map = ref(null)
 const mk = ref(null)
 const latitude = ref('')
 const longitude = ref('')
-const isShowScada = ref(defaultSettings.isShowScada)
+const isShowScada = ref(false)
 const isMediaDevice = ref(false)
 
+const iot_device_status = ref([])
+const iot_location_way = ref([])
+
 // Computed
 const deviceStatus = computed({
   get() {
@@ -827,10 +801,86 @@ const getPlayerData = (data) => {
   })
 }
 
-const tabChange = (paneName) => {
+const tabChange = (panel) => {
   nextTick(() => {
-    // 实现保持原样,仅语法调整
+    if (form.deviceType == 3 && panel.name != 'deviceReturn') {
+      if (panel.name === 'sipPlayer') {
+        // if (this.$refs.deviceVideo && this.$refs.deviceVideo.destroy) {
+        //   this.$refs.deviceVideo.destroy()
+        // }
+        if (channelId.value) {
+          if (deviceLiveStreamRef.value && deviceLiveStreamRef.value.channelId !== undefined) {
+            deviceLiveStreamRef.value.channelId = channelId.value
+          }
+          deviceLiveStreamRef.value.changeChannel()
+        }
+        if (deviceLiveStreamRef.value.channelId) {
+          deviceLiveStreamRef.value.changeChannel()
+        }
+      } else if (panel.name === 'sipVideo') {
+        if (deviceLiveStreamRef.value && deviceLiveStreamRef.value.destroy) {
+          deviceLiveStreamRef.value.destroy()
+        }
+        // if (
+        //   this.$refs.deviceVideo &&
+        //   this.$refs.deviceVideo.channelId !== undefined &&
+        //   this.$refs.deviceVideo.queryDate
+        // ) {
+        //   this.$refs.deviceVideo.loadDevRecord()
+        // }
+      } else if (panel.name === 'sipChannel') {
+        nextTick(() => {
+          ChannelRef.value.getList()
+        })
+      }
+      //关闭直播流
+      if (
+        panel.name !== 'sipPlayer' &&
+        deviceLiveStreamRef.value &&
+        deviceLiveStreamRef.value.playing
+      ) {
+        deviceLiveStreamRef.value.closeDestroy(false)
+      }
+      //关闭录像流
+      // if (panel.name !== 'sipVideo' && this.$refs.deviceVideo && this.$refs.deviceVideo.playing) {
+      //   this.$refs.deviceVideo.closeDestroy()
+      // }
+    }
   })
+
+  // nextTick(() => {
+  //   // 获取监测统计数据
+  //   if (panel.name === 'deviceStastic') {
+  //     this.$refs.deviceStatistic.getListHistory()
+  //   } else if (panel.name === 'deviceTimer') {
+  //     this.$refs.deviceTimer.getList()
+  //   } else if (panel.name === 'deviceSub') {
+  //     if (this.form.serialNumber) {
+  //       this.$refs.deviceSub.queryParams.gwDeviceId = this.form.deviceId
+  //       this.$refs.deviceSub.gateway.gwDeviceId = this.form.deviceId
+  //       this.$refs.deviceSub.getList()
+  //     }
+  //   }
+  // })
+  // if (form.deviceType !== 3) {
+  //   // 用于关闭视频推流(页面切换时候需要关闭推流)
+  //   if (panel.name !== 'inlineVideo') {
+  //     this.$refs.deviceInlineVideo && this.$refs.deviceInlineVideo.handleClose()
+  //   }
+  //   if (panel.name !== 'scada') {
+  //     const scadaRef = this.$refs.deviceScada || {}
+  //     if (scadaRef && scadaRef.$refs && scadaRef.$refs.deviceScada) {
+  //       const copmRef = scadaRef.$refs.deviceScada
+  //       if (copmRef.$refs && copmRef.$refs.spirit) {
+  //         copmRef.$refs.spirit.forEach((item) => {
+  //           if (item.$vnode.tag.includes('ViewInlineVideo')) {
+  //             item.handleCloseJessibuca()
+  //           }
+  //         })
+  //       }
+  //     }
+  //   }
+  // }
 }
 
 const deviceSynchronizationMethod = () => {
@@ -840,13 +890,6 @@ const deviceSynchronizationMethod = () => {
   })
 }
 
-const getDeviceMethod = (deviceId) => {
-  // 原 getDevice 方法改名避免冲突
-  getDevice(deviceId).then(async (response) => {
-    // 实现保持原样,仅语法调整
-  })
-}
-
 const getCacheThingsModdel = (productId) => {
   // 实现保持原样,仅语法调整
 }
@@ -881,14 +924,12 @@ const loadMap = () => {
 }
 
 const goBack = () => {
-  const obj = {
-    path: '/iotdev/iot/device',
-    query: {
-      t: Date.now(),
-      pageNum: route.query.pageNum
-    }
-  }
-  // $tab.closeOpenPage 需要相应实现
+  // 关闭当前tab页签,打开新页签
+  const { delView } = useTagsViewStore()
+  // 先删除当前页签
+  delView(unref(router.currentRoute))
+  // 跳转到列表页
+  router.push({ name: 'VideoCenterDevice' })
   reset()
 }
 
@@ -920,7 +961,7 @@ const reset = () => {
     clientId: 0
   })
   deviceStatus.value = 0
-  // resetForm 需要相应实现
+  formRef.value.resetFields()
 }
 
 const submitForm = () => {
@@ -946,7 +987,7 @@ const submitForm = () => {
 
   formRef.value.validate((valid) => {
     if (valid) {
-      if (form.deviceId !== 0) {
+      if (form.deviceId !== '0') {
         updateDevice(form).then((response) => {
           if (response.data === 0) {
             ElMessageBox.alert(response.msg, 'Error', {
@@ -957,15 +998,28 @@ const submitForm = () => {
             // form = JSON.parse(JSON.stringify(form))
             loadMap()
             // 是否设备设置为禁用状态,则踢出设备
-            if (form.status === 2) {
-              const params = { clientId: form.serialNumber }
-              clientOut(params).then((res) => {})
-            }
+            // if (form.status === 2) {
+            //   const params = { clientId: form.serialNumber }
+            //   clientOut(params).then((res) => {})
+            // }
           }
         })
       } else {
         addDevice(form).then(async (response) => {
-          // 实现保持原样,仅语法调整
+          // 获取设备状态
+
+          Object.assign(form, response)
+
+          if (form.deviceId == null || form.deviceId === '0') {
+            ElMessage.error(t('device.device-edit148398-69'))
+          } else {
+            if (form.status == 2) {
+              deviceStatus.value = 1
+            }
+
+            ElMessage.success(t('device.device-edit148398-70'))
+            loadMap()
+          }
         })
       }
     }
@@ -1086,7 +1140,7 @@ const generateNum = () => {
   genDisabled.value = true
   const params = { type: serverType.value }
   generatorDeviceNum(params).then((response) => {
-    form.serialNumber = response.data
+    form.serialNumber = response
     genDisabled.value = false
   })
 }
@@ -1120,7 +1174,6 @@ const handleViewMqtt = () => {
   })
 }
 
-// Lifecycle
 onMounted(() => {
   let activeNameParam = route.query.activeName
   if (activeNameParam !== null && activeNameParam !== '') {
@@ -1128,10 +1181,20 @@ onMounted(() => {
   }
   // 获取设备信息
   form.deviceId = route.query && route.query.deviceId
-  if (form.deviceId !== 0) {
-    getDeviceMethod(form.deviceId)
-  }
+
+    if (form.deviceId != 0) {
+       
+      getDevice(form.deviceId).then((response) => { 
+        
+        Object.assign(form, response)
+      })
+    }
+
   isSubDev.value = route.query.isSubDev === 1
+
+  getDicts('iot_location_way').then((response) => {
+    iot_location_way.value = response
+  })
 })
 
 onActivated(() => {
@@ -1146,4 +1209,4 @@ onUnmounted(() => {
   // 取消订阅主题
   mqttUnSubscribe(form)
 })
-</script>
+</script>

+ 407 - 320
src/views/pms/video_center/device/device-log.vue

@@ -1,330 +1,417 @@
 <template>
-    <div class="device-detail-page">
-        <el-card class="main-card" style="padding: 0" body-style="padding-bottom: 0">
-            <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-                <el-form-item :label="$t('device.device-log.798283-0')" prop="logType">
-                    <el-select v-model="queryParams.logType" :placeholder="$t('device.device-log.798283-1')" clearable size="small">
-                        <el-option v-for="dict in dict.type.iot_event_type" :key="dict.value" :label="dict.label" :value="dict.value" />
-                    </el-select>
-                </el-form-item>
-                <el-form-item :label="$t('device.device-log.798283-2')" prop="identity">
-                    <el-input v-model="queryParams.identity" :placeholder="$t('device.device-log.798283-3')" clearable size="small" @keyup.enter.native="handleQuery" />
-                </el-form-item>
-                <el-form-item :label="$t('device.device-log.798283-4')">
-                    <el-date-picker
-                        v-model="daterangeTime"
-                        size="small"
-                        style="width: 240px"
-                        value-format="yyyy-MM-dd"
-                        type="daterange"
-                        range-separator="-"
-                        :start-placeholder="$t('device.device-log.798283-5')"
-                        :end-placeholder="$t('device.device-log.798283-6')"
-                    ></el-date-picker>
-                </el-form-item>
-                <el-form-item>
-                    <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">{{ $t('device.device-log.798283-7') }}</el-button>
-                    <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">{{ $t('device.device-log.798283-8') }}</el-button>
-                </el-form-item>
-            </el-form>
-        </el-card>
-        <el-card class="main-card" body-style="padding-top: 0">
-            <el-table :border="false" v-loading="loading" :data="deviceLogList" size="mini">
-                <el-table-column :label="$t('device.device-log.798283-9')" align="center" prop="logType" width="120">
-                    <template slot-scope="scope">
-                        <dict-tag :options="dict.type.iot_event_type" :value="scope.row.logType" />
-                    </template>
-                </el-table-column>
-                <el-table-column :label="$t('device.device-log.798283-10')" align="center" prop="logType" width="120">
-                    <template slot-scope="scope">
-                        <el-tag type="primary" v-if="scope.row.mode == 1">{{ $t('device.device-log.798283-11') }}</el-tag>
-                        <el-tag type="success" v-else-if="scope.row.mode == 2">{{ $t('device.device-log.798283-12') }}</el-tag>
-                        <el-tag type="info" v-else>{{ $t('device.device-log.798283-13') }}</el-tag>
-                    </template>
-                </el-table-column>
-                <el-table-column :label="$t('device.device-log.798283-14')" align="center" prop="createTime" width="150">
-                    <template slot-scope="scope">
-                        <span>{{ scope.row.createTime }}</span>
-                    </template>
-                </el-table-column>
-                <el-table-column :label="$t('device.device-log.798283-2')" align="center" prop="identity" />
-                <el-table-column :label="$t('device.device-log.798283-15')" align="left" header-align="center" prop="logValue">
-                    <template slot-scope="scope">
-                        <div v-html="formatValueDisplay(scope.row)"></div>
-                    </template>
-                </el-table-column>
+  <div class="device-detail-page">
+    <el-card class="main-card" style="padding: 0" body-style="padding-bottom: 0">
+      <el-form
+        :model="queryParams"
+        ref="queryFormRef"
+        :inline="true"
+        v-show="showSearch"
+        label-width="68px"
+      >
+        <el-form-item :label="t('device.device-log798283-0')" prop="logType">
+          <el-select
+            v-model="queryParams.logType"
+            :placeholder="t('device.device-log798283-1')"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="dict in dict.type.iot_event_type"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item :label="t('device.device-log798283-2')" prop="identity">
+          <el-input
+            v-model="queryParams.identity"
+            :placeholder="t('device.device-log798283-3')"
+            clearable
+            size="small"
+            @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item :label="t('device.device-log798283-4')">
+          <el-date-picker
+            v-model="daterangeTime"
+            size="small"
+            style="width: 240px"
+            value-format="YYYY-MM-DD"
+            type="daterange"
+            range-separator="-"
+            :start-placeholder="t('device.device-log798283-5')"
+            :end-placeholder="t('device.device-log798283-6')"
+          ></el-date-picker>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="Search" size="small" @click="handleQuery">{{
+            t('device.device-log798283-7')
+          }}</el-button>
+          <el-button icon="Refresh" size="small" @click="resetQuery">{{
+            t('device.device-log798283-8')
+          }}</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+    <el-card class="main-card" body-style="padding-top: 0">
+      <el-table :border="false" v-loading="loading" :data="deviceLogList" size="small">
+        <el-table-column
+          :label="t('device.device-log798283-9')"
+          align="center"
+          prop="logType"
+          width="120"
+        >
+          <template #default="scope">
+            <dict-tag :options="dict.type.iot_event_type" :value="scope.row.logType" />
+          </template>
+        </el-table-column>
+        <el-table-column
+          :label="t('device.device-log798283-10')"
+          align="center"
+          prop="logType"
+          width="120"
+        >
+          <template #default="scope">
+            <el-tag type="primary" v-if="scope.row.mode == 1">{{
+              t('device.device-log798283-11')
+            }}</el-tag>
+            <el-tag type="success" v-else-if="scope.row.mode == 2">{{
+              t('device.device-log798283-12')
+            }}</el-tag>
+            <el-tag type="info" v-else>{{ t('device.device-log798283-13') }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column
+          :label="t('device.device-log798283-14')"
+          align="center"
+          prop="createTime"
+          width="150"
+        >
+          <template #default="scope">
+            <span>{{ scope.row.createTime }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column :label="t('device.device-log798283-2')" align="center" prop="identity" />
+        <el-table-column
+          :label="t('device.device-log.798283-15')"
+          align="left"
+          header-align="center"
+          prop="logValue"
+        >
+          <template #default="scope">
+            <div v-html="formatValueDisplay(scope.row)"></div>
+          </template>
+        </el-table-column>
 
-                <el-table-column :label="$t('device.device-log.798283-16')" header-align="center" align="left" prop="remark">
-                    <template slot-scope="scope">
-                        {{ scope.row.remark == null ? $t('device.device-log.798283-17') : scope.row.remark }}
-                    </template>
-                </el-table-column>
-            </el-table>
-            <div style="height: 40px">
-                <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
-            </div>
-        </el-card>
-    </div>
+        <el-table-column
+          :label="t('device.device-log.798283-16')"
+          header-align="center"
+          align="left"
+          prop="remark"
+        >
+          <template #default="scope">
+            {{ scope.row.remark == null ? t('device.device-log798283-17') : scope.row.remark }}
+          </template>
+        </el-table-column>
+      </el-table>
+      <div style="height: 40px">
+        <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.pageNum"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList"
+        />
+      </div>
+    </el-card>
+  </div>
 </template>
 
-<script>
-import { listEventLog } from '../../../api/iot/eventLog';
+<script setup>
+import { ref, reactive, watch, onMounted } from 'vue'
+import { listEventLog } from '@/api/iot/eventLog'
 
-export default {
-    name: 'DeviceLog',
-    dicts: ['iot_event_type', 'iot_yes_no'],
-    props: {
-        device: {
-            type: Object,
-            default: null,
-        },
-    },
-    watch: {
-        // 获取到父组件传递的device后,刷新列表
-        device: function (newVal, oldVal) {
-            this.deviceInfo = newVal;
-            if (this.deviceInfo && this.deviceInfo.deviceId != 0) {
-                this.queryParams.serialNumber = this.deviceInfo.serialNumber;
-                this.getList();
-                // 解析缓存物模型
-                this.thingsModel = this.deviceInfo.cacheThingsModel;
+// 定义属性
+const props = defineProps({
+  device: {
+    type: Object,
+    default: null
+  }
+})
+
+// 定义组件名称和字典
+defineOptions({
+  name: 'DeviceLog',
+  dicts: ['iot_event_type', 'iot_yes_no']
+})
+
+// Refs
+const queryFormRef = ref()
+
+// Reactive data
+const thingsModel = reactive({})
+const loading = ref(true)
+const showSearch = ref(true)
+const total = ref(0)
+const deviceLogList = ref([])
+const daterangeTime = ref([])
+
+const queryParams = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  logType: null,
+  logValue: null,
+  deviceId: null,
+  serialNumber: null,
+  deviceName: null,
+  identity: null,
+  isMonitor: null
+})
+
+const deviceInfo = ref({})
+
+// Watch
+watch(
+  () => props.device,
+  (newVal, oldVal) => {
+    deviceInfo.value = newVal
+    if (deviceInfo.value && deviceInfo.value.deviceId != 0) {
+      queryParams.serialNumber = deviceInfo.value.serialNumber
+      getList()
+      // 解析缓存物模型
+      Object.assign(thingsModel, deviceInfo.value.cacheThingsModel)
+    }
+  }
+)
+
+// Methods
+const getList = () => {
+  loading.value = true
+  // 这里需要实现 addDateRange 方法或者使用其他方式处理日期范围
+  const params = { ...queryParams }
+  if (daterangeTime.value && daterangeTime.value.length === 2) {
+    params.beginTime = daterangeTime.value[0]
+    params.endTime = daterangeTime.value[1]
+  }
+
+  listEventLog(params).then((response) => {
+    deviceLogList.value = response.rows
+    total.value = response.total
+    loading.value = false
+  })
+}
+
+const handleQuery = () => {
+  queryParams.pageNum = 1
+  getList()
+}
+
+const resetQuery = () => {
+  queryFormRef.value?.resetFields()
+  daterangeTime.value = []
+  handleQuery()
+}
+
+// 格式化显示数据定义
+const formatValueDisplay = (row) => {
+  // 类型(1=属性上报,2=调用功能,3=事件上报,4=设备升级,5=设备上线,6=设备离线)
+  if (row.logType == 1) {
+    let propertyItem = getThingsModelItem(1, row.identity)
+    if (propertyItem != '') {
+      return (
+        (propertyItem.parentName
+          ? '[' +
+            propertyItem.parentName +
+            (propertyItem.arrayIndex ? propertyItem.arrayIndex : '') +
+            '] '
+          : '') +
+        propertyItem.name +
+        ': <span style="color:#409EFF;">' +
+        getThingsModelItemValue(propertyItem, row.logValue) +
+        ' ' +
+        (propertyItem.datatype.unit != undefined ? propertyItem.datatype.unit : '') +
+        '</span>'
+      )
+    }
+  } else if (row.logType == 2) {
+    let functionItem = getThingsModelItem(2, row.identity)
+    if (functionItem != '') {
+      return (
+        (functionItem.parentName
+          ? '[' +
+            functionItem.parentName +
+            (functionItem.arrayIndex ? functionItem.arrayIndex : '') +
+            '] '
+          : '') +
+        functionItem.name +
+        ': <span style="color:#409EFF">' +
+        getThingsModelItemValue(functionItem, row.logValue) +
+        ' ' +
+        (functionItem.datatype.unit != undefined ? functionItem.datatype.unit : '') +
+        '</span>'
+      )
+    }
+  } else if (row.logType == 3) {
+    let eventItem = getThingsModelItem(3, row.identity)
+    if (eventItem != '') {
+      return (
+        (eventItem.parentName
+          ? '[' + eventItem.parentName + (eventItem.arrayIndex ? eventItem.arrayIndex : '') + '] '
+          : '') +
+        eventItem.name +
+        ': <span style="color:#409EFF">' +
+        getThingsModelItemValue(eventItem, row.logValue) +
+        ' ' +
+        (eventItem.datatype.unit != undefined ? eventItem.datatype.unit : '') +
+        '</span>'
+      )
+    } else {
+      return row.logValue
+    }
+  } else if (row.logType == 4) {
+    return '<span style="font-weight:bold">设备升级</span>'
+  } else if (row.logType == 5) {
+    return '<span style="font-weight:bold">设备上线</span>'
+  } else if (row.logType == 6) {
+    return '<span style="font-weight:bold">设备离线</span>'
+  }
+  return ''
+}
+
+// 获取物模型项中的值
+const getThingsModelItemValue = (item, oldValue) => {
+  // 枚举和布尔转换为文字
+  if (item.datatype.type == 'bool') {
+    if (oldValue == '0') {
+      return item.datatype.falseText
+    } else if (oldValue == '1') {
+      return item.datatype.trueText
+    }
+  } else if (item.datatype.type == 'enum') {
+    for (let i = 0; i < item.datatype.enumList.length; i++) {
+      if (oldValue == item.datatype.enumList[i].value) {
+        return item.datatype.enumList[i].text
+      }
+    }
+  }
+  return oldValue
+}
+
+// 获取物模型中的项
+const getThingsModelItem = (type, identity) => {
+  if (type == 1 && thingsModel.properties) {
+    for (let i = 0; i < thingsModel.properties.length; i++) {
+      //普通类型 integer/decimal/string/emum//bool
+      if (thingsModel.properties[i].id == identity) {
+        return thingsModel.properties[i]
+      }
+      // 对象 object
+      if (thingsModel.properties[i].datatype.type == 'object') {
+        for (let j = 0; j < thingsModel.properties[i].datatype.params.length; j++) {
+          if (thingsModel.properties[i].datatype.params[j].id == identity) {
+            thingsModel.properties[i].datatype.params[j].parentName = thingsModel.properties[i].name
+            return thingsModel.properties[i].datatype.params[j]
+          }
+        }
+      }
+      // 数组 array
+      if (
+        thingsModel.properties[i].datatype.type == 'array' &&
+        thingsModel.properties[i].datatype.arrayType
+      ) {
+        if (thingsModel.properties[i].datatype.arrayType == 'object') {
+          // 数组元素格式:array_01_parentId_humidity,array_01_前缀终端上报时加上,物模型中没有
+          let realIdentity = identity
+          let arrayIndex = 0
+          if (identity.indexOf('array_') > -1) {
+            arrayIndex = identity.substring(6, 8)
+            realIdentity = identity.substring(9)
+          }
+          for (let j = 0; j < thingsModel.properties[i].datatype.params.length; j++) {
+            if (thingsModel.properties[i].datatype.params[j].id == realIdentity) {
+              // 标注索引和父级名称
+              thingsModel.properties[i].datatype.params[j].arrayIndex = Number(arrayIndex) + 1
+              thingsModel.properties[i].datatype.params[j].parentName =
+                thingsModel.properties[i].name
+              return thingsModel.properties[i].datatype.params[j]
             }
-        },
-    },
-    data() {
-        return {
-            // 物模型
-            thingsModel: {},
-            // 遮罩层
-            loading: true,
-            // 显示搜索条件
-            showSearch: true,
-            // 总条数
-            total: 0,
-            // 设备日志表格数据
-            deviceLogList: [],
-            queryParams: {
-                pageNum: 1,
-                pageSize: 10,
-                logType: null,
-                logValue: null,
-                deviceId: null,
-                serialNumber: null,
-                deviceName: null,
-                identity: null,
-                isMonitor: null,
-            },
-            // 时间范围
-            daterangeTime: [],
-        };
-    },
-    created() {
-        this.queryParams.serialNumber = this.device.serialNumber;
-        this.getList();
-    },
-    methods: {
-        /** 查询设备日志列表 */
-        getList() {
-            this.loading = true;
-            listEventLog(this.addDateRange(this.queryParams, this.daterangeTime)).then((response) => {
-                this.deviceLogList = response.rows;
-                this.total = response.total;
-                this.loading = false;
-            });
-        },
-        /** 搜索按钮操作 */
-        handleQuery() {
-            this.queryParams.pageNum = 1;
-            this.getList();
-        },
-        /** 重置按钮操作 */
-        resetQuery() {
-            this.resetForm('queryForm');
-            this.daterangeTime = [];
-            this.handleQuery();
-        },
-        /** 导出按钮操作 */
-        handleExport() {
-            this.download(
-                'iot/event/export',
-                {
-                    ...this.queryParams,
-                },
-                `eventLog_${new Date().getTime()}.xlsx`
-            );
-        },
-        /** 格式化显示数据定义 */
-        formatValueDisplay(row) {
-            // 类型(1=属性上报,2=调用功能,3=事件上报,4=设备升级,5=设备上线,6=设备离线)
-            if (row.logType == 1) {
-                let propertyItem = this.getThingsModelItem(1, row.identity);
-                if (propertyItem != '') {
-                    return (
-                        (propertyItem.parentName ? '[' + propertyItem.parentName + (propertyItem.arrayIndex ? propertyItem.arrayIndex : '') + '] ' : '') +
-                        propertyItem.name +
-                        ': <span style="color:#409EFF;">' +
-                        this.getThingsModelItemValue(propertyItem, row.logValue) +
-                        ' ' +
-                        (propertyItem.datatype.unit != undefined ? propertyItem.datatype.unit : '') +
-                        '</span>'
-                    );
-                }
-            } else if (row.logType == 2) {
-                let functionItem = this.getThingsModelItem(2, row.identity);
-                if (functionItem != '') {
-                    return (
-                        (functionItem.parentName ? '[' + functionItem.parentName + (functionItem.arrayIndex ? functionItem.arrayIndex : '') + '] ' : '') +
-                        functionItem.name +
-                        ': <span style="color:#409EFF">' +
-                        this.getThingsModelItemValue(functionItem, row.logValue) +
-                        ' ' +
-                        (functionItem.datatype.unit != undefined ? functionItem.datatype.unit : '') +
-                        '</span>'
-                    );
-                }
-            } else if (row.logType == 3) {
-                let eventItem = this.getThingsModelItem(3, row.identity);
-                if (eventItem != '') {
-                    return (
-                        (eventItem.parentName ? '[' + eventItem.parentName + (eventItem.arrayIndex ? eventItem.arrayIndex : '') + '] ' : '') +
-                        eventItem.name +
-                        ': <span style="color:#409EFF">' +
-                        this.getThingsModelItemValue(eventItem, row.logValue) +
-                        ' ' +
-                        (eventItem.datatype.unit != undefined ? eventItem.datatype.unit : '') +
-                        '</span>'
-                    );
-                } else {
-                    return row.logValue;
-                }
-            } else if (row.logType == 4) {
-                return '<span style="font-weight:bold">设备升级</span>';
-            } else if (row.logType == 5) {
-                return '<span style="font-weight:bold">设备上线</span>';
-            } else if (row.logType == 6) {
-                return '<span style="font-weight:bold">设备离线</span>';
+          }
+        } else {
+          // 普通类型
+          for (let j = 0; j < thingsModel.properties[i].datatype.arrayCount.length; j++) {
+            if (thingsModel.properties[i].id == realIdentity) {
+              thingsModel.properties[i].arrayIndex = Number(arrayIndex) + 1
+              thingsModel.properties[i].parentName = "t('device.device-log798283-21')"
+              return thingsModel.properties[i]
             }
-            return '';
-        },
-        /** 获取物模型项中的值*/
-        getThingsModelItemValue(item, oldValue) {
-            // 枚举和布尔转换为文字
-            if (item.datatype.type == 'bool') {
-                if (oldValue == '0') {
-                    return item.datatype.falseText;
-                } else if (oldValue == '1') {
-                    return item.datatype.trueText;
-                }
-            } else if (item.datatype.type == 'enum') {
-                for (let i = 0; i < item.datatype.enumList.length; i++) {
-                    if (oldValue == item.datatype.enumList[i].value) {
-                        return item.datatype.enumList[i].text;
-                    }
-                }
+          }
+        }
+      }
+    }
+  } else if (type == 2 && thingsModel.functions) {
+    for (let i = 0; i < thingsModel.functions.length; i++) {
+      //普通类型 integer/decimal/string/emum/bool
+      if (thingsModel.functions[i].id == identity) {
+        return thingsModel.functions[i]
+      }
+      // 对象 object
+      if (thingsModel.functions[i].datatype.type == 'object') {
+        for (let j = 0; j < thingsModel.functions[i].datatype.params.length; j++) {
+          if (thingsModel.functions[i].datatype.params[j].id == identity) {
+            thingsModel.functions[i].datatype.params[j].parentName = thingsModel.functions[i].name
+            return thingsModel.functions[i].datatype.params[j]
+          }
+        }
+      }
+      // 数组 array
+      if (
+        thingsModel.functions[i].datatype.type == 'array' &&
+        thingsModel.functions[i].datatype.arrayType
+      ) {
+        // 数组元素格式:array_01_parentId_humidity,array_01_前缀终端上报时加上,物模型中没有
+        let realIdentity = identity
+        let arrayIndex = 0
+        if (identity.indexOf('array_') > -1) {
+          arrayIndex = identity.substring(6, 8)
+          realIdentity = identity.substring(9)
+        }
+        if (thingsModel.functions[i].datatype.arrayType == 'object') {
+          for (let j = 0; j < thingsModel.functions[i].datatype.params.length; j++) {
+            if (thingsModel.functions[i].datatype.params[j].id == realIdentity) {
+              // 标注索引和父级名称
+              thingsModel.functions[i].datatype.params[j].arrayIndex = Number(arrayIndex) + 1
+              thingsModel.functions[i].datatype.params[j].parentName = thingsModel.functions[i].name
+              return thingsModel.functions[i].datatype.params[j]
             }
-            return oldValue;
-        },
-        /** 获取物模型中的项*/
-        getThingsModelItem(type, identity) {
-            if (type == 1 && this.thingsModel.properties) {
-                for (let i = 0; i < this.thingsModel.properties.length; i++) {
-                    //普通类型 integer/decimal/string/emum//bool
-                    if (this.thingsModel.properties[i].id == identity) {
-                        return this.thingsModel.properties[i];
-                    }
-                    // 对象 object
-                    if (this.thingsModel.properties[i].datatype.type == 'object') {
-                        for (let j = 0; j < this.thingsModel.properties[i].datatype.params.length; j++) {
-                            if (this.thingsModel.properties[i].datatype.params[j].id == identity) {
-                                this.thingsModel.properties[i].datatype.params[j].parentName = this.thingsModel.properties[i].name;
-                                return this.thingsModel.properties[i].datatype.params[j];
-                            }
-                        }
-                    }
-                    // 数组 array
-                    if (this.thingsModel.properties[i].datatype.type == 'array' && this.thingsModel.properties[i].datatype.arrayType) {
-                        if (this.thingsModel.properties[i].datatype.arrayType == 'object') {
-                            // 数组元素格式:array_01_parentId_humidity,array_01_前缀终端上报时加上,物模型中没有
-                            let realIdentity = identity;
-                            let arrayIndex = 0;
-                            if (identity.indexOf('array_') > -1) {
-                                arrayIndex = identity.substring(6, 8);
-                                realIdentity = identity.substring(9);
-                            }
-                            for (let j = 0; j < this.thingsModel.properties[i].datatype.params.length; j++) {
-                                if (this.thingsModel.properties[i].datatype.params[j].id == realIdentity) {
-                                    // 标注索引和父级名称
-                                    this.thingsModel.properties[i].datatype.params[j].arrayIndex = Number(arrayIndex) + 1;
-                                    this.thingsModel.properties[i].datatype.params[j].parentName = this.thingsModel.properties[i].name;
-                                    return this.thingsModel.properties[i].datatype.params[j];
-                                }
-                            }
-                        } else {
-                            // 普通类型
-                            for (let j = 0; j < this.thingsModel.properties[i].datatype.arrayCount.length; j++) {
-                                if (this.thingsModel.properties[i].id == realIdentity) {
-                                    this.thingsModel.properties[i].arrayIndex = Number(arrayIndex) + 1;
-                                    this.thingsModel.properties[i].parentName = this.$t('device.device-log.798283-21');
-                                    return this.thingsModel.properties[i];
-                                }
-                            }
-                        }
-                    }
-                }
-            } else if (type == 2 && this.thingsModel.functions) {
-                for (let i = 0; i < this.thingsModel.functions.length; i++) {
-                    //普通类型 integer/decimal/string/emum/bool
-                    if (this.thingsModel.functions[i].id == identity) {
-                        return this.thingsModel.functions[i];
-                    }
-                    // 对象 object
-                    if (this.thingsModel.functions[i].datatype.type == 'object') {
-                        for (let j = 0; j < this.thingsModel.functions[i].datatype.params.length; j++) {
-                            if (this.thingsModel.functions[i].datatype.params[j].id == identity) {
-                                this.thingsModel.functions[i].datatype.params[j].parentName = this.thingsModel.functions[i].name;
-                                return this.thingsModel.functions[i].datatype.params[j];
-                            }
-                        }
-                    }
-                    // 数组 array
-                    if (this.thingsModel.functions[i].datatype.type == 'array' && this.thingsModel.functions[i].datatype.arrayType) {
-                        // 数组元素格式:array_01_parentId_humidity,array_01_前缀终端上报时加上,物模型中没有
-                        let realIdentity = identity;
-                        let arrayIndex = 0;
-                        if (identity.indexOf('array_') > -1) {
-                            arrayIndex = identity.substring(6, 8);
-                            realIdentity = identity.substring(9);
-                        }
-                        if (this.thingsModel.functions[i].datatype.arrayType == 'object') {
-                            for (let j = 0; j < this.thingsModel.functions[i].datatype.params.length; j++) {
-                                if (this.thingsModel.functions[i].datatype.params[j].id == realIdentity) {
-                                    // 标注索引和父级名称
-                                    this.thingsModel.functions[i].datatype.params[j].arrayIndex = Number(arrayIndex) + 1;
-                                    this.thingsModel.functions[i].datatype.params[j].parentName = this.thingsModel.functions[i].name;
-                                    return this.thingsModel.functions[i].datatype.params[j];
-                                }
-                            }
-                        } else {
-                            // 普通类型
-                            for (let j = 0; j < this.thingsModel.functions[i].datatype.arrayCount.length; j++) {
-                                if (this.thingsModel.functions[i].id == realIdentity) {
-                                    this.thingsModel.functions[i].arrayIndex = Number(arrayIndex) + 1;
-                                    this.thingsModel.functions[i].parentName = this.$t('device.device-log.798283-21');
-                                    return this.thingsModel.functions[i];
-                                }
-                            }
-                        }
-                    }
-                }
-            } else if (type == 3 && this.thingsModel.events) {
-                for (let i = 0; i < this.thingsModel.events.length; i++) {
-                    if (this.thingsModel.events[i].id == identity) {
-                        return this.thingsModel.events[i];
-                    }
-                }
+          }
+        } else {
+          // 普通类型
+          for (let j = 0; j < thingsModel.functions[i].datatype.arrayCount.length; j++) {
+            if (thingsModel.functions[i].id == realIdentity) {
+              thingsModel.functions[i].arrayIndex = Number(arrayIndex) + 1
+              thingsModel.functions[i].parentName = "t('device.device-log798283-21')"
+              return thingsModel.functions[i]
             }
-            return '';
-        },
-    },
-};
+          }
+        }
+      }
+    }
+  } else if (type == 3 && thingsModel.events) {
+    for (let i = 0; i < thingsModel.events.length; i++) {
+      if (thingsModel.events[i].id == identity) {
+        return thingsModel.events[i]
+      }
+    }
+  }
+  return ''
+}
+
+// Lifecycle
+onMounted(() => {
+  if (props.device) {
+    queryParams.serialNumber = props.device.serialNumber
+    getList()
+  }
+})
 </script>

+ 76 - 78
src/views/pms/video_center/device/index.vue

@@ -36,12 +36,14 @@
             size="default"
             style="width: 150px"
           >
-            <el-option
-              v-for="dict in myDict.type.iot_device_status"
-              :key="dict.value"
-              :label="dict.label"
-              :value="dict.value"
-            />
+           
+
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.IOT_DEVICE_STATUS)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
           </el-select>
         </el-form-item>
         <el-form-item>
@@ -83,7 +85,7 @@
             </template>
           </el-dropdown>
 
-          <el-dropdown @command="handleCommand1">
+          <!-- <el-dropdown @command="handleCommand1">
             <el-button size="default" type="primary">
               分配设备
               <el-icon class="el-icon--right"><arrow-down /></el-icon>
@@ -98,11 +100,11 @@
 
           <el-button type="primary" size="default" @click="recycleDevice" style="margin-left: 10px"
             >回收设备</el-button
-          >
+          > -->
         </div>
 
         <div>
-          <el-radio-group class="fr ml10" plain size="default" v-model="showType">
+          <el-radio-group class="float-right ml-10"  plain v-model="showType">
             <el-radio-button label="card"
               ><el-icon><Menu /></el-icon
             ></el-radio-button>
@@ -182,9 +184,9 @@
         <el-table-column label="状态" align="center" prop="status" width="80">
           <template #default="scope">
             <dict-tag
-              :options="dict.type.iot_device_status"
+              :type="DICT_TYPE.IOT_DEVICE_STATUS"
               :value="scope.row.status"
-              size="default"
+             
             />
           </template>
         </el-table-column>
@@ -210,11 +212,8 @@
         </el-table-column>
         <el-table-column label="定位方式" align="center" prop="locationWay" width="100">
           <template #default="scope">
-            <dict-tag
-              :options="myDict.type.iot_location_way"
-              :value="scope.row.locationWay"
-              size="default"
-            />
+          
+             <dict-tag :type="DICT_TYPE.VIDEO_CENTER_LOCATION_WAY" :value="scope.row.locationWay" />
           </template>
         </el-table-column>
         <el-table-column label="固件版本" align="center" prop="firmwareVersion" width="100">
@@ -299,7 +298,7 @@
             </template>
           </el-dropdown>
 
-          <el-dropdown @command="handleCommand1">
+          <!-- <el-dropdown @command="handleCommand1">
             <el-button size="default" type="primary">
               分配设备
               <el-icon class="el-icon--right"><arrow-down /></el-icon>
@@ -310,20 +309,20 @@
                 <el-dropdown-item command="handleImportAllot">导入分配</el-dropdown-item>
               </el-dropdown-menu>
             </template>
-          </el-dropdown>
+          </el-dropdown> -->
 
-          <el-button
+          <!-- <el-button
             size="default"
             type="primary"
            
             @click="recycleDevice"
             style="margin-left: 10px"
             >回收设备</el-button
-          >
+          > -->
         </div>
 
         <div>
-          <el-radio-group class="fr ml10" plain size="default" v-model="showType">
+          <el-radio-group class="float-right ml-10" plain  v-model="showType">
             <el-radio-button label="card"
               ><el-icon><Menu /></el-icon
             ></el-radio-button>
@@ -368,7 +367,7 @@
                   }}</b>
 
                   <dict-tag
-                    :options="myDict.type.iot_device_status"
+                    :options="iot_device_status"
                     :value="item.status"
                     size="default"
                     style="display: inline-block"
@@ -376,7 +375,9 @@
                 </el-link>
               </el-col>
               <el-col :span="1.5" style="font-size: 20px; padding-top: 5px; cursor: pointer">
-                <svg-icon icon-class="qrcode" @click="openSummaryDialog(item)" />
+                
+
+                <el-image style="width: 20px; height: 20px" :src="qrcode" :fit="fit" @click="openSummaryDialog(item)" />
               </el-col>
               <el-col :span="5">
                 <div style="font-size: 28px; color: #ccc">
@@ -528,7 +529,6 @@ import {
 } from '@element-plus/icons-vue'
 import { getCurrentInstance } from 'vue'
 import { listDeviceShort, delDevice } from '@/api/pms/video/device'
-import { listGroup } from '@/api/pms/video/group'
 import { delSipDeviceBySipId } from '@/api/pms/video/sipdevice'
 import Treeselect from '@riophae/vue-treeselect'
 import '@riophae/vue-treeselect/dist/vue-treeselect.css'
@@ -545,6 +545,9 @@ import batchImport from './batch-import-dialog.vue'
 import gatewayImage from '@/assets/imgs/gateway.svg'
 import videoImage from '@/assets/imgs/video.svg'
 import productImage from '@/assets/imgs/product.svg'
+import qrcode from '@/assets/imgs/qrcode.png'
+
+import {DICT_TYPE, getDictLabel, getStrDictOptions } from "@/utils/dict";
 
 const { proxy } = getCurrentInstance()
 // Vue Router 和 Store
@@ -552,20 +555,11 @@ const router = useRouter()
 const route = useRoute()
 const store = useStore()
 
-// 定义字典类型
-defineProps({
-  myDict: {
-    type: Object,
-    default: () => ({
-      type: {
-        iot_device_status: [],
-        iot_is_enable: [],
-        iot_location_way: [],
-        iot_transport_type: []
-      }
-    })
-  }
-})
+
+const iot_device_status = ref([])
+const iot_is_enable = ref([])
+const iot_location_way = ref([])
+const iot_transport_type = ref([])
 
 // Refs
 const queryFormRef = ref()
@@ -625,28 +619,42 @@ const isSubDev = ref(false)
 
 // 生命周期钩子
 onMounted(() => {
-  // 产品筛选
-  let productId = route.query.productId
-  if (productId != null) {
-    queryParams.productId = Number(productId)
-    queryParams.groupId = null
-    queryParams.serialNumber = null
-  }
-  // 分组筛选
-  let groupId = route.query.groupId
-  if (groupId != null) {
-    queryParams.groupId = Number(groupId)
-    queryParams.productId = null
-    queryParams.serialNumber = null
-  }
-  // 设备编号筛选
-  let sn = route.query.sn
-  if (sn != null) {
-    queryParams.serialNumber = sn
-    queryParams.productId = null
-    queryParams.groupId = null
+   const time = route.query.t
+  if (time != null && time != uniqueId.value) {
+    uniqueId.value = time
+    // 页码筛选
+    let pageNum = route.query.pageNum
+    if (pageNum != null) {
+      queryParams.pageNum = Number(pageNum)
+    }
+    // 产品筛选
+    let productId = route.query.productId
+    if (productId != null) {
+      queryParams.productId = Number(productId)
+      queryParams.groupId = null
+      queryParams.serialNumber = null
+    }
+    // 分组筛选
+    let groupId = route.query.groupId
+    if (groupId != null) {
+      queryParams.groupId = Number(groupId)
+      queryParams.productId = null
+      queryParams.serialNumber = null
+    }
+    // 设备编号筛选
+    let sn = route.query.sn
+    if (sn != null) {
+      queryParams.serialNumber = sn
+      queryParams.productId = null
+      queryParams.groupId = null
+    }
+    
   }
-  connectMqtt()
+
+  getList()
+
+  // 以后会用,暂时注释掉
+  // connectMqtt()
 })
 
 onActivated(() => {
@@ -855,32 +863,22 @@ function mqttSubscribe(list) {
 
 /** 查询设备分组列表 */
 const userStore = useUserStoreWithOut()
-function getGroupList() {
-  loading.value = true
-  let queryGroupParams = {
-    pageSize: 30,
-    pageNum: 1,
-    userId: userStore.user.id
-  }
-  listGroup(queryGroupParams).then((response) => {
-    myGroupList.value = response.rows
-  })
-}
+
 
 /** 查询所有简短设备列表 */
 function getList() {
   loading.value = true
   queryParams.params = {}
-  getGroupList()
+  
 
   listDeviceShort(queryParams)
     .then((response) => {
-      deviceList.value = response.rows
-      total.value = response.total
+      deviceList.value = response
+      total.value = response.length
       // 订阅消息
-      if (deviceList.value && deviceList.value.length > 0) {
-        mqttSubscribe(deviceList.value)
-      }
+      // if (deviceList.value && deviceList.value.length > 0) {
+      //   mqttSubscribe(deviceList.value)
+      // }
     })
     .catch((e) => {
       console.error(e)
@@ -1046,13 +1044,13 @@ function getImg(row) {
       margin-bottom: 20px;
 
       .el-radio-button {
-        :deep(.el-radio-button__inner) {
+        ::deep(.el-radio-button__inner) {
           background-color: #f0f2f5;
           border-color: #fff;
         }
 
         &.is-active {
-          :deep(.el-radio-button__orig-radio:checked + .el-radio-button__inner) {
+          ::deep(.el-radio-button__orig-radio:checked + .el-radio-button__inner) {
             background-color: #0147eb;
             border-color: #0147eb;
           }

+ 145 - 172
src/views/pms/video_center/device/product-list.vue

@@ -1,140 +1,98 @@
 <template>
-    <el-dialog :title="t('device.product-list.058448-0')" v-model="open" width="800px">
-        <div style="margin-top: -55px">
-            <el-divider style="margin-top: -30px" />
-            <el-form :model="queryParams" ref="queryFormRef" inline label-width="68px">
-                <el-form-item :label="t('device.allot-record155854-2')" prop="productName">
-                    <el-input 
-                        v-model="queryParams.productName" 
-                        :placeholder="t('device.product-list058448-2')" 
-                        clearable 
-                        size="small" 
-                        @keyup.enter="handleQuery" 
-                    />
-                </el-form-item>
-                <el-form-item>
-                    <el-button type="primary" icon="Search" size="small" @click="handleQuery">
-                        {{ t('device.product-list058448-3') }}
-                    </el-button>
-                    <el-button icon="Refresh" size="small" @click="resetQuery">
-                        {{ t('device.product-list058448-4') }}
-                    </el-button>
-                </el-form-item>
-            </el-form>
-
-            <el-table 
-                :border="false" 
-                v-loading="loading" 
-                ref="singleTableRef" 
-                :data="productList" 
-                @row-click="rowClick" 
-                highlight-current-row 
-                size="small"
-            >
-                <el-table-column :label="t('device.device-edit.148398-6')" width="50" align="center">
-                    <template #default="scope">
-                        <input type="radio" :checked="scope.row.isSelect" name="product" />
-                    </template>
-                </el-table-column>
-                <el-table-column 
-                    :label="t('device.allot-record155854-2')" 
-                    align="center" 
-                    prop="productName" 
-                />
-                <el-table-column 
-                    :label="t('device.product-list058448-6')" 
-                    align="center" 
-                    prop="categoryName" 
-                />
-                <el-table-column 
-                    :label="t('device.product-list058448-7')" 
-                    align="center" 
-                    prop="tenantName" 
-                />
-                <el-table-column 
-                    :label="t('device.product-list058448-8')" 
-                    align="center" 
-                    prop="status" 
-                    width="70"
-                >
-                    <template #default="scope">
-                        <el-tag type="success" v-if="scope.row.isAuthorize == 1">
-                            {{ t('device.product-list058448-9') }}
-                        </el-tag>
-                        <el-tag type="info" v-if="scope.row.isAuthorize == 0">
-                            {{ t('device.product-list058448-10') }}
-                        </el-tag>
-                    </template>
-                </el-table-column>
-                <el-table-column 
-                    :label="t('device.product-list058448-11')" 
-                    align="center" 
-                    prop="status"
-                >
-                    <template #default="scope">
-                        <dict-tag 
-                            :options="dict.type.iot_vertificate_method" 
-                            :value="scope.row.vertificateMethod" 
-                        />
-                    </template>
-                </el-table-column>
-                <el-table-column 
-                    :label="t('device.product-list058448-12')" 
-                    align="center" 
-                    prop="networkMethod"
-                >
-                    <template #default="scope">
-                        <dict-tag 
-                            :options="dict.type.iot_network_method" 
-                            :value="scope.row.networkMethod" 
-                        />
-                    </template>
-                </el-table-column>
-                <el-table-column 
-                    :label="t('device.product-list058448-13')" 
-                    align="center" 
-                    prop="createTime" 
-                    width="100"
-                >
-                    <template #default="scope">
-                        <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
-                    </template>
-                </el-table-column>
-            </el-table>
-
-            <pagination 
-                v-show="total > 0" 
-                :total="total" 
-                v-model:page="queryParams.pageNum" 
-                v-model:limit="queryParams.pageSize" 
-                @pagination="getList" 
-            />
-        </div>
-        <template #footer>
-            <div class="dialog-footer">
-                <el-button @click="confirmSelectProduct" type="primary">
-                    {{ t('device.product-list058448-14') }}
-                </el-button>
-                <el-button @click="closeDialog" type="info">
-                    {{ t('device.product-list058448-15') }}
-                </el-button>
-            </div>
-        </template>
-    </el-dialog>
+  <el-dialog title="选择产品" v-model="open" width="800px">
+    <div>
+      <el-form :model="queryParams" ref="queryFormRef" inline>
+        <el-form-item :label="t('device.allot-record155854-2')" prop="productName">
+          <el-input
+            v-model="queryParams.productName"
+            placeholder="请输入产品名称"
+            clearable
+            size="small"
+            @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary"  size="small" @click="handleQuery">
+            查询
+          </el-button>
+          <el-button  size="small" @click="resetQuery"> 重置 </el-button>
+        </el-form-item>
+      </el-form>
+
+      <el-table
+        :border="false"
+        v-loading="loading"
+        ref="singleTableRef"
+        :data="productList"
+        @row-click="rowClick"
+        highlight-current-row
+        size="small"
+      >
+        <el-table-column :label="t('device.device-edit148398-6')" width="50" align="center">
+          <template #default="scope">
+            <input type="radio" :checked="scope.row.isSelect" name="product" />
+          </template>
+        </el-table-column>
+        <el-table-column
+          :label="t('device.allot-record155854-2')"
+          align="center"
+          prop="productName"
+        />
+        <el-table-column label="分类名称" align="center" prop="categoryName" />
+        <el-table-column label="租户名称" align="center" prop="tenantName" />
+
+        <el-table-column label="认证方式" align="center" prop="status">
+          <template #default="scope">
+            <dict-tag :type="DICT_TYPE.VIDEO_CENTER_VERTIFICATE_METHOD" :value="scope.row.vertificateMethod" />
+          </template>
+        </el-table-column>
+        <el-table-column label="联网方式" align="center" prop="networkMethod">
+          <template #default="scope">
+             <dict-tag :type="DICT_TYPE.VIDEO_CENTER_NETWORK_METHOD" :value="scope.row.networkMethod" />
+          </template>
+        </el-table-column>
+        <el-table-column label="创建时间" align="center" prop="createTime" width="100">
+          <template #default="scope">
+            <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+
+     <div class="mt-5 flex justify-center">
+          <pagination
+        v-show="total > 0"
+        :total="total"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        @pagination="getList"
+      />
+     </div>
+    </div>
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="confirmSelectProduct" type="primary"> 确认 </el-button>
+        <el-button @click="closeDialog" type="info"> 取消 </el-button>
+      </div>
+    </template>
+  </el-dialog>
 </template>
 
 <script setup>
 import { ref, reactive, onMounted } from 'vue'
 import { listProduct } from '@/api/pms/video/product'
+import { parseTime } from '@/utils/dateUtil'
+import { getDicts } from '@/api/pms/video/dicts'
+import {DICT_TYPE, getDictLabel} from "@/utils/dict";
 
-const { t} = useI18n()
+
+const { t } = useI18n()
 
 // 定义属性
 const props = defineProps({
-    productId: {
-        type: Number,
-        default: 0,
-    },
+  productId: {
+    type: Number,
+    default: 0
+  }
 })
 
 // 定义事件
@@ -142,10 +100,12 @@ const emit = defineEmits(['productEvent'])
 
 // 字典配置
 defineOptions({
-    name: 'ProductList',
-    dicts: ['iot_vertificate_method', 'iot_network_method']
+  name: 'ProductList'
 })
 
+const iot_vertificate_method = ref([])
+const iot_network_method = ref([])
+
 // 响应式数据
 const open = defineModel('open')
 const loading = ref(true)
@@ -156,74 +116,87 @@ const queryFormRef = ref()
 const singleTableRef = ref()
 
 const queryParams = reactive({
-    pageNum: 1,
-    pageSize: 10,
-    productName: null,
-    categoryId: null,
-    categoryName: null,
-    tenantId: null,
-    tenantName: null,
-    isSys: null,
-    status: 2, //已发布
-    deviceType: null,
-    networkMethod: null,
+  pageNum: 1,
+  pageSize: 10,
+  productName: null,
+  categoryId: null,
+  categoryName: null,
+  tenantId: null,
+  tenantName: null,
+  isSys: null,
+  status: 2, //已发布
+  deviceType: null,
+  networkMethod: null
 })
 
 // 方法定义
 const getList = () => {
-    loading.value = true
-    listProduct(queryParams).then((response) => {
-        //产品列表初始化isSelect值,用于单选
-        for (let i = 0; i < response.rows.length; i++) {
-            response.rows[i].isSelect = false
-        }
-        productList.value = response.rows
-        total.value = response.total
-        if (props.productId != 0) {
-            setRadioSelected(props.productId)
-        }
-        loading.value = false
-    })
+  loading.value = true
+  listProduct(queryParams).then((response) => {
+    //产品列表初始化isSelect值,用于单选
+    for (let i = 0; i < response.list.length; i++) {
+      response.list[i].isSelect = false
+    }
+    productList.value = response.list
+    total.value = response.total
+    if (props.productId != 0) {
+      setRadioSelected(props.productId)
+    }
+    loading.value = false
+  })
 }
 
 const handleQuery = () => {
-    queryParams.pageNum = 1
-    getList()
+  queryParams.pageNum = 1
+  getList()
 }
 
 const resetQuery = () => {
-    queryFormRef.value?.resetFields()
-    handleQuery()
+  queryFormRef.value?.resetFields()
+  handleQuery()
 }
 
 const rowClick = (productRow) => {
-    if (productRow != null) {
-        setRadioSelected(productRow.productId)
-        product.value = productRow
-    }
+  if (productRow != null) {
+    setRadioSelected(productRow.productId)
+    product.value = productRow
+  }
 }
 
 const setRadioSelected = (productId) => {
-    for (let i = 0; i < productList.value.length; i++) {
-        if (productList.value[i].productId == productId) {
-            productList.value[i].isSelect = true
-        } else {
-            productList.value[i].isSelect = false
-        }
+  for (let i = 0; i < productList.value.length; i++) {
+    if (productList.value[i].productId == productId) {
+      productList.value[i].isSelect = true
+    } else {
+      productList.value[i].isSelect = false
     }
+  }
 }
 
 const confirmSelectProduct = () => {
-    emit('productEvent', product.value)
-    open.value = false
+  emit('productEvent', product.value)
+  open.value = false
 }
 
 const closeDialog = () => {
-    open.value = false
+  open.value = false
 }
 
 // 生命周期钩子
 onMounted(() => {
-    getList()
+  getList()
+
+  getDicts('iot_network_method').then((response) => {
+    iot_network_method.value = response
+  })
+
+  getDicts('iot_vertificate_method').then((response) => {
+    iot_vertificate_method.value = response
+  })
+})
+
+defineExpose({
+  getList,
+  open
 })
-</script>
+</script>

+ 1 - 1
src/views/pms/video_center/product/index.vue

@@ -534,7 +534,7 @@ function handleTemp() {
 // 查看设备按钮操作
 function handleViewDevice(productId) {
   router.push({
-    path: '/iotdev/iot/device',
+    path: '/videocenter/device',
     query: {
       t: Date.now(),
       productId: productId

+ 225 - 203
src/views/pms/video_center/sip/channel.vue

@@ -1,85 +1,119 @@
 <template>
-    <div style="padding-left: 20px">
-        <el-row :gutter="10" class="mb8">
-            <el-col :span="1.5">
-                <el-button type="warning" plain :icon="Refresh" size="small" @click="getList">{{ t('refresh') }}</el-button>
-            </el-col>
-        </el-row>
-        <el-table v-loading="loading" :data="channelList" size="small">
-            <el-table-column :label="t('sip.channel.998532-0')" align="center" prop="deviceSipId" />
-            <el-table-column :label="t('sip.channel.998532-1')" align="center" prop="channelSipId" />
-            <el-table-column :label="t('sip.channel.998532-2')" min-width="120">
-                <template #default="scope">
-                    <el-image v-if="isVideoChannel(scope.row)" :src="getSnap(scope.row)" :preview-src-list="getBigSnap(scope.row)" fit="contain" style="width: 60px">
-                        <template #error>
-                            <div class="image-slot">
-                                <i class="el-icon-picture-outline"></i>
-                            </div>
-                        </template>
-                    </el-image>
-                </template>
-            </el-table-column>
-            <el-table-column :label="t('sip.channel.998532-3')" align="center" prop="channelName" />
-            <el-table-column :label="t('sip.channel.998532-4')" align="center" prop="model" />
-            <el-table-column :label="t('sip.channel.998532-9')" align="center" prop="streamPush">
-                <template #default="scope">
-                    <el-tag type="warning" v-if="scope.row.streamPush === 0">{{ t('sip.channel.998532-10') }}</el-tag>
-                    <el-tag type="success" v-if="scope.row.streamPush === 1">{{ t('sip.channel.998532-11') }}</el-tag>
-                </template>
-            </el-table-column>
-            <el-table-column :label="t('sip.channel.998532-12')" align="center" prop="streamRecord">
-                <template #default="scope">
-                    <el-tag type="warning" v-if="scope.row.streamRecord === 0">{{ t('sip.channel.998532-13') }}</el-tag>
-                    <el-tag type="success" v-if="scope.row.streamRecord === 1">{{ t('sip.channel.998532-14') }}</el-tag>
-                </template>
-            </el-table-column>
-            <el-table-column :label="t('sip.channel.998532-15')" align="center" prop="videoRecord">
-                <template #default="scope">
-                    <el-tag type="warning" v-if="scope.row.videoRecord === 0">{{ t('sip.channel.998532-16') }}</el-tag>
-                    <el-tag type="success" v-if="scope.row.videoRecord === 1">{{ t('sip.channel.998532-17') }}</el-tag>
-                </template>
-            </el-table-column>
-            <el-table-column :label="t('sip.channel.998532-5')" align="center" prop="status" width="80">
-                <template #default="scope">
-                    <dict-tag :options="dict.type.iot_device_status" :value="scope.row.status" size="small" />
-                </template>
-            </el-table-column>
-            <el-table-column :label="t('opation')" align="center" width="120" class-name="small-padding fixed-width">
-                <template #default="scope">
-                    <el-button size="small" type="success" :icon="VideoPlay" style="padding: 5px" :disabled="scope.row.status !== 3" @click="sendDevicePush(scope.row)">
-                        {{ t('sip.channel.998532-6') }}
-                    </el-button>
-                </template>
-            </el-table-column>
-        </el-table>
-        <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
-    </div>
+  <div style="padding-left: 20px">
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="warning" plain :icon="Refresh" size="small" @click="getList"
+          >刷新</el-button
+        >
+      </el-col>
+    </el-row>
+    <el-table v-loading="loading" :data="channelList" size="small">
+      <el-table-column :label="t('sip.channel998532-0')" align="center" prop="deviceSipId" />
+      <el-table-column :label="t('sip.channel998532-1')" align="center" prop="channelSipId" />
+      <el-table-column :label="t('sip.channel998532-2')" min-width="120">
+        <template #default="scope">
+          <el-image
+            v-if="isVideoChannel(scope.row)"
+            :src="getSnap(scope.row)"
+            :preview-src-list="getBigSnap(scope.row)"
+            fit="contain"
+            style="width: 60px"
+          >
+            <template #error>
+              <div class="image-slot">
+                <i class="el-icon-picture-outline"></i>
+              </div>
+            </template>
+          </el-image>
+        </template>
+      </el-table-column>
+      <el-table-column :label="t('sip.channel998532-3')" align="center" prop="channelName" />
+      <el-table-column :label="t('sip.channel998532-4')" align="center" prop="model" />
+      <el-table-column :label="t('sip.channel998532-9')" align="center" prop="streamPush">
+        <template #default="scope">
+          <el-tag type="warning" v-if="scope.row.streamPush === 0">{{
+            t('sip.channel998532-10')
+          }}</el-tag>
+          <el-tag type="success" v-if="scope.row.streamPush === 1">{{
+            t('sip.channel998532-11')
+          }}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column :label="t('sip.channel998532-12')" align="center" prop="streamRecord">
+        <template #default="scope">
+          <el-tag type="warning" v-if="scope.row.streamRecord === 0">{{
+            t('sip.channel998532-13')
+          }}</el-tag>
+          <el-tag type="success" v-if="scope.row.streamRecord === 1">{{
+            t('sip.channel998532-14')
+          }}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column :label="t('sip.channel998532-15')" align="center" prop="videoRecord">
+        <template #default="scope">
+          <el-tag type="warning" v-if="scope.row.videoRecord === 0">{{
+            t('sip.channel998532-16')
+          }}</el-tag>
+          <el-tag type="success" v-if="scope.row.videoRecord === 1">{{
+            t('sip.channel998532-17')
+          }}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column :label="t('sip.channel998532-5')" align="center" prop="status" width="80">
+        <template #default="scope">
+          <dict-tag :options="iot_device_status" :value="scope.row.status" size="small" />
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="操作"
+        align="center"
+        width="120"
+        class-name="small-padding fixed-width"
+      >
+        <template #default="scope">
+          <el-button
+            size="small"
+            type="success"
+            :icon="VideoPlay"
+            style="padding: 5px"
+            :disabled="scope.row.status !== 3"
+            @click="sendDevicePush(scope.row)"
+          >
+            {{ t('sip.channel998532-6') }}
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
 </template>
 
 <script setup>
 import { ref, reactive, watch, onMounted } from 'vue'
 import { Refresh, VideoPlay } from '@element-plus/icons-vue'
 import { listChannel, getChannel, delChannel } from '@/api/pms/video/channel'
+import { ElMessage, ElMessageBox } from 'element-plus'
 
 const { t } = useI18n() // 国际化
 
 // 定义 props
 const props = defineProps({
-    device: {
-        type: Object,
-        default: null,
-    },
+  device: {
+    type: Object,
+    default: null
+  }
 })
 
 // 定义 emits
 const emit = defineEmits(['playerEvent'])
 
-// 字典数据(需要根据实际项目情况调整)
-const dict = {
-    type: {
-        iot_device_status: [], // 需要根据实际字典数据填充
-    }
-}
+const iot_device_status = ref([])
 
 // 响应式数据
 const loadSnap = ref({})
@@ -96,201 +130,189 @@ const open = ref(false)
 
 // 查询参数
 const queryParams = reactive({
-    pageNum: 1,
-    pageSize: 10,
-    deviceSipId: null,
+  pageNum: 1,
+  pageSize: 10,
+  deviceSipId: null
 })
 
 // 表单参数
 const form = reactive({
-    channelId: null,
-    channelSipId: null,
-    deviceSipId: null,
-    channelName: null,
-    manufacture: null,
-    model: null,
-    owner: null,
-    civilcode: null,
-    block: null,
-    address: null,
-    parentid: null,
-    ipaddress: null,
-    port: null,
-    password: null,
-    ptztype: null,
-    ptztypetext: null,
-    status: 0,
-    longitude: null,
-    latitude: null,
-    streamid: null,
-    subcount: null,
-    parental: 1,
-    hasaudio: 1,
+  channelId: null,
+  channelSipId: null,
+  deviceSipId: null,
+  channelName: null,
+  manufacture: null,
+  model: null,
+  owner: null,
+  civilcode: null,
+  block: null,
+  address: null,
+  parentid: null,
+  ipaddress: null,
+  port: null,
+  password: null,
+  ptztype: null,
+  ptztypetext: null,
+  status: 0,
+  longitude: null,
+  latitude: null,
+  streamid: null,
+  subcount: null,
+  parental: 1,
+  hasaudio: 1
 })
 
 // 监听 device prop 变化
 watch(
-    () => props.device,
-    (newVal, oldVal) => {
-        deviceInfo.value = newVal
-        if (deviceInfo.value && deviceInfo.value.deviceId != 0) {
-            queryParams.deviceSipId = deviceInfo.value.serialNumber
-        }
+  () => props.device,
+  (newVal, oldVal) => {
+    deviceInfo.value = newVal
+    if (deviceInfo.value && deviceInfo.value.deviceId != 0) {
+      queryParams.deviceSipId = deviceInfo.value.serialNumber
     }
+  }
 )
 
 // 通知设备上传媒体流
 const sendDevicePush = (itemData) => {
-    var data = { tabName: 'sipPlayer', channelId: itemData.channelSipId }
-    emit('playerEvent', data)
-    console.log('通知设备推流:' + itemData.deviceSipId + ' : ' + itemData.channelSipId)
+  var data = { tabName: 'sipPlayer', channelId: itemData.channelSipId }
+  emit('playerEvent', data)
+  console.log('通知设备推流:' + itemData.deviceSipId + ' : ' + itemData.channelSipId)
 }
 
 // 查询监控设备通道信息列表
 const getList = () => {
-    loading.value = true
-    // listChannel(queryParams).then((response) => {
-    //     console.log(response)
-    //     channelList.value = response.rows
-    //     total.value = response.total
-    //     loading.value = false
-    // })
-
-    // 模拟数据
-    
-    channelList.value = [
-        {
-            channelId: 1,
-            deviceSipId: queryParams.deviceSipId,
-            channelSipId: '34020000002000000001',
-            channelName: '前门摄像头',
-            model: 'IPC-1234',
-            streamPush: 1,
-            streamRecord: 1,
-            videoRecord: 0,
-            status: 3,
-        },
-        {
-            channelId: 2,
-            deviceSipId: queryParams.deviceSipId,
-            channelSipId: '34020000002000000002',
-            channelName: '后门摄像头',
-            model: 'IPC-5678',
-            streamPush: 0,
-            streamRecord: 1,
-            videoRecord: 1,
-            status: 2,
-        },
-    ]
-    total.value = channelList.value.length
+  loading.value = true
+  listChannel(queryParams).then((response) => {
+   
+    channelList.value = response
+    total.value = response.length
     loading.value = false
-
+  })
 }
 
 // 取消按钮
 const cancel = () => {
-    open.value = false
-    reset()
+  open.value = false
+  reset()
 }
 
 // 表单重置
 const reset = () => {
-    Object.assign(form, {
-        channelId: null,
-        channelSipId: null,
-        deviceSipId: null,
-        channelName: null,
-        manufacture: null,
-        model: null,
-        owner: null,
-        civilcode: null,
-        block: null,
-        address: null,
-        parentid: null,
-        ipaddress: null,
-        port: null,
-        password: null,
-        ptztype: null,
-        ptztypetext: null,
-        status: 0,
-        longitude: null,
-        latitude: null,
-        streamid: null,
-        subcount: null,
-        parental: 1,
-        hasaudio: 1,
-    })
-    // 如果有 resetForm 方法需要根据实际情况实现
+  Object.assign(form, {
+    channelId: null,
+    channelSipId: null,
+    deviceSipId: null,
+    channelName: null,
+    manufacture: null,
+    model: null,
+    owner: null,
+    civilcode: null,
+    block: null,
+    address: null,
+    parentid: null,
+    ipaddress: null,
+    port: null,
+    password: null,
+    ptztype: null,
+    ptztypetext: null,
+    status: 0,
+    longitude: null,
+    latitude: null,
+    streamid: null,
+    subcount: null,
+    parental: 1,
+    hasaudio: 1
+  })
+  // 如果有 resetForm 方法需要根据实际情况实现
+  resetForm('form')
 }
 
 // 搜索按钮操作
 const handleQuery = () => {
-    queryParams.pageNum = 1
-    getList()
+  queryParams.pageNum = 1
+  getList()
 }
 
 // 修改按钮操作
 const handleUpdate = (row) => {
-    reset()
-    const channelId = row.channelId || ids.value
-    getChannel(channelId).then((response) => {
-        Object.assign(form, response.data)
-        open.value = true
-        title.value = this.t('sip.channel.998532-7')
-    })
+  reset()
+  const channelId = row.channelId || ids.value
+  getChannel(channelId).then((response) => {
+    
+    Object.assign(form, response.data)
+    open.value = true
+    title.value = t('sip.channel998532-7')
+  })
 }
 
 // 删除按钮操作
 const handleDelete = (row) => {
-    const channelIds = row.channelId || ids.value
-    // 这里需要根据实际项目的确认框实现方式调整
-    // $modal.confirm(t('sip.channel.998532-8', [channelIds]))
-    //     .then(function() {
-    //         return delChannel(channelIds);
-    //     })
-    //     .then(() => {
-    //         getList();
-    //         // $modal.msgSuccess(t('sip.channel.998532-18'));
-    //     })
-    //     .catch(() => {});
+  const channelIds = row.channelId || ids.value
+
+  ElMessageBox.confirm(t('sip.channel998532-8', [channelIds]))
+    .then(function () {
+      return delChannel(channelIds)
+    })
+    .then(() => {
+      getList()
+      ElMessage.success(t('sip.channel998532-18'))
+    })
+    .catch(() => {})
 }
 
 // 获取快照URL
 const getSnap = (row) => {
-    console.log('getSnap:' + import.meta.env.VITE_APP_BASE_API + '/profile/snap/' + row.deviceSipId + '_' + row.channelSipId + '.jpg')
-    return import.meta.env.VITE_APP_BASE_API + '/profile/snap/' + row.deviceSipId + '_' + row.channelSipId + '.jpg'
+  return (
+    import.meta.env.VITE_APP_BASE_URL +
+    '/profile/snap/' +
+    row.deviceSipId +
+    '_' +
+    row.channelSipId +
+    '.jpg'
+  )
 }
 
 // 获取大图URL
 const getBigSnap = (row) => {
-    return [getSnap(row)]
+  return [getSnap(row)]
 }
 
 // 判断是否为视频通道
 const isVideoChannel = (row) => {
-    let channelType = row.channelSipId.substring(10, 13)
-    // 111-DVR编码;112-视频服务器编码;118-网络视频录像机(NVR)编码;131-摄像机编码;132-网络摄像机(IPC)编码
-    return !(channelType !== '111' && channelType !== '112' && channelType !== '118' && channelType !== '131' && channelType !== '132')
+  let channelType = row.channelSipId.substring(10, 13)
+  // 111-DVR编码;112-视频服务器编码;118-网络视频录像机(NVR)编码;131-摄像机编码;132-网络摄像机(IPC)编码
+  return !(
+    channelType !== '111' &&
+    channelType !== '112' &&
+    channelType !== '118' &&
+    channelType !== '131' &&
+    channelType !== '132'
+  )
 }
 
 // 生命周期钩子
 onMounted(() => {
-    if (props.device) {
-        queryParams.deviceSipId = props.device.serialNumber
-        getList()
-    }
+  if (props.device) {
+    queryParams.deviceSipId = props.device.serialNumber
+    getList()
+  }
+})
+
+defineExpose({
+  getList
 })
 </script>
 
 <style scoped>
 .image-slot {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    width: 100%;
-    height: 100%;
-    background: var(--el-fill-color-light);
-    color: var(--el-text-color-secondary);
-    font-size: 30px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 100%;
+  background: var(--el-fill-color-light);
+  color: var(--el-text-color-secondary);
+  font-size: 30px;
 }
-</style>
+</style>

+ 246 - 193
src/views/pms/video_center/sip/components/player/deviceLiveStream.vue

@@ -1,200 +1,253 @@
 <template>
   <div>
-    <el-row>
-      <span style="margin-left: 10px" prop="channelName">通道名称:</span>
-      <el-select v-model="channelId" placeholder="请选择" @change="changeChannel()" size="small">
-        <el-option v-for="option in channelList" :key="option.value" :label="option.label" :value="option.value"></el-option>
+    <el-row align="middle">
+      <span style="margin-left: 10px">通道名称:</span>
+      <el-select 
+        v-model="channelId" 
+        placeholder="请选择" 
+        @change="changeChannel" 
+        size="small"
+        style="width: 200px;"
+      >
+        <el-option 
+          v-for="option in channelList" 
+          :key="option.value" 
+          :label="option.label" 
+          :value="option.value"
+        />
       </el-select>
-      <span style="margin: 10px 10px 10px 30px">开启拉流:</span>
-      <el-switch v-model="pushStream" active-color="#13ce66" inactive-color="#c4c6c9" style="border-radius: 10px" :disabled="channelId === ''" @change="startPushStream"></el-switch>
-      <span style="margin: 10px 10px 10px 30px">开启直播录像:</span>
-      <el-switch v-model="playrecord" active-color="#13ce66" inactive-color="#c4c6c9" style="border-radius: 10px" :disabled="channelId === ''" @change="startPlayRecord"></el-switch>
+      <span style="margin: 0 10px 0 30px">开启拉流:</span>
+      <el-switch 
+        v-model="pushStream" 
+        active-color="#13ce66" 
+        inactive-color="#c4c6c9" 
+        :disabled="channelId === ''" 
+        @change="startPushStream"
+      />
+      <span style="margin: 0 10px 0 30px">开启直播录像:</span>
+      <el-switch 
+        v-model="playrecord" 
+        active-color="#13ce66" 
+        inactive-color="#c4c6c9" 
+        :disabled="channelId === ''" 
+        @change="handleStartPlayRecord"
+      />
     </el-row>
-    <player ref="player" :playerinfo="playinfo" class="components-container"></player>
+    <player 
+      ref="playerRef" 
+      :playerinfo="playinfo" 
+      class="components-container"
+      style="margin-top: 10px;"
+    />
   </div>
 </template>
-<script>
-import player from '@/views/components/player/player.vue';
-import { startPlay, closeStream, listChannel } from '@/api/iot/channel';
-import { startPlayRecord } from '@/api/iot/record';
-
-export default {
-  name: 'device-live-stream',
-  components: {
-    player,
-  },
-  props: {
-    device: {
-      type: Object,
-      default: null,
-    },
-  },
-  watch: {
-    // 获取到父组件传递的device后
-    device: function (newVal, oldVal) {
-      this.deviceInfo = newVal;
-      if (this.deviceInfo.channelId) {
-        this.channelId = this.deviceInfo.channelId;
-        this.changeChannel();
-      }
-      if (this.deviceInfo && this.deviceInfo.deviceId !== 0) {
-        this.queryParams.deviceSipId = this.deviceInfo.serialNumber;
-        this.deviceId = this.device.serialNumber;
-      }
-    },
-  },
-  data() {
-    return {
-      deviceInfo: {},
-      deviceId: '',
-      channelId: '',
-      streamId: '',
-      ssrc: '',
-      playurl: '',
-      playinfo: { playtype: 'play' },
-      playrecord: false,
-      playrecording: false,
-      playing: false,
-      pushStream: false,
-      retrycount: 0,
-      channelList: [],
-      // 查询参数
-      queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        deviceSipId: null,
-        channelSipId: null,
-      },
-    };
-  },
-  created() {
-    this.queryParams.deviceSipId = this.device.serialNumber;
-    this.deviceId = this.device.serialNumber;
-    this.getList();
-    this.playinfo = {
-      playtype: 'play',
-      deviceId: this.device.serialNumber,
-    };
-  },
-  beforeDestroy() {
-    console.log("beforeDestroy");
-    this.closeDestroy(false);
-  },
-  methods: {
-    /** 查询监控设备通道信息列表 */
-    getList() {
-      this.loading = true;
-      listChannel(this.queryParams).then((response) => {
-        this.channelList = response.rows.map((item) => {
-          return { value: item.channelSipId, label: item.channelName };
-        });
-        console.log(this.channelList);
-      });
-    },
-    changeChannel() {
-      this.playinfo.channelId = this.channelId;
-      this.startPlayer();
-    },
+
+<script setup>
+import { ref, reactive, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'
+import player from './player.vue'
+import { startPlay, closeStream, listChannel } from '@/api/pms/video/channel'
+import { startPlayRecord } from '@/api/pms/video/record'
+
+// 定义props
+const props = defineProps({
+  device: {
+    type: Object,
+    default: null
+  }
+})
+
+// 定义响应式数据
+const playerRef = ref(null)
+const deviceInfo = ref({})
+const deviceId = ref('')
+const channelId = ref('')
+const streamId = ref('')
+const ssrc = ref('')
+const playurl = ref('')
+const playrecord = ref(false)
+const playrecording = ref(false)
+const playing = ref(false)
+const pushStream = ref(false)
+const retrycount = ref(0)
+const channelList = ref([])
+
+// 查询参数
+const queryParams = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  deviceSipId: null,
+  channelSipId: null
+})
+
+// 播放信息
+const playinfo = reactive({ 
+  playtype: 'play' 
+})
+
+// Watch device prop变化
+watch(() => props.device, (newVal, oldVal) => {
+  deviceInfo.value = newVal
+  if (newVal?.channelId) {
+    channelId.value = newVal.channelId
+    changeChannel()
+  }
+  if (newVal && newVal.deviceId !== 0) {
+    queryParams.deviceSipId = newVal.serialNumber
+    deviceId.value = newVal.serialNumber
+  }
+})
+
+// 组件挂载时执行
+onMounted(() => {
+  if (props.device) {
+    queryParams.deviceSipId = props.device.serialNumber
+    deviceId.value = props.device.serialNumber
+    getList()
+    playinfo.deviceId = props.device.serialNumber
+  }
+})
+
+// 组件销毁前执行
+onBeforeUnmount(() => {
+  console.log("beforeDestroy")
+  closeDestroy(false)
+})
+
+// 查询监控设备通道信息列表
+const getList = () => {
+  listChannel(queryParams).then((response) => {
+    channelList.value = response.map((item) => {
+      return { value: item.channelSipId, label: item.channelName }
+    })
+    
+  })
+}
+
+// 通道切换
+const changeChannel = () => {
+  playinfo.channelId = channelId.value
+  startPlayer()
+}
+
+// 超时回调
+const TimeoutCallback = () => {
+  closeDestroy(false)
+  retrycount.value = 0
+  setTimeout(() => {
+    startPlayer()
+  }, 1000)
+}
+
+// 开启/关闭推流
+const startPushStream = () => {
+  if (!channelId.value) {
+    console.log('开始通道: [' + channelId.value + ']')
+    return
+  }
+  console.log('推流状态: [' + pushStream.value + ']')
+  if (pushStream.value) {
+    startPlayer()
+  } else {
+    closeDestroy(true)
+  }
+}
+
+// 开启/关闭录像播放
+const handleStartPlayRecord = () => {
+  console.log('录像状态: [' + playrecord.value + ']')
+  closeDestroy(true)
+  setTimeout(() => {
+    startPlayer()
+  }, 500)
+}
+
+// 开启直播播放器
+const startPlayer = () => {
+  if (!channelId.value) {
+    
+    return
+  }
+  deviceId.value = queryParams.deviceSipId
+  if (playing.value) {
+    closeDestroy(false)
+  }
+  
+  // 注册回调
+  playerRef.value?.registercallback('loadingTimeout', TimeoutCallback)
+  playerRef.value?.registercallback('delayTimeout', TimeoutCallback)
+  
+  if (playrecord.value) {
+    // 录像播放
+    startPlayRecord(deviceId.value, channelId.value).then((response) => {
+     
+      const res = response.data
+      streamId.value = res.streamId
+      playurl.value = res.playurl
+      playerRef.value?.play(playurl.value)
+      playing.value = true
+      playrecording.value = true
+      pushStream.value = true
+    })
+  } else {
     // 直播播放
-    TimeoutCallback() {
-      this.closeDestroy(false);
-      this.retrycount = 0;
-      setTimeout(() => {
-        this.startPlayer();
-      }, 1000);
-    },
-    startPushStream() {
-      if (!this.channelId) {
-        console.log('开始通道: [' + this.channelId + ']');
-        return;
-      }
-      console.log('推流状态: [' + this.pushStream + ']');
-      if (this.pushStream) {
-        this.startPlayer();
-      } else {
-        this.closeDestroy(true);
-      }
-    },
-    startPlayRecord() {
-      console.log('录像状态: [' + this.playrecord + ']');
-      this.closeDestroy(true);
-      setTimeout(() => {
-        this.startPlayer();
-      }, 500);
-    },
-    // 开启直播播放器
-    startPlayer() {
-      if (!this.channelId) {
-        console.log('直播录像通道: [' + this.channelId + ']');
-        return;
-      }
-      this.deviceId = this.queryParams.deviceSipId;
-      if (this.playing) {
-        this.closeDestroy(false);
-      }
-      this.$refs.player.registercallback('loadingTimeout', this.TimeoutCallback);
-      this.$refs.player.registercallback('delayTimeout', this.TimeoutCallback);
-      if (this.playrecord) {
-        startPlayRecord(this.deviceId, this.channelId).then((response) => {
-          console.log('开始录像:' + this.deviceId + ' : ' + this.channelId);
-          const res = response.data;
-          this.streamId = res.streamId;
-          this.playurl = res.playurl;
-          this.$refs.player.play(this.playurl);
-          this.playing = true;
-          this.playrecording = true;
-          this.pushStream = true;
-        });
-      } else {
-        startPlay(this.deviceId, this.channelId).then((response) => {
-          console.log('开始推流: [' + this.channelId + ']');
-          const res = response.data;
-          this.streamId = res.streamId;
-          this.playurl = res.playurl;
-          this.$refs.player.play(this.playurl);
-          this.playing = true;
-          this.playrecording = false;
-          this.pushStream = true;
-        });
-      }
-    },
-    closeStream(force) {
-      if (force) {
-        if (this.playing && this.streamId) {
-          console.log('强制关闭推流: [' + this.streamId + ']');
-          closeStream(this.deviceId, this.channelId, this.streamId).then((res) => {
-            this.streamId = '';
-            this.ssrc = '';
-            this.playurl = '';
-            this.pushStream = false;
-          });
-          this.playing = false;
-          this.playrecording = false;
-        }
-      } else {
-        if (this.playrecording === true) {
-          return;
-        }
-        if (this.playing && this.streamId) {
-          console.log('关闭推流: [' + this.streamId + ']');
-          closeStream(this.deviceId, this.channelId, this.streamId).then((res) => {
-            this.streamId = '';
-            this.ssrc = '';
-            this.playurl = '';
-            this.pushStream = false;
-          });
-          this.playing = false;
-          this.playrecording = false;
-        }
-      }
-    },
-    closeDestroy(force) {
-      this.closeStream(force);
-      this.$refs.player.destroy();
-    },
-    destroy() {
-      this.$refs.player.destroy();
-    },
-  },
-};
-</script>
+    startPlay(deviceId.value, channelId.value).then((response) => {
+      
+      const res = response.data
+      streamId.value = res.streamId
+      playurl.value = res.playurl
+      playerRef.value?.play(playurl.value)
+      playing.value = true
+      playrecording.value = false
+      pushStream.value = true
+    })
+  }
+}
+
+// 关闭流
+const handleCloseStream = (force) => {
+  if (force) {
+    if (playing.value && streamId.value) {
+    
+      closeStream(deviceId.value, channelId.value, streamId.value).then((res) => {
+        streamId.value = ''
+        ssrc.value = ''
+        playurl.value = ''
+        pushStream.value = false
+      })
+      playing.value = false
+      playrecording.value = false
+    }
+  } else {
+    if (playrecording.value === true) {
+      return
+    }
+    if (playing.value && streamId.value) {
+      console.log('关闭推流: [' + streamId.value + ']')
+      closeStream(deviceId.value, channelId.value, streamId.value).then((res) => {
+        streamId.value = ''
+        ssrc.value = ''
+        playurl.value = ''
+        pushStream.value = false
+      })
+      playing.value = false
+      playrecording.value = false
+    }
+  }
+}
+
+// 关闭并销毁
+const closeDestroy = (force) => {
+  handleCloseStream(force)
+  playerRef.value?.destroy()
+}
+
+// 销毁播放器
+const destroy = () => {
+  playerRef.value?.destroy()
+}
+
+// 暴露给父组件的方法
+defineExpose({
+  destroy
+})
+</script>

+ 378 - 321
src/views/pms/video_center/sip/components/player/player.vue

@@ -1,351 +1,408 @@
 <template>
-    <div class="root">
-        <div class="container-shell">
-            <div id="container" ref="container" :style="{width: width, height: height}"></div>
-        </div>
+  <div class="root">
+    <div class="container-shell">
+      <div id="container" ref="containerRef" :style="{width: width, height: height}"></div>
     </div>
+  </div>
 </template>
 
-<script>
-let jessibucaPlayer = {};
-import {ptzdirection, ptzscale} from '@/api/iot/sipdevice';
-
-export default {
-    name: 'player',
-    props: {
-        playerinfo: {
-            type: Object,
-            default: null,
-        },
-        width: {
-            type: String,
-            default: '1000px'
-        },
-        height: {
-            type: String,
-            default: '630px'
-        }
-    },
-    mounted() {
-        console.log("this._uid",this._uid);
-    },
-    watch: {
-        playerinfo: function (newVal, oldVal) {
-            console.log('playerinfo 发生变化');
-            this.playinfo = newVal;
-            if (this.playinfo && this.playinfo.playtype !== '') {
-                this.playtype = this.playinfo.playtype;
-            }
-        },
-    },
-    jessibuca: null,
-    data() {
-        return {
-            isPlaybackPause: false,
-            useWebGPU: false,
-            isInit: false,
-            playinfo: {},
-            playtype: 'play',
-            operateBtns: {
-                fullscreen: true,
-                zoom: true,
-                play: true,
-                audio: true,
-            },
-        };
-    },
-    beforeDestroy() {
-    },
-    created() {
-        this.playinfo = this.playerinfo;
-        if (this.playinfo && this.playinfo.playtype !== '') {
-            this.playtype = this.playinfo.playtype;
-        }
-        this.init();
-    },
-    methods: {
-        init() {
-            var isSupportWebgpu = 'gpu' in navigator;
-            if (isSupportWebgpu) {
-                console.log('支持webGPU');
-                this.useWebGPU = true;
-            } else {
-                console.log('暂不支持webGPU,降级到webgl渲染');
-                this.useWebGPU = false;
-            }
-
-            const useVconsole = this.isMobile() || this.isPad();
-            if (useVconsole && window.VConsole) {
-                new window.VConsole();
-            }
-            this.$nextTick(() => {
-                this.initplayer();
-            });
-        },
-        initplayer() {
-            this.isPlaybackPause = false;
-            this.initconf();
-            jessibucaPlayer[this._uid] = new window.JessibucaPro({
-                container: this.$refs.container,
-                decoder: '/js/jessibuca-pro/decoder-pro.js',
-                videoBuffer: Number(0.2), // 缓存时长
-                isResize: false,
-                useWCS: false,
-                useMSE: false,
-                useSIMD: true,
-                wcsUseVideoRender: false,
-                loadingText: '加载中',
-                debug: false,
-                debugLevel: "debug",
-                showBandwidth: true, // 显示网速
-                showPlaybackOperate: true,
-                operateBtns: this.operateBtns,
-                forceNoOffscreen: true,
-                isNotMute: true, // 默认关闭声音
-                showPerformance: false,
-                // playFailedAndReplay: true,
-                // networkDelayTimeoutReplay: true,
-                playbackForwardMaxRateDecodeIFrame: 4,
-                useWebGPU: this.useWebGPU, // 使用WebGPU
-            });
-            let jessibuca = jessibucaPlayer[this._uid];
-            this.initcallback(jessibuca);
-            this.isInit = true;
-        },
-        initconf() {
-            if (this.playtype === 'play') {
-                //直播按钮配置
-                this.operateBtns.ptz = true;
-            } else {
-                //录像回放按钮配置
-                this.operateBtns.ptz = false;
-            }
-        },
-        initcallback(jessibuca) {
-            const _this = this;
-            jessibuca.on('error', function (error) {
-                console.log('jessibuca error', error);
-                //_this.destroy();
-            });
-            jessibuca.on("playFailedAndPaused", function (reason, lastFrameInfo, msg) {
-                console.log('playFailedAndPaused', reason, msg);
-                // lastFrameInfo 是最后一帧的画面,可以用来重播的时候,显示最后一帧画面。
-                // msg 具体的错误信息。
-            });
-            jessibuca.on('visibilityChange', (value) => {
-                if (value === true) {
-                    // 窗口显示
-                    console.log('visibilityChange true');
-                } else {
-                    // 窗口隐藏
-                    console.log('visibilityChange false');
-                }
-            });
-            jessibuca.on('pause', function (pause) {
-                console.log('pause success!');
-                console.log(pause);
-            });
-            jessibuca.on('play', function (flag) {
-                console.log('play!', flag);
-            });
-            jessibuca.on('loading', function (load) {
-                console.log('loading success!', load);
-            });
-            jessibuca.on('stats', function (s) {
-                // console.log('stats is', s);
-            });
-            jessibuca.on('timeout', function (error) {
-                console.log('timeout:', error);
-            });
-            jessibuca.on('playbackPreRateChange', (rate) => {
-                jessibuca.forward(rate);
-            });
-
-            let pre = 0;
-            let cur = 0;
-            jessibuca.on('timeUpdate', function (ts) {
-                cur = parseInt(ts / 60000);
-                if (pre !== cur) {
-                    pre++;
-                }
-            });
-            jessibuca.on(JessibucaPro.EVENTS.ptz, (arrow) => {
-                console.log('ptz arrow', arrow);
-                _this.handlePtz(arrow);
-            });
-            jessibuca.on('crashLog', (data) => {
-                console.log('crashLog is', data);
-            });
-        },
-        registercallback(events, func) {
-            if (jessibucaPlayer[this._uid]) {
-                jessibucaPlayer[this._uid].on(events, func);
-            }
-        },
-        isMobile() {
-            return /iphone|ipad|android.*mobile|windows.*phone|blackberry.*mobile/i.test(window.navigator.userAgent.toLowerCase());
-        },
-        isPad() {
-            return /ipad|android(?!.*mobile)|tablet|kindle|silk/i.test(window.navigator.userAgent.toLowerCase());
-        },
-        play(url) {
-            if (jessibucaPlayer[this._uid]) {
-                jessibucaPlayer[this._uid].play(url);
-            }
-        },
-        pause() {
-            if (jessibucaPlayer[this._uid]) {
-                jessibucaPlayer[this._uid].pause();
-            }
-        },
-        replay(url) {
-            if (jessibucaPlayer[this._uid]) {
-                jessibucaPlayer[this._uid].destroy().then(() => {
-                    this.initplayer();
-                    this.play(url);
-                });
-            } else {
-                this.initplayer();
-                this.play(url);
-            }
-        },
-        handlePtz(arrow) {
-            let leftRight = 0;
-            let upDown = 0;
-            if (arrow === 'left') {
-                leftRight = 2;
-            } else if (arrow === 'right') {
-                leftRight = 1;
-            } else if (arrow === 'up') {
-                upDown = 1;
-            } else if (arrow === 'down') {
-                upDown = 2;
-            }
-            var data = {
-                leftRight: leftRight,
-                upDown: upDown,
-                moveSpeed: 125,
-            };
-            if (this.playinfo && this.playinfo.playtype !== '') {
-                ptzdirection(this.playinfo.deviceId, this.playinfo.channelId, data).then(async (response) => {
-                    //console.log("云台方向控制:" + JSON.stringify(response));
-                });
-            }
-        },
-        playback(url, playTimes) {
-            if (jessibucaPlayer[this._uid]) {
-                jessibucaPlayer[this._uid].playback(url, {
-                    playList: playTimes,
-                    fps: 25, //FPS(定频(本地设置)生效)
-                    showControl: true,
-                    showRateBtn: true,
-                    isUseFpsRender: true, // 是否使用固定的fps渲染,如果设置的fps小于流推过来的,会造成内存堆积甚至溢出
-                    isCacheBeforeDecodeForFpsRender: false, // rfs渲染时,是否在解码前缓存数据
-                    supportWheel: true, // 是否支持滚动轴切换精度。
-                    rateConfig: [
-                        {label: '正常', value: 1},
-                        {label: '2倍', value: 2},
-                        {label: '4倍', value: 4},
-                        {label: '8倍', value: 8},
-                    ],
-                });
-                this.isPlaybackPause = false;
-            }
-        },
-        playbackPause() {
-            if (jessibucaPlayer[this._uid]) {
-                jessibucaPlayer[this._uid].playbackPause();
-                this.isPlaybackPause = true;
-            }
-        },
-        replayback(url, playTimes) {
-            if (jessibucaPlayer[this._uid]) {
-                jessibucaPlayer[this._uid].destroy().then(() => {
-                    this.initplayer();
-                    this.playback(url, playTimes);
-                });
-            } else {
-                this.initplayer();
-                this.playback(url, playTimes);
-            }
-        },
-        setPlaybackStartTime(curTime) {
-            if (jessibucaPlayer[this._uid]) {
-                jessibucaPlayer[this._uid].setPlaybackStartTime(curTime);
-            }
-        },
-        destroy() {
-            if (jessibucaPlayer[this._uid]) {
-                jessibucaPlayer[this._uid].destroy().then(() => {
-                    this.initplayer();
-                });
-            }
-        },
-        close() {
-            if (jessibucaPlayer[this._uid]) {
-                jessibucaPlayer[this._uid].close();
-            }
-        },
-    },
-};
+<script setup>
+import { ref, reactive, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'
+import { ptzdirection, ptzscale } from '@/api/pms/video/sipdevice'
+
+// 定义props
+const props = defineProps({
+  playerinfo: {
+    type: Object,
+    default: null,
+  },
+  width: {
+    type: String,
+    default: '1000px'
+  },
+  height: {
+    type: String,
+    default: '630px'
+  }
+})
+
+// 定义响应式数据
+const containerRef = ref(null)
+const isPlaybackPause = ref(false)
+const useWebGPU = ref(false)
+const isInit = ref(false)
+const playinfo = ref({})
+const playtype = ref('play')
+
+const operateBtns = reactive({
+  fullscreen: true,
+  zoom: true,
+  play: true,
+  audio: true,
+})
+
+// jessibucaPlayer实例存储
+let jessibucaPlayer = {}
+
+// Watch playerinfo变化
+watch(() => props.playerinfo, (newVal, oldVal) => {
+  console.log('playerinfo 发生变化')
+  playinfo.value = newVal
+  if (newVal && newVal.playtype !== '') {
+    playtype.value = newVal.playtype
+  }
+})
+
+// 组件挂载时执行
+onMounted(() => {
+  console.log("component mounted")
+  playinfo.value = props.playerinfo
+  if (playinfo.value && playinfo.value.playtype !== '') {
+    playtype.value = playinfo.value.playtype
+  }
+  init()
+})
+
+// 组件销毁前执行
+onBeforeUnmount(() => {
+  // 清理资源
+  if (jessibucaPlayer[currentInstanceId.value]) {
+    jessibucaPlayer[currentInstanceId.value].destroy()
+    delete jessibucaPlayer[currentInstanceId.value]
+  }
+})
+
+// 实例ID
+const currentInstanceId = ref(`player_${Date.now()}_${Math.floor(Math.random() * 10000)}`)
+
+// 初始化
+const init = () => {
+  var isSupportWebgpu = 'gpu' in navigator
+  if (isSupportWebgpu) {
+    console.log('支持webGPU')
+    useWebGPU.value = true
+  } else {
+    console.log('暂不支持webGPU,降级到webgl渲染')
+    useWebGPU.value = false
+  }
+
+  const useVconsole = isMobile() || isPad()
+  if (useVconsole && window.VConsole) {
+    new window.VConsole()
+  }
+  
+  nextTick(() => {
+    initplayer()
+  })
+}
+
+// 初始化播放器
+const initplayer = () => {
+  isPlaybackPause.value = false
+  initconf()
+  
+  jessibucaPlayer[currentInstanceId.value] = new window.JessibucaPro({
+    container: containerRef.value,
+    decoder: '/js/jessibuca-pro/decoder-pro.js',
+    videoBuffer: Number(0.2), // 缓存时长
+    isResize: false,
+    useWCS: false,
+    useMSE: false,
+    useSIMD: true,
+    wcsUseVideoRender: false,
+    loadingText: '加载中',
+    debug: false,
+    debugLevel: "debug",
+    showBandwidth: true, // 显示网速
+    showPlaybackOperate: true,
+    operateBtns: { ...operateBtns },
+    forceNoOffscreen: true,
+    isNotMute: true, // 默认关闭声音
+    showPerformance: false,
+    // playFailedAndReplay: true,
+    // networkDelayTimeoutReplay: true,
+    playbackForwardMaxRateDecodeIFrame: 4,
+    useWebGPU: useWebGPU.value, // 使用WebGPU
+  })
+  
+  let jessibuca = jessibucaPlayer[currentInstanceId.value]
+  initcallback(jessibuca)
+  isInit.value = true
+}
+
+// 初始化配置
+const initconf = () => {
+  if (playtype.value === 'play') {
+    //直播按钮配置
+    operateBtns.ptz = true
+  } else {
+    //录像回放按钮配置
+    operateBtns.ptz = false
+  }
+}
+
+// 初始化回调
+const initcallback = (jessibuca) => {
+  jessibuca.on('error', function (error) {
+    console.log('jessibuca error', error)
+  })
+  
+  jessibuca.on("playFailedAndPaused", function (reason, lastFrameInfo, msg) {
+    console.log('playFailedAndPaused', reason, msg)
+  })
+  
+  jessibuca.on('visibilityChange', (value) => {
+    if (value === true) {
+      // 窗口显示
+      console.log('visibilityChange true')
+    } else {
+      // 窗口隐藏
+      console.log('visibilityChange false')
+    }
+  })
+  
+  jessibuca.on('pause', function (pause) {
+    console.log('pause success!', pause)
+  })
+  
+  jessibuca.on('play', function (flag) {
+    console.log('play!', flag)
+  })
+  
+  jessibuca.on('loading', function (load) {
+    console.log('loading success!', load)
+  })
+  
+  jessibuca.on('stats', function (s) {
+    // console.log('stats is', s)
+  })
+  
+  jessibuca.on('timeout', function (error) {
+    console.log('timeout:', error)
+  })
+  
+  jessibuca.on('playbackPreRateChange', (rate) => {
+    jessibuca.forward(rate)
+  })
+
+  let pre = 0
+  let cur = 0
+  jessibuca.on('timeUpdate', function (ts) {
+    cur = parseInt(ts / 60000)
+    if (pre !== cur) {
+      pre++
+    }
+  })
+  
+  jessibuca.on(window.JessibucaPro.EVENTS.ptz, (arrow) => {
+    console.log('ptz arrow', arrow)
+    handlePtz(arrow)
+  })
+  
+  jessibuca.on('crashLog', (data) => {
+    console.log('crashLog is', data)
+  })
+}
+
+// 注册回调
+const registercallback = (events, func) => {
+  if (jessibucaPlayer[currentInstanceId.value]) {
+    jessibucaPlayer[currentInstanceId.value].on(events, func)
+  }
+}
+
+// 判断是否为移动设备
+const isMobile = () => {
+  return /iphone|ipad|android.*mobile|windows.*phone|blackberry.*mobile/i.test(window.navigator.userAgent.toLowerCase())
+}
+
+// 判断是否为平板设备
+const isPad = () => {
+  return /ipad|android(?!.*mobile)|tablet|kindle|silk/i.test(window.navigator.userAgent.toLowerCase())
+}
+
+// 播放
+const play = (url) => {
+  if (jessibucaPlayer[currentInstanceId.value]) {
+    jessibucaPlayer[currentInstanceId.value].play(url)
+  }
+}
+
+// 暂停
+const pause = () => {
+  if (jessibucaPlayer[currentInstanceId.value]) {
+    jessibucaPlayer[currentInstanceId.value].pause()
+  }
+}
+
+// 重新播放
+const replay = (url) => {
+  if (jessibucaPlayer[currentInstanceId.value]) {
+    jessibucaPlayer[currentInstanceId.value].destroy().then(() => {
+      initplayer()
+      play(url)
+    })
+  } else {
+    initplayer()
+    play(url)
+  }
+}
+
+// 处理PTZ控制
+const handlePtz = (arrow) => {
+  let leftRight = 0
+  let upDown = 0
+  if (arrow === 'left') {
+    leftRight = 2
+  } else if (arrow === 'right') {
+    leftRight = 1
+  } else if (arrow === 'up') {
+    upDown = 1
+  } else if (arrow === 'down') {
+    upDown = 2
+  }
+  
+  var data = {
+    leftRight: leftRight,
+    upDown: upDown,
+    moveSpeed: 125,
+  }
+  
+  if (playinfo.value && playinfo.value.playtype !== '') {
+    ptzdirection(playinfo.value.deviceId, playinfo.value.channelId, data).then(async (response) => {
+      //console.log("云台方向控制:" + JSON.stringify(response))
+    })
+  }
+}
+
+// 回放
+const playback = (url, playTimes) => {
+  if (jessibucaPlayer[currentInstanceId.value]) {
+    jessibucaPlayer[currentInstanceId.value].playback(url, {
+      playList: playTimes,
+      fps: 25, //FPS(定频(本地设置)生效)
+      showControl: true,
+      showRateBtn: true,
+      isUseFpsRender: true, // 是否使用固定的fps渲染,如果设置的fps小于流推过来的,会造成内存堆积甚至溢出
+      isCacheBeforeDecodeForFpsRender: false, // rfs渲染时,是否在解码前缓存数据
+      supportWheel: true, // 是否支持滚动轴切换精度。
+      rateConfig: [
+        {label: '正常', value: 1},
+        {label: '2倍', value: 2},
+        {label: '4倍', value: 4},
+        {label: '8倍', value: 8},
+      ],
+    })
+    isPlaybackPause.value = false
+  }
+}
+
+// 暂停回放
+const playbackPause = () => {
+  if (jessibucaPlayer[currentInstanceId.value]) {
+    jessibucaPlayer[currentInstanceId.value].playbackPause()
+    isPlaybackPause.value = true
+  }
+}
+
+// 重新回放
+const replayback = (url, playTimes) => {
+  if (jessibucaPlayer[currentInstanceId.value]) {
+    jessibucaPlayer[currentInstanceId.value].destroy().then(() => {
+      initplayer()
+      playback(url, playTimes)
+    })
+  } else {
+    initplayer()
+    playback(url, playTimes)
+  }
+}
+
+// 设置回放开始时间
+const setPlaybackStartTime = (curTime) => {
+  if (jessibucaPlayer[currentInstanceId.value]) {
+    jessibucaPlayer[currentInstanceId.value].setPlaybackStartTime(curTime)
+  }
+}
+
+// 销毁播放器
+const destroy = () => {
+  if (jessibucaPlayer[currentInstanceId.value]) {
+    jessibucaPlayer[currentInstanceId.value].destroy().then(() => {
+      initplayer()
+    })
+  }
+}
+
+// 关闭播放器
+const close = () => {
+  if (jessibucaPlayer[currentInstanceId.value]) {
+    jessibucaPlayer[currentInstanceId.value].close()
+  }
+}
+
+// 暴露给父组件的方法
+defineExpose({
+  play,
+  pause,
+  replay,
+  playback,
+  playbackPause,
+  replayback,
+  setPlaybackStartTime,
+  destroy,
+  close,
+  registercallback
+})
 </script>
 
 <style scoped lang="scss">
 .root {
-    display: flex;
-    margin-right: 3rem;
+  display: flex;
+  margin-right: 3rem;
 }
 
 .container-shell {
-    backdrop-filter: blur(5px);
-    // background: hsla(0, 0%, 50%, 0.5);
-    //background: #fff;
-    //padding: 10px 4px 10px 4px;
-    /* border: 2px solid black; */
-    // width: auto;
-    position: relative;
-    border-radius: 10px;
-    // box-shadow: 0 5px 5px;
+  backdrop-filter: blur(5px);
+  position: relative;
+  border-radius: 10px;
 }
 
 .container-shell:before {
-    //content: "设备播放器";
-    position: absolute;
-    color: darkgray;
-    //top: 4px;
-    left: 10px;
-    //text-shadow: 1px 1px black;
+  position: absolute;
+  color: darkgray;
+  left: 10px;
 }
 
 #container {
-    background: rgba(13, 14, 27, 0.7);
-    border-radius: 5px;
+  background: rgba(13, 14, 27, 0.7);
+  border-radius: 5px;
 }
 
 .err {
-    position: absolute;
-    top: 40px;
-    left: 10px;
-    color: red;
+  position: absolute;
+  top: 40px;
+  left: 10px;
+  color: red;
 }
 
 .option {
-    position: absolute;
-    top: 4px;
-    right: 10px;
-    display: flex;
-    place-content: center;
-    font-size: 12px;
+  position: absolute;
+  top: 4px;
+  right: 10px;
+  display: flex;
+  place-content: center;
+  font-size: 12px;
 }
 
 .option span {
-    color: white;
+  color: white;
 }
 
 @media (max-width: 720px) {
-    #container {
-        width: 90vw;
-        height: 52.7vw;
-    }
+  #container {
+    width: 90vw;
+    height: 52.7vw;
+  }
 }
-</style>
+</style>

+ 12 - 12
src/views/pms/video_center/sip/index.vue

@@ -260,84 +260,84 @@ const rules = {
     protocol: [
         {
             required: true,
-            message: t('sip.index.998533-26'),
+            message: t('sip.index998533-26'),
             trigger: 'blur',
         },
     ],
     ip: [
         {
             required: true,
-            message: t('sip.index.998533-27'),
+            message: t('sip.index998533-27'),
             trigger: 'blur',
         },
     ],
     domain: [
         {
             required: true,
-            message: t('sip.index.998533-28'),
+            message: t('sip.index998533-28'),
             trigger: 'blur',
         },
     ],
     secret: [
         {
             required: true,
-            message: t('sip.index.998533-29'),
+            message: t('sip.index998533-29'),
             trigger: 'blur',
         },
     ],
     portHttp: [
         {
             required: true,
-            message: t('sip.index.998533-30'),
+            message: t('sip.index998533-30'),
             trigger: 'blur',
         },
     ],
     portHttps: [
         {
             required: true,
-            message: t('sip.index.998533-31'),
+            message: t('sip.index998533-31'),
             trigger: 'blur',
         },
     ],
     portRtmp: [
         {
             required: true,
-            message: t('sip.index.998533-32'),
+            message: t('sip.index998533-32'),
             trigger: 'blur',
         },
     ],
     portRtsp: [
         {
             required: true,
-            message: t('sip.index.998533-33'),
+            message: t('sip.index998533-33'),
             trigger: 'blur',
         },
     ],
     rtpPortRange: [
         {
             required: true,
-            message: t('sip.index.998533-34'),
+            message: t('sip.index998533-34'),
             trigger: 'blur',
         },
     ],
     delFlag: [
         {
             required: true,
-            message: t('sip.index.998533-35'),
+            message: t('sip.index998533-35'),
             trigger: 'blur',
         },
     ],
     createBy: [
         {
             required: true,
-            message: t('sip.index.998533-36'),
+            message: t('sip.index998533-36'),
             trigger: 'blur',
         },
     ],
     createTime: [
         {
             required: true,
-            message: t('sip.index.998533-37'),
+            message: t('sip.index998533-37'),
             trigger: 'blur',
         },
     ],

+ 8 - 7
src/views/pms/video_center/sip/mediaServer-edit.vue

@@ -269,7 +269,7 @@ const rules = reactive({
 const setDialogWidth = () => {
   let val = document.body.clientWidth
   if (val < defaultWidth.value) {
-    dialogWidth.value = '100%'
+    dialogWidth.value = '80%'
   } else {
     dialogWidth.value = defaultWidth.value + 'px'
   }
@@ -323,8 +323,8 @@ const checkServer = () => {
       checkmediaServer(query)
         .then((response) => {
           btnLoading.value = false
-          if (response.data != null) {
-            Object.assign(mediaServerForm, response.data)
+          if (response != null) {
+            Object.assign(mediaServerForm, response)
             mediaServerForm.autoConfig = true
             mediaServerForm.rtpEnable = true
             mediaServerForm.protocol = 'http'
@@ -345,7 +345,7 @@ const checkServer = () => {
             ElMessage.success(t('sip.mediaServerEdit998534-26'))
           } else {
             serverCheck.value = -1
-           ElMessage.error(t('sip.mediaServerEdit998534-27'))
+            ElMessage.error(t('sip.mediaServerEdit998534-27'))
           }
         })
         .catch((error) => {
@@ -389,19 +389,20 @@ const onSubmit = () => {
   if (mediaServerForm.id != null) {
     updatemediaServer(mediaServerForm).then((response) => {
       ElMessage.success('更新成功')
+      emit('getServerList')
+      emit('delay')
       showDialog.value = false
     })
   } else {
     portRangeChange()
     addmediaServer(mediaServerForm).then((response) => {
       ElMessage.success('添加成功')
+      emit('getServerList')
+      emit('delay')
       showDialog.value = false
     })
   }
 
-  emit('getServerList')
-  emit('delay')
-
 }
 
 // 关闭对话框

+ 10 - 53
src/views/pms/video_center/sip/mediaServer.vue

@@ -11,9 +11,7 @@
           
           >{{ t('sip.mediaServer998535-0') }}</el-button
         >
-        <el-button type="warning" plain :icon="Refresh" size="small" @click="getServerList">{{
-          t('refresh')
-        }}</el-button>
+        <el-button type="warning" plain :icon="Refresh" size="small" @click="getServerList">刷新</el-button>
       </div>
       <el-row :gutter="30">
         <el-col
@@ -177,54 +175,12 @@ const pageSizeChange = (val) => {
 const getServerList = () => {
   loading.value = true
   // 获取服务器列表: 实际要用的
-  // listmediaServer(queryParams).then((response) => {
-  //   mediaServerList.value = response.rows
-  //   total.value = response.total
-  //   loading.value = false
-  // })
-
-  // 测试数据
-  setTimeout(() => {
-    mediaServerList.value = [
-      {
-        id: 1,
-        serverId: '1',
-        ip: '192.168.1.1',
-        protocol: 'rtmp',
-        createTime: 1696118400000
-      },
-      {
-        id: 2,
-        serverId: '2',
-        ip: '192.168.1.2',
-        protocol: 'rtmp',
-        createTime: 1696118400000
-      },
-      {
-        id: 3,
-        serverId: '3',
-        ip: '192.168.1.3',
-        protocol: 'rtmp',
-        createTime: 1696118400000
-      },
-      {
-        id: 4,
-        serverId: '4',
-        ip: '192.168.1.4',
-        protocol: 'rtmp',
-        createTime: 1696118400000
-      },
-      {
-        id: 5,
-        serverId: '5',
-        ip: '192.168.1.5',
-        protocol: 'rtmp',
-        createTime: 1696118400000
-      }
-    ]
-    total.value = 5
+  listmediaServer(queryParams).then((response) => {
+    mediaServerList.value = response.list
+    total.value = response.total
     loading.value = false
-  }, 1000)
+  })
+
 }
 
 // 添加
@@ -264,11 +220,12 @@ const delay = () => {
 const del = (row) => {
   const ids = row.id // 这里原代码有问题,应该是row.id而不是this.ids
   ElMessageBox.confirm(t('sip.mediaServer998535-7', [ids]))
-    .then(function () {
-      delmediaServer(ids)
+    .then(async function () {
+     await delmediaServer(ids)
+      await getServerList()
     })
     .then(() => {
-      getServerList()
+     
       ElMessage.success('删除成功')
     })
     .catch(() => {})

+ 152 - 101
src/views/pms/video_center/sip/sipidGen.vue

@@ -1,120 +1,171 @@
 <template>
-  <el-dialog :title="title" :visible.sync="open" append-to-body width="400px">
-    <el-form ref="createForm" :model="createForm" label-width="100px">
-      <el-form-item :label="$t('sip.sipidGen.998538-0')">
-        <el-cascader v-model="createForm.city" :options="cityOptions" change-on-select @change="changeProvince">
-        </el-cascader>
+  <el-dialog :title="title" v-model="open" append-to-body width="400px">
+    <el-form ref="createFormRef" :model="createForm" label-width="100px">
+      <el-form-item :label="t('sip.sipidGen998538-0')">
+        <el-cascader 
+          v-model="createForm.city" 
+          :options="cityOptions" 
+          :props="{ checkStrictly: true }"
+          @change="changeProvince" />
+       
       </el-form-item>
-      <el-form-item :label="$t('sip.index.998533-9')" prop="deviceType">
-        <el-select v-model="createForm.deviceType" :placeholder="$t('sip.index.998533-14')">
-          <el-option v-for="dict in dict.type.video_type" :key="dict.value" :label="dict.label"
-                     :value="dict.value"></el-option>
+      <el-form-item :label="t('sip.index998533-9')" prop="deviceType">
+        <el-select v-model="createForm.deviceType" :placeholder="t('sip.index998533-14')">
+          <el-option 
+            v-for="dict in video_type" 
+            :key="dict.value" 
+            :label="dict.label"
+            :value="dict.value" />
+          
         </el-select>
       </el-form-item>
-      <el-form-item :label="$t('sip.index.998533-15')" prop="channelType">
-        <el-select v-model="createForm.channelType" :placeholder="$t('sip.index.998533-16')">
-          <el-option v-for="dict in dict.type.channel_type" :key="dict.value" :label="dict.label"
-                     :value="dict.value"></el-option>
+      <el-form-item :label="t('sip.index998533-15')" prop="channelType">
+        <el-select v-model="createForm.channelType" :placeholder="t('sip.index998533-16')">
+          <el-option 
+            v-for="dict in channel_type" 
+            :key="dict.value" 
+            :label="dict.label"
+            :value="dict.value" />
+      
         </el-select>
       </el-form-item>
-      <el-form-item :label="$t('sip.index.998533-20')" prop="createNum">
-        <el-input-number v-model="createForm.createNum" :placeholder="$t('sip.index.998533-19')"
-                         controls-position="right" style="width:220px;" type="number"/>
+      <el-form-item :label="t('sip.index998533-20')" prop="createNum">
+        <el-input-number 
+          v-model="createForm.createNum" 
+          :placeholder="t('sip.index998533-19')"
+          controls-position="right" 
+          style="width:220px;" 
+          type="number"/>
       </el-form-item>
     </el-form>
-    <div slot="footer" class="dialog-footer">
-      <el-button type="primary" @click="submitForm">{{ $t('sip.index.998533-21') }}</el-button>
-      <el-button @click="closeDialog">{{ $t('cancel') }}</el-button>
-    </div>
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button type="primary" @click="submitForm">{{ t('sip.index998533-21') }}</el-button>
+        <el-button @click="closeDialog">取消</el-button>
+      </div>
+    </template>
   </el-dialog>
 </template>
 
-<script>
-import {
-  regionData,
-  CodeToText
-} from 'element-china-area-data'
+<script setup>
+import { ref, reactive, onMounted } from 'vue'
+import {regionData, codeToText} from 'element-china-area-data'
+import { addChannel } from "@/api/pms/video/channel"
+import { ElMessage } from 'element-plus'
+import { getDicts } from '@/api/pms/video/dicts'
 
-import { addChannel } from "@/api/pms/video/channel";
 
-export default {
+// i18n
+const { t } = useI18n()
+
+// 定义属性
+const props = defineProps({
+  product: {
+    type: Object,
+    default: null
+  }
+})
+
+// 定义事件
+const emit = defineEmits(['addGenEvent'])
+
+// 定义组件名称和字典
+defineOptions({
   name: "SipidDialog",
-  dicts: ['video_type', 'channel_type'],
-  props: {
-    product: {
-      type: Object,
-      default: null
-    }
-  },
-  data() {
-    return {
-      // 遮罩层
-      loading: true,
-      title: this.$t('sip.sipidGen.998538-1'),
-      // 总条数
-      total: 0,
-      // 打开选择产品对话框
-      open: false,
-      devsipid: "",
-      createForm: {
-        city: '',
-        deviceType: '',
-        channelType: '',
-        createNum: 1,
-      },
-      // 城市
-      cityOptions: regionData,
-      city: '',
-      cityCode: '',
-    };
-  },
-  created() {
-
-  },
-  methods: {
-    /** 行政区划改变 **/
-    changeProvince(data) {
-      if (data && data[0] != null && data[1] != null && data[2] != null) {
-        const str = CodeToText[data[0]] + '/' + CodeToText[data[1]] + '/' + CodeToText[data[2]];
-        this.createForm.citycode = str;
-      }
-    },
-    /** 提交按钮 */
-    submitForm() {
-      if (this.createForm.createNum < 1) {
-        this.$modal.alertError(this.$t('sip.index.998533-42'));
-        return;
-      }
-      this.createForm.productId = this.product.productId;
-      this.createForm.productName = this.product.productName;
-      this.createForm.tenantId = this.product.tenantId;
-      this.createForm.tenantName = this.product.tenantName;
-      this.createForm.deviceSipId = this.createForm.city[2] + "0000" + this.createForm.deviceType + "0"
-      this.createForm.channelSipId = this.createForm.city[2] + "0000" + this.createForm.channelType + "0"
-      if (this.createForm.deviceType !== "" && this.createForm.channelType !== "" && this.createForm.city.length === 3) {
-        addChannel(this.createForm.createNum, this.createForm).then(response => {
-          this.$modal.msgSuccess(this.$t('sip.sipidGen.998538-2'));
-          this.devsipid = response.data;
-          this.confirmSelectProduct();
-        });
-      } else {
-        this.$message({
-          type: 'error',
-          message: this.$t('sip.sipidGen.998538-3')
-        });
-      }
-
-    },
-    confirmSelectProduct() {
-      this.open = false;
-      this.$emit('addGenEvent', this.devsipid);
-    },
-    /**关闭对话框 */
-    closeDialog() {
-      this.open = false;
+})
+
+const video_type = ref([])
+const channel_type = ref([])
+
+// Refs
+const createFormRef = ref()
+
+// Reactive data
+const loading = ref(true)
+const title = t('sip.sipidGen998538-1')
+const total = ref(0)
+const open = defineModel('open')
+const devsipid = ref("")
+const cityOptions = regionData
+const city = ref('')
+const cityCode = ref('')
+
+const createForm = reactive({
+  city: '',
+  deviceType: '',
+  channelType: '',
+  createNum: 1,
+  citycode: '',
+  productId: '',
+  productName: '',
+  tenantId: '',
+  tenantName: '',
+  deviceSipId: '',
+  channelSipId: ''
+})
+
+// Methods
+/** 行政区划改变 **/
+const changeProvince = (data) => {
+  if (data && data[0] != null && data[1] != null && data[2] != null) {
+    const str = codeToText[data[0]] + '/' + codeToText[data[1]] + '/' + codeToText[data[2]]
+    createForm.citycode = str
+  }
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  if (createForm.createNum < 1) {
+    ElMessage.error(t('sip.index998533-42'))
+    return
+  }
+  
+  createForm.productId = props.product.productId
+  createForm.productName = props.product.productName
+  createForm.tenantId = props.product.tenantId
+  createForm.tenantName = props.product.tenantName
+  
+  if (createForm.city && createForm.city.length >= 3) {
+    createForm.deviceSipId = createForm.city[2] + "0000" + createForm.deviceType + "0"
+    createForm.channelSipId = createForm.city[2] + "0000" + createForm.channelType + "0"
+    
+    if (createForm.deviceType !== "" && createForm.channelType !== "" && createForm.city.length === 3) {
+      addChannel(createForm.createNum, createForm).then(response => {
+        ElMessage.success(t('sip.sipidGen998538-2'))
+        devsipid.value = response
+        confirmSelectProduct()
+      })
+    } else {
+      ElMessage.error(t('sip.sipidGen998538-3'))
     }
+  } else {
+    ElMessage.error(t('sip.sipidGen998538-3'))
   }
 }
+
+const confirmSelectProduct = () => {
+  open.value = false
+  emit('addGenEvent', devsipid.value)
+}
+
+/**关闭对话框 */
+const closeDialog = () => {
+  open.value = false
+}
+
+defineExpose({
+  open
+})
+
+onMounted(() => {
+  getDicts('video_type').then((response) => {
+    video_type.value = response
+  })
+
+    getDicts('channel_type').then((response) => {
+    channel_type.value = response
+  })
+})
 </script>
 
-<style scoped></style>
+<style scoped></style>