Files
zyt/.trellis/tasks/archive/2026-05/05-08-order-amount-edit/prd.md
T

9.1 KiB
Raw Blame History

业务订单详情-修改总金额功能

Goal

在业务订单详情页面(admin/src/views/consumer/prescription/order_list.vue)增加修改总金额的功能,支持权限控制,并在操作日志中记录修改历史。已完成状态的订单不允许修改金额。

What I already know

前端架构

  • 详情页面:admin/src/views/consumer/prescription/order_list.vue60k+ tokens,包含详情抽屉)
  • API文件:admin/src/api/tcm.ts(已有 prescriptionOrderDetailprescriptionOrderEditprescriptionOrderLogs 等接口)
  • 订单状态枚举:
    • fulfillment_status = 3:已完成
    • 已完成/已取消订单不可编辑(line 3025)
  • 操作日志展示:详情抽屉中已有操作日志时间线(line 1192-1218

后端架构

  • 控制器:server/app/adminapi/controller/tcm/PrescriptionOrderController.php
  • 逻辑层:server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php
  • 模型:server/app/common/model/tcm/PrescriptionOrder.php
  • 日志模型:server/app/common/model/tcm/PrescriptionOrderLog.php
  • 日志写入方法:PrescriptionOrderLogic::writeLog() (line 2638-2658)
  • 日志读取方法:PrescriptionOrderLogic::getLogs() (line 1913)

现有日志记录模式

self::writeLog($orderId, $adminId, $adminInfo, 'action_name', '操作摘要');

日志字段:

  • prescription_order_id:订单ID
  • admin_id:操作人ID
  • admin_name:操作人姓名
  • action:操作类型(最多32字符)
  • summary:操作摘要(最多500字符)
  • create_time:创建时间

Confirmed Facts

  • 总金额字段:amount (decimal(10,2), NOT NULL, DEFAULT '0.00', COMMENT '业务订单金额')
  • 状态限制:已完成(fulfillment_status = 3)和已取消(fulfillment_status = 4)都不允许修改金额
  • 权限控制:新增独立菜单权限节点 tcm.prescriptionOrder/updateAmount
  • 金额校验规则:
    • 最小值:必须大于 0(不能为0或负数)
    • 最大值:无限制
    • 精度:保留2位小数
  • 需代收金额:前端计算属性自动计算(amount - linked_pay_paid_total),无需后端处理
  • 按钮位置:放在金额显示区域旁边(在显示总金额的卡片内)

Requirements (final)

功能需求

  1. 在业务订单详情页面的金额显示卡片内增加"修改金额"按钮
  2. 点击按钮弹出修改金额对话框,显示当前金额,允许输入新金额
  3. 已完成(fulfillment_status = 3)和已取消(fulfillment_status = 4)状态的订单隐藏修改金额按钮
  4. 修改金额需要权限控制(v-perms="['tcm.prescriptionOrder/updateAmount']"
  5. 金额校验:
    • 必须大于 0
    • 保留2位小数
    • 最大值无限制
  6. 修改成功后,在操作日志中记录:
    • 操作人姓名
    • 原金额
    • 新金额
    • 操作时间
    • 日志格式:将订单金额从 ¥{原金额} 修改为 ¥{新金额}
  7. 修改成功后立即刷新订单详情数据,需代收金额自动重新计算

技术需求

  • 前端:在金额显示卡片内增加修改按钮和对话框
  • 前端:新增API接口 prescriptionOrderUpdateAmount(params: { id: number; amount: number })
  • 后端:新增控制器方法 PrescriptionOrderController::updateAmount()
  • 后端:新增验证规则 PrescriptionOrderValidate::updateAmount
  • 后端:新增逻辑层方法 PrescriptionOrderLogic::updateAmount()
  • 后端:记录操作日志(action: update_amount
  • SQL:新增菜单权限记录(server/sql/1.9.20260508/add_update_amount_menu.sql

Acceptance Criteria (final)

  • 已完成和已取消状态的订单不显示"修改金额"按钮
  • 无权限的管理员不显示"修改金额"按钮
  • 修改金额对话框正确显示当前金额
  • 输入金额 ≤ 0 时提示错误
  • 输入金额精度超过2位小数时自动截断或提示
  • 提交成功后,订单 amount 字段更新为新金额
  • 操作日志中正确记录:{操作人} 将订单金额从 ¥{原金额} 修改为 ¥{新金额}
  • 修改后详情页面数据自动刷新,需代收金额正确显示
  • 后端返回错误时前端正确提示

Definition of Done

  • 前后端代码实现完成
  • 新增菜单权限SQL脚本
  • 金额修改功能测试通过(正常流程、权限控制、状态限制)
  • 操作日志记录正确
  • 代码通过 lint/typecheck
  • 无 console.log 残留

Out of Scope (explicit)

  • 批量修改金额
  • 修改金额审批流程
  • 金额修改历史版本对比
  • 修改其他订单字段(如运费、优惠等)

Technical Approach

实现流程

1. 后端实现(优先)

SQL 菜单权限server/sql/1.9.20260508/add_update_amount_menu.sql

INSERT INTO `zyt_system_menu` (`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_cache`, `is_show`, `is_disable`) 
VALUES 
(处方订单菜单ID, 'A', '修改订单金额', '', 0, 'tcm.prescriptionOrder/updateAmount', '', '', '', '', 0, 0, 0);

验证规则PrescriptionOrderValidate.php

public function updateAmount(): PrescriptionOrderValidate
{
    return $this->only(['id', 'amount'])
        ->append('id', 'require|number')
        ->append('amount', 'require|float|gt:0');
}

逻辑层PrescriptionOrderLogic.php

public static function updateAmount(array $params, int $adminId, array $adminInfo): bool
{
    $id = (int) $params['id'];
    $newAmount = round((float) $params['amount'], 2);
    
    // 权限检查
    $order = PrescriptionOrder::find($id);
    if (!$order) {
        self::setError('订单不存在');
        return false;
    }
    
    // 状态检查:已完成(3)和已取消(4)不允许修改
    if (in_array($order->fulfillment_status, [3, 4], true)) {
        self::setError('已完成或已取消的订单不允许修改金额');
        return false;
    }
    
    $oldAmount = round((float) $order->amount, 2);
    
    // 更新金额
    $order->amount = $newAmount;
    $order->save();
    
    // 记录日志
    $summary = sprintf('将订单金额从 ¥%.2f 修改为 ¥%.2f', $oldAmount, $newAmount);
    self::writeLog($id, $adminId, $adminInfo, 'update_amount', $summary);
    
    return true;
}

控制器PrescriptionOrderController.php

public function updateAmount()
{
    $params = (new PrescriptionOrderValidate())->post()->goCheck('updateAmount');
    $result = PrescriptionOrderLogic::updateAmount($params, $this->adminId, $this->adminInfo);
    
    if ($result === false) {
        return $this->fail(PrescriptionOrderLogic::getError());
    }
    
    return $this->success('修改成功');
}

2. 前端实现

API 接口admin/src/api/tcm.ts

export function prescriptionOrderUpdateAmount(params: { id: number; amount: number }) {
    return request.post({ url: '/tcm.prescriptionOrder/updateAmount', params })
}

页面实现admin/src/views/consumer/prescription/order_list.vue

  • 在金额显示卡片内增加"修改金额"按钮(带权限和状态判断)
  • 新增修改金额对话框(el-dialog + el-input-number
  • 提交后调用 API,成功后刷新详情数据

关键判断逻辑

// 是否可以修改金额
const canUpdateAmount = (row: any) => {
    // 已完成(3)或已取消(4)不允许修改
    return row.fulfillment_status !== 3 && row.fulfillment_status !== 4
}

Implementation Plan

PR1: 后端实现(优先)

  • 创建 SQL 菜单权限文件
  • 添加验证规则 updateAmount
  • 实现逻辑层方法 PrescriptionOrderLogic::updateAmount()
  • 实现控制器方法 PrescriptionOrderController::updateAmount()
  • 测试后端接口(Postman/curl

PR2: 前端实现

  • 添加 API 接口 prescriptionOrderUpdateAmount
  • 在金额卡片内添加"修改金额"按钮(带权限和状态判断)
  • 实现修改金额对话框
  • 实现提交逻辑和数据刷新
  • 测试完整流程(权限、状态、校验、日志)

PR3: 测试和优化

  • 测试各种边界情况(0、负数、超大金额、精度)
  • 测试权限控制
  • 测试状态限制
  • 验证操作日志记录
  • 代码 lint/typecheck
  • 清理 console.log

Technical Notes

文件清单

  • 前端页面:admin/src/views/consumer/prescription/order_list.vue
  • 前端APIadmin/src/api/tcm.ts
  • 后端控制器:server/app/adminapi/controller/tcm/PrescriptionOrderController.php
  • 后端逻辑:server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php
  • 后端验证:server/app/adminapi/validate/tcm/PrescriptionOrderValidate.php
  • SQL脚本:server/sql/1.9.20260508/add_update_amount_menu.sql(待创建)

参考实现

  • 操作日志写入:PrescriptionOrderLogic::writeLog() (line 2638)
  • 操作日志读取:PrescriptionOrderLogic::getLogs() (line 1913)
  • 状态判断逻辑:order_list.vue line 3025

约束

  • 日志 action 字段最多32字符
  • 日志 summary 字段最多500字符
  • 遵循 likeadmin 分层架构:Controller → Logic → Model
  • 权限通过菜单节点 + v-perms 指令控制