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

14 KiB
Raw Blame History

地磅系统移植 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.sql purchase_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 后再编码。

执行方式:

  1. Subagent-Driven(推荐) — 每 Task 派发子 agent,任务间 Review
  2. Inline Execution — 本会话按 Task 批量实现,检查点暂停

如需开始实现,请说明采用哪种方式,或直接说「开始 Task 1」。