Files
shanxia2.0/docs/superpowers/specs/2026-06-07-dibang-migration-design.md
T
2026-06-10 22:59:34 +08:00

223 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 地磅系统移植设计文档
> **日期**: 2026-06-07
> **状态**: 已批准(方案 A)
> **源系统**: `simple-dibang-xiaoshou`(Python FastAPI + art-design-pro)
> **目标系统**: `shanxia2.0`(Python FastAPI + web-admin Fresh Mint)
---
## 1. 背景与目标
### 1.1 背景
CRM、报销(bx)业务已迁入 shanxia2.0 一体化门户。原地磅系统(`docs/sql/dibang.sql`)仍为独立部署,与门户用户体系、主数据割裂。目标是将地磅核心业务迁入本仓库,统一认证、租户与 UI 规范。
### 1.2 移植模块(用户确认)
| 模块 | 原前端路径 | 说明 |
|------|-----------|------|
| 仪表盘 | `views/dashboard/console` | 统计概览 |
| 计划管理 | `views/plans` | 含按月自动生成 |
| 出入库管理 | `views/inventory` | 与地磅单联动 |
| 地磅单管理 | `views/weighing` | 核心业务 |
| 车牌号 | `views/master-data` 车辆 Tab | 仅车辆 CRUD |
### 1.3 不移植
| 原模块 | 替代方案 |
|--------|---------|
| 基础资料-往来单位 | 下拉读 `crm_customer`,存客户名称文本 |
| 基础资料-货物 | 下拉读 `crm_product`,存产品名称文本 |
| 用户管理 / 独立登录 | 门户 `sys_user` + 菜单权限 |
| `cargos` / `companies` 表 | 不建表 |
---
## 2. 设计决策
| 决策点 | 结论 | 理由 |
|--------|------|------|
| 主数据关联 | **方案 A**:仅存名称文本,不做 FK | 与原系统一致;产品/客户名称存在历史不一致 |
| 表前缀 | `db_*` | 与 `bx_*`、`crm_*` 域隔离 |
| 主键 | `VARCHAR(64) UUID` | database-conventions |
| 软删除 | `del_flag`;地磅作废保留 `is_voided` | 作废是业务态,非物理删除 |
| 后端子域 | `app/api/db/`、`app/services/db/` | 参照 bx 子域模式 |
| ORM | SQLAlchemy 同步 Session | 与门户一致(非原地磅 SQLModel async) |
| 鉴权 | 门户 admin JWT + 菜单权限 | 不复用原地磅 auth |
| 租户 | 所有查询/写入带 `tenant_no` | api-conventions |
| 前端 UI | Fresh Mint + P02 复杂列表模板 | 参照 `/#/demo/order` |
| 历史数据 | 独立迁移脚本 int→UUID 映射 | 生产 dibang-test 库需可导入 |
---
## 3. 数据模型
### 3.1 新建表(4 张)
```
db_purchase_plan ← purchase_plans
db_weighing_slip ← weighing_slips
db_inbound_outbound ← inbound_outbound
db_vehicle ← vehicles
```
### 3.2 公共字段(每张业务表末尾)
```sql
`tenant_no` VARCHAR(64) NOT NULL DEFAULT 'shanxia2.0',
`order_num` INT DEFAULT NULL,
`remark` VARCHAR(512) DEFAULT NULL,
`create_by` VARCHAR(64) DEFAULT NULL,
`create_dept_id` VARCHAR(64) NOT NULL DEFAULT '',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_by` VARCHAR(64) DEFAULT NULL,
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`del_flag` SMALLINT NOT NULL DEFAULT 0
```
### 3.3 字段规范改造对照
| 原字段 | 新字段 | 说明 |
|--------|--------|------|
| `id` INT AUTO_INCREMENT | `id` VARCHAR(64) | UUID |
| `is_deleted` | `del_flag` | 0/1 |
| `remarks` | `remark` | 公共字段名 |
| `created_at` VARCHAR | `create_time` DATETIME | 规范时间类型 |
| `purchase_plan_id` INT | `purchase_plan_id` VARCHAR(64) | 关联 ID |
| `inbound_outbound_id` INT | `inbound_outbound_id` VARCHAR(64) | 关联 ID |
| `last_weighing_slip_id` INT | `last_weighing_slip_id` VARCHAR(64) | 关联 ID |
| `plan_date`/`start_date`/`end_date` VARCHAR | DATE 或 DATETIME | 按语义升级 |
| `executed_at` VARCHAR | DATETIME | 执行时间 |
| `is_voided` | 保留 | 地磅单作废标记 |
**业务字段名保持不变**:`plan_no`、`execution_status`、`batch_no`、`vehicle_no`、`cargo_name`、`partner_company` 等。
### 3.4 主数据映射(方案 A)
| 业务字段 | 表单控件 | 存储 |
|---------|---------|------|
| `product` / `cargo_name` | CRM 产品远程搜索下拉 | 选中项的 `product_name` 文本 |
| `customer_name` / `partner_company` / `supplier` / `consignee` | CRM 客户远程搜索下拉 | 选中项的 `customer_name` 文本 |
| `vehicle_no` | `db_vehicle` 下拉或手工输入 | 车牌文本 |
---
## 4. 业务链路(须原样保留)
```
保存地磅单
→ 计算净重/本次量
→ 更新 db_purchase_plan.executed_quantity、execution_status、last_weighing_slip_id
→ 创建或更新 db_inbound_outbound
→ 回写 purchase_plan_id、inbound_outbound_id
作废地磅单 (is_voided=1)
→ 回滚计划已执行量(若已计入)
→ 联动出入库单状态
计划 auto_generate_enabled=1
→ APScheduler 定时任务按月复制生成新计划(原 auto-create-plan 脚本逻辑)
```
**单位约定(勿改)**:计划/出入库 `planned_quantity`、`quantity` 为 **吨(t)**;地磅重量字段为 **kg**;`executed_quantity` 为 **kg**。
---
## 5. 后端架构
```
backend/app/
├── models/db_models.py # DbPurchasePlan, DbWeighingSlip, DbInboundOutbound, DbVehicle
├── schemas/db/ # CreateBody / UpdateBody / Response
├── services/db/
│ ├── base.py # DbCrudService(参照 BxCrudService)
│ ├── plan.py
│ ├── weighing.py # 含联动事务
│ ├── inventory.py
│ ├── vehicle.py
│ └── dashboard.py
├── api/db/
│ ├── __init__.py # db_router
│ ├── plan.py
│ ├── weighing.py
│ ├── inventory.py
│ ├── vehicle.py
│ └── dashboard.py
└── tasks/db_auto_plan.py # 按月自动生成计划
```
**路由注册**:`app/main.py` 增加 `db_router`,前缀 `/api/admin/db/`(或 `/api/web/admin/db/`,与现有 admin 路由一致)。
**CRM 只读依赖**:计划/地磅/出入库表单调用已有 CRM 产品、客户列表 API,不新建 cargos/companies 路由。
---
## 6. 前端架构
```
web-admin/src/
├── api/db/
│ ├── plan.ts
│ ├── weighing.ts
│ ├── inventory.ts
│ ├── vehicle.ts
│ └── dashboard.ts
└── views/db/
├── dashboard/index.vue # 工作台统计
├── plan/index.vue # P02
├── inventory/index.vue # P02
├── weighing/index.vue # P02 + 表单弹窗
└── vehicle/index.vue # P01
```
**菜单**:侧栏新增「地磅管理」一级菜单,子菜单:仪表盘、计划管理、出入库管理、地磅单管理、车牌管理。
**UI 规范**:`docs/web-admin-ui-spec-fresh-mint.md`;状态字段用 `<el-tag>`;按钮带图标;操作列 `fixed="right"`。
---
## 7. 数据迁移
1. 自 `dibang.sql` / 生产库导出四表数据
2. 脚本生成 UUID,维护 `legacy_id → new_id` 映射表
3. 重写 `purchase_plan_id`、`inbound_outbound_id`、`last_weighing_slip_id` 外键
4. 补 `tenant_no='shanxia2.0'` 及公共字段
5. CRM 客户/产品:仅保证下拉可选;历史文本名称不强制对齐 CRM 主数据
---
## 8. 分阶段交付
| 阶段 | 内容 |
|------|------|
| P1 SQL | 4 张 `db_*` DDL 写入 `docs/sql/` 并合并 `shanxia2.0.sql` |
| P2 后端 | vehicle → plan → inventory → weighing → dashboard → 定时任务 |
| P3 前端 | 同上顺序 + CRM 下拉 |
| P4 迁移 | 历史数据脚本 + 菜单权限 SQL |
| P5 验收 | 计划→地磅→出入库全链路 + 看板 |
---
## 9. 风险
| 风险 | 缓解 |
|------|------|
| 产品/客户名称与 CRM 不一致 | 方案 A 存文本;下拉仅辅助录入 |
| int→UUID 关联断裂 | 迁移脚本维护映射表并校验 |
| 联动逻辑回归 | 对照原 `weighing.py` 逐场景验收 |
| ecosystem-landscape 冲突 | OpenSpec 更新地磅归属为本仓库 |
---
## 10. 参考源码
| 用途 | 路径 |
|------|------|
| 原 DDL | `docs/sql/dibang.sql` |
| 原后端 | `simple-dibang-xiaoshou/backend/app/` |
| 原前端 | `simple-dibang-xiaoshou/art-design-pro/src/views/` |
| bx 移植参考 | `backend/app/api/bx/`、`backend/app/services/bx/` |
| CRM 产品/客户 API | `backend/app/api/crm.py` |
| UI 模板 | `web-admin/src/views/system/order/index.vue` |