优化
This commit is contained in:
@@ -363,7 +363,7 @@ onMounted(load)
|
||||
:columns="candidateColumns"
|
||||
:loading="loading || selectionLoading || mutating"
|
||||
preference-key="global-smart-loading-candidates"
|
||||
:show-column-settings="false"
|
||||
column-settings-mode="hide"
|
||||
:empty-text="selectedContainer ? '当前仓库暂无可装货物' : '暂无可用柜次'"
|
||||
>
|
||||
<template #actions="{ row }">
|
||||
@@ -435,7 +435,7 @@ onMounted(load)
|
||||
<div><div class="meter-title"><span>体积</span><strong>{{ formatNumber(totalVolume) }} / {{ formatNumber(volumeLimit) }} m³</strong></div><el-progress :percentage="Math.min(displayedVolumePercent, 100)" :status="volumePercent > 100 ? 'exception' : undefined" /></div>
|
||||
<div><div class="meter-title"><span>重量</span><strong>{{ formatNumber(totalWeight, 1) }} / {{ formatNumber(weightLimit, 1) }} kg</strong></div><el-progress :percentage="Math.min(displayedWeightPercent, 100)" :status="weightPercent > 100 ? 'exception' : undefined" /></div>
|
||||
</div>
|
||||
<DataTable :data="plan.items" :columns="itemColumns" :loading="selectionLoading || mutating" preference-key="global-smart-loading-items" :show-column-settings="false" empty-text="当前柜次暂无已装货物">
|
||||
<DataTable :data="plan.items" :columns="itemColumns" :loading="selectionLoading || mutating" preference-key="global-smart-loading-items" column-settings-mode="hide" empty-text="当前柜次暂无已装货物">
|
||||
<template #actions="{ row }"><div class="row-actions"><el-button v-if="canAssign && editable" link type="primary" :disabled="quantityDrafts[row.id] === row.packageCount" @click="adjust(row)"><Save :size="15" />保存</el-button><el-button v-if="canDelete && editable" link type="danger" @click="remove(row)"><Trash2 :size="15" />移除</el-button></div></template>
|
||||
<template #order="{ row }"><strong>{{ row.orderNo || '—' }}</strong><small>{{ row.inboundCode || '—' }}</small></template>
|
||||
<template #goods="{ row }"><strong>{{ row.productNameZh || '未命名货物' }}</strong><small>{{ row.skuCode || '无 SKU' }}</small></template>
|
||||
|
||||
@@ -227,7 +227,7 @@ onMounted(load)
|
||||
<section v-if="container" class="capacity-grid"><div><div class="meter-title"><span>体积占用(含 110% 上限)</span><strong>{{ formatNumber(totalVolume) }} / {{ formatNumber(volumeLimit) }} m³</strong></div><el-progress :percentage="Math.min(displayedVolumePercent,100)" :status="volumePercent > 100 ? 'exception' : undefined" /></div><div><div class="meter-title"><span>重量占用(含 110% 上限)</span><strong>{{ formatNumber(totalWeight,1) }} / {{ formatNumber(weightLimit,1) }} kg</strong></div><el-progress :percentage="Math.min(displayedWeightPercent,100)" :status="weightPercent > 100 ? 'exception' : undefined" /></div></section>
|
||||
<el-empty v-if="noDraft" description="该货柜尚未创建排柜计划"><el-button v-if="canCreate" type="primary" :loading="mutating" @click="createPlan"><Plus :size="16" />创建排柜计划</el-button></el-empty>
|
||||
<template v-else-if="plan">
|
||||
<DataTable :data="plan.items" :columns="itemColumns" :loading="loading || mutating" preference-key="smart-loading-items" :show-column-settings="false" empty-text="暂无已分配货物">
|
||||
<DataTable :data="plan.items" :columns="itemColumns" :loading="loading || mutating" preference-key="smart-loading-items" column-settings-mode="hide" empty-text="暂无已分配货物">
|
||||
<template #toolbar-start><div><h2>装柜方案</h2><p>计划 {{ plan.planNo }} · 版本 {{ plan.version }};智能建议必须经人工核对。</p></div></template>
|
||||
<template #actions="{ row }"><div class="row-actions"><el-button v-if="canAssign && editable" link type="primary" :disabled="quantityDrafts[row.id] === row.packageCount" @click="adjust(row)"><Save :size="15" />保存箱数</el-button><el-button v-if="canDelete && editable" link type="danger" @click="remove(row)"><Trash2 :size="15" />移除</el-button></div></template>
|
||||
<template #order="{ row }"><strong>{{ row.orderNo || '—' }}</strong><small>{{ row.inboundCode || '—' }}</small></template>
|
||||
@@ -236,7 +236,7 @@ onMounted(load)
|
||||
<template #volume="{ row }">{{ formatNumber(Number(row.volumeCbm || 0)) }} m³</template><template #weight="{ row }">{{ formatNumber(Number(row.grossWeightKg || 0),1) }} kg</template>
|
||||
<template #destination="{ row }">{{ row.destinationWarehouseName || row.destinationWarehouseCode || '—' }}</template>
|
||||
</DataTable>
|
||||
<DataTable :data="candidates" :columns="candidateColumns" :loading="loading || mutating" preference-key="smart-loading-candidates" :show-column-settings="false" empty-text="当前仓库暂无可排柜货物">
|
||||
<DataTable :data="candidates" :columns="candidateColumns" :loading="loading || mutating" preference-key="smart-loading-candidates" column-settings-mode="hide" empty-text="当前仓库暂无可排柜货物">
|
||||
<template #toolbar-start><div><h2>候选货物</h2><p>系统基于仓库、目的仓、可用箱数及 110% 容量上限校验。</p></div></template>
|
||||
<template #actions="{ row }"><el-button v-if="canAssign && editable" link type="primary" :disabled="!routeMatches(row) || assignedDetailIds.has(row.inboundDetailId) || row.availablePackageCount < 1" @click="openAssign(row)"><Plus :size="15" />分配</el-button></template>
|
||||
<template #order="{ row }"><strong>{{ row.orderNo || '—' }}</strong><small>{{ row.inboundCode || '—' }}</small></template>
|
||||
|
||||
@@ -79,4 +79,11 @@ describe('PlatformFirstLegOrdersPanel review queue', () => {
|
||||
expect(source).toContain('item.reason || historyActionLabel(item.action)')
|
||||
expect(source).not.toContain('item.reason || item.action')
|
||||
})
|
||||
|
||||
it('formats cargo measurements without exposing floating-point tails', () => {
|
||||
expect(source).toContain("numeric.toLocaleString('zh-CN', { maximumFractionDigits: 3 })")
|
||||
expect(source).toContain('formatMeasurement(row.grossWeightKg)')
|
||||
expect(source).toContain('formatMeasurement(row.volumeCbm)')
|
||||
expect(source).not.toContain('{{ row.grossWeightKg }} kg / {{ row.volumeCbm }} m³')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -163,6 +163,13 @@ function formattedDate(value: string | null | undefined) {
|
||||
return value ? value.replace('T', ' ').slice(0, 16) : '-'
|
||||
}
|
||||
|
||||
function formatMeasurement(value: unknown) {
|
||||
const numeric = Number(value)
|
||||
return value === null || value === undefined || value === '' || !Number.isFinite(numeric)
|
||||
? '—'
|
||||
: numeric.toLocaleString('zh-CN', { maximumFractionDigits: 3 })
|
||||
}
|
||||
|
||||
function tenantFor(tenantId: number | string) {
|
||||
return tenants.value.find((tenant) => String(tenant.id) === String(tenantId))
|
||||
}
|
||||
@@ -510,7 +517,7 @@ onMounted(() => void loadTenants())
|
||||
<el-table-column prop="cargoName" label="品名" min-width="150" />
|
||||
<el-table-column prop="packageType" label="包装" min-width="100" />
|
||||
<el-table-column prop="packageCount" label="件/箱" width="86" />
|
||||
<el-table-column label="毛重 / 体积" min-width="150"><template #default="{ row }">{{ row.grossWeightKg }} kg / {{ row.volumeCbm }} m³</template></el-table-column>
|
||||
<el-table-column label="毛重 / 体积" min-width="150"><template #default="{ row }">{{ formatMeasurement(row.grossWeightKg) }} kg / {{ formatMeasurement(row.volumeCbm) }} m³</template></el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -22,7 +22,7 @@ const configurableColumns: DataTableColumn[] = [
|
||||
|
||||
function mountTable() {
|
||||
return shallowMount(DataTable, {
|
||||
props: { data: [], columns: configurableColumns, preferenceKey: 'orders-table' },
|
||||
props: { data: [], columns: configurableColumns, preferenceKey: 'orders-table', columnSettingsMode: 'show' },
|
||||
global: {
|
||||
provide: { [UI_PREFERENCE_SCOPE as symbol]: computed(() => 'user-1') },
|
||||
stubs: {
|
||||
@@ -90,7 +90,7 @@ describe('DataTable column preferences', () => {
|
||||
|
||||
it('keeps business actions, column settings, and trailing controls in one toolbar', () => {
|
||||
const wrapper = shallowMount(DataTable, {
|
||||
props: { data: [], columns: configurableColumns, preferenceKey: 'orders-table' },
|
||||
props: { data: [], columns: configurableColumns, preferenceKey: 'orders-table', columnSettingsMode: 'show' },
|
||||
slots: {
|
||||
'toolbar-start': '<h2>订单列表</h2>',
|
||||
'toolbar-actions': '<button>新增订单</button>',
|
||||
@@ -120,7 +120,7 @@ describe('DataTable column preferences', () => {
|
||||
|
||||
it('uses a compact right-aligned toolbar when no leading content is provided', () => {
|
||||
const wrapper = shallowMount(DataTable, {
|
||||
props: { data: [], columns: configurableColumns, preferenceKey: 'orders-table' },
|
||||
props: { data: [], columns: configurableColumns, preferenceKey: 'orders-table', columnSettingsMode: 'show' },
|
||||
slots: { 'toolbar-actions': '<button>新增订单</button>' },
|
||||
global: {
|
||||
provide: { [UI_PREFERENCE_SCOPE as symbol]: computed(() => 'user-1') },
|
||||
@@ -142,7 +142,7 @@ describe('DataTable column preferences', () => {
|
||||
|
||||
it('keeps business actions in a separate mobile-wrappable group from column settings', () => {
|
||||
const wrapper = shallowMount(DataTable, {
|
||||
props: { data: [], columns: configurableColumns, preferenceKey: 'orders-table' },
|
||||
props: { data: [], columns: configurableColumns, preferenceKey: 'orders-table', columnSettingsMode: 'show' },
|
||||
slots: { 'toolbar-actions': '<button class="create-action">新增快递公司</button>' },
|
||||
global: {
|
||||
provide: { [UI_PREFERENCE_SCOPE as symbol]: computed(() => 'user-1') },
|
||||
@@ -166,7 +166,7 @@ describe('DataTable column preferences', () => {
|
||||
|
||||
it('can hide column settings for compact tables without leaving an empty toolbar', () => {
|
||||
const wrapper = shallowMount(DataTable, {
|
||||
props: { data: [], columns: configurableColumns, preferenceKey: 'summary-table', showColumnSettings: false },
|
||||
props: { data: [], columns: configurableColumns, preferenceKey: 'summary-table', columnSettingsMode: 'hide' },
|
||||
global: {
|
||||
provide: { [UI_PREFERENCE_SCOPE as symbol]: computed(() => 'user-1') },
|
||||
stubs: { ElTable: TableStub, ElTableColumn: ColumnStub, ElButton: ButtonStub, ElPopover: PopoverStub },
|
||||
@@ -177,4 +177,53 @@ describe('DataTable column preferences', () => {
|
||||
expect(wrapper.find('button[aria-label="列设置"]').exists()).toBe(false)
|
||||
expect(wrapper.find('.data-table__toolbar').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('shows every column when column settings are hidden', () => {
|
||||
localStorage.setItem('cc:ui-layout:user-1:table:summary-table', JSON.stringify({
|
||||
version: 1,
|
||||
order: configurableColumns.map((column) => String(column.key)),
|
||||
hidden: ['status'],
|
||||
}))
|
||||
const wrapper = shallowMount(DataTable, {
|
||||
props: { data: [], columns: configurableColumns, preferenceKey: 'summary-table', columnSettingsMode: 'hide' },
|
||||
global: {
|
||||
provide: { [UI_PREFERENCE_SCOPE as symbol]: computed(() => 'user-1') },
|
||||
stubs: { ElTable: TableStub, ElTableColumn: ColumnStub, ElButton: ButtonStub, ElPopover: PopoverStub },
|
||||
directives: { loading: {} },
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.findAllComponents(ColumnStub)).toHaveLength(configurableColumns.length)
|
||||
})
|
||||
|
||||
it('hides column settings by default for four or fewer configurable business columns', () => {
|
||||
const wrapper = shallowMount(DataTable, {
|
||||
props: { data: [], columns: configurableColumns, preferenceKey: 'compact-table' },
|
||||
global: {
|
||||
provide: { [UI_PREFERENCE_SCOPE as symbol]: computed(() => 'user-1') },
|
||||
stubs: { ElTable: TableStub, ElTableColumn: ColumnStub, ElButton: ButtonStub, ElPopover: PopoverStub },
|
||||
directives: { loading: {} },
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.find('button[aria-label="列设置"]').exists()).toBe(false)
|
||||
expect(wrapper.find('.data-table__toolbar').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('keeps column settings by default for complex tables', () => {
|
||||
const complexColumns: DataTableColumn[] = [
|
||||
{ key: 'actions', label: '操作' },
|
||||
...Array.from({ length: 5 }, (_, index) => ({ key: `field-${index}`, label: `字段 ${index + 1}` })),
|
||||
]
|
||||
const wrapper = shallowMount(DataTable, {
|
||||
props: { data: [], columns: complexColumns, preferenceKey: 'complex-table' },
|
||||
global: {
|
||||
provide: { [UI_PREFERENCE_SCOPE as symbol]: computed(() => 'user-1') },
|
||||
stubs: { ElTable: TableStub, ElTableColumn: ColumnStub, ElButton: ButtonStub, ElPopover: PopoverStub },
|
||||
directives: { loading: {} },
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.find('button[aria-label="列设置"]').exists()).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -63,13 +63,13 @@ const props = withDefaults(defineProps<{
|
||||
total?: number
|
||||
pageSizes?: number[]
|
||||
preferenceKey?: string
|
||||
showColumnSettings?: boolean
|
||||
columnSettingsMode?: 'auto' | 'show' | 'hide'
|
||||
}>(), {
|
||||
loading: false,
|
||||
emptyText: '暂无数据',
|
||||
total: undefined,
|
||||
pageSizes: () => [10, 20, 50, 100],
|
||||
showColumnSettings: true,
|
||||
columnSettingsMode: 'auto',
|
||||
})
|
||||
|
||||
const page = defineModel<number>('page', { default: 1 })
|
||||
@@ -78,7 +78,6 @@ const slots = useSlots()
|
||||
const preferenceScope = inject(UI_PREFERENCE_SCOPE, computed(() => 'anonymous'))
|
||||
const preference = ref<LayoutPreferenceSnapshot>({ version: 1, order: [], hidden: [] })
|
||||
const tableRef = ref<{ doLayout: () => void }>()
|
||||
const preferenceEnabled = computed(() => Boolean(props.preferenceKey && props.showColumnSettings))
|
||||
|
||||
function columnId(column: DataTableColumn) {
|
||||
const value = column.key ?? column.columnKey ?? column.prop ?? column.property
|
||||
@@ -102,6 +101,12 @@ function columnHideable(column: DataTableColumn) {
|
||||
|
||||
const configurableColumns = computed(() => props.columns.filter((column) => columnId(column)))
|
||||
const columnKeys = computed(() => configurableColumns.value.map((column) => columnId(column) as string))
|
||||
const columnSettingsVisible = computed(() => (
|
||||
props.columnSettingsMode === 'auto'
|
||||
? configurableColumns.value.filter(columnHideable).length > 4
|
||||
: props.columnSettingsMode === 'show'
|
||||
))
|
||||
const preferenceEnabled = computed(() => Boolean(props.preferenceKey && columnSettingsVisible.value))
|
||||
|
||||
function anchorSystemColumns(order: readonly string[]) {
|
||||
const columnsByKey = new Map(configurableColumns.value.map((column) => [columnId(column) as string, column]))
|
||||
@@ -143,7 +148,7 @@ const orderedColumns = computed(() => {
|
||||
})
|
||||
const visibleColumns = computed(() => orderedColumns.value.filter((column) => {
|
||||
const id = columnId(column)
|
||||
return !id || !columnHideable(column) || !preference.value.hidden.includes(id)
|
||||
return !preferenceEnabled.value || !id || !columnHideable(column) || !preference.value.hidden.includes(id)
|
||||
}))
|
||||
const visibleHideableCount = computed(() => visibleColumns.value.filter(columnHideable).length)
|
||||
const preferenceItems = computed<LayoutPreferenceItem[]>(() => orderedColumns.value.flatMap((column) => {
|
||||
|
||||
Reference in New Issue
Block a user