import { Router, type Request, type Response } from 'express' import { listFactories, listOrders } from '../db.js' import { requireAuth } from '../middleware/requireAuth.js' const router = Router() router.use(requireAuth) const cleanText = (v: unknown): string => { if (v === null || v === undefined) return '' return String(v).replace(/\u00A0/g, ' ').replace(/[\s\u3000]+/g, ' ').trim() } const isDone = (status: string): boolean => { const s = cleanText(status) if (!s) return false return /完成|已出完|出完|结束|已完成/.test(s) } const isCanceled = (status: string): boolean => { const s = cleanText(status) if (!s) return false return /取消|作废/.test(s) } const normalizeStage = (status: string): string => { const s = cleanText(status) if (!s) return '未填写' if (isCanceled(s)) return '取消' if (isDone(s)) return '完成' if (/验货|驗貨|待验货|已验货/.test(s)) return '验货' if (/订舱|訂艙|订仓|订仓/.test(s)) return '订舱' if (/包材|唛头|嘜頭/.test(s)) return '包材唛头' if (/不干胶|外箱/.test(s)) return '外箱不干胶' if (/出货|出運|出运|发货|發貨|已出货|待送货/.test(s)) return '出货' if (/生产|待生产|排版|催大货样/.test(s)) return '生产' if (/下单|下單/.test(s)) return '下单' return '其他' } const dateKey = (s?: string): string => { const v = cleanText(s) return v ? v.slice(0, 10) : '' } const lastNDaysKeys = (n: number): string[] => { const out: string[] = [] const now = new Date() now.setHours(0, 0, 0, 0) for (let i = n - 1; i >= 0; i -= 1) { const d = new Date(now) d.setDate(d.getDate() - i) out.push(d.toISOString().slice(0, 10)) } return out } router.get('/dashboard', async (_req: Request, res: Response): Promise => { const orders = await listOrders() const factories = await listFactories() const today = new Date().toISOString().slice(0, 10) const active = orders.filter((o) => !isDone(o.orderProgress) && !isCanceled(o.orderProgress)) const totalAmount = orders.reduce((sum, o) => sum + (o.orderAmount ?? 0), 0) const overdue = active.filter((o) => { const due = dateKey(o.customerDeliveryDate) if (!due) return false return due < today }) const statusMap = new Map() for (const o of orders) { const stage = normalizeStage(o.orderProgress) statusMap.set(stage, (statusMap.get(stage) ?? 0) + 1) } const statusDist = Array.from(statusMap.entries()).map(([name, value]) => ({ name, value, })) const factoryNameById = new Map(factories.map((f) => [f.id, f.name])) const factoryMap = new Map() for (const o of orders) { const key = (o.factoryId ? factoryNameById.get(o.factoryId) : undefined) ?? '未指定' factoryMap.set(key, (factoryMap.get(key) ?? 0) + 1) } const factoryDist = Array.from(factoryMap.entries()).map(([name, value]) => ({ name, value, })) const days = lastNDaysKeys(30) const seriesMap = new Map(days.map((d) => [d, { date: d, amount: 0, count: 0 }])) for (const o of orders) { const d = dateKey(o.orderDate) || dateKey(o.createdAt) if (!d || !seriesMap.has(d)) continue const row = seriesMap.get(d)! row.amount += o.orderAmount ?? 0 row.count += 1 } const series = days.map((d) => seriesMap.get(d)!) res.json({ success: true, data: { kpis: { totalOrders: orders.length, activeOrders: active.length, overdueOrders: overdue.length, totalAmount, }, charts: { statusDist, factoryDist, trend: series, }, }, }) }) export default router