feat(history): align units and history data
This commit is contained in:
@@ -76,7 +76,7 @@ describe("buildSceneFrame", () => {
|
||||
});
|
||||
expect(frame.payload?.links["P-1"]).toEqual({
|
||||
velocity: 0.82,
|
||||
flow: -18.4,
|
||||
flow: -66.24,
|
||||
direction: -1,
|
||||
status: "open",
|
||||
});
|
||||
@@ -196,7 +196,12 @@ describe("buildSceneFrame", () => {
|
||||
const devices = await fetchPressureDevices(new AbortController().signal);
|
||||
|
||||
expect(devices).toEqual([
|
||||
{ device_id: "S-1", device_type: "pressure", node_id: "J-1" },
|
||||
{
|
||||
device_id: "S-1",
|
||||
device_type: "pressure",
|
||||
node_id: "J-1",
|
||||
measurement_unit: "m",
|
||||
},
|
||||
]);
|
||||
expect(mockApiFetch).toHaveBeenCalledWith(
|
||||
expect.stringContaining("/api/v1/scada-devices?limit=1000&offset=0"),
|
||||
@@ -228,6 +233,10 @@ describe("buildSceneFrame", () => {
|
||||
},
|
||||
],
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({ FLOW_UNITS: "LPS", PRESSURE_UNITS: "METERS" }),
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
ok: false,
|
||||
status: 503,
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { apiFetch } from "@/lib/apiFetch";
|
||||
import { fetchNetworkResultUnits } from "@/hooks/useNetworkResultUnits";
|
||||
import { config } from "@config/config";
|
||||
import {
|
||||
DEFAULT_NETWORK_RESULT_UNITS,
|
||||
type NetworkResultUnits,
|
||||
toDisplayValue,
|
||||
} from "@/utils/units";
|
||||
|
||||
export const ZJB_PROJECT_CODE = "zjb";
|
||||
export const ZJB_SCENE_MODEL_ID = "zjb-water-network-v23";
|
||||
@@ -32,8 +38,8 @@ export type SceneResultsPayload = {
|
||||
modelId: string;
|
||||
units: {
|
||||
velocity: "m/s";
|
||||
pressure: "mH2O";
|
||||
flow: "L/s";
|
||||
pressure: "m";
|
||||
flow: "m³/h";
|
||||
};
|
||||
timestamp: string;
|
||||
nodes: Record<string, SceneNodeResult>;
|
||||
@@ -61,6 +67,7 @@ export type PressureDevice = {
|
||||
device_id: string;
|
||||
device_type: string;
|
||||
node_id: string;
|
||||
measurement_unit?: string;
|
||||
};
|
||||
|
||||
type RawPressureDevice = Omit<PressureDevice, "node_id"> & {
|
||||
@@ -192,6 +199,7 @@ export const buildSceneFrame = ({
|
||||
linkRows,
|
||||
pressureDevices,
|
||||
scadaRows,
|
||||
simulationUnits = DEFAULT_NETWORK_RESULT_UNITS,
|
||||
}: {
|
||||
queryTime: Date;
|
||||
model: SceneModelIndex;
|
||||
@@ -199,6 +207,7 @@ export const buildSceneFrame = ({
|
||||
linkRows: RealtimeLinkRow[];
|
||||
pressureDevices: PressureDevice[];
|
||||
scadaRows: ScadaReadingRow[];
|
||||
simulationUnits?: NetworkResultUnits;
|
||||
}): SceneFrame => {
|
||||
const selectedTime = queryTime.toISOString();
|
||||
const frameTime = resolveCommonFrameTime(queryTime, nodeRows, linkRows);
|
||||
@@ -223,7 +232,14 @@ export const buildSceneFrame = ({
|
||||
return;
|
||||
}
|
||||
if (isFiniteNumber(row.pressure)) {
|
||||
nodes[id] = { pressure: row.pressure, source: "simulation" };
|
||||
nodes[id] = {
|
||||
pressure: toDisplayValue(
|
||||
row.pressure,
|
||||
"pressure",
|
||||
simulationUnits.pressure,
|
||||
)!,
|
||||
source: "simulation",
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -234,9 +250,15 @@ export const buildSceneFrame = ({
|
||||
return;
|
||||
}
|
||||
const result: SceneLinkResult = {};
|
||||
if (isFiniteNumber(row.velocity)) result.velocity = row.velocity;
|
||||
if (isFiniteNumber(row.velocity)) {
|
||||
result.velocity = toDisplayValue(
|
||||
row.velocity,
|
||||
"velocity",
|
||||
simulationUnits.velocity,
|
||||
)!;
|
||||
}
|
||||
if (isFiniteNumber(row.flow)) {
|
||||
result.flow = row.flow;
|
||||
result.flow = toDisplayValue(row.flow, "flow", simulationUnits.flow)!;
|
||||
result.direction = Math.sign(row.flow) as -1 | 0 | 1;
|
||||
}
|
||||
const status = normalizeLinkStatus(row.status);
|
||||
@@ -260,7 +282,11 @@ export const buildSceneFrame = ({
|
||||
if (!isFiniteNumber(value)) return;
|
||||
const simulationPressure = nodes[device.node_id]?.pressure;
|
||||
nodes[device.node_id] = {
|
||||
pressure: value,
|
||||
pressure: toDisplayValue(
|
||||
value,
|
||||
"pressure",
|
||||
device.measurement_unit || "m",
|
||||
)!,
|
||||
source: "scada",
|
||||
deviceId: device.device_id,
|
||||
...(simulationPressure === undefined ? {} : { simulationPressure }),
|
||||
@@ -274,7 +300,7 @@ export const buildSceneFrame = ({
|
||||
resultTime,
|
||||
payload: {
|
||||
modelId: model.modelId,
|
||||
units: { velocity: "m/s", pressure: "mH2O", flow: "L/s" },
|
||||
units: { velocity: "m/s", pressure: "m", flow: "m³/h" },
|
||||
timestamp: resultTime,
|
||||
nodes,
|
||||
links,
|
||||
@@ -301,18 +327,23 @@ const readJson = async <T>(url: string, signal: AbortSignal): Promise<T> => {
|
||||
};
|
||||
|
||||
export const fetchPressureDevices = async (signal: AbortSignal) => {
|
||||
const page = await readJson<Page<RawPressureDevice>>(
|
||||
const response = await readJson<Page<RawPressureDevice> | RawPressureDevice[]>(
|
||||
`${config.BACKEND_URL}/api/v1/scada-devices?limit=1000&offset=0`,
|
||||
signal,
|
||||
);
|
||||
return page.items
|
||||
const items = Array.isArray(response) ? response : response.items;
|
||||
return items
|
||||
.filter(
|
||||
(device): device is PressureDevice =>
|
||||
device.device_type?.trim().toLowerCase() === "pressure" &&
|
||||
typeof device.node_id === "string" &&
|
||||
device.node_id.trim().length > 0,
|
||||
)
|
||||
.map((device) => ({ ...device, node_id: device.node_id.trim() }));
|
||||
.map((device) => ({
|
||||
...device,
|
||||
node_id: device.node_id.trim(),
|
||||
measurement_unit: device.measurement_unit?.trim() || "m",
|
||||
}));
|
||||
};
|
||||
|
||||
export const fetchSceneFrame = async ({
|
||||
@@ -337,7 +368,7 @@ export const fetchSceneFrame = async ({
|
||||
pressureDevices.map((device) => device.device_id).join(","),
|
||||
);
|
||||
|
||||
const [nodeRows, linkRows] = await Promise.all([
|
||||
const [nodeRows, linkRows, networkOptions] = await Promise.all([
|
||||
readJson<RealtimeNodeRow[]>(
|
||||
`${config.BACKEND_URL}/api/v1/timeseries/realtime/nodes?${range}`,
|
||||
signal,
|
||||
@@ -346,6 +377,7 @@ export const fetchSceneFrame = async ({
|
||||
`${config.BACKEND_URL}/api/v1/timeseries/realtime/links?${range}`,
|
||||
signal,
|
||||
),
|
||||
fetchNetworkResultUnits(ZJB_PROJECT_CODE, signal),
|
||||
]);
|
||||
|
||||
let scadaRows: ScadaReadingRow[] = [];
|
||||
@@ -370,6 +402,7 @@ export const fetchSceneFrame = async ({
|
||||
linkRows: Array.isArray(linkRows) ? linkRows : [],
|
||||
pressureDevices,
|
||||
scadaRows,
|
||||
simulationUnits: networkOptions,
|
||||
});
|
||||
return { ...frame, warnings };
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user