/** * 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: [] }; } }