+
值类型选择:
+ />
-
+
+ />
+ />
@@ -68,122 +62,130 @@
diff --git a/src/components/BX/waveWorkerUtils.js b/src/components/BX/waveWorkerUtils.js
new file mode 100644
index 0000000..89fad99
--- /dev/null
+++ b/src/components/BX/waveWorkerUtils.js
@@ -0,0 +1,342 @@
+export const MAX_DISPLAY_POINTS = 4000;
+
+export const isPrimaryValue = (value) => Number(value) === 1;
+
+export const getMax = (temp, tempA, tempB, tempC) => {
+ let result = temp > tempA ? temp : tempA;
+ result = result > tempB ? result : tempB;
+ if (tempC !== undefined) result = result > tempC ? result : tempC;
+ return result;
+};
+
+export const getMaxTwo = (temp, tempA, tempB) => {
+ let result = temp > tempA ? temp : tempA;
+ return result > tempB ? result : tempB;
+};
+
+export const getMin = (temp, tempA, tempB, tempC) => {
+ let result = temp < tempA ? temp : tempA;
+ result = result < tempB ? result : tempB;
+ if (tempC !== undefined) result = result < tempC ? result : tempC;
+ return result;
+};
+
+export const getMinOpen = (temp, tempA, tempB) => {
+ let result = temp < tempA ? temp : tempA;
+ return result < tempB ? result : tempB;
+};
+
+export const buildWaveTitle = (boxoList) => {
+ if (boxoList?.systemType === "pms") {
+ return `变电站名称:${boxoList.powerStationName} 监测点名称:${boxoList.measurementPointName} 发生时刻:${boxoList.startTime} 残余电压:${(boxoList.featureAmplitude * 100).toFixed(2)}% 持续时间:${boxoList.duration}s`;
+ }
+ if (boxoList?.systemType === "ZL") {
+ return ` 监测点名称:${boxoList.equipmentName} 发生时刻:${boxoList.startTime} 残余电压:${boxoList.evtParamVVaDepth} 持续时间:${boxoList.evtParamTm}s`;
+ }
+ return `变电站名称:${boxoList.subName} 监测点名称:${boxoList.lineName} 发生时刻:${boxoList.startTime} 残余电压:${(boxoList.featureAmplitude * 100).toFixed(2)}% 持续时间:${boxoList.duration}s`;
+};
+
+export const parsePhaseTitles = (titleList, iphasic, step) => {
+ const base = iphasic * step;
+ const isCurrent = titleList[base + 1]?.substring(0, 1) !== "U";
+ const titles = { aTitle: "", bTitle: "", cTitle: "", unit: isCurrent ? "电流" : "电压" };
+ for (let i = 1; i <= iphasic; i++) {
+ const title = titleList[base + i]?.substring(1) || "";
+ if (i === 1) titles.aTitle = title;
+ else if (i === 2) titles.bTitle = title;
+ else if (i === 3) titles.cTitle = title;
+ }
+ return titles;
+};
+
+export const getSampleStep = (total, maxPoints = MAX_DISPLAY_POINTS) => {
+ if (!total || total <= maxPoints) return 1;
+ return Math.ceil(total / maxPoints);
+};
+
+export const shouldSamplePoint = (index, total, step) =>
+ index % step === 0 || index === total - 1;
+
+export const cloneForWorker = (data) => JSON.parse(JSON.stringify(data));
+
+export const buildShuWorkerPayload = (wp) => ({
+ iphasic: wp.iphasic,
+ pt: wp.pt,
+ ct: wp.ct,
+ waveTitle: wp.waveTitle,
+ listWaveData: wp.listWaveData,
+ time: wp.time,
+ waveType: wp.waveType,
+ yzd: wp.yzd,
+});
+
+export const buildRmsWorkerPayload = (wp) => ({
+ iphasic: wp.iphasic,
+ pt: wp.pt,
+ ct: wp.ct,
+ waveTitle: wp.waveTitle,
+ listRmsData: wp.listRmsData,
+ listRmsMinData: wp.listRmsMinData,
+ time: wp.time,
+ waveType: wp.waveType,
+ yzd: wp.yzd,
+});
+
+export const getXRange = (list) => {
+ if (!list?.length) return { min: 0, max: 1 };
+ return { min: list[0][0], max: list[list.length - 1][0] + 1 };
+};
+
+export const normalizeStats = (stats) => {
+ if (!stats || !isFinite(stats.min) || !isFinite(stats.max)) {
+ return { min: 0, max: 0 };
+ }
+ return stats;
+};
+
+/** Y轴:最大值×1.2,最小值对称留白使波形居中 */
+export const calcYAxisBounds = (dataMin, dataMax) => {
+ const minVal = Number(dataMin);
+ const maxVal = Number(dataMax);
+ if (!isFinite(minVal) || !isFinite(maxVal)) return { min: 0, max: 1 };
+ if (maxVal === minVal) {
+ const pad = Math.abs(maxVal) * 0.2 || 1;
+ return { min: minVal - pad, max: maxVal + pad };
+ }
+ const yMax = maxVal * 1.2;
+ const topPad = yMax - maxVal;
+ return { min: minVal - topPad, max: yMax };
+};
+
+export const calcGlobalInstantRange = (waveDatas, value) => {
+ const usePrimary = isPrimaryValue(value);
+ let min = Infinity;
+ let max = -Infinity;
+ for (const item of waveDatas || []) {
+ const stats = normalizeStats(usePrimary ? item.instantF : item.instantS);
+ min = Math.min(min, stats.min);
+ max = Math.max(max, stats.max);
+ }
+ return calcYAxisBounds(min, max);
+};
+
+export const calcGlobalRmsRange = (waveDatas, value) => {
+ const usePrimary = isPrimaryValue(value);
+ let min = Infinity;
+ let max = -Infinity;
+ for (const item of waveDatas || []) {
+ const stats = normalizeStats(usePrimary ? item.RMSF : item.RMSS);
+ min = Math.min(min, stats.min);
+ max = Math.max(max, stats.max);
+ }
+ return calcYAxisBounds(min, max);
+};
+
+/** 原瞬时波形 Y 轴公式(多图共用同一范围实现对齐) */
+export const calcLegacyInstantYAxis = (dataMin, dataMax) => {
+ const minNum = Number(Number(dataMin).toFixed(2));
+ const maxNum = Number(Number(dataMax).toFixed(2));
+ return {
+ max: maxNum * 1.1,
+ min: minNum > 0 ? minNum - minNum * 0.1 : minNum * 1.1,
+ };
+};
+
+/** 从多相序列中取 [xMin, xMax] 内的 y 极值;不传 x 范围则取全量 */
+export const calcSeriesDataRange = (seriesList, xMin, xMax) => {
+ let min = Infinity;
+ let max = -Infinity;
+ const hasXBounds = xMin != null && xMax != null && isFinite(xMin) && isFinite(xMax);
+ for (const series of seriesList || []) {
+ if (!series?.length) continue;
+ for (const point of series) {
+ const x = point[0];
+ const y = point[1];
+ if (hasXBounds && (x < xMin || x > xMax)) continue;
+ if (!isFinite(y)) continue;
+ min = Math.min(min, y);
+ max = Math.max(max, y);
+ }
+ }
+ if (!isFinite(min) || !isFinite(max)) return { min: 0, max: 1 };
+ return { min, max };
+};
+
+export const getPhaseSeriesList = (iphasic, adata, bdata, cdata) => {
+ const list = [adata];
+ if (iphasic >= 2) list.push(bdata);
+ if (iphasic >= 3) list.push(cdata);
+ return list.filter((s) => s?.length);
+};
+
+export const getChartXExtent = (chart) => {
+ const axis = chart.getModel().getComponent("xAxis", 0);
+ const extent = axis.axis.scale.getExtent();
+ return { min: extent[0], max: extent[1] };
+};
+
+export const calcVisibleInstantYAxis = (seriesList, xMin, xMax) => {
+ const { min, max } = calcSeriesDataRange(seriesList, xMin, xMax);
+ return calcLegacyInstantYAxis(min, max);
+};
+
+/** 按 Y 轴跨度决定小数位,避免小范围时刻度全显示为 0.0 / 0.1 */
+export const calcYAxisLabelPrecision = (min, max) => {
+ const span = Math.abs(Number(max) - Number(min));
+ if (!isFinite(span) || span === 0) return 2;
+ if (span >= 100) return 0;
+ if (span >= 10) return 1;
+ if (span >= 1) return 2;
+ if (span >= 0.1) return 2;
+ if (span >= 0.01) return 3;
+ return 4;
+};
+
+/** 相邻刻度格式化后相同时隐藏,避免出现 0.0 0.0 0.1 0.1 */
+export const createYAxisLabelFormatter = (min, max) => {
+ let lastLabel = null;
+ const precision = calcYAxisLabelPrecision(min, max);
+ return (value) => {
+ const text = Number(value).toFixed(precision);
+ if (text === lastLabel) return "";
+ lastLabel = text;
+ return text;
+ };
+};
+
+export const buildInstantYAxisScale = (bounds) => ({
+ min: bounds.min,
+ max: bounds.max,
+ splitNumber: 5,
+ axisLabel: {
+ formatter: createYAxisLabelFormatter(bounds.min, bounds.max),
+ },
+});
+
+/** dataZoom 时按可见 x 范围重算 Y 轴,使 ABC 相数值与坐标对齐 */
+export const bindInstantYAxisOnZoom = (chart, seriesList) => {
+ const updateYAxis = () => {
+ if (!chart || chart.isDisposed()) return;
+ const { min: xMin, max: xMax } = getChartXExtent(chart);
+ const bounds = calcVisibleInstantYAxis(seriesList, xMin, xMax);
+ chart.setOption({ yAxis: buildInstantYAxisScale(bounds) });
+ };
+ chart.off("dataZoom");
+ chart.on("dataZoom", updateYAxis);
+ return updateYAxis;
+};
+
+export const calcGlobalLegacyInstantYAxis = (waveDatas, value) => {
+ const usePrimary = isPrimaryValue(value);
+ let min = Infinity;
+ let max = -Infinity;
+ for (const item of waveDatas || []) {
+ const stats = normalizeStats(usePrimary ? item.instantF : item.instantS);
+ min = Math.min(min, stats.min);
+ max = Math.max(max, stats.max);
+ }
+ if (!isFinite(min) || !isFinite(max)) return { min: 0, max: 1 };
+ return calcLegacyInstantYAxis(min, max);
+};
+
+/** 原 RMS 波形 Y 轴公式(多图共用同一范围实现对齐) */
+export const calcLegacyRmsYAxis = (dataMin, dataMax) => {
+ const min = Number(dataMin) || 0;
+ const max = Number(dataMax) || 0;
+ return {
+ max: max * 1.06 || 0,
+ min: min - min * 0.04 || 0,
+ };
+};
+
+export const calcVisibleRmsYAxis = (seriesList, xMin, xMax) => {
+ const { min, max } = calcSeriesDataRange(seriesList, xMin, xMax);
+ return calcLegacyRmsYAxis(min, max);
+};
+
+export const buildRmsYAxisScale = (bounds) => ({
+ min: bounds.min,
+ max: bounds.max,
+ splitNumber: 5,
+ axisLabel: {
+ formatter: createYAxisLabelFormatter(bounds.min, bounds.max),
+ },
+});
+
+/** dataZoom 时按可见 x 范围重算 RMS Y 轴 */
+export const bindRmsYAxisOnZoom = (chart, seriesList) => {
+ const updateYAxis = () => {
+ if (!chart || chart.isDisposed()) return;
+ const { min: xMin, max: xMax } = getChartXExtent(chart);
+ const bounds = calcVisibleRmsYAxis(seriesList, xMin, xMax);
+ chart.setOption({ yAxis: buildRmsYAxisScale(bounds) });
+ };
+ chart.off("dataZoom");
+ chart.on("dataZoom", updateYAxis);
+ return updateYAxis;
+};
+
+export const calcGlobalLegacyRmsYAxis = (waveDatas, value) => {
+ const usePrimary = isPrimaryValue(value);
+ let min = Infinity;
+ let max = -Infinity;
+ for (const item of waveDatas || []) {
+ const stats = normalizeStats(usePrimary ? item.RMSF : item.RMSS);
+ min = Math.min(min, stats.min);
+ max = Math.max(max, stats.max);
+ }
+ if (!isFinite(min) || !isFinite(max)) return { min: 0, max: 0 };
+ return calcLegacyRmsYAxis(min, max);
+};
+
+export const WAVE_ALIGNED_GRID = {
+ left: 56,
+ right: "2.8%",
+ bottom: "55px",
+ top: "70px",
+ containLabel: false,
+};
+
+export const RMS_ALIGNED_GRID = {
+ left: 56,
+ right: "45px",
+ bottom: "55px",
+ top: "70px",
+ containLabel: false,
+};
+
+export const buildRmsMinPoint = (wp, value) => {
+ const row = wp.listRmsMinData?.[0];
+ if (!row) return null;
+ const raw = row[1];
+ return {
+ time: row[0],
+ display: isPrimaryValue(value)
+ ? Number(((raw * Number(wp.pt)) / 1000).toFixed(2))
+ : raw,
+ };
+};
+
+export const emptyInstantPrimarySeries = () => ({
+ shunshiFA: [],
+ shunshiFB: [],
+ shunshiFC: [],
+});
+
+export const emptyInstantSecondarySeries = () => ({
+ shunshiSA: [],
+ shunshiSB: [],
+ shunshiSC: [],
+});
+
+export const emptyRmsPrimarySeries = () => ({
+ rmsFA: [],
+ rmsFB: [],
+ rmsFC: [],
+});
+
+export const emptyRmsSecondarySeries = () => ({
+ rmsSA: [],
+ rmsSB: [],
+ rmsSC: [],
+});
diff --git a/src/views/VoltageSag_BJ/components/alarm.vue b/src/views/VoltageSag_BJ/components/alarm.vue
index 2c68047..5c102e3 100644
--- a/src/views/VoltageSag_BJ/components/alarm.vue
+++ b/src/views/VoltageSag_BJ/components/alarm.vue
@@ -134,6 +134,8 @@ const renderChart = (key: any) => {
const outerFontSize = maxChildren > 8 ? 9 : maxChildren > 5 ? 10 : 11;
const outerLabelMaxLen = maxChildren > 8 ? 5 : maxChildren > 5 ? 6 : 8;
const groupScales = getGroupDisplayScales(data.value.innerList || []);
+ const groupCount = data.value.innerList?.length || 0;
+ const innerLabelRotate = groupCount <= 1 ? "tangential" : "radial";
myChart.setOption({
title: {
text: "电压暂降用户分类统计(单位:次)",
@@ -172,7 +174,7 @@ const renderChart = (key: any) => {
},
parentId: item.children[0]?.parentId,
label: {
- rotate: "radial",
+ rotate: innerLabelRotate,
color: "#ffffff",
fontSize: 10,
lineHeight: 12,
@@ -236,7 +238,7 @@ const renderChart = (key: any) => {
borderWidth: 2,
},
label: {
- rotate: "tangential",
+ rotate: innerLabelRotate,
},
sort: null,
},