波形解析相关
This commit is contained in:
@@ -31,15 +31,6 @@
|
|||||||
|
|
||||||
不要直接修改生成内容,如 `frontend/dist/`、`out/`、`logs/`、`public/electron/`。
|
不要直接修改生成内容,如 `frontend/dist/`、`out/`、`logs/`、`public/electron/`。
|
||||||
|
|
||||||
## 构建、测试与开发命令
|
|
||||||
- `npm run dev`:启动 Electron 与前端联调环境。
|
|
||||||
- `npm run dev-frontend`:仅启动前端开发流程。
|
|
||||||
- `npm run dev-electron`:仅启动 Electron 侧开发流程。
|
|
||||||
- `npm run build`:构建前端与 Electron,并执行 `ee-bin encrypt`。
|
|
||||||
- `npm run build-w`:生成 Windows 包,并将 `out/win-unpacked` 重命名为 `out/CN_Tool`。
|
|
||||||
- `cd frontend; npm run lint`:运行 ESLint 并自动修复 `.vue`、TypeScript 等文件。
|
|
||||||
- `cd frontend; npm run type-check`:运行 `vue-tsc` 进行类型检查。
|
|
||||||
|
|
||||||
## 代码风格与命名规范
|
## 代码风格与命名规范
|
||||||
前端格式化规则定义在 `frontend/.prettierrc`:4 空格缩进、单引号、不写分号、单行 120 字符、LF 换行。Lint 规则基于 Vue 3 与 TypeScript。
|
前端格式化规则定义在 `frontend/.prettierrc`:4 空格缩进、单引号、不写分号、单行 120 字符、LF 换行。Lint 规则基于 Vue 3 与 TypeScript。
|
||||||
|
|
||||||
|
|||||||
@@ -144,7 +144,7 @@
|
|||||||
},
|
},
|
||||||
"tray": {
|
"tray": {
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"title": "CN_Tool 灿能运维工具",
|
"title": "电能质量运维工具",
|
||||||
"icon": "/public/images/tray.png"
|
"icon": "/public/images/tray.png"
|
||||||
},
|
},
|
||||||
"security": {
|
"security": {
|
||||||
@@ -180,7 +180,7 @@
|
|||||||
"mode": "undocked"
|
"mode": "undocked"
|
||||||
},
|
},
|
||||||
"windowsOption": {
|
"windowsOption": {
|
||||||
"title": "CN_Tool 灿能运维工具",
|
"title": "电能质量运维工具",
|
||||||
"width": 1600,
|
"width": 1600,
|
||||||
"height": 950,
|
"height": 950,
|
||||||
"minWidth": 1600,
|
"minWidth": 1600,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ module.exports = () => {
|
|||||||
openDevTools: false,
|
openDevTools: false,
|
||||||
singleLock: true,
|
singleLock: true,
|
||||||
windowsOption: {
|
windowsOption: {
|
||||||
title: 'CN_Tool 灿能运维工具',
|
title: '电能质量运维工具',
|
||||||
menuBarVisible: false, // 隐藏菜单栏
|
menuBarVisible: false, // 隐藏菜单栏
|
||||||
width: 1920,
|
width: 1920,
|
||||||
height: 1000,
|
height: 1000,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const path = require('path');
|
|||||||
const lifecycle = require('./preload/lifecycle');
|
const lifecycle = require('./preload/lifecycle');
|
||||||
const { preload } = require('./preload');
|
const { preload } = require('./preload');
|
||||||
|
|
||||||
const APP_DISPLAY_NAME = 'CN_Tool 灿能运维工具';
|
const APP_DISPLAY_NAME = '电能质量运维工具';
|
||||||
|
|
||||||
// new app
|
// new app
|
||||||
const electronApp = new ElectronEgg();
|
const electronApp = new ElectronEgg();
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ class Lifecycle {
|
|||||||
|
|
||||||
logger.info('[lifecycle] Application startup completed');
|
logger.info('[lifecycle] Application startup completed');
|
||||||
this.logWindowManager.addLog('system', '='.repeat(60));
|
this.logWindowManager.addLog('system', '='.repeat(60));
|
||||||
this.logWindowManager.addLog('success', '✓ CN_Tool 灿能运维工具 启动完成!所有服务正常运行');
|
this.logWindowManager.addLog('success', '✓ 电能质量运维工具 启动完成!所有服务正常运行');
|
||||||
this.logWindowManager.addLog('system', `✓ MySQL 端口: ${this.mysqlPort}`);
|
this.logWindowManager.addLog('system', `✓ MySQL 端口: ${this.mysqlPort}`);
|
||||||
this.logWindowManager.addLog('system', `✓ Java 端口: ${this.javaPort}`);
|
this.logWindowManager.addLog('system', `✓ Java 端口: ${this.javaPort}`);
|
||||||
this.logWindowManager.addLog('system', `✓ WebSocket 端口: ${this.websocketPort}`);
|
this.logWindowManager.addLog('system', `✓ WebSocket 端口: ${this.websocketPort}`);
|
||||||
@@ -509,7 +509,7 @@ class Lifecycle {
|
|||||||
this.logWindowManager = new LogWindowManager();
|
this.logWindowManager = new LogWindowManager();
|
||||||
// this.logWindowManager.createLogWindow(); // ← 注释掉,不创建窗口
|
// this.logWindowManager.createLogWindow(); // ← 注释掉,不创建窗口
|
||||||
this.logWindowManager.addLog('system', '='.repeat(80));
|
this.logWindowManager.addLog('system', '='.repeat(80));
|
||||||
this.logWindowManager.addLog('system', 'CN_Tool 灿能运维工具 应用启动');
|
this.logWindowManager.addLog('system', '电能质量运维工具 应用启动');
|
||||||
this.logWindowManager.addLog('system', '='.repeat(80));
|
this.logWindowManager.addLog('system', '='.repeat(80));
|
||||||
|
|
||||||
// 创建 Loading 窗口
|
// 创建 Loading 窗口
|
||||||
@@ -517,7 +517,7 @@ class Lifecycle {
|
|||||||
this.startupManager = new StartupManager();
|
this.startupManager = new StartupManager();
|
||||||
this.startupManager.createLoadingWindow();
|
this.startupManager.createLoadingWindow();
|
||||||
this.logWindowManager.addLog('system', '='.repeat(60));
|
this.logWindowManager.addLog('system', '='.repeat(60));
|
||||||
this.logWindowManager.addLog('system', 'CN_Tool 灿能运维工具 启动中...');
|
this.logWindowManager.addLog('system', '电能质量运维工具 启动中...');
|
||||||
this.logWindowManager.addLog('system', '='.repeat(60));
|
this.logWindowManager.addLog('system', '='.repeat(60));
|
||||||
|
|
||||||
// 开始启动流程
|
// 开始启动流程
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# title
|
# title
|
||||||
VITE_GLOB_APP_TITLE=CN-Tool运维工具平台
|
VITE_GLOB_APP_TITLE=电能质量运维工具
|
||||||
|
|
||||||
# 本地运行端口号
|
# 本地运行端口号
|
||||||
VITE_PORT=18091
|
VITE_PORT=18091
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { CustomAxiosRequestConfig } from "../index";
|
|||||||
import qs from "qs";
|
import qs from "qs";
|
||||||
|
|
||||||
// 声明一个 Map 用于存储每个请求的标识 和 取消函数
|
// 声明一个 Map 用于存储每个请求的标识 和 取消函数
|
||||||
let pendingMap = new Map<string, AbortController>();
|
const pendingMap = new Map<string, AbortController>();
|
||||||
|
|
||||||
// 序列化参数
|
// 序列化参数
|
||||||
export const getPendingUrl = (config: CustomAxiosRequestConfig) =>
|
export const getPendingUrl = (config: CustomAxiosRequestConfig) =>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const shouldHiddenIndex = inject<Ref<number>>('shouldHiddenIndex', ref(-1))
|
|||||||
watch(
|
watch(
|
||||||
() => [shouldHiddenIndex.value, breakPoint.value],
|
() => [shouldHiddenIndex.value, breakPoint.value],
|
||||||
n => {
|
n => {
|
||||||
if (!!attrs.index) {
|
if (attrs.index) {
|
||||||
isShow.value = !(n[0] !== -1 && parseInt(attrs.index) >= Number(n[0]))
|
isShow.value = !(n[0] !== -1 && parseInt(attrs.index) >= Number(n[0]))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const color = [
|
|||||||
|
|
||||||
const chartRef = ref<HTMLDivElement>()
|
const chartRef = ref<HTMLDivElement>()
|
||||||
|
|
||||||
const props = defineProps(['options', 'isInterVal', 'pieInterVal'])
|
const props = defineProps(['options', 'isInterVal', 'pieInterVal', 'group'])
|
||||||
let chart: echarts.ECharts | any = null
|
let chart: echarts.ECharts | any = null
|
||||||
const resizeHandler = () => {
|
const resizeHandler = () => {
|
||||||
// 不在视野中的时候不进行resize
|
// 不在视野中的时候不进行resize
|
||||||
@@ -47,6 +47,10 @@ const initChart = () => {
|
|||||||
}
|
}
|
||||||
// chart?.dispose()
|
// chart?.dispose()
|
||||||
chart = echarts.init(chartRef.value as HTMLDivElement)
|
chart = echarts.init(chartRef.value as HTMLDivElement)
|
||||||
|
if (props.group) {
|
||||||
|
chart.group = props.group
|
||||||
|
echarts.connect(props.group)
|
||||||
|
}
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
title: {
|
title: {
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ const draggable: Directive = {
|
|||||||
el.style.cursor = "move";
|
el.style.cursor = "move";
|
||||||
el.style.position = "absolute";
|
el.style.position = "absolute";
|
||||||
el.onmousedown = function (e) {
|
el.onmousedown = function (e) {
|
||||||
let disX = e.pageX - el.offsetLeft;
|
const disX = e.pageX - el.offsetLeft;
|
||||||
let disY = e.pageY - el.offsetTop;
|
const disY = e.pageY - el.offsetTop;
|
||||||
document.onmousemove = function (e) {
|
document.onmousemove = function (e) {
|
||||||
let x = e.pageX - disX;
|
let x = e.pageX - disX;
|
||||||
let y = e.pageY - disY;
|
let y = e.pageY - disY;
|
||||||
let maxX = el.parentNode.offsetWidth - el.offsetWidth;
|
const maxX = el.parentNode.offsetWidth - el.offsetWidth;
|
||||||
let maxY = el.parentNode.offsetHeight - el.offsetHeight;
|
const maxY = el.parentNode.offsetHeight - el.offsetHeight;
|
||||||
if (x < 0) {
|
if (x < 0) {
|
||||||
x = 0;
|
x = 0;
|
||||||
} else if (x > maxX) {
|
} else if (x > maxX) {
|
||||||
|
|||||||
@@ -12,12 +12,12 @@
|
|||||||
import type { Directive, DirectiveBinding } from "vue";
|
import type { Directive, DirectiveBinding } from "vue";
|
||||||
const addWaterMarker: Directive = (str: string, parentNode: any, font: any, textColor: string) => {
|
const addWaterMarker: Directive = (str: string, parentNode: any, font: any, textColor: string) => {
|
||||||
// 水印文字,父元素,字体,文字颜色
|
// 水印文字,父元素,字体,文字颜色
|
||||||
let can: HTMLCanvasElement = document.createElement("canvas");
|
const can: HTMLCanvasElement = document.createElement("canvas");
|
||||||
parentNode.appendChild(can);
|
parentNode.appendChild(can);
|
||||||
can.width = 205;
|
can.width = 205;
|
||||||
can.height = 140;
|
can.height = 140;
|
||||||
can.style.display = "none";
|
can.style.display = "none";
|
||||||
let cans = can.getContext("2d") as CanvasRenderingContext2D;
|
const cans = can.getContext("2d") as CanvasRenderingContext2D;
|
||||||
cans.rotate((-20 * Math.PI) / 180);
|
cans.rotate((-20 * Math.PI) / 180);
|
||||||
cans.font = font || "16px Microsoft JhengHei";
|
cans.font = font || "16px Microsoft JhengHei";
|
||||||
cans.fillStyle = textColor || "rgba(180, 180, 180, 0.3)";
|
cans.fillStyle = textColor || "rgba(180, 180, 180, 0.3)";
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export const useAuthButtons = () => {
|
|||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
const authButtons = authStore.authButtonListGet[route.name as string] || []
|
const authButtons = authStore.authButtonListGet[route.name as string] || []
|
||||||
const BUTTONS = computed(() => {
|
const BUTTONS = computed(() => {
|
||||||
let currentPageAuthButton: { [key: string]: boolean } = {}
|
const currentPageAuthButton: { [key: string]: boolean } = {}
|
||||||
authButtons.forEach(item => (currentPageAuthButton[item] = true))
|
authButtons.forEach(item => (currentPageAuthButton[item] = true))
|
||||||
// currentPageAuthButton.status = true
|
// currentPageAuthButton.status = true
|
||||||
return currentPageAuthButton
|
return currentPageAuthButton
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export const useSelection = (rowKey: string = "id") => {
|
|||||||
|
|
||||||
// 当前选中的所有 ids 数组
|
// 当前选中的所有 ids 数组
|
||||||
const selectedListIds = computed((): string[] => {
|
const selectedListIds = computed((): string[] => {
|
||||||
let ids: string[] = [];
|
const ids: string[] = [];
|
||||||
selectedList.value.forEach(item => ids.push(item[rowKey]));
|
selectedList.value.forEach(item => ids.push(item[rowKey]));
|
||||||
return ids;
|
return ids;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -98,9 +98,9 @@ export const useTable = (
|
|||||||
const updatedTotalParam = () => {
|
const updatedTotalParam = () => {
|
||||||
state.totalParam = {};
|
state.totalParam = {};
|
||||||
// 处理查询参数,可以给查询参数加自定义前缀操作
|
// 处理查询参数,可以给查询参数加自定义前缀操作
|
||||||
let nowSearchParam: Table.StateProps["searchParam"] = {};
|
const nowSearchParam: Table.StateProps["searchParam"] = {};
|
||||||
// 防止手动清空输入框携带参数(这里可以自定义查询参数前缀)
|
// 防止手动清空输入框携带参数(这里可以自定义查询参数前缀)
|
||||||
for (let key in state.searchParam) {
|
for (const key in state.searchParam) {
|
||||||
// 某些情况下参数为 false/0 也应该携带参数
|
// 某些情况下参数为 false/0 也应该携带参数
|
||||||
if (
|
if (
|
||||||
state.searchParam[key] ||
|
state.searchParam[key] ||
|
||||||
|
|||||||
@@ -83,7 +83,10 @@ export const resetRouter = () => {
|
|||||||
|
|
||||||
router.onError(error => {
|
router.onError(error => {
|
||||||
NProgress.done()
|
NProgress.done()
|
||||||
console.warn('Route error', error.message)
|
console.error('[router] route error', {
|
||||||
|
message: error.message,
|
||||||
|
currentPath: router.currentRoute.value.fullPath
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
router.afterEach(to => {
|
router.afterEach(to => {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { useAuthStore } from '@/stores/modules/auth'
|
|||||||
|
|
||||||
// 引入 views 文件夹下所有 vue 文件
|
// 引入 views 文件夹下所有 vue 文件
|
||||||
const modules = import.meta.glob('@/views/**/*.vue')
|
const modules = import.meta.glob('@/views/**/*.vue')
|
||||||
const STATIC_ROUTE_NAMES = new Set(['layout', 'login', 'home', '403', '404', '500'])
|
const STATIC_ROUTE_NAMES = new Set(['layout', 'login', 'home', 'tools', 'toolWaveform', 'toolMmsMapping', '403', '404', '500'])
|
||||||
|
|
||||||
let isInitializing = false
|
let isInitializing = false
|
||||||
|
|
||||||
@@ -24,11 +24,12 @@ const clearDynamicRoutes = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 component 路径查找对应的模块
|
* 根据菜单 component 路径查找对应的页面模块。
|
||||||
* @param path 组件路径
|
* 兼容两种仓库写法:
|
||||||
|
* 1. /foo/bar.vue
|
||||||
|
* 2. /foo/bar/index.vue
|
||||||
*/
|
*/
|
||||||
const resolveComponentModule = async (path: string) => {
|
const resolveComponentModule = (path: string) => {
|
||||||
// 规范化路径,去除首尾斜杠
|
|
||||||
let normalizedPath = path.trim()
|
let normalizedPath = path.trim()
|
||||||
if (!normalizedPath.startsWith('/')) {
|
if (!normalizedPath.startsWith('/')) {
|
||||||
normalizedPath = '/' + normalizedPath
|
normalizedPath = '/' + normalizedPath
|
||||||
@@ -36,9 +37,26 @@ const resolveComponentModule = async (path: string) => {
|
|||||||
if (normalizedPath.endsWith('.vue')) {
|
if (normalizedPath.endsWith('.vue')) {
|
||||||
normalizedPath = normalizedPath.slice(0, -4)
|
normalizedPath = normalizedPath.slice(0, -4)
|
||||||
}
|
}
|
||||||
|
if (normalizedPath.length > 1 && normalizedPath.endsWith('/')) {
|
||||||
|
normalizedPath = normalizedPath.slice(0, -1)
|
||||||
|
}
|
||||||
|
|
||||||
const fullPath = `/src/views${normalizedPath}.vue`
|
const candidatePaths = [`/src/views${normalizedPath}.vue`, `/src/views${normalizedPath}/index.vue`]
|
||||||
return modules[fullPath]
|
|
||||||
|
for (const candidatePath of candidatePaths) {
|
||||||
|
const moduleLoader = modules[candidatePath]
|
||||||
|
if (moduleLoader) {
|
||||||
|
return {
|
||||||
|
moduleLoader,
|
||||||
|
resolvedPath: candidatePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
moduleLoader: undefined,
|
||||||
|
resolvedPath: candidatePaths
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,6 +68,7 @@ export const initDynamicRouter = async () => {
|
|||||||
isInitializing = true
|
isInitializing = true
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
|
const unresolvedRoutes: Array<{ name?: string; path?: string; component?: string; candidates: string[] }> = []
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. 获取菜单列表 && 按钮权限列表
|
// 1. 获取菜单列表 && 按钮权限列表
|
||||||
@@ -81,11 +100,17 @@ export const initDynamicRouter = async () => {
|
|||||||
|
|
||||||
// 处理组件映射
|
// 处理组件映射
|
||||||
if (item.component && typeof item.component === 'string') {
|
if (item.component && typeof item.component === 'string') {
|
||||||
const moduleLoader = await resolveComponentModule(item.component)
|
const { moduleLoader, resolvedPath } = resolveComponentModule(item.component)
|
||||||
if (moduleLoader) {
|
if (moduleLoader) {
|
||||||
item.component = moduleLoader
|
item.component = moduleLoader
|
||||||
} else {
|
} else {
|
||||||
console.warn(`未能找到组件: ${item.component}`)
|
// 动态路由组件一旦解析失败,对应菜单会落入 404,这里必须打印清楚候选路径。
|
||||||
|
unresolvedRoutes.push({
|
||||||
|
name: item.name,
|
||||||
|
path: item.path,
|
||||||
|
component: item.component,
|
||||||
|
candidates: resolvedPath
|
||||||
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,7 +121,7 @@ export const initDynamicRouter = async () => {
|
|||||||
(typeof item.component === 'function' || typeof item.redirect === 'string')
|
(typeof item.component === 'function' || typeof item.redirect === 'string')
|
||||||
) {
|
) {
|
||||||
const routeItem = item as unknown as RouteRecordRaw
|
const routeItem = item as unknown as RouteRecordRaw
|
||||||
if (item.meta.isFull) {
|
if (item.meta?.isFull) {
|
||||||
router.addRoute(routeItem)
|
router.addRoute(routeItem)
|
||||||
} else {
|
} else {
|
||||||
router.addRoute('layout', routeItem)
|
router.addRoute('layout', routeItem)
|
||||||
@@ -105,6 +130,10 @@ export const initDynamicRouter = async () => {
|
|||||||
console.warn('Invalid route item:', item)
|
console.warn('Invalid route item:', item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unresolvedRoutes.length) {
|
||||||
|
console.error('[dynamic-router] unresolved route components', unresolvedRoutes)
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 当按钮 || 菜单请求出错时,重定向到登陆页
|
// 当按钮 || 菜单请求出错时,重定向到登陆页
|
||||||
userStore.setAccessToken('')
|
userStore.setAccessToken('')
|
||||||
|
|||||||
@@ -34,6 +34,31 @@ export const staticRouter: RouteRecordRaw[] = [
|
|||||||
isKeepAlive: false
|
isKeepAlive: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/tools',
|
||||||
|
name: 'tools',
|
||||||
|
component: () => import('@/views/tools/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '工具中心'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/tools/waveform',
|
||||||
|
name: 'toolWaveform',
|
||||||
|
component: () => import('@/views/tools/waveform/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '波形查看'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/tools/mmsMapping',
|
||||||
|
name: 'toolMmsMapping',
|
||||||
|
alias: ['/tools/mmsmapping', '/tools/mms-mapping'],
|
||||||
|
component: () => import('@/views/tools/mmsMapping/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'MMS 映射'
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/403',
|
path: '/403',
|
||||||
name: '403',
|
name: '403',
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export function isType(val: any) {
|
|||||||
export function generateUUID() {
|
export function generateUUID() {
|
||||||
let uuid = "";
|
let uuid = "";
|
||||||
for (let i = 0; i < 32; i++) {
|
for (let i = 0; i < 32; i++) {
|
||||||
let random = (Math.random() * 16) | 0;
|
const random = (Math.random() * 16) | 0;
|
||||||
if (i === 8 || i === 12 || i === 16 || i === 20) uuid += "-";
|
if (i === 8 || i === 12 || i === 16 || i === 20) uuid += "-";
|
||||||
uuid += (i === 12 ? 4 : i === 16 ? (random & 3) | 8 : random).toString(16);
|
uuid += (i === 12 ? 4 : i === 16 ? (random & 3) | 8 : random).toString(16);
|
||||||
}
|
}
|
||||||
@@ -77,13 +77,13 @@ export function generateUUID() {
|
|||||||
*/
|
*/
|
||||||
export function isObjectValueEqual(a: { [key: string]: any }, b: { [key: string]: any }) {
|
export function isObjectValueEqual(a: { [key: string]: any }, b: { [key: string]: any }) {
|
||||||
if (!a || !b) return false;
|
if (!a || !b) return false;
|
||||||
let aProps = Object.getOwnPropertyNames(a);
|
const aProps = Object.getOwnPropertyNames(a);
|
||||||
let bProps = Object.getOwnPropertyNames(b);
|
const bProps = Object.getOwnPropertyNames(b);
|
||||||
if (aProps.length != bProps.length) return false;
|
if (aProps.length != bProps.length) return false;
|
||||||
for (let i = 0; i < aProps.length; i++) {
|
for (let i = 0; i < aProps.length; i++) {
|
||||||
let propName = aProps[i];
|
const propName = aProps[i];
|
||||||
let propA = a[propName];
|
const propA = a[propName];
|
||||||
let propB = b[propName];
|
const propB = b[propName];
|
||||||
if (!b.hasOwnProperty(propName)) return false;
|
if (!b.hasOwnProperty(propName)) return false;
|
||||||
if (propA instanceof Object) {
|
if (propA instanceof Object) {
|
||||||
if (!isObjectValueEqual(propA, propB)) return false;
|
if (!isObjectValueEqual(propA, propB)) return false;
|
||||||
@@ -101,7 +101,7 @@ export function isObjectValueEqual(a: { [key: string]: any }, b: { [key: string]
|
|||||||
* @returns {Number}
|
* @returns {Number}
|
||||||
*/
|
*/
|
||||||
export function randomNum(min: number, max: number): number {
|
export function randomNum(min: number, max: number): number {
|
||||||
let num = Math.floor(Math.random() * (min - max) + max);
|
const num = Math.floor(Math.random() * (min - max) + max);
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,8 +110,8 @@ export function randomNum(min: number, max: number): number {
|
|||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
export function getTimeState() {
|
export function getTimeState() {
|
||||||
let timeNow = new Date();
|
const timeNow = new Date();
|
||||||
let hours = timeNow.getHours();
|
const hours = timeNow.getHours();
|
||||||
if (hours >= 6 && hours <= 10) return `早上好 ⛅`;
|
if (hours >= 6 && hours <= 10) return `早上好 ⛅`;
|
||||||
if (hours >= 10 && hours <= 14) return `中午好 🌞`;
|
if (hours >= 10 && hours <= 14) return `中午好 🌞`;
|
||||||
if (hours >= 14 && hours <= 18) return `下午好 🌞`;
|
if (hours >= 14 && hours <= 18) return `下午好 🌞`;
|
||||||
@@ -124,7 +124,7 @@ export function getTimeState() {
|
|||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
export function getBrowserLang() {
|
export function getBrowserLang() {
|
||||||
let browserLang = navigator.language ? navigator.language : navigator.browserLanguage;
|
const browserLang = navigator.language ? navigator.language : navigator.browserLanguage;
|
||||||
let defaultBrowserLang = "";
|
let defaultBrowserLang = "";
|
||||||
if (["cn", "zh", "zh-cn"].includes(browserLang.toLowerCase())) {
|
if (["cn", "zh", "zh-cn"].includes(browserLang.toLowerCase())) {
|
||||||
defaultBrowserLang = "zh";
|
defaultBrowserLang = "zh";
|
||||||
@@ -152,7 +152,7 @@ export function getUrlWithParams() {
|
|||||||
* @returns {Array}
|
* @returns {Array}
|
||||||
*/
|
*/
|
||||||
export function getFlatMenuList(menuList: Menu.MenuOptions[]): Menu.MenuOptions[] {
|
export function getFlatMenuList(menuList: Menu.MenuOptions[]): Menu.MenuOptions[] {
|
||||||
let newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList));
|
const newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList));
|
||||||
return newMenuList.flatMap(item => [item, ...(item.children ? getFlatMenuList(item.children) : [])]);
|
return newMenuList.flatMap(item => [item, ...(item.children ? getFlatMenuList(item.children) : [])]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ export function getFlatMenuList(menuList: Menu.MenuOptions[]): Menu.MenuOptions[
|
|||||||
* @returns {Array}
|
* @returns {Array}
|
||||||
* */
|
* */
|
||||||
export function getShowMenuList(menuList: Menu.MenuOptions[]) {
|
export function getShowMenuList(menuList: Menu.MenuOptions[]) {
|
||||||
let newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList));
|
const newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList));
|
||||||
return newMenuList.filter(item => {
|
return newMenuList.filter(item => {
|
||||||
item.children?.length && (item.children = getShowMenuList(item.children));
|
item.children?.length && (item.children = getShowMenuList(item.children));
|
||||||
return !item.meta?.isHide;
|
return !item.meta?.isHide;
|
||||||
|
|||||||
@@ -1,2 +1,34 @@
|
|||||||
/* global css variable */
|
/* global css variable */
|
||||||
$primary-color: var(--el-color-primary);
|
$primary-color: var(--el-color-primary);
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* 波形图三相颜色 */
|
||||||
|
--cn-color-phase-a: #daa520;
|
||||||
|
--cn-color-phase-b: #2e8b57;
|
||||||
|
--cn-color-phase-c: #a52a2a;
|
||||||
|
|
||||||
|
/* 波形状态与常用业务颜色 */
|
||||||
|
--cn-color-run: #20b2aa;
|
||||||
|
--cn-color-breaks: #f4a460;
|
||||||
|
--cn-color-grey: #696969;
|
||||||
|
--cn-color-blue: #87ceeb;
|
||||||
|
--cn-color-orange: #ff7e50;
|
||||||
|
|
||||||
|
/* 画布与基础展示颜色 */
|
||||||
|
--cn-color-canvas-bg: #f9f9f9;
|
||||||
|
--cn-color-white: #ffffff;
|
||||||
|
--cn-color-purple: #800080;
|
||||||
|
--cn-color-lightgray: #cccccc;
|
||||||
|
--cn-color-dark-red: #a0522d;
|
||||||
|
|
||||||
|
/* ITIC 与 F47 曲线颜色 */
|
||||||
|
--cn-color-itic-top: #ff7e50;
|
||||||
|
--cn-color-itic-bottom: #00e3e3;
|
||||||
|
|
||||||
|
/* 电网主题与无数据状态颜色 */
|
||||||
|
--cn-color-guowang: #006565;
|
||||||
|
--cn-color-nanwang: #003078;
|
||||||
|
--cn-color-theme: #003078;
|
||||||
|
--cn-color-no-monitor: #cccccc;
|
||||||
|
--cn-color-no-data: #808080;
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { ElMessage } from "element-plus";
|
|||||||
*/
|
*/
|
||||||
export function hexToRgb(str: any) {
|
export function hexToRgb(str: any) {
|
||||||
let hexs: any = "";
|
let hexs: any = "";
|
||||||
let reg = /^\#?[0-9A-Fa-f]{6}$/;
|
const reg = /^\#?[0-9A-Fa-f]{6}$/;
|
||||||
if (!reg.test(str)) return ElMessage.warning("输入错误的hex");
|
if (!reg.test(str)) return ElMessage.warning("输入错误的hex");
|
||||||
str = str.replace("#", "");
|
str = str.replace("#", "");
|
||||||
hexs = str.match(/../g);
|
hexs = str.match(/../g);
|
||||||
@@ -23,9 +23,9 @@ export function hexToRgb(str: any) {
|
|||||||
* @returns {String} 返回处理后的颜色值
|
* @returns {String} 返回处理后的颜色值
|
||||||
*/
|
*/
|
||||||
export function rgbToHex(r: any, g: any, b: any) {
|
export function rgbToHex(r: any, g: any, b: any) {
|
||||||
let reg = /^\d{1,3}$/;
|
const reg = /^\d{1,3}$/;
|
||||||
if (!reg.test(r) || !reg.test(g) || !reg.test(b)) return ElMessage.warning("输入错误的rgb颜色值");
|
if (!reg.test(r) || !reg.test(g) || !reg.test(b)) return ElMessage.warning("输入错误的rgb颜色值");
|
||||||
let hexs = [r.toString(16), g.toString(16), b.toString(16)];
|
const hexs = [r.toString(16), g.toString(16), b.toString(16)];
|
||||||
for (let i = 0; i < 3; i++) if (hexs[i].length == 1) hexs[i] = `0${hexs[i]}`;
|
for (let i = 0; i < 3; i++) if (hexs[i].length == 1) hexs[i] = `0${hexs[i]}`;
|
||||||
return `#${hexs.join("")}`;
|
return `#${hexs.join("")}`;
|
||||||
}
|
}
|
||||||
@@ -38,9 +38,9 @@ export function rgbToHex(r: any, g: any, b: any) {
|
|||||||
*/
|
*/
|
||||||
export function getDarkColor(color: string, level: number) {
|
export function getDarkColor(color: string, level: number) {
|
||||||
|
|
||||||
let reg = /^\#?[0-9A-Fa-f]{6}$/;
|
const reg = /^\#?[0-9A-Fa-f]{6}$/;
|
||||||
if (!reg.test(color)) return ElMessage.warning("输入错误的hex颜色值");
|
if (!reg.test(color)) return ElMessage.warning("输入错误的hex颜色值");
|
||||||
let rgb = hexToRgb(color);
|
const rgb = hexToRgb(color);
|
||||||
for (let i = 0; i < 3; i++) rgb[i] = Math.round(20.5 * level + rgb[i] * (1 - level));
|
for (let i = 0; i < 3; i++) rgb[i] = Math.round(20.5 * level + rgb[i] * (1 - level));
|
||||||
return rgbToHex(rgb[0], rgb[1], rgb[2]);
|
return rgbToHex(rgb[0], rgb[1], rgb[2]);
|
||||||
}
|
}
|
||||||
@@ -53,9 +53,9 @@ export function getDarkColor(color: string, level: number) {
|
|||||||
*/
|
*/
|
||||||
export function getLightColor(color: string, level: number) {
|
export function getLightColor(color: string, level: number) {
|
||||||
|
|
||||||
let reg = /^\#?[0-9A-Fa-f]{6}$/;
|
const reg = /^\#?[0-9A-Fa-f]{6}$/;
|
||||||
if (!reg.test(color)) return ElMessage.warning("输入错误的hex颜色值");
|
if (!reg.test(color)) return ElMessage.warning("输入错误的hex颜色值");
|
||||||
let rgb = hexToRgb(color);
|
const rgb = hexToRgb(color);
|
||||||
for (let i = 0; i < 3; i++) rgb[i] = Math.round(255 * level + rgb[i] * (1 - level));
|
for (let i = 0; i < 3; i++) rgb[i] = Math.round(255 * level + rgb[i] * (1 - level));
|
||||||
return rgbToHex(rgb[0], rgb[1], rgb[2]);
|
return rgbToHex(rgb[0], rgb[1], rgb[2]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export function isType(val: any) {
|
|||||||
export function generateUUID() {
|
export function generateUUID() {
|
||||||
let uuid = ''
|
let uuid = ''
|
||||||
for (let i = 0; i < 32; i++) {
|
for (let i = 0; i < 32; i++) {
|
||||||
let random = (Math.random() * 16) | 0
|
const random = (Math.random() * 16) | 0
|
||||||
if (i === 8 || i === 12 || i === 16 || i === 20) uuid += '-'
|
if (i === 8 || i === 12 || i === 16 || i === 20) uuid += '-'
|
||||||
uuid += (i === 12 ? 4 : i === 16 ? (random & 3) | 8 : random).toString(16)
|
uuid += (i === 12 ? 4 : i === 16 ? (random & 3) | 8 : random).toString(16)
|
||||||
}
|
}
|
||||||
@@ -77,13 +77,13 @@ export function generateUUID() {
|
|||||||
*/
|
*/
|
||||||
export function isObjectValueEqual(a: { [key: string]: any }, b: { [key: string]: any }) {
|
export function isObjectValueEqual(a: { [key: string]: any }, b: { [key: string]: any }) {
|
||||||
if (!a || !b) return false
|
if (!a || !b) return false
|
||||||
let aProps = Object.getOwnPropertyNames(a)
|
const aProps = Object.getOwnPropertyNames(a)
|
||||||
let bProps = Object.getOwnPropertyNames(b)
|
const bProps = Object.getOwnPropertyNames(b)
|
||||||
if (aProps.length != bProps.length) return false
|
if (aProps.length != bProps.length) return false
|
||||||
for (let i = 0; i < aProps.length; i++) {
|
for (let i = 0; i < aProps.length; i++) {
|
||||||
let propName = aProps[i]
|
const propName = aProps[i]
|
||||||
let propA = a[propName]
|
const propA = a[propName]
|
||||||
let propB = b[propName]
|
const propB = b[propName]
|
||||||
if (!b.hasOwnProperty(propName)) return false
|
if (!b.hasOwnProperty(propName)) return false
|
||||||
if (propA instanceof Object) {
|
if (propA instanceof Object) {
|
||||||
if (!isObjectValueEqual(propA, propB)) return false
|
if (!isObjectValueEqual(propA, propB)) return false
|
||||||
@@ -101,7 +101,7 @@ export function isObjectValueEqual(a: { [key: string]: any }, b: { [key: string]
|
|||||||
* @returns {Number}
|
* @returns {Number}
|
||||||
*/
|
*/
|
||||||
export function randomNum(min: number, max: number): number {
|
export function randomNum(min: number, max: number): number {
|
||||||
let num = Math.floor(Math.random() * (min - max) + max)
|
const num = Math.floor(Math.random() * (min - max) + max)
|
||||||
return num
|
return num
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,8 +110,8 @@ export function randomNum(min: number, max: number): number {
|
|||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
export function getTimeState() {
|
export function getTimeState() {
|
||||||
let timeNow = new Date()
|
const timeNow = new Date()
|
||||||
let hours = timeNow.getHours()
|
const hours = timeNow.getHours()
|
||||||
if (hours >= 6 && hours <= 10) return `早上好 ⛅`
|
if (hours >= 6 && hours <= 10) return `早上好 ⛅`
|
||||||
if (hours >= 10 && hours <= 14) return `中午好 🌞`
|
if (hours >= 10 && hours <= 14) return `中午好 🌞`
|
||||||
if (hours >= 14 && hours <= 18) return `下午好 🌞`
|
if (hours >= 14 && hours <= 18) return `下午好 🌞`
|
||||||
@@ -124,7 +124,7 @@ export function getTimeState() {
|
|||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
export function getBrowserLang() {
|
export function getBrowserLang() {
|
||||||
let browserLang = navigator.language ? navigator.language : navigator.browserLanguage
|
const browserLang = navigator.language ? navigator.language : navigator.browserLanguage
|
||||||
let defaultBrowserLang = ''
|
let defaultBrowserLang = ''
|
||||||
if (['cn', 'zh', 'zh-cn'].includes(browserLang.toLowerCase())) {
|
if (['cn', 'zh', 'zh-cn'].includes(browserLang.toLowerCase())) {
|
||||||
defaultBrowserLang = 'zh'
|
defaultBrowserLang = 'zh'
|
||||||
@@ -152,7 +152,7 @@ export function getUrlWithParams() {
|
|||||||
* @returns {Array}
|
* @returns {Array}
|
||||||
*/
|
*/
|
||||||
export function getFlatMenuList(menuList: Menu.MenuOptions[]): Menu.MenuOptions[] {
|
export function getFlatMenuList(menuList: Menu.MenuOptions[]): Menu.MenuOptions[] {
|
||||||
let newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList))
|
const newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList))
|
||||||
return newMenuList.flatMap(item => [item, ...(item.children ? getFlatMenuList(item.children) : [])])
|
return newMenuList.flatMap(item => [item, ...(item.children ? getFlatMenuList(item.children) : [])])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ export function getFlatMenuList(menuList: Menu.MenuOptions[]): Menu.MenuOptions[
|
|||||||
* @returns {Array}
|
* @returns {Array}
|
||||||
* */
|
* */
|
||||||
export function getShowMenuList(menuList: Menu.MenuOptions[]) {
|
export function getShowMenuList(menuList: Menu.MenuOptions[]) {
|
||||||
let newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList))
|
const newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList))
|
||||||
return newMenuList.filter(item => {
|
return newMenuList.filter(item => {
|
||||||
item.children?.length && (item.children = getShowMenuList(item.children))
|
item.children?.length && (item.children = getShowMenuList(item.children))
|
||||||
return !item.meta?.isHide
|
return !item.meta?.isHide
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>CN_Tool 灿能运维工具 正在启动...</title>
|
<title>电能质量运维工具 正在启动...</title>
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -145,7 +145,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="loading-container">
|
<div class="loading-container">
|
||||||
<div class="logo">CN_Tool 灿能运维工具</div>
|
<div class="logo">电能质量运维工具</div>
|
||||||
<div class="subtitle">南京灿能电力自动化股份有限公司</div>
|
<div class="subtitle">南京灿能电力自动化股份有限公司</div>
|
||||||
|
|
||||||
<div class="status-text" id="statusText">正在初始化应用...</div>
|
<div class="status-text" id="statusText">正在初始化应用...</div>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class LogWindowManager {
|
|||||||
|
|
||||||
// 写入启动标记
|
// 写入启动标记
|
||||||
this.writeToFile(new Date().toISOString().replace('T', ' ').substring(0, 19), 'SYSTEM', '=' .repeat(80));
|
this.writeToFile(new Date().toISOString().replace('T', ' ').substring(0, 19), 'SYSTEM', '=' .repeat(80));
|
||||||
this.writeToFile(new Date().toISOString().replace('T', ' ').substring(0, 19), 'SYSTEM', 'CN_Tool 灿能运维工具 应用启动');
|
this.writeToFile(new Date().toISOString().replace('T', ' ').substring(0, 19), 'SYSTEM', '电能质量运维工具 应用启动');
|
||||||
this.writeToFile(new Date().toISOString().replace('T', ' ').substring(0, 19), 'SYSTEM', '=' .repeat(80));
|
this.writeToFile(new Date().toISOString().replace('T', ' ').substring(0, 19), 'SYSTEM', '=' .repeat(80));
|
||||||
|
|
||||||
// 清理超过30天的旧日志
|
// 清理超过30天的旧日志
|
||||||
@@ -110,7 +110,7 @@ class LogWindowManager {
|
|||||||
this.logWindow = new BrowserWindow({
|
this.logWindow = new BrowserWindow({
|
||||||
width: 900,
|
width: 900,
|
||||||
height: 600,
|
height: 600,
|
||||||
title: 'CN_Tool 灿能运维工具 - 服务日志',
|
title: '电能质量运维工具 - 服务日志',
|
||||||
backgroundColor: '#1e1e1e',
|
backgroundColor: '#1e1e1e',
|
||||||
icon: iconPath,
|
icon: iconPath,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
@@ -152,7 +152,7 @@ class LogWindowManager {
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>CN_Tool 灿能运维工具 服务日志</title>
|
<title>电能质量运维工具 服务日志</title>
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -235,7 +235,7 @@ class LogWindowManager {
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="title">📝 CN_Tool 灿能运维工具 服务日志监控</div>
|
<div class="title">📝 电能质量运维工具 服务日志监控</div>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<button onclick="clearLogs()">清空日志</button>
|
<button onclick="clearLogs()">清空日志</button>
|
||||||
<button onclick="toggleAutoScroll()">自动滚动: <span id="autoScrollStatus">开</span></button>
|
<button onclick="toggleAutoScroll()">自动滚动: <span id="autoScrollStatus">开</span></button>
|
||||||
|
|||||||
Reference in New Issue
Block a user