# 前端提醒后端待补接口 ## 1. 文档定位 本文记录前端页面开发时希望后端新增、补齐或稳定的接口草案。本文中的路径、入参和返参是前端视角的最小诉求,不代表后端已经承诺实现;进入开发前需要后端按当前包结构、权限、安全和业务规则二次确认。 ## 2. 当前待补接口总览 | 优先级 | 接口 | 页面 / 场景 | 状态 | | --- | --- | --- | --- | | P0 | 订单列表接口 `GET /api/reservation/orders` | 订单列表页、首页工作台 | 已完成第一版 | | P0 | 任务列表接口 `GET /api/reservation/tasks` | 任务列表菜单、订单详情任务入口 | 已完成第一版,已补来源邮件会话字段和 `order_status` 筛选 | | P0 | 订单详情接口 `GET /api/reservation/orders/{orderId}` | 订单详情页 | 已完成第一版,已补旧 `tasks[]` 来源邮件会话字段和 V4 `order_overview` / `next_v4_action` / `related_source_messages[]` / `v4_order_tasks[].cards[]`,前端订单详情总览页已接入 | | P0 | 任务详情读取接口 `GET /api/reservation/tasks/{taskId}` | 任务详情页动态渲染 | 已完成第一版,已补来源邮件字段和 3.0 字段元数据 | | Done | V4 订单任务详情接口 `GET /api/reservation/order-tasks/{orderTaskId}` | V4 任务详情页 | 已完成第一版;页面展示顺序调整为 Basic Information、业务卡、SourceMessage Display,来源邮件正文通过 SourceMessage conversation 接口读取当前触发邮件 | | P0 | 任务详情操作接口 | 任务详情保存、确认、OPERA、审计 | 已完成;前端可直接接入 | | P0 | 邮件会话详情接口 `GET /api/source-messages/{sourceMessageId}/conversation` | 邮件会话详情页 | 已完成第一版 | | 联调 | 演示数据 seed 接口 `POST /api/system/reservation/demo-data` | 本地 / test 前端页面看效果 | 已完成;仅 dev/test 受控使用 | | 联调 | Debug EML 上传接口 `POST /api/system/debug/eml-superagent-runs` | Debug 页面上传 `.eml` 看 SuperAgent 结果 | 已完成第一版;仅 dev/test 受控使用 | | Done | Rooming List Excel 生成接口 `POST /api/reservation/rooming-lists/generations` | 房表生成页面 | CP1 已完成;CP2 已实现旅游日期派生、Adults 自动计算和目标默认值字段收口 | | P1 | S10/S99 源邮件只读通知卡与旧 S000/S999 兼容 | 任务列表、任务详情来源邮件查看 | 已完成第一版:旧 S000/S999 兼容,新结构化 S10/S99 可入站并在任务列表 / 详情只读展示 | | P1 | type-known manual review 同卡复核解阻 | 任务详情复核 | 已完成第一版:原业务任务卡复核、字段修正、订单归属确认、READY 流转 | | P1 | 任务卡前端字段白名单元数据接口 | 字段白名单调试、版本对齐 | 未完成;若任务详情已透出完整元数据,可后置 | | P1 | 系统管理菜单树增强接口 | 系统设置 / 菜单管理树形交互 | 已完成:完整菜单树查询、批量保存父级和排序 | | Done | V4 目录 Lookup API | V4 Basic Information、Room Type、Rate Code 选择 | M002 V4 CP11 已实现 Account / Room Type / Rate Code 数据库目录 lookup;设计与实现说明见 `../requirements/M002-v4-real-catalog-lookup-api-design.md` | | 后置 | 普通任务切换订单接口 | 任务详情订单归属调整 | 未完成;已确认后置 | ## 2.1 后端当前接口完成度核对 本节按 2026-07-08 当前后端 Controller 和 result record 核对,避免重复要求后端实现已经存在的接口。 | 接口 / 能力 | 当前后端状态 | 前端是否可直接接入 | 仍需后端处理 | | --- | --- | --- | --- | | `GET /api/reservation/tasks` | 已完成第一版,已补来源邮件会话字段和所属订单状态筛选 | 可以 | `order_status` 按任务所属订单状态过滤;不传时保持当前全部任务列表行为。 | | `GET /api/reservation/orders/{orderId}` | 已完成第一版,已补旧 `tasks[]` 来源邮件会话字段、V4 总览和 V4 `v4_order_tasks[]` 时间线,前端订单详情总览页已接入 | 可以 | 暂无;`include_tasks=false` 时旧 `tasks[]`、V4 `v4_order_tasks[]` 和 `related_source_messages[]` 都返回空数组,`order_overview` 为空快照,`next_v4_action.action_type=NONE`。 | | `GET /api/reservation/tasks/{taskId}` | 已完成第一版,已补任务顶层来源邮件字段和 `fields[]` 3.0 元数据 | 可以 | 当前 Controller 不接收 `hotel_id`;如后续多酒店隔离需要前端显式传酒店上下文,请后端补可选入参或确认按 taskId 全局唯一即可。 | | `GET /api/reservation/order-tasks/{orderTaskId}` | 已完成第一版;Room Information 后端展示模型已补齐且前端业务化展示已接入;Rooming List 确认自动 DEF 后端联动已完成;复核态字段白名单第一版已随 `fields[]` 返回;Payment 附件安全摘要已补齐;Trace 后端稳定字段契约已收口 | 可以;Room Information 前端业务化展示已完成,Rooming List 轻量确认可继续进入前端业务化展示,Payment 预览可基于后端安全摘要继续联动,Trace 专属卡可按 `fields[]` 接入 | V4 任务详情页展示顺序为 Basic Information、业务卡、SourceMessage Display;Trace 卡普通事项内容字段统一为 `trace_items[].text`,不要使用或提交 `content`;`GENERAL` 可编辑 `/trace_items/{index}/text`、`/trace_items/{index}/department_code`,`EXTRA_BED` 可编辑 `/trace_items/{index}/target_room_type_code`、`/trace_items/{index}/extra_bed_room_count`、`/trace_items/{index}/department_code`;`department_code` 第一版固定为 `FO` / `HSK` / `FO+HSK` 三个下拉值,不调用 Department lookup,不开放自由输入,对应字段返回 `options_source=reservation_v4_trace_department_fixed` 和 `fixed_options[]`;`target_room_type_code` 使用 Room Type lookup 且只校验当前酒店目录存在,`extra_bed_room_count` 为正整数。Room Information 已由后端返回 `display_payload.room_information`:New 展示最终值,Update 展示 `current_values`、`proposed_values`、`final_values` 和 `change_summary[]`,Cancel 展示本地订单投影只读;Nights 后端按酒店本地日期派生,Breakfast 前端为含早勾选框,Group Booking Status 显示 `TEN-Tentative` / `DEF-Definite` / `INQ-Inquiry`;New Booking 最终订单投影字段 `group_block_name` / `fit_name` 可编辑,默认值可来自 Agent `target_order`,但 Agent 原始 `target_order` 不在普通 `display_payload` / `confirmed_payload` 中暴露,也不被用户编辑回写。`fields[]` 中 Room Information 字段统一使用 `/room_information/final_values/...`,确认 payload 和复核 `field_overrides[]` 均优先使用这些 pointer;`write_target=confirmed_payload` 是前端请求体语义,不是后端表字段名。`REVIEW_REQUIRED` 仍是原业务卡复核态,问题字段红字提示,按钮统一显示“确认卡片”,前端内部调用 `review-resolution`,并以 `fields[].editable` 渲染当前卡白名单字段,不只渲染 missing/error 字段。Rooming List 卡第一版只做事项确认,前端展示标题、状态、目标订单信息和“确认卡片”按钮,不做名单 rows、附件预览、Excel 生成或 PMS 导入;确认 `ROOMING_LIST` 后,如同订单为 Group,后端会自动把已确认 Room Information 快照中的 Group Booking Status 置为 `DEF`,后续刷新任务详情的 `display_payload` 和 `confirmed_payload` 都会显示 DEF,不需要前端自行提交或计算该状态,并可通过订单任务审计看到 `V4_ROOMING_LIST_AUTO_DEF`;当前订单详情 `order_overview` 不返回 Group Booking Status 字段。本接口仍不直接返回邮件正文或附件 URL。来源邮件卡正文限定为当前触发该 V4 order task 的那封 SourceMessage 正文,前端用 `source_message_summary.source_message_id` 调用 `GET /api/source-messages/{sourceMessageId}/conversation` 后定位当前邮件,默认长度折叠并可展开;缺少 `SOURCE_MESSAGE_ORIGINAL_READ` 或会话接口失败时降级展示安全摘要。Payment 卡已返回 `payment_attachments[]` 安全摘要,供前端展示图片缩略图 / 非图片文件列表;`attachment_ids[]` 第一版只读,不支持前端增删、替换或重新选择附件集合;实际大图预览和下载 URL 仍走 SourceMessage conversation。 | | `PUT /api/reservation/tasks/{taskId}/draft` | 已完成 | 可以 | 当前 Controller 不接收 `hotel_id`;如写操作需要酒店上下文幂等 / 权限校验,请后端补可选入参或请求体字段。 | | `POST /api/reservation/tasks/{taskId}/confirm` | 已完成 | 可以 | 当前 Controller 不接收 `hotel_id`;如写操作需要酒店上下文幂等 / 权限校验,请后端补可选入参或请求体字段。 | | `GET /api/reservation/tasks/{taskId}/audits` | 已完成 | 可以 | 当前 Controller 不接收 `hotel_id`;如审计查询需要酒店上下文隔离,请后端补可选入参。 | | `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/execute` | 已完成第一版模拟操作 | 可以 | 暂无;真实 OPERA 写入另行确认。 | | `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/retry` | 已完成第一版模拟重试 | 可以 | 暂无;真实 OPERA 重试另行确认。 | | `POST /api/reservation/tasks/{taskId}/manual-review-conversions` | 已完成 | 可以 | 暂无。 | | `POST /api/reservation/tasks/{taskId}/manual-review-resolutions` | 已完成第一版 | 可以 | 只用于 type-known manual review;第一版 `confirmed_order_id` 必须等于当前任务订单,不开放普通任务任意切换订单。 | | `GET /api/source-messages` | 已完成安全摘要列表 | 可以 | 不能替代邮件会话全文接口。 | | `GET /api/source-messages/{id}` | 已完成单条安全摘要 | 可以 | 不能替代邮件会话全文接口。 | | `GET /api/source-messages/{id}/original` | 已完成单封原文权限读取 | 谨慎接入 | 必须带 Bearer token,需要同时拥有 `SOURCE_MESSAGE_READ` 和 `SOURCE_MESSAGE_ORIGINAL_READ`;只能读单封邮件,不能返回同一 conversation 全量邮件。 | | `GET /api/reservation/orders` | 已完成第一版 | 可以 | 默认查询全部订单状态;订单列表待处理展示使用 `open_work_item_count`;V4 普通业务已停止双写旧任务,旧 `open_task_count` 仅作为历史诊断计数。 | | `GET /api/source-messages/{sourceMessageId}/conversation` | 已完成第一版,已补 `html_body_sanitized` 和 `html_render_mode` | 可以 | 必须带 Bearer token,需要同时拥有 `SOURCE_MESSAGE_READ` 和 `SOURCE_MESSAGE_ORIGINAL_READ`;返回完整 text/html、后端清洗后的 HTML、媒体外链和关联订单 / 任务摘要;前端不传原文读取 key,页面展示优先使用 `html_body_sanitized`。V4 Payment 卡图片大图预览和非图片下载也复用该权限链路,只能使用当前触发 SourceMessage 且被 `attachment_ids[]` 引用的附件。 | | `POST /api/system/reservation/demo-data` | 已完成 | 仅本地 / test 联调可用 | 默认关闭,必须后端配置访问口令;不能作为生产页面接口。 | | `POST /api/system/debug/eml-superagent-runs` | 已完成第一版 | 仅 dev/test Debug 页面可用 | 默认关闭,必须后端配置访问口令、阿里云 OSS 和 SuperAgent Open API;Debug 服务自身只展示 SuperAgent 结果,不直接创建订单和任务;如 SuperAgent 通过正式回调 / MCP 写入业务结果,V4 smoke 必须创建 V4 order task / cards,不再创建旧 `workflow_reservation_task`;MCP submit 已收口为 M002 V4-only,旧 V2/V3 payload 会返回 `MCP_SUBMIT_V4_REQUIRED`;已能识别旧 S000/S999 和新结构化 S10/S99。 | | `GET /api/source-message-conversations/{externalConversationId}` | 未发现后端实现 | 不可以 | 历史讨论过的候选路径,当前不提供;前端统一使用 `GET /api/source-messages/{sourceMessageId}/conversation`。 | | `GET /api/reservation/message-notifications` | 未发现后端实现 | 不可以 | 历史候选路径,当前不提供。旧 S000/S999 和 V3 S10/S99 兼容数据通过 `SOURCE_MESSAGE_ONLY` 任务展示;V4 S10/S99 新数据走 V4 工作台和 `/api/reservation/source-notifications/{notificationId}`,不要再请求本候选路径。 | | `GET /api/reservation/task-card-field-whitelist` | 未发现后端实现 | 不可以 | 若任务详情 `fields[]` 已补齐 3.0 元数据,可后置。 | | `GET /api/reservation/lookups/accounts` / `room-types` / `rate-codes` | M002 V4 CP11 已实现;M002-V4-owner-rate-catalog-data-alignment 已收敛 Room Type / Rate Code 数据;2026-07-21 结论是 Rate Code 第一阶段暂不做 Account 范围过滤 | 可以 | 用于 V4 任务卡下拉 / 搜索选择;Bearer token + `RESERVATION_TASK_READ` + 酒店访问权;Account / Room Type / Rate Code 支持 `hotel_id`、`keyword`、`page_num`、`page_size`,只返回 ACTIVE 目录。Room Type 当前固定初始化为 `RM2`、`RM3`、`RM4`、`SU1`、`SU2`、`SU3`;Rate Code 当前按酒店级目录返回 OWNER RATE 40 个规范化 code;未来如新增 Account 适用关系,再由后端扩展 `account_code` / `booking_type` 过滤参数。 | ## 2.2 V4 工作台、订单详情和任务详情页用户化展示口径 2026-07-21 已确认:V4 工作台 / 任务列表、订单详情页和任务详情页默认面向普通酒店员工,不面向开发 / 测试。当前后端 `GET /api/reservation/workbench-items`、`GET /api/reservation/order-tasks`、`GET /api/reservation/orders/{orderId}` 和 `GET /api/reservation/order-tasks/{orderTaskId}` 已返回前端完成第一版用户化展示所需的业务数据、订单确认快照、下一步入口、`fields[]` 白名单、`availability`、来源邮件摘要和安全 payload;本 checkpoint 原则上不要求后端新增接口或改变入站 / 确认 / 复核模型。 前端下一轮 UX 重构应按以下口径实现: - 工作台 / 任务列表页面定位为“待处理预订事项列表”或“预订事项工作台”,不是“V4 模型工作台”。 - 任务列表默认视图优先展示待确认、需要复核、待确认已读的来源通知;已完成事项保留筛选入口,不作为默认工作队列。 - 任务列表普通筛选建议为“全部”“待处理”“需要复核”“已完成”“来源通知”。技术筛选如 `item_type`、`order_task_status`、`card_status`、`route_code`、`system_process_category` 可放入高级筛选或受控调试模式,不作为默认筛选文案。 - `ORDER_TASK` 用户可见文案为“预订事项”,`SOURCE_NOTIFICATION` 用户可见文案为“来源通知”或“需查看邮件”;新预订、修改预订、取消预订、付款凭证、跟进事项、房表事项等任务类型应显示业务名称,不直接展示内部 code。 - 列表行主动作使用“继续处理”“查看详情”“确认已读”等业务语言;空态使用“暂无需要处理的预订事项”,不显示内部模型空态。 - 订单详情页定位为“订单总览页”,不是 V4 时间线调试页;`order_overview` 显示为“当前确认快照”或“订单信息总览”,`next_v4_action` 显示为“下一步处理”,`related_source_messages[]` 显示为“关联来源邮件”,`v4_order_tasks[]` 显示为“处理记录”或“来源邮件处理记录”,`cards[]` 显示为事项状态摘要。 - 订单详情页标题优先显示订单业务名、Group Code、Confirmation Number 或用户可理解订单名称;不把数据库 `order_id`、V4 字段名、`order_task_id`、`card_id`、`source_message_id`、`action_type`、`action_status` 等作为主信息层级。订单详情不展示确认 / 复核按钮,所有办理动作仍跳转到任务详情页。 - 页面定位为“订单事项办理页”,不是“V4 任务卡模型调试页”。 - 主标题、顶部摘要和业务事项区域使用普通用户可理解文案,不直接展示 `V4`、Task Card 模型、`order_task_id`、`card_id`、`order_ref`、`source_event_index`、`version`、JSON Pointer、`write_target`、payload 字段名、`route_code` 或内部状态码。 - 技术字段可以继续用于路由、提交、并发校验、错误定位和自动化测试;确需展示时只能放在“技术信息”折叠区或受控调试模式,不得占据默认主信息层级。 - 用户可见业务名称建议:Basic Information = 预订基础信息;Room Information = 房型与日期 / 房型信息;Payment = 付款凭证;Trace = 跟进事项;Rooming List = 房表事项;SourceMessage Display = 来源邮件。 - 用户可见状态建议:`PENDING_CONFIRM` = 待确认;`REVIEW_REQUIRED` = 需要复核;`CONFIRMED` = 已确认;`RESOLVED` = 复核已完成;`OPEN` = 待处理;`COMPLETED` = 已完成。前端业务判断仍使用稳定 code,不使用展示文案反推状态。 - 顶部摘要应优先表达“这封邮件识别出了什么事项、当前还有什么要处理、下一步该点哪里”;已完成事项可以折叠为摘要,待处理和需复核事项应突出。 - 每张事项卡的主动作按钮放在该事项卡右侧,和状态同区域展示;移动端空间不足时可放到卡片底部右对齐。不要做页面底部统一确认按钮。`PENDING_CONFIRM` 和 `REVIEW_REQUIRED` 的用户可见主按钮都叫“确认卡片”,但前端内部仍按状态分别调用普通确认或 `review-resolution`。 - 来源邮件固定放在业务事项之后,默认折叠正文;正文、图片预览和非图片下载仍走 `GET /api/source-messages/{sourceMessageId}/conversation` 原文权限链路。 如果前端实现时发现现有接口不足,可单独向后端提出字段补充,例如用户友好的 `display_title`、任务级 `next_step_label`、业务摘要短句或调试区可见性标记;在提出前不得由前端自行展示 AI 原始 payload 或解析后端内部字段来补标题。 ## 3. 任务列表 / 工作台接口字段补齐 建议路径: ```text GET /api/reservation/tasks ``` 当前状态:后端已按 P0 最小诉求实现第一版,前端任务列表页可以直接接入该接口。接口已返回任务摘要、订单展示键、来源消息 ID / 主题、来源邮件会话摘要和实时可处理状态,不返回完整 AI payload、邮件正文或附件 URL。 本轮前端新增“任务列表”菜单,并且任务列表、订单详情任务队列都需要能跳转到该任务来源消息所在的完整邮件会话。因此建议在现有返回项上补齐来源邮件会话摘要字段。 默认排序:未传 `order_id` 时按来源消息接收时间倒序返回,保证任务列表最新消息 / 最新任务在前;传 `order_id` 时按同订单 `queue_sequence` 正序返回,保证订单队列处理顺序不被打乱。 已完成字段: | 字段 | 说明 | | --- | --- | | `task_id` | 任务 ID。 | | `order_id` | 关联订单 ID。 | | `hotel_id` | 酒店上下文 ID。 | | `display_order_key` | 前端优先展示的业务号或临时订单号。 | | `temporary_order_no` | 临时订单号。 | | `task_type` | 系统主任务类型。 | | `result_type` | AI 结果类型,例如 `normal_task`、`manual_review`、`source_message_review_notification`。 | | `ai_task_type` | SuperAgent 原始任务类型,例如 `New Booking`、`S10`、`S99`。 | | `task_subtype` | 任务 subtype。 | | `route_code` | M002 V3 路由码,例如 `R01_NEW_FIT_RESERVATION_NORMAL`、`S10`、`S99`。 | | `system_process_category` | 系统处理分类,例如 `BUSINESS_TASK`、`SOURCE_MESSAGE_NOTIFICATION`。 | | `task_status` | 任务状态。 | | `card_name` | 任务卡展示名称。 | | `queue_sequence` | 同订单队列顺序。 | | `queue_participation` | 是否参与订单执行队列。 | | `can_process` | 当前是否可处理。 | | `readonly_reason_code` | 只读原因代码。 | | `source_message_id` | 来源 SourceMessage Inbox ID。 | | `source_subject` | 来源消息主题摘要。 | | `created_at` | 任务创建时间。 | | `updated_at` | 任务更新时间。 | 建议入参: | 参数 | 必填 | 说明 | | --- | --- | --- | | `hotel_id` | 否 | 酒店 ID。单酒店阶段默认可为空,由后端按当前用户上下文或平台酒店表唯一 `ACTIVE` 酒店解析;显式传值时后端会校验访问权限。 | | `order_id` | 否 | 按订单过滤。 | | `task_type` | 否 | 当前旧任务列表筛选只提供 `NEW_BOOKING`、`UPDATE_BOOKING`、`CANCEL_BOOKING`、`MANUAL_REVIEW`、`SOURCE_MESSAGE_ONLY`;不再提供历史 `INFORMATIONAL_MESSAGE` 筛选项。旧 S000/S999 和 V3 S10/S99 兼容数据复用 `SOURCE_MESSAGE_ONLY` 只读源邮件通知卡;V4 S10/S99 新数据不进旧任务列表,走 V4 工作台和来源通知详情。 | | `task_status` | 否 | 任务状态过滤。 | | `task_subtype` | 否 | 任务卡 subtype 过滤。 | | `order_status` | 否 | 按任务所属订单状态过滤,支持 `TEMPORARY`、`ACTIVE`、`ENDED`、`LOGIC_DELETED`;不传时保持当前行为。 | | `queue_participation` | 否 | 是否参与订单执行队列。 | | `keyword` | 否 | Group Code、Confirmation No、临时订单号、来源消息安全摘要关键词。 | | `page_num` | 否 | 页码,建议从 1 开始。 | | `page_size` | 否 | 每页条数。 | 建议返参: ```json { "items": [ { "task_id": "10001", "order_id": "20001", "hotel_id": "HOTEL-TEST", "display_order_key": "GRP-001", "temporary_order_no": "TMP-20260708-001", "task_type": "UPDATE_BOOKING", "result_type": "normal_task", "ai_task_type": "Payment Evidence", "task_subtype": "payment_evidence", "route_code": "R10_PAYMENT_EVIDENCE_NORMAL", "system_process_category": "BUSINESS_TASK", "task_status": "PENDING_CONFIRM", "card_name": "Payment Evidence", "queue_sequence": 2, "queue_participation": true, "can_process": false, "readonly_reason_code": "PREVIOUS_TASK_NOT_FINISHED", "source_message_id": "30001", "source_subject": "Booking Update", "source_sender_summary": "guest@example.com", "source_received_at": "2026-07-08T02:58:00Z", "external_conversation_id": "thread-20260708-001", "conversation_message_count": 6, "created_at": "2026-07-08T03:00:00Z", "updated_at": "2026-07-08T03:10:00Z" } ], "page": { "page_num": 1, "page_size": 20, "total": 1 } } ``` 本轮已新增字段: | 字段 | 说明 | | --- | --- | | `source_sender_summary` | 来源消息发件人展示值,当前不打码,用于任务列表快速判断来源。 | | `source_received_at` | 邮件来源接收时间,优先取 AgentBus payload `received_at`,用于任务列表排序和展示。 | | `external_conversation_id` | 来源消息所属邮件会话 ID,用于打开完整邮件会话详情。 | | `conversation_message_count` | 会话内邮件数量,用于提示用户该入口是整段会话,不是单封邮件。 | | `result_type` / `ai_task_type` / `route_code` / `system_process_category` | V3 路由展示字段,用于任务卡标签、筛选和 S10/S99 只读卡判断。 | ## 4. 订单详情与任务时间线接口字段补齐 建议路径: ```text GET /api/reservation/orders/{orderId} ``` 当前状态:后端已按 P0 最小诉求实现第一版,并在 M002 V4 CP15.1 补齐订单详情 V4 总览字段;前端订单详情总览页已接入这些字段。接口返回订单摘要、V4 当前确认快照、V4 下一步处理入口、关联来源邮件摘要、旧 V2/V3 同订单任务时间线和 V4 订单任务时间线;`include_tasks=false` 时旧 `tasks[]`、V4 `v4_order_tasks[]` 和 `related_source_messages[]` 都返回空数组,`order_overview` 为空快照,`next_v4_action.action_type=NONE`。旧任务时间线已补齐每个任务的来源邮件会话摘要。 订单详情页当前定位为“订单总览 + 当前确认快照 + V4 任务时间线 + 下一步入口”,不是 V4 任务卡处理页。同订单任务队列里的每个任务都需要自己的“查看邮件会话”入口,因为不同任务可能来自不同邮件或不同邮件会话。因此 `tasks[]` 中每个任务已补齐来源邮件会话字段。V4 新模型下,同一订单的多卡订单任务通过 `v4_order_tasks[]` 单独返回,前端点击后进入 V4 订单任务详情。 建议入参: | 参数 | 必填 | 说明 | | --- | --- | --- | | `orderId` | 是 | 订单 ID。 | | `hotel_id` | 否 | 酒店 ID。单酒店阶段默认可为空,由后端解析;显式传值时后端会校验访问权限。 | | `include_tasks` | 否 | 是否返回任务时间线,默认 `true`。 | | `include_source_summary` | 否 | 是否返回来源消息摘要,默认 `true`;第一版参数保留,前端暂不要依赖它做字段裁剪。 | 建议返参: ```json { "order": { "order_id": "20001", "hotel_id": "HOTEL-TEST", "order_status": "ACTIVE", "temporary_order_no": "TMP-20260708-001", "confirmation_number": "CNF123456", "group_code": "GRP-001", "block_code": null, "allotment_code": null, "display_name": "GRP-001", "created_at": "2026-07-08T03:00:00Z", "updated_at": "2026-07-08T03:10:00Z" }, "order_overview": { "account_code": "QBD_TRAVEL", "account_name": "Q.B.D. TRAVEL GROUP CO., LTD", "market_code": "LEISURE", "source_code": "TRAVEL_AGENT", "arrival_date": "2026-07-26", "departure_date": "2026-07-29", "rate_code": "GRPA2-850UP", "room_items": [ { "room_type_code": "RM2", "room_count": 2 } ], "trace_card_status": null, "rooming_list_card_status": null, "payment_card_status": "REVIEW_REQUIRED", "latest_confirmed_at": "2026-07-08T04:20:00Z" }, "next_v4_action": { "order_task_id": "40001", "card_id": "41003", "action_type": "REVIEW", "action_status": "REVIEW_REQUIRED", "open_order_task_count": 1 }, "related_source_messages": [ { "source_message_id": "30002", "hotel_id": "HOTEL-TEST", "external_message_id": "AAMk-example", "external_conversation_id": "thread-20260708-002", "subject": "Booking Update", "sender_summary": "guest@example.com", "received_at": "2026-07-08T04:00:00Z", "source_sent_at": null, "conversation_message_count": 2 } ], "tasks": [ { "task_id": "10001", "task_type": "NEW_BOOKING", "result_type": "normal_task", "ai_task_type": "New Booking", "task_subtype": "NEW_BOOKING", "route_code": "R01_NEW_FIT_RESERVATION_NORMAL", "system_process_category": "BUSINESS_TASK", "task_status": "COMPLETED", "card_name": "New Booking", "queue_sequence": 1, "queue_participation": true, "can_process": false, "readonly_reason_code": "TASK_FINISHED", "source_message_id": "30001", "source_subject": "Booking Request", "source_sender_summary": "guest@example.com", "source_received_at": "2026-07-08T02:58:00Z", "external_conversation_id": "thread-20260708-001", "conversation_message_count": 6, "created_at": "2026-07-08T03:00:00Z" } ], "v4_order_tasks": [ { "order_task_id": "40001", "order_ref": "order-1", "order_task_status": "OPEN", "card_counts": { "total_count": 3, "readonly_count": 1, "pending_confirm_count": 1, "review_required_count": 1, "confirmed_count": 0 }, "cards": [ { "card_id": "41001", "card_type": "SOURCE_MESSAGE_DISPLAY", "event_type": null, "source_event_index": 0, "card_sort_order": 10, "card_status": "READONLY", "review_status": null, "confirmed_by": null, "confirmed_at": null, "latest_activity_at": "2026-07-08T04:00:10Z" }, { "card_id": "41003", "card_type": "PAYMENT", "event_type": "PAYMENT", "source_event_index": 2, "card_sort_order": 60, "card_status": "REVIEW_REQUIRED", "review_status": "PENDING", "confirmed_by": null, "confirmed_at": null, "latest_activity_at": "2026-07-08T04:05:00Z" } ], "source_message_summary": { "source_message_id": "30002", "hotel_id": "HOTEL-TEST", "external_message_id": "AAMk-example", "external_conversation_id": "thread-20260708-002", "subject": "Booking Update", "sender_summary": "guest@example.com", "received_at": "2026-07-08T04:00:00Z", "source_sent_at": null, "conversation_message_count": 2 }, "source_received_at": "2026-07-08T04:00:00Z", "created_at": "2026-07-08T04:00:10Z", "updated_at": "2026-07-08T04:05:00Z", "latest_activity_at": "2026-07-08T04:05:00Z" } ], "warnings": [] } ``` 本轮已新增字段: | 字段 | 说明 | | --- | --- | | `source_message_id` | 任务对应的来源 SourceMessage Inbox ID。 | | `source_subject` | 来源消息主题摘要。 | | `source_sender_summary` | 来源消息发件人展示值,当前不打码。 | | `source_received_at` | 邮件来源接收时间,优先取 AgentBus payload `received_at`。 | | `external_conversation_id` | 来源消息所属邮件会话 ID。 | | `conversation_message_count` | 会话内邮件数量。 | | `result_type` / `ai_task_type` / `route_code` / `system_process_category` | V3 路由展示字段,和任务列表字段语义一致。 | | `order_overview` | V4 订单详情当前确认快照,只从已确认 V4 卡片派生;未确认 AI 建议不会进入这里。 | | `order_overview.account_code` / `account_name` / `market_code` / `source_code` | 来自已确认 Basic Information 卡;为空表示 Basic Information 尚未确认或无可靠确认值。 | | `order_overview.arrival_date` / `departure_date` / `rate_code` / `room_items[]` | 来自已确认 Room Information 卡;后出现的已确认卡会覆盖前面同字段。后端已兼容读取新确认快照 `confirmed_payload.room_information.final_values` 和历史 `business_fields`。 | | `order_overview.trace_card_status` / `rooming_list_card_status` / `payment_card_status` | 当前订单下对应业务卡最新状态,方便订单详情页展示是否还有待处理事项。 | | `order_overview.latest_confirmed_at` | 当前订单 V4 卡片最近确认 UTC 时间。 | | `next_v4_action` | 订单详情页下一步处理入口,口径与订单列表 V4 入口一致;前端点击后跳 `/reservation/order-tasks/{order_task_id}`。 | | `next_v4_action.action_type` | `CONFIRM` / `REVIEW` / `NONE`。订单详情页不直接调用确认或复核接口,应进入 V4 订单任务详情页处理。 | | `related_source_messages[]` | 当前订单 V4 订单任务关联来源邮件安全摘要去重列表;用于订单页邮件区,不包含正文、HTML 或附件 URL。 | | `v4_order_tasks[]` | V4 订单任务时间线数组。旧 `tasks[]` 继续保留;V4 时间线按 `source_received_at`、`source_message_id`、`order_context_index`、`created_at`、数字 ID 正序返回。 | | `v4_order_tasks[].order_task_id` | V4 订单任务 ID,字符串。 | | `v4_order_tasks[].order_ref` | V4 回调包内订单引用,不等同 PMS 永久订单号。 | | `v4_order_tasks[].order_task_status` | V4 订单任务状态,当前为 `OPEN` / `COMPLETED`。 | | `v4_order_tasks[].card_counts` | V4 任务卡数量摘要。 | | `v4_order_tasks[].cards[]` | V4 订单任务下任务卡安全摘要,只返回状态、复核状态、确认人和确认时间,不返回业务 payload。 | | `v4_order_tasks[].source_message_summary` | V4 来源邮件安全摘要,不包含正文、HTML、附件 URL 或 AI 原始 payload。 | | `v4_order_tasks[].latest_activity_at` | V4 订单任务自身 `updated_at` 与其下卡片 `updated_at` 的最大 UTC 时间。 | ## 5. 订单列表接口 建议路径: ```text GET /api/reservation/orders ``` 当前状态:后端已完成第一版。默认查询全部订单状态;`open_task_count` 排除旧任务表中 `COMPLETED` 和 `FAILED`,保留为历史诊断计数。M002 V4 CP14 已补齐 V4 继续处理入口字段;后端新增 `open_work_item_count` 作为订单列表统一待处理展示数量,第一版直接等于 V4 未完成订单任务数,不叠加旧任务。当前开发阶段已停止 V4 普通业务双写旧 `workflow_reservation_task`,开发 / 测试环境旧任务数据可清理且可重建;`next_processable_task_id` 仅作为历史 V2/V3 诊断兼容字段,清理后新 V4 订单不应返回旧任务入口。前端已按 `next_v4_order_task_id` 优先进入 V4 订单任务详情;订单列表待处理数量已改为只展示 `open_work_item_count`。 默认排序:按后端维护的订单最近业务活动时间倒序返回,保证最近有业务活动的订单排在前面。后端当前使用 `workflow_reservation_order.latest_activity_at` 作为排序字段,并在订单创建、任务创建、草稿保存、最终确认、人工复核解阻、任务状态变更等写路径维护;前端不要再基于任务时间或更新时间自行重排。 建议入参: | 参数 | 必填 | 说明 | | --- | --- | --- | | `hotel_id` | 否 | 酒店 ID。单酒店阶段默认可为空,由后端解析;显式传值时后端会校验访问权限。 | | `order_status` | 否 | `TEMPORARY`、`ACTIVE`、`ENDED`、`LOGIC_DELETED`。 | | `group_code` | 否 | 按 Group Code 精确或模糊查询,后端决定。 | | `confirmation_number` | 否 | 按 Confirmation No 查询。 | | `keyword` | 否 | 前端搜索框统一关键词;后端匹配订单字段,也会匹配来源消息安全摘要命中的 SourceMessage ID。 | | `page_num` | 否 | 页码。 | | `page_size` | 否 | 每页条数。 | 建议返参: ```json { "items": [ { "order_id": "20001", "hotel_id": "HOTEL-TEST", "order_status": "ACTIVE", "display_order_key": "GRP-001", "temporary_order_no": null, "confirmation_number": "CNF123456", "group_code": "GRP-001", "display_name": "GRP-001", "open_task_count": 2, "open_work_item_count": 1, "next_processable_task_id": "10002", "next_v4_order_task_id": "30001", "next_v4_action_card_id": "31002", "next_v4_action_type": "REVIEW", "next_v4_action_status": "REVIEW_REQUIRED", "v4_open_order_task_count": 1, "updated_at": "2026-07-08T03:10:00Z" } ], "page": { "page_num": 1, "page_size": 20, "total": 1 } } ``` V4 继续处理字段说明: | 字段 | 说明 | | --- | --- | | `open_work_item_count` | 订单列表统一待处理展示数量。第一版忽略旧数据,直接等于 `v4_open_order_task_count`;前端展示 open count 时只使用该字段,不回退旧 `open_task_count`,也不要自行相加。 | | `next_v4_order_task_id` | 当前订单下第一条仍需用户处理的 V4 订单任务 ID;为空表示没有 V4 待处理订单任务。 | | `next_v4_action_card_id` | `next_v4_order_task_id` 下第一张仍需确认或复核的卡片 ID。 | | `next_v4_action_type` | `CONFIRM` / `REVIEW` / `NONE`。`CONFIRM` 调卡片确认接口,`REVIEW` 调复核解阻接口。 | | `next_v4_action_status` | `PENDING_CONFIRM` / `REVIEW_REQUIRED`;`NONE` 时为空。 | | `v4_open_order_task_count` | 当前订单下未完成 V4 订单任务数,`COMPLETED` 不计入。 | 前端“继续处理”入口优先级:优先使用 `next_v4_order_task_id` 跳转 V4 订单任务详情;没有 V4 待处理且旧 `next_processable_task_id` 为空时展示无待处理状态。S10/S99 来源通知不创建订单,不进入订单列表字段统计。订单列表展示“待处理数量”时只使用 `open_work_item_count`,不使用旧 `open_task_count` 作为展示数量,也不在前端自行计算 `open_task_count + v4_open_order_task_count`;旧 `open_task_count` 和 `v4_open_order_task_count` 保留用于兼容与排查。V4 新业务主线只写 V4 模型,开发阶段不维护 V2/V3 旧任务兼容,测试数据可重建;清理旧任务数据后,新 V4 订单不应再出现旧继续处理入口。 ## 6. 前端联调演示数据 seed 接口 建议路径: ```text POST /api/system/reservation/demo-data ``` 当前状态:后端已完成第一版。该接口只用于本地 / test 联调造数,默认关闭,不是生产业务页面接口。该接口会创建旧 `workflow_reservation_task` 演示数据,是历史 V2/V3 页面演示入口;M002 V4 smoke 不应再使用该接口造数,避免重新制造旧任务残留。V4 smoke 应使用 SuperAgent V4 回调或专门 V4 fixture。 启用条件: | 配置 | 说明 | | --- | --- | | `reservation.demo-data.enabled=true` | dev 默认开启;test 需显式启用,也可用环境变量 `RESERVATION_TEST_DEMO_DATA_ENABLED=true`。 | | `reservation.demo-data.access-key` | 配置访问口令;dev 优先使用 `RESERVATION_DEV_DEMO_DATA_ACCESS_KEY`,test 优先使用 `RESERVATION_TEST_DEMO_DATA_ACCESS_KEY`,旧通用变量 `RESERVATION_DEMO_DATA_ACCESS_KEY` 仅作为兼容兜底。 | | `X-TH-Hotel-Demo-Data-Key` | 请求头必须携带,与后端配置口令一致。 | 请求示例: ```json { "run_label": "frontend-smoke" } ``` 返回说明: | 字段 | 说明 | | --- | --- | | `demo_run_id` | 本次 seed 唯一关键词,可用于任务列表 / 订单列表搜索。 | | `source_messages[]` | 生成的来源消息 ID、外部消息 ID 和外部会话 ID。 | | `orders[]` | 生成的订单 ID、订单状态和展示键。 | | `tasks[]` | 生成的任务 ID、任务类型、任务 subtype 和任务状态。 | | `entrypoints` | 可直接访问的任务列表、订单列表、订单详情、任务详情、邮件会话详情 URL。 | 第一版 seed 覆盖:队列阻塞、已完成 OPERA 模拟、OPERA 失败可重试、Fallback 人工复核、历史 Message Notification 只读任务、邮件会话完整 HTML / 附件 / 内联图片。旧 S000/S999 特殊只读任务可通过 SuperAgent 回调补充;0711 P0 新入口的 S10/S99 已纳入后端 P0 fixtures 回归测试参考。 ## 6.1 M002 V3 当前状态和后续待补能力 本节记录 0711 P0 基线确认后,前端关心的 V3 能力状态。已完成项可以直接接入;后置项需要另开 checkpoint。 | 能力 | 页面 / 场景 | 状态 | 前端最小诉求 | | --- | --- | --- | --- | | 结构化 `S10/S99` 入站 | 任务列表、任务详情、Debug EML 结果展示 | 已完成第一版 | 后端接收 `result_type=source_message_review_notification + route_code=S10/S99`,创建只读源邮件通知卡;任务列表可见,订单列表不可见;返回 `route_code`、入口说明、`agent_assessment`、`notification` 和 S99 的入口 `manual_review`。 | | 旧 `S000/S999` 兼容映射 | 任务列表、任务详情 | 已完成第一版 | 旧数据继续可见;前端可按 `S000→S10`、`S999→S99` 展示统一文案。 | | 40 条 P0.1 路由元数据 | 任务列表筛选、订单任务时间线、任务详情标题、字段展示 | 已完成第一版 | 后端保存并返回 AI 原始 `result_type/ai_task_type/task_subtype`、`route_code` 和系统处理分类;前端不要只依赖系统主任务类型判断卡片。 | | P0.1 稳定 route_code | 任务列表筛选、订单任务时间线、任务详情标题 | 已完成第一版 | `route_code` 保持历史稳定,不因路由总数变 40 而连续重编号;前端仍可能看到 `R41_FALLBACK_BUSINESS_EVENT_REVIEW` 和 `R42_UNHANDLED_CURRENT_INTENT`。 | | Parent split 父事件卡型 | 任务列表、订单任务时间线、任务详情标题 | 已完成第一版 | 0712 P0.1 后,Parent split 父事件展示为 `Parent Group / Cancel Allotment / cancel_allotment_control_block`;`route_code=R08_CANCEL_ALLOTMENT_CONTROL_BLOCK_NORMAL` 展示为普通业务卡,`route_code=R08_CANCEL_ALLOTMENT_CONTROL_BLOCK_REVIEW` 展示为同卡人工复核业务卡;`linked_parent_release_after_child_split` 仅作为关系字段,不作为任务 subtype 筛选项。 | | `unhandled_current_intents[]` 展示块 | 任务详情 | 已完成第一版 | 后端保存并在任务详情 `unhandled_intents[]` 返回未覆盖业务意图,只用于展示和源邮件查看,不自动建业务任务卡。 | | `adapter_contract_error` | 任务详情、错误提示 | 已完成第一版 | 命中 P1/P2 未闭合或路由冲突时,任务详情 `adapter_contract_errors[]` 返回稳定错误 code 和原始片段,不转成 Fallback。 | | type-known manual review 同卡解阻 | 任务详情复核 | 已完成第一版 | `manual_review` 不再全部等同 Fallback;已知业务卡型返回原业务卡信息、`review_status`、`review_resolution` 和可编辑 pointer 字段,解阻后进入 `READY`。 | | 复核场景订单归属确认 | 任务详情复核 | 已完成第一版 | 后端提供复核确认时的订单归属确认;当前第一版只能确认当前任务所属订单,后续如要选择其他订单需另行细化。 | | P0 fixtures 回归基线 | 联调回归 | 已完成第一版 | 后端已将 0711 P0 fixtures 纳入测试参考;前端对 S10/S99、同卡复核和只读诊断块的展示应继续按本节稳定字段接入。 | ### 6.2 前端本轮接入状态(2026-07-11) 本轮前端已按 M002 V3 P0 完成以下接入,后端不需要重复补接口: - 任务列表已按 `result_type`、`route_code`、`system_process_category` 识别 `source_message_review_notification`、`adapter_contract_error`、`unhandled_current_intent` 只读诊断任务;S10/S99 和旧 S000/S999 都不展示订单入口。 - 任务详情已展示 `result_type`、`ai_task_type`、`task_subtype`、`route_code`、`system_process_category`、`review_status`、来源邮件入口、`source_message_only_result`、`manual_review`、`adapter_contract_errors[]` 和 `unhandled_intents[]`。 - Parent Group P0.1 前端已按 `route_code=R08_CANCEL_ALLOTMENT_CONTROL_BLOCK_NORMAL/REVIEW` 展示 `Parent Group / Cancel Allotment / cancel_allotment_control_block`;review 场景继续走同卡人工复核解阻,不展示为 `adapter_contract_error`。 - type-known `result_type=manual_review` 已在原业务任务卡展示复核状态和缺失字段,并调用 `POST /api/reservation/tasks/{taskId}/manual-review-resolutions` 解阻,不再创建第二张人工复核任务卡。 - 第一版解阻 UI 已改为优先使用任务详情 `fields[].field_pointer`,并同时提交 P0 主 `fields[].field_path`;旧扁平 `legacy_field_path` / `legacy_field_values` 仅用于 `field_contract_version=code-v1` 历史任务过渡回显,不作为新前端主动提交路径。 - 前端只读规则已收口:S10/S99、适配契约异常、未处理意图、前置任务阻塞和同卡人工复核待解阻状态都不显示保存草稿、确认任务、人工转换或 OPERA 执行 / 重试入口。 - 前端 fixture 已补 V3 最小结构样例:`source_message` 完整对象、`message_events[]` 的 `event_role`、`current_or_history`、`source_event_index`、四字段 `case_keys`、`relevant_message_excerpt`、`attachments`、`file_references`、`context_used`、`extracted_fields`、`manual_review`。 仍建议后端确认: - `GET /api/reservation/tasks` 中旧 S000/S999 和 V3 S10/S99 兼容行是否稳定返回 `task_type=SOURCE_MESSAGE_ONLY`。V4 S10/S99 已不应从旧任务列表返回,应通过 V4 工作台和来源通知接口展示。 - `adapter_contract_error` / `unhandled_current_intent` 如果未来也作为独立列表行返回,请保持 `source_message_id` 可用,便于前端继续提供邮件会话入口。 - 同卡人工复核解阻成功后是否一定返回 `opera_operations[]`。当前文档写“两条 OPERA 模拟操作”,前端实现按实际返回刷新,不假设固定数量。 - Parent Group `manual_review.reason_code=target_object_unclear` 场景需要任务详情稳定透出 `context_used.parent_identity_candidates[]`。当前 `ReservationTaskDetailResult` 后端 DTO 仅透出 `manual_review`,前端已兼容顶层 `context_used.parent_identity_candidates[]` 或 `manual_review.context_used.parent_identity_candidates[]`,但若后端不透出 candidates,页面只能显示空态提示。 前端注意:不要把访问口令写入前端仓库、浏览器环境变量或构建产物;该接口只能由本地联调人员手动调用或由受控测试脚本调用。 ## 7. 邮件会话详情接口 建议优先路径: ```text GET /api/source-messages/{sourceMessageId}/conversation ``` 历史候选路径,当前不提供: ```text GET /api/source-message-conversations/{externalConversationId} ``` 当前状态:`GET /api/source-messages/{sourceMessageId}/conversation` 已完成第一版。前端入口从某个任务的 `source_message_id` 进入,后端根据该 SourceMessage 找到 `external_conversation_id`,再返回同一邮件会话下的全部邮件。 中文说明: - 该接口已经完成权限收口:请求必须带 `Authorization: Bearer `,当前用户必须同时拥有 `SOURCE_MESSAGE_READ` 和 `SOURCE_MESSAGE_ORIGINAL_READ`,后端会按 SourceMessage 实际所属酒店校验访问权。 - “全部邮件”指同一个 `externalConversationId` 下的历史邮件、当前邮件和后续回复,不是只展示任务对应的单封来源邮件。 - V4 任务详情页的 `SOURCE_MESSAGE_DISPLAY` 卡如果展示正文,只展示当前触发该 V4 order task 的那一封 SourceMessage;前端应按入口 `sourceMessageId` 在 `messages[]` 中定位对应 `id`,不要把整条会话全部铺在任务详情卡片里。 - V4 Payment 卡如果展示付款凭证附件,前端先用任务详情里的 `payment_attachments[]` 安全摘要渲染 UI:图片显示缩略图,点击后通过本接口取得受控 `externalUrl` 打开大图预览;非图片统一展示文件名、类型、大小和下载按钮,不在卡片内嵌 PDF / Word / Excel 预览。 - 邮件会话详情页需要展示完整正文或清洗后的 HTML、附件、内联图片、发件人展示值、发送 / 接收时间、主题和关联订单 / 任务。 - 前端不在页面上做业务截断或隐藏;但仍只调用本项目后端接口,不直接访问邮箱、AgentBus、数据库或外部附件 URL Secret。 - 原文读取审计由后端在该业务接口内部处理,actor 使用当前登录用户稳定 ID;前端不保存或传递 `X-TH-Hotel-Source-Original-Read-Key` 一类受控访问 key。 - 2026-07-08 后端已新增 `html_body_sanitized` 和 `html_render_mode`;前端页面展示邮件 HTML 时应优先使用 `html_body_sanitized`,`html_body` 只作为原始内容兼容字段,不建议生产直渲。 - 第一版仅处理 HTML 内容清洗;附件和内联图片 URL 来自本系统 OSS 服务,暂不做额外拦截或代理转换。 - Payment 卡预览 / 下载匹配必须使用后端返回的附件 ID / `externalMediaId`,不能按文件名猜测;前端不得把 `externalUrl` 放进确认 payload、日志、错误上报、URL query 或 localStorage。 建议入参: | 参数 | 必填 | 说明 | | --- | --- | --- | | `sourceMessageId` | 是 | 入口来源消息 ID。后端据此定位 `externalConversationId`。 | 当前第一版不额外接收 `hotelId`、`includeBody`、`includeRelated`。后端默认按 SourceMessage 自身酒店上下文查询同会话邮件,返回完整 text/html、清洗后的 HTML 和关联订单 / 任务摘要,并在内部写原文读取审计。 建议返参: ```json { "conversation": { "external_conversation_id": "thread-20260708-001", "hotel_id": "HOTEL-TEST", "channel": "EMAIL", "subject": "Re: Booking Update", "message_count": 6, "first_received_at": "2026-07-06T01:10:00Z", "last_received_at": "2026-07-08T03:28:00Z" }, "messages": [ { "id": "30001", "external_message_id": "msg-001", "external_conversation_id": "thread-20260708-001", "sender_summary": "guest@example.com", "subject": "Booking Request", "received_at": "2026-07-06T01:10:00Z", "source_sent_at": "2026-07-06T01:08:00Z", "text_body": "完整邮件正文", "html_body": "

完整邮件 HTML

", "html_body_sanitized": "

完整邮件 HTML

", "html_sanitize_required": true, "html_render_mode": "SANITIZED_HTML", "inline_images": [], "attachments": [ { "mediaType": "ATTACHMENT", "fileName": "rooming-list.xlsx", "contentType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "sizeBytes": 10240, "externalUrl": "由后端决定是否返回可访问 URL", "externalMediaId": "media-001" } ], "related_orders": [ { "order_id": "20001", "display_order_key": "GRP-001", "order_status": "ACTIVE" } ], "related_tasks": [ { "task_id": "10001", "order_id": "20001", "task_type": "NEW_BOOKING", "task_subtype": "NEW_BOOKING", "task_status": "PENDING_CONFIRM", "card_name": "New Booking" } ] } ] } ``` ## 8. 任务详情接口字段元数据扩展 建议路径: ```text GET /api/reservation/tasks/{taskId} ``` 当前状态:后端已有任务详情接口,前端任务详情页可以接入。该接口已返回 `fields[]`、草稿、确认 payload、可处理状态和 OPERA 模拟操作;本轮已透出来源邮件会话字段,以及旧 `docs/import/20260708/任务卡前端展示字段表 3.0.xlsx` 中 P0 需要的字段元数据。0711 P0 后续开发应迁移到 `docs/import/20260711/开发交付_P0冻结基线_2026-07-11/01_Adapter_Frontend/任务卡前端字段变更说明_3.0_to_当前版_2026-07-10.xlsx` 和同目录路由说明。 任务详情页面相关已完成接口: | 接口 | 用途 | 后端状态 | | --- | --- | --- | | `GET /api/reservation/tasks/{taskId}` | 读取任务详情、字段矩阵、当前值、可处理状态、OPERA 操作摘要。 | 已完成第一版,已补本节字段。 | | `PUT /api/reservation/tasks/{taskId}/draft` | 保存任务卡草稿。 | 已完成。 | | `POST /api/reservation/tasks/{taskId}/confirm` | 最终确认任务卡字段。 | 已完成。 | | `GET /api/reservation/tasks/{taskId}/audits` | 查询任务审计流水。 | 已完成。 | | `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/execute` | 执行 OPERA 模拟操作。 | 已完成第一版模拟。 | | `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/retry` | 重试失败的 OPERA 模拟操作。 | 已完成第一版模拟。 | | `POST /api/reservation/tasks/{taskId}/manual-review-conversions` | 将 Fallback / manual_review 转换为具体任务类型。 | 已完成。 | | `POST /api/reservation/tasks/{taskId}/manual-review-resolutions` | type-known manual review 在原业务任务卡上提交字段修正和订单归属确认。 | 已完成第一版。 | 已完成的 `fields[]` 字段: 返回口径:`fields[]` 是后端按当前任务生效规则过滤后的字段集合,不是完整字段矩阵。后端已经应用 `visible`、`result_type`、`task_type`、`task_subtype` 和 `display_condition`;未返回字段对当前任务视为不展示、不校验、不提交,前端不要自行补齐,也不要依赖固定字段数量。 | 字段 | 说明 | | --- | --- | | `row_number` | 字段矩阵行号。 | | `card_name` | 任务卡名称。 | | `display_area` | 前端展示区域。 | | `field_path` | 字段路径。 | | `display_name` | 展示名。 | | `visible` | 是否展示。 | | `editable` | 是否可编辑。 | | `input_editable` | 是否输入方式编辑。 | | `select_editable` | 是否下拉方式编辑。 | | `date_picker` | 是否日期选择。 | | `number_input` | 是否数字输入。 | | `file_display` | 是否文件展示。 | | `table_editable` | 是否表格编辑。 | | `enum_options` | 枚举选项。 | | `required_rule` | 必填规则。 | | `display_condition` | 展示条件。 | | `validation_rule` | 校验规则。 | | `write_path` | 写入路径。 | | `opera_write_participation` | 是否参与 OPERA 写入。 | | `opera_parameter_mapping` | OPERA 参数映射。 | | `notes` | 备注。 | | `value` | 当前回显值。 | 本轮已补字段: | 位置 | 字段 | 说明 | | --- | --- | --- | | 顶层 | `source_subject` | 任务来源消息主题摘要。 | | 顶层 | `source_sender_summary` | 任务来源消息发件人展示值,当前不打码。 | | 顶层 | `source_received_at` | 任务来源邮件接收时间,优先取 AgentBus payload `received_at`。 | | 顶层 | `external_conversation_id` | 任务来源消息所属邮件会话 ID。 | | 顶层 | `conversation_message_count` | 会话内邮件数量。 | | `fields[]` | `result_type` | 3.0 字段表中的结果类型,用于前端调试和字段分组校验。 | | `fields[]` | `task_type` | 3.0 字段表中的任务主类型。 | | `fields[]` | `task_subtype` | 3.0 字段表中的任务 subtype / 业务动作。 | | `fields[]` | `default_value_source` | 3.0 字段表中的默认值 / 回显来源。 | ### 8.1 Type-known manual review 同卡复核解阻 当前状态:后端已完成第一版。`result_type=manual_review` 且 `system_task_type` 不是 `MANUAL_REVIEW` 时,前端在原业务任务卡上展示复核模式,不进入 Fallback 转换页面。 任务详情增量字段: | 字段 | 说明 | | --- | --- | | `review_status` | `PENDING` 表示等待复核,`RESOLVED` 表示已解阻。 | | `review_resolution` | 已解阻后的复核结果;未解阻时为 `null`。 | | `manual_review` | SuperAgent 原始复核说明、缺失字段、阻塞点、建议人工动作;只读展示。 | 解阻接口: ```text POST /api/reservation/tasks/{taskId}/manual-review-resolutions Content-Type: application/json ``` 请求示例: ```json { "confirmed_order_id": "20001", "reason": "确认 PMS 房型代码后解阻。", "field_overrides": [ { "field_pointer": "/extracted_fields/room_items/0/pms_room_type_code", "field_path": "extracted_fields.room_items.0.pms_room_type_code", "value": "RM3" } ] } ``` 0711 P0 房型复核说明:前端应优先提交 `/extracted_fields/room_items/0/pms_room_type_code` 或任务详情 `fields[].field_path=extracted_fields.room_items.0.pms_room_type_code`。后端仍兼容旧扁平 key / pointer,也支持只提交 `field_path`。如果同时提交 `field_pointer` 和 `field_path`,两者必须指向同一字段。响应里的 `review_resolution.field_overrides[].field_path` 使用 P0 主路径;前端只提交 `field_path` 时,后端会返回 P0 主 `field_pointer`;前端提交旧 pointer 时,`field_pointer` 保留前端原始值,`legacy_field_path` 仅用于旧页面过渡。 返回示例: ```json { "task_id": "10001", "order_id": "20001", "task_status": "READY", "review_status": "RESOLVED", "review_resolution": { "schema_version": "manual-review-resolution-v1", "confirmed_order_id": "20001", "resolved_at": "2026-07-11T00:00:00Z", "field_overrides": [ { "field_pointer": "/extracted_fields/room_items/0/pms_room_type_code", "field_path": "extracted_fields.room_items.0.pms_room_type_code", "legacy_field_path": "extracted_fields.pms_room_type_code", "value": "RM3" } ] }, "confirmed_payload": { "schema_version": "field_matrix-p0-room-items-v1", "field_values": { "extracted_fields.room_items.0.pms_room_type_code": "RM3" }, "legacy_field_values": { "extracted_fields.pms_room_type_code": "RM3" }, "effective_payload": { "extracted_fields": { "room_items": [ { "pms_room_type_code": "RM3" } ] } } }, "opera_operations": [ {"operation_code": "SIMULATE_PRECHECK"}, {"operation_code": "SIMULATE_WRITE"} ] } ``` 前端注意: - `field_overrides[]` 必须提供 `field_pointer` 或 `field_path`。`field_pointer` 必须是 RFC 6901 JSON Pointer;`field_path` 可以是 P0 主路径或旧扁平路径。两者都只能指向任务详情 `fields[]` 中当前可编辑字段;只读字段、未知字段或两者指向不一致会返回 `TASK_REVIEW_POINTER_INVALID`。 - 同一次请求不能重复提交同一字段;重复 `field_pointer` 或重复映射到同一 `field_path` 会返回 `TASK_REVIEW_POINTER_DUPLICATE`。 - `confirmed_order_id` 第一版必须等于当前任务 `order_id`;普通任务任意切换订单继续后置。 - type-known manual review 不能调用通用 `POST /api/reservation/tasks/{taskId}/confirm`;必须调用本节解阻接口,否则后端返回 `TASK_REVIEW_RESOLUTION_REQUIRED`。 - `review_resolution.resolved_at` 是 UTC `Z` 时间点。 - 解阻成功后刷新任务详情,按钮状态以新的 `task_status=READY` 和 `availability` 为准。 - `confirmed_payload.field_values` 按 P0 主 `field_path` 保存;`legacy_field_values` 是旧扁平兼容回显;`effective_payload` 是后端第一版嵌套结构,不是 OPERA 最终参数。 建议返参增量示例: ```json { "task_id": "10001", "order_id": "20001", "source_message_id": "30001", "source_subject": "Booking Update", "source_sender_summary": "guest@example.com", "source_received_at": "2026-07-08T02:58:00Z", "external_conversation_id": "thread-20260708-001", "conversation_message_count": 6, "system_task_type": "NEW_BOOKING", "task_card_type": "NEW_BOOKING", "task_status": "PENDING_CONFIRM", "field_contract_version": "20260711-p0", "fields": [ { "row_number": 2, "card_name": "New Booking", "result_type": "RESERVATION", "task_type": "NEW_BOOKING", "task_subtype": "NEW_BOOKING", "display_area": "基础信息", "field_path": "case_keys.group_code", "display_name": "Group Code", "visible": "是", "editable": "否", "default_value_source": "AI识别结果 / 已确认草稿回显", "value": "GRP-001" } ] } ``` 中文说明: - 如果前端只做“按后端字段直接渲染”,现有 `fields[]` 可以支撑第一版表单展示;本轮已经扩展 `ReservationTaskFieldResult`,避免前端维护第二套字段矩阵。 - `fields[]` 已是当前任务生效字段集合,前端不能把导入 Excel 或历史矩阵里的其他字段自行合成到页面上;例如 Group Block 不应补出 FIT 专属 Confirmation No. 输入框。 - `result_type`、`task_type`、`task_subtype`、`default_value_source` 当前从后端字段矩阵定义透出。 - 如果后端已有更细的字段来源或适用场景元数据,可后续再扩展 `field_source`、`applicable_scenario`,不作为本轮 P0 阻塞项。 - 前端默认不需要为 `GET /api/reservation/orders`、`GET /api/reservation/tasks`、`GET /api/reservation/orders/{orderId}` 自动拼 `hotel_id`;如已接入酒店选择器,可以传当前选中酒店,后端会校验访问权限。当前 `GET /api/reservation/tasks/{taskId}` 以及任务写操作 Controller 不接收 `hotel_id`;第一版先按 ID 定位,后续多酒店隔离 / 权限方案统一补齐。 ## 9. S10/S99 源邮件只读通知与历史兼容 当前状态:后端不提供历史候选的 `/api/reservation/message-notifications` 列表 / 详情接口。旧 SuperAgent 入口返回 `S000,source_message_id` 或 `S999,source_message_id` 时,后端会创建 `SOURCE_MESSAGE_ONLY` 只读特殊任务;V3 结构化 `S10/S99` 兼容路径也沿用该旧任务模型。V4 `route_code=S10/S99` 新数据已改为独立来源通知模型,通过 V4 工作台和 `/api/reservation/source-notifications/{notificationId}` 展示,并通过 `/api/reservation/source-notifications/{notificationId}/ack` 确认已读 / 已处理。 V3 入口兼容语义: - `S10`:`result_type=source_message_review_notification`,`route_code=S10`,表示未匹配当前支持的业务事件。 - `S99`:`result_type=source_message_review_notification`,`route_code=S99`,表示输入不足或无法形成业务素材包。 - 旧 `S000` 前端语义映射为 `S10`。 - 旧 `S999` 前端语义映射为 `S99`。 历史 `INFORMATIONAL_MESSAGE` 仍可通过任务列表 / 任务详情兼容展示,但新数据不要依赖它。 展示规则: - 旧 `task_type=SOURCE_MESSAGE_ONLY`、`task_subtype=S000/S999`:按只读源邮件通知卡展示。 - V3 `route_code=S10/S99` 兼容数据:按旧只读源邮件通知卡展示。 - V4 `route_code=S10/S99` 新数据:按来源通知详情展示,可 ack,不通过旧任务详情处理。 - 旧 `SOURCE_MESSAGE_ONLY` 任务列表可见,订单列表不可见;V4 来源通知在 V4 工作台可见,订单列表和订单详情不可见。 - 旧任务详情只允许查看来源邮件、会话、附件和 SuperAgent 原始返回;V4 来源通知详情只允许查看来源邮件摘要、通知信息和 ack 状态。 - 任务详情通过 `source_message_only_result` 返回 `entry_result_code`、`entry_result_meaning`、`entry_result_description`、`entry_result_source_message_id`、`result_type`、`route_code`、`agent_assessment`、`notification`、S99 的入口 `manual_review` 和 `raw_answer`。 - 不显示编辑、人工转换、执行 OPERA 或重试 OPERA 按钮;V4 只显示 ack。 - 不参与订单任务执行顺序阻塞,也不创建隐藏技术订单。 当前不建议新增路径: ```text GET /api/reservation/message-notifications GET /api/reservation/message-notifications/{taskId} ``` 列表建议入参: | 参数 | 必填 | 说明 | | --- | --- | --- | | `hotel_id` | 否 | 酒店 ID。单酒店阶段默认可为空,由后端解析;显式传值时后端会校验访问权限。 | | `order_id` | 否 | 按临时订单或真实订单过滤。 | | `keyword` | 否 | 邮件主题、摘要、发送人关键词。 | | `page_num` | 否 | 页码。 | | `page_size` | 否 | 每页条数。 | 详情建议返参: ```json { "task_id": "10009", "order_id": "20009", "task_type": "SOURCE_MESSAGE_ONLY", "task_subtype": "S000", "task_status": "COMPLETED", "queue_participation": false, "readonly": true, "visible_reason": "S000 pure information entry result", "relevant_message_excerpt": "Noted with thanks.", "entry_result_code": "S000", "entry_result_description": "纯信息类邮件", "attachments": [], "source_message_id": "30009", "external_conversation_id": "thread-20260708-009", "created_at": "2026-07-08T03:00:00Z" } ``` V3 S10 结构化详情当前增量: ```json { "task_id": "10010", "readonly": true, "result_type": "source_message_review_notification", "route_code": "S10", "agent_assessment": { "status": "no_booking_action_detected", "reason_code": "no_booking_action_detected" }, "notification": { "notification_type": "source_message_review", "show_source_message": true, "requires_user_decision": true }, "manual_review": null, "source_message_id": "30010" } ``` ## 9.1 V3 诊断展示块 任务详情接口已新增两个只读数组: | 字段 | 说明 | | --- | --- | | `adapter_contract_errors[]` | 同一 SuperAgent 入站批次中未生成任务的 Adapter 契约错误。 | | `unhandled_intents[]` | 同一 SuperAgent 入站批次中无法映射到业务任务卡的未处理意图。 | 数组元素字段: | 字段 | 说明 | | --- | --- | | `transition_id` | AI transition ID。 | | `source_event_index` | AI current 事件序号。 | | `array_index` | AI 返回数组顺序。 | | `result_type` | AI 结果类型。 | | `ai_task_type` | AI 原始任务类型。 | | `task_subtype` | 业务动作 subtype,可能为空。 | | `route_code` | V3 路由码。 | | `system_process_category` | 系统处理分类。 | | `adapter_error_code` | 契约错误代码;未处理意图通常为空。 | | `adapter_error_message` | 契约错误安全摘要。 | | `payload_fragment` | 对前端展示安全的 AI item 片段。 | 前端注意:这两个数组不是任务队列,不提供编辑、确认、执行 OPERA 或重试入口;只用于解释为什么同一封邮件中的某些 event 没有变成业务任务。 ## 10. 系统管理菜单树增强接口 为支持系统设置中“菜单管理”从表格交互升级为“左侧菜单树 + 右侧配置面板”,前端希望后端补两个增强接口。该能力仍属于系统管理后台 `/api/admin/menus/**`,不改变菜单可见性和后端接口权限的边界。 ### 10.1 完整菜单树查询 建议路径: ```text GET /api/admin/menus/tree ``` 权限要求: | 要求 | 说明 | | --- | --- | | 登录 | 必须携带 `Authorization: Bearer ` | | 权限 | 需要 `SYSTEM_MENU_MANAGE` | | 审计 | 只读查询不需要写管理审计 | 查询行为: - 返回完整菜单树,不分页。 - 默认返回全部菜单,包括 `ACTIVE` / `DISABLED`、`visible=true` / `false`。 - 按 `parent_id` 组树,根节点 `parent_id=null`。 - 同级按 `sort_order` 升序,其次按 `menu_name` 或 `id` 稳定排序。 - `BIGINT` ID 继续以字符串返回。 - 如果存在脏数据,例如 `parent_id` 指向不存在菜单,应 fail-safe:该节点作为根级异常节点返回,或在响应中提供 `warnings[]`,不要导致接口 500。 建议返参: ```json { "items": [ { "id": "10001", "parent_id": null, "menu_code": "SYSTEM_SETTINGS", "menu_name": "系统设置", "menu_type": "PAGE", "route_path": "/system", "component_key": "system", "icon_key": "pi pi-cog", "permission_code": "SYSTEM_ADMIN_CONSOLE_ACCESS", "sort_order": 900, "visible": true, "menu_status": "ACTIVE", "known_route": true, "created_at": "2026-07-16T00:00:00Z", "updated_at": "2026-07-16T00:00:00Z", "children": [] } ], "warnings": [] } ``` ### 10.2 批量调整菜单父级和排序 建议路径: ```text PUT /api/admin/menus/tree-order ``` 权限要求: | 要求 | 说明 | | --- | --- | | 登录 | 必须携带 `Authorization: Bearer ` | | 权限 | 需要 `SYSTEM_MENU_MANAGE` | | 审计 | 写操作必须写 `platform_admin_audit_log` | 请求体建议: ```json { "items": [ { "menu_id": "10002", "parent_id": "10001", "sort_order": 100 } ] } ``` 后端要求: - 只允许修改 `parent_id` 和 `sort_order`,不允许顺带修改 `menu_name`、`route_path`、`permission_code`、`visible`、`menu_status`。 - 使用事务保存。 - 校验 `menu_id` 必须存在。 - 校验 `parent_id` 为空或存在。 - 禁止把自己设为自己的父级。 - 禁止形成循环菜单树。 - `sort_order` 可为空;为空时后端按请求 `items[]` 顺序生成 `100`、`200`、`300`... 的稳定排序号。 - 成功后返回更新后的完整菜单树,方便前端立即刷新。 - 审计中记录调整前后的 `parent_id` / `sort_order`,不记录 token、secret 或敏感信息。 建议成功返参: ```json { "items": [ { "id": "10001", "parent_id": null, "menu_code": "SYSTEM_SETTINGS", "menu_name": "系统设置", "sort_order": 900, "visible": true, "menu_status": "ACTIVE", "known_route": true, "children": [] } ], "warnings": [] } ``` 前端接入注意: - 前端菜单树管理页优先使用 `GET /api/admin/menus/tree`,不再依赖分页菜单列表拼完整树。 - `GET /api/admin/menus` 仍保留给表格分页、搜索和兼容页面使用。 - `PUT /api/admin/menus/{menuId}` 仍用于单条菜单基础字段编辑。 - `PUT /api/admin/menus/tree-order` 只用于批量保存树结构和排序。 ## 11. 任务卡前端字段白名单元数据接口 是否需要该接口待确认。如果任务详情接口 `fields[]` 已透出 3.0 所需元数据,则第一版可以不做独立白名单接口;如果后续需要字段矩阵调试页、版本对齐页或前端预加载全部任务卡配置,再补独立接口。 建议路径: ```text GET /api/reservation/task-card-field-whitelist ``` 建议入参: | 参数 | 必填 | 说明 | | --- | --- | --- | | `task_type` | 否 | 按系统主任务类型过滤。 | | `task_subtype` | 否 | 按任务卡 subtype 过滤。 | | `version` | 否 | 字段白名单版本,例如 `20260711-p0`。 | 建议返参: ```json { "version": "20260711-p0", "items": [ { "task_type": "UPDATE_BOOKING", "task_subtype": "RATE_CHANGE", "field_path": "rate.rate_code", "display_name": "Rate Code", "visible": true, "editable": true, "input_type": "select", "options": [] } ] } ``` ## 12. Manual Invoice 手工开票生成接口 M009 后端 CP2 已实现,前端 V1 已接入 `/reservation/invoices/new`,可以在无订单 / 无任务数据时独立生成 Proforma Invoice。该接口是正式业务开票生成入口,不走 M008 调试上传 access key。 路径: ```text POST /api/reservation/invoices/manual-generations ``` 入参: ```json { "hotel_id": "HOTEL-TEST", "source_type": "MANUAL", "task_id": null, "order_id": null, "template_code": "PROFORMA_INVOICE_V1", "invoice_payload": { "document": { "invoice_date": "2026-07-17", "booking_date": "2026-07-12", "due_date": "2026-07-22" }, "recipient": { "company_code": "LIAN_TAI", "contact_id": "LIAN_TAI_KHUN_ANN", "company": "LIAN TAI TRAVEL (THAILAND) CO., LTD.", "attention": "Khun Ann", "address": "2/86 Rajpattana Road, Rajpattana, Sapansoong, Bangkok, TH, 10240", "telephone": "061-397-2675", "email": "op.liantaitravel@gmail.com" }, "booking": { "group_name": "GRP-DEMO-0802", "arrival_date": "2026-08-02", "departure_date": "2026-08-05", "room_rate_note": "includingBF", "extra_bed_rate": 1200 }, "charges": [ { "description": "GRP-DEMO-0802", "room_type": "Deluxe Room", "quantity": 2, "rate": 3000, "nights": 3 } ] } } ``` 返参: ```json { "invoice_generation_id": "2080000000000000001", "generation_status": "SUCCEEDED", "pdf_url": "https://oss.example.test/reservation-invoices/HOTEL-TEST/2026-07-17/.../proforma-invoice.pdf", "pdf_object_key": "reservation-invoices/HOTEL-TEST/2026-07-17/.../proforma-invoice.pdf", "generated_excel_object_key": "reservation-invoices/HOTEL-TEST/2026-07-17/.../proforma-invoice.xlsx", "totals": { "subtotal": 16822.43, "vat": 1177.57, "total": 18000.00, "currency": "THB" }, "created_at": "2026-07-17T03:30:00Z" } ``` 前端诉求: - 前端已按 `RESERVATION_INVOICE_GENERATE` 做路由权限保护;侧边栏是否展示仍取决于登录态后端返回的 `menus[]`。 - 如需在菜单中展示,建议后端 / 管理员配置 `menu_code=RESERVATION_MANUAL_INVOICE`、`route_path=/reservation/invoices/new`、`permission_code=RESERVATION_INVOICE_GENERATE`。 - 该接口必须支持 `source_type=MANUAL` 且 `task_id` / `order_id` 为空。 - 如果前端同时传 `task_id` 和 `order_id`,必须保证任务属于该订单;后端不一致时返回 `RESERVATION_INVOICE_CONTEXT_MISMATCH`。 - `recipient.company_code` 和 `recipient.contact_id` 用于表达目录选择结果;`company`、`attention`、`address`、`telephone`、`email` 是最终用于生成 PDF 的文本值,Manual 覆盖时也必须提交。 - 后端需要重新计算金额、VAT 和合计;前端计算只做预览。 - `charges[].rate` 必填且必须是数字,允许 `0`,不能小于 `0`;`charges[].quantity` 和 `charges[].nights` 仍必须大于 `0`。 - 后端需要返回可预览 / 下载的 PDF URL。 - `pdf_url` 第一版可作为预览地址;前端会优先用浏览器 `fetch + Blob` 触发下载,避免跨域场景下 `` 失效。如果 OSS CORS 不允许浏览器读取文件,前端会退回打开 PDF 页面。后续如要求稳定下载体验,建议后端提供带 `Content-Disposition` 的受控下载代理或签名下载 URL。 - 该接口应走 Bearer 登录、酒店访问权和 `RESERVATION_INVOICE_GENERATE` 权限,不走 M008 调试上传 access key。 - 第一版最多支持 10 条 `charges[]`;超过 10 条会返回 `RESERVATION_INVOICE_VALIDATION_FAILED`。 - 第一版只支持 `template_code=PROFORMA_INVOICE_V1`,模板文件由后端受控维护。 - 第一版已写入 `workflow_reservation_invoice_generation` 生成记录和业务审计,但暂不提供前端查询历史列表 / 详情接口。 - 错误响应中的 `error_code` 用于前端主错误文案映射;`message` / `details[]` 只作为折叠技术详情展示,不直接铺给普通用户。 ## 13. Rooming List Excel 生成接口 CP2 契约 M010 Rooming List Excel 生成接口 CP1 已实现,前端 V1 已接入 `/reservation/rooming-lists/new`。CP2 不新增路径,继续收口同一个正式业务接口。 路径: ```text POST /api/reservation/rooming-lists/generations ``` CP2 前端提交字段: | 字段 | 必填 | 说明 | | --- | --- | --- | | `file` | 是 | 来源 Excel 文件,仅支持 `.xls` / `.xlsx`。 | | `hotel_id` | 否 | 当前选择酒店;不传时由后端按登录用户酒店上下文解析。 | | `people_per_room` | 是 | 每间房人数,正整数。 | | `room_type` | 是 | 目标 Excel 的 Room Type。 | | `payment_type` | 否 | 目标 Excel 的 Payment Type;默认 `BTQR`,当前允许 `BTQR`、`CA`。 | | `nationality` | 是 | 目标 Excel 的 Nationality;只允许 `KR`、`CHN`。 | CP2 前端不再提交: ```text arrival departure title rate_code adults children vip email id_type id_number ``` 后端派生规则: - 从来源 Excel `旅游日期` 列解析入住和离店日期;样例 `2026年5月9日-5月14日` 派生 `Arrival=2026/05/09`、`Departure=2026/05/14`。 - `Adults` 按当前分房行实际人数计算;尾房人数不足时按实际人数写入。 - `Children` 固定为 `0`。 - `Title`、`Rate Code`、`VIP`、`Email`、`ID Type`、`ID Number` 第一版固定为空。 - 如果来源 Excel 缺少 `旅游日期`、日期格式无法解析、结束日期不晚于起始日期,或同一文件出现多个不同旅游日期区间,后端返回受控错误,不生成 Excel。 前端诉求: - 页面第一部分保留上传来源 Excel、每房人数、Room Type。 - 目标默认值区域只保留 Payment Type 和 Nationality 两个下拉。 - Payment Type 默认选中 `BTQR`,当前提供 `BTQR`、`CA` 两个选项。 - Nationality 只提供 `KR` 和 `CHN`。 - 前端不读取完整 Excel 作为权威解析结果;旅游日期和成人数以后端生成结果为准。 - 页面不要把上传文件内容、客人名单、生成文件内容写入浏览器日志、埋点、错误上报、URL 或 localStorage。 ## 14. 已确认后置接口 普通任务切换订单接口继续后置,前端暂不开发提交能力。后续如果恢复开发,建议另行确认: ```text POST /api/reservation/tasks/{taskId}/order-binding ``` 待确认入参: ```json { "target_order_id": "20002", "reason": "人工确认该任务属于另一个订单" } ``` 待确认返参: ```json { "task_id": "10001", "previous_order_id": "20001", "target_order_id": "20002", "task_status": "PENDING_CONFIRM", "audit_id": "90001" } ``` ## 15. 待确认问题 - 订单列表、任务列表当前统一使用 `items + page` 分页结构;邮件会话详情不分页,返回同一会话全部邮件。 - 邮件会话详情接口已优先使用 `GET /api/source-messages/{sourceMessageId}/conversation`。 - 任务详情 `fields[]` 已由后端直接透出 P0 需要的 3.0 元数据;独立字段白名单接口后置。 - 独立 Message Notification 页面继续后置;旧 S000/S999 和 V3 S10/S99 继续在旧任务列表和任务详情兼容展示,V4 S10/S99 走 V4 工作台和来源通知详情。 - 邮件会话全文读取的审计策略由后端内部处理;前端不保存原文读取 key。 - `GET /api/reservation/tasks` 中旧 S000/S999 和 V3 S10/S99 兼容行的 `task_type` 返回值请后端最终确认;V4 S10/S99 不应再进入旧任务列表。 - `manual-review-resolutions` 成功响应中的 `opera_operations[]` 数量请后端最终确认;前端不写死两条,只按返回内容刷新展示。 - 系统管理菜单树增强接口已完成:`GET /api/admin/menus/tree`、`PUT /api/admin/menus/tree-order`。 - Manual Invoice 第一阶段的客户 / 联系人目录来源、模板初始文件、VAT 配置和生成记录是否必须落库,已在 M009 中列为开发前确认项。 - V4 真实目录与 Lookup API 第一版已在后端 CP11 落地,前端 CP12 已接入 `GET /api/reservation/lookups/accounts`、`GET /api/reservation/lookups/room-types`、`GET /api/reservation/lookups/rate-codes` 用于 V4 字段选择控件。前端按 `options_source` 选择接口,空列表 / stale / warnings 只做非阻塞提示,确认和复核仍只提交 code;2026-07-21 结论是 Rate Code 第一阶段暂不按 Account + `booking_type` 过滤,继续使用酒店级 `RATE_CODE` 目录,前端不要硬编码 OWNER RATE Excel 中的 Account 映射;真实 PMS 同步、目录管理后台扩展和 SuperAgent 目录机器接口仍后置。 - V4 Payment 附件预览下一阶段已确认:后端需补 `payment_attachments[]` 安全摘要;前端图片缩略图 + 点击大图预览,非图片文件列表 + 下载;预览和下载仍走 SourceMessage conversation 原文权限链路。`attachment_ids[]` 第一版作为 Agent 返回的只读业务事实,前端只展示并确认卡片,不做附件集合编辑。 - V4 复核态交互已确认:`REVIEW_REQUIRED` 不新建独立复核任务卡,仍在原业务卡内编辑当前卡 `fields[]` 白名单业务字段;问题字段红字提示;主按钮文案统一为“确认卡片”,但前端内部调用 `POST /api/reservation/order-tasks/{orderTaskId}/cards/{cardId}/review-resolution`。 - V4 Room Information smoke 修复已完成:`REVIEW_REQUIRED` 下当前卡白名单业务字段会按 `fields[].editable=true` 暴露给前端,`/room_information/final_values/...` pointer 可用于复核提交;Basic Information 和普通业务卡的 `display_payload` / `confirmed_payload` 不返回 Agent `target_order`,普通业务卡也会移除邮件 HTML、raw evidence、附件原始 URL 和 PMS 原始响应等敏感字段;Rooming List 自动 DEF 后刷新任务详情的 Room Information `display_payload` / `confirmed_payload` 应显示 DEF,审计接口返回 `V4_ROOMING_LIST_AUTO_DEF`;当前订单详情 `order_overview` 不返回 Group Booking Status 字段。