Files
shanxia2.0/docs/superpowers/plans/2026-07-27-pl-plan-create-date.md
T
2026-07-27 16:30:35 +08:00

12 KiB
Raw Blame History

运输计划创建日期 + 取货/送达默认 — Implementation Plan

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: 为 pl_plan 增加业务字段「创建日期」(create_date/createDate),在新增/编辑弹窗中可编辑;新增时取货/送达时间若为空则默认等于计划日期。

Architecture: MySQL 增量迁移回填存量;SQLAlchemy 模型 + Pydantic Create/Update/Read 贯通;创建接口缺省时服务端用当天。前端仅改 pl-plan-form-dialog(及仍在用的 plan/form.vue),列表/查看暂不展示。

Tech Stack: FastAPI + SQLAlchemy + Pydantic v2;Vue 3 + Element Plus;MySQL 5.7

Spec: docs/superpowers/specs/2026-07-27-pl-plan-create-date-design.md


文件结构

文件 职责
backend/scripts/migrate_20260727_pl_plan_create_date.sql 增量 DDL + 存量回填
docs/sql/shanxia2.0.sql pl_plan 建表定义同步加 create_date
backend/app/models/pl_models.py PlPlan.create_date
backend/app/schemas/pl/plan.py Create/Update/Read/CreateFromContractRequest 的 createDate
backend/app/api/pl/plan.py create / create-full / create-from-contract / update 写入
backend/tests/test_pl_plan_create_date.py 缺省日期解析纯函数单测(若抽 helper)或创建默认行为说明见 Task 3
web-admin/src/api/pl/index.ts Plan / PlanCreateFullPayload 增加 createDate
web-admin/src/components/business/pl-plan-form-dialog/index.vue UI + 默认值 + 提交
web-admin/src/views/pl/plan/form.vue 与弹窗对齐(路由仍挂载时)

Task 1: 迁移 SQL + DDL 快照

Files:

  • Create: backend/scripts/migrate_20260727_pl_plan_create_date.sql

  • Modify: docs/sql/shanxia2.0.sql(CREATE TABLE pl_plan 中 plan_date 前插入 create_date)

  • Step 1: 写增量迁移脚本

-- backend/scripts/migrate_20260727_pl_plan_create_date.sql
-- 运输计划:业务创建日期 create_date(与系统 create_time 独立)

ALTER TABLE `pl_plan`
  ADD COLUMN `create_date` date DEFAULT NULL COMMENT '创建日期' AFTER `plan_no`;

UPDATE `pl_plan`
SET `create_date` = DATE(`create_time`)
WHERE `create_date` IS NULL AND `create_time` IS NOT NULL;

UPDATE `pl_plan`
SET `create_date` = CURDATE()
WHERE `create_date` IS NULL;

ALTER TABLE `pl_plan`
  MODIFY COLUMN `create_date` date NOT NULL COMMENT '创建日期';
  • Step 2: 同步 docs/sql/shanxia2.0.sql

在 CREATE TABLE \pl_plan`中,于 ``plan_no`` 行之后、``plan_date` `` 行之前增加:

  `create_date` date NOT NULL COMMENT '创建日期',

(不必改历史 INSERT 行;本地/环境以迁移脚本为准。若本机有库,执行 Step 1 脚本。)

  • Step 3: Commit
git add backend/scripts/migrate_20260727_pl_plan_create_date.sql docs/sql/shanxia2.0.sql
git commit -m "$(cat <<'EOF'
chore(pl): add pl_plan.create_date migration and DDL snapshot

EOF
)"

Task 2: ORM + Schema

Files:

  • Modify: backend/app/models/pl_models.py(PlPlan,约 plan_no / plan_date 附近)

  • Modify: backend/app/schemas/pl/plan.py

  • Step 1: 模型增加列

在 plan_no 与 plan_date 之间:

    plan_no = Column(String(32), nullable=False, unique=True, comment="计划订单编号 POYYYYMMDD###")
    create_date = Column(Date, nullable=False, comment="创建日期")
    plan_date = Column(Date, nullable=False, comment="计划日期")
  • Step 2: Schema 贯通

PlanCreate(约 126 行)增加(紧挨 plan_date):

class PlanCreate(PlanBase):
    create_date: Optional[date] = Field(
        default=None, alias="createDate", description="创建日期;缺省则服务端用当天"
    )
    plan_date: date = Field(..., alias="planDate", description="计划日期")
    products: Optional[list[PlanProductCreate]] = Field(default=None, description="产品明细列表")
    model_config = {"populate_by_name": True}

PlanUpdate 增加:

    create_date: Optional[date] = Field(default=None, alias="createDate")
    plan_date: Optional[date] = Field(default=None, alias="planDate")

PlanRead 在 plan_date 旁增加:

    create_date: date = Field(alias="createDate")
    plan_date: date = Field(alias="planDate")

CreateFromContractRequest 增加可选:

    create_date: Optional[date] = Field(
        default=None, alias="createDate", description="创建日期;缺省当天"
    )
    plan_date: date = Field(..., alias="planDate", description="计划日期")

确保文件顶部已有 Optional、date 导入。

  • Step 3: Commit
git add backend/app/models/pl_models.py backend/app/schemas/pl/plan.py
git commit -m "$(cat <<'EOF'
feat(pl): add create_date to PlPlan model and schemas

EOF
)"

Task 3: API 写入 create_date

Files:

  • Modify: backend/app/api/pl/plan.py(create_plan、create_plan_full、create_from_contract、update_plan)

说明:update_plan 已用 payload.model_dump(exclude_unset=True) + setattr,Schema 加字段后更新路径自动生效,无需改循环逻辑。

  • Step 1: 抽一小段解析(同文件顶部附近或内联)

在 plan.py 模块级增加:

from datetime import date

def _resolve_create_date(value: date | None) -> date:
    return value or date.today()

(若文件已 from datetime import date,勿重复导入。)

  • Step 2: 三处创建赋值

在 PlPlan(...) 构造处,plan_date=payload.plan_date 旁增加:

        create_date=_resolve_create_date(getattr(payload, "create_date", None)),
        plan_date=payload.plan_date,

覆盖:

  1. create_plan(约 396–400 行)
  2. create_plan_full(约 478–482 行)
  3. create_from_contract 内 PlPlan(...)(约 598–602 行)— 使用 payload.create_date
  • Step 3: 写纯函数单测
# backend/tests/test_pl_plan_create_date.py
from datetime import date

from app.api.pl.plan import _resolve_create_date


def test_resolve_create_date_uses_explicit():
    assert _resolve_create_date(date(2026, 1, 15)) == date(2026, 1, 15)


def test_resolve_create_date_defaults_today():
    assert _resolve_create_date(None) == date.today()

Run: cd backend && source venv/bin/activate && pytest tests/test_pl_plan_create_date.py -v
Expected: PASS

  • Step 4: Commit
git add backend/app/api/pl/plan.py backend/tests/test_pl_plan_create_date.py
git commit -m "$(cat <<'EOF'
feat(pl): persist create_date on plan create APIs

EOF
)"

Task 4: 前端 API 类型

Files:

  • Modify: web-admin/src/api/pl/index.ts

  • Step 1: 类型增加 createDate

Plan 接口(约 planDate 旁):

  planNo: string
  createDate: string
  planDate: string

PlanCreateFullPayload:

  contractId: string
  createDate: string
  planDate: string

createFromContract 可选扩展(若合同入口会传):

  createFromContract: (data: {
    contractId: string
    planDate: string
    createDate?: string
    followUserId?: string
    followUserName?: string
  }) =>
  • Step 2: Commit
git add web-admin/src/api/pl/index.ts
git commit -m "$(cat <<'EOF'
feat(web-admin): add createDate to transport plan API types

EOF
)"

Task 5: 新增/编辑弹窗 UI 与默认值

Files:

  • Modify: web-admin/src/components/business/pl-plan-form-dialog/index.vue

  • Step 1: 模板 — 计划日期前加创建日期

在基础信息 form-grid-4 内,「计划日期」el-form-item 之前插入:

            <el-form-item label="创建日期" prop="createDate">
              <el-date-picker
                v-model="formData.createDate"
                type="date"
                placeholder="选择日期"
                value-format="YYYY-MM-DD"
                style="width: 100%"
              />
            </el-form-item>
  • Step 2: formData / rules / reset / load / payload

辅助函数(script 内):

function todayYmd(): string {
  return new Date().toISOString().split('T')[0]
}

formData 初始:

  createDate: todayYmd(),
  planDate: todayYmd(),
  // ...
  pickupTime: '',  // reset 时再按计划日期填充
  deliveryTime: '',

basicRules:

  createDate: [{ required: true, message: '请选择创建日期', trigger: 'change' }],
  planDate: [{ required: true, message: '请选择计划日期', trigger: 'change' }],

resetForm 的 Object.assign:

    createDate: todayYmd(),
    planDate: todayYmd(),
    // ...其它字段同现有...
    pickupTime: todayYmd(), // 与默认 planDate 相同;用户改后不再联动
    deliveryTime: todayYmd(),

注意:resetForm 里先算一次 const d = todayYmd(),createDate/planDate/pickupTime/deliveryTime 都用同一个 d,避免跨日边界不一致。

loadPlanForEdit 的 Object.assign:

      createDate: data.createDate || formatDate(data.createTime) || todayYmd(),
      planDate: data.planDate,
      // pickup/delivery 仍用接口值,空则保持空(不要用计划日期覆盖)
      pickupTime: formatDate(data.pickupTime) || '',
      deliveryTime: formatDate(data.deliveryTime) || '',

buildPlanCommonPayload:

    createDate: formData.createDate,
    planDate: formData.planDate,

确认 没有 对 planDate 的 watch 去改取货/送达。

  • Step 3: 手工核对(开发者)
  1. 打开新增:创建日期、计划日期、取货、送达均为当天。
  2. 只改计划日期:取货/送达不变。
  3. 改取货后再改计划日期:取货仍为用户改过的值。
  4. 保存后再编辑:创建日期回填正确;createTime 未变。
  • Step 4: Commit
git add web-admin/src/components/business/pl-plan-form-dialog/index.vue
git commit -m "$(cat <<'EOF'
feat(web-admin): add createDate and default pickup/delivery in plan form dialog

EOF
)"

Task 6: 对齐独立表单页(若仍使用)

Files:

  • Modify: web-admin/src/views/pl/plan/form.vue

  • Step 1: 与弹窗同构的最小改动

若该页仍可从路由 /pl/plan/form 打开:同样在计划日期前加「创建日期」,formData/rules/提交/reset 增加 createDate;新增时 pickupTime/deliveryTime 空则填 planDate。
若页面已废弃不用,可在 PR 说明中注明「未改 form.vue」,并跳过本 Task。

  • Step 2: Commit(有改动时)
git add web-admin/src/views/pl/plan/form.vue
git commit -m "$(cat <<'EOF'
feat(web-admin): align plan form page with createDate field

EOF
)"

Task 7: 一致性检查与图谱

Files: 无强制新文件

  • Step 1: 字段一致性(若脚本覆盖 pl)
cd backend && source venv/bin/activate && python scripts/check_field_consistency.py

若报 createDate/create_date 相关缺失,按脚本提示补齐后重跑至通过或确认脚本未覆盖 pl_plan。

  • Step 2: 更新 graphify
./scripts/update-graph.sh all

或按仓库约定:graphify update .(根目录若配置)/ 仅 backend+web-admin。

  • Step 3: Commit 图谱变更(若有)
git add backend/graphify-out web-admin/graphify-out graphify-out 2>/dev/null || true
git status
# 仅提交实际变更的 graph 文件
git commit -m "$(cat <<'EOF'
chore: update graphify after pl_plan create_date

EOF
)"

Spec 覆盖自检

Spec 项 Task
D1 create_date 独立字段 1–3
D2 存量回填 1
D3 仅弹窗 UI 5(列表/查看不改)
D4 新增取货/送达默认计划日期、不联动 5
D5 计划日期默认当天不变 5
D6 安排弹窗不改 —(无 Task)
后端缺省当天 3
验收:createTime 不被改写 3(未写 create_time)+ 5 手工

Placeholder 扫描

无 TBD/TODO;步骤含具体 SQL/代码/命令。

类型一致性

全程使用:DB create_date、API/前端 createDate、Python create_date / alias createDate。