优化项目
This commit is contained in:
59
src/utils/chartAxisHelper.ts
Normal file
59
src/utils/chartAxisHelper.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
const AXIS_DECIMALS = 2
|
||||
|
||||
export function roundAxisValue(val: number, decimals = AXIS_DECIMALS): number {
|
||||
if (!Number.isFinite(val)) return 0
|
||||
const factor = 10 ** decimals
|
||||
return Math.round(val * factor) / factor
|
||||
}
|
||||
|
||||
/** Y 轴刻度:最多 2 位小数,末尾 0 去掉(如 1.00 → 1,0.10 → 0.1) */
|
||||
export function formatAxisLabel(value: number): string {
|
||||
if (!Number.isFinite(value)) return '0'
|
||||
return String(Number(roundAxisValue(value).toFixed(AXIS_DECIMALS)))
|
||||
}
|
||||
|
||||
/** 瞬间波形 Y 轴范围 */
|
||||
export function calcShuYAxisRange(dataMin: number, dataMax: number): { min: number; max: number } {
|
||||
const min = Number(dataMin)
|
||||
const max = Number(dataMax)
|
||||
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
||||
return { min: 0, max: 1 }
|
||||
}
|
||||
|
||||
let axisMax = max * 1.1
|
||||
let axisMin = min > 0 ? min - min * 0.1 : min * 1.1
|
||||
|
||||
if (axisMax <= axisMin) {
|
||||
const pad = Math.abs(max) * 0.1 || 0.01
|
||||
axisMax = max + pad
|
||||
axisMin = min - pad
|
||||
}
|
||||
|
||||
return {
|
||||
min: roundAxisValue(axisMin),
|
||||
max: roundAxisValue(axisMax)
|
||||
}
|
||||
}
|
||||
|
||||
/** RMS 波形 Y 轴范围 */
|
||||
export function calcRmsYAxisRange(dataMin: number, dataMax: number): { min: number; max: number } {
|
||||
const min = Number(dataMin)
|
||||
const max = Number(dataMax)
|
||||
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
||||
return { min: 0, max: 1 }
|
||||
}
|
||||
|
||||
let axisMax = max * 1.06 * 1.1
|
||||
let axisMin = min - min * 0.2
|
||||
|
||||
if (axisMax <= axisMin) {
|
||||
const pad = Math.abs(max - min) * 0.1 || Math.abs(max) * 0.1 || 0.01
|
||||
axisMax = max + pad
|
||||
axisMin = min - pad
|
||||
}
|
||||
|
||||
return {
|
||||
min: roundAxisValue(axisMin),
|
||||
max: roundAxisValue(axisMax)
|
||||
}
|
||||
}
|
||||
83
src/utils/luckysheetHelper.ts
Normal file
83
src/utils/luckysheetHelper.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { exportExcel } from '@/views/system/reportForms/export.js'
|
||||
|
||||
/** 解析 Luckysheet 接口返回的 sheet 数据 */
|
||||
export function parseLuckysheetSheets(sheets: any[]) {
|
||||
sheets.forEach((item: any) => {
|
||||
if (item.data1) {
|
||||
try {
|
||||
item.data = JSON.parse(item.data1)
|
||||
} catch {
|
||||
/* ignore invalid json */
|
||||
}
|
||||
}
|
||||
item.celldata?.forEach((cell: any) => {
|
||||
if (item.data?.[cell.r]?.[cell.c]?.v != null) {
|
||||
item.data[cell.r][cell.c] = cell.v
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
declare const luckysheet: any
|
||||
|
||||
const DEFAULT_REPORT_OPTIONS = {
|
||||
title: '',
|
||||
lang: 'zh',
|
||||
showtoolbar: false,
|
||||
showinfobar: false,
|
||||
showsheetbar: true,
|
||||
}
|
||||
|
||||
/** 销毁已有 Luckysheet 实例,避免重复 create 导致 DOM 堆积 */
|
||||
export function destroyLuckysheet() {
|
||||
try {
|
||||
if (typeof luckysheet !== 'undefined' && luckysheet.destroy) {
|
||||
luckysheet.destroy()
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
/** 解析 sheet 数据、销毁旧实例并渲染报表 */
|
||||
export function renderLuckysheetReport(
|
||||
container: string,
|
||||
sheets: any[],
|
||||
options: Record<string, any> = {}
|
||||
) {
|
||||
parseLuckysheetSheets(sheets)
|
||||
destroyLuckysheet()
|
||||
setTimeout(() => {
|
||||
luckysheet.create({
|
||||
container,
|
||||
...DEFAULT_REPORT_OPTIONS,
|
||||
...options,
|
||||
data: sheets,
|
||||
})
|
||||
}, 10)
|
||||
}
|
||||
|
||||
/** 安全导出 Luckysheet,无数据时提示并返回 false */
|
||||
export function exportLuckysheetFile(filename: string, hasData = true): boolean {
|
||||
if (!hasData) {
|
||||
ElMessage.warning('暂无数据')
|
||||
return false
|
||||
}
|
||||
try {
|
||||
if (typeof luckysheet === 'undefined' || !luckysheet.getAllSheets) {
|
||||
ElMessage.warning('暂无数据')
|
||||
return false
|
||||
}
|
||||
const sheets = luckysheet.getAllSheets()
|
||||
if (!sheets?.length) {
|
||||
ElMessage.warning('暂无数据')
|
||||
return false
|
||||
}
|
||||
exportExcel(sheets, filename)
|
||||
return true
|
||||
} catch {
|
||||
ElMessage.warning('导出失败,请先加载报表数据')
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -1,45 +1,60 @@
|
||||
/**
|
||||
* window.localStorage
|
||||
* @method set 设置
|
||||
* @method get 获取
|
||||
* @method remove 移除
|
||||
* @method clear 移除全部
|
||||
*/
|
||||
export const Local = {
|
||||
set(key: string, val: any) {
|
||||
window.localStorage.setItem(key, JSON.stringify(val))
|
||||
},
|
||||
get(key: string) {
|
||||
const json: any = window.localStorage.getItem(key)
|
||||
return JSON.parse(json)
|
||||
},
|
||||
remove(key: string) {
|
||||
window.localStorage.removeItem(key)
|
||||
},
|
||||
clear() {
|
||||
window.localStorage.clear()
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* window.sessionStorage
|
||||
* @method set 设置会话缓存
|
||||
* @method get 获取会话缓存
|
||||
* @method remove 移除会话缓存
|
||||
* @method clear 移除全部会话缓存
|
||||
*/
|
||||
export const Session = {
|
||||
set(key: string, val: any) {
|
||||
window.sessionStorage.setItem(key, JSON.stringify(val))
|
||||
},
|
||||
get(key: string) {
|
||||
const json: any = window.sessionStorage.getItem(key)
|
||||
return JSON.parse(json)
|
||||
},
|
||||
remove(key: string) {
|
||||
window.sessionStorage.removeItem(key)
|
||||
},
|
||||
clear() {
|
||||
window.sessionStorage.clear()
|
||||
},
|
||||
}
|
||||
/**
|
||||
* window.localStorage
|
||||
* @method set 设置
|
||||
* @method get 获取
|
||||
* @method remove 移除
|
||||
* @method clear 移除全部
|
||||
*/
|
||||
export const Local = {
|
||||
set(key: string, val: any) {
|
||||
window.localStorage.setItem(key, JSON.stringify(val))
|
||||
},
|
||||
get(key: string) {
|
||||
const json: any = window.localStorage.getItem(key)
|
||||
return JSON.parse(json)
|
||||
},
|
||||
remove(key: string) {
|
||||
window.localStorage.removeItem(key)
|
||||
},
|
||||
clear() {
|
||||
window.localStorage.clear()
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* window.sessionStorage
|
||||
* @method set 设置会话缓存
|
||||
* @method get 获取会话缓存
|
||||
* @method remove 移除会话缓存
|
||||
* @method clear 移除全部会话缓存
|
||||
*/
|
||||
const DEFAULT_THEME_NAME = '电能质量监测系统'
|
||||
|
||||
export function getStoredTheme(): { name?: string; logoUrl?: string; [key: string]: any } {
|
||||
try {
|
||||
const raw = window.localStorage.getItem('getTheme')
|
||||
return raw ? JSON.parse(raw) : {}
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
export function getStoredThemeName(): string {
|
||||
return getStoredTheme().name || DEFAULT_THEME_NAME
|
||||
}
|
||||
|
||||
export const Session = {
|
||||
set(key: string, val: any) {
|
||||
window.sessionStorage.setItem(key, JSON.stringify(val))
|
||||
},
|
||||
get(key: string) {
|
||||
const json: any = window.sessionStorage.getItem(key)
|
||||
return JSON.parse(json)
|
||||
},
|
||||
remove(key: string) {
|
||||
window.sessionStorage.removeItem(key)
|
||||
},
|
||||
clear() {
|
||||
window.sessionStorage.clear()
|
||||
},
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ interface TableStoreParams {
|
||||
resetCallback?: () => void // 重置
|
||||
loadCallback?: () => void // 接口调用后的回调
|
||||
exportProcessingData?: () => void //导出处理数据
|
||||
beforeSearchFun?: () => void // 接口调用前的回调
|
||||
beforeSearchFun?: () => void | boolean // 接口调用前的回调,返回 false 中止请求
|
||||
}
|
||||
|
||||
export default class TableStore {
|
||||
@@ -75,7 +75,13 @@ export default class TableStore {
|
||||
}
|
||||
|
||||
index() {
|
||||
this.table.beforeSearchFun && this.table.beforeSearchFun()
|
||||
if (this.table.beforeSearchFun) {
|
||||
const canSearch = this.table.beforeSearchFun()
|
||||
if (canSearch === false) {
|
||||
this.table.loading = false
|
||||
return
|
||||
}
|
||||
}
|
||||
this.table.data = []
|
||||
this.table.loading = true
|
||||
// 重置用的数据数据
|
||||
|
||||
42
src/utils/waveCache.ts
Normal file
42
src/utils/waveCache.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
const MAX_CACHE_SIZE = 30
|
||||
|
||||
const cache = new Map<string, unknown>()
|
||||
|
||||
function dataFingerprint(data: unknown[][] | undefined): string {
|
||||
if (!data?.length) return '0'
|
||||
const first = data[0]
|
||||
const last = data[data.length - 1]
|
||||
return `${data.length}:${first?.[0]}:${last?.[0]}`
|
||||
}
|
||||
|
||||
export function buildWaveCacheKey(
|
||||
type: 'shu' | 'rms',
|
||||
wp: Record<string, any> | undefined,
|
||||
value: number,
|
||||
isOpen: boolean,
|
||||
boxoList: Record<string, any>
|
||||
): string {
|
||||
if (!wp) return ''
|
||||
const waveFp =
|
||||
type === 'shu' ? dataFingerprint(wp.listWaveData) : dataFingerprint(wp.listRmsData)
|
||||
const boxoFp = boxoList?.startTime ?? boxoList?.lineName ?? boxoList?.equipmentName ?? ''
|
||||
return `${type}|${wp.time}|${wp.waveType}|${wp.iphasic}|${value}|${isOpen}|${waveFp}|${boxoFp}`
|
||||
}
|
||||
|
||||
export function getWaveCache<T>(key: string): T | null {
|
||||
if (!key || !cache.has(key)) return null
|
||||
const value = cache.get(key) as T
|
||||
cache.delete(key)
|
||||
cache.set(key, value)
|
||||
return value
|
||||
}
|
||||
|
||||
export function setWaveCache(key: string, value: unknown): void {
|
||||
if (!key) return
|
||||
if (cache.has(key)) cache.delete(key)
|
||||
cache.set(key, value)
|
||||
while (cache.size > MAX_CACHE_SIZE) {
|
||||
const oldest = cache.keys().next().value
|
||||
if (oldest !== undefined) cache.delete(oldest)
|
||||
}
|
||||
}
|
||||
96
src/utils/waveWorkerPool.ts
Normal file
96
src/utils/waveWorkerPool.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { toRaw } from 'vue'
|
||||
|
||||
type WorkerMessageHandler = (data: any) => void
|
||||
|
||||
let shuWorker: Worker | null = null
|
||||
let rmsWorker: Worker | null = null
|
||||
|
||||
/** 递归剥离 Vue 响应式代理,得到可 structuredClone 的纯对象 */
|
||||
export function toPlainDeep<T>(value: T): T {
|
||||
const raw = toRaw(value as object) as T
|
||||
if (Array.isArray(raw)) {
|
||||
return raw.map(item => toPlainDeep(item)) as T
|
||||
}
|
||||
if (raw !== null && typeof raw === 'object') {
|
||||
const out: Record<string, unknown> = {}
|
||||
for (const [key, val] of Object.entries(raw)) {
|
||||
out[key] = toPlainDeep(val)
|
||||
}
|
||||
return out as T
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
const BOXO_LIST_KEYS = [
|
||||
'systemType',
|
||||
'powerStationName',
|
||||
'measurementPointName',
|
||||
'startTime',
|
||||
'featureAmplitude',
|
||||
'duration',
|
||||
'engineeringName',
|
||||
'equipmentName',
|
||||
'evtParamVVaDepth',
|
||||
'evtParamTm',
|
||||
'lineName',
|
||||
'persistTime',
|
||||
'subName'
|
||||
] as const
|
||||
|
||||
export function buildWorkerPayload(
|
||||
type: 'shu' | 'rms',
|
||||
wp: Record<string, any>,
|
||||
boxoList: Record<string, any>,
|
||||
extras: { requestId: number; value: number; isOpen: boolean; iphasic?: number }
|
||||
) {
|
||||
const plainWp = toPlainDeep(wp)
|
||||
const wpPayload: Record<string, unknown> = {
|
||||
pt: plainWp.pt,
|
||||
ct: plainWp.ct,
|
||||
waveTitle: plainWp.waveTitle,
|
||||
iphasic: plainWp.iphasic,
|
||||
time: plainWp.time,
|
||||
waveType: plainWp.waveType,
|
||||
yzd: plainWp.yzd
|
||||
}
|
||||
if (type === 'shu') {
|
||||
wpPayload.listWaveData = plainWp.listWaveData
|
||||
} else {
|
||||
wpPayload.listRmsData = plainWp.listRmsData
|
||||
}
|
||||
|
||||
const plainBoxo: Record<string, unknown> = {}
|
||||
const rawBoxo = toPlainDeep(boxoList)
|
||||
for (const key of BOXO_LIST_KEYS) {
|
||||
if (rawBoxo[key] !== undefined) {
|
||||
plainBoxo[key] = rawBoxo[key]
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
requestId: extras.requestId,
|
||||
value: extras.value,
|
||||
isOpen: extras.isOpen,
|
||||
iphasic: extras.iphasic,
|
||||
wp: wpPayload,
|
||||
boxoList: plainBoxo
|
||||
}
|
||||
}
|
||||
|
||||
export function getShuWorker(onMessage: WorkerMessageHandler): Worker {
|
||||
if (!shuWorker) {
|
||||
shuWorker = new Worker(new URL('../components/echarts/shuWorker.js', import.meta.url))
|
||||
}
|
||||
shuWorker.onmessage = e => onMessage(e.data)
|
||||
shuWorker.onerror = error => console.error('Shu worker error:', error)
|
||||
return shuWorker
|
||||
}
|
||||
|
||||
export function getRmsWorker(onMessage: WorkerMessageHandler): Worker {
|
||||
if (!rmsWorker) {
|
||||
rmsWorker = new Worker(new URL('../components/echarts/rmsWorker.js', import.meta.url))
|
||||
}
|
||||
rmsWorker.onmessage = e => onMessage(e.data)
|
||||
rmsWorker.onerror = error => console.error('Rms worker error:', error)
|
||||
return rmsWorker
|
||||
}
|
||||
Reference in New Issue
Block a user