import { axiosInstance } from '@/api/rbac' import { resolveAdminApiPath } from '@/utils/adminApi' function monitorUrl(path: string): string { return resolveAdminApiPath(path) } function assertBusinessOk(body: unknown) { if (body == null) throw new Error('空响应') const payload = body as Record const code = payload.code ?? payload.Code const ok = code === undefined || code === null || code === 0 || code === 200 || code === '0' || code === '200' || payload.success === true || payload.Success === true if (!ok) { throw new Error( String(payload.msg ?? payload.Msg ?? payload.message ?? payload.Message ?? '请求失败'), ) } } function num(raw: unknown): number { const value = Number(raw ?? 0) return Number.isFinite(value) ? value : 0 } function growth(raw: unknown): number | null { if (raw === null || raw === undefined || raw === '') return null const value = Number(raw) return Number.isFinite(value) ? value : null } function normalizeRegionTrend(raw: unknown) { const bundle = (raw ?? {}) as Record const normalizePeriod = (periodRaw: unknown) => { const period = (periodRaw ?? {}) as Record const labels = period.labels ?? period.Labels const seriesRaw = period.series ?? period.Series return { labels: Array.isArray(labels) ? labels.map(String) : [], series: Array.isArray(seriesRaw) ? seriesRaw.map((item) => { const row = item as Record const values = row.values ?? row.Values return { region: String(row.region ?? row.Region ?? ''), values: Array.isArray(values) ? values.map((v) => num(v)) : [], } }) : [], } } return { week: normalizePeriod(bundle.week ?? bundle.Week), month: normalizePeriod(bundle.month ?? bundle.Month), } } export interface MonitorOverview { order: { todayCreated: number todayCreatedGrowthPercent: number | null total: number totalMonthGrowthPercent: number | null pendingPayment: number pendingOnline: number pendingSign: number problematic: number todayRevenue: number todayRevenueGrowthPercent: number | null } customer: { totalCustomers: number totalCustomersMonthGrowthPercent: number | null newCustomersToday: number newCustomersGrowthPercent: number | null onlineCustomers: number inactiveLogin7d: number inactiveLogin7dDelta: number } orderTrend7d: Array<{ label: string; count: number }> revenueTrend7d: Array<{ label: string; revenue: number; grossProfit: number }> regionOrderTrend: ReturnType regionReceivableTrend: ReturnType regionSignRates: Array<{ region: string; rate: number }> trackRates: { trackCompleteRate: number trackTimelyRate: number otdRate: number } } function normalizeOverview(raw: Record): MonitorOverview { const order = (raw.order ?? raw.Order ?? {}) as Record const customer = (raw.customer ?? raw.Customer ?? {}) as Record const track = (raw.trackRates ?? raw.TrackRates ?? {}) as Record const orderTrendRaw = raw.orderTrend7d ?? raw.OrderTrend7d const revenueTrendRaw = raw.revenueTrend7d ?? raw.RevenueTrend7d const signRatesRaw = raw.regionSignRates ?? raw.RegionSignRates return { order: { todayCreated: num(order.todayCreated ?? order.TodayCreated), todayCreatedGrowthPercent: growth(order.todayCreatedGrowthPercent ?? order.TodayCreatedGrowthPercent), total: num(order.total ?? order.Total), totalMonthGrowthPercent: growth(order.totalMonthGrowthPercent ?? order.TotalMonthGrowthPercent), pendingPayment: num(order.pendingPayment ?? order.PendingPayment), pendingOnline: num(order.pendingOnline ?? order.PendingOnline), pendingSign: num(order.pendingSign ?? order.PendingSign), problematic: num(order.problematic ?? order.Problematic), todayRevenue: num(order.todayRevenue ?? order.TodayRevenue), todayRevenueGrowthPercent: growth(order.todayRevenueGrowthPercent ?? order.TodayRevenueGrowthPercent), }, customer: { totalCustomers: num(customer.totalCustomers ?? customer.TotalCustomers), totalCustomersMonthGrowthPercent: growth( customer.totalCustomersMonthGrowthPercent ?? customer.TotalCustomersMonthGrowthPercent, ), newCustomersToday: num(customer.newCustomersToday ?? customer.NewCustomersToday), newCustomersGrowthPercent: growth( customer.newCustomersGrowthPercent ?? customer.NewCustomersGrowthPercent, ), onlineCustomers: num(customer.onlineCustomers ?? customer.OnlineCustomers), inactiveLogin7d: num(customer.inactiveLogin7d ?? customer.InactiveLogin7d), inactiveLogin7dDelta: num(customer.inactiveLogin7dDelta ?? customer.InactiveLogin7dDelta), }, orderTrend7d: Array.isArray(orderTrendRaw) ? orderTrendRaw.map((item) => { const row = item as Record return { label: String(row.label ?? row.Label ?? ''), count: num(row.count ?? row.Count), } }) : [], revenueTrend7d: Array.isArray(revenueTrendRaw) ? revenueTrendRaw.map((item) => { const row = item as Record return { label: String(row.label ?? row.Label ?? ''), revenue: num(row.revenue ?? row.Revenue), grossProfit: num(row.grossProfit ?? row.GrossProfit), } }) : [], regionOrderTrend: normalizeRegionTrend(raw.regionOrderTrend ?? raw.RegionOrderTrend), regionReceivableTrend: normalizeRegionTrend(raw.regionReceivableTrend ?? raw.RegionReceivableTrend), regionSignRates: Array.isArray(signRatesRaw) ? signRatesRaw.map((item) => { const row = item as Record return { region: String(row.region ?? row.Region ?? ''), rate: num(row.rate ?? row.Rate), } }) : [], trackRates: { trackCompleteRate: num(track.trackCompleteRate ?? track.TrackCompleteRate), trackTimelyRate: num(track.trackTimelyRate ?? track.TrackTimelyRate), otdRate: num(track.otdRate ?? track.OtdRate), }, } } /** 实时监控概览 GET /monitor/overview */ export async function getMonitorOverview(): Promise { const res = await axiosInstance.get(monitorUrl('/monitor/overview')) assertBusinessOk(res.data) const payload = res.data as Record const data = (payload.data ?? payload.Data ?? payload) as Record return normalizeOverview(data) } export function formatMonitorNumber(value: number): string { return Number(value || 0).toLocaleString() } export function formatMonitorCurrency(value: number): string { return `¥ ${Number(value || 0).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: 0, })}` } export function formatMonitorGrowth(value: number | null | undefined): { show: boolean up: boolean text: string } { if (value == null || Number.isNaN(Number(value))) { return { show: false, up: true, text: '' } } const numValue = Number(value) return { show: true, up: numValue >= 0, text: `${Math.abs(numValue).toFixed(1)}%`, } }