From 991150e64b2cad503478d70a0c250b6db020d450 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Fri, 11 Sep 2026 11:15:07 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 5 +- api/pda-dropship.js | 41 ++++++ data/demo-data.js | 1 + pages.json | 2 + .../dropship-palletization.vue | 138 ++++++++++++++++++ pages/dropship-tasks/dropship-tasks.vue | 86 +++++++++++ pages/home/home.vue | 8 +- pages/module/module.vue | 8 +- tests/dropship-palletization.test.mjs | 44 ++++++ tests/page-contract.test.mjs | 8 +- 10 files changed, 332 insertions(+), 9 deletions(-) create mode 100644 api/pda-dropship.js create mode 100644 pages/dropship-palletization/dropship-palletization.vue create mode 100644 pages/dropship-tasks/dropship-tasks.vue create mode 100644 tests/dropship-palletization.test.mjs diff --git a/AGENTS.md b/AGENTS.md index 8919130..65e88fb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,7 +8,7 @@ ## 开发与发布边界 -- 当前已有 uni-app Vue 3 页面、`uni_modules/`、`vite.config.js`、`.env.example` 和 H5 同源代理配置。项目仍没有根级依赖清单、仓库内 npm 构建命令或可核实的 Android 构建命令;H5 已使用 HBuilderX 5.15 自带编译器和 `cli.exe launch web` 验证,具体命令见 `README.md`。现有 Node.js 内置测试仅覆盖页面契约与本地状态规则。 +- 当前已有 uni-app Vue 3 页面、`uni_modules/`、`vite.config.js`、`.env.example` 和 H5 同源代理配置。真实作业包括一件代发合托和集装箱拣货;项目仍没有根级依赖清单、仓库内 npm 构建命令或可核实的 Android 构建命令。H5 已使用 HBuilderX 5.15 自带编译器和 `cli.exe launch web` 验证,具体命令见 `README.md`。现有 Node.js 内置测试仅覆盖页面契约与本地状态规则。 - PDA 采用 uni-app 开发并支持在线更新;Android 硬件扫描已确认使用广播模式并已接入:Action=`android.intent.action.SCANRESULT`、字符串 Extra=`value`。设备型号不构成开发、发布或验收门禁;继续通过设备适配层接入,不绑定单一厂商 SDK。 - 正式作业已确认为在线模式:断网不能开始正式拣货、提交、完成任务或推进 `LOADED`,不实现离线业务提交队列;恢复网络后提示员工刷新重试。 - H5 调试使用 HBuilderX 5.15 自带的 uni-app Vue 3 编译器;Android 发布流程仍待明确后补充准确的依赖版本、打包命令,并同步更新 `README.md` 与本文件。 @@ -55,6 +55,7 @@ | 登录与会话 | `pages/login/`、`stores/session.js` | 远程鉴权适配和会话清理 | | 工作台与模块入口 | `pages/home/`、`pages/module/`、`pages/operation/` | `data/demo-data.js` 与页面禁用规则 | | 待处理任务、服务端就绪与领取 | `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 托盘或系统发新托盘,全部归托后逐托封托;公网前缀 `/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 | | 拣货任务与箱码扫码 | `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/picking.vue` 的 `evidence` 阶段 | 正式边界是 `api/pda-loading.js` 的证据查询、预览、上传、作废和 `completeContainerPickingTask` 全部按当前任务与仓库进入;不得保留按入仓单/客户作用域的旧证据调用。上传队列 `utils/evidence-upload-queue.js`,合同 `tests/pda-loading-api.test.mjs`、`tests/picking-evidence-stage.test.mjs` | @@ -69,7 +70,7 @@ | 验收域 | PDA 范围与代码入口 | 验收首读 | |---|---|---|---| -| 作业全链路 | 登录、工作台、扫码拣货、装柜证据、草稿持久化、批量提交、异常和在线更新 | `pages/login/`、`pages/home/`、`pages/picking/`、`stores/session.js`、`stores/picking.js`、`utils/scan-broadcast.js`、`pages.json` | 按业务选择 `../../docs/订单与客户/`、`../../docs/入库测量与计费/`、`../../docs/国内货柜履约/` 和 `README.md` 的契约与验收规则 | +| 作业全链路 | 登录、工作台、一件代发扫码清点/归托/封托、集装箱扫码拣货、装柜证据、草稿持久化、批量提交、异常和在线更新 | `pages/login/`、`pages/home/`、`pages/dropship-tasks/`、`pages/dropship-palletization/`、`pages/picking/`、`stores/session.js`、`stores/picking.js`、`utils/scan-broadcast.js`、`pages.json` | 按业务选择 `../../docs/订单与客户/`、`../../docs/入库测量与计费/`、`../../docs/国内货柜履约/` 和 `README.md` 的契约与验收规则 | 作业边界:PDA 不承担客户工作台或后台配置;服务端状态、权限、幂等和 `LOADED` 门禁是验收事实来源。发布采用既定 uni-app 在线更新安排。 diff --git a/api/pda-dropship.js b/api/pda-dropship.js new file mode 100644 index 0000000..52ed010 --- /dev/null +++ b/api/pda-dropship.js @@ -0,0 +1,41 @@ +import { apiRequest } from '@/api/http.js' + +const ROOT = '/first-leg/pda-dropship' + +function operationId(action, taskId) { + const random = Math.random().toString(36).slice(2, 10) + return `pda-dropship-${action}-${taskId}-${Date.now()}-${random}`.slice(0, 128) +} + +export function listDropshipPalletizationTasks(keyword = '') { + const query = String(keyword || '').trim() + return apiRequest({ url: `${ROOT}/tasks/pending${query ? `?keyword=${encodeURIComponent(query)}` : ''}`, method: 'GET' }) +} + +export function getDropshipPalletizationTask(taskId, warehouseId) { + return apiRequest({ url: `${ROOT}/tasks/${encodeURIComponent(taskId)}?warehouseId=${encodeURIComponent(warehouseId)}`, method: 'GET' }) +} + +export function claimDropshipPalletizationTask(taskId, warehouseId) { + return apiRequest({ url: `${ROOT}/tasks/${encodeURIComponent(taskId)}/claim`, method: 'POST', data: { warehouseId } }) +} + +export function resolveDropshipCarton(taskId, warehouseId, boxCode) { + return apiRequest({ url: `${ROOT}/tasks/${encodeURIComponent(taskId)}/cartons/resolve?warehouseId=${encodeURIComponent(warehouseId)}&boxCode=${encodeURIComponent(String(boxCode || '').trim())}`, method: 'GET' }) +} + +export function countDropshipCarton(taskId, payload) { + return apiRequest({ url: `${ROOT}/tasks/${encodeURIComponent(taskId)}/cartons/count`, method: 'POST', data: { ...payload, operationId: payload.operationId || operationId('count', taskId) } }) +} + +export function bindDropshipPendingCartons(taskId, warehouseId, palletNo) { + return apiRequest({ url: `${ROOT}/tasks/${encodeURIComponent(taskId)}/pallets/bind-pending`, method: 'POST', data: { warehouseId, palletNo: String(palletNo || '').trim().toUpperCase(), operationId: operationId('bind', taskId) } }) +} + +export function createAndBindDropshipPallet(taskId, warehouseId) { + return apiRequest({ url: `${ROOT}/tasks/${encodeURIComponent(taskId)}/pallets/create-and-bind`, method: 'POST', data: { warehouseId, operationId: operationId('create-bind', taskId) } }) +} + +export function sealDropshipPallet(taskId, warehouseId, pallet) { + return apiRequest({ url: `${ROOT}/tasks/${encodeURIComponent(taskId)}/pallets/${encodeURIComponent(pallet.palletId)}/seal`, method: 'POST', data: { warehouseId, expectedVersion: pallet.version, operationId: operationId('seal', taskId) } }) +} diff --git a/data/demo-data.js b/data/demo-data.js index ba2fdde..d3309fe 100644 --- a/data/demo-data.js +++ b/data/demo-data.js @@ -13,6 +13,7 @@ export const MODULES = [ { name: '入库质检', icon: '检', description: '登记质检结果与异常信息' } ] }, { key: 'outbound', name: '出库', icon: '出', description: '拣货、复核与装箱', meta: '3 个待办', operations: [ + { name: '一件代发合托', icon: '托', description: '逐箱清点并生成或绑定 DP 托盘', available: true }, { name: '集装箱拣货', icon: '拣', description: '按箱号扫描并确认拣货', available: true }, { name: '出库复核', icon: '核', description: '复核拣货商品与出库数量' }, { name: '装箱交接', icon: '装', description: '完成装箱并登记交接信息' } diff --git a/pages.json b/pages.json index bada3f1..80ca699 100644 --- a/pages.json +++ b/pages.json @@ -5,6 +5,8 @@ { "path": "pages/module/module", "style": { "navigationStyle": "custom", "navigationBarTitleText": "业务模块", "backgroundColor": "#F5F7FA" } }, { "path": "pages/operation/operation", "style": { "navigationStyle": "custom", "navigationBarTitleText": "现场作业", "backgroundColor": "#F5F7FA" } }, { "path": "pages/tasks/tasks", "style": { "navigationStyle": "custom", "navigationBarTitleText": "拣货任务", "backgroundColor": "#F5F7FA" } }, + { "path": "pages/dropship-tasks/dropship-tasks", "style": { "navigationStyle": "custom", "navigationBarTitleText": "一件代发合托", "backgroundColor": "#F5F7FA" } }, + { "path": "pages/dropship-palletization/dropship-palletization", "style": { "navigationStyle": "custom", "navigationBarTitleText": "合托作业", "backgroundColor": "#F5F7FA" } }, { "path": "pages/history/history", "style": { "navigationStyle": "custom", "navigationBarTitleText": "作业记录", "backgroundColor": "#F5F7FA" } }, { "path": "pages/profile/profile", "style": { "navigationStyle": "custom", "navigationBarTitleText": "个人中心", "backgroundColor": "#F5F7FA" } }, { "path": "pages/scanner-test/scanner-test", "style": { "navigationStyle": "custom", "navigationBarTitleText": "广播扫码测试", "backgroundColor": "#F5F7FA" } }, diff --git a/pages/dropship-palletization/dropship-palletization.vue b/pages/dropship-palletization/dropship-palletization.vue new file mode 100644 index 0000000..7b782ef --- /dev/null +++ b/pages/dropship-palletization/dropship-palletization.vue @@ -0,0 +1,138 @@ +