From d986e563a616e1390272bbf56974404b8922ee36 Mon Sep 17 00:00:00 2001 From: Huarch Date: Fri, 17 Jul 2026 10:13:50 +0800 Subject: [PATCH] fix(map): convert actual demand display units --- .../olmap/core/Controls/useStyleEditor.ts | 36 ++++++++++++++----- src/components/olmap/core/MapComponent.tsx | 7 ++-- src/utils/units.test.ts | 19 ++++++++++ src/utils/units.ts | 4 +++ 4 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 src/utils/units.test.ts diff --git a/src/components/olmap/core/Controls/useStyleEditor.ts b/src/components/olmap/core/Controls/useStyleEditor.ts index 88183f7..65c4506 100644 --- a/src/components/olmap/core/Controls/useStyleEditor.ts +++ b/src/components/olmap/core/Controls/useStyleEditor.ts @@ -32,9 +32,23 @@ import { } from "./styleEditorTypes"; import { LegendStyleConfig } from "./StyleLegend"; import { calculateClassification } from "@utils/breaksClassification"; +import { isLpsFlowProperty, toM3h } from "@utils/units"; const UNIT_HEADLOSS_RANGE: [number, number] = [0, 5]; +const normalizeComputedStyleValue = (property: string, value: unknown) => { + const numericValue = Number(value); + if (!Number.isFinite(numericValue)) { + return Number.NaN; + } + + const displayValue = isLpsFlowProperty(property) + ? toM3h(numericValue, "lps") + : numericValue; + + return property === "flow" ? Math.abs(displayValue) : displayValue; +}; + export const useStyleEditor = ({ layerStyleStates, setLayerStyleStates, @@ -337,12 +351,20 @@ export const useStyleEditor = ({ layerType === "junctions" ? isElevation && elevationRange ? [elevationRange[0], elevationRange[1]] - : currentJunctionCalData?.map((item: any) => item.value) || [] + : currentJunctionCalData + ?.map((item: any) => + normalizeComputedStyleValue(effectiveStyleConfig.property, item.value) + ) + .filter(Number.isFinite) || [] : isDiameter && diameterRange ? [diameterRange[0], diameterRange[1]] : isUnitHeadloss ? [UNIT_HEADLOSS_RANGE[0], UNIT_HEADLOSS_RANGE[1]] - : currentPipeCalData?.map((item: any) => item.value) || []; + : currentPipeCalData + ?.map((item: any) => + normalizeComputedStyleValue(effectiveStyleConfig.property, item.value) + ) + .filter(Number.isFinite) || []; const canApply = layerType === "junctions" @@ -416,7 +438,7 @@ export const useStyleEditor = ({ const dataMap = new Map(); records.forEach((record: any) => { - dataMap.set(record.ID, record.value || 0); + dataMap.set(record.ID, normalizeComputedStyleValue(property, record.value || 0)); }); vectorTileSources.forEach((vectorTileSource) => { @@ -434,8 +456,7 @@ export const useStyleEditor = ({ return; } - renderFeature.properties_[property] = - property === "flow" ? Math.abs(value) : value; + renderFeature.properties_[property] = value; }); }); }); @@ -457,7 +478,7 @@ export const useStyleEditor = ({ const dataMap = new Map(); records.forEach((record: any) => { - dataMap.set(record.ID, record.value || 0); + dataMap.set(record.ID, normalizeComputedStyleValue(property, record.value || 0)); }); const listener = (event: any) => { @@ -478,8 +499,7 @@ export const useStyleEditor = ({ return; } - renderFeature.properties_[property] = - property === "flow" ? Math.abs(value) : value; + renderFeature.properties_[property] = value; }); } catch (error) { console.error("Error processing tile load event:", error); diff --git a/src/components/olmap/core/MapComponent.tsx b/src/components/olmap/core/MapComponent.tsx index 6829155..51a6786 100644 --- a/src/components/olmap/core/MapComponent.tsx +++ b/src/components/olmap/core/MapComponent.tsx @@ -24,7 +24,7 @@ import { TextLayer } from "@deck.gl/layers"; import { TripsLayer } from "@deck.gl/geo-layers"; import { CollisionFilterExtension } from "@deck.gl/extensions"; import { ContourLayer } from "deck.gl"; -import { toM3h } from "@utils/units"; +import { isLpsFlowProperty, toM3h } from "@utils/units"; import { usePathname } from "next/navigation"; import { cleanupTransientMapResources, @@ -204,8 +204,7 @@ const MapComponent: React.FC = ({ children }) => { return junctionData.map((j) => { const record = nodeMap.get(j.id); let val = record ? record.value : undefined; - // 在这合并时将实际需水量从 LPS 转换为大写表示 - if (val !== undefined && junctionText === "actualdemand") { + if (val !== undefined && isLpsFlowProperty(junctionText)) { val = toM3h(val, "lps"); } return record ? { ...j, [junctionText]: val } : j; @@ -236,7 +235,7 @@ const MapComponent: React.FC = ({ children }) => { return junctionData.map((j) => { const record = nodeMap.get(j.id); let val = record ? record.value : undefined; - if (val !== undefined && junctionText === "actualdemand") { + if (val !== undefined && isLpsFlowProperty(junctionText)) { val = toM3h(val, "lps"); } return record ? { ...j, [junctionText]: val } : j; diff --git a/src/utils/units.test.ts b/src/utils/units.test.ts new file mode 100644 index 0000000..0659f94 --- /dev/null +++ b/src/utils/units.test.ts @@ -0,0 +1,19 @@ +import { FLOW_DISPLAY_UNIT, isLpsFlowProperty, toM3h } from "./units"; + +describe("flow display units", () => { + it("uses cubic meters per hour as the flow display unit", () => { + expect(FLOW_DISPLAY_UNIT).toBe("m³/h"); + }); + + it("converts L/s values to m³/h", () => { + expect(toM3h(10, "lps")).toBe(36); + expect(toM3h(10, "L/s")).toBe(36); + }); + + it("recognizes computed properties that arrive from the backend in L/s", () => { + expect(isLpsFlowProperty("flow")).toBe(true); + expect(isLpsFlowProperty("actual_demand")).toBe(true); + expect(isLpsFlowProperty("actualdemand")).toBe(true); + expect(isLpsFlowProperty("pressure")).toBe(false); + }); +}); diff --git a/src/utils/units.ts b/src/utils/units.ts index 08dcf7e..f90c721 100644 --- a/src/utils/units.ts +++ b/src/utils/units.ts @@ -1,5 +1,9 @@ export const FLOW_DISPLAY_UNIT = "m³/h"; const M3H_FACTOR = 3600; +const LPS_FLOW_PROPERTIES = new Set(["flow", "actual_demand", "actualdemand"]); + +export const isLpsFlowProperty = (property: string) => + LPS_FLOW_PROPERTIES.has(property); export const toM3h = (value: number, sourceUnit: string = "m³/s") => { if (!Number.isFinite(value)) return Number.NaN;