98 lines
6.8 KiB
TypeScript
98 lines
6.8 KiB
TypeScript
import { readFileSync } from 'node:fs'
|
|
import { resolve } from 'node:path'
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
const page = (name: string) => readFileSync(resolve(process.cwd(), 'src/modules/overseas-warehouse/pages', name), 'utf8')
|
|
const component = (name: string) => readFileSync(resolve(process.cwd(), 'src/modules/overseas-warehouse/components', name), 'utf8')
|
|
|
|
describe('overseas warehouse 1920px layout acceptance', () => {
|
|
it('keeps action columns first and wide enough for every visible action', () => {
|
|
const widths: Record<string, number> = {
|
|
'LastMileOrdersView.vue': 330,
|
|
'InboundOrdersView.vue': 300,
|
|
'DispatchesView.vue': 380,
|
|
'OutboundsView.vue': 180,
|
|
'DeliveryOrdersView.vue': 300,
|
|
'RelabelOrdersView.vue': 180,
|
|
'PalletsView.vue': 180,
|
|
'InventoryView.vue': 110,
|
|
}
|
|
for (const [name, width] of Object.entries(widths)) {
|
|
const source = page(name)
|
|
const columns = source.slice(source.indexOf('const columns'), source.indexOf('async function', source.indexOf('const columns')))
|
|
expect(columns).toMatch(new RegExp(`key: 'actions',[\\s\\S]*?label: '操作',[\\s\\S]*?width: ${width},[\\s\\S]*?fixed: 'left'`))
|
|
expect(columns.indexOf("key: 'actions'")).toBeLessThan(columns.indexOf("label:", columns.indexOf("key: 'actions'") + 20))
|
|
}
|
|
})
|
|
|
|
it('keeps all inbound-order row actions on one line', () => {
|
|
const source = page('InboundOrdersView.vue')
|
|
expect(source).toContain('<template #actions="{ row }"><div class="row-actions density-actions">')
|
|
expect(source).toContain('.row-actions { min-width: max-content; flex-wrap: nowrap; white-space: nowrap; }')
|
|
expect(source).toContain('.row-actions :deep(.el-button) { flex: 0 0 auto; }')
|
|
expect(readFileSync(resolve(process.cwd(), 'src/styles/adminDensity.css'), 'utf8')).toContain('.density-actions > :is(.el-button, .el-dropdown) { margin-left: 0; }')
|
|
})
|
|
|
|
it('assigns explicit desktop widths to dense query inputs', () => {
|
|
for (const name of ['LastMileOrdersView.vue', 'InboundOrdersView.vue', 'OutboundsView.vue', 'DeliveryOrdersView.vue', 'RelabelOrdersView.vue', 'PalletsView.vue', 'InventoryView.vue']) {
|
|
const source = page(name)
|
|
const fieldLines = source.split(/\r?\n/).filter((line) => /type: '(input|select|daterange)'/.test(line))
|
|
expect(fieldLines.length, name).toBeGreaterThan(0)
|
|
expect(fieldLines.every((line) => line.includes('width:')), `${name} has a query field without width`).toBe(true)
|
|
}
|
|
})
|
|
|
|
it('provides semantic placeholders for editable form controls', () => {
|
|
for (const name of ['LastMileOrdersView.vue', 'InboundOrdersView.vue', 'OutboundsView.vue', 'DeliveryOrdersView.vue', 'RelabelOrdersView.vue', 'PalletsView.vue', 'InventoryView.vue']) {
|
|
const editableControls = [...page(name).matchAll(/<el-(?:input-number|date-picker|input|select)[ >][^>]*>/g)]
|
|
.map(([tag]) => tag)
|
|
.filter((tag) => !/\s(?:readonly|disabled)(?:\s|\/?>)/.test(tag))
|
|
.filter((tag) => !tag.includes('v-model="planEditForm.warehouseId"'))
|
|
expect(editableControls.every((tag) => tag.includes('placeholder=')), `${name} has an editable control without placeholder`).toBe(true)
|
|
}
|
|
})
|
|
|
|
it('uses four-field desktop density and full-width form controls', () => {
|
|
const sharedDetail = component('OverseasReadOnlyDetail.vue')
|
|
expect(sharedDetail).toContain('grid-template-columns: repeat(2, minmax(0, 1fr))')
|
|
expect(page('LastMileOrderDetailView.vue')).toContain('density-fields')
|
|
expect(page('InboundOrderDetailView.vue')).toContain('density-fields')
|
|
expect(page('DispatchDetailView.vue')).toContain('.document-section { grid-column: 1 / -1; }')
|
|
expect(page('DispatchDetailView.vue')).toContain('density-fields')
|
|
expect(page('DeliveryOrderDetailView.vue')).toContain('density-fields')
|
|
expect(page('InventoryDetailView.vue')).toContain('density-fields')
|
|
expect(page('InventoryDetailView.vue').match(/class="inventory-table-wrap"/g)).toHaveLength(3)
|
|
expect(page('InventoryDetailView.vue')).toContain('.inventory-table-wrap { padding:0 var(--admin-space-5) var(--admin-space-4); }')
|
|
const outbounds = page('OutboundsView.vue')
|
|
expect(outbounds).toContain('.create-outbound-form :deep(.el-form-item__content > .el-input-number) { width: 100%; }')
|
|
expect(outbounds).not.toContain('.create-outbound-form :deep(.el-select)')
|
|
expect(outbounds).toContain('.candidate-pagination :deep(.el-pagination__sizes .el-select), .return-pagination :deep(.el-pagination__sizes .el-select) { width: 128px; }')
|
|
expect(page('RelabelOrdersView.vue')).toContain('.el-form :deep(.el-date-editor) { width: 100%; }')
|
|
expect(page('PalletsView.vue')).toContain('.el-form :deep(.el-input-number) { width: 100%; }')
|
|
expect(page('RelabelOrdersView.vue')).toContain('.el-form :deep(.el-row) { margin-left: 0 !important; margin-right: 0 !important; }')
|
|
expect(page('PalletsView.vue')).toContain('.el-form :deep(.el-row) { margin-left: 0 !important; margin-right: 0 !important; }')
|
|
const lastMileDetail = page('LastMileOrderDetailView.vue')
|
|
expect(lastMileDetail).toContain('class="fee-form-grid"')
|
|
expect(lastMileDetail).toContain('filterable allow-create clearable default-first-option')
|
|
expect(lastMileDetail).toContain('.fee-form { min-width: 0; overflow-x: hidden; }')
|
|
expect(lastMileDetail).toContain('.fee-form :deep(.el-select), .fee-form :deep(.el-input-number) { width: 100%; }')
|
|
expect(lastMileDetail).toContain("field.label === '入仓码' || field.label === '集装箱号'")
|
|
expect(lastMileDetail).toContain(':title="isSingleLineBusinessField(field) ? String(field.value) : undefined"')
|
|
expect(lastMileDetail).toContain('.detail-field-value--business { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }')
|
|
})
|
|
|
|
it('keeps the inbound detail compact and puts pallet facts before appointment metadata', () => {
|
|
const inbound = page('InboundOrderDetailView.vue')
|
|
expect(inbound).toContain('grid-template-columns: repeat(5, minmax(0, 1fr))')
|
|
expect(inbound).toContain('class="section-heading"')
|
|
expect(inbound).toContain('.detail-section { min-width: 0; padding: 0;')
|
|
expect(inbound).toContain(':deep(.density-detail-header) { border-bottom: 1px solid var(--cc-border); }')
|
|
expect(inbound).toContain('.appointment-fields { grid-template-columns:repeat(4,minmax(0,1fr)); }')
|
|
expect(inbound).toContain('class="compact-section-heading"')
|
|
expect(inbound.match(/class="detail-table-wrap"/g)).toHaveLength(2)
|
|
expect(inbound).toContain('.detail-table-wrap { padding:var(--admin-space-3) var(--admin-space-5) var(--admin-space-4); }')
|
|
expect(inbound.indexOf('class="detail-section pallet-section"')).toBeLessThan(inbound.indexOf('class="detail-section appointment-section"'))
|
|
expect(inbound).not.toContain("fields: ['状态', '预约状态'")
|
|
})
|
|
})
|