diff --git a/AGENTS.md b/AGENTS.md index 6ef7477..24d0e55 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,42 +1,33 @@ -# Overseas PDA Uni-app Instructions +# 海外 PDA 指引 ## 快速读取顺序 -1. 先用“页面与能力快速索引”定位 `src/pages.json`、工作台或最小页面;页面业务配置从 `src/data/overseas-workbench.js` 进入,不扫描 `src/uni_modules/`。 -2. 登录、Token 或统一入口请求先读 `src/api/auth.js`、`src/stores/session.js`、`src/config/runtime.js` 和 `../../docs/统一认证与服务通信契约.md`。 -3. 沿实际 API 定位:入仓/库存契约读 `../../baiyue-firstleg/lastleg-service/AGENTS.md`;资源契约读 `../../baiyue-firstleg/warehouse-overseas-service/AGENTS.md`;网关路径或鉴权问题才读 `../../baiyue-firstleg/gateway/AGENTS.md`。跨模块流程或入口不明才读 `../../docs/海外仓业务/README.md`;纯页面改动不自动读取后端指引。 +1. 按下表定位最小页面;业务配置见 `src/data/overseas-workbench.js`,不扫 `src/uni_modules/`。 +2. 登录/Token/统一请求先读下表登录API/会话、`src/config/runtime.js`、`../../docs/统一认证与服务通信契约.md`。 +3. 沿实际 API 读直接服务指引:入仓/库存 `../../baiyue-firstleg/lastleg-service/AGENTS.md`,资源 `../../baiyue-firstleg/warehouse-overseas-service/AGENTS.md`;网关路径/鉴权问题才读 `../../baiyue-firstleg/gateway/AGENTS.md`。跨模块或入口不明才读 `../../docs/海外仓业务/README.md`。 -最小读取集按任务保持在适用指引和目标页面/API;纯展示任务不增加服务指引,服务端判断才读直接服务指引,跨服务状态或鉴权无法判断时再增加相关方。读取预算遵循根指引的行数与字符数标准,先读适用规则,再检索业务命中段,不全文加载海外仓 README。 +仅读适用指引/目标页面/API;纯页面不读后端,跨服务状态/鉴权不明才扩读。遵根预算,先规则后命中段,不全文读海外仓 README。 ## 项目定位 -- 本项目是“柏悦物流海外版”独立 uni-app Vue 3 工程,面向海外仓现场人员。 -- 工程必须独立安装、构建和发布,不得依赖 `apps/pda-uniapp/` 或仓库外 `pda-shared` 目录。 -- 当前设备端业务范围包括海外仓入仓、退货签收与合箱、库内、换标、库存/库位/托盘查询,以及排车拣货、普通/一件代发出库任务、任务完成和发车;派送与客户回访由 Admin/Client 承载,国内集装箱拣货/装柜由国内 PDA 承载。 +- “柏悦物流海外版”面向海外仓现场人员,uni-app Vue 3 独立安装/构建/发布,不依赖 `apps/pda-uniapp/` 或仓库外 `pda-shared`。 +- 业务/任务完成见下表;派送/客户回访归 Admin/Client,国内集装箱拣货/装柜归国内 PDA。 ## 服务与发布边界 -- Auth 是唯一账号和 Token 签发方;认证和业务请求共用统一 Gateway,App 根地址只读 VITE_API_BASE_URL,H5 使用 VITE_H5_API_BASE_URL。 -- 登录、刷新和本地会话必须校验统一 Token 的平台主体、成员、有效期和冻结海外仓;`OVERSEAS_WAREHOUSE_PDA_OPERATOR` 与 `lastleg:pda:operate` 只从 Auth 登录/刷新响应的顶层权限快照读取并持久化,不得解析 JWT 权限。权限快照缺失、无效、过期、跨主体或撤权响应必须 fail-closed 清理会话,不得只依赖页面入口隐藏。 -- 并发 401 只允许一次 refresh;统一 Token 和权限快照完整校验后原子替换,主体或绑定仓改变时清理会话并重新登录,每个原请求或照片上传最多重放一次。刷新失败清理本地会话,业务错误和网络错误保留 code、requestId、traceId 或 network 诊断。 -- 国内与海外 AppID、Android 包名、签名、版本号、构建产物和在线更新通道必须独立。 -- `src/manifest.json` 中的 AppID 在正式打包前由海外版所属 DCloud 账号创建;不得伪造或复用国内 AppID。 -- 环境地址只通过 `.env.local` 等未提交环境文件配置,不写入源码。 -- 海外 Android App 启动后仅在 `APP-PLUS` 调用 `src/utils/app-update.js`,通过海外独立 `VITE_PDA_UPDATE_URL` 检查 HTTPS APK/WGT;强制更新不可跳过,WGT 安装后立即重启。更新服务、AppID、包名、签名和版本序列均不得与国内 PDA 混用。 +- Auth 唯一签发账号/Token;认证/业务共用 Gateway,App 根地址只读 VITE_API_BASE_URL,H5 用 VITE_H5_API_BASE_URL。 +- 登录/刷新/会话校验Token平台主体、成员、有效期、冻结仓;`OVERSEAS_WAREHOUSE_PDA_OPERATOR`、`lastleg:pda:operate` 仅读存Auth登录/刷新顶层快照,禁解析JWT权限。快照缺失/无效/过期/跨主体或撤权均fail-closed清会话,不能只藏入口。 +- 并发401仅一次refresh,完整校验Token/快照再原子替换;主体/仓变化清会话重登录,原请求/照片上传最多重放一次。刷新失败清会话;业务/网络错留code、requestId、traceId或network诊断。 +- 国内/海外 AppID、Android 包名、签名、版本号、产物、更新通道独立;`src/manifest.json` AppID须正式打包前由海外所属DCloud账号创建,禁伪造/复用国内AppID。 +- 环境地址仅配 `.env.local` 等未提交环境文件,不入源码。 +- Android启动仅在 `APP-PLUS` 调 `src/utils/app-update.js`,以独立 `VITE_PDA_UPDATE_URL` 查HTTPS APK/WGT;强更禁跳过,WGT安装即重启。更新服务/标识/签名/版本序列不得与国内 PDA 混用。 -## 工程入口 - -- 源码根:`src/`;页面注册:`src/pages.json`;应用配置:`src/manifest.json`。 -- 工作台定义:`src/data/overseas-workbench.js`。 -- 登录与会话:`src/api/auth.js`、`src/stores/session.js`。 -- 扫码设备层:`src/utils/scan-broadcast.js`;广播 Action=`android.intent.action.SCANRESULT`,Extra=`value`。 -- 入仓作业已接柜号级真实海外 API:账号锁柜、三类照片签收、统一箱码定位入仓码、FBA 按箱数收货、OVERSEAS 逐箱收货、一件代发按国内封托来源托盘整托收货并逐入仓码核平;退货入库通过退货单号或 SKU 候选进入并按本包实收生成退货箱与计费批次;移库、托盘管理、换标收货/执行/复核以及库存/库位/托盘查询均已接入专用 PDA API。库存盘点底层页面与接口仍保留,但当前工作台不开放入口。 +- 源码根 `src/`;扫码广播 Action=`android.intent.action.SCANRESULT`,Extra=`value`。 +- 均接真实PDA API;入仓账号锁柜、逐码核平;退货号/SKU候选进入,按本包实收生成退货箱/计费批次。换标含收货/执行/复核;盘点页面/API保留、工作台隐藏。 ## 页面与能力快速索引 -本表只保留首个入口;完整 API、字段、状态与恢复规则见 [按需业务索引](docs/business-index.md)。从本应用根执行 `rg -n -F '任务词或文件名' docs/business-index.md` 读取命中条款;涉及业务行为变更时必须核对对应细则,纯定位不全文加载。保留所有适用的最近模块指引。 - -表中路径均相对本应用根目录。 +路径相对应用根;[业务索引](docs/business-index.md)存API/字段/状态/恢复。应用根 `rg -n -F '任务词或文件名' docs/business-index.md`;涉及业务行为变更时必须核对对应细则及最近指引,定位不全文读。 | 目标 | 首个入口 | |---|---| @@ -51,12 +42,10 @@ | 退货箱内清点 | `src/pages/return-counting/return-counting.vue`、`src/api/return-counting.js` | | 仓储转运测量、打托与标签 | `src/pages/warehouse-transfer/warehouse-transfer.vue`、`src/api/warehouse-transfers.js` | | 托盘管理真实作业 | `src/pages/pallet/pallet.vue`、`src/api/pallet.js` | -| 库存盘点(入口隐藏) | `src/pages/stocktake/stocktake.vue`、`src/api/warehouse-operations.js`、`src/stores/warehouse-work.js` | -| 商品移库真实作业 | `src/pages/move/move.vue`、`src/api/warehouse-operations.js`、`src/stores/warehouse-work.js` | +| 库存盘点(入口隐藏)、商品移库 | `src/pages/stocktake/stocktake.vue`、`src/pages/move/move.vue`;共用 `src/api/warehouse-operations.js`、`src/stores/warehouse-work.js` | | 换标真实作业 | `src/pages/relabel/relabel.vue`、`src/api/relabel.js` | -| 现场查询真实作业 | `src/pages/query/query.vue`、`src/api/warehouse-operations.js` | -| 排车拣货与发车 | `src/pages/dispatch/dispatch.vue`、`src/api/fulfillment.js`、`src/stores/fulfillment.js` | -| 整车发车与证照提醒 | `src/pages/dispatch/dispatch.vue`、`src/api/fulfillment.js` 的 `departDispatch` | +| 现场查询 | `src/pages/query/query.vue`;同上库内API | +| 排车拣货、整车发车与证照提醒 | `src/pages/dispatch/dispatch.vue`、`src/api/fulfillment.js`(`departDispatch`)、`src/stores/fulfillment.js` | | 普通/一件代发出库 | `src/pages/outbound/outbound.vue`、`src/api/fulfillment.js`、`src/stores/fulfillment.js` | | 扫码设备与诊断 | `src/utils/scan-broadcast.js`、`src/pages/scanner-test/scanner-test.vue` | | 作业记录与人员 | `src/pages/history/history.vue`、`src/pages/profile/profile.vue` | @@ -65,48 +54,44 @@ ## 海外业务接口边界 -- 库内、换标、收货、排车与出库只调用专用 `/api/pda/**`,客户身份、绑定仓及资源范围由服务端校验;不得借用平台、客户或内部接口绕过授权。 -- 前端只展示服务端业务标识与操作资格;写操作保留稳定幂等键,失败/409 后重新读取权威状态,不把网络超时判成操作未执行或已成功。 -- 修改收货、退货、移库、托盘、换标、发车、照片或任务恢复前,必须定向读取 `docs/business-index.md` 的对应页面行及“海外业务接口边界”条款;专项检查仍按下文质量门禁执行。 -- 仓储转运按托盘分别保存箱数、长宽高(cm)和毛重(kg),体积按本托尺寸计算;SKU件数逐种核对差异,不以预报箱数强制核平。箱唛沿用客户预报编号,PDA不得另造新箱号;测量完成前客户与平台可增加整单预报箱数,不选SKU,箱内SKU以PDA实点为准,PDA刷新时合并新箱并保留本机草稿,清点提交携带forecastPackageCount拦截旧快照。生成托盘号后锁定该卡测量数据,必须取得服务端绑定确认且至少有一张现场照片才能完成打托;完成请求提交稳定幂等键、照片文件 ID,SKU实收件数有差异时在完成入口弹窗必填差异原因,不重复提交整份托盘测量。重新进入从详情恢复托盘和鉴权照片;标签使用服务端 `labelDownloadPath` 下载 PDF,打开文档不等于真机打印完成。 +- 库内/换标/收货/排车/出库/查询仅用 `/api/pda/**` API/DTO,经 `gateway` 显式PDA路由,不直连Lastleg/借平台、客户、内部接口。Gateway/服务端校验Token、`lastleg:pda:operate`、冻结仓、客户/资源归属;工作台 `available`、本地客户/仓ID不代替授权。 +- 仅展示服务端业务标识/资格;写操作留稳定幂等键,失败/409重读权威状态,超时不判未执行/成功。 +- 收货/退货/移库/托盘/换标/发车/照片/恢复变更须读 `docs/business-index.md` 对应页面行及“海外业务接口边界”,执行专项门禁。 +- 仓储转运逐托存箱数、长宽高(cm)、毛重(kg),本托尺寸算体积;逐SKU核对件数差异,不以预报箱数强制核平。沿用客户预报箱唛,不造箱号。测量完成前客户/平台可增整单预报箱数、不选SKU,箱内SKU以PDA实点为准;刷新合并新箱、留本机草稿,清点传forecastPackageCount拦旧快照。生成托盘号锁该卡测量,服务端绑定确认且至少一张现场照片才可完成打托;完成传稳定幂等键、照片文件ID,SKU实收差异在完成弹窗必填原因,不重传测量。重进从详情恢复托盘/鉴权照片;`labelDownloadPath` 下载PDF,打开不等于真机打印。 -- 换标目标确认即提交拆托合托,不再二次点击底部提交。`RelabelPalletWork.vue` 按当前轮次 `PALLET_BIND` 最新记录提供逐箱改绑,扫描新目标后弹窗确认,使用既有 `relabel-disassemble` 精确来源路径(不传 `actualSource`);同目标不发写请求。服务器持有库存、托盘版本与幂等约束,已排车或出库禁止直接改绑。离线回归 `tests/relabel-pallet-work.test.mjs`,不等同真机验收。 +- 换标目标确认即提交拆合托,无底部二次提交。下述组件按本轮最新 `PALLET_BIND` 逐箱改绑,扫新目标弹窗确认,经 `relabel-disassemble` 精确来源路径(不传 `actualSource`);同目标不写。服务端约束库存/托盘版本及幂等,已排车/出库禁改绑。回归 `tests/relabel-pallet-work.test.mjs`,离线非真机验收。 -- SKU 正常作业固定显示一个旧SKU扫描框,通过 `relabel-tasks/{relabelNo}/skus/scan` 提交 itemId、skuIndex 和旧SKU,不要求扫描新标签;多箱同SKU先选择具体明细。服务端每条保存 `SKU_SCAN` 历史,页面按当前返工轮次隐藏已完成子项;全部SKU完成才完成箱的SKU阶段,混合单仍需箱唛阶段。箱唛待处理列表同样隐藏已完成项。回归 `tests/relabel-quick-sku.test.mjs`。 +- SKU仅一个旧SKU扫描框,经 `relabel-tasks/{relabelNo}/skus/scan` 传itemId、skuIndex、旧SKU,不要求新标签;多箱同SKU先选明细。逐条存 `SKU_SCAN`,按本轮返工隐藏完成项;全SKU完成才完成箱SKU阶段,混合单还需箱唛阶段,箱唛列表也隐藏完成项。回归 `tests/relabel-quick-sku.test.mjs`。 -- 换标执行页内嵌 `src/components/RelabelPalletWork.vue`:`relabel-sources` 展示原入仓单各托盘箱数;选择来源库存行并扫描实托、输入拆出箱数、核对本批已完成换标箱,再扫描目标托盘合托。每次一个来源库存行,可分批处理多个托盘,无需为拆托额外逐箱扫码。`relabel-disassemble.actualSource` 原子调整本单冻结记账来源并移动库存,目标仍归原入仓单,不新建入库。仅同新目的仓合托;新增托盘不等待客户确认,409后刷新重扫。H5 提供标签打印,原生打印设备适配尚未完成;不能宣称生成托盘号即打印成功。回归 `tests/relabel-pallet-work.test.mjs`。 +- 换标页内嵌 `src/components/RelabelPalletWork.vue`;`relabel-sources` 展示原入仓单逐托箱数。每次选一来源库存行、扫实托、填拆出箱数、核本批已换标箱、扫目标合托;可分批多托,拆托不额外逐箱扫。`relabel-disassemble.actualSource` 原子调整本单冻结记账来源/移库存,目标归原入仓单、不新入库;仅同新目的仓合托,新托不等客户确认,409刷新重扫。H5可印标签,原生打印未适配,生成托盘号非打印成功;回归见逐箱改绑。 -- 换标任务标明类型,仅显示实际明细需要的 Tab。混合明细同时进入箱唛/SKU 作业,服务端分开保存两部分进度,`cartonProcessedPackages/skuProcessedPackages` 决定各 Tab 待处理数量;两项均完成后整箱计数一次,不能仅扫箱唛就视为 SKU 完成。 +- 换标标类型,仅显明细所需Tab;混合明细做箱唛/SKU两项,服务端分存进度,`cartonProcessedPackages/skuProcessedPackages` 定各Tab待处理数;两项完成整箱计一次,扫箱唛非SKU完成。 -- 换标完工提交使 PDA 任务进入 `WAIT_REVIEW`,申请进入 `CUSTOMER_CONFIRM_PENDING`,客户确认原子完成复核并释放后续履约资格。PDA 复核池只读;平台通过专用 `/rework` 接口携带任务版本、幂等键和必填备注退回,历史事实归档后重新计数,PDA 展示 `reviewRemark` 并清空上一轮输入和照片草稿。 +- 换标完工后任务 `WAIT_REVIEW`、申请 `CUSTOMER_CONFIRM_PENDING`;客户确认原子复核/释放履约资格。PDA复核池只读;平台经 `/rework` 携任务版本/幂等键/必填备注退回,历史归档重计数;PDA显 `reviewRemark`、清上轮输入/照片草稿。 -- 换标执行完成照片以缩略图展示并支持大图预览、移除和重拍。重新进入任务通过 `relabel-tasks/{relabelNo}/photos/files/{fileId}/download` 鉴权读取,不持久化设备临时图片地址;重拍先上传成功再替换待提交文件 ID,失败保留原照片,移除只解绑待提交引用。 +- 换标完工照片支持缩略图/大图/移除/重拍;重进经 `relabel-tasks/{relabelNo}/photos/files/{fileId}/download` 鉴权读,不存设备临时地址。重拍上传成功才换待提交ID,失败留原图;移除仅解绑待提交引用。 -- 退货查询空态集中在 `src/api/return-receipt.js`、`src/api/return-packing.js`:仅 `startReturnReceipt`、`findReturnSkuCandidates`、`findPackingOrders` 将 `A0404/404` 转为无匹配结果;签收确认、合箱写入和标签读取不得套用此处理,权限、网络与服务错误仍须保留诊断并报错。回归见 `tests/return-receipt-api.test.mjs`、`tests/return-packing-api.test.mjs`,不得将查询无记录误报为写入成功。 -- `src/api/inbound.js` 已接入待卸柜候选、柜详情/prepare、current 恢复、三类照片签收、统一箱码定位入仓码、实物托盘解析、普通 FBA bulk/普通 OVERSEAS carton、一件代发 source pallet 整托收货及整柜完成;FBA bulk 不提交 `skuCode`,库存分配由服务端按计划明细完成;一件代发只提交国内冻结的来源托盘号,不允许逐箱或拆托收货。响应与 404/409 判定集中在 `src/api/receiving-adapter.js`,统一 Token 刷新与业务 401 单次重放由 `src/api/overseas.js` 统一处理。 -- 入仓摘要、箱码解析和实收响应的 `assigned/mergeAllowed/urgent/mergeHint` 只消费 Lastleg 返回值,布尔标志只有 `true` 生效,`mergeAllowed` 缺省为 `false`;合托仅作提示,不能改变收货资格或触发分配。首扫实物托盘只确认服务端已有托盘、库位与资源锁预留,不在设备端重新分配托盘、库位或资源锁;只提交业务箱码、托盘码及当前收货数量,最终资格由服务端决定。 -- `src/api/overseas.js` 的 `overseasUrl` 统一拼接普通请求、上传和下载地址:先移除运行时 `apiBase` 末尾斜杠;当基址已以 `/api` 结尾时,再移除业务路径重复的 `/api` 前缀。各业务 API 不得自行拼接 `session.apiBase`,也不得依赖双斜杠或重复 `/api` 被网关容错。 -- 待卸柜候选只消费服务端已按 Token 绑定仓过滤的结果,并严格校验每柜正式 `overseasWarehouseCode`、`overseasWarehouseName` 与 `warehouse-profile` 一致;字段缺失或仓不一致一律 fail-closed,不得从 FBA/业务目的仓或内部 ID 推导。候选保留服务端返回的未齐全柜并严格消费 `allPlansReady`、`operable`、`blockReason`、`plannedArrivalAt` 与柜级计划统计;`operable=false` 只能查看只读摘要,不得调用 prepare。候选顺序沿用服务端“可操作优先、同组计划到仓时间升序、时间为空最后”的排序,前端不得用入仓码/计划数组长度自行推导就绪或把预计到港冒充计划到仓。 -- 候选详情、prepare 响应和 current 恢复都必须重复校验同一接柜仓编码;prepare 只建立已分配柜的作业会话,不得当作首次认领。服务端仓冲突的 `409/A0409` 中文错误保留 `requestId`/`traceId`;会话建立后仍按既有 current 恢复与完成前禁止切柜逻辑处理。 -- `src/api/pallet.js` 只调用 Lastleg 托盘专用 PDA Controller;前端提交服务端扫码返回的 `palletVersion`、`positionVersion` 和随机幂等键,不提交客户、仓库或库位标识。409 后必须重新扫码获取最新版本,禁止用旧库存快照继续作业。 -- 请求身份和资源范围只取 Token 与 current 会话;前端不得提交 `customerId`、`planNo`、`allocationId`、`warehouseId` 或 `locationId`。409 必须引导账号恢复当前柜,完成前不得切柜。 -- 签收照片固定为三个角色且每个角色只有一个当前文件;上传成功后使用服务端 `downloadPath` 在当前会话内鉴权读取。更换失败时保留原 `fileId` 和可提交状态,无原图的失败槽不得计入 `photosReady`;本地临时路径仅用于本次设备预览,不作为跨会话文件事实。 -- 库内、换标与现场查询只调用 `/api/pda/**` 业务 API/DTO,并统一受 `lastleg:pda:operate`、Token 冻结仓库范围和服务端资源归属约束;写操作必须保留稳定幂等键,409 后重新读取服务端状态,不得把平台、客户或内部接口直接暴露给 PDA。 -- 柜号签收入仓调用 Lastleg `/api/pda/v1/last-leg/receiving-containers/**`;退货签收与合箱分别调用 `/api/pda/v1/last-leg/return-receipts/**`、`/api/pda/v1/last-leg/return-inventory/**`,具体入口见上表。浏览器或设备请求必须经统一 `gateway` 的显式 PDA 路由,不得直连 Lastleg。 -- 海外业务 Token、PDA 权限和可信身份最终由 Gateway 与服务端校验;前端不得用工作台 `available`、本地客户 ID 或仓库 ID 代替授权和资源归属校验。 -- 排车和出库入口只调用专用 PDA 接口;客户与冻结海外仓范围由 Token、Gateway 和服务端解析,前端不提交 `customerId`、`warehouseId`,也不把内部数据库 ID 展示成业务编号。网络失败保留草稿和幂等键,恢复后以服务端任务状态为准;排车详情返回的 `canDepart`、`departBlockReason` 是发车资格依据,拣货及完成按钮同时核对当前单`canPick/pickBlockReason`;平台未转派送生成 `WAIT_OUTBOUND` 出库单时不得发车;完成或发车成功后不得重复提交。派送始终由 Admin/Client 承载。 +- 退货空态归上表签收API及 `src/api/return-packing.js`:仅 `startReturnReceipt/findReturnSkuCandidates/findPackingOrders` 将 `A0404/404` 转无匹配;签收确认/合箱写/标签读禁套用,权限/网络/服务错留诊断并报错,无记录非写成功;跑下述两项退货API回归。 +- 上表入仓API接待卸柜候选、详情/prepare、current、三类照片、箱码定位、实托解析、普通FBA bulk/OVERSEAS carton、一件代发source pallet整托及整柜完成。FBA bulk不传 `skuCode`,服务端按计划分库存;一件代发仅传国内冻结来源托盘号,禁逐箱/拆托收货。响应/404/409归 `src/api/receiving-adapter.js`,Token刷新/业务401单次重放归 `src/api/overseas.js`。 +- 入仓摘要/箱码/实收的 `assigned/mergeAllowed/urgent/mergeHint` 仅读Lastleg;布尔仅 `true` 生效,`mergeAllowed` 默认 `false`。合托只提示,不改资格/触发分配;首扫仅确认服务端已有实托/库位/资源锁预留,设备端不重分配。仅传业务箱码/托盘码/收货数量,服务端定资格。 +- `overseasUrl`(上述overseas.js)统一拼请求/上传/下载:去 `apiBase` 尾斜杠,基址以 `/api` 结尾则去业务路径重复 `/api`;禁自拼 `session.apiBase`,不靠网关容错双斜杠/重复前缀。 +- 待卸柜候选仅读服务端Token绑定仓过滤结果;逐柜验正式 `overseasWarehouseCode/overseasWarehouseName` 与 `warehouse-profile`,缺失/不符fail-closed,禁FBA/目的仓/内部ID推导。保留未齐全柜,严格取 `allPlansReady/operable/blockReason/plannedArrivalAt` 及柜统计;`operable=false` 仅只读摘要、禁prepare。沿用服务端可操作优先、同组计划到仓升序、空值末位;禁按入仓码/计划数组长度推就绪,禁预计到港替代计划到仓。 +- 详情/prepare/current均重验接柜仓码;prepare仅建已分配柜会话,非首次认领。仓冲突 `409/A0409` 留中文错误及 `requestId/traceId`;建后仍走current恢复。 +- 上表托盘API仅用Lastleg专用PDA Controller,传扫码的 `palletVersion/positionVersion`、随机幂等键,不传客户/仓/库位;409重扫取新版本,禁旧库存快照。 +- 请求身份/资源范围仅取Token/current,不传 `customerId/planNo/allocationId/warehouseId/locationId`;409引导账号恢复当前柜,完成前禁切柜。 +- 签收照片三角色各一当前文件;上传后以服务端 `downloadPath` 会话内鉴权读。换图失败留原 `fileId`/可提交状态,无原图失败槽不计 `photosReady`;临时路径仅本次预览。 +- 柜号签收入仓用Lastleg `/api/pda/v1/last-leg/receiving-containers/**`,退货签收/合箱分别用 `/api/pda/v1/last-leg/return-receipts/**`、`/api/pda/v1/last-leg/return-inventory/**`,入口见上表。 +- 排车/出库网络失败留草稿/幂等键,恢复看服务端任务。发车看 `canDepart/departBlockReason`,拣货/完成同时核 `canPick/pickBlockReason`;平台未转派送生成 `WAIT_OUTBOUND` 出库单禁发车,完成/发车成功禁重提。 ## 质量门禁 -- 已发车排车详情按需挂载`src/components/DispatchHandoverStatus.vue`,通过`src/api/trip-handover.js`读取当前派送资源和最近交接;每次进入/刷新一次GET,列表不逐行请求。仅只读、不提交客户或仓ID;后台确认交接,已完成派送保留完成时资源。回归`tests/trip-handover.test.mjs`。 +- 已发车详情按需挂载 `src/components/DispatchHandoverStatus.vue`,经 `src/api/trip-handover.js` 读当前派送资源/最近交接;进入/刷新各一次GET,列表不逐行请求。只读;后台确认交接,已完成派送留完成时资源。回归 `tests/trip-handover.test.mjs`。 - 安装:`npm install`;检查:`npm test`。 -- 仓储转运测量、打托、照片或标签入口变更运行 `node --test tests/warehouse-transfer-api.test.mjs tests/project-contract.test.mjs tests/workbench-availability.test.mjs`;静态合同不替代真实扫码、绑定及打印验收。 -- 退货签收、合箱或工作台入口变更先运行 `node --test tests/return-receipt-api.test.mjs tests/return-packing-api.test.mjs tests/project-contract.test.mjs tests/workbench-availability.test.mjs`;离线检查不替代真实 API 联调与真机扫码验收。 -- 当前 uni-app H5 编译链要求 `vue-i18n` 精确固定为 `9.1.9`;不得改回范围版本或单独升级。依赖变更必须同步 `package.json`、`package-lock.json` 与现有 `pnpm-lock.yaml`,并至少执行 H5 编译门禁。 -- 正式产品形态是海外 PDA App;`npm run build:h5` 仅用于浏览器调试和模板编译门禁,App 资源编译使用 `npm run build:app`。 -- APK/IPA 必须在 HBuilderX 或正式原生打包环境中使用独立 AppID 与签名验证;仅通过 App 资源编译不得声称 APK 真机验收完成。 -- 修改 `src/manifest.json` 图标映射或 `static/app-icons/` 时运行 `node --test tests/app-icons.test.mjs`,不得缺失已声明尺寸、用同一错误尺寸文件占位或从国内 PDA 复制 AppID/签名。 -- 修改任务、入仓码、柜号、托盘码、库位码等用户可见标识时运行 `node --test tests/business-identifiers-ui.test.mjs`;不得以内部数据库 ID 作为业务编号回退。 -- 修改更新协议、版本比较、强制更新、安装或重启行为时运行 `node --test tests/app-update.test.mjs`;新增原生模块、权限或不兼容运行时能力必须发海外 APK,不能仅发布 WGT,也不能下载国内更新包。 +- 专项用 `node --test`:转运测量/打托/照片/标签变更跑 `tests/warehouse-transfer-api.test.mjs`;退货签收/合箱/工作台变更先跑 `tests/return-receipt-api.test.mjs tests/return-packing-api.test.mjs`;两类均加 `tests/project-contract.test.mjs tests/workbench-availability.test.mjs`。静态/离线不替代真实API、真机扫码/绑定/打印。 +- H5编译链 `vue-i18n` 固定 `9.1.9`,禁范围版本/单独升级;依赖变更同步 `package.json`、`package-lock.json`、现有 `pnpm-lock.yaml`,至少跑H5编译。 +- 产品为海外PDA App;`npm run build:h5` 仅浏览器调试/模板门禁,App资源用 `npm run build:app`。APK/IPA须在HBuilderX/正式原生打包环境以独立AppID/签名验证,资源编译非APK真机验收。 +- 改 `src/manifest.json` 图标映射或 `static/app-icons/` 跑 `node --test tests/app-icons.test.mjs`;禁缺声明尺寸、同一错尺寸占位、复制国内AppID/签名。 +- 改任务/入仓码/柜号/托盘码/库位码等可见标识,以 `node --test` 跑上表标识隔离测试;禁内部ID回退业务号。 +- 改更新协议/版本比较/强制更新/安装/重启跑 `node --test tests/app-update.test.mjs`;新增原生模块/权限/不兼容运行时能力须发海外APK,不能只发WGT或下载国内包。 - 不提交 `node_modules/`、`dist/`、`unpackage/`、环境文件、签名证书或打包产物。 diff --git a/src/api/fulfillment.js b/src/api/fulfillment.js index dfe224a..acd177a 100644 --- a/src/api/fulfillment.js +++ b/src/api/fulfillment.js @@ -43,7 +43,7 @@ export function normalizeDispatchTask(value) { ...value, taskNo: String(value.taskNo || ''), dispatchNo: String(value.dispatchNo), recordVersion: value.recordVersion, pickingReconciled: value.pickingReconciled === true, actions: Object.fromEntries(Object.entries(value.actions || {}).map(([key, gate]) => [key, { ...gate, allowed: gate?.allowed === true }])), - items: value.items.map(item => ({ ...item, dispatchItemId: String(item.dispatchItemId || ''), palletNo: String(item.palletNo || ''), + items: value.items.map(item => ({ ...item, dispatchItemId: String(item.dispatchItemId || ''), sourceKey: String(item.sourceKey || ''), sourceBusinessType: item.sourceBusinessType == null ? null : String(item.sourceBusinessType), sourceBusinessNo: item.sourceBusinessNo == null ? null : String(item.sourceBusinessNo), palletNo: String(item.palletNo || ''), scheduledPackages: dispatchCount(item.scheduledPackages), pickedPackages: dispatchCount(item.pickedPackages), returnCartons: (item.returnCartons || []).map(carton => ({ ...carton, returnCartonId: String(carton.returnCartonId || ''), cartonMark: String(carton.cartonMark || ''), productQuantity: dispatchCount(carton.productQuantity) })), positions: (item.positions || []).map(position => ({ ...position, positionId: String(position.positionId || ''), balanceId: String(position.balanceId || ''), availablePackages: dispatchCount(position.availablePackages), allocatedPackages: dispatchCount(position.allocatedPackages), pickedPackages: dispatchCount(position.pickedPackages) })) diff --git a/src/pages/dispatch/dispatch.vue b/src/pages/dispatch/dispatch.vue index d15f1da..780eb18 100644 --- a/src/pages/dispatch/dispatch.vue +++ b/src/pages/dispatch/dispatch.vue @@ -11,8 +11,9 @@