提交
This commit is contained in:
1 parent
725774ef0c
commit
c3be9d1dce
176 files changed
+41925
-6342
No files matched your search
@@ -0,0 +1,393 @@
|
||||
# 地磅系统移植 Implementation Plan
|
||||
|
||||
> **⚠️ 策略已修订(2026-06-07)**
|
||||
> 旧版「CRM 式重写 `/api/web/admin/db/*`」代码已删除。
|
||||
> **权威实施方案**:[`docs/db-migration/00-migration-plan.md`](../../db-migration/00-migration-plan.md)(**原样搬运 + 门户适配**,对齐 bx 思路)
|
||||
> 端点清单:[`docs/db-migration/01-api-inventory.md`](../../db-migration/01-api-inventory.md)
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 将原地磅系统五模块(仪表盘、计划、出入库、地磅单、车牌)迁入 shanxia2.0,含 4 张 `db_*` 表、后端联动逻辑与 Fresh Mint 前端。
|
||||
|
||||
**Architecture:** 参照 bx 子域模式,新建 `app/api/db/` + `app/services/db/`;主数据方案 A(CRM 下拉写名称文本);地磅保存事务内更新计划并生成出入库单。
|
||||
|
||||
**Tech Stack:** Python 3.9 FastAPI · SQLAlchemy · Pydantic v2 · Vue 3 · Element Plus · MySQL 5.7
|
||||
|
||||
> **设计文档**: `docs/superpowers/specs/2026-06-07-dibang-migration-design.md`
|
||||
> **OpenSpec**: `openspec/changes/dibang-migration/`
|
||||
|
||||
---
|
||||
|
||||
## File Map
|
||||
|
||||
### SQL — 新建
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `docs/sql/db_tables.sql` | 四张 `db_*` 表 DDL |
|
||||
| `docs/sql/db_menu_permissions.sql` | 地磅菜单与按钮权限 |
|
||||
| `scripts/migrate_dibang_data.py` | 历史数据 int→UUID 迁移 |
|
||||
|
||||
### Backend — 新建
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `backend/app/models/db_models.py` | 4 个 SQLAlchemy 模型 |
|
||||
| `backend/app/services/db/base.py` | DbCrudService 基类 |
|
||||
| `backend/app/services/db/vehicle.py` | 车牌业务 |
|
||||
| `backend/app/services/db/plan.py` | 计划业务 + plan_no 生成 |
|
||||
| `backend/app/services/db/inventory.py` | 出入库业务 |
|
||||
| `backend/app/services/db/weighing.py` | 地磅单 + 联动事务 |
|
||||
| `backend/app/services/db/dashboard.py` | 统计聚合 |
|
||||
| `backend/app/schemas/db/*.py` | Pydantic schemas |
|
||||
| `backend/app/api/db/__init__.py` | db_router 聚合 |
|
||||
| `backend/app/api/db/vehicle.py` | 车牌路由 |
|
||||
| `backend/app/api/db/plan.py` | 计划路由 |
|
||||
| `backend/app/api/db/inventory.py` | 出入库路由 |
|
||||
| `backend/app/api/db/weighing.py` | 地磅路由 |
|
||||
| `backend/app/api/db/dashboard.py` | 仪表盘路由 |
|
||||
| `backend/app/tasks/db_auto_plan.py` | 按月自动生成计划 |
|
||||
|
||||
### Backend — 修改
|
||||
| 文件 | 变更 |
|
||||
|------|------|
|
||||
| `backend/app/api/__init__.py` | export db_router |
|
||||
| `backend/app/main.py` | include_router(db_router) + import db_models |
|
||||
|
||||
### Frontend — 新建
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `web-admin/src/api/db/*.ts` | 5 个 API 模块 |
|
||||
| `web-admin/src/views/db/vehicle/index.vue` | 车牌 P01 |
|
||||
| `web-admin/src/views/db/plan/index.vue` | 计划 P02 |
|
||||
| `web-admin/src/views/db/inventory/index.vue` | 出入库 P02 |
|
||||
| `web-admin/src/views/db/weighing/index.vue` | 地磅 P02 |
|
||||
| `web-admin/src/views/db/dashboard/index.vue` | 仪表盘 |
|
||||
|
||||
### Frontend — 修改
|
||||
| 文件 | 变更 |
|
||||
|------|------|
|
||||
| `web-admin/src/router/modules/sqxp.ts`(或等价) | 地磅菜单路由 |
|
||||
|
||||
### 参考源码(只读)
|
||||
| 路径 | 用途 |
|
||||
|------|------|
|
||||
| `simple-dibang-xiaoshou/backend/app/api/routes/weighing.py` | 联动逻辑 |
|
||||
| `simple-dibang-xiaoshou/backend/app/api/routes/plans.py` | 计划号生成 |
|
||||
| `simple-dibang-xiaoshou/art-design-pro/src/views/weighing/index.vue` | 字段与交互 |
|
||||
| `backend/app/services/bx/base.py` | CRUD 基类模式 |
|
||||
| `web-admin/src/views/system/order/index.vue` | 列表 UI 模板 |
|
||||
|
||||
---
|
||||
|
||||
## Task 1: 编写四表 DDL
|
||||
|
||||
**Files:**
|
||||
- Create: `docs/sql/db_tables.sql`
|
||||
- Modify: `docs/sql/shanxia2.0.sql`(追加四表定义)
|
||||
|
||||
- [x] **Step 1: 编写 `db_vehicle` 表**
|
||||
|
||||
```sql
|
||||
CREATE TABLE `db_vehicle` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`vehicle_no` varchar(255) NOT NULL COMMENT '车牌号',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0',
|
||||
`order_num` int(11) 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(6) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_vehicle_no` (`vehicle_no`),
|
||||
KEY `idx_tenant` (`tenant_no`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='地磅-车牌';
|
||||
```
|
||||
|
||||
- [x] **Step 2: 编写 `db_purchase_plan` 表**(业务字段参照 `dibang.sql` purchase_plans,关联 ID 改 VARCHAR(64),日期改 DATE/DATETIME)
|
||||
|
||||
- [x] **Step 3: 编写 `db_weighing_slip` 表**(保留 `is_voided`,关联 ID VARCHAR(64))
|
||||
|
||||
- [x] **Step 4: 编写 `db_inbound_outbound` 表**
|
||||
|
||||
- [ ] **Step 5: 在 MySQL 执行 DDL 验证**
|
||||
|
||||
Run: `mysql -u... shanxia2.0 < docs/sql/db_tables.sql`
|
||||
Expected: `SHOW TABLES LIKE 'db_%';` 返回 4 行
|
||||
|
||||
- [x] **Step 6: 将 DDL 合并进 `docs/sql/shanxia2.0.sql`**
|
||||
|
||||
---
|
||||
|
||||
## Task 2: SQLAlchemy 模型
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/app/models/db_models.py`
|
||||
- Modify: `backend/app/main.py`
|
||||
|
||||
- [ ] **Step 1: 创建 DbVehicle 模型**
|
||||
|
||||
```python
|
||||
from app.core.database import Base
|
||||
from sqlalchemy import Column, String, DateTime, Integer, SmallInteger
|
||||
from datetime import datetime
|
||||
|
||||
class DbVehicle(Base):
|
||||
__tablename__ = 'db_vehicle'
|
||||
id = Column(String(64), primary_key=True)
|
||||
vehicle_no = Column(String(255), nullable=False, index=True)
|
||||
tenant_no = Column(String(64), nullable=False, default='shanxia2.0', index=True)
|
||||
order_num = Column(Integer)
|
||||
remark = Column(String(512))
|
||||
create_by = Column(String(64))
|
||||
create_dept_id = Column(String(64), nullable=False, default='')
|
||||
create_time = Column(DateTime, nullable=False, default=datetime.now)
|
||||
update_by = Column(String(64))
|
||||
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)
|
||||
del_flag = Column(SmallInteger, nullable=False, default=0)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 创建 DbPurchasePlan、DbWeighingSlip、DbInboundOutbound**(字段与 DDL 一一对应)
|
||||
|
||||
- [ ] **Step 3: 在 main.py 添加** `import app.models.db_models # noqa: F401`
|
||||
|
||||
---
|
||||
|
||||
## Task 3: DbCrudService 与 db_router 骨架
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/app/services/db/base.py`
|
||||
- Create: `backend/app/api/db/__init__.py`
|
||||
- Modify: `backend/app/api/__init__.py`, `backend/app/main.py`
|
||||
|
||||
- [ ] **Step 1: 复制并改名 BxCrudService → DbCrudService**(`backend/app/services/bx/base.py`)
|
||||
|
||||
- [ ] **Step 2: 创建 db_router 并注册 health 端点**
|
||||
|
||||
```python
|
||||
from fastapi import APIRouter
|
||||
db_router = APIRouter(tags=['地磅管理'])
|
||||
|
||||
@db_router.get('/db/health')
|
||||
def db_health():
|
||||
return {'code': 0, 'data': {'status': 'ok', 'module': 'db'}}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: main.py 注册** `app.include_router(db_router, prefix=settings.API_V1_PREFIX)`
|
||||
|
||||
- [ ] **Step 4: 启动后端验证** `./start-local.sh`,访问 `/docs` 可见 db health
|
||||
|
||||
---
|
||||
|
||||
## Task 4: 车牌 CRUD(后端 + 前端)
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/app/schemas/db/vehicle.py`
|
||||
- Create: `backend/app/services/db/vehicle.py`
|
||||
- Create: `backend/app/api/db/vehicle.py`
|
||||
- Create: `web-admin/src/api/db/vehicle.ts`
|
||||
- Create: `web-admin/src/views/db/vehicle/index.vue`
|
||||
|
||||
- [ ] **Step 1: 实现 `_row_to_dict` + list/create/update/soft_delete**(tenant_no 过滤,vehicle_no 唯一校验)
|
||||
|
||||
- [ ] **Step 2: 路由** `GET/POST/PUT/DELETE /api/.../db/vehicles`(路径与现有 admin 风格对齐)
|
||||
|
||||
- [ ] **Step 3: 前端 API 函数** `fetchVehicleList`, `fetchCreateVehicle`, ...
|
||||
|
||||
- [ ] **Step 4: 前端页面** 参照 `web-admin/src/views/system/unit/index.vue`:筛选、工具栏、表格、分页、弹窗
|
||||
|
||||
- [ ] **Step 5: 注册路由** `/#/db/vehicle`
|
||||
|
||||
- [ ] **Step 6: 手工验证** 新增/编辑/删除车牌
|
||||
|
||||
---
|
||||
|
||||
## Task 5: 计划管理(后端 + 前端)
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/app/schemas/db/plan.py`
|
||||
- Create: `backend/app/services/db/plan.py`
|
||||
- Create: `backend/app/api/db/plan.py`
|
||||
- Create: `web-admin/src/api/db/plan.ts`
|
||||
- Create: `web-admin/src/views/db/plan/index.vue`
|
||||
|
||||
- [ ] **Step 1: 移植 plan_no 生成逻辑**(参照 `simple-dibang-xiaoshou/backend/app/api/routes/plans.py` 中生成规则)
|
||||
|
||||
```python
|
||||
def generate_plan_no() -> str:
|
||||
from datetime import datetime
|
||||
return f"SX-{datetime.now().strftime('%Y%m%d%H%M%S')}{'001'}" # 对齐原系统序号逻辑
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 实现计划 CRUD + 分页筛选**(business_type、execution_status、plan_no、日期范围)
|
||||
|
||||
- [ ] **Step 3: 表单支持 auto_generate_enabled / auto_generate_end_month**
|
||||
|
||||
- [ ] **Step 4: 前端列表** 参照 order 模板;执行状态用 `<el-tag>`
|
||||
|
||||
- [ ] **Step 5: 表单产品/客户下拉** 调用 CRM API,选中写入 `product`、`customer_name` 文本
|
||||
|
||||
- [ ] **Step 6: 验证** 创建计划 → 列表可见 → 编辑 → 软删除
|
||||
|
||||
---
|
||||
|
||||
## Task 6: 出入库管理(后端 + 前端)
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/app/schemas/db/inventory.py`
|
||||
- Create: `backend/app/services/db/inventory.py`
|
||||
- Create: `backend/app/api/db/inventory.py`
|
||||
- Create: `web-admin/src/api/db/inventory.ts`
|
||||
- Create: `web-admin/src/views/db/inventory/index.vue`
|
||||
|
||||
- [ ] **Step 1: 实现出入库 CRUD**(字段映射原 inbound_outbound)
|
||||
|
||||
- [ ] **Step 2: 列表筛选** date、partner_company、business_type、status、vehicle_no
|
||||
|
||||
- [ ] **Step 3: 前端页面** P02 模板 + 状态 Tag
|
||||
|
||||
- [ ] **Step 4: 验证** 独立 CRUD 可用(联动在 Task 7 验收)
|
||||
|
||||
---
|
||||
|
||||
## Task 7: 地磅单管理与联动(核心)
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/app/schemas/db/weighing.py`
|
||||
- Create: `backend/app/services/db/weighing.py`
|
||||
- Create: `backend/app/api/db/weighing.py`
|
||||
- Create: `web-admin/src/api/db/weighing.ts`
|
||||
- Create: `web-admin/src/views/db/weighing/index.vue`
|
||||
|
||||
- [ ] **Step 1: 阅读原 `weighing.py` 全部保存/作废逻辑**,列出函数清单
|
||||
|
||||
- [ ] **Step 2: 实现 `save_weighing_slip` 服务方法(单事务)**
|
||||
|
||||
```python
|
||||
def save_weighing_slip(db, tenant_no, user_id, dept_id, payload):
|
||||
# 1. 创建或更新 db_weighing_slip
|
||||
# 2. 若有关联 plan:更新 executed_quantity, execution_status, last_weighing_slip_id
|
||||
# 3. 创建或更新 db_inbound_outbound,回写 inbound_outbound_id
|
||||
# 4. db.commit() — 任一步失败 rollback
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 实现 `void_weighing_slip`**:is_voided=1 + 回滚计划量
|
||||
|
||||
- [ ] **Step 4: API 路由** list / get / post / put / post:void
|
||||
|
||||
- [ ] **Step 5: 前端表单** 毛重/皮重/扣杂/净重/本次量;CRM 产品客户下拉;车牌下拉
|
||||
|
||||
- [ ] **Step 6: 全链路验证**
|
||||
|
||||
Run 手工流程:创建计划 → 保存地磅单 → 检查计划 executed_quantity 变化 → 检查出入库单生成
|
||||
|
||||
Expected: 三表数据一致,单位 kg/t 与原系统行为相同
|
||||
|
||||
---
|
||||
|
||||
## Task 8: 仪表盘
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/app/services/db/dashboard.py`
|
||||
- Create: `backend/app/api/db/dashboard.py`
|
||||
- Create: `web-admin/src/api/db/dashboard.ts`
|
||||
- Create: `web-admin/src/views/db/dashboard/index.vue`
|
||||
|
||||
- [ ] **Step 1: 移植原 dashboard 统计 SQL/聚合**(参照 `simple-dibang-xiaoshou/backend/app/api/routes/dashboard.py`)
|
||||
|
||||
- [ ] **Step 2: 返回概览:计划数、地磅单数、出入库数、近期趋势**
|
||||
|
||||
- [ ] **Step 3: 前端 dashboard 页渲染卡片 + 图表(ECharts 与项目现有用法一致)**
|
||||
|
||||
---
|
||||
|
||||
## Task 9: 计划自动生成定时任务
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/app/tasks/db_auto_plan.py`
|
||||
- Modify: `backend/app/tasks/__init__.py`
|
||||
|
||||
- [ ] **Step 1: 移植 `auto_create_monthly_plan.py` 核心查询与复制逻辑**
|
||||
|
||||
- [ ] **Step 2: 注册为 APScheduler 每月 1 日 01:30 任务(cron 可配置)**
|
||||
|
||||
- [ ] **Step 3: 提供手动触发入口或管理命令用于测试**
|
||||
|
||||
Run: 手动调用 task 函数
|
||||
Expected: 模板计划生成新记录,`auto_generate_last_month` 更新
|
||||
|
||||
---
|
||||
|
||||
## Task 10: 菜单权限与路由
|
||||
|
||||
**Files:**
|
||||
- Create: `docs/sql/db_menu_permissions.sql`
|
||||
- Modify: `web-admin/src/router/modules/sqxp.ts`
|
||||
|
||||
- [ ] **Step 1: SQL 插入「地磅管理」一级菜单及 5 个子菜单**
|
||||
|
||||
- [ ] **Step 2: 按钮权限** db:plan:list/add/edit/remove 等
|
||||
|
||||
- [ ] **Step 3: 前端 hash 路由** `#/db/dashboard`, `#/db/plan`, ...
|
||||
|
||||
- [ ] **Step 4: 管理员角色绑定菜单**
|
||||
|
||||
---
|
||||
|
||||
## Task 11: 历史数据迁移
|
||||
|
||||
**Files:**
|
||||
- Create: `scripts/migrate_dibang_data.py`
|
||||
|
||||
- [ ] **Step 1: 读取原库四表导出 CSV 或直连 dibang-test**
|
||||
|
||||
- [ ] **Step 2: 生成 UUID,写 mapping 表 `{table, old_id, new_id}`**
|
||||
|
||||
- [ ] **Step 3: 按依赖顺序导入** plan → inbound_outbound → weighing → vehicle
|
||||
|
||||
- [ ] **Step 4: 校验** 记录数一致;抽样检查关联 ID
|
||||
|
||||
Run: `python scripts/migrate_dibang_data.py --dry-run`
|
||||
Expected: 打印将迁移行数,无 orphan 关联
|
||||
|
||||
---
|
||||
|
||||
## Task 12: 收尾验证
|
||||
|
||||
- [ ] **Step 1: 运行 field consistency 检查**(若 db 模块纳入脚本)
|
||||
|
||||
- [ ] **Step 2: `./scripts/update-graph.sh all`**
|
||||
|
||||
- [ ] **Step 3: 前端 lint** `pnpm lint`(仅 db 相关文件)
|
||||
|
||||
- [ ] **Step 4: 对照原系统 5 个核心场景写验收清单并逐项通过**
|
||||
|
||||
---
|
||||
|
||||
## Spec Coverage Checklist
|
||||
|
||||
| Spec 要求 | Task |
|
||||
|-----------|------|
|
||||
| 四表 DDL + 公共字段 | Task 1 |
|
||||
| 历史迁移脚本 | Task 11 |
|
||||
| 车牌 CRUD | Task 4 |
|
||||
| 计划 CRUD + plan_no | Task 5 |
|
||||
| 出入库 CRUD | Task 6 |
|
||||
| 地磅联动 + 作废 | Task 7 |
|
||||
| 仪表盘 API | Task 8 |
|
||||
| auto_generate 定时任务 | Task 9 |
|
||||
| 前端五页 + Fresh Mint | Task 4–8, 10 |
|
||||
| CRM 下拉方案 A | Task 5, 7 |
|
||||
| ecosystem 代码路径 | OpenSpec delta(已写入) |
|
||||
|
||||
---
|
||||
|
||||
**Plan complete.** 实施时可按 Task 1→12 顺序执行;Task 7 为风险最高项,建议单独评审原 `weighing.py` 后再编码。
|
||||
|
||||
**执行方式:**
|
||||
|
||||
1. **Subagent-Driven(推荐)** — 每 Task 派发子 agent,任务间 Review
|
||||
2. **Inline Execution** — 本会话按 Task 批量实现,检查点暂停
|
||||
|
||||
如需开始实现,请说明采用哪种方式,或直接说「开始 Task 1」。
|
||||
@@ -0,0 +1,20 @@
|
||||
# 地磅三表 CRM 产品 ID + 规格 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development or superpowers:executing-plans.
|
||||
|
||||
**Goal:** 计划/出入库/地磅单三表存储 `product_id` + `specification`,新建与编辑必选 CRM 产品。
|
||||
|
||||
**Architecture:** 方案 B(ID + 名称/规格快照);`resolve_crm_product` 统一校验并回填;级联复制 product 字段。
|
||||
|
||||
**Tech Stack:** FastAPI + SQLAlchemy + Vue 3 + Element Plus
|
||||
|
||||
---
|
||||
|
||||
## 任务清单
|
||||
|
||||
- [x] DDL:`docs/sql/20260609_db_product_id_specification.sql` + `db_tables.sql`
|
||||
- [x] 后端:`product_helpers.py`、ORM、Schema、Mapper、三模块 API、自动计划
|
||||
- [x] 前端:`DbCrmProductSelect` 三 v-model、三页面表单与 API 类型
|
||||
- [ ] 执行增量 SQL 到开发库
|
||||
- [ ] 历史数据回填 `product_id`(可选脚本)
|
||||
- [ ] 全链路验收:计划 → 出入库 → 地磅
|
||||
@@ -0,0 +1,222 @@
|
||||
# 地磅系统移植设计文档
|
||||
|
||||
> **日期**: 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` |
|
||||
@@ -0,0 +1,27 @@
|
||||
# 地磅三表 CRM 产品 ID + 规格 — 设计文档
|
||||
|
||||
> **日期**: 2026-06-09
|
||||
> **状态**: 已批准(方案 B + 新建必选 CRM 产品)
|
||||
> **前置**: `docs/superpowers/specs/2026-06-07-dibang-migration-design.md` 方案 A 升级
|
||||
|
||||
## 目标
|
||||
|
||||
计划、出入库、地磅单三表均存储 `product_id`(`crm_product.id`)与 `specification`(规格快照,来源 `crm_product.model`),新建/编辑时必须从 CRM 选择产品,禁止手输纯文本。
|
||||
|
||||
## 字段
|
||||
|
||||
| 表 | 新增/补齐 | 保留快照 |
|
||||
|---|---|---|
|
||||
| `db_purchase_plan` | `product_id` | `product`、`specification` |
|
||||
| `db_inbound_outbound` | `product_id`、`specification` | `product` |
|
||||
| `db_weighing_slip` | `product_id`、`specification` | `cargo_name` |
|
||||
|
||||
不建 DB 外键;服务端按 `tenant_no` 校验 CRM 产品存在且 `status=on`,并用 CRM 数据回填名称与规格。
|
||||
|
||||
## 级联
|
||||
|
||||
计划 → 出入库 → 地磅:复制 `product_id`、`product`/`cargo_name`、`specification`。自动按月生成计划同步复制。
|
||||
|
||||
## 历史数据
|
||||
|
||||
已有行 `product_id` 可为 NULL;编辑保存时需重新选择 CRM 产品后方可提交。
|
||||
Reference in new issue
Block a user