diff --git a/public/favicon.ico b/public/favicon.ico index 029a1f39..fe16b5ad 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon1.ico b/public/favicon1.ico deleted file mode 100644 index fe16b5ad..00000000 Binary files a/public/favicon1.ico and /dev/null differ diff --git a/public/favicon3.ico b/public/favicon3.ico new file mode 100644 index 00000000..029a1f39 Binary files /dev/null and b/public/favicon3.ico differ diff --git a/src/components/baInput/components/remoteSelect.vue b/src/components/baInput/components/remoteSelect.vue index 6c71a374..a101f604 100644 --- a/src/components/baInput/components/remoteSelect.vue +++ b/src/components/baInput/components/remoteSelect.vue @@ -1,310 +1,310 @@ - - - - - + + + + + diff --git a/src/components/echarts/waveForm.vue b/src/components/echarts/waveForm.vue index 84727ef4..acd047d5 100644 --- a/src/components/echarts/waveForm.vue +++ b/src/components/echarts/waveForm.vue @@ -1,190 +1,190 @@ - - - + + + diff --git a/src/components/table/index.vue b/src/components/table/index.vue index 54817a52..18b96052 100644 --- a/src/components/table/index.vue +++ b/src/components/table/index.vue @@ -1,43 +1,24 @@ @@ -80,13 +56,13 @@ const key = ref(0) interface Props extends /* @vue-ignore */ Partial> { isGroup?: boolean showOverflow?: boolean - height?: string | boolean + height?: string | number } const props = withDefaults(defineProps(), { isGroup: false, showOverflow: true, - height: false + height: undefined }) onMounted(() => { tableStore.table.ref = tableRef.value as VxeTableInstance diff --git a/src/components/tree/pqs/Terminal.vue b/src/components/tree/pqs/Terminal.vue index dab14c13..3a797509 100644 --- a/src/components/tree/pqs/Terminal.vue +++ b/src/components/tree/pqs/Terminal.vue @@ -1,197 +1,197 @@ - - - - + + + + diff --git a/src/layouts/admin/container/classic.vue b/src/layouts/admin/container/classic.vue index 8cffe645..a0afa101 100644 --- a/src/layouts/admin/container/classic.vue +++ b/src/layouts/admin/container/classic.vue @@ -1,33 +1,33 @@ - - - - - + + + + + diff --git a/src/utils/auth.ts b/src/utils/auth.ts index c68a67a9..237ea3d1 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -1,71 +1,70 @@ -import { useCache, CACHE_KEY } from '@/hooks/web/useCache' -import { TokenType } from '@/api/login/types' -import { decrypt, encrypt } from '@/utils/jsencrypt' - -const { wsCache } = useCache() - -const AccessTokenKey = 'ACCESS_TOKEN' -const RefreshTokenKey = 'REFRESH_TOKEN' - -// 获取token -export const getAccessToken = () => { - // 此处与TokenKey相同,此写法解决初始化时Cookies中不存在TokenKey报错 - return wsCache.get(AccessTokenKey) ? wsCache.get(AccessTokenKey) : wsCache.get('ACCESS_TOKEN') -} - -// 刷新token -export const getRefreshToken = () => { - return wsCache.get(RefreshTokenKey) -} - -// 设置token -export const setToken = (token: TokenType) => { - wsCache.set(RefreshTokenKey, token.refreshToken) - wsCache.set(AccessTokenKey, token.accessToken) -} - -// 删除token -export const removeToken = () => { - wsCache.delete(AccessTokenKey) - wsCache.delete(RefreshTokenKey) -} - -/** 格式化token(jwt格式) */ -export const formatToken = (token: string): string => { - return 'Bearer ' + token -} -// ========== 账号相关 ========== - -export type LoginFormType = { - tenantName: string - username: string - password: string - rememberMe: boolean -} - -export const getLoginForm = () => { - const loginForm: LoginFormType = wsCache.get(CACHE_KEY.LoginForm) - if (loginForm) { - loginForm.password = decrypt(loginForm.password) as string - } - return loginForm -} - -export const setLoginForm = (loginForm: LoginFormType) => { - loginForm.password = encrypt(loginForm.password) as string - wsCache.set(CACHE_KEY.LoginForm, loginForm, { exp: 30 * 24 * 60 * 60 }) -} - -export const removeLoginForm = () => { - wsCache.delete(CACHE_KEY.LoginForm) -} - -// ========== 租户相关 ========== - -export const getTenantId = () => { - return wsCache.get(CACHE_KEY.TenantId) -} - -export const setTenantId = (username: string) => { - wsCache.set(CACHE_KEY.TenantId, username) -} +import { useCache, CACHE_KEY } from '@/hooks/web/useCache' +import { decrypt, encrypt } from '@/utils/jsencrypt' + +const { wsCache } = useCache() + +const AccessTokenKey = 'ACCESS_TOKEN' +const RefreshTokenKey = 'REFRESH_TOKEN' + +// 获取token +export const getAccessToken = () => { + // 此处与TokenKey相同,此写法解决初始化时Cookies中不存在TokenKey报错 + return wsCache.get(AccessTokenKey) ? wsCache.get(AccessTokenKey) : wsCache.get('ACCESS_TOKEN') +} + +// 刷新token +export const getRefreshToken = () => { + return wsCache.get(RefreshTokenKey) +} + +// 设置token +export const setToken = (token: any) => { + wsCache.set(RefreshTokenKey, token.refreshToken) + wsCache.set(AccessTokenKey, token.accessToken) +} + +// 删除token +export const removeToken = () => { + wsCache.delete(AccessTokenKey) + wsCache.delete(RefreshTokenKey) +} + +/** 格式化token(jwt格式) */ +export const formatToken = (token: string): string => { + return 'Bearer ' + token +} +// ========== 账号相关 ========== + +export type LoginFormType = { + tenantName: string + username: string + password: string + rememberMe: boolean +} + +export const getLoginForm = () => { + const loginForm: LoginFormType = wsCache.get(CACHE_KEY.LoginForm) + if (loginForm) { + loginForm.password = decrypt(loginForm.password) as string + } + return loginForm +} + +export const setLoginForm = (loginForm: LoginFormType) => { + loginForm.password = encrypt(loginForm.password) as string + wsCache.set(CACHE_KEY.LoginForm, loginForm, { exp: 30 * 24 * 60 * 60 }) +} + +export const removeLoginForm = () => { + wsCache.delete(CACHE_KEY.LoginForm) +} + +// ========== 租户相关 ========== + +export const getTenantId = () => { + return wsCache.get(CACHE_KEY.TenantId) +} + +export const setTenantId = (username: string) => { + wsCache.set(CACHE_KEY.TenantId, username) +} diff --git a/src/utils/echartMethod.ts b/src/utils/echartMethod.ts index 8af8e287..408d7ddf 100644 --- a/src/utils/echartMethod.ts +++ b/src/utils/echartMethod.ts @@ -1,159 +1,302 @@ -const dataProcessing = (arr: any[]) => { - return arr - .filter(item => typeof item === 'number' || (typeof item === 'string' && !isNaN(parseFloat(item)))) - .map(item => (typeof item === 'number' ? item : parseFloat(item))) -} -const calculateValue = (o: number, value: number, num: number, isMin: boolean) => { - if (value === 0) { - return 0 - } else if (value > 0 && Math.abs(value) < 1 && isMin == true) { - return 0 - } else if (value > -1 && value < 0 && isMin == false) { - return 0 - } - let base - if (Math.abs(o) >= 100) { - base = 100 - } else if (Math.abs(o) >= 10) { - base = 10 - } else if (Math.abs(o) >= 1) { - base = 1 - } else { - base = 0.1 - } - let calculatedValue - if (isMin) { - if (value < 0) { - calculatedValue = value + num * value - } else { - calculatedValue = value - num * value - } - } else { - if (value < 0) { - calculatedValue = value - num * value - } else { - calculatedValue = value + num * value - } - } - if (base === 0.1) { - return parseFloat(calculatedValue.toFixed(1)) - } 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 numList = dataProcessing(arr) - let maxValue = 0 - let minValue = 0 - let max = 0 - let min = 0 - maxValue = Math.max(...numList) - minValue = Math.min(...numList) - const o = maxValue - minValue - if (Math.abs(o) >= 300) { - num = 0.02 - } - - min = calculateValue(o, minValue, num, true) - max = calculateValue(o, maxValue, num, false) - // if (-100 >= minValue) { - // min = Math.floor((minValue + num * minValue) / 100) * 100 - // } else if (-10 >= minValue && minValue > -100) { - // min = Math.floor((minValue + num * minValue) / 10) * 10 - // } else if (-1 >= minValue && minValue > -10) { - // min = Math.floor(minValue + num * minValue) - // } else if (0 > minValue && minValue > -1) { - // min = parseFloat((minValue + num * minValue).toFixed(1)) - // } else if (minValue == 0) { - // min = 0 - // } else if (0 < minValue && minValue < 1) { - // min = parseFloat((minValue - num * minValue).toFixed(1)) - // } else if (1 <= minValue && minValue < 10) { - // min = Math.floor(minValue - num * minValue) - // } else if (10 <= minValue && minValue < 100) { - // min = Math.floor((minValue - num * minValue) / 10) * 10 - // } else if (100 <= minValue) { - // min = Math.floor((minValue - num * minValue) / 100) * 100 - // } - - // if (-100 >= maxValue) { - // max = Math.ceil((maxValue - num * maxValue) / 100) * 100 - // } else if (-10 >= maxValue && maxValue > -100) { - // max = Math.ceil((maxValue - num * maxValue) / 10) * 10 - // } else if (-1 >= maxValue && maxValue > -10) { - // max = Math.ceil(maxValue - num * maxValue) - // } else if (0 > maxValue && maxValue > -1) { - // max = parseFloat((maxValue - num * maxValue).toFixed(1)) - // } else if (maxValue == 0) { - // max = 0 - // } else if (0 < maxValue && maxValue < 1) { - // max = parseFloat((maxValue + num * maxValue).toFixed(1)) - // } else if (1 <= maxValue && maxValue < 10) { - // max = Math.ceil(maxValue + num * maxValue) - // } else if (10 <= maxValue && maxValue < 100) { - // max = Math.ceil((maxValue + num * maxValue) / 10) * 10 - // } else if (100 <= maxValue) { - // max = Math.ceil((maxValue + num * maxValue) / 100) * 100 - // } - - // if (maxValue > 1000 || minValue < -1000) { - // max = Math.ceil(maxValue / 100) * 100 - // if (minValue == 0) { - // min = 0 - // } else { - // min = Math.floor(minValue / 100) * 100 - // } - // } else if (maxValue < 60 && minValue > 40) { - // max = 60 - // min = 40 - // } else if (maxValue == minValue && maxValue < 10 && minValue > 0) { - // max = Math.ceil(maxValue / 10) * 10 - // min = Math.floor(minValue / 10) * 10 - // } else if (maxValue == minValue && maxValue != 0 && minValue != 0) { - // max = Math.ceil(maxValue / 10 + 1) * 10 - // min = Math.floor(minValue / 10 - 1) * 10 - // } else { - // max = Math.ceil(maxValue / 10) * 10 - // min = Math.floor(minValue / 10) * 10 - // } - - // if (maxValue > 0 && maxValue < 1) { - // max = 1 - // } else if (max == 0 && minValue > -1 && minValue < 0) { - // min = -1 - // } - - return [min, max] -} - -/** - * title['A相','B相',] - * data[[1,2],[3,4]] - */ -// 导出csv文件 -const convertToCSV = (title: object, data: any) => { - console.log('🚀 ~ convertToCSV ~ data:', data) - let csv = '' - // 添加列头 - csv += ',' + title.join(',') + '\n' - // 遍历数据并添加到CSV字符串中 - data?.map(item => { - csv += item.join(',') + '\n' - }) - return csv -} -export const exportCSV = (title: object, data: any, filename: string) => { - const csv = convertToCSV(title, data) - const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }) - const link = document.createElement('a') - link.href = URL.createObjectURL(blob) - link.download = filename - link.click() - // 释放URL对象 - URL.revokeObjectURL(link.href) -} +const dataProcessing = (arr: any[]) => { + return arr + .filter(item => typeof item === 'number' || (typeof item === 'string' && !isNaN(parseFloat(item)))) + .map(item => (typeof item === 'number' ? item : parseFloat(item))) +} +const calculateValue = (o: number, value: number, num: number, isMin: boolean) => { + if (value === 0) { + return 0 + } else if (value > 0 && Math.abs(value) < 1 && isMin == true) { + return 0 + } else if (value > -1 && value < 0 && isMin == false) { + return 0 + } + let base + if (Math.abs(o) >= 100) { + base = 100 + } else if (Math.abs(o) >= 10) { + base = 10 + } else if (Math.abs(o) >= 1) { + base = 1 + } else { + base = 0.1 + } + let calculatedValue + if (isMin) { + if (value < 0) { + calculatedValue = value + num * value + } else { + calculatedValue = value - num * value + } + } else { + if (value < 0) { + calculatedValue = value - num * value + } else { + calculatedValue = value + num * value + } + } + if (base === 0.1) { + return parseFloat(calculatedValue.toFixed(1)) + } 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 numList = dataProcessing(arr) + let maxValue = 0 + let minValue = 0 + let max = 0 + let min = 0 + maxValue = Math.max(...numList) + minValue = Math.min(...numList) + const o = maxValue - minValue + if (Math.abs(o) >= 300) { + num = 0.02 + } + + min = calculateValue(o, minValue, num, true) + max = calculateValue(o, maxValue, num, false) + // if (-100 >= minValue) { + // min = Math.floor((minValue + num * minValue) / 100) * 100 + // } else if (-10 >= minValue && minValue > -100) { + // min = Math.floor((minValue + num * minValue) / 10) * 10 + // } else if (-1 >= minValue && minValue > -10) { + // min = Math.floor(minValue + num * minValue) + // } else if (0 > minValue && minValue > -1) { + // min = parseFloat((minValue + num * minValue).toFixed(1)) + // } else if (minValue == 0) { + // min = 0 + // } else if (0 < minValue && minValue < 1) { + // min = parseFloat((minValue - num * minValue).toFixed(1)) + // } else if (1 <= minValue && minValue < 10) { + // min = Math.floor(minValue - num * minValue) + // } else if (10 <= minValue && minValue < 100) { + // min = Math.floor((minValue - num * minValue) / 10) * 10 + // } else if (100 <= minValue) { + // min = Math.floor((minValue - num * minValue) / 100) * 100 + // } + + // if (-100 >= maxValue) { + // max = Math.ceil((maxValue - num * maxValue) / 100) * 100 + // } else if (-10 >= maxValue && maxValue > -100) { + // max = Math.ceil((maxValue - num * maxValue) / 10) * 10 + // } else if (-1 >= maxValue && maxValue > -10) { + // max = Math.ceil(maxValue - num * maxValue) + // } else if (0 > maxValue && maxValue > -1) { + // max = parseFloat((maxValue - num * maxValue).toFixed(1)) + // } else if (maxValue == 0) { + // max = 0 + // } else if (0 < maxValue && maxValue < 1) { + // max = parseFloat((maxValue + num * maxValue).toFixed(1)) + // } else if (1 <= maxValue && maxValue < 10) { + // max = Math.ceil(maxValue + num * maxValue) + // } else if (10 <= maxValue && maxValue < 100) { + // max = Math.ceil((maxValue + num * maxValue) / 10) * 10 + // } else if (100 <= maxValue) { + // max = Math.ceil((maxValue + num * maxValue) / 100) * 100 + // } + + // if (maxValue > 1000 || minValue < -1000) { + // max = Math.ceil(maxValue / 100) * 100 + // if (minValue == 0) { + // min = 0 + // } else { + // min = Math.floor(minValue / 100) * 100 + // } + // } else if (maxValue < 60 && minValue > 40) { + // max = 60 + // min = 40 + // } else if (maxValue == minValue && maxValue < 10 && minValue > 0) { + // max = Math.ceil(maxValue / 10) * 10 + // min = Math.floor(minValue / 10) * 10 + // } else if (maxValue == minValue && maxValue != 0 && minValue != 0) { + // max = Math.ceil(maxValue / 10 + 1) * 10 + // min = Math.floor(minValue / 10 - 1) * 10 + // } else { + // max = Math.ceil(maxValue / 10) * 10 + // min = Math.floor(minValue / 10) * 10 + // } + + // if (maxValue > 0 && maxValue < 1) { + // max = 1 + // } else if (max == 0 && minValue > -1 && minValue < 0) { + // min = -1 + // } + + return [min, max] +} + +/** + * title['A相','B相',] + * data[[1,2],[3,4]] + */ +// 导出csv文件 +const convertToCSV = (title: object, data: any) => { + console.log('🚀 ~ convertToCSV ~ data:', data) + let csv = '' + // 添加列头 + csv += ',' + title.join(',') + '\n' + // 遍历数据并添加到CSV字符串中 + data?.map(item => { + csv += item.join(',') + '\n' + }) + return csv +} +export const exportCSV = (title: object, data: any, filename: string) => { + const csv = convertToCSV(title, data) + const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }) + const link = document.createElement('a') + link.href = URL.createObjectURL(blob) + link.download = filename + link.click() + // 释放URL对象 + URL.revokeObjectURL(link.href) +} + + + +/** + * 补全时间序列数据中缺失的条目 + * @param rawData 原始数据,格式为 [["时间字符串", "数值", "单位", "类型"], ...] + * @returns 补全后的数据,缺失条目数值为 null + */ +export const completeTimeSeries = (rawData: string[][]): (string | null)[][] => { + // 步骤1:校验原始数据并解析时间 + if (rawData.length < 2) { + console.warn('数据量不足2条,无法计算时间间隔,直接返回原始数据') + return rawData.map(item => [...item]) + } + + // 解析所有时间为Date对象,过滤无效时间并按时间排序 + const validData = rawData + .map(item => { + // 确保至少有时间和数值字段 + if (!item[0]) { + return { time: new Date(0), item, isValid: false } + } + const time = new Date(item[0]) + return { time, item, isValid: !isNaN(time.getTime()) } + }) + .filter(data => data.isValid) + .sort((a, b) => a.time.getTime() - b.time.getTime()) // 确保数据按时间排序 + .map(data => data.item) + + if (validData.length < 2) { + throw new Error('有效时间数据不足2条,无法继续处理') + } + + // 步骤2:计算时间间隔(分析前几条数据确定最可能的间隔) + const intervals: number[] = [] + // 分析前10条数据来确定间隔,避免单一间隔出错 + const analyzeCount = Math.min(10, validData.length - 1) + for (let i = 0; i < analyzeCount; i++) { + const currentTime = new Date(validData[i][0]!).getTime() + const nextTime = new Date(validData[i + 1][0]!).getTime() + const interval = nextTime - currentTime + if (interval > 0) { + intervals.push(interval) + } + } + + // 取最常见的间隔作为标准间隔 + const timeInterval = getMostFrequentValue(intervals) + if (timeInterval <= 0) { + throw new Error('无法确定有效的时间间隔') + } + + // 步骤3:生成完整的时间序列范围(从第一条到最后一条) + const startTime = new Date(validData[0][0]!).getTime() + const endTime = new Date(validData[validData.length - 1][0]!).getTime() + const completeTimes: Date[] = [] + + // 生成从 startTime 到 endTime 的所有间隔时间点 + for (let time = startTime; time <= endTime; time += timeInterval) { + completeTimes.push(new Date(time)) + } + + // 步骤4:将原始数据转为时间映射表,使用精确的时间字符串匹配 + const timeDataMap = new Map() + validData.forEach(item => { + // 使用原始时间字符串作为键,避免格式转换导致的匹配问题 + if (item[0]) { + timeDataMap.set(item[0], item) + } + }) + + // 提取模板数据(从第一条有效数据中提取单位和类型,处理可能的缺失) + const template = validData[0] + + // 步骤5:对比补全数据,缺失条目数值为 null + const completedData = completeTimes.map(time => { + // 保持与原始数据相同的时间格式 + const timeStr = formatTime(time) + const existingItem = timeDataMap.get(timeStr) + + if (existingItem) { + // 存在该时间,返回原始数据 + return [...existingItem] + } else { + // 缺失该时间,数值设为 null,其他字段沿用第一个有效数据的格式 + // 处理可能缺失的单位和类型字段 + const result: (string | null | undefined)[] = [timeStr, '/'] + // 仅在原始数据有单位字段时才添加 + if (template.length > 2) { + result.push(template[2]) + } + // 仅在原始数据有类型字段时才添加 + if (template.length > 3) { + result.push(template[3]) + } + return result + } + }) + + return completedData +} + +/** + * 格式化时间为 "YYYY-MM-DD HH:mm:ss" 格式 + * @param date 日期对象 + * @returns 格式化后的时间字符串 + */ +function formatTime(date: Date): string { + const year = date.getFullYear() + const month = String(date.getMonth() + 1).padStart(2, '0') + const day = String(date.getDate()).padStart(2, '0') + const hours = String(date.getHours()).padStart(2, '0') + const minutes = String(date.getMinutes()).padStart(2, '0') + const seconds = String(date.getSeconds()).padStart(2, '0') + + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}` +} + +/** + * 获取数组中出现频率最高的值 + * @param arr 数字数组 + * @returns 出现频率最高的值 + */ +function getMostFrequentValue(arr: number[]): number { + if (arr.length === 0) return 0 + + const frequencyMap = new Map() + arr.forEach(num => { + frequencyMap.set(num, (frequencyMap.get(num) || 0) + 1) + }) + + let maxFrequency = 0 + let mostFrequent = arr[0] + + frequencyMap.forEach((frequency, num) => { + if (frequency > maxFrequency) { + maxFrequency = frequency + mostFrequent = num + } + }) + + return mostFrequent +} diff --git a/src/utils/router.ts b/src/utils/router.ts index a9ea05ff..65610d61 100644 --- a/src/utils/router.ts +++ b/src/utils/router.ts @@ -1,295 +1,295 @@ -import router from '@/router/index' -import { isNavigationFailure, NavigationFailureType } from 'vue-router' -import type { RouteRecordRaw, RouteLocationRaw } from 'vue-router' -import { ElNotification } from 'element-plus' -import { useConfig } from '@/stores/config' -import { useNavTabs } from '@/stores/navTabs' -import { closeShade } from '@/utils/pageShade' -import { adminBaseRoute } from '@/router/static' -import { compact, isEmpty, reverse } from 'lodash-es' -import { isAdminApp } from '@/utils/common' - -/** - * 导航失败有错误消息的路由push - * @param to — 导航位置,同 router.push - */ -export const routePush = async (to: RouteLocationRaw) => { - try { - const failure = await router.push(to) - if (isNavigationFailure(failure, NavigationFailureType.aborted)) { - ElNotification({ - message: 'utils.Navigation failed, navigation guard intercepted!', - type: 'error' - }) - } else if (isNavigationFailure(failure, NavigationFailureType.duplicated)) { - // ElNotification({ - // message: '已在目标页', - // type: 'warning' - // }) - } - } catch (error) { - ElNotification({ - message: '导航失败,路由无效', - type: 'error' - }) - console.error(error) - } -} - -/** - * 获取第一个菜单 - */ -export const getFirstRoute = (routes: RouteRecordRaw[], menuType = 'tab'): false | RouteRecordRaw => { - const routerPaths: string[] = [] - const routers = router.getRoutes() - routers.forEach(item => { - if (item.path) routerPaths.push(item.path) - }) - let find: boolean | RouteRecordRaw = false - for (const key in routes) { - if ( - routes[key].meta?.type == 'menu' && - routes[key].meta?.menu_type == menuType && - routerPaths.indexOf(routes[key].path) !== -1 - ) { - return routes[key] - } else if (routes[key].children && routes[key].children?.length) { - find = getFirstRoute(routes[key].children!) - if (find) return find - } - } - return find -} - -/** - * 打开侧边菜单 - * @param menu 菜单数据 - */ -export const onClickMenu = (menu: RouteRecordRaw) => { - switch (menu.meta?.menu_type) { - case 'iframe': - case 'tab': - routePush({ path: menu.path }) - break - case 'link': - window.open(menu.path, '_blank') - break - - default: - ElNotification({ - message: 'utils.Navigation failed, the menu type is unrecognized!', - type: 'error' - }) - break - } - - const config = useConfig() - if (config.layout.shrink) { - closeShade(() => { - config.setLayout('menuCollapse', true) - }) - } -} - -/** - * 处理后台的路由 - */ -export const handleAdminRoute = (routes: any) => { - const viewsComponent = import.meta.glob('/src/views/**/*.vue') - addRouteAll(viewsComponent, routes, adminBaseRoute.name as string) - const menuAdminBaseRoute = (adminBaseRoute.path as string) + '/' - // 更新stores中的路由菜单数据 - const navTabs = useNavTabs() - navTabs.setTabsViewRoutes(handleMenuRule(routes, menuAdminBaseRoute)) - navTabs.fillAuthNode(handleAuthNode(routes, menuAdminBaseRoute)) -} - -/** - * 获取菜单的paths - */ -export const getMenuPaths = (menus: RouteRecordRaw[]): string[] => { - let menuPaths: string[] = [] - menus.forEach(item => { - menuPaths.push(item.path) - if (item.children && item.children.length > 0) { - menuPaths = menuPaths.concat(getMenuPaths(item.children)) - } - }) - return menuPaths -} - -/** - * 后台的菜单处理 - */ -const handleMenuRule = (routes: any, pathPrefix = '/', type = ['menu', 'menu_dir']) => { - const menuRule: RouteRecordRaw[] = [] - for (const key in routes) { - if (routes[key].extend == 'add_rules_only') { - continue - } - if (!type.includes(routes[key].type)) { - continue - } - if (routes[key].type == 'menu_dir' && routes[key].children && !routes[key].children.length) { - continue - } - if ( - ['route', 'menu', 'nav_user_menu', 'nav'].includes(routes[key].type) && - ((routes[key].menu_type == 'tab' && !routes[key].component) || - (['link', 'iframe'].includes(routes[key].menu_type) && !routes[key].url)) - ) { - continue - } - const currentPath = ['link', 'iframe'].includes(routes[key].menu_type) - ? routes[key].url - : pathPrefix + routes[key].path - let children: RouteRecordRaw[] = [] - if (routes[key].children && routes[key].children.length > 0) { - children = handleMenuRule(routes[key].children, pathPrefix, type) - } - menuRule.push({ - path: currentPath, - name: routes[key].name, - component: routes[key].component, - meta: { - id: routes[key].id, - title: routes[key].title, - icon: routes[key].icon, - keepalive: routes[key].keepalive, - menu_type: routes[key].menu_type, - type: routes[key].type - }, - children: children - }) - } - return menuRule -} - -/** - * 处理权限节点 - * @param routes 路由数据 - * @param prefix 节点前缀 - * @returns 组装好的权限节点 - */ -const handleAuthNode = (routes: any, prefix = '/') => { - const authNode: Map = new Map([]) - assembleAuthNode(routes, authNode, prefix, prefix) - return authNode -} -const assembleAuthNode = (routes: any, authNode: Map, prefix = '/', parent = '/') => { - const authNodeTemp = [] - for (const key in routes) { - if (routes[key].type == 'button') authNodeTemp.push(prefix + routes[key].name) - if (routes[key].children && routes[key].children.length > 0) { - assembleAuthNode(routes[key].children, authNode, prefix, prefix + routes[key].name) - } - } - if (authNodeTemp && authNodeTemp.length > 0) { - authNode.set(parent, authNodeTemp) - } -} - -/** - * 动态添加路由-带子路由 - * @param viewsComponent - * @param routes - * @param parentName - * @param analyticRelation 根据 name 从已注册路由分析父级路由 - */ -export const addRouteAll = ( - viewsComponent: Record, - routes: any, - parentName: string, - analyticRelation = false -) => { - for (const idx in routes) { - if (routes[idx].extend == 'add_menu_only') { - continue - } - if ( - (routes[idx].menu_type == 'tab' && viewsComponent[routes[idx].component]) || - routes[idx].menu_type == 'iframe' - ) { - addRouteItem(viewsComponent, routes[idx], parentName, analyticRelation) - } - - if (routes[idx].children && routes[idx].children.length > 0) { - addRouteAll(viewsComponent, routes[idx].children, parentName, analyticRelation) - } - } -} - -/** - * 动态添加路由 - * @param viewsComponent - * @param route - * @param parentName - * @param analyticRelation 根据 name 从已注册路由分析父级路由 - */ -export const addRouteItem = ( - viewsComponent: Record, - route: any, - parentName: string, - analyticRelation: boolean -) => { - let path = '', - component - if (route.menu_type == 'iframe') { - path = (isAdminApp() ? adminBaseRoute.path : '') + '/iframe/' + encodeURIComponent(route.url) - component = () => import('@/layouts/common/router-view/iframe.vue') - } else { - path = parentName ? route.path : '/' + route.path - component = viewsComponent[route.component] - } - - if (route.menu_type == 'tab' && analyticRelation) { - const parentNames = getParentNames(route.name) - if (parentNames.length) { - for (const key in parentNames) { - if (router.hasRoute(parentNames[key])) { - parentName = parentNames[key] - break - } - } - } - } - - const routeBaseInfo: RouteRecordRaw = { - path: path, - name: route.name, - component: component, - meta: { - ...route, - title: route.title, - extend: route.extend, - icon: route.icon, - keepalive: route.keepalive, - menu_type: route.menu_type, - type: route.type, - url: route.url, - addtab: true - } - } - if (parentName) { - router.addRoute(parentName, routeBaseInfo) - } else { - router.addRoute(routeBaseInfo) - } -} - -/** - * 根据name字符串,获取父级name组合的数组 - * @param name - */ -const getParentNames = (name: string) => { - const names = compact(name.split('/')) - const tempNames = [] - const parentNames = [] - for (const key in names) { - tempNames.push(names[key]) - if (parseInt(key) != names.length - 1) { - parentNames.push(tempNames.join('/')) - } - } - return reverse(parentNames) -} +import router from '@/router/index' +import { isNavigationFailure, NavigationFailureType } from 'vue-router' +import type { RouteRecordRaw, RouteLocationRaw } from 'vue-router' +import { ElNotification } from 'element-plus' +import { useConfig } from '@/stores/config' +import { useNavTabs } from '@/stores/navTabs' +import { closeShade } from '@/utils/pageShade' +import { adminBaseRoute } from '@/router/static' +import { compact, isEmpty, reverse } from 'lodash-es' +import { isAdminApp } from '@/utils/common' + +/** + * 导航失败有错误消息的路由push + * @param to — 导航位置,同 router.push + */ +export const routePush = async (to: RouteLocationRaw) => { + try { + const failure = await router.push(to) + if (isNavigationFailure(failure, NavigationFailureType.aborted)) { + ElNotification({ + message: 'utils.Navigation failed, navigation guard intercepted!', + type: 'error' + }) + } else if (isNavigationFailure(failure, NavigationFailureType.duplicated)) { + // ElNotification({ + // message: '已在目标页', + // type: 'warning' + // }) + } + } catch (error) { + ElNotification({ + message: '导航失败,路由无效', + type: 'error' + }) + console.error(error) + } +} + +/** + * 获取第一个菜单 + */ +export const getFirstRoute = (routes: RouteRecordRaw[], menuType = 'tab'): false | RouteRecordRaw => { + const routerPaths: string[] = [] + const routers = router.getRoutes() + routers.forEach(item => { + if (item.path) routerPaths.push(item.path) + }) + let find: boolean | RouteRecordRaw = false + for (const key in routes) { + if ( + routes[key].meta?.type == 'menu' && + routes[key].meta?.menu_type == menuType && + routerPaths.indexOf(routes[key].path) !== -1 + ) { + return routes[key] + } else if (routes[key].children && routes[key].children?.length) { + find = getFirstRoute(routes[key].children!) + if (find) return find + } + } + return find +} + +/** + * 打开侧边菜单 + * @param menu 菜单数据 + */ +export const onClickMenu = (menu: RouteRecordRaw) => { + switch (menu.meta?.menu_type) { + case 'iframe': + case 'tab': + routePush({ path: menu.path }) + break + case 'link': + window.open(menu.path, '_blank') + break + + default: + ElNotification({ + message: 'utils.Navigation failed, the menu type is unrecognized!', + type: 'error' + }) + break + } + + const config = useConfig() + if (config.layout.shrink) { + closeShade(() => { + config.setLayout('menuCollapse', true) + }) + } +} + +/** + * 处理后台的路由 + */ +export const handleAdminRoute = (routes: any) => { + const viewsComponent = import.meta.glob('/src/views/**/*.vue') + addRouteAll(viewsComponent, routes, adminBaseRoute.name as string) + const menuAdminBaseRoute = (adminBaseRoute.path as string) + '/' + // 更新stores中的路由菜单数据 + const navTabs = useNavTabs() + navTabs.setTabsViewRoutes(handleMenuRule(routes, menuAdminBaseRoute)) + navTabs.fillAuthNode(handleAuthNode(routes, menuAdminBaseRoute)) +} + +/** + * 获取菜单的paths + */ +export const getMenuPaths = (menus: RouteRecordRaw[]): string[] => { + let menuPaths: string[] = [] + menus.forEach(item => { + menuPaths.push(item.path) + if (item.children && item.children.length > 0) { + menuPaths = menuPaths.concat(getMenuPaths(item.children)) + } + }) + return menuPaths +} + +/** + * 后台的菜单处理 + */ +const handleMenuRule = (routes: any, pathPrefix = '/', type = ['menu', 'menu_dir']) => { + const menuRule: RouteRecordRaw[] = [] + for (const key in routes) { + if (routes[key].extend == 'add_rules_only') { + continue + } + if (!type.includes(routes[key].type)) { + continue + } + if (routes[key].type == 'menu_dir' && routes[key].children && !routes[key].children.length) { + continue + } + if ( + ['route', 'menu', 'nav_user_menu', 'nav'].includes(routes[key].type) && + ((routes[key].menu_type == 'tab' && !routes[key].component) || + (['link', 'iframe'].includes(routes[key].menu_type) && !routes[key].url)) + ) { + continue + } + const currentPath = ['link', 'iframe'].includes(routes[key].menu_type) + ? routes[key].url + : pathPrefix + routes[key].path + let children: RouteRecordRaw[] = [] + if (routes[key].children && routes[key].children.length > 0) { + children = handleMenuRule(routes[key].children, pathPrefix, type) + } + menuRule.push({ + path: currentPath, + name: routes[key].name, + component: routes[key].component, + meta: { + id: routes[key].id, + title: routes[key].title, + icon: routes[key].icon, + keepalive: routes[key].keepalive, + menu_type: routes[key].menu_type, + type: routes[key].type + }, + children: children + }) + } + return menuRule +} + +/** + * 处理权限节点 + * @param routes 路由数据 + * @param prefix 节点前缀 + * @returns 组装好的权限节点 + */ +const handleAuthNode = (routes: any, prefix = '/') => { + const authNode: Map = new Map([]) + assembleAuthNode(routes, authNode, prefix, prefix) + return authNode +} +const assembleAuthNode = (routes: any, authNode: Map, prefix = '/', parent = '/') => { + const authNodeTemp = [] + for (const key in routes) { + if (routes[key].type == 'button') authNodeTemp.push(prefix + routes[key].name) + if (routes[key].children && routes[key].children.length > 0) { + assembleAuthNode(routes[key].children, authNode, prefix, prefix + routes[key].name) + } + } + if (authNodeTemp && authNodeTemp.length > 0) { + authNode.set(parent, authNodeTemp) + } +} + +/** + * 动态添加路由-带子路由 + * @param viewsComponent + * @param routes + * @param parentName + * @param analyticRelation 根据 name 从已注册路由分析父级路由 + */ +export const addRouteAll = ( + viewsComponent: Record, + routes: any, + parentName: string, + analyticRelation = false +) => { + for (const idx in routes) { + if (routes[idx].extend == 'add_menu_only') { + continue + } + if ( + (routes[idx].menu_type == 'tab' && viewsComponent[routes[idx].component]) || + routes[idx].menu_type == 'iframe' + ) { + addRouteItem(viewsComponent, routes[idx], parentName, analyticRelation) + } + + if (routes[idx].children && routes[idx].children.length > 0) { + addRouteAll(viewsComponent, routes[idx].children, parentName, analyticRelation) + } + } +} + +/** + * 动态添加路由 + * @param viewsComponent + * @param route + * @param parentName + * @param analyticRelation 根据 name 从已注册路由分析父级路由 + */ +export const addRouteItem = ( + viewsComponent: Record, + route: any, + parentName: string, + analyticRelation: boolean +) => { + let path = '', + component + if (route.menu_type == 'iframe') { + path = (isAdminApp() ? adminBaseRoute.path : '') + '/iframe/' + encodeURIComponent(route.url) + component = () => import('@/layouts/common/router-view/iframe.vue') + } else { + path = parentName ? route.path : '/' + route.path + component = viewsComponent[route.component] + } + + if (route.menu_type == 'tab' && analyticRelation) { + const parentNames = getParentNames(route.name) + if (parentNames.length) { + for (const key in parentNames) { + if (router.hasRoute(parentNames[key])) { + parentName = parentNames[key] + break + } + } + } + } + + const routeBaseInfo: RouteRecordRaw = { + path: path, + name: route.name, + component: component, + meta: { + ...route, + title: route.title, + extend: route.extend, + icon: route.icon, + keepalive: route.keepalive, + menu_type: route.menu_type, + type: route.type, + url: route.url, + addtab: true + } + } + if (parentName) { + router.addRoute(parentName, routeBaseInfo) + } else { + router.addRoute(routeBaseInfo) + } +} + +/** + * 根据name字符串,获取父级name组合的数组 + * @param name + */ +const getParentNames = (name: string) => { + const names = compact(name.split('/')) + const tempNames = [] + const parentNames = [] + for (const key in names) { + tempNames.push(names[key]) + if (parseInt(key) != names.length - 1) { + parentNames.push(tempNames.join('/')) + } + } + return reverse(parentNames) +} diff --git a/src/views/cockpit/TerminalLog.vue b/src/views/cockpit/TerminalLog.vue index 0754c047..ff05fda3 100644 --- a/src/views/cockpit/TerminalLog.vue +++ b/src/views/cockpit/TerminalLog.vue @@ -23,7 +23,7 @@ const prop = defineProps({ const dictData = useDictData() const fontdveoption = dictData.getBasicData('Dev_Ops') -const tableStore = new TableStore({ +const tableStore:any = new TableStore({ url: '/device-boot/pqsTerminalLogs/getList', method: 'POST', column: [ diff --git a/src/views/pqs/harmonicMonitoring/detailed/pollutionReport/SubstationTab.vue b/src/views/pqs/harmonicMonitoring/detailed/pollutionReport/SubstationTab.vue index 81af3a2c..d0c8cb81 100644 --- a/src/views/pqs/harmonicMonitoring/detailed/pollutionReport/SubstationTab.vue +++ b/src/views/pqs/harmonicMonitoring/detailed/pollutionReport/SubstationTab.vue @@ -399,7 +399,7 @@ const handleCurrentChange = (val: number) => { const exportEvent = () => { const allFilteredData = filteredData.value tableRef.value.exportData({ - filename: '场战级评估-污染值报告', + filename: '场站级评估-污染值报告', sheetName: 'Sheet1', type: 'xlsx', useStyle: true, diff --git a/src/views/pqs/harmonicMonitoring/monitoringPoint/online/shishishuju/index.vue b/src/views/pqs/harmonicMonitoring/monitoringPoint/online/shishishuju/index.vue index cdd3b83e..66352189 100644 --- a/src/views/pqs/harmonicMonitoring/monitoringPoint/online/shishishuju/index.vue +++ b/src/views/pqs/harmonicMonitoring/monitoringPoint/online/shishishuju/index.vue @@ -652,7 +652,7 @@ const initRadioCharts = () => { echartsData1.value.options.series[i].center = ['50%', '50%'] } } -const initEcharts = (color: string, key: number) => { +const initEcharts = (color: string, key: number, name: string) => { return { options: { tooltip: {}, @@ -731,7 +731,7 @@ const initEcharts = (color: string, key: number) => { data: [ { value: 0, - name: 'A相', + name: name, itemStyle: { color: color } @@ -744,14 +744,14 @@ const initEcharts = (color: string, key: number) => { } //渲染echarts const init = () => { -const url = (localStorage.getItem('WebSocketUrl') || 'ws://192.168.1.68:10407/api/pushMessage/') - echartsDataV1.value = initEcharts('#DAA520', 0) - echartsDataV2.value = initEcharts('#2E8B57', 0) - echartsDataV3.value = initEcharts('#A52a2a', 0) + const url = localStorage.getItem('WebSocketUrl') || 'ws://192.168.1.68:10407/api/pushMessage/' + echartsDataV1.value = initEcharts('#DAA520', 0, 'A相') + echartsDataV2.value = initEcharts('#2E8B57', 0, 'B相') + echartsDataV3.value = initEcharts('#A52a2a', 0, 'C相') - echartsDataA1.value = initEcharts('#DAA520', 1) - echartsDataA2.value = initEcharts('#2E8B57', 1) - echartsDataA3.value = initEcharts('#A52a2a', 1) + echartsDataA1.value = initEcharts('#DAA520', 1, 'A相') + echartsDataA2.value = initEcharts('#2E8B57', 1, 'B相') + echartsDataA3.value = initEcharts('#A52a2a', 1, 'C相') if (!dataSocket.socketServe) { console.error('WebSocket 客户端实例不存在') @@ -764,9 +764,7 @@ const url = (localStorage.getItem('WebSocketUrl') || 'ws://192.168.1.68:10407/ap }) } let pids = monitoringPoint.state.pid.split(',') - dataSocket.socketServe.connect( - `${url}${adminInfo.id},${monitoringPoint.state.lineId},${pids[pids.length - 2]}` - ) + dataSocket.socketServe.connect(`${url}${adminInfo.id},${monitoringPoint.state.lineId},${pids[pids.length - 2]}`) dataSocket.socketServe.registerCallBack('message', (res: any) => { txtContent.value = res.value let data = JSON.parse(res.value) diff --git a/src/views/pqs/harmonicMonitoring/monitoringPoint/online/wentaishujufenxi/index.vue b/src/views/pqs/harmonicMonitoring/monitoringPoint/online/wentaishujufenxi/index.vue index 1e521b49..8153283d 100644 --- a/src/views/pqs/harmonicMonitoring/monitoringPoint/online/wentaishujufenxi/index.vue +++ b/src/views/pqs/harmonicMonitoring/monitoringPoint/online/wentaishujufenxi/index.vue @@ -1,1941 +1,1972 @@ - - - - + + + + diff --git a/src/views/pqs/harmonicMonitoring/reportForms/statistics/index.vue b/src/views/pqs/harmonicMonitoring/reportForms/statistics/index.vue index a1aee4db..6cf5145f 100644 --- a/src/views/pqs/harmonicMonitoring/reportForms/statistics/index.vue +++ b/src/views/pqs/harmonicMonitoring/reportForms/statistics/index.vue @@ -1,170 +1,172 @@ - - - + + + diff --git a/src/views/user/login.vue b/src/views/user/login.vue index 9bfe9635..5c14d803 100644 --- a/src/views/user/login.vue +++ b/src/views/user/login.vue @@ -1,338 +1,338 @@ - - - - - + + + + +