import type { EChartsOption, LineSeriesOption } from 'echarts' import type { DailyPoint } from './types' import { label, quantityText, reasonsText, shownQuantity } from './state' export function skuTrendOption(points: DailyPoint[]): EChartsOption { const dates = points.map(point => point.businessDate) const values = points.map(point => { const value = shownQuantity(point) return point.dataStatus !== 'UNKNOWN' && value != null && Number.isFinite(Number(value)) ? Number(value) : null }) const series: LineSeriesOption[] = [{ name: '每日出库量', type: 'line', connectNulls: false, lineStyle: { opacity: 0 }, symbolSize: 8, showAllSymbol: true, data: values.map((value, index) => ({ value, symbol: points[index]?.dataStatus === 'COMPLETE' ? 'circle' : 'emptyCircle' })), itemStyle: { color: '#6078ea' }, emphasis: { scale: 1.5 }, }] let segment: { partial: boolean; data: (number | null)[] } | null = null for (let index = 1; index < points.length; index++) { if (values[index - 1] == null || values[index] == null || Date.parse(dates[index]!) - Date.parse(dates[index - 1]!) !== 86400000) { segment = null; continue } const partial = points[index - 1]!.dataStatus !== 'COMPLETE' || points[index]!.dataStatus !== 'COMPLETE' if (!segment || segment.partial !== partial) { segment = { partial, data: Array(points.length).fill(null) } series.push({ type: 'line', data: segment.data, symbol: 'none', silent: true, connectNulls: false, tooltip: { show: false }, lineStyle: { color: '#6078ea', width: 3, type: partial ? 'dashed' : 'solid' }, emphasis: { disabled: true }, animation: false }) } segment.data[index - 1] = values[index - 1]! segment.data[index] = values[index]! } return { animation: false, grid: { left: 24, right: 32, top: 42, bottom: 80, containLabel: true }, xAxis: { type: 'category', data: dates, name: '日期(北京时间)', nameLocation: 'middle', nameGap: 30, boundaryGap: false, axisLine: { show: true }, axisTick: { show: true }, axisLabel: { hideOverlap: true, showMinLabel: true, showMaxLabel: true, formatter: (value: string) => value.slice(5) } }, yAxis: { type: 'value', name: '出库量(件)', min: 0, axisLine: { show: true }, axisTick: { show: true }, splitLine: { show: true, lineStyle: { type: 'dashed', color: '#e5eaf3' } } }, tooltip: { trigger: 'axis', renderMode: 'richText', confine: true, axisPointer: { type: 'line' }, formatter: params => { const entries = Array.isArray(params) ? params : [params] const item = entries.find(entry => entry.seriesIndex === 0) ?? entries[0] const point = item ? points[item.dataIndex] : undefined return point ? `${point.businessDate}\n出库量:${quantityText(shownQuantity(point))} 件\n${label(point.dataStatus)}\n覆盖截止:${point.coveredUntil ?? '未知'}\n${reasonsText(point.reasonCodes)}` : '' } }, dataZoom: [{ type: 'slider', bottom: 4, height: 20, start: 0, end: 100, filterMode: 'none' }], aria: { enabled: true, description: 'SKU每日出库趋势。横轴为北京时间日期,纵轴为出库件数。完整日实线,未完整日虚线,缺失日期断线。详细数值可展开下方表格。' }, series, } }