优化
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import { afterEach, expect, it, vi } from 'vitest'
|
||||
import { mount, type VueWrapper } from '@vue/test-utils'
|
||||
import type { EChartsOption, LegendComponentOption, PieSeriesOption } from 'echarts'
|
||||
import TripOperationsCharts from './TripOperationsCharts.vue'
|
||||
import type { TripOperationsCharts as Charts, TripOperationsSummary } from '../api/tripOperations'
|
||||
|
||||
vi.mock('vue-echarts', () => ({ default: { name: 'VChart', props: ['option', 'initOptions', 'updateOptions', 'autoresize'], template: '<div class="echarts-pie-stub"/>' } }))
|
||||
const wrappers: VueWrapper[] = []
|
||||
const emptyCharts = (): Charts => ({ physicalPallets: [], destinationTrips: [], externalAgreedAmounts: [], externalPalletRates: [] })
|
||||
const summary = (): TripOperationsSummary => ({ trips: 20, inTransit: 5, completed: 15, physicalPallets: 90, palletSpaces: 100, ownPackages: 50, externalPackages: 20, externalAgreedAmounts: [{ currency: 'CNY', amount: 390 }, { currency: 'USD', amount: 100 }], costs: { visible: false, unrecordedTrips: null, unallocatedTrips: null, totals: [] } })
|
||||
function render(charts: Charts, totals = summary()) {
|
||||
const wrapper = mount(TripOperationsCharts, { props: { charts, summary: totals }, global: { stubs: {
|
||||
ElButton: { template: '<button><slot/></button>' },
|
||||
} } })
|
||||
wrappers.push(wrapper)
|
||||
return wrapper
|
||||
}
|
||||
const option = (wrapper: VueWrapper, selector: string) => wrapper.find(selector).findComponent({ name: 'VChart' }).props('option') as EChartsOption
|
||||
const series = (options: EChartsOption) => (options.series as PieSeriesOption[])[0]!
|
||||
afterEach(() => wrappers.splice(0).forEach(wrapper => wrapper.unmount()))
|
||||
|
||||
it('uses four ECharts pies with compact native legends, accurate server totals and daily rates', () => {
|
||||
const charts = emptyCharts()
|
||||
charts.physicalPallets = [{ label: '每日实运托盘', unit: '托', points: [{ label: '2026-10-02', value: 10 }] }]
|
||||
charts.destinationTrips = [{ label: '目的地涉及车次', unit: '次', points: [{ label: 'ONT8', value: 3 }, { label: 'ABE2', value: 8 }] }]
|
||||
charts.externalAgreedAmounts = [{ label: 'CNY', unit: 'CNY', points: [{ label: '2026-10-02', value: 390 }] }]
|
||||
charts.externalPalletRates = [{ label: 'CNY', unit: 'CNY/标准托位', points: [{ label: '2026-10-07', value: 30 }, { label: '2026-10-02', value: 90 }] }]
|
||||
const original = structuredClone(charts)
|
||||
const wrapper = render(charts)
|
||||
expect(wrapper.findAllComponents({ name: 'VChart' })).toHaveLength(4)
|
||||
for (const chart of wrapper.findAllComponents({ name: 'VChart' })) {
|
||||
expect(series(chart.props('option'))).toMatchObject({ type: 'pie', label: { show: false } })
|
||||
expect(chart.props('initOptions')).toEqual({ renderer: 'canvas' })
|
||||
expect(chart.props('updateOptions')).toEqual({ notMerge: true })
|
||||
}
|
||||
expect(wrapper.find('svg').exists()).toBe(false)
|
||||
expect(wrapper.find('.series-caption').exists()).toBe(false)
|
||||
expect(wrapper.find('.chart > .chart-note').exists()).toBe(false)
|
||||
expect(wrapper.find('.chart--pallets .chart-metric').text()).toBe('90 托')
|
||||
expect(wrapper.find('.chart--rates .chart-metric').text()).toContain('CNY/标准托位 30.00')
|
||||
expect(wrapper.find('.chart--rates .chart-metric').attributes('title')).toContain('最近统计日:2026-10-07')
|
||||
const legend = option(wrapper, '.chart--pallets').legend as LegendComponentOption
|
||||
expect(legend.icon).toBe('circle')
|
||||
expect(typeof legend.formatter === 'function' && legend.formatter('2026-10-02')).toBe('10-02')
|
||||
expect(option(wrapper, '.chart--pallets').tooltip).toMatchObject({ trigger: 'item', confine: true, renderMode: 'richText' })
|
||||
expect(series(option(wrapper, '.chart--rates')).data).toEqual([
|
||||
{ name: '2026-10-02', value: 90, itemStyle: { color: '#3b82f6' } },
|
||||
{ name: '2026-10-07', value: 30, itemStyle: { color: '#14b8a6' } },
|
||||
])
|
||||
expect(charts).toEqual(original)
|
||||
})
|
||||
|
||||
it('switches currency without combining monetary amounts or leaving stale ECharts slices', async () => {
|
||||
const charts = emptyCharts()
|
||||
charts.externalAgreedAmounts = [{ label: 'CNY', unit: 'CNY', points: [{ label: '2026-10-02', value: 390 }] }, { label: 'USD', unit: 'USD', points: [{ label: '2026-10-03', value: 100 }] }]
|
||||
const wrapper = render(charts)
|
||||
expect(wrapper.find('.chart--amounts .chart-metric').text()).toBe('CNY 390.00')
|
||||
expect(wrapper.find('.chart--amounts').findAllComponents({ name: 'VChart' })).toHaveLength(1)
|
||||
const usd = wrapper.findAll('.chart--amounts .series-selector button').find(button => button.text() === 'USD')!
|
||||
await usd.trigger('click')
|
||||
expect(usd.attributes('aria-pressed')).toBe('true')
|
||||
expect(wrapper.find('.chart--amounts .chart-metric').text()).toBe('USD 100.00')
|
||||
expect(series(option(wrapper, '.chart--amounts')).data).toEqual([{ name: '2026-10-03', value: 100, itemStyle: { color: '#3b82f6' } }])
|
||||
await wrapper.setProps({ charts: { ...charts, externalAgreedAmounts: [charts.externalAgreedAmounts[0]!] } })
|
||||
expect(wrapper.find('.chart--amounts .chart-metric').text()).toBe('CNY 390.00')
|
||||
})
|
||||
|
||||
it('keeps every destination in its pie and exposes full legend data only on demand', async () => {
|
||||
const charts = emptyCharts()
|
||||
charts.destinationTrips = [{ label: '目的地涉及车次', unit: '次', points: Array.from({ length: 7 }, (_, index) => ({ label: `FBA-${index}`, value: index + 1 })) }]
|
||||
const wrapper = render(charts)
|
||||
expect(wrapper.find('.chart--destinations .chart-metric').text()).toBe('7 个目的地')
|
||||
const options = option(wrapper, '.chart--destinations')
|
||||
expect(series(options).data).toHaveLength(7)
|
||||
expect((options.legend as LegendComponentOption).data).toHaveLength(5)
|
||||
expect(wrapper.find('.chart-details').exists()).toBe(false)
|
||||
await wrapper.find('.chart-more').trigger('click')
|
||||
expect(wrapper.emitted('show-details')).toHaveLength(1)
|
||||
await wrapper.setProps({ detailsVisible: true })
|
||||
expect(wrapper.find('[aria-label="派送目的地明细"]').findAll('tbody tr')).toHaveLength(7)
|
||||
expect(wrapper.find('[aria-label="派送目的地明细"]').text()).toContain('FBA-0')
|
||||
})
|
||||
|
||||
it('preserves known zeros and does not draw equal positive shares for an empty sum', () => {
|
||||
const charts = emptyCharts()
|
||||
charts.physicalPallets = [{ label: '托盘', unit: '托', points: [{ label: '2026-10-01', value: 0 }, { label: '2026-10-02', value: 2 }] }]
|
||||
charts.externalPalletRates = [{ label: 'USD', unit: 'USD/标准托位', points: [{ label: '2026-10-01', value: 0 }] }]
|
||||
const wrapper = render(charts)
|
||||
expect(series(option(wrapper, '.chart--rates'))).toMatchObject({ stillShowZeroSum: false, showEmptyCircle: true, data: [{ name: '2026-10-01', value: 0 }] })
|
||||
expect(option(wrapper, '.chart--rates').graphic).toMatchObject([{ style: { text: '暂无正值数据' } }])
|
||||
expect(wrapper.find('.chart--rates .chart-metric').text()).toContain('0.00')
|
||||
expect(series(option(wrapper, '.chart--pallets')).data).toHaveLength(2)
|
||||
})
|
||||
|
||||
it('shows missing amounts and rates as unknown and omits empty chart widgets', () => {
|
||||
const wrapper = render(emptyCharts(), { ...summary(), physicalPallets: 0, externalAgreedAmounts: [] })
|
||||
expect(wrapper.findAll('.chart-empty')).toHaveLength(4)
|
||||
expect(wrapper.find('.chart--amounts .chart-metric').text()).toBe('—')
|
||||
expect(wrapper.find('.chart--rates .chart-metric').text()).toBe('—')
|
||||
expect(wrapper.findComponent({ name: 'VChart' }).exists()).toBe(false)
|
||||
})
|
||||
Reference in New Issue
Block a user