Files
smart_grid_iot/server/src/task/icc_analog_mapper.ts
T

105 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* ICC 探测器模拟量数据字段映射(集中配置,便于按 ICC 平台实际返回结构调整)。
*
* ICC 返回的原始字段名 → 本系统 electricity_data 字段。接入真实 ICC 平台时
* 仅需调整本文件与 fetch 路径即可,业务层无需改动。纯映射逻辑,无 SQL 无 DOM。
*/
export interface IccAnalogRawRecord {
[field: string]: any;
}
/** 模拟量分页列表接口路径({version} 由调用方按 ICC_VERSION 替换) */
export const ICC_ANALOG_ENDPOINT = "/evo-apigw/evo-fdbu/{version}/analog/subsystem/page";
/** 原始记录关键字段映射:本系统字段 → ICC 返回字段名 */
export const ICC_ANALOG_FIELDS = {
deviceCode: "deviceCode", // 探测器编码(→ electric_line.line_code 幂等键)
uniqueCode: "uniqueCode", // 设备唯一标识码(→ electricity_data.imei)
analogType: "analogType", // 模拟量类型
analogName: "analogName", // 模拟量名称(→ electricity_data.analog_name)
analogUnit: "analogUnit", // 模拟量单位(→ electricity_data.analog_unit)
analogValue: "analogValue", // 模拟量值
reportTime: "reportTime" // 上报/采集时间(yyyy-MM-dd HH:mm:ss,接口文档声明字段,保留映射)
} as const;
/** 字符串 trim;null / undefined / 空串统一归一为 undefined。 */
function toOptionalString(value: unknown): string | undefined {
if (value === undefined || value === null) return undefined;
const s = String(value).trim();
return s === "" ? undefined : s;
}
/**
* 将 ICC 原始模拟量记录映射为本系统 electricity_data 落库字段。
* analogValue 用 Number 解析,空值/非法值统一归一为 null(可空落库)。
*/
export function mapIccAnalogRecord(raw: IccAnalogRawRecord): {
deviceCode: string;
uniqueCode?: string;
analogType?: string;
analogName?: string;
analogUnit?: string;
analogValue: number | null;
reportTime?: string;
} {
const f = ICC_ANALOG_FIELDS;
// 匹配键保持空串语义,由调用方判跳
const deviceCode = String(raw[f.deviceCode] ?? "").trim();
// 数值解析:空 / null / 非数值统一返回 null
let analogValue: number | null = null;
const rawValue = raw[f.analogValue];
if (rawValue !== undefined && rawValue !== null && String(rawValue).trim() !== "") {
const num = Number(rawValue);
analogValue = Number.isFinite(num) ? num : null;
}
return {
deviceCode,
uniqueCode: toOptionalString(raw[f.uniqueCode]),
analogType: toOptionalString(raw[f.analogType]),
analogName: toOptionalString(raw[f.analogName]),
analogUnit: toOptionalString(raw[f.analogUnit]),
analogValue,
// reportTime 保留映射(接口文档仍声明该字段;当前采集时间以同步时间为准,见同步服务)
reportTime: toOptionalString(raw[f.reportTime])
};
}
/**
* 解析模拟量分页响应(兼容三种形态):
* - payload 为数组 → 直接作为列表
* - payload.data.pageData 为数组 → 取 pageData
* - payload.data.list 为数组 → 取 list
* - 结构不匹配或解析异常 → 返回空列表
*/
export function parseAnalogPage(payload: any): {
list: IccAnalogRawRecord[];
nextPage?: number;
totalCount?: number;
} {
try {
if (Array.isArray(payload)) {
return { list: payload };
}
const page = payload?.data;
if (page && Array.isArray(page.pageData)) {
return {
list: page.pageData,
nextPage: Number(page.nextPage) > 0 ? Number(page.nextPage) : undefined,
totalCount: Number(page.totalCount) > 0 ? Number(page.totalCount) : undefined
};
}
if (page && Array.isArray(page.list)) {
return {
list: page.list,
nextPage: Number(page.nextPage) > 0 ? Number(page.nextPage) : undefined,
totalCount: Number(page.totalCount) > 0 ? Number(page.totalCount) : undefined
};
}
return { list: [] };
} catch {
return { list: [] };
}
}