diff --git a/src/api/system/resource.ts b/src/api/system/resource.ts index 3b3d55c..894750d 100644 --- a/src/api/system/resource.ts +++ b/src/api/system/resource.ts @@ -10,12 +10,13 @@ }) } // 资源查询 -export function getResourceListByRole(roleId: string) { +export function getResourceListByRole(roleId: string, bizType: string) { return request({ url: `${prefix}/resource/treeListByRoleId`, method: 'get', params: { roleId, + bizType }, }) } diff --git a/src/api/system/resource.ts b/src/api/system/resource.ts index 3b3d55c..894750d 100644 --- a/src/api/system/resource.ts +++ b/src/api/system/resource.ts @@ -10,12 +10,13 @@ }) } // 资源查询 -export function getResourceListByRole(roleId: string) { +export function getResourceListByRole(roleId: string, bizType: string) { return request({ url: `${prefix}/resource/treeListByRoleId`, method: 'get', params: { roleId, + bizType }, }) } diff --git a/src/router/modules/monitor.ts b/src/router/modules/monitor.ts index 5d45895..f5f0190 100644 --- a/src/router/modules/monitor.ts +++ b/src/router/modules/monitor.ts @@ -22,8 +22,8 @@ // import('@/views/monitor/realTime/index-noPlugin-single.vue'), // SDK单路 // import('@/views/monitor/realTime/index-noPlugin.vue'), // SDK4路 // import('@/views/monitor/realTime/index-isc-single.vue'), // isc - import('@/views/monitor/realTime/index-media-single.vue'), // 商流媒体单路 - // import('@/views/monitor/realTime/index-new-gm-plugin.vue'), // 国 + // import('@/views/monitor/realTime/index-media-single.vue'), // 商流媒体单路 + import('@/views/monitor/realTime/index-new-gm-plugin.vue'), // 国 meta: { title: '实时监控', auth: '/realTime', diff --git a/src/api/system/resource.ts b/src/api/system/resource.ts index 3b3d55c..894750d 100644 --- a/src/api/system/resource.ts +++ b/src/api/system/resource.ts @@ -10,12 +10,13 @@ }) } // 资源查询 -export function getResourceListByRole(roleId: string) { +export function getResourceListByRole(roleId: string, bizType: string) { return request({ url: `${prefix}/resource/treeListByRoleId`, method: 'get', params: { roleId, + bizType }, }) } diff --git a/src/router/modules/monitor.ts b/src/router/modules/monitor.ts index 5d45895..f5f0190 100644 --- a/src/router/modules/monitor.ts +++ b/src/router/modules/monitor.ts @@ -22,8 +22,8 @@ // import('@/views/monitor/realTime/index-noPlugin-single.vue'), // SDK单路 // import('@/views/monitor/realTime/index-noPlugin.vue'), // SDK4路 // import('@/views/monitor/realTime/index-isc-single.vue'), // isc - import('@/views/monitor/realTime/index-media-single.vue'), // 商流媒体单路 - // import('@/views/monitor/realTime/index-new-gm-plugin.vue'), // 国 + // import('@/views/monitor/realTime/index-media-single.vue'), // 商流媒体单路 + import('@/views/monitor/realTime/index-new-gm-plugin.vue'), // 国 meta: { title: '实时监控', auth: '/realTime', diff --git a/src/views/alarm/policyConfig/videoPreview/videoPreview.vue b/src/views/alarm/policyConfig/videoPreview/videoPreview.vue index 983a636..4280c58 100644 --- a/src/views/alarm/policyConfig/videoPreview/videoPreview.vue +++ b/src/views/alarm/policyConfig/videoPreview/videoPreview.vue @@ -501,11 +501,68 @@ } }) +/** + * 向 type 为 '1' 的组织对象中注入设备统计字段(仅统计叶子节点设备) + * @param {Array} data - 包含组织和设备节点的 JSON 数组 + * @returns {Array} 修改后的原始数据数组(直接修改对象引用) + */ + function injectDeviceCounts(data: any[]): any { + // ---------------------- 步骤 1:构建组织节点映射表 ---------------------- // + const orgMap = new Map() // 使用 Map 存储组织节点,便于快速查找 + + // 遍历所有节点,筛选出 type 为 '1' 的组织节点,并初始化统计字段 + data.forEach((node) => { + if (node.type === '1') { + node.totalDevices = 0 // 设备总数 + node.onlineDevices = 0 // 在线设备数 + orgMap.set(node.id, node) // 以 id 为键存入 Map + } + }) + + // ---------------------- 步骤 2:递归统计叶子节点设备 ---------------------- // + /** + * 递归函数:遍历节点,仅当节点为叶子节点(无 children)时视为设备 + * @param {Object} node - 当前遍历的节点(组织或设备) + */ + function traverse(node: { children: any[]; device: { deviceStatus: number }; pid: any; nodeParentId: any; type: string }) { + // ---------------------- 判断是否为叶子节点设备 ---------------------- // + // 条件:无 children 或 children 为空数组,且存在 device 字段 + if ((!node.children || node.children.length === 0) && node.device) { + const parentOrgId = node.pid || node.nodeParentId // 获取父组织 ID(优先使用 pid) + const parentOrg = orgMap.get(parentOrgId) // 从映射表中查找父组织 + + if (parentOrg) { + parentOrg.totalDevices++ // 设备总数 +1 + if (node.device.deviceStatus === 1) { + parentOrg.onlineDevices++ // 在线设备数 +1(状态为 1 时) + } + } + } + + // ---------------------- 递归处理子节点(仅组织节点需要处理子节点) ---------------------- // + if (node.type === '1' && node.children) { // 仅当节点是组织且有子节点时递归 + node.children.forEach((child) => { + traverse(child) // 递归处理子节点 + }) + } + } + + // ---------------------- 步骤 3:从顶级组织开始递归统计 ---------------------- // + data.forEach((node) => { + if (node.type === '1') { // 仅从组织节点开始递归,避免直接处理设备节点 + traverse(node) + } + }) + + return data // 返回修改后的原始数据 +} + onMounted(() => { systemType.value = window.localStorage.getItem('systemType') as string videoTree().then((response) => { if (response.code === 200) { data.value = response.data + data.value = injectDeviceCounts(data.value) } }) if (systemType.value === 'sm') { @@ -557,6 +614,10 @@ + + + ({{ data.onlineDevices }}/{{ data.totalDevices }}) + { + if (node.type === '1') { + node.totalDevices = 0 // 设备总数 + node.onlineDevices = 0 // 在线设备数 + orgMap.set(node.id, node) // 以 id 为键存入 Map + } + }) + + // ---------------------- 步骤 2:递归统计叶子节点设备 ---------------------- // + /** + * 递归函数:遍历节点,仅当节点为叶子节点(无 children)时视为设备 + * @param {Object} node - 当前遍历的节点(组织或设备) + */ + function traverse(node: { children: any[]; device: { deviceStatus: number }; pid: any; nodeParentId: any; type: string }) { + // ---------------------- 判断是否为叶子节点设备 ---------------------- // + // 条件:无 children 或 children 为空数组,且存在 device 字段 + if ((!node.children || node.children.length === 0) && node.device) { + const parentOrgId = node.pid || node.nodeParentId // 获取父组织 ID(优先使用 pid) + const parentOrg = orgMap.get(parentOrgId) // 从映射表中查找父组织 + + if (parentOrg) { + parentOrg.totalDevices++ // 设备总数 +1 + if (node.device.deviceStatus === 1) { + parentOrg.onlineDevices++ // 在线设备数 +1(状态为 1 时) + } + } + } + + // ---------------------- 递归处理子节点(仅组织节点需要处理子节点) ---------------------- // + if (node.type === '1' && node.children) { // 仅当节点是组织且有子节点时递归 + node.children.forEach((child) => { + traverse(child) // 递归处理子节点 + }) + } + } + + // ---------------------- 步骤 3:从顶级组织开始递归统计 ---------------------- // + data.forEach((node) => { + if (node.type === '1') { // 仅从组织节点开始递归,避免直接处理设备节点 + traverse(node) + } + }) + + return data // 返回修改后的原始数据 +} + onMounted(() => { systemType.value = window.localStorage.getItem('systemType') as string videoTree().then((response) => { if (response.code === 200) { data.value = response.data + data.value = injectDeviceCounts(data.value) } }) if (systemType.value === 'sm') { @@ -557,6 +614,10 @@ + + + ({{ data.onlineDevices }}/{{ data.totalDevices }}) + { console.log('play触发播放事件') + // 实现把插件原有截图提醒改成抓拍两字 + if (props.showOperateBtns) { + const screenshotBtn = $container.querySelector('.jessibuca-screenshot') + if (screenshotBtn) { + screenshotBtn.title = '抓拍' + + // 修改按钮内的文本 + const textElement = screenshotBtn.querySelector('.icon-title') + if (textElement) { + textElement.textContent = '抓拍' + } + } + } }) jessibuca.on('playToRenderTimes', (times) => { console.log('监听调用play方法 经过 初始化-> 网络请求-> 解封装 -> 解码 -> 渲染 一系列过程的时间消耗:', times) }) + + // 监听播放器就绪事件,修改截图按钮的提示文字 + jessibuca.on('ready', () => { + console.log('=====监听播放器就绪事件======'); + if (props.showOperateBtns) { + const screenshotBtn = $container.querySelector('.jessibuca-screenshot') + if (screenshotBtn) { + screenshotBtn.title = '抓拍' + } + } + }) } // 获取视频流地址并播放视频 diff --git a/src/api/system/resource.ts b/src/api/system/resource.ts index 3b3d55c..894750d 100644 --- a/src/api/system/resource.ts +++ b/src/api/system/resource.ts @@ -10,12 +10,13 @@ }) } // 资源查询 -export function getResourceListByRole(roleId: string) { +export function getResourceListByRole(roleId: string, bizType: string) { return request({ url: `${prefix}/resource/treeListByRoleId`, method: 'get', params: { roleId, + bizType }, }) } diff --git a/src/router/modules/monitor.ts b/src/router/modules/monitor.ts index 5d45895..f5f0190 100644 --- a/src/router/modules/monitor.ts +++ b/src/router/modules/monitor.ts @@ -22,8 +22,8 @@ // import('@/views/monitor/realTime/index-noPlugin-single.vue'), // SDK单路 // import('@/views/monitor/realTime/index-noPlugin.vue'), // SDK4路 // import('@/views/monitor/realTime/index-isc-single.vue'), // isc - import('@/views/monitor/realTime/index-media-single.vue'), // 商流媒体单路 - // import('@/views/monitor/realTime/index-new-gm-plugin.vue'), // 国 + // import('@/views/monitor/realTime/index-media-single.vue'), // 商流媒体单路 + import('@/views/monitor/realTime/index-new-gm-plugin.vue'), // 国 meta: { title: '实时监控', auth: '/realTime', diff --git a/src/views/alarm/policyConfig/videoPreview/videoPreview.vue b/src/views/alarm/policyConfig/videoPreview/videoPreview.vue index 983a636..4280c58 100644 --- a/src/views/alarm/policyConfig/videoPreview/videoPreview.vue +++ b/src/views/alarm/policyConfig/videoPreview/videoPreview.vue @@ -501,11 +501,68 @@ } }) +/** + * 向 type 为 '1' 的组织对象中注入设备统计字段(仅统计叶子节点设备) + * @param {Array} data - 包含组织和设备节点的 JSON 数组 + * @returns {Array} 修改后的原始数据数组(直接修改对象引用) + */ + function injectDeviceCounts(data: any[]): any { + // ---------------------- 步骤 1:构建组织节点映射表 ---------------------- // + const orgMap = new Map() // 使用 Map 存储组织节点,便于快速查找 + + // 遍历所有节点,筛选出 type 为 '1' 的组织节点,并初始化统计字段 + data.forEach((node) => { + if (node.type === '1') { + node.totalDevices = 0 // 设备总数 + node.onlineDevices = 0 // 在线设备数 + orgMap.set(node.id, node) // 以 id 为键存入 Map + } + }) + + // ---------------------- 步骤 2:递归统计叶子节点设备 ---------------------- // + /** + * 递归函数:遍历节点,仅当节点为叶子节点(无 children)时视为设备 + * @param {Object} node - 当前遍历的节点(组织或设备) + */ + function traverse(node: { children: any[]; device: { deviceStatus: number }; pid: any; nodeParentId: any; type: string }) { + // ---------------------- 判断是否为叶子节点设备 ---------------------- // + // 条件:无 children 或 children 为空数组,且存在 device 字段 + if ((!node.children || node.children.length === 0) && node.device) { + const parentOrgId = node.pid || node.nodeParentId // 获取父组织 ID(优先使用 pid) + const parentOrg = orgMap.get(parentOrgId) // 从映射表中查找父组织 + + if (parentOrg) { + parentOrg.totalDevices++ // 设备总数 +1 + if (node.device.deviceStatus === 1) { + parentOrg.onlineDevices++ // 在线设备数 +1(状态为 1 时) + } + } + } + + // ---------------------- 递归处理子节点(仅组织节点需要处理子节点) ---------------------- // + if (node.type === '1' && node.children) { // 仅当节点是组织且有子节点时递归 + node.children.forEach((child) => { + traverse(child) // 递归处理子节点 + }) + } + } + + // ---------------------- 步骤 3:从顶级组织开始递归统计 ---------------------- // + data.forEach((node) => { + if (node.type === '1') { // 仅从组织节点开始递归,避免直接处理设备节点 + traverse(node) + } + }) + + return data // 返回修改后的原始数据 +} + onMounted(() => { systemType.value = window.localStorage.getItem('systemType') as string videoTree().then((response) => { if (response.code === 200) { data.value = response.data + data.value = injectDeviceCounts(data.value) } }) if (systemType.value === 'sm') { @@ -557,6 +614,10 @@ + + + ({{ data.onlineDevices }}/{{ data.totalDevices }}) + { console.log('play触发播放事件') + // 实现把插件原有截图提醒改成抓拍两字 + if (props.showOperateBtns) { + const screenshotBtn = $container.querySelector('.jessibuca-screenshot') + if (screenshotBtn) { + screenshotBtn.title = '抓拍' + + // 修改按钮内的文本 + const textElement = screenshotBtn.querySelector('.icon-title') + if (textElement) { + textElement.textContent = '抓拍' + } + } + } }) jessibuca.on('playToRenderTimes', (times) => { console.log('监听调用play方法 经过 初始化-> 网络请求-> 解封装 -> 解码 -> 渲染 一系列过程的时间消耗:', times) }) + + // 监听播放器就绪事件,修改截图按钮的提示文字 + jessibuca.on('ready', () => { + console.log('=====监听播放器就绪事件======'); + if (props.showOperateBtns) { + const screenshotBtn = $container.querySelector('.jessibuca-screenshot') + if (screenshotBtn) { + screenshotBtn.title = '抓拍' + } + } + }) } // 获取视频流地址并播放视频 diff --git a/src/views/monitor/realTime/index-media-single.vue b/src/views/monitor/realTime/index-media-single.vue index d8a40c7..0330607 100644 --- a/src/views/monitor/realTime/index-media-single.vue +++ b/src/views/monitor/realTime/index-media-single.vue @@ -29,6 +29,8 @@ const loading = ref(false) const src = ref(['']) const title = ref('') +const loadingTest = ref('视频加载中,请稍等...') +const showLoadingText = ref(false) const leafLoading = ref(false) const currentLeafId = ref('') const currentData = ref() // 当前播放视频的设备信息 @@ -72,10 +74,13 @@ currentIndex = 0 // ElMessage.warning('正在加载流,请稍等!') leafLoading.value = true + showLoadingText.value = true + loadingTest.value = '视频加载中,请稍等...' currentLeafId.value = data.device.id // 获取视频流接口 fetchMediaStream(data.device.cameraIndexCode, data.device.nvrIndexCode).then((res: any) => { leafLoading.value = false + showLoadingText.value = false src.value[currentIndex] = `${res}?token=${window.localStorage.getItem('token')}` jessibucaRef.value.play(src.value[currentIndex]) currentCameras[currentIndex] = data @@ -86,6 +91,7 @@ }).catch(() => { ElMessage.warning('未获取到流!请联系管理员!') leafLoading.value = false + loadingTest.value = '未获取到流!请联系管理员!' }) } treeClickCount = now @@ -138,10 +144,68 @@ return data } + +/** + * 向 type 为 '1' 的组织对象中注入设备统计字段(仅统计叶子节点设备) + * @param {Array} data - 包含组织和设备节点的 JSON 数组 + * @returns {Array} 修改后的原始数据数组(直接修改对象引用) + */ + function injectDeviceCounts(data: any[]): any { + // ---------------------- 步骤 1:构建组织节点映射表 ---------------------- // + const orgMap = new Map() // 使用 Map 存储组织节点,便于快速查找 + + // 遍历所有节点,筛选出 type 为 '1' 的组织节点,并初始化统计字段 + data.forEach((node) => { + if (node.type === '1') { + node.totalDevices = 0 // 设备总数 + node.onlineDevices = 0 // 在线设备数 + orgMap.set(node.id, node) // 以 id 为键存入 Map + } + }) + + // ---------------------- 步骤 2:递归统计叶子节点设备 ---------------------- // + /** + * 递归函数:遍历节点,仅当节点为叶子节点(无 children)时视为设备 + * @param {Object} node - 当前遍历的节点(组织或设备) + */ + function traverse(node: { children: any[]; device: { deviceStatus: number }; pid: any; nodeParentId: any; type: string }) { + // ---------------------- 判断是否为叶子节点设备 ---------------------- // + // 条件:无 children 或 children 为空数组,且存在 device 字段 + if ((!node.children || node.children.length === 0) && node.device) { + const parentOrgId = node.pid || node.nodeParentId // 获取父组织 ID(优先使用 pid) + const parentOrg = orgMap.get(parentOrgId) // 从映射表中查找父组织 + + if (parentOrg) { + parentOrg.totalDevices++ // 设备总数 +1 + if (node.device.deviceStatus === 1) { + parentOrg.onlineDevices++ // 在线设备数 +1(状态为 1 时) + } + } + } + + // ---------------------- 递归处理子节点(仅组织节点需要处理子节点) ---------------------- // + if (node.type === '1' && node.children) { // 仅当节点是组织且有子节点时递归 + node.children.forEach((child) => { + traverse(child) // 递归处理子节点 + }) + } + } + + // ---------------------- 步骤 3:从顶级组织开始递归统计 ---------------------- // + data.forEach((node) => { + if (node.type === '1') { // 仅从组织节点开始递归,避免直接处理设备节点 + traverse(node) + } + }) + + return data // 返回修改后的原始数据 +} + onMounted(() => { videoTree().then((response) => { if (response.code === 200) { data.value = response.data + data.value = injectDeviceCounts(data.value) // data.value = solveData(data.value) } }) @@ -217,6 +281,10 @@ + + + ({{ data.onlineDevices }}/{{ data.totalDevices }}) +
- 视频加载中,请稍等... + {{ loadingTest }}
diff --git a/src/api/system/resource.ts b/src/api/system/resource.ts index 3b3d55c..894750d 100644 --- a/src/api/system/resource.ts +++ b/src/api/system/resource.ts @@ -10,12 +10,13 @@ }) } // 资源查询 -export function getResourceListByRole(roleId: string) { +export function getResourceListByRole(roleId: string, bizType: string) { return request({ url: `${prefix}/resource/treeListByRoleId`, method: 'get', params: { roleId, + bizType }, }) } diff --git a/src/router/modules/monitor.ts b/src/router/modules/monitor.ts index 5d45895..f5f0190 100644 --- a/src/router/modules/monitor.ts +++ b/src/router/modules/monitor.ts @@ -22,8 +22,8 @@ // import('@/views/monitor/realTime/index-noPlugin-single.vue'), // SDK单路 // import('@/views/monitor/realTime/index-noPlugin.vue'), // SDK4路 // import('@/views/monitor/realTime/index-isc-single.vue'), // isc - import('@/views/monitor/realTime/index-media-single.vue'), // 商流媒体单路 - // import('@/views/monitor/realTime/index-new-gm-plugin.vue'), // 国 + // import('@/views/monitor/realTime/index-media-single.vue'), // 商流媒体单路 + import('@/views/monitor/realTime/index-new-gm-plugin.vue'), // 国 meta: { title: '实时监控', auth: '/realTime', diff --git a/src/views/alarm/policyConfig/videoPreview/videoPreview.vue b/src/views/alarm/policyConfig/videoPreview/videoPreview.vue index 983a636..4280c58 100644 --- a/src/views/alarm/policyConfig/videoPreview/videoPreview.vue +++ b/src/views/alarm/policyConfig/videoPreview/videoPreview.vue @@ -501,11 +501,68 @@ } }) +/** + * 向 type 为 '1' 的组织对象中注入设备统计字段(仅统计叶子节点设备) + * @param {Array} data - 包含组织和设备节点的 JSON 数组 + * @returns {Array} 修改后的原始数据数组(直接修改对象引用) + */ + function injectDeviceCounts(data: any[]): any { + // ---------------------- 步骤 1:构建组织节点映射表 ---------------------- // + const orgMap = new Map() // 使用 Map 存储组织节点,便于快速查找 + + // 遍历所有节点,筛选出 type 为 '1' 的组织节点,并初始化统计字段 + data.forEach((node) => { + if (node.type === '1') { + node.totalDevices = 0 // 设备总数 + node.onlineDevices = 0 // 在线设备数 + orgMap.set(node.id, node) // 以 id 为键存入 Map + } + }) + + // ---------------------- 步骤 2:递归统计叶子节点设备 ---------------------- // + /** + * 递归函数:遍历节点,仅当节点为叶子节点(无 children)时视为设备 + * @param {Object} node - 当前遍历的节点(组织或设备) + */ + function traverse(node: { children: any[]; device: { deviceStatus: number }; pid: any; nodeParentId: any; type: string }) { + // ---------------------- 判断是否为叶子节点设备 ---------------------- // + // 条件:无 children 或 children 为空数组,且存在 device 字段 + if ((!node.children || node.children.length === 0) && node.device) { + const parentOrgId = node.pid || node.nodeParentId // 获取父组织 ID(优先使用 pid) + const parentOrg = orgMap.get(parentOrgId) // 从映射表中查找父组织 + + if (parentOrg) { + parentOrg.totalDevices++ // 设备总数 +1 + if (node.device.deviceStatus === 1) { + parentOrg.onlineDevices++ // 在线设备数 +1(状态为 1 时) + } + } + } + + // ---------------------- 递归处理子节点(仅组织节点需要处理子节点) ---------------------- // + if (node.type === '1' && node.children) { // 仅当节点是组织且有子节点时递归 + node.children.forEach((child) => { + traverse(child) // 递归处理子节点 + }) + } + } + + // ---------------------- 步骤 3:从顶级组织开始递归统计 ---------------------- // + data.forEach((node) => { + if (node.type === '1') { // 仅从组织节点开始递归,避免直接处理设备节点 + traverse(node) + } + }) + + return data // 返回修改后的原始数据 +} + onMounted(() => { systemType.value = window.localStorage.getItem('systemType') as string videoTree().then((response) => { if (response.code === 200) { data.value = response.data + data.value = injectDeviceCounts(data.value) } }) if (systemType.value === 'sm') { @@ -557,6 +614,10 @@ + + + ({{ data.onlineDevices }}/{{ data.totalDevices }}) + { console.log('play触发播放事件') + // 实现把插件原有截图提醒改成抓拍两字 + if (props.showOperateBtns) { + const screenshotBtn = $container.querySelector('.jessibuca-screenshot') + if (screenshotBtn) { + screenshotBtn.title = '抓拍' + + // 修改按钮内的文本 + const textElement = screenshotBtn.querySelector('.icon-title') + if (textElement) { + textElement.textContent = '抓拍' + } + } + } }) jessibuca.on('playToRenderTimes', (times) => { console.log('监听调用play方法 经过 初始化-> 网络请求-> 解封装 -> 解码 -> 渲染 一系列过程的时间消耗:', times) }) + + // 监听播放器就绪事件,修改截图按钮的提示文字 + jessibuca.on('ready', () => { + console.log('=====监听播放器就绪事件======'); + if (props.showOperateBtns) { + const screenshotBtn = $container.querySelector('.jessibuca-screenshot') + if (screenshotBtn) { + screenshotBtn.title = '抓拍' + } + } + }) } // 获取视频流地址并播放视频 diff --git a/src/views/monitor/realTime/index-media-single.vue b/src/views/monitor/realTime/index-media-single.vue index d8a40c7..0330607 100644 --- a/src/views/monitor/realTime/index-media-single.vue +++ b/src/views/monitor/realTime/index-media-single.vue @@ -29,6 +29,8 @@ const loading = ref(false) const src = ref(['']) const title = ref('') +const loadingTest = ref('视频加载中,请稍等...') +const showLoadingText = ref(false) const leafLoading = ref(false) const currentLeafId = ref('') const currentData = ref() // 当前播放视频的设备信息 @@ -72,10 +74,13 @@ currentIndex = 0 // ElMessage.warning('正在加载流,请稍等!') leafLoading.value = true + showLoadingText.value = true + loadingTest.value = '视频加载中,请稍等...' currentLeafId.value = data.device.id // 获取视频流接口 fetchMediaStream(data.device.cameraIndexCode, data.device.nvrIndexCode).then((res: any) => { leafLoading.value = false + showLoadingText.value = false src.value[currentIndex] = `${res}?token=${window.localStorage.getItem('token')}` jessibucaRef.value.play(src.value[currentIndex]) currentCameras[currentIndex] = data @@ -86,6 +91,7 @@ }).catch(() => { ElMessage.warning('未获取到流!请联系管理员!') leafLoading.value = false + loadingTest.value = '未获取到流!请联系管理员!' }) } treeClickCount = now @@ -138,10 +144,68 @@ return data } + +/** + * 向 type 为 '1' 的组织对象中注入设备统计字段(仅统计叶子节点设备) + * @param {Array} data - 包含组织和设备节点的 JSON 数组 + * @returns {Array} 修改后的原始数据数组(直接修改对象引用) + */ + function injectDeviceCounts(data: any[]): any { + // ---------------------- 步骤 1:构建组织节点映射表 ---------------------- // + const orgMap = new Map() // 使用 Map 存储组织节点,便于快速查找 + + // 遍历所有节点,筛选出 type 为 '1' 的组织节点,并初始化统计字段 + data.forEach((node) => { + if (node.type === '1') { + node.totalDevices = 0 // 设备总数 + node.onlineDevices = 0 // 在线设备数 + orgMap.set(node.id, node) // 以 id 为键存入 Map + } + }) + + // ---------------------- 步骤 2:递归统计叶子节点设备 ---------------------- // + /** + * 递归函数:遍历节点,仅当节点为叶子节点(无 children)时视为设备 + * @param {Object} node - 当前遍历的节点(组织或设备) + */ + function traverse(node: { children: any[]; device: { deviceStatus: number }; pid: any; nodeParentId: any; type: string }) { + // ---------------------- 判断是否为叶子节点设备 ---------------------- // + // 条件:无 children 或 children 为空数组,且存在 device 字段 + if ((!node.children || node.children.length === 0) && node.device) { + const parentOrgId = node.pid || node.nodeParentId // 获取父组织 ID(优先使用 pid) + const parentOrg = orgMap.get(parentOrgId) // 从映射表中查找父组织 + + if (parentOrg) { + parentOrg.totalDevices++ // 设备总数 +1 + if (node.device.deviceStatus === 1) { + parentOrg.onlineDevices++ // 在线设备数 +1(状态为 1 时) + } + } + } + + // ---------------------- 递归处理子节点(仅组织节点需要处理子节点) ---------------------- // + if (node.type === '1' && node.children) { // 仅当节点是组织且有子节点时递归 + node.children.forEach((child) => { + traverse(child) // 递归处理子节点 + }) + } + } + + // ---------------------- 步骤 3:从顶级组织开始递归统计 ---------------------- // + data.forEach((node) => { + if (node.type === '1') { // 仅从组织节点开始递归,避免直接处理设备节点 + traverse(node) + } + }) + + return data // 返回修改后的原始数据 +} + onMounted(() => { videoTree().then((response) => { if (response.code === 200) { data.value = response.data + data.value = injectDeviceCounts(data.value) // data.value = solveData(data.value) } }) @@ -217,6 +281,10 @@ + + + ({{ data.onlineDevices }}/{{ data.totalDevices }}) +
- 视频加载中,请稍等... + {{ loadingTest }}
diff --git a/src/views/monitor/realTime/index-new-gm-plugin.vue b/src/views/monitor/realTime/index-new-gm-plugin.vue index eb8a20c..836d14f 100644 --- a/src/views/monitor/realTime/index-new-gm-plugin.vue +++ b/src/views/monitor/realTime/index-new-gm-plugin.vue @@ -12,7 +12,7 @@ const treeRef = ref(null) as any const filterText = ref('') const data = ref([]) - +const loadingTest = ref('视频加载中,请稍等...') const defaultProps = ref({ children: 'children', label: 'name', @@ -29,6 +29,7 @@ const src = ref(['']) const title = ref('') const leafLoading = ref(false) +const showLoadingText = ref(false) const currentLeafId = ref('') const currentStreamId = ref('') // 正在播的流的国标号 const resize = () => { @@ -73,8 +74,9 @@ return } - // ElMessage.warning('正在加载流,请稍等!') leafLoading.value = true + showLoadingText.value = true + loadingTest.value = '视频加载中,请稍等...' currentLeafId.value = data.device.id // 先停心跳 @@ -89,6 +91,7 @@ // 获取视频流接口 fetchStream(data.device.cameraIndexCode).then((res: any) => { leafLoading.value = false + showLoadingText.value = false const { url, createStreamResponseId } = res src.value[0] = `${url}?token=${window.localStorage.getItem('token')}` jessibucaRef.value.play(src.value[0]) @@ -106,6 +109,7 @@ }).catch(() => { ElMessage.warning('未获取到流!请联系管理员!') leafLoading.value = false + loadingTest.value = '未获取到流!请联系管理员!' }) } treeClickCount = now @@ -188,10 +192,70 @@ return data } +/** + * 向 type 为 '1' 的组织对象中注入设备统计字段(仅统计叶子节点设备) + * @param {Array} data - 包含组织和设备节点的 JSON 数组 + * @returns {Array} 修改后的原始数据数组(直接修改对象引用) + */ +function injectDeviceCounts(data: any[]): any { + // ---------------------- 步骤 1:构建组织节点映射表 ---------------------- // + const orgMap = new Map() // 使用 Map 存储组织节点,便于快速查找 + + // 遍历所有节点,筛选出 type 为 '1' 的组织节点,并初始化统计字段 + data.forEach((node) => { + if (node.type === '1') { + node.totalDevices = 0 // 设备总数 + node.onlineDevices = 0 // 在线设备数 + orgMap.set(node.id, node) // 以 id 为键存入 Map + } + }) + + // ---------------------- 步骤 2:递归统计叶子节点设备 ---------------------- // + /** + * 递归函数:遍历节点,仅当节点为叶子节点(无 children)时视为设备 + * @param {Object} node - 当前遍历的节点(组织或设备) + */ + function traverse(node: { children: any[]; device: { deviceStatus: number }; pid: any; nodeParentId: any; type: string }) { + // ---------------------- 判断是否为叶子节点设备 ---------------------- // + // 条件:无 children 或 children 为空数组,且存在 device 字段 + if ((!node.children || node.children.length === 0) && node.device) { + const parentOrgId = node.pid || node.nodeParentId // 获取父组织 ID(优先使用 pid) + const parentOrg = orgMap.get(parentOrgId) // 从映射表中查找父组织 + + if (parentOrg) { + parentOrg.totalDevices++ // 设备总数 +1 + if (node.device.deviceStatus === 1) { + parentOrg.onlineDevices++ // 在线设备数 +1(状态为 1 时) + } + } + } + + // ---------------------- 递归处理子节点(仅组织节点需要处理子节点) ---------------------- // + if (node.type === '1' && node.children) { // 仅当节点是组织且有子节点时递归 + node.children.forEach((child) => { + traverse(child) // 递归处理子节点 + }) + } + } + + // ---------------------- 步骤 3:从顶级组织开始递归统计 ---------------------- // + data.forEach((node) => { + if (node.type === '1') { // 仅从组织节点开始递归,避免直接处理设备节点 + traverse(node) + } + }) + + return data // 返回修改后的原始数据 +} + onMounted(() => { videoTree().then((response) => { if (response.code === 200) { data.value = response.data + console.log('==============', data.value) + console.log('计算设备在线数', injectDeviceCounts(data.value)) + data.value = injectDeviceCounts(data.value) + // data.value = solveData(data.value) } }) @@ -256,8 +320,7 @@ >