This commit is contained in:
2026-08-07 14:47:11 +08:00
parent e7cc0cf18b
commit 7ac173fac4
21 changed files with 1714 additions and 791 deletions
@@ -5,102 +5,81 @@ import { describe, expect, it } from 'vitest'
const source = readFileSync(join(process.cwd(), 'src/modules/fba-pricing/carrier-rates/pages/CarrierRatesView.vue'), 'utf8')
const queryToolbarSource = readFileSync(join(process.cwd(), 'src/shared/components/QueryToolbar.vue'), 'utf8')
describe('CarrierRatesView source contract', () => {
it('keeps operation column first and covers every required business field', () => {
const scopeColumn = "key: 'scope', label: '适用范围'"
const destinationColumn = "key: 'destinationCode', prop: 'destinationCode'"
expect(source.indexOf("key: 'actions'")).toBeLessThan(source.indexOf(scopeColumn))
expect(source.indexOf(scopeColumn)).toBeLessThan(source.indexOf(destinationColumn))
expect(source.indexOf(destinationColumn)).toBeLessThan(source.indexOf("key: 'rate'"))
for (const label of ['起运仓', '业务类型', '渠道编码', '船司', 'FBA 目的仓', '计费单位', '单价', '币种', '固定附加费', '有效期', '备注', '生效时间', '结束时间']) {
describe('CarrierRatesView price-book source contract', () => {
it('keeps the operation column first and presents version-level history', () => {
expect(source.indexOf("key: 'actions'")).toBeLessThan(source.indexOf("key: 'version'"))
for (const label of ['价格表版本', '原始文件', '解析结果', '校验结果', '上传时间', '实际生效区间']) {
expect(source).toContain(label)
}
expect(source).toContain("placeholder: 'FBA 目的仓编码'")
expect(source).toContain("placeholder: '渠道编码'")
expect(source).toContain('formatEffectivePeriod')
expect(source).toContain('PENDING_CONFIRMATION')
expect(source).toContain('SUPERSEDED')
})
it('implements immutable version actions with exact backend permissions', () => {
expect(source).toContain("firstleg:fba-pricing:rate:edit")
expect(source).toContain('创建版本')
expect(source).toContain('新版本')
expect(source).toContain('停用')
expect(source).not.toContain('编辑价格')
it('uses only the parsed price-book workflow instead of legacy carrier-rate editing', () => {
for (const capability of [
'listPlatformPriceBooks',
'getPlatformPriceBook',
'uploadPlatformPriceBook',
'publishPlatformPriceBook',
'downloadPlatformPriceBookSource',
]) expect(source).toContain(capability)
for (const legacyCapability of [
'createPlatformCarrierRateVersion',
'listPlatformCarrierRates',
'retirePlatformCarrierRate',
'新增价格版本',
'编辑价格',
'有效期',
'生效日期',
]) expect(source).not.toContain(legacyCapability)
})
it('treats carrier rates as platform-wide data without a customer selector', () => {
expect(source).toContain("key: 'scope', label: '适用范围'")
expect(source).toContain('全部客户')
expect(source).not.toContain("key: 'customerId'")
expect(source).not.toContain('listPlatformTenants')
expect(source).not.toContain('PlatformTenantSelector')
expect(source).not.toContain('selectedTenantId')
expect(source).not.toContain('租户')
it('keeps uploaded prices immutable and makes confirmation the only edit action', () => {
expect(source).toContain('上传并解析')
expect(source).toContain('查看并确认')
expect(source).toContain('确认并立即生效')
expect(source).toContain('价格行不可在页面内修改')
expect(source).toContain('confirmPriceBook')
expect(source).toContain('publishPlatformPriceBook')
expect(source).not.toContain('草稿')
})
it('uses semantic compact filter widths without a customer field', () => {
for (const field of [
"key: 'rateCode', type: 'input', width: 220",
"key: 'destinationCode', type: 'input', width: 220",
"key: 'channelCode', type: 'input', width: 220",
"key: 'chargeUnit', type: 'select', width: 180",
"key: 'status', type: 'select', width: 160",
]) expect(source).toContain(field)
expect(source).not.toContain(':search-on-reset="false"')
expect(source).not.toContain('请选择所属企业并查询价格数据')
expect(source).not.toContain('customers.value[0]')
it('maps only active platform public domestic and overseas warehouses before confirmation', () => {
expect(source).toContain('listAllPlatformWarehouses()')
expect(source).toContain("warehouse.warehouseType === 'DOMESTIC'")
expect(source).toContain("warehouse.warehouseType === 'OVERSEAS'")
expect(source).toContain('起运仓映射')
expect(source).toContain('海外仓映射')
expect(source).toContain('originWarehouseCode')
expect(source).toContain('sourceDestinationName')
expect(source).not.toContain('tenantId')
expect(source).not.toContain('客户选择')
})
it('loads the platform-wide list and keeps row actions independent of customer scope', () => {
expect(source).toContain('void loadRateData()')
expect(source).toContain('listPlatformCarrierRates({ rateCode: filters.value.rateCode })')
expect(source).toContain('getPlatformCarrierRate(row.id)')
expect(source).toContain('retirePlatformCarrierRate(row.id)')
expect(source).toContain('<dt>适用范围</dt><dd>全部客户</dd>')
it('shows parsing blockers and a channel-tabbed, read-only preview', () => {
expect(source).toContain('nonMappingBlockingIssues')
expect(source).toContain('解析与校验')
expect(source).toContain('按渠道预览')
expect(source).toContain('<el-tabs v-model="selectedChannelCode"')
expect(source).toContain('sourceLocation')
expect(source).toContain('pricingTaxModeLabel')
})
it('loads shared carrier master data under the platform public scope', () => {
expect(source).toContain('listPlatformPartners({ page: 1, size: 200, type: \'CARRIER\', status: \'ACTIVE\' })')
expect(source).toContain('平台仓库或船司资料加载失败')
expect(source).not.toContain('listPlatformPartners(customerId,')
expect(source).not.toContain('所属企业的仓库或船司资料加载失败')
expect(source).toContain('async function loadPlatformMasterData()')
expect(source).not.toContain('loadCustomerMasterData')
it('accepts only xlsx uploads and retains original-file download', () => {
expect(source).toContain('accept=".xlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"')
expect(source).toContain("endsWith('.xlsx')")
expect(source).toContain('10 * 1024 * 1024')
expect(source).toContain('downloadSource')
expect(source).toContain('saveBlob')
})
it('keeps public rate queries independent from edit-only master data', () => {
expect(source).toContain('await loadRateData()')
expect(source).not.toContain('loadPlatformMasterData(customerId)')
})
it('inherits QueryToolbar wrapping and full-width mobile controls', () => {
expect(queryToolbarSource).toContain('flex-wrap: wrap')
expect(queryToolbarSource).toContain('@media (max-width: 720px)')
expect(queryToolbarSource).toContain('width: 100%')
expect(source).not.toContain('--query-field-width')
})
it('guards unsaved work, failures and narrow screens', () => {
expect(source).toContain('useUnsavedWorkRegistration')
it('uses the shared query and table primitives with mobile layout handling', () => {
expect(source).toContain("import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'")
expect(source).toContain("import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'")
expect(source).toContain('LoadErrorState')
expect(source).toContain('ApiErrorMeta')
expect(queryToolbarSource).toContain('flex-wrap: wrap')
expect(source).toContain('@media (max-width: 720px)')
})
it('reuses the first-leg order list primitives for status, empty state and pagination', () => {
expect(source).toContain("import StatusBadge from '@/shared/components/StatusBadge.vue'")
expect(source).toContain('<StatusBadge :status="statusLabel(')
expect(source).toContain('<template #empty><el-empty')
expect(source).toContain('<div class="business-page">')
expect(source).not.toContain('<QueryToolbar v-model="filters" class="surface-panel"')
expect(source).not.toContain('<template #pagination-left>')
expect(source).not.toContain('<el-tag')
})
it('does not create route or navigation ownership in the page task', () => {
expect(source).not.toContain('createRouter')
expect(source).not.toContain('adminNavigation')
for (const unsupportedCapability of ['导入', '导出', '全部船期', '参考时效', '最晚进仓时间']) {
expect(source).not.toContain(unsupportedCapability)
}
})
})