fix(selfop): enable visible turnover rate sorting and formula help
This commit is contained in:
@@ -13,7 +13,7 @@ vi.mock('../api/analytics', () => ({ analyticsApi: mocks }))
|
|||||||
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => mocks.allowed }) }))
|
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => mocks.allowed }) }))
|
||||||
const toolbar = defineComponent({ name: 'QueryToolbar', props: ['modelValue', 'fields'], emits: ['update:modelValue', 'search', 'reset'], setup(_, { slots }) { return () => h('div', slots.actions?.()) } })
|
const toolbar = defineComponent({ name: 'QueryToolbar', props: ['modelValue', 'fields'], emits: ['update:modelValue', 'search', 'reset'], setup(_, { slots }) { return () => h('div', slots.actions?.()) } })
|
||||||
const table = defineComponent({ name: 'DataTable', props: ['data', 'columns', 'total', 'page'], emits: ['update:page', 'update:pageSize'], setup(p, { slots }) { return () => h('div', [slots.filters?.(), slots['toolbar-start']?.(), slots['toolbar-actions']?.(), slots['before-results']?.(), ...(p.columns ?? []).map((column: { headerSlotName?: string; prop: string; label: string }) => column.headerSlotName ? slots[column.headerSlotName]?.({ column: { property: column.prop, label: column.label } }) : null), ...(p.data ?? []).flatMap((row: TurnoverRow) => (p.columns ?? []).map((column: { slotName?: string; prop: keyof TurnoverRow }) => column.slotName && slots[column.slotName] ? slots[column.slotName]?.({ row }) : String(row[column.prop] ?? '')))]) } })
|
const table = defineComponent({ name: 'DataTable', props: ['data', 'columns', 'total', 'page'], emits: ['update:page', 'update:pageSize'], setup(p, { slots }) { return () => h('div', [slots.filters?.(), slots['toolbar-start']?.(), slots['toolbar-actions']?.(), slots['before-results']?.(), ...(p.columns ?? []).map((column: { headerSlotName?: string; prop: string; label: string }) => column.headerSlotName ? slots[column.headerSlotName]?.({ column: { property: column.prop, label: column.label } }) : null), ...(p.data ?? []).flatMap((row: TurnoverRow) => (p.columns ?? []).map((column: { slotName?: string; prop: keyof TurnoverRow }) => column.slotName && slots[column.slotName] ? slots[column.slotName]?.({ row }) : String(row[column.prop] ?? '')))]) } })
|
||||||
const button = defineComponent({ emits: ['click'], setup(_, { slots, emit }) { return () => h('button', { onClick: () => emit('click') }, slots.default?.()) } })
|
const button = defineComponent({ emits: ['click'], setup(_, { slots, emit }) { return () => h('button', { onClick: (event: MouseEvent) => emit('click', event) }, slots.default?.()) } })
|
||||||
const shell = defineComponent({ setup(_, { slots }) { return () => h('div', slots.default?.()) } })
|
const shell = defineComponent({ setup(_, { slots }) { return () => h('div', slots.default?.()) } })
|
||||||
const total = { value: 100, knownSubtotal: 100, unknownSkuCount: 0, reasonCodes: [] }
|
const total = { value: 100, knownSubtotal: 100, unknownSkuCount: 0, reasonCodes: [] }
|
||||||
const risk = { matchedSkuCount: 0, knownPhysicalQuantity: 0, unknownSkuCount: 0, physicalQuantityRatio: 0 }
|
const risk = { matchedSkuCount: 0, knownPhysicalQuantity: 0, unknownSkuCount: 0, physicalQuantityRatio: 0 }
|
||||||
@@ -208,6 +208,26 @@ describe('inventory turnover page fixed snapshot behavior', () => {
|
|||||||
await w.get('button[data-column="averageDailyOutboundQuantity"]').trigger('click'); await flushPromises()
|
await w.get('button[data-column="averageDailyOutboundQuantity"]').trigger('click'); await flushPromises()
|
||||||
expect(mocks.turnover.mock.calls.at(-1)![0]).toMatchObject({ baseWindowDays: 7, sortBy: 'AVERAGE_DAILY_DESC' })
|
expect(mocks.turnover.mock.calls.at(-1)![0]).toMatchObject({ baseWindowDays: 7, sortBy: 'AVERAGE_DAILY_DESC' })
|
||||||
})
|
})
|
||||||
|
it.each(['SKU', 'OWNER'] as const)('sorts the default percentage column for %s and keeps formula help independent', async (groupBy) => {
|
||||||
|
const w = page(); await flushPromises()
|
||||||
|
await change(w, { groupBy, customerCodes: ['OWNER-A'], rangePreset: 'LAST_7_DAYS' }, true)
|
||||||
|
w.findComponent(table).vm.$emit('update:page', 2); await flushPromises()
|
||||||
|
expect(w.find('button[data-column="quantityTurnoverCount"]').exists()).toBe(false)
|
||||||
|
const before = mocks.turnover.mock.calls.length
|
||||||
|
await w.get('button[aria-label="期间周转率计算说明"]').trigger('click'); await flushPromises()
|
||||||
|
expect(mocks.turnover).toHaveBeenCalledTimes(before)
|
||||||
|
expect(w.text()).toContain('期间周转率=所选 7 天完整出库量 ÷ 同期平均实物库存 × 100%')
|
||||||
|
expect(w.text()).toContain('平均实物库存=同期每日末实物库存之和 ÷ 天数')
|
||||||
|
const header = w.get('button[data-column="quantityTurnoverRate"]')
|
||||||
|
for (const direction of ['DESC', 'ASC']) {
|
||||||
|
await header.trigger('click'); await flushPromises()
|
||||||
|
expect(mocks.turnover.mock.calls.at(-1)![0]).toMatchObject({ groupBy, customerCodes: ['OWNER-A'], baseWindowDays: 7, endDate: '2026-10-12', hideZeroInventory: true, sortBy: `TURNOVER_${direction}`, current: 1, snapshotContext: 'token-A', includeOverview: false })
|
||||||
|
expect(header.attributes('aria-label')).toContain(direction === 'ASC' ? '当前升序' : '当前降序')
|
||||||
|
expect(w.findComponent(toolbar).props('modelValue').sortBy).toBe(`TURNOVER_${direction}`)
|
||||||
|
}
|
||||||
|
await w.findAll('button').find(b => b.text() === '扩展列')!.trigger('click')
|
||||||
|
expect(w.get('button[data-column="quantityTurnoverCount"]').attributes('aria-label')).toContain('当前升序')
|
||||||
|
})
|
||||||
it('keeps the successful sort marker and page when a header query fails', async () => {
|
it('keeps the successful sort marker and page when a header query fails', async () => {
|
||||||
const w = page(); await flushPromises()
|
const w = page(); await flushPromises()
|
||||||
w.findComponent(table).vm.$emit('update:page', 2); await flushPromises()
|
w.findComponent(table).vm.$emit('update:page', 2); await flushPromises()
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ const columns = computed<DataTableColumn[]>(() => [
|
|||||||
{ prop: 'transitQuantity', label: '在途', slotName: 'transitQuantity', minWidth: 125 },
|
{ prop: 'transitQuantity', label: '在途', slotName: 'transitQuantity', minWidth: 125 },
|
||||||
...([7, 15, 30] as const).map(n => ({ prop: `outbound${n}`, label: `${n}日出库`, slotName: `outbound${n}`, minWidth: 160 })),
|
...([7, 15, 30] as const).map(n => ({ prop: `outbound${n}`, label: `${n}日出库`, slotName: `outbound${n}`, minWidth: 160 })),
|
||||||
{ prop: 'averageDailyOutboundQuantity', label: `${applied.value?.baseWindowDays ?? 30}日日均`, slotName: 'daily', minWidth: 110 },
|
{ prop: 'averageDailyOutboundQuantity', label: `${applied.value?.baseWindowDays ?? 30}日日均`, slotName: 'daily', minWidth: 110 },
|
||||||
{ prop: 'quantityTurnoverRate', label: '期间周转率', slotName: 'turnoverRate', minWidth: 145 },
|
{ prop: 'quantityTurnoverRate', label: '期间周转率', slotName: 'turnoverRate', minWidth: 180 },
|
||||||
...(ownerMode.value ? [{ prop: 'noOutboundInWindow', label: '无出库SKU / 实物', slotName: 'noOutbound', minWidth: 190 }, { prop: 'slowCoverage', label: '慢消化SKU / 待判断', slotName: 'slow', minWidth: 175 }] : [{ prop: 'inventoryCoverageDays', label: '预计可售天数', slotName: 'coverage', minWidth: 150 }]),
|
...(ownerMode.value ? [{ prop: 'noOutboundInWindow', label: '无出库SKU / 实物', slotName: 'noOutbound', minWidth: 190 }, { prop: 'slowCoverage', label: '慢消化SKU / 待判断', slotName: 'slow', minWidth: 175 }] : [{ prop: 'inventoryCoverageDays', label: '预计可售天数', slotName: 'coverage', minWidth: 150 }]),
|
||||||
...(expanded.value ? [{ prop: 'frozenQuantity', label: '冻结件数', slotName: 'frozenQuantity', minWidth: 125 }, { prop: 'defectiveQuantity', label: '次品实物', slotName: 'defectiveQuantity', minWidth: 125 }, { prop: 'averagePhysicalQuantity', label: '期间平均实物', slotName: 'averageStock', minWidth: 145 }, { prop: 'quantityTurnoverCount', label: '期间件数周转', slotName: 'turnover', minWidth: 145 }, { prop: 'lastObservedOutboundDate', label: '最近已观测出库日', slotName: 'lastDate', minWidth: 180 }] : []),
|
...(expanded.value ? [{ prop: 'frozenQuantity', label: '冻结件数', slotName: 'frozenQuantity', minWidth: 125 }, { prop: 'defectiveQuantity', label: '次品实物', slotName: 'defectiveQuantity', minWidth: 125 }, { prop: 'averagePhysicalQuantity', label: '期间平均实物', slotName: 'averageStock', minWidth: 145 }, { prop: 'quantityTurnoverCount', label: '期间件数周转', slotName: 'turnover', minWidth: 145 }, { prop: 'lastObservedOutboundDate', label: '最近已观测出库日', slotName: 'lastDate', minWidth: 180 }] : []),
|
||||||
].map(column => ({ ...column, headerSlotName: turnoverSortColumns[column.prop] ? 'sortHeader' : undefined })))
|
].map(column => ({ ...column, headerSlotName: turnoverSortColumns[column.prop] ? 'sortHeader' : undefined })))
|
||||||
@@ -279,10 +279,22 @@ onUnmounted(() => { exportController?.abort(); fence.cancel(); runtimeFence.canc
|
|||||||
<p v-if="inputError" role="alert">{{ inputError }}</p><p v-if="notice" role="status">{{ notice }}</p>
|
<p v-if="inputError" role="alert">{{ inputError }}</p><p v-if="notice" role="status">{{ notice }}</p>
|
||||||
<DataTable :data="data?.rows ?? []" :columns="columns" :loading="loading" :total="data?.total ?? 0" :page="page" :page-size="size" appearance="integrated" :empty-text="!warehouses.length ? '暂无可用仓库' : error ? '读取失败,请重试' : '暂无符合条件的数据'" @update:page="page = $event; load()" @update:page-size="size = $event; search()">
|
<DataTable :data="data?.rows ?? []" :columns="columns" :loading="loading" :total="data?.total ?? 0" :page="page" :page-size="size" appearance="integrated" :empty-text="!warehouses.length ? '暂无可用仓库' : error ? '读取失败,请重试' : '暂无符合条件的数据'" @update:page="page = $event; load()" @update:page-size="size = $event; search()">
|
||||||
<template #sortHeader="{ column }">
|
<template #sortHeader="{ column }">
|
||||||
|
<span class="turnover-sort-heading">
|
||||||
<button type="button" class="turnover-sort" :data-column="column.property" :disabled="loading" :aria-label="`${column.label}:${columnSortDirection(column.property) === 'ASC' ? '当前升序,' : columnSortDirection(column.property) === 'DESC' ? '当前降序,' : ''}点击${columnSortDirection(column.property) === 'DESC' ? '升序' : '降序'}排列`" @click.stop="sortColumn(column.property)">
|
<button type="button" class="turnover-sort" :data-column="column.property" :disabled="loading" :aria-label="`${column.label}:${columnSortDirection(column.property) === 'ASC' ? '当前升序,' : columnSortDirection(column.property) === 'DESC' ? '当前降序,' : ''}点击${columnSortDirection(column.property) === 'DESC' ? '升序' : '降序'}排列`" @click.stop="sortColumn(column.property)">
|
||||||
{{ column.label }}
|
{{ column.label }}
|
||||||
<span class="turnover-sort-arrows" aria-hidden="true"><span :class="{ active: columnSortDirection(column.property) === 'ASC' }">▲</span><span :class="{ active: columnSortDirection(column.property) === 'DESC' }">▼</span></span>
|
<span class="turnover-sort-arrows" aria-hidden="true"><span :class="{ active: columnSortDirection(column.property) === 'ASC' }">▲</span><span :class="{ active: columnSortDirection(column.property) === 'DESC' }">▼</span></span>
|
||||||
</button>
|
</button>
|
||||||
|
<el-popover v-if="column.property === 'quantityTurnoverRate'" title="期间周转率计算说明" trigger="click" placement="bottom" :width="380" teleported>
|
||||||
|
<template #reference><el-button link aria-label="期间周转率计算说明" title="查看计算公式" @click.stop><Info :size="14" /></el-button></template>
|
||||||
|
<div class="turnover-rules">
|
||||||
|
<p>期间周转率=所选 {{ applied?.baseWindowDays ?? 30 }} 天完整出库量 ÷ 同期平均实物库存 × 100%。</p>
|
||||||
|
<p>平均实物库存=同期每日末实物库存之和 ÷ 天数。历史库存由流水还原并核对;包含冻结、次品实物,不含在途。</p>
|
||||||
|
<p>货主汇总使用汇总出库量 ÷ 汇总平均实物库存,不取各 SKU 百分比的平均值。</p>
|
||||||
|
<p>缺少完整销量、合格历史库存或平均库存为 0 时显示“—”;当前库存不代替历史平均库存。100% 表示所选期间出库量相当于平均库存周转一次。</p>
|
||||||
|
<p>点击列名切换从高到低/从低到高,对全部匹配记录排序,“—”排在最后。</p>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template #toolbar-start><slot name="view-tabs"><h2 class="turnover-title">库存周转<span>销量 · 库存 · 周转效率</span></h2></slot></template>
|
<template #toolbar-start><slot name="view-tabs"><h2 class="turnover-title">库存周转<span>销量 · 库存 · 周转效率</span></h2></slot></template>
|
||||||
<template #toolbar-actions><el-button :disabled="loading || !data || exporting" title="导出当前查询的全部记录与当前显示列(CSV)" @click="exportRows">{{ exporting ? `导出中 ${exportProgress} 条` : '导出' }}</el-button><el-button v-if="exporting" @click="exportController?.abort()">取消导出</el-button><el-button @click="router.push('/self-operated/collection')">数据采集</el-button><el-button @click="page = 1; load(true)">整体刷新</el-button><el-button @click="expanded = !expanded">{{ expanded ? '收起扩展列' : '扩展列' }}</el-button><el-popover title="统计说明" trigger="click" placement="bottom-end" :width="460" teleported><template #reference><el-button aria-label="库存周转统计说明" title="统计说明"><Info :size="16" /></el-button></template><div class="turnover-rules"><p>7/15/30天均为截至所选日期的完整滚动窗口。日均仅使用完整窗口;预计可售天数使用查询时固定的当前正品可售库存,不是库龄。</p><p>期间件数周转次数=同期完整出库÷流水还原并经库存锚点核对的每日末实物库存均值。缺日、缺商品或单位异常不补零;当前库存不代替历史平均库存。件数不是占用空间,快慢标签仅供人工复核。</p><p>货主视图按“含此类SKU的货主”筛选;未知数量保留已知小计,不平均SKU可售天数。库存过期不抹去有完整证据的历史销量与周转。</p>
|
<template #toolbar-actions><el-button :disabled="loading || !data || exporting" title="导出当前查询的全部记录与当前显示列(CSV)" @click="exportRows">{{ exporting ? `导出中 ${exportProgress} 条` : '导出' }}</el-button><el-button v-if="exporting" @click="exportController?.abort()">取消导出</el-button><el-button @click="router.push('/self-operated/collection')">数据采集</el-button><el-button @click="page = 1; load(true)">整体刷新</el-button><el-button @click="expanded = !expanded">{{ expanded ? '收起扩展列' : '扩展列' }}</el-button><el-popover title="统计说明" trigger="click" placement="bottom-end" :width="460" teleported><template #reference><el-button aria-label="库存周转统计说明" title="统计说明"><Info :size="16" /></el-button></template><div class="turnover-rules"><p>7/15/30天均为截至所选日期的完整滚动窗口。日均仅使用完整窗口;预计可售天数使用查询时固定的当前正品可售库存,不是库龄。</p><p>期间件数周转次数=同期完整出库÷流水还原并经库存锚点核对的每日末实物库存均值。缺日、缺商品或单位异常不补零;当前库存不代替历史平均库存。件数不是占用空间,快慢标签仅供人工复核。</p><p>货主视图按“含此类SKU的货主”筛选;未知数量保留已知小计,不平均SKU可售天数。库存过期不抹去有完整证据的历史销量与周转。</p>
|
||||||
@@ -391,6 +403,7 @@ onUnmounted(() => { exportController?.abort(); fence.cancel(); runtimeFence.canc
|
|||||||
</AdminPage>
|
</AdminPage>
|
||||||
</template>
|
</template>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.turnover-sort-heading { display: inline-flex; align-items: center; gap: var(--admin-space-1); }
|
||||||
.turnover-sort { display: inline-flex; align-items: center; gap: 6px; padding: 0; border: 0; background: transparent; color: inherit; font: inherit; cursor: pointer; }
|
.turnover-sort { display: inline-flex; align-items: center; gap: 6px; padding: 0; border: 0; background: transparent; color: inherit; font: inherit; cursor: pointer; }
|
||||||
.turnover-sort:disabled { cursor: wait; }
|
.turnover-sort:disabled { cursor: wait; }
|
||||||
.turnover-sort:focus-visible { outline: 2px solid var(--el-color-primary); outline-offset: 3px; }
|
.turnover-sort:focus-visible { outline: 2px solid var(--el-color-primary); outline-offset: 3px; }
|
||||||
|
|||||||
@@ -163,5 +163,6 @@
|
|||||||
| 库存周转/零库存筛选样式 | 用户截图 `codex-clipboard-c21dd284-0aed-4db0-840b-172260c2e3fb.png` | 将原生复选框从查询按钮组移到列表快捷筛选右侧,使用 Element 带边框复选框并垂直居中;无概览、无货主条件时不渲染空白概览行;首次读取失败不提示保留上次结果 | 保留默认选中、即时查询及禁用行为;视觉待人工1920×1080、100%截图确认 |
|
| 库存周转/零库存筛选样式 | 用户截图 `codex-clipboard-c21dd284-0aed-4db0-840b-172260c2e3fb.png` | 将原生复选框从查询按钮组移到列表快捷筛选右侧,使用 Element 带边框复选框并垂直居中;无概览、无货主条件时不渲染空白概览行;首次读取失败不提示保留上次结果 | 保留默认选中、即时查询及禁用行为;视觉待人工1920×1080、100%截图确认 |
|
||||||
|
|
||||||
| 库存周转/多选货主、导出及周转率 | 用户截图 `codex-clipboard-b295bb06-d54f-45a8-9d9f-d7562da01ac8.png` 与本轮追加要求 | 原货主下拉改为可搜索多选,选项折叠并可清空,SKU/货主两视图及概览、图表同集合查询;列表顶部导出当前查询全部匹配记录为CSV,包含当前显示列与扩展列,显示进度、支持取消;默认显示期间周转率=期间件数周转次数×100%,未知保留—,悬停说明原因及口径 | 多选范围、跨页导出、CSV转义、空值与零值回归;视觉待人工1920×1080、100%截图确认 |
|
| 库存周转/多选货主、导出及周转率 | 用户截图 `codex-clipboard-b295bb06-d54f-45a8-9d9f-d7562da01ac8.png` 与本轮追加要求 | 原货主下拉改为可搜索多选,选项折叠并可清空,SKU/货主两视图及概览、图表同集合查询;列表顶部导出当前查询全部匹配记录为CSV,包含当前显示列与扩展列,显示进度、支持取消;默认显示期间周转率=期间件数周转次数×100%,未知保留—,悬停说明原因及口径 | 多选范围、跨页导出、CSV转义、空值与零值回归;视觉待人工1920×1080、100%截图确认 |
|
||||||
|
| 库存周转/期间周转率表头 | 用户截图 `codex-clipboard-94ff8645-7783-42b1-a82d-3170295b823a.png` 要求计算口径与排序直接放在默认百分比列 | 默认百分比列接入 TURNOVER 服务端全量升降序,与扩展周转次数及排序下拉同步;保留货主、日期、固定版本、隐藏零库存并回到第一页。列名旁信息按钮独立展示公式、日末均值、货主汇总与未知口径,不触发查询 | 默认列实际点击、两种分组、双向排序与说明按钮回归;视觉待人工1920×1080、100%截图确认 |
|
||||||
|
|
||||||
| 经营总览/指标卡说明 | 用户反馈“完整”下方破折号含义不清 | 无异常原因时不渲染说明占位符,待核验为0时隐藏该行;真实异常、正数待核验、未知主数值及已知小计保留 | 页面回归及构建;视觉待人工截图确认 |
|
| 经营总览/指标卡说明 | 用户反馈“完整”下方破折号含义不清 | 无异常原因时不渲染说明占位符,待核验为0时隐藏该行;真实异常、正数待核验、未知主数值及已知小计保留 | 页面回归及构建;视觉待人工截图确认 |
|
||||||
|
|||||||
@@ -6,19 +6,19 @@ export const turnoverSortColumns: Record<string, TurnoverSortMetric> = {
|
|||||||
outbound7: 'OUTBOUND_7', outbound15: 'OUTBOUND_15', outbound30: 'OUTBOUND_30',
|
outbound7: 'OUTBOUND_7', outbound15: 'OUTBOUND_15', outbound30: 'OUTBOUND_30',
|
||||||
averageDailyOutboundQuantity: 'AVERAGE_DAILY', inventoryCoverageDays: 'COVERAGE',
|
averageDailyOutboundQuantity: 'AVERAGE_DAILY', inventoryCoverageDays: 'COVERAGE',
|
||||||
frozenQuantity: 'FROZEN', defectiveQuantity: 'DEFECTIVE',
|
frozenQuantity: 'FROZEN', defectiveQuantity: 'DEFECTIVE',
|
||||||
averagePhysicalQuantity: 'AVERAGE_PHYSICAL', quantityTurnoverCount: 'TURNOVER',
|
averagePhysicalQuantity: 'AVERAGE_PHYSICAL', quantityTurnoverCount: 'TURNOVER', quantityTurnoverRate: 'TURNOVER',
|
||||||
}
|
}
|
||||||
const metricLabels: Record<TurnoverSortMetric, string> = {
|
const metricLabels: Record<TurnoverSortMetric, string> = {
|
||||||
INVENTORY_VOLUME: '库存立方数', OUTBOUND_VOLUME: '所选时段出库立方数(估算)', UNIT_VOLUME: '单件体积',
|
INVENTORY_VOLUME: '库存立方数', OUTBOUND_VOLUME: '所选时段出库立方数(估算)', UNIT_VOLUME: '单件体积',
|
||||||
PHYSICAL: '实物件数', AVAILABLE: '正品可售', TRANSIT: '在途', OUTBOUND_7: '完整7日出库',
|
PHYSICAL: '实物件数', AVAILABLE: '正品可售', TRANSIT: '在途', OUTBOUND_7: '完整7日出库',
|
||||||
OUTBOUND_15: '完整15日出库', OUTBOUND_30: '完整30日出库', AVERAGE_DAILY: '基准窗口日均出库',
|
OUTBOUND_15: '完整15日出库', OUTBOUND_30: '完整30日出库', AVERAGE_DAILY: '基准窗口日均出库',
|
||||||
COVERAGE: '预计可售天数', FROZEN: '冻结件数', DEFECTIVE: '次品实物',
|
COVERAGE: '预计可售天数', FROZEN: '冻结件数', DEFECTIVE: '次品实物',
|
||||||
AVERAGE_PHYSICAL: '期间平均实物', TURNOVER: '期间件数周转',
|
AVERAGE_PHYSICAL: '期间平均实物', TURNOVER: '期间周转率',
|
||||||
}
|
}
|
||||||
export const turnoverSortOptions: { value: TurnoverSort; label: string }[] = [
|
export const turnoverSortOptions: { value: TurnoverSort; label: string }[] = [
|
||||||
...(Object.keys(metricLabels) as TurnoverSortMetric[]).flatMap(metric => [
|
...(Object.keys(metricLabels) as TurnoverSortMetric[]).flatMap(metric => [
|
||||||
{ value: `${metric}_DESC` as TurnoverSort, label: `${metricLabels[metric]}从多到少` },
|
{ value: `${metric}_DESC` as TurnoverSort, label: `${metricLabels[metric]}${metric === 'TURNOVER' ? '从高到低' : '从多到少'}` },
|
||||||
{ value: `${metric}_ASC` as TurnoverSort, label: `${metricLabels[metric]}从少到多` },
|
{ value: `${metric}_ASC` as TurnoverSort, label: `${metricLabels[metric]}${metric === 'TURNOVER' ? '从低到高' : '从少到多'}` },
|
||||||
]),
|
]),
|
||||||
{ value: 'NO_OUTBOUND_PHYSICAL_DESC', label: '已确认无出库实物最多' },
|
{ value: 'NO_OUTBOUND_PHYSICAL_DESC', label: '已确认无出库实物最多' },
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user