docs: add mobile-h5 dibang adaptation design for unified backend

Capture the approved approach to point mobile-h5 at shanxia2.0 backend APIs, portal login, and CRM/PL master-data selectors without UI permission gates.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-08-03 22:19:38 +08:00
1 parent 732c1b1dc9
commit e1170aa855
1 file changed
+183
@@ -0,0 +1,183 @@
# mobile-h5 地磅移动端适配一体化后端 — 设计说明
**日期:** 2026-08-03
**状态:** 待用户审阅
**方案:** 方案 1 — 以改 H5 为主,复用已有 `backend` 地磅 API
## 1. 背景与目标
### 现状
- `mobile-h5`:原地磅移动端(Vue 3 + Vant 4),对接旧地磅后端与 `docs/sql/dibang.sql`(自增 int 主键、独立主数据表)。
- 一体化库:`docs/sql/shanxia2.0.sql` 已含 `db_weighing_slip` / `db_purchase_plan` / `db_inbound_outbound` 等。
- 一体化后端:`backend/app/api/db/*` 已挂载 `/api/plans|inventory|weighing|dashboard`,协议对齐原 simple-dibang-xiaoshou(camelCase、直接 JSON),且 web-admin「地磅管理」已在用。
### 目标
将 `mobile-h5` 改造为对接一体化 `backend` + 新 SQL 模型,保留现有业务页面与操作流,尽快可上线。
### 非目标
- 不重做 H5 视觉 / UI 规范迁移。
- 不把 CRM / 报销业务做进 H5。
- 本期不改用 token 现场链接(继续出入库单 id)。
- 本期不在 H5 增加角色/菜单权限门禁。
- 不改 web-admin(仅作协议与选择器参考)。
## 2. 已确认约束
| 项 | 决定 |
|----|------|
| 改造策略 | 方案 1:改 H5 为主;后端仅补缺口 |
| 登录 | 门户 `/api/web/auth/login` + RSA + JWT(对齐 web-admin) |
| 基础资料模块 | 删除整页与 CRUD |
| 往来单位 | 只读选 CRM 客户管理数据 |
| 货物 | 只读选 CRM 产品管理数据;创建须带 `productId` |
| 车牌 | 只读选 PL 车辆(`self` 自有 + `carrier` 承运商/三方) |
| 手输自动建档 | 全端禁止(含现场页);无「手动输入新车牌」/`ensureVehicleExists` |
| 现场填写链 | 继续用出入库单 **id** 打开 `/inventory/fill/:id` |
| H5 权限 UI | **不做任何限制**(不按角色藏菜单/拦入口) |
## 3. 架构
```text
┌─────────────────┐ JWT Bearer ┌──────────────────────┐
│ mobile-h5 │ ───────────────────► │ backend (FastAPI) │
│ Vue3 + Vant │ │ │
│ │ /api/web/auth/* │ RSA 登录 / JWT │
│ 计划/出入库/ │ /api/plans|inventory │ db_* 地磅业务 │
│ 地磅/仪表盘 │ /weighing|dashboard │ │
│ │ /api/web/crm/* │ 客户、产品 │
│ 选择器只读 │ /api/transport/vehicle│ 自有+承运商车辆 │
└─────────────────┘ └──────────┬───────────┘
│
MySQL shanxia2.0
db_* / crm_* / pl_vehicle
```
### 数据归属
| H5 语义 | 读来源 | 写入业务表 |
|---------|--------|------------|
| 往来单位 | CRM 客户 | 名称快照(`customerName` / `partnerCompany` / `supplier`·`consignee` 等) |
| 货物 | CRM 产品 | `productId` + 名称/规格快照 |
| 车牌 | `pl_vehicle`(`vehicle_type` ∈ {`self`,`carrier`}) | 仅 `vehicleNo` 文本,禁止 create 车辆 |
### 删除范围
- 仪表盘「基础资料」入口;`master-data/*` 路由与页面。
- `companyApi` / `cargoApi` / `vehicleApi` CRUD 封装。
- `ensureVehicleExists`、「手动输入新车牌」相关 UI/逻辑。
- 未挂菜单的用户管理页(账号改走门户)。
## 4. 登录与 HTTP
### 登录流程(对齐 web-admin)
1. `GET /api/web/auth/login-rsa-public-key` → `publicKeyPem`
2. JSEncrypt 加密 `{ username, password, ts }` → `{ encryptedLogin }`
3. `POST /api/web/auth/login` → 门户信封 `{ code, data: { token, refreshToken, expiresIn, userInfo } }`
4. H5 存储 token;请求头 `Authorization: Bearer <token>`
5. 可选:`POST /api/web/auth/refresh-token`(参考 web-admin)
### 适配要点
- 新增 `loginRsa`(参考 `web-admin/src/utils/loginRsa.ts`);依赖 `jsencrypt`。
- 登录账号为门户 `sys_user.user_no`。
- Token 字段:门户 `token` ↔ H5 现有 `accessToken` 映射统一。
- 响应形态:
- 门户 auth / CRM:`{ code, data, message }`
- 地磅 db API:直接 JSON 实体(与 `web-admin/src/utils/http/db.ts` 一致)
- Dev:Vite 代理 `/api` → backend;生产:`VITE_API_URL`。
- API 加密:与 web-admin 同策略;登录 RSA 路径与现场免登路径列入排除列表。
- 集合根路径须带尾斜杠:`/plans/`、`/inventory/`、`/weighing/`(避免 307 丢 Authorization)。
### 关于后端 `require_admin_or_super_admin`
地磅业务接口依赖 `get_db_current_user` → `require_admin_or_super_admin`。
门户登录时 `resolve_web_role_for_user` 会把几乎所有绑定角色映射为 JWT `admin` / `super_admin`,因此 web-admin 中普通业务账号也能调地磅 API;真正限制门户入口的是**菜单授权**。
H5 **不做**前端角色/菜单门禁;能登录即可使用各业务页。403 仅展示接口返回文案。
## 5. 主数据选择器
| 字段 | 接口参考(web-admin) | 交互 |
|------|----------------------|------|
| 客户 | `POST /api/web/crm/customer/list` 远程搜 | Picker + 搜索;`allowCreate=false` |
| 产品 | `POST /api/web/crm/products/list`(或 options) | 选中写入 `productId` + 名称/规格 |
| 车辆 | `GET /api/transport/vehicle`(`vehicleType`=`self`/`carrier`) | 只选车牌;无手输新建 |
无匹配时提示「请到门户维护」,不提供新建入口。
对照:web-admin 地磅用 `DbCrmCustomerSelect` / `DbCrmProductSelect` / `PlVehicleSelect`;H5 同源,但客户亦禁止 create(比门户地磅客户选择更严)。
## 6. 业务页适配
### 主键与类型
全部业务 `id` 及关联外键(`purchasePlanId`、`inboundOutboundId`、`lastWeighingSlipId`、`fillLinkInventoryId`、`productId`)由 `number` 改为 **`string`**。
路由/query 禁止 `Number(uuid)`。类型对齐 `web-admin/src/api/db/{plans,inventory,weighing}.ts`。
### 创建必填
计划 / 出入库 / 地磅单创建须传 **`productId`**(后端 Create schema 已要求)。
### 模块能力(保留)
| 模块 | 能力 |
|------|------|
| 仪表盘 | 今日统计、四张 DualBar 图;入口:计划 / 出入库 / 地磅(去掉基础资料) |
| 计划 | 搜索、CRUD、生成出入库、查看关联 |
| 出入库 | 搜索、CRUD、生成地磅、磅单二维码(内容=出入库 id)、查看关联 |
| 地磅单 | 筛选、CRUD、作废、从出入库带入创建 |
操作流保持:计划 → 出入库 → 地磅单。
## 7. 现场免登页
- 路由:`/inventory/fill/:id`、`/inventory/plan/:id`(`noAuth`)。
- 继续用业务 **id** 打开;读写现有免登出入库 get/patch、计划 third-party-page 等。
- 车牌只选;去掉自动建档。
- 若车辆列表必须鉴权:后端补**最小只读 options**(免登或带业务上下文校验),仍禁止写入主数据。
- 二维码 URL 形态:`#/inventory/fill/{id}`。
## 8. 后端变更边界
优先零改或极少改。仅当下列缺口存在时补丁:
1. 现场免登场景下的车辆只读检索。
2. (可选)车辆 self+carrier 合并检索若前端拼两次调用体验差,可加薄聚合 options。
不重写 db 业务逻辑;不扩大本期权限模型。
## 9. 错误处理
- 业务失败:toast `detail` / `message`。
- 401:清 token → `/login`(免登页除外)。
- 不做 H5 侧角色预检。
## 10. 验收标准
1. 门户账号经 RSA 登录 H5 成功。
2. 仪表盘可用;无「基础资料」入口。
3. 计划 → 出入库 → 地磅 → 作废全链路成功。
4. 客户 / 产品 / 车辆只能选择,无法手输新增。
5. 现场 fill 页用 id 打开可填;车牌只能选。
6. 主键为 string,无 int 强转导致的故障。
## 11. 实现顺序建议
1. HTTP / 登录 / 环境变量 / 代理与加密排除。
2. API 类型与路径对齐(id→string、尾斜杠、productId)。
3. 选择器接 CRM/PL;删除基础资料与自动建档。
4. 业务页联调(计划 / 出入库 / 地磅 / 仪表盘)。
5. 现场页车牌只选 + 后端只读补丁(若需要)。
6. 验收清单回归。
## 12. 参考路径
- H5:`mobile-h5/`
- 后端地磅:`backend/app/api/db/`、`backend/app/schemas/db/`、`backend/app/models/db_models.py`
- 门户登录:`backend/app/api/public.py`(`/web/auth/*`)、`web-admin/src/utils/loginRsa.ts`
- web-admin 地磅:`web-admin/src/views/db/`、`web-admin/src/api/db/`、`web-admin/src/utils/http/db.ts`
- 选择器参考:`DbCrmCustomerSelect.vue`、`DbCrmProductSelect.vue`、`PlVehicleSelect`
- SQL:`docs/sql/dibang.sql`(旧)、`docs/sql/shanxia2.0.sql`(新)