From 0f5cb1d3c5890278951bb31d1b627b63143c5ecd Mon Sep 17 00:00:00 2001 From: guanj Date: Thu, 9 Apr 2026 11:44:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 4 +- src/layouts/admin/components/globalPopUp.vue | 82 +- src/utils/echartMethod.ts | 22 +- src/utils/tree.ts | 832 +++++++++--------- src/utils/webSocketClient.ts | 4 +- .../area/SteadyState/index.vue | 563 ++++++------ .../area/harmonicDistortionRate/index.vue | 534 +++++------ .../area/qualifiedRate/index.vue | 18 +- .../area/terminalonlinerate/index.vue | 744 ++++++++-------- .../detailed/overLabelDetails/index.vue | 23 +- .../embed/lntegruty/index_JB.vue | 6 +- .../embed/onlinerate/index_JB.vue | 4 +- .../online/shishishuju/index.vue | 46 +- .../components/Administration.vue | 4 +- 14 files changed, 1516 insertions(+), 1370 deletions(-) diff --git a/src/App.vue b/src/App.vue index ab119aff..9ba56761 100644 --- a/src/App.vue +++ b/src/App.vue @@ -13,9 +13,11 @@ onMounted(async () => { const response = await fetch('/') const WebSocketUrl:any = response.headers.get('X-WebSocket-Url') const WebSocketUrl2:any = response.headers.get('X-WebSocket-Url2') + const WebSocketUrl3:any = response.headers.get('X-WebSocket-Url3') const MqttUrl:any = response.headers.get('X-MqttUrl-Url') - localStorage.setItem('WebSocketUrl2', WebSocketUrl2) localStorage.setItem('WebSocketUrl', WebSocketUrl) + localStorage.setItem('WebSocketUrl2', WebSocketUrl2) + localStorage.setItem('WebSocketUrl3', WebSocketUrl3) localStorage.setItem('MqttUrl', MqttUrl) }) diff --git a/src/layouts/admin/components/globalPopUp.vue b/src/layouts/admin/components/globalPopUp.vue index 3e3ba2b7..745c4248 100644 --- a/src/layouts/admin/components/globalPopUp.vue +++ b/src/layouts/admin/components/globalPopUp.vue @@ -50,7 +50,8 @@ import { ref, reactive, onMounted } from 'vue' import { defaultAttribute } from '@/components/table/defaultAttribute' import { mainHeight } from '@/utils/layout' import { useDictData } from '@/stores/dictData' -import MQTT from '@/utils/mqtt' +// import MQTT from '@/utils/mqtt' +import socketClient from '@/utils/webSocketClient' const dictData = useDictData() const event = dictData.getBasicData('Event_Statis') import { useAdminInfo } from '@/stores/adminInfo' @@ -68,37 +69,68 @@ const handleClose = (done: any) => { drawer.value = false done() } -const init = async () => { - const mqttClient = new MQTT('/sendEvent') - // 设置消息接收回调 - try { - await mqttClient.init() +const dataSocket = reactive({ + socketServe: socketClient.Instance +}) +// const init = async () => { +// const mqttClient = new MQTT('/sendEvent') +// // 设置消息接收回调 +// try { +// await mqttClient.init() - // 订阅主题 - await mqttClient.subscribe() - // 设置消息接收回调 - mqttClient.onMessage((topic, message) => { - const msg = JSON.parse(message.toString()) - // console.log('🚀 ~ init ~ msg:', msg) - if (msg.deptList.includes(adminInfo.$state.deptId)) { - drawer.value = true - isLoading.value = true - eventList.value.unshift(msg) - setTimeout(() => { - isLoading.value = false - }, 500) - } - }) - } catch (error) { - // console.error('MQTT 初始化失败:', error) - } +// // 订阅主题 +// await mqttClient.subscribe() +// // 设置消息接收回调 +// mqttClient.onMessage((topic, message) => { +// const msg = JSON.parse(message.toString()) +// // console.log('🚀 ~ init ~ msg:', msg) +// if (msg.deptList.includes(adminInfo.$state.deptId)) { +// drawer.value = true +// isLoading.value = true +// eventList.value.unshift(msg) +// setTimeout(() => { +// isLoading.value = false +// }, 500) +// } +// }) +// } catch (error) { +// // console.error('MQTT 初始化失败:', error) +// } +// } +const socket = async () => { + // const url = localStorage.getItem('WebSocketUrl3') || 'ws://192.168.2.130:10203/event/' + const url = 'ws://192.168.2.130:10203/event/' + console.log('🚀 ~ socket ~ url:', url) + + await dataSocket.socketServe.connect(`${url}${adminInfo.id}`) + + await dataSocket.socketServe.registerCallBack('message', (res: any) => { + if (res.deptList.includes(adminInfo.$state.deptId)) { + drawer.value = true + isLoading.value = true + eventList.value.unshift(res) + setTimeout(() => { + isLoading.value = false + }, 500) + } + // logList.value.push({ + // type: res.code == 500 ? 'error' : '', + // time: formatDate(new Date(), 'YYYY-MM-DD hh:mm:ss'), + // name: res.message + // }) + }) } + +onUnmounted(() => { + dataSocket.socketServe?.closeWs() +}) + onMounted(() => { // startMqtt('/sendEvent', (topic, message) => { // const msg = JSON.parse(message.toString()) // console.log(msg) // }) - init() + socket() }) defineExpose({ open, diff --git a/src/utils/echartMethod.ts b/src/utils/echartMethod.ts index 408d7ddf..12dcd05c 100644 --- a/src/utils/echartMethod.ts +++ b/src/utils/echartMethod.ts @@ -11,6 +11,7 @@ const calculateValue = (o: number, value: number, num: number, isMin: boolean) = } else if (value > -1 && value < 0 && isMin == false) { return 0 } + let base if (Math.abs(o) >= 100) { base = 100 @@ -19,8 +20,11 @@ const calculateValue = (o: number, value: number, num: number, isMin: boolean) = } else if (Math.abs(o) >= 1) { base = 1 } else { - base = 0.1 + const multiple = 1 / 0.1 + + base = Math.ceil(Math.abs(o) * multiple) / multiple } + let calculatedValue if (isMin) { if (value < 0) { @@ -35,18 +39,19 @@ const calculateValue = (o: number, value: number, num: number, isMin: boolean) = calculatedValue = value + num * value } } + if (base === 0.1) { - return parseFloat(calculatedValue.toFixed(1)) + // return parseFloat(calculatedValue.toFixed(1)) + return Math.ceil(calculatedValue * 10) / 10 } else if (isMin) { return Math.floor(calculatedValue / base) * base } else { return Math.ceil(calculatedValue / base) * base } } - // 处理y轴最大最小值 export const yMethod = (arr: any) => { - let num = 0.1 + let num = 0.2 let numList = dataProcessing(arr) let maxValue = 0 let minValue = 0 @@ -54,12 +59,9 @@ export const yMethod = (arr: any) => { let min = 0 maxValue = Math.max(...numList) minValue = Math.min(...numList) - const o = maxValue - minValue - if (Math.abs(o) >= 300) { - num = 0.02 - } - + const o = maxValue - minValue == 0 ? maxValue : maxValue - minValue min = calculateValue(o, minValue, num, true) + max = calculateValue(o, maxValue, num, false) // if (-100 >= minValue) { // min = Math.floor((minValue + num * minValue) / 100) * 100 @@ -158,8 +160,6 @@ export const exportCSV = (title: object, data: any, filename: string) => { URL.revokeObjectURL(link.href) } - - /** * 补全时间序列数据中缺失的条目 * @param rawData 原始数据,格式为 [["时间字符串", "数值", "单位", "类型"], ...] diff --git a/src/utils/tree.ts b/src/utils/tree.ts index 91059ef9..29336356 100644 --- a/src/utils/tree.ts +++ b/src/utils/tree.ts @@ -1,400 +1,432 @@ -interface TreeHelperConfig { - id: string - children: string - pid: string -} - -const DEFAULT_CONFIG: TreeHelperConfig = { - id: 'id', - children: 'children', - pid: 'pid' -} -export const defaultProps = { - children: 'children', - label: 'name', - value: 'id', - isLeaf: 'leaf', - emitPath: false // 用于 cascader 组件:在选中节点改变时,是否返回由该节点所在的各级菜单的值所组成的数组,若设置 false,则只返回该节点的值 -} - -const getConfig = (config: Partial) => Object.assign({}, DEFAULT_CONFIG, config) - -// tree from list -export const listToTree = (list: any[], config: Partial = {}): T[] => { - const conf = getConfig(config) as TreeHelperConfig - const nodeMap = new Map() - const result: T[] = [] - const { id, children, pid } = conf - - for (const node of list) { - node[children] = node[children] || [] - nodeMap.set(node[id], node) - } - for (const node of list) { - const parent = nodeMap.get(node[pid]) - ;(parent ? parent.children : result).push(node) - } - return result -} - -export const treeToList = (tree: any, config: Partial = {}): T => { - config = getConfig(config) - const { children } = config - const result: any = [...tree] - for (let i = 0; i < result.length; i++) { - if (!result[i][children!]) continue - result.splice(i + 1, 0, ...result[i][children!]) - } - return result -} - -export const findNode = ( - tree: any, - func: Fn, - config: Partial = {} -): T | null => { - config = getConfig(config) - const { children } = config - const list = [...tree] - for (const node of list) { - if (func(node)) return node - node[children!] && list.push(...node[children!]) - } - return null -} - -export const findNodeAll = ( - tree: any, - func: Fn, - config: Partial = {} -): T[] => { - config = getConfig(config) - const { children } = config - const list = [...tree] - const result: T[] = [] - for (const node of list) { - func(node) && result.push(node) - node[children!] && list.push(...node[children!]) - } - return result -} - -export const findPath = ( - tree: any, - func: Fn, - config: Partial = {} -): T | T[] | null => { - config = getConfig(config) - const path: T[] = [] - const list = [...tree] - const visitedSet = new Set() - const { children } = config - while (list.length) { - const node = list[0] - if (visitedSet.has(node)) { - path.pop() - list.shift() - } else { - visitedSet.add(node) - node[children!] && list.unshift(...node[children!]) - path.push(node) - if (func(node)) { - return path - } - } - } - return null -} - -export const findPathAll = (tree: any, func: Fn, config: Partial = {}) => { - config = getConfig(config) - const path: any[] = [] - const list = [...tree] - const result: any[] = [] - const visitedSet = new Set(), - { children } = config - while (list.length) { - const node = list[0] - if (visitedSet.has(node)) { - path.pop() - list.shift() - } else { - visitedSet.add(node) - node[children!] && list.unshift(...node[children!]) - path.push(node) - func(node) && result.push([...path]) - } - } - return result -} - -export const filter = ( - tree: T[], - func: (n: T) => boolean, - config: Partial = {} -): T[] => { - config = getConfig(config) - const children = config.children as string - - function listFilter(list: T[]) { - return list - .map((node: any) => ({ ...node })) - .filter((node) => { - node[children] = node[children] && listFilter(node[children]) - return func(node) || (node[children] && node[children].length) - }) - } - - return listFilter(tree) -} - -export const forEach = ( - tree: T[], - func: (n: T) => any, - config: Partial = {} -): void => { - config = getConfig(config) - const list: any[] = [...tree] - const { children } = config - for (let i = 0; i < list.length; i++) { - // func 返回true就终止遍历,避免大量节点场景下无意义循环,引起浏览器卡顿 - if (func(list[i])) { - return - } - children && list[i][children] && list.splice(i + 1, 0, ...list[i][children]) - } -} - -/** - * @description: Extract tree specified structure - */ -export const treeMap = ( - treeData: T[], - opt: { children?: string; conversion: Fn } -): T[] => { - return treeData.map((item) => treeMapEach(item, opt)) -} - -/** - * @description: Extract tree specified structure - */ -export const treeMapEach = ( - data: any, - { children = 'children', conversion }: { children?: string; conversion: Fn } -) => { - const haveChildren = Array.isArray(data[children]) && data[children].length > 0 - const conversionData = conversion(data) || {} - if (haveChildren) { - return { - ...conversionData, - [children]: data[children].map((i: number) => - treeMapEach(i, { - children, - conversion - }) - ) - } - } else { - return { - ...conversionData - } - } -} - -/** - * 递归遍历树结构 - * @param treeDatas 树 - * @param callBack 回调 - * @param parentNode 父节点 - */ -export const eachTree = (treeDatas: any[], callBack: Fn, parentNode = {}) => { - treeDatas.forEach((element) => { - const newNode = callBack(element, parentNode) || element - if (element.children) { - eachTree(element.children, callBack, newNode) - } - }) -} - -/** - * 构造树型结构数据 - * @param {*} data 数据源 - * @param {*} id id字段 默认 'id' - * @param {*} parentId 父节点字段 默认 'parentId' - * @param {*} children 孩子节点字段 默认 'children' - */ -export const handleTree = (data: any[], id?: string, parentId?: string, children?: string) => { - if (!Array.isArray(data)) { - console.warn('data must be an array') - return [] - } - const config = { - id: id || 'id', - parentId: parentId || 'parentId', - childrenList: children || 'children' - } - - const childrenListMap = {} - const nodeIds = {} - const tree: any[] = [] - - for (const d of data) { - const parentId = d[config.parentId] - if (childrenListMap[parentId] == null) { - childrenListMap[parentId] = [] - } - nodeIds[d[config.id]] = d - childrenListMap[parentId].push(d) - } - - for (const d of data) { - const parentId = d[config.parentId] - if (nodeIds[parentId] == null) { - tree.push(d) - } - } - - for (const t of tree) { - adaptToChildrenList(t) - } - - function adaptToChildrenList(o) { - if (childrenListMap[o[config.id]] !== null) { - o[config.childrenList] = childrenListMap[o[config.id]] - } - if (o[config.childrenList]) { - for (const c of o[config.childrenList]) { - adaptToChildrenList(c) - } - } - } - - return tree -} - -/** - * 构造树型结构数据 - * @param {*} data 数据源 - * @param {*} id id字段 默认 'id' - * @param {*} parentId 父节点字段 默认 'parentId' - * @param {*} children 孩子节点字段 默认 'children' - * @param {*} rootId 根Id 默认 0 - */ -// @ts-ignore -export const handleTree2 = (data, id, parentId, children, rootId) => { - id = id || 'id' - parentId = parentId || 'parentId' - // children = children || 'children' - rootId = - rootId || - Math.min( - ...data.map((item) => { - return item[parentId] - }) - ) || - 0 - // 对源数据深度克隆 - const cloneData = JSON.parse(JSON.stringify(data)) - // 循环所有项 - const treeData = cloneData.filter((father) => { - const branchArr = cloneData.filter((child) => { - // 返回每一项的子级数组 - return father[id] === child[parentId] - }) - branchArr.length > 0 ? (father.children = branchArr) : '' - // 返回第一层 - return father[parentId] === rootId - }) - return treeData !== '' ? treeData : data -} - -/** - * 校验选中的节点,是否为指定 level - * - * @param tree 要操作的树结构数据 - * @param nodeId 需要判断在什么层级的数据 - * @param level 检查的级别, 默认检查到二级 - * @return true 是;false 否 - */ -export const checkSelectedNode = (tree: any[], nodeId: any, level = 2): boolean => { - if (typeof tree === 'undefined' || !Array.isArray(tree) || tree.length === 0) { - console.warn('tree must be an array') - return false - } - - // 校验是否是一级节点 - if (tree.some((item) => item.id === nodeId)) { - return false - } - - // 递归计数 - let count = 1 - - // 深层次校验 - function performAThoroughValidation(arr: any[]): boolean { - count += 1 - for (const item of arr) { - if (item.id === nodeId) { - return true - } else if (typeof item.children !== 'undefined' && item.children.length !== 0) { - if (performAThoroughValidation(item.children)) { - return true - } - } - } - return false - } - - for (const item of tree) { - count = 1 - if (performAThoroughValidation(item.children)) { - // 找到后对比是否是期望的层级 - if (count >= level) { - return true - } - } - } - - return false -} - -/** - * 获取节点的完整结构 - * @param tree 树数据 - * @param nodeId 节点 id - */ -export const treeToString = (tree: any[], nodeId) => { - if (typeof tree === 'undefined' || !Array.isArray(tree) || tree.length === 0) { - console.warn('tree must be an array') - return '' - } - // 校验是否是一级节点 - const node = tree.find((item) => item.id === nodeId) - if (typeof node !== 'undefined') { - return node.name - } - let str = '' - - function performAThoroughValidation(arr) { - for (const item of arr) { - if (item.id === nodeId) { - str += ` / ${item.name}` - return true - } else if (typeof item.children !== 'undefined' && item.children.length !== 0) { - str += ` / ${item.name}` - if (performAThoroughValidation(item.children)) { - return true - } - } - } - return false - } - - for (const item of tree) { - str = `${item.name}` - if (performAThoroughValidation(item.children)) { - break - } - } - return str -} +interface TreeHelperConfig { + id: string + children: string + pid: string +} + +const DEFAULT_CONFIG: TreeHelperConfig = { + id: 'id', + children: 'children', + pid: 'pid' +} +export const defaultProps = { + children: 'children', + label: 'name', + value: 'id', + isLeaf: 'leaf', + emitPath: false // 用于 cascader 组件:在选中节点改变时,是否返回由该节点所在的各级菜单的值所组成的数组,若设置 false,则只返回该节点的值 +} + +const getConfig = (config: Partial) => Object.assign({}, DEFAULT_CONFIG, config) + +// tree from list +export const listToTree = (list: any[], config: Partial = {}): T[] => { + const conf = getConfig(config) as TreeHelperConfig + const nodeMap = new Map() + const result: T[] = [] + const { id, children, pid } = conf + + for (const node of list) { + node[children] = node[children] || [] + nodeMap.set(node[id], node) + } + for (const node of list) { + const parent = nodeMap.get(node[pid]) + ;(parent ? parent.children : result).push(node) + } + return result +} + +export const treeToList = (tree: any, config: Partial = {}): T => { + config = getConfig(config) + const { children } = config + const result: any = [...tree] + for (let i = 0; i < result.length; i++) { + if (!result[i][children!]) continue + result.splice(i + 1, 0, ...result[i][children!]) + } + return result +} + +export const findNode = ( + tree: any, + func: Fn, + config: Partial = {} +): T | null => { + config = getConfig(config) + const { children } = config + const list = [...tree] + for (const node of list) { + if (func(node)) return node + node[children!] && list.push(...node[children!]) + } + return null +} + +export const findNodeAll = ( + tree: any, + func: Fn, + config: Partial = {} +): T[] => { + config = getConfig(config) + const { children } = config + const list = [...tree] + const result: T[] = [] + for (const node of list) { + func(node) && result.push(node) + node[children!] && list.push(...node[children!]) + } + return result +} + +export const findPath = ( + tree: any, + func: Fn, + config: Partial = {} +): T | T[] | null => { + config = getConfig(config) + const path: T[] = [] + const list = [...tree] + const visitedSet = new Set() + const { children } = config + while (list.length) { + const node = list[0] + if (visitedSet.has(node)) { + path.pop() + list.shift() + } else { + visitedSet.add(node) + node[children!] && list.unshift(...node[children!]) + path.push(node) + if (func(node)) { + return path + } + } + } + return null +} + +export const findPathAll = (tree: any, func: Fn, config: Partial = {}) => { + config = getConfig(config) + const path: any[] = [] + const list = [...tree] + const result: any[] = [] + const visitedSet = new Set(), + { children } = config + while (list.length) { + const node = list[0] + if (visitedSet.has(node)) { + path.pop() + list.shift() + } else { + visitedSet.add(node) + node[children!] && list.unshift(...node[children!]) + path.push(node) + func(node) && result.push([...path]) + } + } + return result +} + +export const filter = ( + tree: T[], + func: (n: T) => boolean, + config: Partial = {} +): T[] => { + config = getConfig(config) + const children = config.children as string + + function listFilter(list: T[]) { + return list + .map((node: any) => ({ ...node })) + .filter((node) => { + node[children] = node[children] && listFilter(node[children]) + return func(node) || (node[children] && node[children].length) + }) + } + + return listFilter(tree) +} +export const filterTree = ( + tree: T[], + func: (n: T) => boolean, + config: Partial = {} +): T[] => { + config = getConfig(config) + const children = config.children as string + + function listFilter(list: T[]) { + return list + .map((node: any) => ({ ...node })) + .filter((node) => { + // 1. 如果当前节点匹配 → 直接保留【所有子节点】,不再过滤下级 + if (func(node)) { + return true; + } + + // 2. 如果当前节点不匹配,递归过滤子节点 + if (node[children]) { + const filteredChildren = listFilter(node[children]); + if (filteredChildren.length > 0) { + node[children] = filteredChildren; + return true; + } + } + + // 3. 都不匹配,过滤掉 + return false; + }) + } + + return listFilter(tree) +} +export const forEach = ( + tree: T[], + func: (n: T) => any, + config: Partial = {} +): void => { + config = getConfig(config) + const list: any[] = [...tree] + const { children } = config + for (let i = 0; i < list.length; i++) { + // func 返回true就终止遍历,避免大量节点场景下无意义循环,引起浏览器卡顿 + if (func(list[i])) { + return + } + children && list[i][children] && list.splice(i + 1, 0, ...list[i][children]) + } +} + +/** + * @description: Extract tree specified structure + */ +export const treeMap = ( + treeData: T[], + opt: { children?: string; conversion: Fn } +): T[] => { + return treeData.map((item) => treeMapEach(item, opt)) +} + +/** + * @description: Extract tree specified structure + */ +export const treeMapEach = ( + data: any, + { children = 'children', conversion }: { children?: string; conversion: Fn } +) => { + const haveChildren = Array.isArray(data[children]) && data[children].length > 0 + const conversionData = conversion(data) || {} + if (haveChildren) { + return { + ...conversionData, + [children]: data[children].map((i: number) => + treeMapEach(i, { + children, + conversion + }) + ) + } + } else { + return { + ...conversionData + } + } +} + +/** + * 递归遍历树结构 + * @param treeDatas 树 + * @param callBack 回调 + * @param parentNode 父节点 + */ +export const eachTree = (treeDatas: any[], callBack: Fn, parentNode = {}) => { + treeDatas.forEach((element) => { + const newNode = callBack(element, parentNode) || element + if (element.children) { + eachTree(element.children, callBack, newNode) + } + }) +} + +/** + * 构造树型结构数据 + * @param {*} data 数据源 + * @param {*} id id字段 默认 'id' + * @param {*} parentId 父节点字段 默认 'parentId' + * @param {*} children 孩子节点字段 默认 'children' + */ +export const handleTree = (data: any[], id?: string, parentId?: string, children?: string) => { + if (!Array.isArray(data)) { + console.warn('data must be an array') + return [] + } + const config = { + id: id || 'id', + parentId: parentId || 'parentId', + childrenList: children || 'children' + } + + const childrenListMap = {} + const nodeIds = {} + const tree: any[] = [] + + for (const d of data) { + const parentId = d[config.parentId] + if (childrenListMap[parentId] == null) { + childrenListMap[parentId] = [] + } + nodeIds[d[config.id]] = d + childrenListMap[parentId].push(d) + } + + for (const d of data) { + const parentId = d[config.parentId] + if (nodeIds[parentId] == null) { + tree.push(d) + } + } + + for (const t of tree) { + adaptToChildrenList(t) + } + + function adaptToChildrenList(o) { + if (childrenListMap[o[config.id]] !== null) { + o[config.childrenList] = childrenListMap[o[config.id]] + } + if (o[config.childrenList]) { + for (const c of o[config.childrenList]) { + adaptToChildrenList(c) + } + } + } + + return tree +} + +/** + * 构造树型结构数据 + * @param {*} data 数据源 + * @param {*} id id字段 默认 'id' + * @param {*} parentId 父节点字段 默认 'parentId' + * @param {*} children 孩子节点字段 默认 'children' + * @param {*} rootId 根Id 默认 0 + */ +// @ts-ignore +export const handleTree2 = (data, id, parentId, children, rootId) => { + id = id || 'id' + parentId = parentId || 'parentId' + // children = children || 'children' + rootId = + rootId || + Math.min( + ...data.map((item) => { + return item[parentId] + }) + ) || + 0 + // 对源数据深度克隆 + const cloneData = JSON.parse(JSON.stringify(data)) + // 循环所有项 + const treeData = cloneData.filter((father) => { + const branchArr = cloneData.filter((child) => { + // 返回每一项的子级数组 + return father[id] === child[parentId] + }) + branchArr.length > 0 ? (father.children = branchArr) : '' + // 返回第一层 + return father[parentId] === rootId + }) + return treeData !== '' ? treeData : data +} + +/** + * 校验选中的节点,是否为指定 level + * + * @param tree 要操作的树结构数据 + * @param nodeId 需要判断在什么层级的数据 + * @param level 检查的级别, 默认检查到二级 + * @return true 是;false 否 + */ +export const checkSelectedNode = (tree: any[], nodeId: any, level = 2): boolean => { + if (typeof tree === 'undefined' || !Array.isArray(tree) || tree.length === 0) { + console.warn('tree must be an array') + return false + } + + // 校验是否是一级节点 + if (tree.some((item) => item.id === nodeId)) { + return false + } + + // 递归计数 + let count = 1 + + // 深层次校验 + function performAThoroughValidation(arr: any[]): boolean { + count += 1 + for (const item of arr) { + if (item.id === nodeId) { + return true + } else if (typeof item.children !== 'undefined' && item.children.length !== 0) { + if (performAThoroughValidation(item.children)) { + return true + } + } + } + return false + } + + for (const item of tree) { + count = 1 + if (performAThoroughValidation(item.children)) { + // 找到后对比是否是期望的层级 + if (count >= level) { + return true + } + } + } + + return false +} + +/** + * 获取节点的完整结构 + * @param tree 树数据 + * @param nodeId 节点 id + */ +export const treeToString = (tree: any[], nodeId) => { + if (typeof tree === 'undefined' || !Array.isArray(tree) || tree.length === 0) { + console.warn('tree must be an array') + return '' + } + // 校验是否是一级节点 + const node = tree.find((item) => item.id === nodeId) + if (typeof node !== 'undefined') { + return node.name + } + let str = '' + + function performAThoroughValidation(arr) { + for (const item of arr) { + if (item.id === nodeId) { + str += ` / ${item.name}` + return true + } else if (typeof item.children !== 'undefined' && item.children.length !== 0) { + str += ` / ${item.name}` + if (performAThoroughValidation(item.children)) { + return true + } + } + } + return false + } + + for (const item of tree) { + str = `${item.name}` + if (performAThoroughValidation(item.children)) { + break + } + } + return str +} diff --git a/src/utils/webSocketClient.ts b/src/utils/webSocketClient.ts index 93d42dc6..b34bc053 100644 --- a/src/utils/webSocketClient.ts +++ b/src/utils/webSocketClient.ts @@ -104,7 +104,7 @@ export default class SocketService { // 通过接受服务端发送的type字段来回调函数 - if ((message.key || message.code) && this.callBackMapping['message']) { + if ((message.key || message.code || message.time) && this.callBackMapping['message']) { this.callBackMapping['message']!(message) } else { console.log('抛弃====>') @@ -112,7 +112,7 @@ export default class SocketService { // 丢弃或继续写你的逻辑 } } else { - ElMessage.error(event.data) + // ElMessage.error(event.data) } } diff --git a/src/views/pqs/harmonicMonitoring/area/SteadyState/index.vue b/src/views/pqs/harmonicMonitoring/area/SteadyState/index.vue index 98b5a336..f36d4846 100644 --- a/src/views/pqs/harmonicMonitoring/area/SteadyState/index.vue +++ b/src/views/pqs/harmonicMonitoring/area/SteadyState/index.vue @@ -1,274 +1,289 @@ - - - + + + diff --git a/src/views/pqs/harmonicMonitoring/area/harmonicDistortionRate/index.vue b/src/views/pqs/harmonicMonitoring/area/harmonicDistortionRate/index.vue index 3a19f9b5..f115362b 100644 --- a/src/views/pqs/harmonicMonitoring/area/harmonicDistortionRate/index.vue +++ b/src/views/pqs/harmonicMonitoring/area/harmonicDistortionRate/index.vue @@ -1,259 +1,275 @@ - - - + + + diff --git a/src/views/pqs/harmonicMonitoring/area/qualifiedRate/index.vue b/src/views/pqs/harmonicMonitoring/area/qualifiedRate/index.vue index 0f7e8ce1..615a770b 100644 --- a/src/views/pqs/harmonicMonitoring/area/qualifiedRate/index.vue +++ b/src/views/pqs/harmonicMonitoring/area/qualifiedRate/index.vue @@ -83,6 +83,14 @@ /> + + + @@ -113,6 +121,7 @@ import TableHeader from '@/components/table/header/index.vue' import TableStore from '@/utils/tableStore' import Table from '@/components/table/index.vue' import charts from './components/charts.vue' +import { filterTree } from '@/utils/tree' defineOptions({ name: 'harmonic-boot/area/qualifiedRate' }) @@ -272,7 +281,13 @@ const tableStore = new TableStore({ ], loadCallback: () => { - tableStore.table.data = tree2List(tableStore.table.data, Math.random() * 1000) + tableStore.table.data = tree2List( + filterTree(tableStore.table.data, node => { + // 筛选条件:name 包含关键词 + return node.name.includes(tableStore.table.params.searchValue) + }), + Math.random() * 1000 + ) tableStore.table.column[0].title = tableStore.table.params.statisticalType.name chartsRef.value && chartsRef.value.getTableStoreParams(tableStore.table.params) @@ -288,6 +303,7 @@ tableStore.table.params.manufacturer = [] tableStore.table.params.loadType = [] tableStore.table.params.serverName = 'harmonicBoot' tableStore.table.params.powerFlag = sign[0]?.algoDescribe || 0 +tableStore.table.params.searchValue = '' provide('tableStore', tableStore) // const tree2List = (list: any, pid?: string) => { // //存储结果的数组 diff --git a/src/views/pqs/harmonicMonitoring/area/terminalonlinerate/index.vue b/src/views/pqs/harmonicMonitoring/area/terminalonlinerate/index.vue index 3a3ae10b..998c1a9c 100644 --- a/src/views/pqs/harmonicMonitoring/area/terminalonlinerate/index.vue +++ b/src/views/pqs/harmonicMonitoring/area/terminalonlinerate/index.vue @@ -1,365 +1,379 @@ - - - + + + diff --git a/src/views/pqs/harmonicMonitoring/detailed/overLabelDetails/index.vue b/src/views/pqs/harmonicMonitoring/detailed/overLabelDetails/index.vue index a43033fd..e1e07c9c 100644 --- a/src/views/pqs/harmonicMonitoring/detailed/overLabelDetails/index.vue +++ b/src/views/pqs/harmonicMonitoring/detailed/overLabelDetails/index.vue @@ -68,14 +68,14 @@ const tableStore = new TableStore({ { field: 'lineScale', title: '电压等级', minWidth: "120px", }, { field: 'lineName', title: '监测点名称', minWidth: "150px", }, { field: 'loadType', title: '干扰源类型', minWidth: "150px", }, - { field: 'lineObjectName', title: '监测点对象名称', minWidth: "150px", formatter: (row: any) => { return row.cellValue == null ? '/' : row.cellValue } }, + { field: 'lineObjectName', title: '监测点对象名称', minWidth: "180px", formatter: (row: any) => { return row.cellValue == null ? '/' : row.cellValue } }, { field: 'overDay', title: '超标天数', minWidth: "80px", }, - { field: 'freqOverDay', title: '频率偏差超标天数', minWidth: "100px", }, - { field: 'volDevOverDay', title: '电压偏差超标天数', minWidth: "100px", }, - { field: 'volDisOverDay', title: '电压总畸变率超标天数', minWidth: "100px", }, - { field: 'volContainOverDay', title: '谐波电压含有率超标天数', minWidth: "110px", }, - { field: 'harmVolOverDay', title: '谐波电压超标天数', minWidth: "100px", }, - { field: 'harmCurOverDay', title: '谐波电流超标天数', minWidth: "100px", }, + { field: 'freqOverDay', title: '频率偏差', minWidth: "100px", }, + { field: 'volDevOverDay', title: '电压偏差', minWidth: "100px", }, + { field: 'volDisOverDay', title: '电压总畸变率', minWidth: "100px", }, + { field: 'volContainOverDay', title: '谐波电压含有率', minWidth: "100px", }, + { field: 'harmVolOverDay', title: '谐波电压', minWidth: "100px", }, + { field: 'harmCurOverDay', title: '谐波电流', minWidth: "100px", }, { title: '各次谐波电压含有率超标天数', children: [ @@ -104,10 +104,11 @@ const tableStore = new TableStore({ ], }, - { field: 'threeUnbalance', title: '三相电压不平衡度超标天数', minWidth: "110px", }, - { field: 'negativeOverDay', title: '负序电流超标天数', minWidth: "100px", }, - { field: 'flickerOverDay', title: '闪变超标天数', minWidth: "100px", }, - { field: 'monitorNumber', title: '监测点编号', minWidth: "180px", formatter: (row: any) => { return row.cellValue == null ? '/' : row.cellValue } }, + { field: 'intHarmOverDay', title: '间谐波电压含有率', minWidth: "100px", }, + { field: 'threeUnbalance', title: '三相电压不平衡度', minWidth: "100px", }, + { field: 'negativeOverDay', title: '负序电流', minWidth: "100px", }, + { field: 'flickerOverDay', title: '闪变', minWidth: "100px", }, + { field: 'monitorNumber', title: '监测点编号', minWidth: "100px", formatter: (row: any) => { return row.cellValue == null ? '/' : row.cellValue } }, diff --git a/src/views/pqs/harmonicMonitoring/embed/lntegruty/index_JB.vue b/src/views/pqs/harmonicMonitoring/embed/lntegruty/index_JB.vue index f38bbd0d..abd840db 100644 --- a/src/views/pqs/harmonicMonitoring/embed/lntegruty/index_JB.vue +++ b/src/views/pqs/harmonicMonitoring/embed/lntegruty/index_JB.vue @@ -162,14 +162,15 @@ - + +