Files
admin-web/src/modules/self-operated/skuTrendChart.ts
T

49 lines
3.2 KiB
TypeScript

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<number | null>(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,
}
}