编辑 | blame | 历史 | 原始文档

课题经费拨付对接财务报销 - 前端联调方案

涉及模块:yudao-module-research(课题管理)↔ yudao-module-finance(财务报销),跨模块通过新建的 yudao-module-finance-api 本地 Bean 调用。
后端接口前缀:/research/fund-record
附件关联:课题侧 recordType = research_fund_record,财务侧 recordType = finance_reimbursement,application = file(同一批 blob 双绑,互不影响)

涉及页面

文件 说明
src/api/research/fund/index.ts FundRecord 类型补 4 个字段;createFundRecord / updateFundRecord 注释更新
src/views/research/application/data.ts FundStatus 新增 APPROVING: 15、REJECTED: 30;useFundColumns 新增「财务报销单号」「驳回原因」两列
src/views/research/application/modules/fund-form.vue 移除「拨付状态」下拉(状态改为系统驱动);「拨付凭证」改必填;编辑已驳回记录时展示驳回原因
src/views/research/application/modules/fund-panel.vue 编辑/删除按钮改为仅「待拨付」可见;「已驳回」行新增「重新发起报销」按钮;按状态补顶部提示
src/views/research/application/detail/approve/index.vue 无需改(内嵌 fund-panel,字典驱动展示自动兼容新状态)

前端 finance 模块页面**无需改动**:报销单由后端自动创建并提交,财务人员在既有的「财务报销 → 报销单」列表里正常审批即可。

字典已由 SQL 脚本补齐,前端继续用 getDictOptions(DICT_TYPE.RESEARCH_FUND_STATUS) / CellDict 取值,无需新建枚举:

字典类型 名称 取值
research_fund_status 经费拨付状态 0 待拨付 / 15 报销审批中 / 20 已拨付 / 30 已驳回

字典项 id 段:8100401 待拨付 / 8100403 报销审批中 / 8100402 已拨付 / 8100404 已驳回。

按钮权限标识(无变化,沿用一期):

research:fund:create、research:fund:update、research:fund:delete、research:fund:query

业务流程与数据带入

课题详情 → 经费拨付面板
        │
        登记拨款(拨付批次、拨付金额、拨付日期、收款单位、备注、拨付凭证)
        │  ← 凭证必填:先上传拿 blobId,再把全部 blobId 放进本次请求体一起提交
        ▼
   create 接口(一条龙,前端只需调一次)
        ├── 1. 课题侧落 research_fund_record 台账(状态先置「待拨付」)
        ├── 2. 同一批 blob 绑定到课题台账(research_fund_record)
        ├── 3. 自动创建财务报销单 finance_reimbursement(1:1、金额一致)
        │      标题 = 课题〔课题名〕第N期/第N次经费拨款
        │      明细固定 1 行:费用类型=其他(5)、发票金额=拨款金额、发票日期=拨付日期、费用说明=标题
        ├── 4. 立即提交 BPM 审批(finance_reimbursement_approve)
        └── 5. 台账回写 reimbursementId / reimbursementNo,状态置「报销审批中(15)」
        ▼
财务审核 → 财务主管审批(在财务模块的报销单审批中心完成)
        │
        ├── 通过  → 台账自动变「已拨付(20)」
        ├── 驳回  → 台账自动变「已驳回(30)」,并回写驳回原因 + 驳回时间
        └── 撤回/取消 → 台账退回「待拨付(0)」,可编辑后重新发起

信息带入(关键)

从 到 带入字段
课题申报书 经费拨付登记弹窗 课题名称、立项编号、申请经费(用于余额提示)、可登记性(仅「已立项」可登记)
经费拨付登记 自动生成的财务报销单 标题(课题名 + 批次)、报销总金额 = 拨付金额、申请日期 = 拨付日期、备注、费用说明、申请人 = 当前登录用户
经费拨付登记 财务报销单凭证 同一批 blobIds 双绑到课题台账与财务报销单
财务报销审批结果 课题经费拨付台账 状态(20/30/0)、驳回原因、驳回时间

API

方法 路径 说明
POST /research/fund-record/create 登记经费拨付(后端自动创建并提交财务报销审批)
PUT /research/fund-record/update 修改并重新发起报销(仅「待拨付」「已驳回」可改)
DELETE /research/fund-record/delete?id= 删除拨款记录(仅「待拨付」可删,联动清理财务侧草稿报销单)
GET /research/fund-record/list?applicationId= 某课题申报书下的经费拨付记录列表

请求参数(create / update 共用同一个 VO):

参数 类型 必填 说明
id Long update 必填 拨款记录编号
applicationId Long 是 课题申报书 ID
batchName String 否 拨付批次,如「第一期」;留空时标题按 第N次 自动编号
amount BigDecimal 是 拨付金额(元),不得为负
payDate LocalDate(yyyy-MM-dd) 否 拨付日期;留空时后端按当天处理
payee String 否 收款单位/账户名
remark String 否 备注
blobIds Long[] 是 拨付凭证附件 blobId 列表;全量替换语义,清空必须传空数组

⚠ status 字段已从请求体中移除:拨付状态由系统驱动(登记 → 报销审批中 → 已拨付/已驳回),前端不要再传,也不要在表单里放状态下拉。

响应字段新增(/list 返回的每条记录):

字段 类型 说明
reimbursementId Long 关联财务报销单 ID
reimbursementNo String 关联财务报销单号(登记成功后回填)
rejectReason String 财务报销驳回原因(BPM 回写)
rejectTime LocalDateTime 财务报销驳回时间(BPM 回写)

响应示例:

{
  "code": 0,
  "data": [
    {
      "id": 3,
      "applicationId": 2,
      "batchName": "第一期",
      "amount": 50000.0,
      "payDate": "2026-12-01",
      "payee": "XX大学",
      "status": 15,
      "reimbursementId": 7,
      "reimbursementNo": "BX20260929000007",
      "rejectReason": "",
      "rejectTime": null,
      "remark": "第一期拨款",
      "creatorName": "超级管理员",
      "createTime": "2026-09-29 10:00:00",
      "attachmentList": [],
      "hasAttachment": true
    }
  ]
}

字段展示规则

字段 展示位置 说明
status 列表「拨付状态」列 字典 research_fund_status 渲染,0/15/20/30 四态
reimbursementNo 列表「财务报销单号」列 登记成功后回填;为空显示 -;财务人员在财务模块按此单号查单
rejectReason 列表「驳回原因」列;编辑弹窗顶部 Alert 仅「已驳回」有值;未填时后端回写「财务未填写驳回原因」
rejectTime 仅后端存储 列表不展示,供排查/追溯
hasAttachment 列表「拨付凭证」列 凭证已必填,仅「已上传 / 缺失」两态

业务规则说明

场景 规则
单据关系 一条拨款记录 ⟷ 一张财务报销单,**1:1、金额一致**;一个批次一张单
登记即提交 课题侧点保存后立即自动提交 BPM,**不需要**再去财务模块提交一次
可登记前提 只有**已立项**的课题申报书才能登记经费拨付
凭证必填 拨付凭证必填,会随自动生成的财务报销单一起送交财务审批
金额上限 本次金额 + 该申报单已登记金额 ≤ 申请预算(budgetAmount)
修改前提 只有「待拨付(0)」「已驳回(30)」可修改并重新发起报销;「报销审批中」需财务端先撤回或等待结果
驳回重发 「已驳回」记录改金额/凭证/批次后重新发起,原有金额、凭证、批次不丢失,驳回原因与时间被清空
删除前提 只有「待拨付(0)」可删除;若关联的财务报销单已不是「草稿」,删除会被拒绝并提示联系财务确认
审批回写 报销通过 → 台账「已拨付(20)」;驳回 → 「已驳回(30)」+ 原因/时间;撤回或取消 → 退回「待拨付(0)」
无流程兜底 财务审批分类下没有已发布流程时,登记直接失败并提示去 BPM 创建发布流程,**不会留下孤儿草稿报销单**(后端事务回滚)

注意事项

  • 必须先部署财务报销审批流程:bpm_category 中 finance_reimbursement_approve 分类已存在,但其下必须有一个**已发布**的流程定义(2 节点:财务审核 → 财务主管审批),否则登记拨款会报「请先在 BPM 创建并发布报销审批流程后重试」。
  • 拨付明细由系统生成,不可编辑:报销单的明细固定 1 行(费用类型=其他、发票金额=拨款金额、发票日期=拨付日期),前端不要在课题侧做明细编辑。
  • 状态只读:拨付状态由系统与 BPM 驱动,前端任何表单都不要再提交 status。
  • 删除是"两清":删待拨付记录时会联动删除财务侧的草稿报销单;财务侧已提交/已通过的报销单必须先撤回或处理,否则删除被拒。
  • 软关联无外键:台账与报销单靠 reimbursement_id 关联。若财务侧**直接删除**了报销单,台账会留下悬空 ID,此时再次修改会提示「关联的财务报销单已不存在,请删除本条拨款记录后重新登记」。
  • 附件为全量替换语义:修改记录时 blobIds 传的是全部凭证;不传或传空数组会清空凭证(且后端会先校验必填并直接拒绝)。
  • 列表页余额提示仅供参考:可用余额 = 申请经费 − 已登记拨付合计,最终以服务端累计校验为准(超出会返回带「本次/已登记/合计/上限」四要素的精确报错)。