107 lines
9.7 KiB
Markdown
107 lines
9.7 KiB
Markdown
# 柏悦物流海外版 PDA
|
||
|
||
独立的 uni-app Vue 3 App 工程,正式产品形态是安装在海外仓手持 PDA 上的 App。工程不依赖国内 PDA 源码或仓库外共享目录,可独立安装依赖、运行、编译和发布;H5 只用于浏览器调试和编译门禁,不是最终交付形态。
|
||
|
||
工作台提供柜号级真实入仓、托盘管理、排车拣货、出库任务、一件代发出库、任务完成和发车入口;派送单、派送状态与客户回访由 Admin/Client 承载。登录使用Auth 签发的统一 Access/Refresh Token;业务请求统一经 `gateway`,不得请求国内 Firstleg/Warehouse 业务接口。
|
||
|
||
## 本地运行与检查
|
||
|
||
Node.js 22 环境:
|
||
|
||
```powershell
|
||
npm install
|
||
npm test
|
||
npm run dev:h5
|
||
```
|
||
|
||
开发环境可在不提交的 `.env.local` 中配置 `VITE_PDA_DEV_USERNAME`、`VITE_PDA_DEV_PASSWORD`,登录页会自动预填;生产 App 构建始终忽略这两个值,账号必须具备 `OVERSEAS_WAREHOUSE_PDA_OPERATOR`、`lastleg:pda:operate` 和有效海外仓绑定。
|
||
|
||
生产编译:
|
||
|
||
```powershell
|
||
npm run build:h5
|
||
npm run build:app
|
||
```
|
||
|
||
- `build:h5` 生成浏览器调试资源,用于页面和模板编译检查;
|
||
- `build:app` 生成正式 App 的离线打包资源;
|
||
- 生成可安装 APK/IPA 需使用 HBuilderX App 开发版执行云打包或配置原生离线打包环境。
|
||
|
||
## 正式 App 打包前必填
|
||
|
||
1. 使用海外版所属的 DCloud 账号为本应用获取独立 AppID,写入 `src/manifest.json` 的 `appid`;不得复用国内版 AppID。
|
||
2. 确认 Android 包名 `com.baiyuelogistics.pda.overseas`,如公司已有正式命名规范,在首次正式签名前修改。
|
||
3. 配置海外版独立 Android 签名证书;证书、密码和账号信息不得提交仓库。
|
||
4. 复制 `.env.example` 为本机 `.env.local`,配置统一 Gateway 地址;环境文件不提交仓库。
|
||
5. 在目标海外 PDA 上验证扫描广播 Action=`android.intent.action.SCANRESULT`、Extra=`value`。
|
||
|
||
## 当前实现边界
|
||
|
||
- 已复用并内置:登录壳、PDA 样式、扫码广播、声音反馈、导航、网络检测、图标及 `uni_modules`。
|
||
- 已隔离:国内集装箱拣货、装柜证据、国内 Firstleg API、国内任务状态和国内本地草稿。
|
||
- 入仓页面已接待卸柜候选、柜详情与账号锁柜、三类角色照片签收、current 恢复、统一箱码与既有物理托盘解析、FBA 按箱数和 OVERSEAS 逐箱收货、逐入仓码核平及整柜完成的真实 API;收货页不预列柜内入仓码,箱码解析成功后只显示本次命中的入仓码;409 会引导返回当前柜,错误会保留业务码、requestId 与 traceId。
|
||
- 候选列表明确显示当前 PDA 绑定仓及每柜已分配的海外接柜仓编码/名称,仅接受与绑定仓一致的服务端候选、详情、prepare 与 current 会话;字段缺失或仓不匹配时直接阻断,不从 FBA/业务目的仓或内部 ID 推导。列表同时显示已齐全与未齐全柜,展示计划到仓时间、总订单、入仓码、已生成计划、未操作和缺入仓码数量;未齐全柜置灰但可查看服务端阻断原因,只有服务端 `allPlansReady=true && operable=true` 才能建立已分配柜的作业会话。
|
||
- 托盘管理已接 `/api/pda/v1/last-leg/pallet-operations/**`:支持扫描查询当前仓实物托盘及库存内容,并按服务端版本执行组托、拆托、换托和解绑;不同目的仓不能合托,冻结或处理中的库存由服务端拒绝。
|
||
- 排车拣货已接 `/api/pda/v1/last-leg/dispatches/**`:支持任务列表、业务单号恢复、托盘码扫码拣货、任务完成及全部箱数核平后的发车;服务端仍会校验关联出库单和托盘门禁。
|
||
- 出库作业已接 `/api/pda/v1/last-leg/outbound-tasks/**`:支持普通出库和一件代发任务列表/详情、托盘码/箱码/SKU/入仓码扫码拣货与核平完成;不会展示或进入派送流程。
|
||
- 排车与出库写操作使用可恢复的稳定幂等键。网络失败保留当前任务、扫码草稿和幂等键;成功后释放键并按服务端状态恢复,避免重复完成或发车。
|
||
- 入仓请求不手填客户、计划、分配、仓库或库位标识;身份与当前柜范围由 Token、Gateway 和服务端会话确定。页面同时支持 PDA 广播扫码与 H5 人工输入。
|
||
- 登录、恢复和刷新会 fail-closed 校验统一 Token 的平台操作主体和冻结海外仓,并从 Auth 登录/刷新响应的顶层权限快照校验 `OVERSEAS_WAREHOUSE_PDA_OPERATOR`、`lastleg:pda:operate`,不从 JWT 解析权限;并发 401 共享一次 refresh,主体与绑定仓保持一致后原子替换统一 Token 和权限快照,并将原请求或照片上传重放一次。刷新失败或重放后仍未授权时清空会话和作业草稿,并返回登录页;退出或重新登录后,旧请求不能重放到新会话,迟到的刷新响应也不能恢复旧会话或清除新会话。
|
||
- 库存盘点、商品移库、换标收货/执行/复核以及库存/库位/托盘查询均已接入 `/api/pda/**` 专用接口;支持 PDA 广播扫码与 H5 人工输入,并按服务端版本、幂等键和冲突状态恢复,不调用平台、客户或内部接口。
|
||
- 本地契约测试与 H5/App 资源编译不等于真实测试环境 HTTP 或 PDA 真机验收。
|
||
|
||
## App 在线更新
|
||
|
||
Android App 启动后会读取 `VITE_PDA_UPDATE_URL` 并检查海外 PDA 的独立更新通道,员工也可在“个人中心 → 检查更新”手动触发;H5 仅展示 App 操作提示,不执行更新。更新服务接收 `appid`、`platform`、`appVersion`、`appVersionCode`、`wgtVersion` 查询参数,无更新返回 `{ "update": false }`,有更新返回:
|
||
|
||
```json
|
||
{
|
||
"update": true,
|
||
"appid": "<海外PDA AppID>",
|
||
"packageType": "wgt",
|
||
"versionName": "0.0.2",
|
||
"versionCode": 2,
|
||
"minAppVersionCode": 1,
|
||
"downloadUrl": "https://updates.example.com/pda/overseas/0.0.2.wgt",
|
||
"mandatory": true,
|
||
"releaseNotes": "本次更新内容"
|
||
}
|
||
```
|
||
|
||
`packageType` 只允许 `apk` 或 `wgt`,`appid` 必须与当前安装包一致。WGT 清单还须提供 `minAppVersionCode`(最低兼容 APK 整数版本),不满足时客户端拒绝安装并提示升级 APK。`mandatory=true` 时员工不能跳过,并在下载或安装失败后提供重试;wgt 安装完成会立即重启,APK 交由 Android 安装器完成覆盖安装。正式发布要求:
|
||
|
||
1. 海外 PDA 每次整包发布同时递增 `src/manifest.json` 的 `versionName` 与整数 `versionCode`,使用海外独立 AppID、包名和签名打包 APK。
|
||
2. wgt 发布至少递增 `versionName`,并使用与已安装原生包兼容的 uni-app 编译器生成;新增原生模块、权限或不兼容运行时能力时必须发布 APK,不能只发 wgt。
|
||
3. 更新清单与下载地址使用 HTTPS,先在测试设备验证可选更新、强制更新、断网重试、APK 覆盖安装、wgt 重启及扫码作业回归,再切换正式清单。
|
||
4. 海外和国内更新记录、文件目录及发布权限保持隔离,服务端必须按请求中的 `appid` 拒绝跨应用更新包。
|
||
|
||
## TEST H5 静态托管
|
||
|
||
发布构建使用 `/` 资源 base 与 hash 路由,部署到本应用独立域名根目录,浏览器入口为 `/#/`。开发服务仍使用根路径;不能将 Vite 开发代理当作静态服务器配置。
|
||
|
||
执行 `npm run build:h5`。无需启动 Vite 开发服务器;`npm run build:app` 不属于 H5 发布。
|
||
|
||
`deploy/Dockerfile.h5` 只复制已构建 `dist/build/h5/` 及静态 Nginx 配置,不在镜像中复制源码、依赖或重新编译。`.dockerignore` 只放行这两类输入。容器静态目录为 `/srv/pda-h5/`。
|
||
|
||
从本仓库执行 `docker compose -f deploy/docker-compose.h5.test.yml build --pull=false`,再由获授权的部署流程执行 `docker compose -f deploy/docker-compose.h5.test.yml up -d --wait --wait-timeout 120`。必须设置 `IMAGE_TAG`,`NGINX_BASE_IMAGE` 可指定已缓存的兼容 Alpine Nginx 镜像。容器名及网络别名为 `pda-overseas-h5-test`,仅在外部 `firstleg-test-network` 暴露容器 80,不发布宿主端口。健康检查同时请求 `/healthz` 与 `/` 的实际首页。
|
||
|
||
独立域名入口将 `/` 代理至本应用静态容器根目录,或将构建目录内容直接发布到站点根目录;不再挂载 PDA 子路径。缺失资源返回 404,不回退首页,HTML 使用 `Cache-Control: no-store`。域名入口还须配置同源 API 代理:两端均将 `/gateway-api/` 转统一 Gateway `/api/`。入口须保留 Authorization,支持文件上传下载及至少 11m 请求体。域名与上游只在部署侧配置,不编入 PDA 源码。
|
||
|
||
部署配置检查:`node --test tests/h5-deployment.test.mjs`。没有 Docker 运行时的本地合同检查不能替代目标主机 `docker compose config`、Nginx 启动与真实 HTTP 验收。
|
||
|
||
构建后执行 `node scripts/verify-h5.mjs`,核对 HTML/JS/CSS 资源路径、同源 API 和无本机/旧海外配置泄漏。该检查与本地构建仅证明产物;TEST 页面登录、仓权限、业务操作和 Android 真机另行验收。
|
||
|
||
### 两端统一 API 配置
|
||
|
||
两端的 `VITE_API_BASE_URL` 均为统一 Gateway 绝对地址(含 `/api`);`VITE_H5_API_BASE_URL=/gateway-api`;`API_PROXY_TARGET` 为同一 Gateway 源地址(不含 `/api`)。实际地址只放在未提交的 `.env.local`;修改后重启开发服务,发布前重新打包。
|
||
|
||
两端独立域名入口均配置以下规则;`gateway:9000` 仅适用于同一 Docker 网络,其他部署须替换成实际统一 Gateway 上游。静态容器只提供页面文件,Vite 代理不会随静态包发布。
|
||
|
||
```nginx
|
||
location ^~ /gateway-api/ {
|
||
proxy_pass http://gateway:9000/api/;
|
||
proxy_set_header Authorization $http_authorization;
|
||
client_max_body_size 11m;
|
||
}
|
||
```
|