281 lines
7.8 KiB
TypeScript
281 lines
7.8 KiB
TypeScript
import type { WaterNetworkSourceId } from "../map/sources";
|
|
import { formatValue } from "./format-value";
|
|
|
|
export type LocalizedFeatureProperty = {
|
|
key: string;
|
|
label: string;
|
|
value: string;
|
|
};
|
|
|
|
export type FeaturePanelBadgeTone = "active" | "inactive" | "warning" | "critical" | "info";
|
|
|
|
export type FeaturePanelBadge = {
|
|
label: string;
|
|
tone: FeaturePanelBadgeTone;
|
|
};
|
|
|
|
export type FeaturePanelModel = {
|
|
id: string;
|
|
badge?: FeaturePanelBadge;
|
|
attributes: LocalizedFeatureProperty[];
|
|
};
|
|
|
|
const PROPERTY_LABELS: Record<string, string> = {
|
|
fid: "GeoServer 要素 ID",
|
|
id: "编号",
|
|
gid: "要素编号",
|
|
name: "名称",
|
|
code: "编码",
|
|
type: "类型",
|
|
node1: "起点节点",
|
|
node2: "终点节点",
|
|
from_node: "起点节点",
|
|
to_node: "终点节点",
|
|
diameter: "管径",
|
|
dn: "管径",
|
|
length: "长度",
|
|
roughness: "粗糙系数",
|
|
shape: "断面形状",
|
|
max_depth: "最大深度",
|
|
invert_elevation: "井底高程",
|
|
orifice_type: "孔口类型",
|
|
discharge_coeff: "流量系数",
|
|
gated: "闸门",
|
|
offset_height: "偏移高度",
|
|
geom1: "几何参数 1",
|
|
geom2: "几何参数 2",
|
|
pump_curve: "泵曲线",
|
|
startup_depth: "启动水深",
|
|
shutoff_depth: "停泵水深",
|
|
outfall_type: "排放类型",
|
|
stage_data: "阶段数据",
|
|
status: "状态",
|
|
material: "材质",
|
|
elevation: "高程",
|
|
demand: "需水量",
|
|
pressure: "压力",
|
|
flow: "流量",
|
|
velocity: "流速",
|
|
zone: "分区",
|
|
district: "片区",
|
|
source: "来源",
|
|
updated_at: "更新时间",
|
|
point_id: "测点 ID",
|
|
point_external_id: "测点编号",
|
|
point_name: "测点名称",
|
|
device_id: "设备 ID",
|
|
device_external_id: "设备编号",
|
|
device_type_id: "设备类型 ID",
|
|
device_type_name: "设备类型",
|
|
device_icon_code: "设备图标编码",
|
|
active: "运行状态",
|
|
junction_id: "关联检查井",
|
|
location_source: "位置来源",
|
|
synced_at: "同步时间"
|
|
};
|
|
|
|
const PROPERTY_ORDER: Record<string, number> = {
|
|
fid: 9,
|
|
id: 10,
|
|
gid: 11,
|
|
name: 12,
|
|
code: 13,
|
|
diameter: 20,
|
|
dn: 20,
|
|
length: 21,
|
|
roughness: 22,
|
|
max_depth: 30,
|
|
invert_elevation: 31,
|
|
orifice_type: 32,
|
|
outfall_type: 32,
|
|
shape: 33,
|
|
pump_curve: 34,
|
|
material: 23,
|
|
node1: 24,
|
|
from_node: 24,
|
|
node2: 25,
|
|
to_node: 25,
|
|
elevation: 30,
|
|
demand: 31,
|
|
pressure: 32,
|
|
flow: 33,
|
|
velocity: 34,
|
|
status: 90
|
|
};
|
|
|
|
const STATUS_LABELS: Record<string, string> = {
|
|
on: "运行",
|
|
off: "停止",
|
|
active: "运行中",
|
|
inactive: "停用",
|
|
online: "在线",
|
|
offline: "离线",
|
|
open: "开启",
|
|
closed: "关闭",
|
|
normal: "正常",
|
|
warning: "告警",
|
|
critical: "严重"
|
|
};
|
|
|
|
const OUTFALL_TYPE_LABELS: Record<string, string> = {
|
|
free: "自由出流"
|
|
};
|
|
|
|
const GATED_LABELS: Record<string, string> = {
|
|
no: "否",
|
|
false: "否",
|
|
"0": "否",
|
|
yes: "是",
|
|
true: "是",
|
|
"1": "是"
|
|
};
|
|
|
|
const FEATURE_PANEL_PROPERTY_KEYS: Record<WaterNetworkSourceId, readonly string[]> = {
|
|
pumps: ["id", "status", "startup_depth", "shutoff_depth"],
|
|
conduits: ["id", "length", "diameter"],
|
|
junctions: ["id", "invert_elevation", "max_depth"],
|
|
orifices: ["id", "discharge_coeff", "gated", "shape", "geom1", "geom2"],
|
|
outfalls: ["id", "invert_elevation", "outfall_type"],
|
|
scada: ["id", "point_id", "point_external_id", "point_name", "device_external_id", "active", "device_type_id", "device_type_name", "junction_id", "synced_at"]
|
|
};
|
|
|
|
const FEATURE_PANEL_BADGE_KEYS: Partial<Record<WaterNetworkSourceId, string>> = {
|
|
pumps: "status",
|
|
orifices: "gated",
|
|
scada: "active"
|
|
};
|
|
|
|
export function getLocalizedFeatureProperties(properties: Record<string, unknown>): LocalizedFeatureProperty[] {
|
|
return Object.entries(properties).filter(([key]) => normalizePropertyKey(key) !== "cluster_size").map(([key, value]) => ({
|
|
key,
|
|
label: getFeaturePropertyLabel(key),
|
|
value: formatFeaturePropertyValue(key, value)
|
|
})).sort((first, second) => getPropertyOrder(first.key) - getPropertyOrder(second.key));
|
|
}
|
|
|
|
export function getFeaturePanelProperties(
|
|
layer: WaterNetworkSourceId,
|
|
properties: Record<string, unknown>,
|
|
featureId?: string
|
|
): LocalizedFeatureProperty[] {
|
|
return FEATURE_PANEL_PROPERTY_KEYS[layer].map((key) => {
|
|
const value = key === "id" ? properties[key] ?? featureId : properties[key];
|
|
|
|
return {
|
|
key,
|
|
label: getFeaturePropertyLabel(key),
|
|
value: formatFeaturePropertyValue(key, value)
|
|
};
|
|
});
|
|
}
|
|
|
|
export function getFeaturePanelModel(
|
|
layer: WaterNetworkSourceId,
|
|
properties: Record<string, unknown>,
|
|
featureId?: string
|
|
): FeaturePanelModel {
|
|
const entries = getFeaturePanelProperties(layer, properties, featureId);
|
|
const idKey = layer === "scada" ? "point_external_id" : "id";
|
|
const id = entries.find((entry) => entry.key === idKey)?.value ?? "暂无";
|
|
const badgeKey = FEATURE_PANEL_BADGE_KEYS[layer];
|
|
const badgeEntry = badgeKey ? entries.find((entry) => entry.key === badgeKey) : undefined;
|
|
|
|
return {
|
|
id,
|
|
badge: badgeEntry ? getFeaturePanelBadge(layer, badgeEntry.value) : undefined,
|
|
attributes: entries.filter((entry) => entry.key !== idKey && entry.key !== badgeKey)
|
|
};
|
|
}
|
|
|
|
export function getFeaturePropertyLabel(key: string) {
|
|
const normalizedKey = normalizePropertyKey(key);
|
|
return PROPERTY_LABELS[normalizedKey] ?? key;
|
|
}
|
|
|
|
export function formatFeaturePropertyValue(key: string, value: unknown) {
|
|
const normalizedKey = normalizePropertyKey(key);
|
|
|
|
if (isStatusKey(key) && typeof value === "string") {
|
|
return STATUS_LABELS[value.toLowerCase()] ?? value;
|
|
}
|
|
|
|
if (normalizedKey === "outfall_type" && typeof value === "string") {
|
|
return OUTFALL_TYPE_LABELS[value.toLowerCase()] ?? value;
|
|
}
|
|
|
|
if (normalizedKey === "gated" && value !== null && value !== undefined && value !== "") {
|
|
return GATED_LABELS[String(value).toLowerCase()] ?? formatValue(value);
|
|
}
|
|
|
|
if (normalizedKey === "active" && typeof value === "boolean") {
|
|
return value ? "在线" : "离线";
|
|
}
|
|
|
|
if (normalizedKey === "location_source" && value === "density_cluster_demo") {
|
|
return "密度聚类模拟位置";
|
|
}
|
|
|
|
if (normalizedKey === "location_source" && value === "uniform_farthest_point_demo") {
|
|
return "空间均匀采样模拟位置";
|
|
}
|
|
|
|
if ((normalizedKey === "diameter" || normalizedKey === "dn") && value !== null && value !== undefined && value !== "") {
|
|
const diameterInMeters = typeof value === "number" ? value : Number(value);
|
|
return Number.isFinite(diameterInMeters)
|
|
? `${formatValue(diameterInMeters * 1000)} mm`
|
|
: formatValue(value);
|
|
}
|
|
|
|
if (["length", "elevation", "invert_elevation", "max_depth", "startup_depth", "shutoff_depth"].includes(normalizedKey)
|
|
&& value !== null && value !== undefined && value !== "") {
|
|
return `${formatValue(value)} m`;
|
|
}
|
|
|
|
return formatValue(value);
|
|
}
|
|
|
|
function getPropertyOrder(key: string) {
|
|
return PROPERTY_ORDER[normalizePropertyKey(key)] ?? 100;
|
|
}
|
|
|
|
function normalizePropertyKey(key: string) {
|
|
return key.trim().replaceAll("-", "_").toLowerCase();
|
|
}
|
|
|
|
function isStatusKey(key: string) {
|
|
return normalizePropertyKey(key) === "status";
|
|
}
|
|
|
|
function getFeaturePanelBadge(
|
|
layer: WaterNetworkSourceId,
|
|
value: string
|
|
): FeaturePanelBadge {
|
|
if (layer === "orifices") {
|
|
return value === "是"
|
|
? { label: "有闸门", tone: "info" }
|
|
: value === "否"
|
|
? { label: "无闸门", tone: "inactive" }
|
|
: { label: `闸门 ${value}`, tone: "inactive" };
|
|
}
|
|
|
|
const normalizedValue = value.toLowerCase();
|
|
|
|
if (["运行", "运行中", "在线", "开启", "正常"].includes(value)) {
|
|
return { label: value, tone: "active" };
|
|
}
|
|
|
|
if (["停止", "停用", "离线", "关闭"].includes(value)) {
|
|
return { label: value, tone: "inactive" };
|
|
}
|
|
|
|
if (normalizedValue === "warning" || value === "告警") {
|
|
return { label: value, tone: "warning" };
|
|
}
|
|
|
|
if (normalizedValue === "critical" || value === "严重") {
|
|
return { label: value, tone: "critical" };
|
|
}
|
|
|
|
return { label: value, tone: "inactive" };
|
|
}
|