export const DIMENSIONS = [ "region", "city", "type", "model", "department", "status", "vehicleClass", ] as const; export const GROUPS = [...DIMENSIONS, "none"] as const; export const CATEGORIES = [ "all", "inventory", "available", "awaiting", "operating", "pending", "abnormal", ] as const; export type Dimension = (typeof DIMENSIONS)[number]; export type QueryPlan = { kind: "assets" | "flow" | "clarify"; category: (typeof CATEGORIES)[number]; groupBy: (typeof GROUPS)[number]; secondaryGroupBy?: Dimension; view: "chart" | "table" | "list"; analysis?: "distribution" | "compare" | "exceptions" | "briefing"; filters: Partial>; start?: string; end?: string; comparePrevious?: boolean; exception?: "overdue" | "dueSoon" | "missingDueDate"; topN?: number; sortBy?: "count" | "rate" | "abnormal" | "pending"; sortOrder?: "asc" | "desc"; vehicleIds?: string[]; responseMode?: "vehicle-status"; excludeFilters?: Partial>; clarification?: string; }; export type AssistantAction = | { type: "explore"; interactionId: string; keys?: Partial>; date?: string } | { type: "drill"; keys: Partial> } | { type: "group"; groupBy: QueryPlan["groupBy"]; secondaryGroupBy?: Dimension; } | { type: "category"; category: QueryPlan["category"] } | { type: "analysis"; analysis: NonNullable } | { type: "view"; view: QueryPlan["view"] } | { type: "day"; date: string } | { type: "compare-period" } | { type: "exception"; exception: "overdue" } | { type: "restore" } | { type: "clear-filter"; dimension: Dimension } | { type: "reset-filters" } | { type: "sort"; sortBy: "count" | "rate" | "abnormal" | "pending"; sortOrder: "asc" | "desc"; topN?: number; }; export type AssistantRequest = { message?: string; subject: string | null; sessionId?: string; baseResultId?: string; action?: AssistantAction; }; export type AssistantRow = { id: string; plate: string; vehicleClass: string; type: string; model: string; region: string; city: string; department: string; status: string; inventory?: boolean; abnormal?: boolean; pending?: boolean; abnormalType?: string; targetCompletionTime?: string; actualCompletionTime?: string; date?: string; event?: string; }; /** A model chooses a query and a renderer; values are always computed by the server. */ export type AnalysisDisplay = "metrics" | "chart" | "table" | "list"; export type PresentationBlock = { id: string; title?: string; kind: "summary" | "narrative" | "metrics" | "chart" | "table"; text?: string; metrics?: string[]; dataset?: "groups" | "rows" | "daily" | "comparison"; chart?: "bar" | "donut" | "line"; series?: { field: string; label: string }[]; columns?: { field: string; label: string }[]; interactionId?: string; }; export type PresentationInteraction = { id: string; label: string; kind: "group" | "point" | "followup"; plan: QueryPlan; }; export type ResultPresentation = { title?: string; blocks: PresentationBlock[]; interactions: PresentationInteraction[]; }; export type AnalysisQuery = { id: string; title: string; question: string; plan: QueryPlan; display: AnalysisDisplay; }; export type AnalysisSection = Omit & { result?: AssistantResult; error?: string; }; export type AnalysisContext = { id: string; title: string; plan: QueryPlan; summary: string; metrics: AssistantResult["metrics"]; }; export type AssistantGroup = { name: string; count: number; operating: number; rate: number; keys?: Partial>; abnormal?: number; pending?: number; share?: number; }; export const GAP_REASONS = { unrecognized: "未识别需求", unsupported: "暂不支持", privacy: "输入未通过安全检查", generation: "生成失败", empty: "无匹配数据", unsatisfied: "用户标记未解决", } as const; export type GapReason = keyof typeof GAP_REASONS; export const GAP_STATUSES = { open: "待评估", planned: "已纳入计划", resolved: "已解决", dismissed: "暂不处理", } as const; export type GapStatus = keyof typeof GAP_STATUSES; export type DemandGap = { id: number; demand: string; reason: GapReason; status: GapStatus; occurrences: number; firstSeen: string; lastSeen: string; }; export type AssistantResult = { plan: QueryPlan; presentation?: ResultPresentation; presentationStatus?: "generated" | "fallback"; presentationWarning?: string; layout?: "tabs" | "stack"; sections?: AnalysisSection[]; /** Aggregated context only: no vehicle rows are needed to refer across analyses. */ analyses?: AnalysisContext[]; answerKind?: "analysis" | "clarification" | "help"; engine?: "deepseek" | "local"; suggestions?: string[]; interpretation?: string; contextNote?: string; scope?: { company: string; permission: string; filters: string[]; grouping: string; period: string; definitions: string[]; sourceUpdatedAt: string | null; }; unanswered?: { question: string; reason: string }[]; correction?: { resultId?: string; message: string }; outcome?: "complete" | "partial" | "empty" | "unsupported" | "clarification" | "help"; inventoryBreakdown?: { title: string; summary: string; groups: AssistantGroup[] }; title: string; summary: string; source: string; fetchedAt: string; sessionId?: string; resultId?: string; breadcrumbs?: { resultId: string; label: string }[]; groups: AssistantGroup[]; rows: AssistantRow[]; metrics: { label: string; value: number; unit: string }[]; insights?: string[]; exceptions?: { label: string; count: number; category?: QueryPlan["category"]; }[]; comparison?: { label: string; current: number; previous: number; delta: number; rate: number | null; }[]; groupComparison?: { baseline: string; rows: { name: string; count: number; delta: number; share: number; rateDelta: number; }[]; }; comparisonPeriod?: { start: string; end: string }; daily?: { date: string; delivered: number; returned: number; replaced: number; total: number; }[]; warning?: string; gap?: { recorded: boolean; reason: GapReason; demand: string }; }; export type AssistantEvent = | { type: "step"; label: string } | { type: "answer"; text: string } | { type: "result"; result: AssistantResult } | { type: "error"; message: string }; export const GROUP_LABELS: Record = { region: "区域", city: "城市", type: "车型", model: "型号", department: "部门", status: "运营状态", vehicleClass: "车型细分", none: "全部", }; export const CATEGORY_LABELS: Record = { all: "全部资产", inventory: "库存车辆", available: "可运营库存", awaiting: "待运营库存", operating: "运营车辆", pending: "待交车车辆", abnormal: "异动车辆", };