import { createApiClient } from "../lib/apiClient"; import type { DashboardCategorySliceDto, DashboardMetricCardDto, DashboardOverviewDto, DashboardRecentLabelItemDto, WeeklyPrintVolumePointDto, } from "../types/dashboardOverview"; const api = createApiClient({ getToken: () => { try { return localStorage.getItem("access_token") ?? localStorage.getItem("token") ?? null; } catch { return null; } }, }); const PATH = "/dashboard/overview"; function num(x: unknown, fallback = 0): number { const n = typeof x === "number" ? x : Number(x); return Number.isFinite(n) ? n : fallback; } function normMetric(raw: unknown): DashboardMetricCardDto { if (!raw || typeof raw !== "object") { return { key: "", title: "", value: 0, previousValue: 0, changeValue: 0, changeRate: 0 }; } const o = raw as Record; return { key: String(o.key ?? o.Key ?? ""), title: String(o.title ?? o.Title ?? ""), value: num(o.value ?? o.Value, 0), previousValue: num(o.previousValue ?? o.PreviousValue, 0), changeValue: num(o.changeValue ?? o.ChangeValue, 0), changeRate: num(o.changeRate ?? o.ChangeRate, 0), }; } function normWeeklyPoint(raw: unknown): WeeklyPrintVolumePointDto | null { if (!raw || typeof raw !== "object") return null; const o = raw as Record; const date = String(o.date ?? o.Date ?? ""); if (!date) return null; return { date, value: num(o.value ?? o.Value, 0) }; } function normCategorySlice(raw: unknown): DashboardCategorySliceDto | null { if (!raw || typeof raw !== "object") return null; const o = raw as Record; const categoryId = String(o.categoryId ?? o.CategoryId ?? ""); const categoryName = String(o.categoryName ?? o.CategoryName ?? ""); return { categoryId, categoryName, count: num(o.count ?? o.Count, 0), ratio: num(o.ratio ?? o.Ratio, 0), }; } function str(o: Record, camel: string, pascal: string, fallback = ""): string { const v = o[camel] ?? o[pascal]; if (v === null || v === undefined) return fallback; return String(v); } function normRecentLabel(raw: unknown): DashboardRecentLabelItemDto | null { if (!raw || typeof raw !== "object") return null; const o = raw as Record; const taskId = str(o, "taskId", "TaskId", ""); const labelCode = str(o, "labelCode", "LabelCode", ""); const displayName = str(o, "displayName", "DisplayName", ""); const printedAt = str(o, "printedAt", "PrintedAt", ""); const status = str(o, "status", "Status", "active"); const labelTypeBadge = str(o, "labelTypeBadge", "LabelTypeBadge", ""); const printedBy = str(o, "printedByName", "PrintedByName", ""); const pbUid = o.printedByUserId ?? o.PrintedByUserId; const printedByUserId = pbUid === null || pbUid === undefined ? null : String(pbUid); if (!taskId && !labelCode) return null; return { taskId: taskId || labelCode, labelCode: labelCode || "—", displayName: displayName || "—", printedByUserId, printedByName: printedBy || "—", printedAt: printedAt, status: status || "active", labelTypeBadge: labelTypeBadge || "—", }; } function normalizeOverview(raw: unknown): DashboardOverviewDto { if (!raw || typeof raw !== "object") { return emptyOverview(); } const o = raw as Record; const weeklyRaw = (o.weeklyPrintVolume ?? o.WeeklyPrintVolume) as unknown; const weeklyArr = Array.isArray(weeklyRaw) ? weeklyRaw : []; const byCat = (o.byCategory ?? o.ByCategory) as unknown; const legacyCat = (o.categoryDistribution ?? o.CategoryDistribution) as unknown; const catArr = Array.isArray(byCat) && byCat.length ? byCat : Array.isArray(legacyCat) ? legacyCat : []; const totalRaw = o.byCategoryTotal ?? o.ByCategoryTotal ?? o.categoryDistributionTotal ?? o.CategoryDistributionTotal; const total = num(totalRaw, 0); const recentRaw = (o.recentLabels ?? o.RecentLabels) as unknown; const recentArr = Array.isArray(recentRaw) ? recentRaw : []; return { labelsPrintedToday: normMetric(o.labelsPrintedToday ?? o.LabelsPrintedToday), activeTemplates: normMetric(o.activeTemplates ?? o.ActiveTemplates), activeUsers: normMetric(o.activeUsers ?? o.ActiveUsers), locations: normMetric(o.locations ?? o.Locations), people: normMetric(o.people ?? o.People), products: normMetric(o.products ?? o.Products), weeklyPrintVolume: weeklyArr .map(normWeeklyPoint) .filter((x): x is WeeklyPrintVolumePointDto => x !== null), byCategory: catArr .map(normCategorySlice) .filter((x): x is DashboardCategorySliceDto => x !== null), byCategoryTotal: Number.isFinite(total) ? total : 0, recentLabels: recentArr .map(normRecentLabel) .filter((x): x is DashboardRecentLabelItemDto => x !== null), generatedAt: (o.generatedAt ?? o.GeneratedAt ?? null) as string | null, metricCards: Array.isArray(o.metricCards ?? o.MetricCards) ? (o.metricCards ?? o.MetricCards)!.map(normMetric) : undefined, categoryDistribution: Array.isArray(o.categoryDistribution ?? o.CategoryDistribution) ? (o.categoryDistribution ?? o.CategoryDistribution)!.map(normCategorySlice).filter(Boolean) as DashboardCategorySliceDto[] : undefined, categoryDistributionTotal: num(o.categoryDistributionTotal ?? o.CategoryDistributionTotal, 0), }; } function emptyMetric(key: string, title: string): DashboardMetricCardDto { return { key, title, value: 0, previousValue: 0, changeValue: 0, changeRate: 0 }; } function emptyOverview(): DashboardOverviewDto { return { labelsPrintedToday: emptyMetric("labelsPrintedToday", "Labels Printed Today"), activeTemplates: emptyMetric("activeTemplates", "Active Templates"), activeUsers: emptyMetric("activeUsers", "Active Users"), locations: emptyMetric("locations", "Locations"), people: emptyMetric("people", "People"), products: emptyMetric("products", "Products"), weeklyPrintVolume: [], byCategory: [], byCategoryTotal: 0, recentLabels: [], generatedAt: null, }; } /** * Dashboard 首页统计(文档:`Dashboard统计接口对接说明.md`) */ export async function getDashboardOverview(signal?: AbortSignal): Promise { const raw = await api.requestJson({ path: PATH, method: "GET", signal, }); return normalizeOverview(raw); } export type { DashboardOverviewDto };