yeg
2026-09-28 2c96ead3fcfe5df3ab1c46ec13ec4f681fd16d82
时间解析同时接受毫秒数与 ISO 文本

修「最近数据时间」在候选列表显示为空:该字段是 Instant 类型的 VO 属性,后端输出 ISO 文本,
而我按毫秒数解析,于是整列都显示占位符。控制台的实时区同一字段走手写快照、是毫秒数,
两处本来就形态不同,所以解析层同时接受两种形态,不做取舍。
2个文件已修改
20 ■■■■■ 已修改文件
src/api/deviceCabinets.ts 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/businessTime.ts 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/deviceCabinets.ts
@@ -76,8 +76,8 @@
  channelCount: number
  onlineStatus: CabinetOnlineStatus
  /** 来源里最近一次采样行的设备时间;没有采样行或来源不提供时为空。 */
  /** 最近数据时间:业务接口输出毫秒时间戳;没有采样行时为空。 */
  lastDataAt: number | null
  /** 最近数据时间:后端 Instant 属性输出 ISO 文本,手写快照输出毫秒数;没有采样行时为空。 */
  lastDataAt: string | number | null
}
export interface DiscoveredCabinetListResult {
src/utils/businessTime.ts
@@ -1,6 +1,18 @@
/** 业务接口只接受毫秒时间戳;缺失或非法时间不伪装为当前时间。 */
/**
 * 业务时间解析:只接受毫秒时间戳或 ISO-8601 文本,缺失或非法时间不伪装为当前时间。
 *
 * <p>同时接受两种形态,是因为后端目前并不统一:手写 Map 的时间字段是毫秒数,
 * 而 Instant 类型的 VO 属性走 ISO 文本(见 KNOWN-GAPS「时间字段两种形态」)。
 */
export function businessTime(value: unknown): number | null {
  return typeof value === 'number' && Number.isFinite(value) && Number.isFinite(new Date(value).getTime()) ? value : null
  if (typeof value === 'number') {
    return Number.isFinite(value) && Number.isFinite(new Date(value).getTime()) ? value : null
  }
  if (typeof value === 'string' && value.trim()) {
    const parsed = new Date(value.trim()).getTime()
    return Number.isFinite(parsed) ? parsed : null
  }
  return null
}
/** 将业务时间按浏览器本地时区展示,保留毫秒精度。 */