# 付款详情打印页:数据与渲染流程梳理 **页面 URL**: `http://czemc.localhost/budget/#/payment/payment-detail-print/161`(示例 id=161) **组件**: `czemc-budget-execution-frontend/src/views/payment/PaymentDetailPrint.vue` **路由**: `/payment/payment-detail-print/:id`(`src/router/index.js`) --- ## 一、入口与路由 | 项目 | 说明 | |------|------| | **路由定义** | `path: '/payment/payment-detail-print/:id'`,`name: 'PaymentDetailPrint'` | | **组件** | `() => import('@/views/payment/PaymentDetailPrint.vue')`,懒加载 | | **meta** | `title: '付款详情打印'`,`hidden: true`(不显示在菜单) | | **访问方式** | 直接访问 URL,或从预算执行等页面通过 `router.push({ path: \`/payment/payment-detail-print/${row.payment_id}\` })` 跳转 | URL 中的 `161` 为付款 id(`Payment.id`),从 `route.params.id` 读取。 --- ## 二、整体数据与渲染流程概览 ``` onMounted └─ loadPaymentDetail() ├─ 1) paymentAPI.getDetail(id) → GET /budget/payments/{id} ├─ 2) payment 赋值,collectFlowId(payment.flow_info.id) // 付款主流程 ├─ 3) loadPaymentTemplateElements() // 付款分类模板元素 ├─ 4) loadApprovalFlowDetails() // 审批流程类型字段的流程详情 ├─ 5) loadRelatedPlannedExpenditure() // 若 related_type=planned_expenditure ├─ 6) nextTick + setTimeout(300) → renderPrintTemplates() └─ 7) renderedPrintTemplates 更新后 → 触发 renderPdfAsImages(会议纪要 PDF 等) 子组件挂载(ContractInfoCard / PlannedExpenditureInfoCard): └─ PlannedExpenditureTemplateReadonly └─ 从 flow_bindings / element_values 解析流程 ID → emit('collect-flow-id', id) └─ 父层 collectFlowId(id) → collectedFlowIds watch(collectedFlowIds.size) → renderPrintTemplates() └─ oaFlowAPI.renderPrintTemplates(flowIds) → POST /oa/flow/render-print-templates └─ renderedPrintTemplates = res.data → 渲染「相关流程详情」区块 ``` --- ## 三、主数据源:付款详情接口 ### 3.1 请求 - **调用**: `paymentAPI.getDetail(paymentId)`,其中 `paymentId = route.params.id`(如 161) - **接口**: `GET /budget/payments/{id}` - **后端**: `backend/Modules/Budget/app/Http/Controllers/Api/PaymentController.php` → `show($id)` ### 3.2 后端加载与格式化 - `Payment::with(['paymentCategory.parent', 'oaFlow', 'elementValues.element'])->findOrFail($id)` - 使用 `formatPayment($payment, true)` 输出,其中会: - 按 `oa_flow_id` 查 OA 流程,得到 `flow_info`(id、no、title、status_text、custom_model_id、created_at 等) - 按 `payment_category_id` 算支付类型与面包屑,得到 `payment_type_info` - 把 `fields_data` 作为 `fields` 返回(与 element_values 双写一致) - `includeDetails === true` 时附加 `details: [ formatPaymentLineItemFromPayment($payment) ]`,用于兼容前端对「明细」的引用 ### 3.3 返回数据结构(与页面用法对应) | 字段 | 说明 | 页面中的主要用途 | |------|------|------------------| | id, serial_number, status, status_text | 付款标识与状态 | 标题区、状态展示、表格 | | total_amount, updated_at | 金额与更新时间 | 本次支付、付款确认日期 | | payment_type_info | { payment_type_text, breadcrumb } | 支付类型一行 | | flow_info | { id, no, title, status_text, custom_model_id, … } | 流程信息展示、collectFlowId、抽屉跳转 OA | | description, remarks | 说明、备注 | 表格两行 | | fields | 模板字段键值(element_id → value) | 支付模板区所有「元素」的取值来源 | | related_type, related_id | 关联类型与 id | 决定关联内容分支(见下) | | contract_id | 合同 id(可与 related 并存) | 合同信息卡片、关联合同事前流程 | | details | 长度 1 的数组,兼容用 | currentDetail 等(打印页用到不多) | `payment` 写入 `ref(null)`,请求成功后再赋值为接口返回的 `response.data`,此后整页以 `payment` 为单一数据根进行渲染。 --- ## 四、页面渲染结构(从上到下) ### 4.1 打印工具栏 - 固定于页面右上,内含「打印」「关闭」。 - 打印前会执行 `renderPdfAsImages()`,把本页所有会议纪要等 PDF 占位渲染成图片,再 `window.print()`。 - 仅在屏幕显示,`@media print` 下隐藏。 ### 4.2 页眉 - 标题:「付款详情」 - 打印/归档时间:`printTime`(`new Date().toLocaleString('zh-CN')`) ### 4.3 付款基本信息(`.section.payment-basic-info`) 数据一律来自 `payment`: 1. **固定行** - 编号、状态、本次支付、付款确认日期(仅当 `status === 'completed'`)、支付类型、流程信息、说明、备注。 2. **支付模板区(visiblePaymentTemplateElements)** - 数据:`paymentTemplateElements` 来自 `loadPaymentTemplateElements()`,过滤后得到 `visiblePaymentTemplateElements`。 - 取值:`payment.fields[el.id]`(及勾选清单备注键 `el.id_remark_${optionValue}`)。 - 按元素类型分别渲染: - **checklist**:只读勾选列表 + 备注 - **meeting_minutes**:`MeetingMinutesField` 只读;若唯一附件为 PDF,下方通栏用 PDF 占位,由 `renderPdfAsImages` 转成图片 - **detail_table**:表格列来自 `detailTableFieldsMap`(`detailTableFieldAPI.getList(elementId)`),行数据来自 `payment.fields[elementId]`,部门/用户通过 `departmentMap`、`userMap` 转名称 - **approval_flow**:用 `flowDetailsCache` 展示流程简述,`flowDetailsCache` 由 `loadApprovalFlowDetails()` 调用 `plannedExpenditureAPI.getOaFlowDetails(flowIds)` 填充 - **附件**:从 `payment.fields[elementId]` 解析为 `{ name, url }` 列表展示 - 其余:`formatTemplateFieldValue(el, payment.fields[el.id])` 文本或默认展示 `loadPaymentTemplateElements` 使用 `payment.payment_category_id` 调 `paymentCategoryAPI.getTemplateElements(categoryId)`,得到该分类下模板元素列表,并预加载所有 `detail_table` 的字段配置与部门/用户列表(若需要)。 ### 4.4 关联内容区(按 related_type 三分支) 分支仅由 `relatedTypeCase` 决定,`relatedTypeCase` 来自 `payment.related_type`(`'planned_expenditure' | 'contract' | null/undefined/''` 等视为 `'null'`)。 - **relatedTypeCase === 'null'** - 仅再判断 `payment.contract_id`。 - 若有合同 id,渲染 **ContractInfoCard**,`contract-id=payment.contract_id`,`embed-planned-expenditures="true"`,用于展示合同信息与「关联合同的事前流程」。 - **relatedTypeCase === 'contract'** - 渲染 **ContractInfoCard**,`contract-id=payment.related_id`,当前付款 id 传入,同样嵌入合同事前流程。 - **relatedTypeCase === 'planned_expenditure'** - 先渲染 **PlannedExpenditureInfoCard**: - `expenditure`、`template` 来自 `loadRelatedPlannedExpenditure()`(按 `payment.related_id` 调 `plannedExpenditureAPI.getDetail(relatedId)`,再按 `category_id` 拉模板并写入 `relatedPlannedExpenditure`、`relatedPlannedExpenditureTemplate`)。 - 内部用 `PlannedExpenditureTemplateReadonly`,会 emit `collect-flow-id`。 - 再若存在 `payment.contract_id`,渲染 **ContractInfoCard**,`embed-planned-expenditures="false"`,只展示合同信息与合同相关支付列表,不再嵌入事前流程。 三个分支里,凡是出现 **ContractInfoCard** 且 `embedPlannedExpenditures === true`,或出现 **PlannedExpenditureInfoCard**,其内的 **PlannedExpenditureTemplateReadonly** 都会从模板配置、`flow_bindings`、`element_values` 中解析出流程 id,并向父级 emit `collect-flow-id`,由页面 `collectFlowId` 汇总到 `collectedFlowIds`。 ### 4.5 相关流程详情(renderedPrintTemplates) - **显示条件**: `renderedPrintTemplates.length > 0` - **数据来源**: - 流程 id 来自 `collectedFlowIds`(付款主流程 + 合同/事前流程子组件上报的流程 id)。 - 请求:`oaFlowAPI.renderPrintTemplates(Array.from(collectedFlowIds))` → `POST /oa/flow/render-print-templates`,body 为 `{ flow_ids: number[] }`。 - 后端对每个 flow_id 用 OA 的打印模版(CustomModel.print_format)渲染 HTML,返回 `{ flow_id, flow_title, flow_info: { no, title, creator_name, created_at }, html }` 等。 - **渲染方式**: - 标题:「相关流程详情」 - 列表:`v-for="(template, idx) in renderedPrintTemplates"`,每条显示「序号、流程编号 - 流程标题(创建人 创建时间)」,正文 `v-html="template.html"`。 - 分页:整块前 `page-break-before: always`;从第二条起每条前也 `page-break-before: always`。 流程 id 收集与「相关流程详情」的详细说明见:`付款详情打印页-相关流程详情渲染说明.md`。 --- ## 五、关键辅助请求一览 | 用途 | 调用链 | 接口 | |------|--------|------| | 付款主数据 | paymentAPI.getDetail(id) | GET /budget/payments/{id} | | 付款分类模板元素 | paymentCategoryAPI.getTemplateElements(categoryId) | 见 api 中 paymentCategory 相关 | | 明细表列配置 | detailTableFieldAPI.getList(elementId) | 见 api 中 detailTableField | | 部门/用户 | departmentAPI.getTree()、userAPI.getSimpleList() | 部门树、用户简单列表 | | 审批流程简述 | plannedExpenditureAPI.getOaFlowDetails(flowIds) | 批量取 OA 流程展示信息 | | 事前流程实体+模板 | plannedExpenditureAPI.getDetail(relatedId)、plannedExpenditureTemplateAPI.getByCategory(categoryId) | 事前流程详情、按分类取模板 | | 合同相关 | ContractInfoCard 内 contractAPI、paymentAPI、plannedExpenditureAPI 等 | 合同详情、合同下支付列表、关联事前流程等 | | 相关流程 HTML | oaFlowAPI.renderPrintTemplates(flowIds) | POST /oa/flow/render-print-templates | --- ## 六、状态与缓存(前端) - `payment`:当前付款详情,整页主数据源。 - `paymentTemplateElements` / `visiblePaymentTemplateElements`:模板元素列表与「有值才展示」的过滤结果。 - `templatesCache`:按事前分类 id 缓存的打印用模板,避免重复请求。 - `flowDetailsCache`:按流程 id 缓存的流程简述,供审批流程元素展示。 - `detailTableFieldsMap`:按明细表元素 id 缓存的列配置。 - `departmentMap` / `userMap`:部门、用户 id→名称。 - `collectedFlowIds`:当前页及子组件上报的流程 id 集合,用于拉取「相关流程详情」。 - `renderedPrintTemplates`:接口返回的流程打印 HTML 列表,驱动「相关流程详情」区块。 - `relatedPlannedExpenditure` / `relatedPlannedExpenditureTemplate`:仅当 `related_type === 'planned_expenditure'` 时有效,用于 PlannedExpenditureInfoCard。 --- ## 七、与 URL 中 id 的对应关系 对 `http://czemc.localhost/budget/#/payment/payment-detail-print/161`: - `161` 即 `route.params.id`,作为 `paymentId` 传入 `paymentAPI.getDetail(161)`。 - 若存在,返回的 `Payment` 即 id=161 的付款记录,整页展示、关联内容、流程收集与「相关流程详情」都基于这一条付款数据派生而来。 --- ## 八、相关文件索引 | 角色 | 路径 | |------|------| | 页面组件 | `czemc-budget-execution-frontend/src/views/payment/PaymentDetailPrint.vue` | | 路由 | `czemc-budget-execution-frontend/src/router/index.js` | | 付款接口 | `paymentAPI.getDetail` → `GET /budget/payments/{id}` | | 付款详情后端 | `backend/Modules/Budget/app/Http/Controllers/Api/PaymentController.php`(show、formatPayment) | | 合同信息卡片 | `czemc-budget-execution-frontend/src/components/payment-print/ContractInfoCard.vue` | | 事前流程信息卡片 | `czemc-budget-execution-frontend/src/components/payment-print/PlannedExpenditureInfoCard.vue` | | 事前模板只读(含 collect-flow-id) | `czemc-budget-execution-frontend/src/components/PlannedExpenditureTemplateReadonly.vue` | | 相关流程详情渲染说明 | `czemc-budget-execution-frontend/docs/付款详情打印页-相关流程详情渲染说明.md` | | 流程打印模版 API / 后端 | `oaFlowAPI.renderPrintTemplates`、`backend/Modules/Oa/.../FlowController.php` :: renderPrintTemplates | 以上为付款详情打印页(含 `/payment/payment-detail-print/161`)的数据与渲染流程梳理,便于从 URL → 接口 → 状态 → 区块逐层对照。