refactor: remove dropship printing from PDA

This commit is contained in:
2026-09-14 17:52:00 +08:00
parent 9933b96189
commit f8f21b9f37
6 changed files with 11 additions and 76 deletions
+1 -1
View File
@@ -58,7 +58,7 @@
| 登录与会话 | `pages/login/`、`stores/session.js` | 远程鉴权适配和会话清理 | | 登录与会话 | `pages/login/`、`stores/session.js` | 远程鉴权适配和会话清理 |
| 工作台、仓库选择与模块入口 | `pages/home/`、`components/PortalHeader.vue`、`stores/session.js`、`pages/module/`、`pages/operation/` | 左上角只提供启用国内仓选择,选择结果持久化;`data/demo-data.js` 的 `visible` 控制展示、`available` 控制可操作;隐藏能力不得删除源码或路由 | | 工作台、仓库选择与模块入口 | `pages/home/`、`components/PortalHeader.vue`、`stores/session.js`、`pages/module/`、`pages/operation/` | 左上角只提供启用国内仓选择,选择结果持久化;`data/demo-data.js` 的 `visible` 控制展示、`available` 控制可操作;隐藏能力不得删除源码或路由 |
| 待处理任务、服务端就绪与领取 | `pages/tasks/tasks.vue` | `api/pda-loading.js` 的 `listLoadingOrders`、`getContainerPickingTask`、`claimContainerPickingTask`;合并任务和缺少柜号/仓库/版本的任务不可进入 | | 待处理任务、服务端就绪与领取 | `pages/tasks/tasks.vue` | `api/pda-loading.js` 的 `listLoadingOrders`、`getContainerPickingTask`、`claimContainerPickingTask`;合并任务和缺少柜号/仓库/版本的任务不可进入 |
| 一件代发 | `pages/dropship-tasks/dropship-tasks.vue`、`pages/dropship-palletization/dropship-palletization.vue` | `api/pda-dropship.js`;作为入库作业,测量审核按预计托数预生成 DP 托盘码,PDA 不展开全部托盘卡片,直接扫码并只展示当前操作托盘;全部预生成托盘码合并为每托一页的多页 A4 PDF,含 SKU 明细但不直接驱动打印机;PDA 明确执行逐箱清点并支持先扫箱或先扫托、归托、换托/移回待绑托和逐托封托;同一国内作业仓的多票可继续装入同一开放托盘,单票全部归托不等于托盘装满,实物装满后才封托;预计托数与已生成托盘数不一致时失败关闭;公网前缀 `/api/platform/v1/first-leg/pda-dropship/**` | | 一件代发 | `pages/dropship-tasks/dropship-tasks.vue`、`pages/dropship-palletization/dropship-palletization.vue` | `api/pda-dropship.js`;作为入库作业,测量审核按预计托数预生成 DP 托盘码,由 Admin 电脑端合并打印后贴到空托盘;PDA 不承载打印,只直接扫码并展示当前操作托盘;PDA 明确执行逐箱清点并支持先扫箱或先扫托、归托、换托/移回待绑托和逐托封托;同一国内作业仓的多票可继续装入同一开放托盘,单票全部归托不等于托盘装满,实物装满后才封托;预计托数与已生成托盘数不一致时失败关闭;公网前缀 `/api/platform/v1/first-leg/pda-dropship/**` |
| 业务编号展示与错误脱敏 | `utils/user-facing.js`、`tests/user-facing-identifiers.test.mjs` | 任务和作业页优先显示真实集装箱号,缺失时显示柜次号,再缺失显示“集装箱号 —”;不得展示 taskId、inboundId、orderId、loadingPlanId、containerBookingId 或长整型内部 ID,错误仍保留 code、requestId、traceId | | 业务编号展示与错误脱敏 | `utils/user-facing.js`、`tests/user-facing-identifiers.test.mjs` | 任务和作业页优先显示真实集装箱号,缺失时显示柜次号,再缺失显示“集装箱号 —”;不得展示 taskId、inboundId、orderId、loadingPlanId、containerBookingId 或长整型内部 ID,错误仍保留 code、requestId、traceId |
| 拣货任务与箱码扫码 | `pages/picking/`、`stores/picking.js` | `api/pda-loading.js`、`utils/scan-broadcast.js`、`components/ScanTargetInput.vue`;服务端契约见 `../../baiyue-firstleg/firstleg/src/main/resources/openapi/phase3-pda-convergence-v1.yaml` | | 拣货任务与箱码扫码 | `pages/picking/`、`stores/picking.js` | `api/pda-loading.js`、`utils/scan-broadcast.js`、`components/ScanTargetInput.vue`;服务端契约见 `../../baiyue-firstleg/firstleg/src/main/resources/openapi/phase3-pda-convergence-v1.yaml` |
| 一件代发清点组托状态与草稿 | `pages/dropship-palletization/dropship-palletization.vue` | `stores/dropship-palletizing.js`、`utils/dropship-palletizing-state.js`;服务端契约见 `../../baiyue-firstleg/firstleg/src/main/resources/openapi/dropship-palletization-v1.yaml`,合同 `tests/dropship-palletizing-*.test.mjs` | | 一件代发清点组托状态与草稿 | `pages/dropship-palletization/dropship-palletization.vue` | `stores/dropship-palletizing.js`、`utils/dropship-palletizing-state.js`;服务端契约见 `../../baiyue-firstleg/firstleg/src/main/resources/openapi/dropship-palletization-v1.yaml`,合同 `tests/dropship-palletizing-*.test.mjs` |
+1 -26
View File
@@ -1,4 +1,4 @@
import { apiDownload, apiRequest } from '@/api/http.js' import { apiRequest } from '@/api/http.js'
import { stableOperationId } from '@/utils/idempotency.js' import { stableOperationId } from '@/utils/idempotency.js'
import { session } from '@/stores/session.js' import { session } from '@/stores/session.js'
@@ -44,31 +44,6 @@ export function sealDropshipPallet(taskId, warehouseId, pallet) {
return apiRequest({ url: `${ROOT}/tasks/${encodeURIComponent(taskId)}/pallets/${encodeURIComponent(pallet.palletId)}/seal`, method: 'POST', data: { warehouseId: stableId(warehouseId), expectedVersion: pallet.version, operationId: operationId('seal', taskId, { warehouseId, palletId: pallet.palletId, version: pallet.version }) } }) return apiRequest({ url: `${ROOT}/tasks/${encodeURIComponent(taskId)}/pallets/${encodeURIComponent(pallet.palletId)}/seal`, method: 'POST', data: { warehouseId: stableId(warehouseId), expectedVersion: pallet.version, operationId: operationId('seal', taskId, { warehouseId, palletId: pallet.palletId, version: pallet.version }) } })
} }
export function downloadDropshipPalletLabel(taskId, warehouseId, palletId) {
const baseUrl = String(session.apiBase || '/api/platform/v1').replace(/\/$/, '')
const url = `${baseUrl}${ROOT}/tasks/${encodeURIComponent(taskId)}/pallets/${encodeURIComponent(palletId)}/print?warehouseId=${encodeURIComponent(stableId(warehouseId))}`
return apiDownload({ url }).then((response) => {
const contentType = response.header?.['Content-Type'] || response.header?.['content-type'] || ''
if (response.statusCode < 200 || response.statusCode >= 300 || !response.tempFilePath || (contentType && !/^application\/pdf/i.test(contentType))) {
const error = new Error('托盘码打印文件生成失败')
error.statusCode = response.statusCode
error.requestId = response.header?.['X-Request-Id'] || response.header?.['x-request-id']
error.traceId = response.header?.['X-Trace-Id'] || response.header?.['x-trace-id']
throw error
}
return response.tempFilePath
})
}
export function downloadAllDropshipPalletLabels(taskId, warehouseId) {
const baseUrl = String(session.apiBase || '/api/platform/v1').replace(/\/$/, '')
const url = `${baseUrl}${ROOT}/tasks/${encodeURIComponent(taskId)}/pallets/print?warehouseId=${encodeURIComponent(stableId(warehouseId))}`
return apiDownload({ url }).then((response) => {
const contentType = response.header?.['Content-Type'] || response.header?.['content-type'] || ''
if (response.statusCode < 200 || response.statusCode >= 300 || !response.tempFilePath || (contentType && !/^application\/pdf/i.test(contentType))) throw new Error('全部托盘码打印文件生成失败')
return response.tempFilePath
})
}
function requireValue(value, message) { function requireValue(value, message) {
if (value === null || value === undefined || value === '') throw new Error(message) if (value === null || value === undefined || value === '') throw new Error(message)
+1 -1
View File
@@ -8,7 +8,7 @@ export const DEMO_ACCOUNTS = [
export const MODULES = [ export const MODULES = [
{ key: 'inbound', name: '入库', icon: '入', description: '收货、上架与质检', meta: '3 个静态页面', operations: [ { key: 'inbound', name: '入库', icon: '入', description: '收货、上架与质检', meta: '3 个静态页面', operations: [
{ name: '一件代发', icon: '托', description: '完成逐箱入库后生成并打印 DP 托盘码', available: true, visible: true }, { name: '一件代发', icon: '托', description: '扫描已由电脑端打印并贴好的 DP 托盘码', available: true, visible: true },
{ name: '到货收货', icon: '收', description: '扫描到货单并确认实收数量' }, { name: '到货收货', icon: '收', description: '扫描到货单并确认实收数量' },
{ name: '商品上架', icon: '上', description: '按推荐库位完成商品上架' }, { name: '商品上架', icon: '上', description: '按推荐库位完成商品上架' },
{ name: '入库质检', icon: '检', description: '登记质检结果与异常信息' } { name: '入库质检', icon: '检', description: '登记质检结果与异常信息' }
@@ -55,11 +55,9 @@
<view class="section-card"> <view class="section-card">
<view class="section-heading"><view><text class="section-title">2. 托盘操作</text><text class="section-desc">直接扫描托盘码,只显示当前操作的托盘;待绑托箱扫描目标托盘后批量归托</text></view><button class="text-button" :disabled="loading" @tap="loadTask">刷新</button></view> <view class="section-heading"><view><text class="section-title">2. 托盘操作</text><text class="section-desc">直接扫描托盘码,只显示当前操作的托盘;待绑托箱扫描目标托盘后批量归托</text></view><button class="text-button" :disabled="loading" @tap="loadTask">刷新</button></view>
<view class="batch-print-row"><text>已生成 {{ task.generatedPalletCount || 0 }} 个托盘码</text><button class="text-button batch-print" :disabled="printing || !task.generatedPalletCount" @tap="printAllPallets">打开全部 A4 托盘单</button></view>
<view v-if="currentPallet" class="pallet-card"> <view v-if="currentPallet" class="pallet-card">
<view class="pallet-head"><text class="pallet-code">{{ currentPallet.palletNo }}</text><text class="pallet-status" :class="currentPallet.status === 'SEALED' ? 'sealed' : ''">{{ currentPallet.status === 'SEALED' ? '已封托' : '当前托盘' }}</text></view> <view class="pallet-head"><text class="pallet-code">{{ currentPallet.palletNo }}</text><text class="pallet-status" :class="currentPallet.status === 'SEALED' ? 'sealed' : ''">{{ currentPallet.status === 'SEALED' ? '已封托' : '当前托盘' }}</text></view>
<text class="pallet-meta">{{ currentPallet.cartonCount || 0 }} 箱 · {{ currentPallet.skuCount || 0 }} SKU · {{ currentPallet.weightKg || 0 }} kg · {{ currentPallet.volumeCbm || 0 }} m³</text> <text class="pallet-meta">{{ currentPallet.cartonCount || 0 }} 箱 · {{ currentPallet.skuCount || 0 }} SKU · {{ currentPallet.weightKg || 0 }} kg · {{ currentPallet.volumeCbm || 0 }} m³</text>
<button v-if="currentPallet.palletId" class="secondary-button" :disabled="printing" @tap="printPallet(currentPallet)">{{ printing ? '正在生成 A4 文件…' : '打开当前托盘 A4 单' }}</button>
<view v-for="item in (currentPalletDetails?.cartons || [])" :key="item.cartonId" class="carton-row"><text>{{ item.boxCode }}</text><button v-if="currentPallet.status === 'OPEN'" class="text-button" :disabled="submitting" @tap="moveCarton(item, null)">移回待绑托</button></view> <view v-for="item in (currentPalletDetails?.cartons || [])" :key="item.cartonId" class="carton-row"><text>{{ item.boxCode }}</text><button v-if="currentPallet.status === 'OPEN'" class="text-button" :disabled="submitting" @tap="moveCarton(item, null)">移回待绑托</button></view>
<button v-if="currentPallet.palletId && currentPallet.status === 'OPEN'" class="primary-button" :disabled="!currentPallet.cartonCount || submitting" @tap="sealPallet(currentPallet)">封托</button> <button v-if="currentPallet.palletId && currentPallet.status === 'OPEN'" class="primary-button" :disabled="!currentPallet.cartonCount || submitting" @tap="sealPallet(currentPallet)">封托</button>
</view> </view>
@@ -72,7 +70,7 @@
<script> <script>
import PortalHeader from '@/components/PortalHeader.vue' import PortalHeader from '@/components/PortalHeader.vue'
import ScanTargetInput from '@/components/ScanTargetInput.vue' import ScanTargetInput from '@/components/ScanTargetInput.vue'
import { bindDropshipPendingCartons, claimDropshipPalletizationTask, countDropshipCarton, downloadAllDropshipPalletLabels, downloadDropshipPalletLabel, getDropshipPalletizationTask, moveDropshipCarton, resolveDropshipCarton, sealDropshipPallet } from '@/api/pda-dropship.js' import { bindDropshipPendingCartons, claimDropshipPalletizationTask, countDropshipCarton, getDropshipPalletizationTask, moveDropshipCarton, resolveDropshipCarton, sealDropshipPallet } from '@/api/pda-dropship.js'
import { session, requireSession } from '@/stores/session.js' import { session, requireSession } from '@/stores/session.js'
import { formatApiError } from '@/utils/user-facing.js' import { formatApiError } from '@/utils/user-facing.js'
import { stableOperationId } from '@/utils/idempotency.js' import { stableOperationId } from '@/utils/idempotency.js'
@@ -83,7 +81,7 @@
export default { export default {
components: { PortalHeader, ScanTargetInput }, components: { PortalHeader, ScanTargetInput },
data() { return { user: session.currentUser, taskId: '', warehouseId: '', task: null, palletCode: '', selectedPalletId: '', selectedPalletNo: '', boxCode: '', carton: null, skuCounts: [], activeScan: 'boxCode', loading: false, submitting: false, printing: false, error: '', notice: '' } }, data() { return { user: session.currentUser, taskId: '', warehouseId: '', task: null, palletCode: '', selectedPalletId: '', selectedPalletNo: '', boxCode: '', carton: null, skuCounts: [], activeScan: 'boxCode', loading: false, submitting: false, error: '', notice: '' } },
computed: { computed: {
statusLabel() { return this.task?.taskStatus === 'COMPLETED' ? '已完成' : (this.task?.taskStatus === 'CLAIMED' ? '作业中' : '待领取') }, statusLabel() { return this.task?.taskStatus === 'COMPLETED' ? '已完成' : (this.task?.taskStatus === 'CLAIMED' ? '作业中' : '待领取') },
palletSetupReady() { return this.task?.palletSetupReady === true }, palletSetupReady() { return this.task?.palletSetupReady === true },
@@ -141,36 +139,6 @@
}, },
continueOtherTask() { uni.redirectTo({ url: `/pages/dropship-tasks/dropship-tasks?warehouseId=${encodeURIComponent(this.warehouseId)}` }) }, continueOtherTask() { uni.redirectTo({ url: `/pages/dropship-tasks/dropship-tasks?warehouseId=${encodeURIComponent(this.warehouseId)}` }) },
async sealPallet(pallet) { const result = await this.runMutation(() => sealDropshipPallet(this.taskId, this.warehouseId, pallet), `${pallet.palletNo} 已封托`); if (result && this.selectedPalletNo === pallet.palletNo) { this.selectedPalletId = ''; this.selectedPalletNo = ''; this.palletCode = '' } }, async sealPallet(pallet) { const result = await this.runMutation(() => sealDropshipPallet(this.taskId, this.warehouseId, pallet), `${pallet.palletNo} 已封托`); if (result && this.selectedPalletNo === pallet.palletNo) { this.selectedPalletId = ''; this.selectedPalletNo = ''; this.palletCode = '' } },
async printPallet(pallet) {
if (this.printing) return
this.printing = true; this.resetMessages()
try {
const filePath = await downloadDropshipPalletLabel(this.taskId, this.warehouseId, pallet.palletId)
// #ifdef H5
const link = document.createElement('a'); link.href = filePath; link.download = `${pallet.palletNo}-托盘码.pdf`; link.click()
// #endif
// #ifndef H5
await new Promise((resolve, reject) => uni.openDocument({ filePath, fileType: 'pdf', showMenu: true, success: resolve, fail: reject }))
// #endif
this.notice = `${pallet.palletNo} A4 托盘信息单已打开`
} catch (error) { this.error = formatApiError(error, '托盘码打印失败') }
finally { this.printing = false }
},
async printAllPallets() {
if (this.printing) return
this.printing = true; this.resetMessages()
try {
const filePath = await downloadAllDropshipPalletLabels(this.taskId, this.warehouseId)
// #ifdef H5
const link = document.createElement('a'); link.href = filePath; link.download = `${this.task.inboundCode}-全部托盘码.pdf`; link.click()
// #endif
// #ifndef H5
await new Promise((resolve, reject) => uni.openDocument({ filePath, fileType: 'pdf', showMenu: true, success: resolve, fail: reject }))
// #endif
this.notice = `已打开 ${this.task.generatedPalletCount || 0} 个托盘码的 A4 文件`
} catch (error) { this.error = formatApiError(error, '全部托盘码打印失败') }
finally { this.printing = false }
},
async runMutation(action, message) { async runMutation(action, message) {
if (this.submitting) return null if (this.submitting) return null
if (!isOnline()) { this.error = '当前网络不可用,请联网后刷新'; return null } if (!isOnline()) { this.error = '当前网络不可用,请联网后刷新'; return null }
@@ -209,6 +177,5 @@
.quantity-stepper { display: grid; grid-template-columns: 38px 56px 38px; overflow: hidden; border: 1px solid #b8c6d8; border-radius: 8px; background: #fff; }.quantity-stepper button,.quantity-stepper input { box-sizing: border-box; height: 40px; margin: 0; border: 0; border-radius: 0; text-align: center; background: #fff; }.quantity-stepper button { color: #155eef; font-size: 20px; line-height: 40px; }.quantity-stepper input { width: 56px; border-right: 1px solid #dce4ed; border-left: 1px solid #dce4ed; color: #12233f; font-size: 15px; }.difference-field { grid-column: 1 / -1; margin-top: 0; }.pallet-hint { display: block; margin-top: 10px; color: #155eef; font-size: 11px; text-align: center; } .quantity-stepper { display: grid; grid-template-columns: 38px 56px 38px; overflow: hidden; border: 1px solid #b8c6d8; border-radius: 8px; background: #fff; }.quantity-stepper button,.quantity-stepper input { box-sizing: border-box; height: 40px; margin: 0; border: 0; border-radius: 0; text-align: center; background: #fff; }.quantity-stepper button { color: #155eef; font-size: 20px; line-height: 40px; }.quantity-stepper input { width: 56px; border-right: 1px solid #dce4ed; border-left: 1px solid #dce4ed; color: #12233f; font-size: 15px; }.difference-field { grid-column: 1 / -1; margin-top: 0; }.pallet-hint { display: block; margin-top: 10px; color: #155eef; font-size: 11px; text-align: center; }
.field { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 10px; color: #344054; font-size: 12px; }.field input { box-sizing: border-box; width: 120px; height: 42px; padding: 0 10px; border: 1px solid #cfd8e3; border-radius: 8px; background: #fff; }.field.stacked { align-items: stretch; flex-direction: column; gap: 6px; }.field textarea { box-sizing: border-box; width: 100%; height: 70px; padding: 9px; border: 1px solid #cfd8e3; border-radius: 8px; background: #fff; } .field { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 10px; color: #344054; font-size: 12px; }.field input { box-sizing: border-box; width: 120px; height: 42px; padding: 0 10px; border: 1px solid #cfd8e3; border-radius: 8px; background: #fff; }.field.stacked { align-items: stretch; flex-direction: column; gap: 6px; }.field textarea { box-sizing: border-box; width: 100%; height: 70px; padding: 9px; border: 1px solid #cfd8e3; border-radius: 8px; background: #fff; }
.pallet-code { color: #12233f; font-size: 19px; font-weight: 700; overflow-wrap: anywhere; }.text-button { min-width: 58px; height: 40px; border: 0; color: #155eef; font-size: 14px; line-height: 40px; background: transparent; }.empty { padding: 18px 0 8px; color: #98a2b3; font-size: 14px; text-align: center; } .pallet-code { color: #12233f; font-size: 19px; font-weight: 700; overflow-wrap: anywhere; }.text-button { min-width: 58px; height: 40px; border: 0; color: #155eef; font-size: 14px; line-height: 40px; background: transparent; }.empty { padding: 18px 0 8px; color: #98a2b3; font-size: 14px; text-align: center; }
.batch-print-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 7px 0; border-top: 1px solid #edf1f5; color: #667085; font-size: 13px; }.batch-print { min-width: 148px; padding: 0 4px; font-weight: 700; }
.palletization-page :deep(.scan-target-value) { font-size: 17px; } .palletization-page :deep(.scan-target-value) { font-size: 17px; }
</style> </style>
+4 -10
View File
@@ -19,13 +19,9 @@ test('dropship palletization adapter uses only the dedicated production PDA cont
const api = await read('../api/pda-dropship.js') const api = await read('../api/pda-dropship.js')
for (const route of [ for (const route of [
'/tasks/pending', '/cartons/resolve', '/cartons/count', '/tasks/pending', '/cartons/resolve', '/cartons/count',
'/pallets/bind-pending', '/seal', '/print' '/pallets/bind-pending', '/seal'
]) assert.match(api, new RegExp(route.replaceAll('/', '\\/'))) ]) assert.match(api, new RegExp(route.replaceAll('/', '\\/')))
assert.match(api, /apiDownload/) assert.doesNotMatch(api, /apiDownload|downloadAllDropshipPalletLabels|pallets\/print/)
assert.match(api, /downloadAllDropshipPalletLabels/)
assert.match(api, /pallets\/print\?warehouseId=/)
assert.match(api, /application\\\/pdf/)
assert.match(api, /session\.apiBase \|\| '\/api\/platform\/v1'/)
assert.match(api, /tasks\/pending\?\$\{params\.join\('&'\)\}/) assert.match(api, /tasks\/pending\?\$\{params\.join\('&'\)\}/)
assert.match(api, /warehouseId=\$\{encodeURIComponent\(warehouseId\)\}/) assert.match(api, /warehouseId=\$\{encodeURIComponent\(warehouseId\)\}/)
assert.match(api, /operationId\('count'/) assert.match(api, /operationId\('count'/)
@@ -45,7 +41,7 @@ test('palletization UI accepts carton and pre-generated pallet scans in either o
assert.match(tasks, /\.search-card\s*\{[^}]*display:\s*flex;[^}]*box-shadow:\s*none;/) assert.match(tasks, /\.search-card\s*\{[^}]*display:\s*flex;[^}]*box-shadow:\s*none;/)
assert.match(tasks, /\.task-list\s*\{[^}]*overflow:\s*hidden;[^}]*border-radius:\s*7px;/) assert.match(tasks, /\.task-list\s*\{[^}]*overflow:\s*hidden;[^}]*border-radius:\s*7px;/)
assert.match(tasks, /\.task-card\s*\{[^}]*margin:\s*0;[^}]*border-radius:\s*0;[^}]*box-shadow:\s*none;/) assert.match(tasks, /\.task-card\s*\{[^}]*margin:\s*0;[^}]*border-radius:\s*0;[^}]*box-shadow:\s*none;/)
for (const text of ['一件代发入库', '领取并开始入库', '扫箱清点', '读取 SKU', '确认清点', '扫托盘', '可选', '差异说明', '托盘码', '打开全部 A4 托盘单', '封托']) assert.match(work, new RegExp(text)) for (const text of ['一件代发入库', '领取并开始入库', '扫箱清点', '读取 SKU', '确认清点', '扫托盘', '可选', '差异说明', '托盘码', '封托']) assert.match(work, new RegExp(text))
for (const text of ['sku-label', 'sku-code', 'quantity-stepper', 'adjustQuantity']) assert.match(work, new RegExp(text)) for (const text of ['sku-label', 'sku-code', 'quantity-stepper', 'adjustQuantity']) assert.match(work, new RegExp(text))
assert.match(work, /减少 \$\{line\.skuCode\} 清点数量/) assert.match(work, /减少 \$\{line\.skuCode\} 清点数量/)
assert.match(work, /增加 \$\{line\.skuCode\} 清点数量/) assert.match(work, /增加 \$\{line\.skuCode\} 清点数量/)
@@ -70,11 +66,9 @@ test('palletization UI accepts carton and pre-generated pallet scans in either o
assert.match(work, /selectedPalletNo/) assert.match(work, /selectedPalletNo/)
assert.match(work, /已选择仓库开放托盘/) assert.match(work, /已选择仓库开放托盘/)
assert.match(work, /直接扫描托盘码,只显示当前操作的托盘/) assert.match(work, /直接扫描托盘码,只显示当前操作的托盘/)
assert.match(work, /打开全部 A4 托盘单/)
assert.match(work, /currentPalletDetails/) assert.match(work, /currentPalletDetails/)
assert.doesNotMatch(work, /v-for="pallet in task\.pallets"/) assert.doesNotMatch(work, /v-for="pallet in task\.pallets"/)
assert.match(work, /downloadDropshipPalletLabel/) assert.doesNotMatch(work, /downloadDropshipPalletLabel|downloadAllDropshipPalletLabels|打开当前托盘 A4 单|打开全部 A4 托盘单/)
assert.match(work, /downloadAllDropshipPalletLabels/)
assert.match(work, /formatApiError/) assert.match(work, /formatApiError/)
assert.doesNotMatch(work, /Number\(this\.warehouseId\)/) assert.doesNotMatch(work, /Number\(this\.warehouseId\)/)
assert.doesNotMatch(work, /taskId\s*\}\}|warehouseId\s*\}\}|inboundId\s*\}\}/) assert.doesNotMatch(work, /taskId\s*\}\}|warehouseId\s*\}\}|inboundId\s*\}\}/)
+2 -3
View File
@@ -28,11 +28,10 @@ test('formal palletization preserves both scan orders, moves and sealing guards'
assert.match(page, /currentPalletDetails\?\.cartons/) assert.match(page, /currentPalletDetails\?\.cartons/)
assert.doesNotMatch(page, /模拟成功|actualSkuQuantity/) assert.doesNotMatch(page, /模拟成功|actualSkuQuantity/)
}) })
test('palletization preserves compact multi-SKU input and printing', () => { test('palletization preserves compact multi-SKU input without desktop printing actions', () => {
assert.match(page, /v-for="\(line, index\) in skuCounts"/) assert.match(page, /v-for="\(line, index\) in skuCounts"/)
assert.match(page, /quantity-stepper/) assert.match(page, /quantity-stepper/)
assert.match(page, /printAllPallets/) assert.doesNotMatch(page, /printPallet|printAllPallets|打开当前托盘 A4 单|打开全部 A4 托盘单/)
assert.match(page, /printPallet/)
}) })
test('count and move use the formal multi-SKU contract with versioned retries', () => { test('count and move use the formal multi-SKU contract with versioned retries', () => {
for (const path of ['cartons/count', 'pallets/bind-pending', '/move', '/seal']) assert.ok(api.includes(path)) for (const path of ['cartons/count', 'pallets/bind-pending', '/move', '/seal']) assert.ok(api.includes(path))