From e7d26a4991f2b14d5305a7067b0b75600d616b65 Mon Sep 17 00:00:00 2001 From: hechang27-sprt Date: Thu, 9 Apr 2026 08:54:51 +0800 Subject: [PATCH] fix(table-v2): extract timestamp display and align text --- .../base/data/list-table-v2/list-table-v2.vue | 93 +++++++------ packages/base/data/list-table-v2/types.ts | 32 ++--- .../list-table-v2/usePretextColumnWidths.ts | 19 +-- .../list-table-v2/usePretextRowHeights.ts | 5 +- packages/base/item/tzDateTime.vue | 59 +++------ plugs/composables/index.ts | 1 + plugs/composables/useTimestampDisplay.ts | 123 ++++++++++++++++++ 7 files changed, 213 insertions(+), 119 deletions(-) create mode 100644 plugs/composables/useTimestampDisplay.ts diff --git a/packages/base/data/list-table-v2/list-table-v2.vue b/packages/base/data/list-table-v2/list-table-v2.vue index b8148e8..dbb8d3b 100644 --- a/packages/base/data/list-table-v2/list-table-v2.vue +++ b/packages/base/data/list-table-v2/list-table-v2.vue @@ -19,13 +19,7 @@
Column widths: {{ columnWidths.map((w) => Math.round(w)).join(",") }}
Column configs: - {{ - computedConfigs.map((c) => ({ - key: c.key, - flexBasis: Math.round(c.flexBasis), - flexGrow: c.flexGrow.toFixed(1), - })) - }} + {{ computedConfigs }}
@@ -35,7 +29,7 @@
- {{ getHeaderText(col) }} + {{ getHeaderText(col) }}
@@ -63,7 +57,9 @@ @click="handleCellClick(row.index, col)" > - {{ getRow(row.index) ? formatCellValue(getRow(row.index)!, col) : '--' }} + {{ + getRow(row.index) ? formatCellValue(getRow(row.index)!, col) : "--" + }} @@ -88,18 +84,20 @@ diff --git a/plugs/composables/index.ts b/plugs/composables/index.ts index 0a0ce04..50fe08b 100644 --- a/plugs/composables/index.ts +++ b/plugs/composables/index.ts @@ -5,3 +5,4 @@ export * from "./useModifyForm"; export * from "./useSysDict"; export * from "./useWatchOnce"; export * from "./useRefreshFlags"; +export * from "./useTimestampDisplay"; diff --git a/plugs/composables/useTimestampDisplay.ts b/plugs/composables/useTimestampDisplay.ts new file mode 100644 index 0000000..4c393fa --- /dev/null +++ b/plugs/composables/useTimestampDisplay.ts @@ -0,0 +1,123 @@ +import dayjs, { type Dayjs } from "dayjs"; +import customParseFormat from "dayjs/plugin/customParseFormat"; +import timezone from "dayjs/plugin/timezone"; +import utc from "dayjs/plugin/utc"; +import { match, P } from "ts-pattern"; +import { computed, toValue, type MaybeRefOrGetter } from "vue"; + +dayjs.extend(customParseFormat); +dayjs.extend(utc); +dayjs.extend(timezone); + +export type TimestampDisplayType = "iso8601" | "unix" | "unixMillis"; + +export interface TimestampDisplayConfig { + valueFormat?: string; + valueTz?: string; + displayFormat?: string; + locale?: string; + type?: TimestampDisplayType; +} + +export interface TimestampDisplayInput extends TimestampDisplayConfig { + value: string | number; +} + +export type TimestampSimpleConfig = undefined | boolean | string | TimestampDisplayConfig; + +export const DEFAULT_TIMESTAMP_DISPLAY_FORMAT = "YYYY-MM-DD HH:mm:ss"; + +function withDefaultDisplayFormat( + config: TimestampDisplayConfig, + defaultDisplayFormat?: string +): TimestampDisplayConfig { + if (!defaultDisplayFormat || config.displayFormat) { + return config; + } + + return { + ...config, + displayFormat: defaultDisplayFormat, + }; +} + +export function normalizeTimestampValue( + timestamp: TimestampSimpleConfig, + defaultDisplayFormat?: string +): TimestampDisplayConfig | null { + return match(timestamp) + .with(P.nullish, () => null) + .with(true, () => withDefaultDisplayFormat({ type: "unixMillis" }, defaultDisplayFormat)) + .with(P.union("iso8601", "unix", "unixMillis"), (type) => withDefaultDisplayFormat({ type }, defaultDisplayFormat)) + .with(P.string, (valueFormat) => withDefaultDisplayFormat({ valueFormat }, defaultDisplayFormat)) + .otherwise((config) => withDefaultDisplayFormat({ ...config }, defaultDisplayFormat)); +} + +export function parseTimestampValue(value: string | number, config: TimestampDisplayConfig): Dayjs { + const numericValue = match(value) + .with(P.string, parseFloat) + .otherwise((n) => n); + + if (!isNaN(numericValue)) { + if (config.type == "unix") return dayjs.unix(numericValue); + if (config.type == "unixMillis") return dayjs(numericValue); + } + + if (config.valueFormat && config.valueTz) { + return dayjs.tz(value, config.valueFormat, config.valueTz); + } + + if (config.valueTz) { + return dayjs.tz(value, config.valueTz); + } + + if (config.valueFormat) { + return dayjs(value, config.valueFormat); + } + + return dayjs(value); +} + +export function formatTimestampDisplay(value: string | number, config: TimestampDisplayConfig): string { + let parsed = parseTimestampValue(value, config); + + if (!parsed.isValid()) { + return String(value); + } + + if (config.locale) { + parsed = parsed.locale(config.locale); + } + + return config.displayFormat ? parsed.format(config.displayFormat) : parsed.format(); +} + +export function formatTimestampFromValue( + value: string | number, + timestamp: TimestampSimpleConfig, + defaultDisplayFormat = DEFAULT_TIMESTAMP_DISPLAY_FORMAT +): string { + const config = normalizeTimestampValue(timestamp, defaultDisplayFormat); + if (!config) { + return String(value); + } + + return formatTimestampDisplay(value, config); +} + +export function useTimestampDisplay(input: MaybeRefOrGetter) { + const parsed = computed(() => { + const resolved = toValue(input); + return parseTimestampValue(resolved.value, resolved); + }); + + const display = computed(() => { + const resolved = toValue(input); + return formatTimestampDisplay(resolved.value, resolved); + }); + + return { + parsed, + display, + }; +}