import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import test from 'node:test' const source = readFileSync(new URL('./FirstLegOrdersView.vue', import.meta.url), 'utf8') const routerSource = readFileSync(new URL('../routes.ts', import.meta.url), 'utf8') const editorShellSource = readFileSync(new URL('../components/FirstLegOrderEditorShell.vue', import.meta.url), 'utf8') const progressSource = readFileSync(new URL('../components/OrderProgressPanel.vue', import.meta.url), 'utf8') test('routes the confirmed first-leg path to the implemented order view', () => { assert.match(routerSource, /path: 'orders\/first-leg'[\s\S]*?component: \(\) => import\('\.\/views\/FirstLegOrdersView\.vue'\)[\s\S]*?release: 'active'/) }) test('opens order creation as a dedicated protected page while keeping draft editing in a drawer', () => { assert.match(routerSource, /path: 'orders\/first-leg\/create'[\s\S]*?name: 'first-leg-order-create'[\s\S]*?release: 'active'[\s\S]*?permission: 'order:first-leg:create'/) assert.match(routerSource, /name: 'first-leg-order-create'[\s\S]*?props: \{ createPage: true \}/) assert.match(source, /router\.push\(\{ name: 'first-leg-order-create' \}\)/) assert.match(source, /defineProps<\{ createPage\?: boolean \}>/) assert.match(source, /const isCreatePage = computed\(\(\) => props\.createPage\)/) assert.match(source, /]*:page="isCreatePage"/) assert.match(editorShellSource, /
/) assert.match(editorShellSource, / { assert.match(source, /function openCreate\(\)/) assert.match(source, /async function saveDraft\(\)/) assert.match(source, /function submitOrder\(\)/) assert.match(source, /async function openDetail\(order: FirstLegOrder\)/) assert.match(source, /Promise\.allSettled\(\[/) assert.match(source, /const orderPageRequest = isCreatePage\.value\s*\? store\.loadWarehouseType\('DOMESTIC', true\)\s*:\s*store\.load\(\)/) assert.match(source, /Promise\.allSettled\(\[\s*orderPageRequest,\s*companyRequest/) assert.match(source, /tenantStore\.loadCompanyContext\(\)/) assert.match(source, /await store\.loadDetail\(order\.id\)/) assert.doesNotMatch(source, /cancelOrder|取消订单/) }) test('keeps create-page support errors scoped to create-page requests', () => { assert.match(source, /if \(!isCreatePage\.value && store\.draftLoadError\)/) }) test('blocks order submission before company approval while preserving draft actions', () => { assert.match(source, /companySubmissionBlocked/) assert.match(source, /companyAuditLoaded\.value = true/) assert.match(source, /企业资料待审核,当前仅可保存订单草稿/) assert.match(source, /暂时无法提交订单/) assert.match(source, /router\.push\('\/company\/profile'\)/) assert.match(source, /auth\.hasPermission\('order:first-leg:submit'\)/) }) test('defers approval checks to the server when the member cannot read the company profile', () => { assert.match(source, /const canViewCompanyProfile = computed/) assert.match(source, /const companySubmissionBlocked = computed\(\(\) => companyAuditLoaded\.value/) assert.match(source, /const knownCompanyAuditStatus = companyAuditLoaded\.value \? tenantStore\.company\.auditStatus : undefined/) assert.match(source, /store\.submit\([^\n]*knownCompanyAuditStatus\)/) }) test('renders dynamic cargo lines and responsive drawers', () => { assert.match(source, /v-for="\(item, index\) in form\.items"/) assert.match(source, /function addCargoItem\(\)/) assert.match(source, /function removeCargoItem\(index: number\)/) assert.match(source, /:global\(\.first-leg-editor\).*width: 100% !important/) assert.match(source, /class="mobile-order-list"/) assert.match(source, /\.desktop-order-table \{ display: none; \}/) }) test('keeps primary mobile order actions touch sized', () => { assert.match(source, /\.editor-actions :deep\(\.el-button\) \{ min-height: 44px;/) }) test('uses the shared query toolbar and data table without metric cards', () => { assert.match(source, /import QueryToolbar, \{ type QueryField, type QueryModel \}/) assert.match(source, /import DataTable, \{ type DataTableColumn \}/) assert.match(source, /const filters = ref/) assert.match(source, //) assert.match(source, /async function searchOrders\(model: QueryModel\)/) assert.match(source, /await store\.load\(\{/) assert.match(source, / { assert.match(source, /import OrderProgressPanel/) assert.match(source, //) assert.match(source, /

关键业务摘要<\/h3>/) assert.match(source, /progressSummaryItems/) assert.match(source, /summary\.preloadStatus/) assert.match(source, /summary\.expectedPickCount/) assert.match(source, /summary\.deliveryTrackingNo/) assert.match(progressSource, /FIRST_LEG_PROGRESS_STAGES/) assert.match(progressSource, /从订单提交到派送完成/) assert.match(progressSource, /item\.kind === 'CUSTOM_NODE'/) assert.match(progressSource, /业务节点/) assert.match(progressSource, /暂无进度记录/) assert.doesNotMatch(progressSource, /客户确认|差异处理中|派送中/) }) test('uses only fields present on C02 rows before loading full detail', () => { assert.match(source, /getOrderCargoSummary/) assert.match(source, /目的地 \/ 渠道/) assert.match(source, /运输方式待更新|渠道待更新/) assert.doesNotMatch(source, /key: 'operator'/) assert.doesNotMatch(source, /key: 'transportMode', type: 'select'/) assert.match(source, /store\.draftLoadError/) assert.match(source, /mainStatus: statusValue && statusValue !== 'DRAFT' \? statusValue : undefined/) assert.match(source, /draftOnly: statusValue === 'DRAFT'/) assert.match(source, /createdFrom: range\[0\] \? `\$\{range\[0\]\}T00:00:00`/) }) test('shows and searches the inbound code after a draft is submitted', () => { assert.match(source, /placeholder: '订单号、入仓码、渠道或仓库'/) assert.match(source, /order\.businessSummary\.inboundCode/) assert.match(source, /v-if="\(row as FirstLegOrder\)\.businessSummary\.inboundCode"[^>]*>入仓码/) assert.match(source, /v-if="order\.businessSummary\.inboundCode"[^>]*>入仓码/) assert.match(source, /v-if="detailOrder\.businessSummary\.inboundCode">
入仓码<\/dt>/) }) test('keeps the seven-stage progress and business summary usable on mobile', () => { assert.match(progressSource, /grid-template-columns: repeat\(7, 82px\)/) assert.match(progressSource, /overflow-x: auto/) assert.match(source, /\.fulfillment-summary \{ grid-template-columns: 1fr; \}/) }) test('keeps the first viewport compact and moves create into the table toolbar', () => { assert.match(source, /class="order-table-toolbar"/) assert.match(source, /订单列表<\/strong>共 \{\{ filteredOrders\.length \}\} 条<\/span>/) assert.match(source, /class="order-table-toolbar"[\s\S]*order:first-leg:create[\s\S]*创建订单[\s\S]*class="order-eligibility is-pending"/) assert.doesNotMatch(source, //) assert.match(source, /client-main:has\(> \.first-leg-page:not\(\.is-create-route\)\) > \.client-page-heading > div\) \{ position: absolute; width: 1px; height: 1px;/) }) test('keeps desktop query actions on the first row and only shows the qualification notice before approval', () => { assert.match(source, /\.first-leg-query-toolbar \{ flex-wrap: nowrap; \}/) assert.match(source, /query-toolbar__filters\) \{ display: grid; min-width: 0; flex: 1 1 auto;/) assert.match(source, /query-toolbar__actions\) \{ align-self: flex-start; flex-wrap: nowrap; margin-left: auto;/) assert.match(source, /v-if="companySubmissionBlocked && !supportingDataErrors\.some/) assert.doesNotMatch(source, /企业资料已审核,可正常提交订单/) assert.doesNotMatch(source, /order-eligibility\.is-approved/) }) test('does not let order-list loading block the create form', () => { assert.match(source, /v-loading="isCreatePage && supportingDataLoading"/) assert.match(source, /const pageDataLoading = computed\(\(\) => supportingDataLoading\.value \|\| \(!isCreatePage\.value && store\.loading\)\)/) }) test('does not expose arbitrary status mutation controls to customers', () => { assert.doesNotMatch(source, /setStatusForPreview/) assert.doesNotMatch(source, /状态更新|更新状态/) }) test('requires an enabled platform receiving warehouse in the order form', () => { assert.match(source, /store\.warehouses\.filter\(\(warehouse\) => warehouse\.warehouseType === 'DOMESTIC'\)/) assert.match(source, /availableWarehouses\.value\.length === 0/) assert.match(source, /label="国内收货仓"[^>]*required/) assert.match(source, /v-model="form\.receivingWarehouseId"/) assert.match(source, /selectedWarehouse\.businessHours/) assert.match(source, /class="selected-warehouse" aria-label="所选收货仓详情"/) assert.doesNotMatch(source, /class="selected-warehouse"[^>]*>[\s\S]*?\{\{ selectedWarehouse\.name \}\}<\/strong>/) assert.match(source, /first-leg-editor \.el-drawer__header\) \{[^}]*margin-bottom: 0;[^}]*border-bottom: 1px solid var\(--border\)/) assert.match(source, /first-leg-editor \.el-drawer__body\) \{[^}]*min-height: 0;[^}]*padding: 18px 22px 32px;[^}]*overscroll-behavior: contain/) assert.match(source, /first-leg-editor \.el-drawer__footer\) \{[^}]*border-top: 1px solid var\(--border\);[^}]*background: #fff/) assert.match(source, /detailOrder\.receivingWarehouseSnapshot\?\.name/) assert.match(source, /detailOrder\.receivingWarehouseSnapshot\.code/) assert.match(source, /loadSelectedWarehouse\(detailedOrder\.receivingWarehouseId\)/) }) test('selects platform destinations by type and caches private addresses per user', () => { assert.match(source, /warehouse\.warehouseType === form\.destinationType/) assert.match(source, /await store\.loadWarehouseType\(type\)/) assert.match(source, /await loadDestinationWarehouses\(form\.destinationType\)/) assert.match(source, /:loading="destinationWarehousesLoading"/) assert.match(source, /v-model="form\.destinationWarehouseId"/) assert.match(source, /form\.amazonWarehouseCode = form\.destinationType === 'FBA' \? warehouse\.code : ''/) assert.match(source, /cc:first-leg:private-addresses:\$\{auth\.user\?\.id/) assert.match(source, /localStorage\.setItem\(privateAddressStorageKey\(\)/) assert.match(source, /私人地址不能引用平台公共仓库|form\.destinationWarehouseId = ''/) }) test('lets the create-page instance own destination loading and exposes a recoverable error state', () => { assert.match(source, /await router\.push\(\{ name: 'first-leg-order-create' \}\)\s*\n\}/) assert.doesNotMatch(source, /await router\.push\(\{ name: 'first-leg-order-create' \}\)[\s\S]*?await loadDestinationWarehouses\(form\.destinationType\)/) assert.match(source, /if \(destinationResult\.status === 'rejected'\) supportingDataErrors\.value\.push\(`目的仓加载失败:\$\{errorMessage\(destinationResult\.reason\)\}`\)/) assert.match(source, /下单配套数据加载失败/) }) test('shows a loading state before the list can create an order', () => { assert.match(source, / { assert.match(source, /async function selectDestinationWarehouse\(id: string\)/) assert.match(source, /await store\.loadWarehouseDetail\(warehouse\.id\)/) assert.match(source, /availableWarehouses\.value\.length === 1/) assert.match(source, /availableDestinationWarehouses\.value\.length === 1/) assert.match(source, /function createPickupPartySnapshot\(\)/) assert.match(source, /contactName: tenantStore\.company\.contactName/) assert.match(source, /selectedDestinationWarehouse\.address/) }) test('collects the backend-required first-leg fields', () => { for (const model of ['destinationCountryCode', 'destinationWarehouseName', 'channelCode', 'pricingTaxMode', 'pickupMethod', 'taxMode', 'destinationType', 'packageType', 'upc']) { assert.match(source, new RegExp(`v-model="(?:form|item)\\.${model}"`)) } assert.match(source, /form\.channelName = channel\?\.channelName/) }) test('distills order creation into the confirmed prototype sections with server pricing', () => { assert.match(source, /

目的地信息<\/h3>/) assert.match(source, /

发货信息<\/h3>/) assert.match(source, /

货物明细<\/h3>/) assert.ok(source.indexOf('

发货信息

') < source.indexOf('

目的地信息

')) assert.ok(source.indexOf('

目的地信息

') < source.indexOf('

货物明细

')) assert.match(source, /class="segmented-options"/) assert.match(source, /class="prototype-form-row prototype-form-row--tabs"/) assert.match(source, /class="cargo-primary-grid"/) assert.match(source, /title="更多申报信息"/) assert.match(source, /参考运费/) assert.match(source, /仅供参考,最终以实际结算为准/) assert.doesNotMatch(source, /v-model="form\.(?:businessType|origin|destination|priority|tradeTerm)"/) }) test('loads only active server channels for the selected domestic warehouse', () => { assert.match(source, /getMerchantPricingChannels\(warehouseId\)/) assert.match(source, /const channelOptions = ref\(\[\]\)/) assert.match(source, /channelOptions\.value = \[\]/) assert.match(source, /form\.channelCode = ''/) assert.match(source, /sequence !== channelRequestSequence \|\| form\.receivingWarehouseId !== warehouseId/) assert.match(source, /channel\.pricingTaxModes\.includes\(form\.pricingTaxMode\)/) assert.match(source, /availablePricingTaxModes/) assert.match(source, /:loading="channelLoading"/) assert.match(source, /:disabled="!form\.receivingWarehouseId \|\| channelLoading"/) assert.match(source, /当前收货仓暂无可用渠道/) assert.match(source, /渠道加载失败/) assert.match(source, /@click="retryPricingChannels"/) assert.doesNotMatch(source, /SEA-US-GENERAL|SEA-US-SENSITIVE|SEA-US-EXPRESS|美线 FBA 直送/) assert.doesNotMatch(source, /channelOptions\.some\(\(channel\) => channel\.code/) }) test('estimates by warehouse, destination, tax mode, weight and volume without blocking saves', () => { assert.match(source, /estimateMerchantFirstLegPrice\(request\)/) assert.match(source, /originWarehouseId: form\.receivingWarehouseId/) assert.match(source, /destinationCode: form\.destinationType === 'FBA' \? form\.amazonWarehouseCode : undefined/) assert.match(source, /destinationWarehouseId: form\.destinationType === 'OVERSEAS'/) assert.match(source, /pricingTaxMode: form\.pricingTaxMode/) assert.match(source, /actualWeightKg: summary\.grossWeightKg/) assert.match(source, /actualVolumeCbm: summary\.volumeCbm/) assert.match(source, /setTimeout\(\(\) => void loadPriceEstimate\(\), 300\)/) assert.match(source, /sequence === estimateRequestSequence/) assert.match(source, /您仍可正常保存订单草稿/) assert.match(source, /v-for="mode in availablePricingTaxModes"/) assert.match(source, /pricingTaxModeLabel\(mode\)/) assert.doesNotMatch(source, /当前价格表不提供不包税报价|历史草稿的不包税设置/) const saveSource = source.slice(source.indexOf('async function saveDraft()'), source.indexOf('async function submitOrder()')) assert.doesNotMatch(saveSource, /loadPriceEstimate|priceEstimateError|estimateMerchantFirstLegPrice/) }) test('keeps the reference estimate readable on narrow screens', () => { assert.match(source, /\.price-estimate__result \{ grid-template-columns: 1fr; \}/) assert.match(source, /\.price-estimate__result > small \{ grid-column: auto; \}/) }) test('shows field-level validation and concise guidance for required order inputs', () => { assert.match(source, /ref="orderFormRef"[^>]*:model="form" :rules="orderFormRules"/) assert.match(source, /prop="shipperPartySnapshot\.contactName" required/) assert.match(source, /prop="consigneePartySnapshot\.address" required/) assert.match(source, /:prop="`items\.\$\{index\}\.cargoNameCn`" required/) assert.match(source, /:prop="`items\.\$\{index\}\.grossWeightKg`" required/) assert.match(source, /label="UPC".*required.*v-model="item\.upc"/) assert.match(source, /placeholder="例如:蓝牙音箱"/) assert.match(source, /\.order-form :deep\(\.el-form-item__error\).*position: static/) }) test('collects snapshots only for pickup and private destinations', () => { assert.doesNotMatch(source, /firstLegPartySource|v-model="form\.(?:shipper|consignee)PartyId"/) assert.match(source, /form\.pickupMethod === 'PICKUP'/) assert.match(source, /form\.destinationType === 'PRIVATE'/) assert.match(source, /form\.shipperPartySnapshot\.contactName/) assert.match(source, /form\.consigneePartySnapshot\.address/) assert.match(source, /syncPrivateDestinationName/) assert.match(source, /changePickupMethod/) }) test('shows fulfillment courier information as read-only client detail', () => { assert.match(source, /履约快递信息/) assert.match(source, /detailOrder\.expressCompanyName/) assert.match(source, /detailOrder\.trackingNumber/) assert.match(source, /客户端仅只读展示/) assert.doesNotMatch(source, /v-model="form\.expressCompanyName"/) assert.doesNotMatch(source, /v-model="form\.trackingNumber"/) }) test('shows the full customer-safe order detail without platform-only controls', () => { const detailSource = source.slice(source.indexOf('', source.indexOf('${heading}<\\/h3>`)) } for (const field of ['贸易条款', '发货方式', '报关方式', '运输渠道', '收货要求', '目的仓类型', '海关查验', '提交时间', '完成时间', 'SKU / UPC', 'HS 编码', '申报价值', '危险品']) { assert.match(source, new RegExp(field)) } assert.doesNotMatch(detailSource, /承运商|待平台指派/) assert.match(source, /detailOrder\.customerRemark/) assert.doesNotMatch(detailSource, /内部备注|审核通过|添加备注/) }) test('loads merchant inbound billing as an isolated read-only detail section', () => { assert.match(source, /import InboundBillingPanel/) assert.match(source, /import \{ getMerchantInboundBilling \}/) assert.match(source, /void loadInboundBilling\(order\)/) assert.match(source, / { const templateSource = source.slice(source.indexOf('')) assert.doesNotMatch(templateSource, /租户|tenantId|所属企业|企业筛选/) }) test('discards stale inbound billing responses when the drawer closes or the user changes orders', () => { assert.match(source, /let inboundBillingRequestSequence = 0/) assert.match(source, /const sequence = \+\+inboundBillingRequestSequence/) assert.match(source, /sequence === inboundBillingRequestSequence[\s\S]*detailOpen\.value[\s\S]*detailId\.value === orderId/) assert.match(source, /watch\(detailOpen,[\s\S]*resetInboundBillingState\(\)/) }) test('protects unsaved drafts and exposes recoverable load failures', () => { assert.match(source, /useUnsavedWorkRegistration\(/) assert.match(source, /routeKey: unsavedRouteKey/) assert.doesNotMatch(source, /onBeforeRouteLeave|beforeunload/) assert.match(source, /confirmDiscardChanges/) assert.match(source, /:before-close="requestCloseEditor"/) assert.match(source, /store\.loadError/) assert.match(source, /订单数据加载失败/) assert.match(source, /订单详情加载失败/) assert.match(source, /部分订单配套数据加载失败/) assert.doesNotMatch(source, /往来单位加载失败/) assert.match(source, /企业资料加载失败/) assert.match(source, /@click="loadPageData"/) assert.match(source, /@click="retryDetail"/) }) test('copies reactive order drafts into plain request data', () => { assert.match(source, /function cloneDraft\(draft: FirstLegOrderDraft\)/) assert.match(source, /items: draft\.items\.map\(\(item\) => \(\{ \.\.\.item \}\)\)/) assert.match(source, /store\.saveDraft\(cloneDraft\(form\)/) assert.match(source, /store\.submit\(cloneDraft\(form\)/) assert.doesNotMatch(source, /structuredClone\((?:form|order\.)/) }) test('loads complete order detail before editing and rejects an unavailable historical warehouse', () => { assert.match(source, /async function openEdit\(order: FirstLegOrder\)/) assert.match(source, /const detailedOrder = await store\.loadDetail\(order\.id\)/) assert.match(source, /draftFromOrder\(detailedOrder\)/) assert.match(source, /draft\.receivingWarehouseId = ''/) assert.match(source, /draft\.channelCode = ''/) assert.match(source, /原平台收货仓当前不可用,请重新选择可用收货仓/) assert.match(source, /原目的仓当前不可用,请重新选择平台维护的目的仓/) })