This commit is contained in:
2026-10-19 17:56:31 +08:00
parent 5a46198bf0
commit 5c28cd7c79
84 changed files with 3356 additions and 3630 deletions
+12
View File
@@ -0,0 +1,12 @@
# 费用项目默认价格核对
本轮依据:2026-10-19 用户确认“固定价格,使用的地方也能修改,只是带入”。原型入口为 `docs/悦/货代SAAS平台后台/prototype-src/modules/10-general.html:8-12` 的 `page-gen-fee`、`tbody-gen-fee`;原型没有默认价格字段及该页新增/编辑表单定义,新增字段按本轮确认实现。
| 页面 | 操作 | 原型承载/布局 | 当前实现及本轮结论 |
|---|---|---|---|
| 费用项目 | 列表 | 页面内表格,原型无价格列 | 沿用列表,增加默认价格列,空值显示“—” |
| 费用项目 | 新增、编辑 | 原型未定义表单尺寸与承载方式 | 沿用现有 620px 抽屉与表单,增加可空默认价格及说明 |
| 入库费用 | 新增、编辑、调整时选费 | 本轮仅变更选费带值逻辑 | 沿用现有表单;主动选择时带入单价和金额,支持人工覆盖,回显保留原值 |
| 柜次费用 | 新增时选费 | 本轮仅变更选费带值逻辑 | 沿用现有表单;主动选择时带入金额,支持人工覆盖,调整回显保留原值 |
详情、审核、文件预览、删除和停用操作无变更。自动检查与视觉验收分开;1920×1080、100% 缩放待人工截图确认。
@@ -19,6 +19,7 @@ const payload: SavePlatformFeeItemRequest = {
category: '仓储成本',
tradeScope: 'INTERNATIONAL',
feeTypeName: '仓库租赁费',
defaultPrice: 60,
supplierCategory: 'TRUCKING',
pickupPayable: false,
pickupReceivable: false,
@@ -11,6 +11,7 @@ export interface PlatformFeeItemResource {
feeCode: string | null
supplierCategory: SupplierCategory | null
feeTypeName: string
defaultPrice: number | null
pickupPayable: boolean
pickupReceivable: boolean
warehousePayable: boolean
@@ -28,6 +29,7 @@ export interface SavePlatformFeeItemRequest {
category: string
tradeScope: FeeItemTradeScope
feeTypeName: string
defaultPrice: number | null
supplierCategory: SupplierCategory | null
pickupPayable: boolean
pickupReceivable: boolean
@@ -6,7 +6,7 @@ import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils'
import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { useAccessPreviewStore } from '@/core/access/accessPreview'
import { useAuthStore } from '@/core/auth/auth'
import { listPlatformFeeItems } from '@/modules/fee-items/api/platformFeeItems'
import { createPlatformFeeItem, listPlatformFeeItems, updatePlatformFeeItem } from '@/modules/fee-items/api/platformFeeItems'
import FeeItemsView from './FeeItemsView.vue'
const source = readFileSync(join(process.cwd(), 'src/modules/fee-items/pages/FeeItemsView.vue'), 'utf8').replace(/\r\n/g, '\n')
@@ -54,6 +54,26 @@ enableAutoUnmount(afterEach)
afterAll(() => vi.unstubAllGlobals())
describe('FeeItemsView public master data and access', () => {
it('saves configured and zero prices and clears the default on edit', async () => {
const wrapper = await mountView(['firstleg:fee-item:view', 'firstleg:fee-item:create', 'firstleg:fee-item:edit'])
const state = (wrapper.vm.$ as unknown as { setupState: {
openCreate(): void; saveFeeItem(): Promise<void>
form: { id: string; category: string; feeTypeName: string; defaultPrice: number | null }
} }).setupState
state.openCreate(); await flushPromises()
Object.assign(state.form, { category: '操作费', feeTypeName: '加封费', defaultPrice: 60 })
await state.saveFeeItem(); await flushPromises()
expect(createPlatformFeeItem).toHaveBeenLastCalledWith(expect.objectContaining({ defaultPrice: 60 }))
state.openCreate(); await flushPromises()
Object.assign(state.form, { category: '操作费', feeTypeName: '零元费', defaultPrice: 0 })
await state.saveFeeItem(); await flushPromises()
expect(createPlatformFeeItem).toHaveBeenLastCalledWith(expect.objectContaining({ defaultPrice: 0 }))
state.openCreate(); await flushPromises()
Object.assign(state.form, { id: '1', category: '操作费', feeTypeName: '加封费', defaultPrice: null })
await state.saveFeeItem(); await flushPromises()
expect(updatePlatformFeeItem).toHaveBeenCalledWith('1', expect.objectContaining({ defaultPrice: null }))
})
beforeEach(() => {
vi.stubGlobal('ResizeObserver', ResizeObserverStub)
vi.stubGlobal('localStorage', createMemoryStorage())
@@ -71,6 +71,7 @@ function emptyForm(): FeeItemForm {
category: '',
tradeScope: 'DOMESTIC',
feeTypeName: '',
defaultPrice: null,
supplierCategory: null,
pickupPayable: false,
pickupReceivable: false,
@@ -86,6 +87,7 @@ const rules: FormRules<FeeItemForm> = {
category: [{ required: true, message: '请输入费用分类', trigger: 'blur' }],
tradeScope: [{ required: true, message: '请选择贸易范围', trigger: 'change' }],
feeTypeName: [{ required: true, message: '请输入费用名称', trigger: 'blur' }],
defaultPrice: [{ type: 'number', min: 0, max: 9999999999.99, message: '默认价格须为非负金额,最多两位小数', trigger: 'change' }],
}
const hasPayableDirection = computed(() => form.pickupPayable || form.warehousePayable)
@@ -118,6 +120,7 @@ const columns: DataTableColumn[] = [
{ key: 'actions', label: '操作', width: 250, fixed: 'left', slotName: 'actions' },
{ key: 'feeTypeName', label: '费用项目', minWidth: 210, slotName: 'feeItem' },
{ key: 'category', prop: 'category', label: '费用分类', minWidth: 150 },
{ key: 'defaultPrice', label: '默认价格(CNY)', width: 150, formatter: (row: PlatformFeeItemResource) => row.defaultPrice == null ? '—' : Number(row.defaultPrice).toFixed(2) },
{ key: 'tradeScope', label: '贸易范围', width: 110, slotName: 'tradeScope' },
{ key: 'pickup', label: '提货', minWidth: 160, slotName: 'pickup' },
{ key: 'warehouse', label: '仓库', minWidth: 160, slotName: 'warehouse' },
@@ -203,6 +206,7 @@ function assignForm(item: PlatformFeeItemResource) {
category: item.category,
tradeScope: item.tradeScope,
feeTypeName: item.feeTypeName,
defaultPrice: item.defaultPrice,
supplierCategory: item.supplierCategory,
pickupPayable: item.pickupPayable,
pickupReceivable: item.pickupReceivable,
@@ -236,6 +240,7 @@ function buildPayload(): SavePlatformFeeItemRequest {
category: form.category.trim(),
tradeScope: form.tradeScope,
feeTypeName: form.feeTypeName.trim(),
defaultPrice: form.defaultPrice ?? null,
supplierCategory: hasPayableDirection.value ? form.supplierCategory : null,
pickupPayable: form.pickupPayable,
pickupReceivable: form.pickupReceivable,
@@ -440,6 +445,10 @@ onMounted(() => {
<el-form-item label="贸易范围" prop="tradeScope" required>
<el-segmented v-model="form.tradeScope" :options="[{ label: '国内', value: 'DOMESTIC' }, { label: '国际', value: 'INTERNATIONAL' }]" />
</el-form-item>
<el-form-item label="默认价格(CNY)" prop="defaultPrice">
<el-input-number v-model="form.defaultPrice" :min="0" :max="9999999999.99" :precision="2" controls-position="right" placeholder="不填则由使用时手工录入" />
</el-form-item>
<p class="muted-value">选择费用项目时自动带入,使用时仍可修改;清空表示不设置默认价格。</p>
</FormSection>
<FormSection class="density-form-section" title="费用方向" description="选择费用在提货和仓库环节的应收、应付属性。">
<div class="direction-grid">