14 KiB
地磅系统移植 Implementation Plan
⚠️ 策略已修订(2026-06-07)
旧版「CRM 式重写/api/web/admin/db/*」代码已删除。
权威实施方案:docs/db-migration/00-migration-plan.md(原样搬运 + 门户适配,对齐 bx 思路)
端点清单:docs/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(追加四表定义) -
Step 1: 编写
db_vehicle表
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='地磅-车牌';
-
Step 2: 编写
db_purchase_plan表(业务字段参照dibang.sqlpurchase_plans,关联 ID 改 VARCHAR(64),日期改 DATE/DATETIME) -
Step 3: 编写
db_weighing_slip表(保留is_voided,关联 ID VARCHAR(64)) -
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 行
- 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 模型
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 端点
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中生成规则)
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服务方法(单事务)
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 后再编码。
执行方式:
- Subagent-Driven(推荐) — 每 Task 派发子 agent,任务间 Review
- Inline Execution — 本会话按 Task 批量实现,检查点暂停
如需开始实现,请说明采用哪种方式,或直接说「开始 Task 1」。