VWCG-1334 PC 消费订单详情与多菜品展示技术开发设计
1. 文档信息
| 项 | 内容 |
|---|---|
| 云效需求 | VWCG-1334 PC端消费订单详情信息与多菜品展示优化 |
| 文档版本 | V0.1 技术评审稿 |
| 日期 | 2026-09-08 |
| 阶段 | DEFINE / PLAN |
| 目标仓库 | store;若要求新增普通自提/档口快照,需联动全部订单生产端,至少包括 ai_api |
| 当前基线 | store origin/master@a7ee68bd830acfbff747ce9655f1a1215957ddae |
| DoR | BLOCKED:4 个 P0 口径待确认,见第 15 节 |
| 实施状态 | 仅完成需求与技术分析;未改业务代码、SQL、云效状态或云效正文 |
2. 结论先行
这是一个真实需求,但不是“只调弹框样式”的纯前端任务。推荐拆成两个可独立验收、顺序交付的 Use Case:
UC-MEAL-ORDER-DETAIL-001:详情接口生成稳定的展示 DTO,前端用配置驱动的三列栅格展示有效字段;移除菜品表 250px 内部滚动,按 1366×768、100% 缩放验证至少 6 个菜品直接可见。UC-MEAL-ORDER-EXPORT-002:保留现有异步.xlsx和列表筛选/权限范围,以订单游标批量取数、批量查询菜品,一条菜品明细写一行,订单字段重复,合计只按订单累计一次。
当前系统已经具备大部分取餐字段和流式 XLSX 基础,不需要重建页面或更换导出机制。真正的缺口是:
- 详情 UI 使用当前用户资料,不优先使用订单
user_name/user_mobile快照。 - 普通自提地址和档口名称没有订单快照;如果验收要求历史数据完全不受配置变化影响,需要新增快照字段并联动订单生产端。
- 详情接口没有统一的订单来源、订单类型、取餐方式、订单/取餐柜状态中文展示合同。
- 异步消费订单导出当前一订单一行,没有菜品明细,也没有取餐字段。
- 多菜品拆行后,订单金额会在明细行重复;Excel 底部汇总必须按订单去重累计,不能按输出行求和。
- 一张 XLSX 工作表最多 1,048,576 行;多菜品展开后更容易触顶,需求尚未确认“拆 Sheet”还是“限制导出范围”。
需求优先级建议为 P0。原因不是视觉,而是订单追溯、历史快照和导出口径必须保持一致。
3. 分析框架与真需求判断
本文用三种思路:
Y 模型:将“详情排版不好看”还原为“订单信息无法一次核对、历史信息可能漂移、Excel 无法追溯到菜品”的业务问题。MECE:拆为详情读取合同、页面布局、消费模式、菜品明细、异步导出、权限、性能和兼容八个面。系统思维:详情、导出、订单生产端和历史快照互相约束,不能只改一个 Vue 模板。
| 层 | 判断 |
|---|---|
| 表层诉求 | 增加字段、统一三列、显示 6 个菜品、扩充导出 |
| 真实目标 | 让后台运营能在一个入口核对订单人、组织、档口、取餐、菜品和金额,并导出同口径追溯证据 |
| 不做代价 | 详情继续缺字段;历史人员信息可能随当前资料变化;多菜品导出无法逐项核对 |
| 错误方案 | 仅扩大弹框或把多个菜品名称拼在一个单元格;都不能解决字段合同和逐菜品追溯 |
| 结论 | 真需求;技术上是中等复杂度的前后端 + 异步导出改造 |
4. 范围与非目标
4.1 In Scope
- PC「订单管理 > 消费订单 > 查看」现有弹框。
POST /p/mealOrder/detail的兼容性增量响应。- 堂食、线上订餐自提、取餐柜、外部订单和其他现有来源的字段显隐。
- 菜品表 8 列、六行直显、弹框整体滚动和金额区。
POST /p/mealOrder/export的type=1异步 XLSX 内容。- 订单与菜品一对多拆行、中文枚举、空值、金额与时间格式。
- 现有菜单权限、餐厅范围、部门范围和租户范围不扩大。
4.2 Out of Scope
- 不改为独立详情页,不改变消费订单列表入口、筛选器和关闭方式。
- 不新增详情编辑、退款、补打以外的操作。
- 不改变订单、退款、营销策略、支付和取餐柜状态流转。
- 不将异步
.xlsx改成 CSV,不改其他type=2-9报表。 - 不修改同步导出路径。
- 不在本需求中补历史业务数据,除非产品确认快照迁移口径。
- 不把
VWCG-1078补打小票能力作为本需求新增内容;只要求布局改造后按钮继续可用。
5. 当前系统证据与差距
| 链路 | 当前事实 | 差距 / 处理 |
|---|---|---|
| PC 弹框 | consume/index.vue 中字段按行硬编码 |
改为字段配置数组 + 三列 CSS Grid;空值过滤后自动补位 |
| 弹框尺寸 | el-dialog 未指定宽高 |
建议宽度 80vw、最大宽度约 1200px、顶部 4vh;以原型和实测再微调 |
| 菜品滚动 | el-table max-height="250",图片 90×90 |
移除表格固定 250px;图片压到 56×56 或经视觉确认的等效尺寸;滚动归弹框 body |
| 用户/手机 | 页面读 orderDetail.user.name/mobile,为当前用户资料 |
后端返回快照优先的展示字段:订单快照非空优先,当前用户资料只作兼容回退 |
| 原/当前部门 | Logic 已返回 department_attribution |
原部门用订单快照;当前部门明确为实时组织关系,不承诺历史不变 |
| 档口 | 订单只有 restaurant_id,列表/打印实时查餐厅 |
无名称快照;需确认采用实时回退还是新增快照字段 |
| 普通自提地址 | 可从当前档口 location 查询 |
没有订单地址快照;不满足“配置变化后历史不变”的强验收 |
| 取餐方式 | restaurant_method 已有 1/2/4 |
详情和导出需统一中文 堂食/自提/取餐柜,非法值输出空 |
| 取餐号 | 独立表 meal_order_pickup.pickup_no |
详情与导出需批量关联;禁止逐订单 N+1 查询 |
| 取餐柜 | 主表已有编号、地址快照、状态、格口和时间 | 增加中文状态和默认时间清洗;名称只能实时查设备,编号可直接用快照 |
| 订单状态 | 列表已有统一状态映射,详情由前端根据列表行临时推断 | 将统一状态文本放入详情 DTO,避免列表行过期或算法不一致 |
| 金额 | 列表已有订单金额、优惠、计算后实付 | 详情复用相同金额函数,统一两位小数;不能直接混用 total_price/pay_price |
| 导出 | exportOrdersToFile 以订单为一行、ID 游标每批 1000、流式写 XLSX |
增加批量菜品查询与逐菜品写行;订单合计只累计一次 |
| 权限 | 详情有对象级校验;提交导出时收窄部门/餐厅,执行时重放餐厅权限 | 不改变订单集合;建议补回归测试证明新增 join 不扩大范围 |
6. 总体设计
flowchart LR
A["消费订单列表"] -->|"查看 orderId"| B["/p/mealOrder/detail"]
B --> C["订单主表与用户兼容回退"]
B --> D["档口 / 取餐号 / 取餐柜字段"]
B --> E["菜品明细"]
C --> F["详情展示 DTO"]
D --> F
E --> F
F --> G["配置驱动三列弹框"]
A -->|"按当前筛选导出"| H["/p/mealOrder/export type=1"]
H --> I["export_log"]
I --> J["ExportMealOrder"]
J --> K["订单游标批次"]
K --> L["批量查询菜品并按 order_id 分组"]
L --> M["XlsxStreamWriter 逐菜品写行"]
设计原则:
- 不改变现有详情路由和权限入口,只增加兼容字段。
- 页面只消费后端给出的稳定展示值,不在前端复制业务枚举和金额算法。
- 详情与导出共用字段标准化方法,避免两个口径再次分叉。
- 导出继续流式写入;批量查菜品,不把全量订单或全量输出行放进内存。
- 所有新增字段为空时输出空字符串,页面不占位,Excel 不出现内部值。
7. UC-MEAL-ORDER-DETAIL-001:查看完整订单详情
7.1 概要
- 主要角色:拥有消费订单菜单及相应数据范围的 PC 管理员。
- 触发:在消费订单列表点击某一订单的「查看」。
- 目标:在一个弹框内核对订单、组织、档口、取餐、金额和全部菜品。
- 成功后置:不修改任何业务数据;弹框展示该订单权限范围内的有效信息。
- 失败后置:订单数据不变;展示明确失败提示,关闭后可重试。
7.2 主流程
| 步骤 | 动作 / 系统响应 | 页面 / API | AC |
|---|---|---|---|
| M1 | 管理员在列表点击查看 | PAGE-ORDER-DETAIL-01 |
AC-D01 |
| M2 | 前端清空上一个订单状态、打开加载态并请求当前 orderId |
/p/mealOrder/detail |
AC-D02 |
| M3 | 后端校验登录、菜单、餐厅和人员数据权限 | Controller 既有校验 | AC-D03 |
| M4 | 后端读取订单、菜品、取餐号、档口及取餐柜相关字段并生成展示 DTO | Logic | AC-D04 |
| M5 | 前端过滤空值,按字段顺序自动排成三列;金额独立一行 | Vue | AC-D05 |
| M6 | 六个菜品直接可见;更多菜品由弹框内容区整体滚动 | Vue/CSS | AC-D06 |
7.3 分支、异常与恢复
| ID | 条件 | 行为 | 恢复 |
|---|---|---|---|
| A1@M4 | 堂食,无取餐字段 | 隐藏取餐号、时段、地址和柜机字段,后续字段自动补位 | 正常结束 |
| A2@M4 | 线上自提 | 展示取餐方式、取餐号、日期、时段和地址 | 正常结束 |
| A3@M4 | 取餐柜 | 展示编号、快照地址、格口、中文取餐状态、入柜/实际取餐时间 | 正常结束 |
| A4@M4 | 外部/其他订单字段缺失 | 只展示可证明的有效字段,不填 -- 占格 |
正常结束 |
| E1@M3 | 无权限或订单越权 | 后端拒绝,不返回订单内容 | R1 关闭弹框或选择有权限订单 |
| E2@M4 | 订单不存在/已删除 | 返回业务失败,前端显示错误并停止渲染 | R2 刷新列表后重试 |
| E3@M2 | 网络失败、超时或快速切换订单 | 保留当前请求序号防止旧响应覆盖新订单 | R3 重试当前订单;不得展示上一单数据 |
| E4@M4 | 枚举非法或默认时间 2000-01-01... |
输出空字符串,不向用户显示内部值 | R4 记录测试缺口,数据治理另行处理 |
7.4 业务规则
BR-D01:姓名/手机号优先级为meal_order.user_name/user_mobile非空值 → 当前用户关联值 → 空。BR-D02:原部门来自origin_department_name快照;当前部门来自当前组织关系,两者语义不可互换。BR-D03:订单状态复用列表统一状态映射;不再由前端仅根据支付状态推断。BR-D04:取餐方式1=堂食、2=自提、4=取餐柜;未知值为空。BR-D05:取餐柜状态0=不适用、1=未存餐、2=已存餐、3=已取餐、4=已撤销;0 不展示。BR-D06:金额统一两位小数并带人民币符号;实付金额复用列表mealOrderPayAmount口径。BR-D07:空值定义为null、空字符串、仅空白、默认零日期;金额0.00是有效值,不隐藏。BR-D08:详情为只读,不新增审计写操作;权限失败继续由现有安全日志链路处理。
8. 详情接口设计
8.1 兼容策略
保留现有 data 原字段和 goods 结构,新增 display 对象;旧前端仍可运行,新前端逐步切换到 display。不删除或改名既有字段。
建议响应增量:
{
"display": {
"user_name": "张三",
"user_mobile": "138****0000",
"order_status_text": "已完成",
"order_no": "260907194900001",
"order_type_text": "在线订单",
"order_source_text": "AI运动营养师订餐订单",
"trade_time": "2026-09-07 19:49:14",
"original_department_name": "校本部",
"current_department_name": "校本部",
"restaurant_name": "汁内实烧店",
"meal_times_text": "晚餐",
"pickup_method_text": "自提",
"pickup_no": "004",
"pickup_date": "2026-09-07",
"pickup_time_range": "19:30-20:00",
"pickup_address": "二层东侧取餐区",
"locker_code": "",
"locker_cell_no": "",
"locker_status_text": "",
"locker_store_time": "",
"locker_pickup_time": "",
"order_amount": "33.90",
"discount_amount": "0.00",
"pay_amount": "33.90"
}
}
说明:手机号是否脱敏沿用当前后台权限政策;本需求不能自行改变。如果当前页面本来允许明文,新增 DTO 先保持现状,另行评审字段级脱敏。
8.2 查询策略
- 主订单继续由模型详情读取,并保留 Controller 对
orderId的对象级权限校验。 - 取餐号一次查询
meal_order_pickup,字段限制为pickup_no/prepare_status/...。 - 档口一次查询
restaurants,字段限制为name/location;只有产品接受“当前配置回退”时才可作为历史显示值。 - 取餐柜名称如需展示,可按
locker_code查询当前设备;订单已保存编号和地址快照,因此名称为空时仍可展示编号。 - 菜品继续使用订单明细快照字段;虚拟
custom_dish/package_fee沿用当前配置映射。
8.3 建议文件落点
| 层 | 文件 | 调整 |
|---|---|---|
| Controller | application/p/controller/MealOrder.php |
路由与权限不变;只返回扩展后的详情 |
| Logic | application/p/logic/MealOrder.php |
新增详情 DTO、枚举/时间/金额标准化、取餐号和档口查询 |
| Model | application/common/model/meal/Order.php |
原关系兼容保留;如有必要扩充明确字段,不把业务映射塞入 Model |
| Frontend | public/static/src/view/order/consume/index.vue |
字段配置、动态三列、金额行、六菜品布局、错误态 |
| Frontend test | public/static/test/unit/specs/consumeOrderDetail.spec.js |
字段优先级、显隐、六行、请求竞态、补打按钮兼容 |
| Backend test | tests/MealOrder/MealOrderDetailDisplayContractTest.php |
DTO、模式、枚举、空值、权限合同 |
9. 页面与交互设计
9.1 字段顺序
普通信息按下列顺序过滤空值后进入三列:
- 用户、手机号、订单状态。
- 订单编号、订单类型、订单来源、交易时间。
- 原部门、当前部门、档口、餐次。
- 取餐方式、取餐号、取餐日期、取餐时段、取餐地址。
- 取餐柜编号、格口、取餐状态、入柜时间、取餐柜取餐时间。
金额固定为底部三列:订单金额、优惠金额、实付金额;实付金额使用更高字重,不用新增主题色。
9.2 尺寸与滚动
- 验收视口:至少覆盖
1366×768和1920×1080,浏览器缩放 100%。 - 弹框建议:宽
80vw、max-width: 1200px、margin-top/top: 4vh;最终值以实际 Element UI 渲染截图为准。 - 弹框 body 负责纵向滚动;表格取消
max-height=250,避免内外双滚动条。 - 菜品图片建议 56×56,行高控制在约 64px;如果视觉坚持 90×90,则 1366×768 下无法同时满足六行直显,必须二选一并回到产品确认。
- 表头随内容滚动时应保持清晰;如使用 sticky,必须验证 Element UI 表头和横向滚动兼容。
- 加载期间显示 skeleton/loading;失败时不得残留上一订单字段或菜品。
9.3 与 VWCG-1078 的并行冲突
当前 develop_VWCG-1078_0908 已修改同一个 Vue 组件和 MealOrder Controller/Logic,并在详情 footer 增加补打按钮。VWCG-1334 应在 VWCG-1078 合入目标分支后再切分支,或在开发前语义合并,确保:
- 补打按钮的可见性、禁用态和确认流程保留。
- 请求序号防竞态逻辑保留。
- 详情弹框滚动后 footer 按钮仍可操作。
- 不用整文件覆盖方式解决冲突。
10. UC-MEAL-ORDER-EXPORT-002:按菜品明细导出消费订单
10.1 主流程
| 步骤 | 动作 / 系统响应 | 对象 | AC |
|---|---|---|---|
| M1 | 管理员在消费订单列表按当前筛选提交导出 | /p/mealOrder/export type=1 |
AC-E01 |
| M2 | Controller 将筛选条件与授权餐厅/部门范围写入 export_log |
DATA-EXPORT-01 |
AC-E02 |
| M3 | Cron 领取一条任务并重放权限 | ExportMealOrder |
AC-E03 |
| M4 | Logic 以订单 ID 游标读取一批订单 | ydy_meal_order |
AC-E04 |
| M5 | 按本批 order IDs 一次查询菜品和取餐号并分组 | initial_menu/meal_order_pickup |
AC-E05 |
| M6 | 每条菜品写一行,重复订单字段;无菜品订单写一条空菜品行 | XlsxStreamWriter |
AC-E06 |
| M7 | 订单合计只累计一次,写合计行后原子完成文件 | XLSX | AC-E07 |
| M8 | 导出日志显示成功并提供下载 | export_log |
AC-E08 |
10.2 分支、异常与恢复
| ID | 条件 | 行为 | 恢复 |
|---|---|---|---|
| A1@M6 | 一单多菜品 | 按明细稳定顺序逐行写;订单字段每行相同 | 正常结束 |
| A2@M6 | 订单无菜品 | 保留一条订单行,菜品列为空,避免订单静默丢失 | 正常结束 |
| A3@M6 | 非取餐柜订单 | 取餐柜列为空 | 正常结束 |
| E1@M3 | 权限已变化 | 以执行时重放后的交集收窄,不扩大订单集合 | 重新提交合法范围 |
| E2@M5 | 查询/写文件失败 | abort() 清理临时文件,任务失败,不留下可下载的半文件 |
修复后重新提交 |
| E3@M6 | 预计输出超过单 Sheet 上限 | 禁止截断;按确认方案拆 Sheet 或在提交前阻断并提示缩小范围 | 用户缩小筛选或启用多 Sheet |
| E4@M6 | 菜名为空/虚拟菜品 | 使用订单时可证明的名称或现有虚拟映射;仍为空则输出空,不输出 UUID 代替名称 | 数据治理另行处理 |
10.3 业务规则
BR-E01:导出订单集合与列表同筛选、同权限;新增菜品 join 不能增加或减少订单。BR-E02:输出顺序先按订单id DESC,同订单菜品按明细id ASC,保证重复导出稳定。BR-E03:一条菜品明细一行;订单字段在同订单各行重复。BR-E04:底部订单金额、优惠、实付和订单数只按订单累计一次;菜品数量/金额可按明细累计。BR-E05:所有金额两位小数;时间为YYYY-MM-DD HH:mm:ss,日期为YYYY-MM-DD,默认零日期输出空。BR-E06:枚举输出中文,不输出数字枚举、null或undefined。BR-E07:保持.xlsx、导出日志、OSS/本地文件行为和原子完成语义。BR-E08:禁止全量select()->toArray()、N+1 明细查询和先积累全部$rows再写。
11. XLSX 字段合同
建议表头:
| 分组 | 字段 |
|---|---|
| 订单基础 | 序号、订单编号、用户、手机号、订单状态、订单类型、订单来源、交易时间 |
| 组织与档口 | 原部门、当前部门、档口、餐次 |
| 取餐信息 | 取餐方式、取餐号、取餐日期、取餐时段、取餐地址、取餐柜编号、格口、取餐状态、入柜时间、取餐柜取餐时间 |
| 菜品明细 | 菜品名称、重量(克)、单价(元/单位重量)、数量(份)、消费日期、菜品金额(元) |
| 金额信息 | 订单金额(元)、优惠金额(元)、实付金额(元) |
说明:
- 原需求同时出现两个“取餐时间”。文档建议把计划窗口命名为「取餐时段」,实际柜机完成时间命名为「取餐柜取餐时间」,避免重名列。
- 「订单类型」建议映射
order_type(在线/离线),「订单来源」映射source(绑盘机、消费机、线上订餐、外部订单等);这是 P0 待确认。 - 重量建议使用订单明细
weight表示本行实际重量;单价展示dishes_price / dishes_weight的既有口径。字段语义需用样例订单回读确认。 - 多菜品行重复订单金额是需求明确行为,直接在 Excel 中汇总该列会重复计算;文件底部合计必须由程序按订单累计,不以输出行求和。
12. 导出实现策略
建议继续修改 application/p/logic/MealOrder.php::exportOrdersToFile,不改 ExportMealOrder 的任务调度结构:
- 订单查询继续使用
meal_order.id倒序游标,批次大小先沿用 1000。 - 每批收集
order_id,一次查询:- 菜品明细 + 菜品名称/图片所需字段;
- 取餐号;
- 必要的档口、设备与当前部门映射。
- 在批次内按
order_id分组,不跨批次持有历史对象。 - 遍历订单时先累计一次订单合计,再遍历该订单菜品写行。
- 无菜品时写一条空菜品行,保证订单集合不丢失。
finish()成功后才暴露最终文件;异常执行abort()。
若新增普通自提/档口快照字段:
- SQL 应使用正式产品版本号命名,本轮不猜版本号。
- 新字段建议语义明确,例如
restaurant_name_snapshot、pickup_address_snapshot,不复用含义不清的现有列。 store、ai_api和其他写ydy_meal_order的订单生产端都要补写;旧订单只能按确认规则回退当前配置或保留空,不能伪造历史值。- 回滚时先回滚读取逻辑到兼容回退,再回滚生产端;不要先删字段造成旧代码报错。
13. 权限、安全与隐私
- 详情继续经过
checkLogin、消费订单菜单权限和assertOrderRestaurantPermission,不能只靠前端隐藏。 - 导出提交继续调用
resolvePermittedRestaurantIds/resolvePermittedDepartmentUuids;Cron 执行仍重放权限。 - 新增 join 必须从已授权订单 ID 出发,不得先查询全量菜品再在应用层过滤。
- 手机号属于敏感字段;本需求保持既有后台展示政策,不新增更大数据范围。是否脱敏需由现有角色权限政策决定。
- 日志只记录订单 ID、任务 ID、行数、耗时和错误类型;不得输出手机号、姓名、完整订单内容或 XLSX 行。
- 本需求无写业务数据、幂等和事务状态变更;异步导出领取与文件原子完成沿用现有机制。
14. 测试与验收矩阵
| Test ID | 层级 | 场景 | 通过条件 |
|---|---|---|---|
API-D01 |
后端契约 | 快照姓名/手机号存在 | DTO 优先快照,不读取后改名值 |
API-D02 |
后端契约 | 快照为空 | 合法回退当前用户;均空则返回空字符串 |
API-D03 |
后端契约 | 堂食/自提/取餐柜/外部订单 | 枚举中文正确,不适用字段为空 |
API-D04 |
后端契约 | 取餐柜 0-4 状态、默认时间 | 状态/时间清洗正确 |
SEC-D01 |
权限 | 无菜单、无餐厅、无人员权限 | 详情拒绝且无字段泄漏 |
UI-D01 |
前端单测 | 空字段混排 | 不占空位,顺序稳定,金额 0.00 不隐藏 |
UI-D02 |
前端单测 | 快速连续查看两单 | 旧响应不能覆盖新订单 |
UI-D03 |
前端单测 | VWCG-1078 合并后 |
补打按钮和 loading/disabled 行为不回归 |
VIS-D01 |
浏览器 | 1366×768、100% | 6 行菜品直接可见,无表格内部纵向滚动 |
VIS-D02 |
浏览器 | 1920×1080、10+ 菜品 | 弹框整体滚动,表头/金额/footer 可辨与可操作 |
EXP-E01 |
后端单元 | 1 单 3 菜 | 输出 3 行,订单字段相同,菜品字段各自正确 |
EXP-E02 |
后端单元 | 订单无菜品 | 输出 1 条空菜品行,不丢订单 |
EXP-E03 |
后端单元 | 虚拟菜品/打包费 | 按确认口径输出,不出现空名称或内部 UUID |
EXP-E04 |
后端单元 | 多订单多菜 | 排序稳定;订单合计不因拆行重复累计 |
EXP-E05 |
文件 | 生成 XLSX | unzip -t 通过;表头、中文、列数和行数正确 |
SEC-E01 |
集成 | 筛选 + 餐厅/部门权限 | 导出订单 ID 集合与同条件列表一致 |
PERF-E01 |
性能 | 建议 20 万订单、平均 3 明细 | 约 60 万明细行,无 OOM、无持续内存增长;时限待确认 |
BOUND-E01 |
边界 | 预计超过 1,048,574 数据行 | 不截断;按已确认的多 Sheet/阻断策略处理 |
建议验证命令(BUILD 后执行):
vendor/bin/phpunit tests/MealOrder/MealOrderDetailDisplayContractTest.php
vendor/bin/phpunit tests/MealOrder/MealOrderDetailExportTest.php
vendor/bin/phpunit tests/DataPermission/ChangedInterfacesPermissionCoverageTest.php
vendor/bin/phpunit tests/Security/SecurityFixesTest.php
cd public/static && npm run unit -- consumeOrderDetail.spec.js
cd public/static && npm run build
unzip -t <generated-consume-order-file>.xlsx
还需在隔离测试环境按同一筛选调用列表与导出,比较唯一订单 ID 集合、订单数、菜品明细数和金额合计;只做文件能打开不算通过。
15. Definition of Ready 与待确认项
当前 DoR: BLOCKED。以下 P0 项关闭后才能进入开发:
| ID | P0 问题 | 推荐答案 | 影响 | 建议负责人 |
|---|---|---|---|---|
Q-001 |
普通自提地址和档口名称是否要求历史完全不随配置变化? | 若“是”,新增订单快照字段并联动所有生产端;旧单只允许明确回退或留空 | 决定是否跨 store/ai_api、是否有 SQL |
产品 + 后端 |
Q-002 |
「订单类型」和「订单来源」是否分别对应 order_type 在线/离线与 source 生产来源? |
采用该映射,并给出历史非法值为空 | 决定详情/导出列语义 | 产品 |
Q-003 |
custom_dish、package_fee 是否作为菜品明细行导出? |
页面已有虚拟项;建议保留行,打包费同时增加订单级列时需另确认 | 决定金额对账和明细行数 | 产品 + 财务/运营 |
Q-004 |
展开后超过单 Sheet 上限如何处理? | 优先按多个 Sheet 无损导出;若本期不做,提交前明确限制并提示缩小范围 | 决定 XLSX Writer 扩展和工期 | 产品 + 测试 |
P1 建议确认:
- 手机号是否继续明文,还是按角色脱敏。
- 20 万订单/60 万明细的性能样本、峰值内存和最长完成时间。
- 取餐柜“名称或编号”是否只展示订单快照编号即可;设备名称当前不是快照。
- 1366×768 下图片最终尺寸是 56px 还是 64px。
16. 开发切片与估时
以下为单人净开发估时,不含产品待确认、排队、真实大数据准备和上线窗口:
| 切片 | 内容 | 估时 |
|---|---|---|
| S1 | 详情 DTO、取餐号/档口/状态/金额标准化、后端测试 | 1.5-2.5 人日 |
| S2 | Vue 动态字段、三列布局、六行与整体滚动、前端测试 | 1.5-2.5 人日 |
| S3 | 异步导出逐菜品拆行、批量查询、去重合计、XLSX 测试 | 2.5-4 人日 |
| S4 | 权限/列表-导出集合对比、四模式数据、构建与视觉验收 | 1.5-2.5 人日 |
| 合计 | 不新增快照字段 / 单 Sheet 受控策略 | 7-11 人日 |
| 可选增量 | 新增普通自提/档口快照,联动订单生产端和迁移 | 另加 3-6 人日 |
| 可选增量 | XlsxStreamWriter 多 Sheet 支持和容量测试 |
另加 2-4 人日 |
进入 BUILD 后建议顺序:先锁定字段合同和测试数据,再完成详情端到端,随后改导出;不要先做 CSS 再补接口和快照。
17. 发布、兼容与回滚
- 发布顺序:兼容性后端/SQL(如有)→ 订单生产端写快照(如有)→ PC 前端 → 导出 Cron → 回归与灰度观察。
- 无 SQL 方案:可回滚 Vue 和 Logic;新增响应字段不影响旧前端。
- 有 SQL 方案:字段先加后用;回滚先停用新读取与写入,再评估删列,默认不在紧急回滚中删数据列。
- 导出失败时保持
export_log失败态,不提供半文件;旧已完成文件不重写。 - 重点观察:详情失败率、导出任务失败率、平均/峰值耗时、输出行数、峰值内存、超过行数上限次数。
18. 追踪矩阵
| UC / 步骤 | 页面 | API / 任务 | 数据 | AC / Test | 目标文件 |
|---|---|---|---|---|---|
DETAIL/M1-M2 |
消费订单/详情弹框 | /p/mealOrder/detail |
orderId |
UI-D02 |
consume/index.vue |
DETAIL/M3-M4 |
加载/失败态 | 详情权限与 Logic | 订单、用户、档口、取餐号、柜机 | API-D01-D04, SEC-D01 |
Controller/Logic/Model |
DETAIL/M5-M6 |
三列/菜品表 | 详情响应 | display/goods |
UI-D01-D03, VIS-D01-D02 |
consume/index.vue |
EXPORT/M1-M3 |
列表/导出日志 | /export + Cron |
export_log/query_conditions |
AC-E01-E03, SEC-E01 |
Controller/Cron |
EXPORT/M4-M7 |
[不适用:后台任务] | exportOrdersToFile |
订单、菜品、取餐、XLSX | EXP-E01-E05, PERF-E01, BOUND-E01 |
Logic/XlsxStreamWriter |
EXPORT/M8 |
导出日志 | /exportLogs |
文件路径、状态 | AC-E08 |
既有链路回归 |
19. 评审结论
- 产品:需求方向成立,但需关闭
Q-001至Q-004。 - 前端:同一弹框可以实现,不需要新页面;六菜品目标要求同时调整图片/行高和滚动容器。
- 后端:现有详情路由和导出调度可复用;需要新增稳定 DTO 与批量明细导出。
- 数据:取餐柜和原部门已有快照;普通自提地址、档口名称没有快照,不能在文案层宣称完全历史一致。
- 测试:必须按四消费模式、权限、空值、请求竞态、多菜品拆行、XLSX 容量和
VWCG-1078兼容做专项回归。 - 云效:当前正文没有 AI 可执行 Use Case 标记;本轮没有外部写授权,因此未回写。若要进入开发,应先把本文两个 UC 的精简正文同步到
VWCG-1334并通过 OpenAPI 回读。
20. 证据与人审
- 原始需求:
raw-request.md - 任务契约:
task-contract.md - 云效与系统证据:
yunxiao-read-evidence.md - 原型:
evidence/pc-consume-order-detail-layout-prototype.png - 本地登录阻塞:
evidence/local-login-blocker.png - HTML 人审页:
technical-development-design.html - 人审状态:待产品、前端、后端和测试共同评审。