130 lines
3.8 KiB
TypeScript
130 lines
3.8 KiB
TypeScript
import type {
|
|
AssistantAction,
|
|
AssistantResult,
|
|
Dimension,
|
|
PresentationBlock,
|
|
PresentationInteraction,
|
|
} from "../../../shared/assets/assistant";
|
|
|
|
export type PresentationDatum = Record<string, unknown>;
|
|
const fields: Record<NonNullable<PresentationBlock["dataset"]>, string[]> = {
|
|
groups: [
|
|
"name",
|
|
"count",
|
|
"operating",
|
|
"rate",
|
|
"abnormal",
|
|
"pending",
|
|
"share",
|
|
],
|
|
daily: ["date", "delivered", "returned", "replaced", "total"],
|
|
comparison: ["label", "current", "previous", "delta", "rate"],
|
|
rows: [
|
|
"id",
|
|
"plate",
|
|
"vehicleClass",
|
|
"type",
|
|
"model",
|
|
"region",
|
|
"city",
|
|
"department",
|
|
"status",
|
|
"inventory",
|
|
"abnormal",
|
|
"pending",
|
|
"abnormalType",
|
|
"targetCompletionTime",
|
|
"actualCompletionTime",
|
|
"date",
|
|
"event",
|
|
],
|
|
};
|
|
export function presentationData(
|
|
result: AssistantResult,
|
|
dataset: PresentationBlock["dataset"],
|
|
): PresentationDatum[] {
|
|
return dataset ? (result[dataset] || []).map((row) => ({ ...row })) : [];
|
|
}
|
|
export function presentationFields(block: PresentationBlock) {
|
|
const allowed = block.dataset ? fields[block.dataset] : [];
|
|
const defaults =
|
|
block.dataset === "daily"
|
|
? [
|
|
{ field: "date", label: "日期" },
|
|
{ field: "total", label: "车次" },
|
|
]
|
|
: block.dataset === "comparison"
|
|
? [
|
|
{ field: "label", label: "指标" },
|
|
{ field: "current", label: "本期" },
|
|
{ field: "previous", label: "上期" },
|
|
]
|
|
: block.dataset === "rows"
|
|
? [
|
|
{ field: "plate", label: "车牌" },
|
|
{ field: "status", label: "状态" },
|
|
]
|
|
: [
|
|
{ field: "name", label: "分组" },
|
|
{ field: "count", label: "数量" },
|
|
];
|
|
return (block.columns?.length ? block.columns : defaults).filter((column) =>
|
|
allowed.includes(column.field),
|
|
);
|
|
}
|
|
export function presentationSeries(block: PresentationBlock) {
|
|
const allowed = block.dataset ? fields[block.dataset] : [];
|
|
const fallback =
|
|
block.dataset === "daily"
|
|
? { field: "total", label: "车次" }
|
|
: block.dataset === "comparison"
|
|
? { field: "current", label: "本期" }
|
|
: { field: "count", label: "数量" };
|
|
return (block.series?.length ? block.series : [fallback]).filter(
|
|
(series) =>
|
|
allowed.includes(series.field) &&
|
|
!["name", "date", "label"].includes(series.field),
|
|
);
|
|
}
|
|
export function presentationMetrics(
|
|
result: AssistantResult,
|
|
labels?: string[],
|
|
) {
|
|
return labels?.length
|
|
? labels.flatMap((label) => {
|
|
const metric = result.metrics.find((item) => item.label === label);
|
|
return metric ? [metric] : [];
|
|
})
|
|
: result.metrics;
|
|
}
|
|
export function presentationValue(value: unknown, field: string) {
|
|
if (value === undefined || value === null || value === "") return "—";
|
|
if (typeof value === "number")
|
|
return Number.isFinite(value)
|
|
? `${value.toLocaleString("zh-CN")}${["rate", "share"].includes(field) ? "%" : ""}`
|
|
: "—";
|
|
if (typeof value === "boolean") return value ? "是" : "否";
|
|
return typeof value === "string" ? value : "—";
|
|
}
|
|
export function presentationAction(
|
|
interaction: PresentationInteraction | undefined,
|
|
datum?: PresentationDatum,
|
|
): AssistantAction | undefined {
|
|
if (!interaction) return;
|
|
if (interaction.kind === "followup")
|
|
return { type: "explore", interactionId: interaction.id };
|
|
if (
|
|
interaction.kind === "group" &&
|
|
datum?.keys &&
|
|
typeof datum.keys === "object" &&
|
|
Object.keys(datum.keys).length
|
|
)
|
|
return {
|
|
type: "explore",
|
|
interactionId: interaction.id,
|
|
keys: datum.keys as Partial<Record<Dimension, string>>,
|
|
};
|
|
if (interaction.kind === "point" && typeof datum?.date === "string")
|
|
return { type: "explore", interactionId: interaction.id, date: datum.date };
|
|
}
|