云
2026-09-29 f87ce86307056f63f79312178037cc8714eb2b13
docs/project-business/index.html
@@ -10,7 +10,7 @@
  --line:#24344f; --text:#dbe4f0; --muted:#8fa1b8;
  --c-base:#8a94a6; --c-sale:#4f9cff; --c-sup:#c9a86a; --c-erp:#5fc79e;
  --c-prod:#e0b34f; --c-wm:#7e6bd6; --c-qc:#e06c6c; --c-dv:#59a8b8;
  --c-as:#c78bd6; --c-hrm:#9db85a; --c-bpm:#e6a23c; --c-ai:#56c8d8; --c-fin:#3ec9a7; --c-ums:#d6955c; --c-res:#e070a8;
  --c-as:#c78bd6; --c-hrm:#9db85a; --c-bpm:#e6a23c; --c-ai:#56c8d8; --c-fin:#3ec9a7; --c-ums:#d6955c; --c-res:#e070a8; --c-arch:#7fb3d5;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
@@ -114,6 +114,7 @@
  <a data-t="flow-finance"><span class="dot" style="background:var(--c-fin)"></span>财务报销流程</a>
  <a data-t="flow-ums"><span class="dot" style="background:var(--c-ums)"></span>会员入会流程</a>
  <a data-t="flow-research"><span class="dot" style="background:var(--c-res)"></span>课题管理流程</a>
  <a data-t="flow-archive"><span class="dot" style="background:var(--c-arch)"></span>档案管理流程</a>
  <div class="group">结构与数据</div>
  <a data-t="relation"><span class="dot" style="background:var(--c-bpm)"></span>系统关系</a>
  <a data-t="dataflow"><span class="dot" style="background:var(--c-fin)"></span>数据流</a>
@@ -143,6 +144,7 @@
<section class="page" id="flow-finance"></section>
<section class="page" id="flow-ums"></section>
<section class="page" id="flow-research"></section>
<section class="page" id="flow-archive"></section>
<section class="page" id="relation">
  <h2 class="pt">系统关系</h2>
  <p class="desc">模块之间的调用与数据依赖:实线=单据/数据流向,虚线=审批回调与辅助能力。</p>
@@ -195,6 +197,7 @@
      "FIN(发票报销,独立模块)",
      "UMS(学会会员,独立模块)",
      "RES(科研课题,独立模块)",
      "ARC(档案管理,独立模块)",
      "CRM(客户关系)",
      "SRM(供应商关系)",
      "HRM(人力资源)",
@@ -206,14 +209,14 @@
    "businessPositioning": "让工厂的订单、物料、生产、库存、质量、人员、资金在一个系统内闭环流转,管理层可通过 BI 大屏掌握全局。",
    "coreChain": "CRM 商机/合同 → ERP 销售订单 → MES 主生产计划/工单/报工 → MES 质检与仓储 → 销售出库发货 → 开票回款 → 售后闭环",
    "techBase": "Spring Boot + MyBatis + Flowable + Redis + Quartz/RocketMQ/Kafka + Milvus 向量库 + 通义千问",
    "database": "MySQL 8.4,运行库 mom-jssm 共 427 张表(含 system_*、bpm_*、act_* 底座表与 mes_*/erp_*/crm_*/srm_*/hrm_*/mdm_*/ai_*/finance_*/ums_*/research_* 业务表),多租户已关闭",
    "database": "MySQL 8.4,运行库 mom-jssm 共 430 张表(含 system_*、bpm_*、act_* 底座表与 mes_*/erp_*/crm_*/srm_*/hrm_*/mdm_*/ai_*/finance_*/ums_*/research_*/archive_* 业务表),多租户已关闭",
    "frontend": "mom-pro2-before(Vue3 管理后台,同仓库存放,只读参考)"
  },
  "stats": {
    "businessModules": 16,
    "coreObjects": 56,
    "documentFlows": 9,
    "approvalListeners": 15,
    "businessModules": 17,
    "coreObjects": 59,
    "documentFlows": 10,
    "approvalListeners": 24,
    "aiCapabilities": 8,
    "wmBillTypes": 15
  },
@@ -344,10 +347,18 @@
    "课题管理:经费拨付台账的「已拨付(20)」等价于报销单「已通过(20)」,不含出纳实际付款动作;若日后需要独立的「已付款」状态,需另增状态与审批节点【二期可扩展】",
    "课题管理:申报单与 ums_member 是软关联(无外键),会员被删除后申报单会留下悬空 memberId;成员列表需容错展示「会员已删除」【待确认是否加外键或删除保护】",
    "课题管理:BPM 流程 research_topic_approve 三节点默认审批人为「角色=超级管理员(1) + 依次审批」,该 dev 库超级管理员角色下有 4 个用户(admin/张娟/马芳/马贞),每个节点需 4 人会签才推进;全新安装库该角色仅 admin 一人、流程可开箱即用。dev 库需减少超级管理员用户或改在 BPM 设计器中为每节点指定审批人【环境配置项,非代码缺陷】",
    "课题管理:立项通知复用 system_notice 系统公告,不新增 system_notify_template、不发站内信;如需短信/站内信定向通知需另行配置【待确认通知渠道】"
    "课题管理:立项通知复用 system_notice 系统公告,不新增 system_notify_template、不发站内信;如需短信/站内信定向通知需另行配置【待确认通知渠道】",
    "档案管理:档案借阅 BPM 流程 archive_borrow_approve 为手工导出部署产物(_archive_bpm_export.sql 内 act_*/bpm 表的 UUID 与时间戳只能在部署时生成,无法预写),必须先在 BPM 模型部署再导出再合并进 config_export_all 阶段一;顺序错会导致新库初始化时该流程缺失【部署顺序硬约束,已在文件头与 README 双重标注】",
    "档案管理:菜单 1075600~1075699 与各 archive:* 权限点仅在归档脚本中,普通角色未配 system_role_menu,非超管登录看不到「档案管理」目录【待确认是否补授权,与财务报销/会员管理同类问题】",
    "档案管理:档案与来源单据(课题申报书/会员/报销单)为软关联,来源单据被删除后档案的 source_id/source_no 会成为悬空快照;档案本身不随来源单据删除而删除【待确认是否需要删除保护或外键】",
    "档案管理:需求中的「学会文件、会议纪要、调研报告、学术论文、合同协议」等电子文档由「文书档案」分类承载,系统内无对应来源模块,仅支持手工录入并挂电子附件;合同档案未纳入自动归档(用户明确排除)【已确认的边界】",
    "档案管理:逾期提醒按用户决策仅查询时实时计算(不建 infra_job、不发站内信),借阅列表「逾期」列与 /overdue-page 独立入口呈现;若日后需要到期主动推送,需另加定时任务与通知渠道【用户已确认的简化,二期可扩展】",
    "档案管理:「同一档案仅允许一条未归还借阅单」由应用层 submit 校验 + 审批通过时条件更新(UPDATE ... WHERE status=10)共同保证,MySQL 无法对「部分状态唯一」建约束;校验与更新之间的理论窗口已收敛为可感知的冲突报错(档案已被占用)而非脏数据【已接受的风险】",
    "档案管理:档案统计按分类/密级/载体三组 GROUP BY 聚合(无 N+1),当前量级可接受;档案过万后需改为缓存或物化统计表【本期不做】",
    "档案管理:跨模块改表——research_application / ums_member / finance_reimbursement 各新增可空列 archive_document_id(archive_module_migration.sql 用 information_schema 守卫保证幂等),需与三方模块确认变更窗口【跨模块改表,无破坏性】"
  ],
  "generatedAt": "2026-09-29",
  "analysisBasis": "基于 dev_business 分支 87bf4a99 源码,6 组并行源码走读(MES 生产质量 / MES 仓储 / ERP / CRM+SRM / 售后+HRM / AI+BI+MDM+BPM+底座);2026-09-28 增量补充 yudao-module-finance 独立财务报销模块(报销单 + 明细 + 发票附件 + BPM 审批 + 归档)与 yudao-module-ums 独立会员管理模块(入会申请 + BPM 两级审批 + 审批通过自动建会员与登录账号 + 会员列表/通讯录);2026-09-28 增量:BPM 流程定义 ums_membership_approve(入会审批)已在 mom-jssm 部署并并入 config_export_all 阶段一(分类 ums_membership_approve,秘书处初审 → 理事会审议,两节点审批人均为「角色」策略、角色=超级管理员(1) 兜底,表单类型=自定义表单,查看路径 /ums/application/detail/approve/index.vue);同时修复 mom-jssm 由 CREATE TABLE ... LIKE 克隆导致的 47 个指向 ruoyi-vue-pro 的 act_*/flw_* 跨库外键(重建为指向 mom-jssm 自身,孤儿行预检为 0);2026-09-28 增量:新增 yudao-module-research 独立科研课题模块一期(课题指南发布 + 在线申报 + 专家评审明细 + BPM 三级立项审批 + 立项通知公告 + 经费拨付记录,4 张 research_* 表 / 5 个字典 / bpm_category id=8002 / 流程 research_topic_approve / 菜单 1075510~1075553),并并入 config_export_all_20260928 阶段一;申报人取 ums_member(软关联)、立项通知复用 system_notice 公告、拨款凭证走 system 附件中心 recordType=research_fund_record;2026-09-29 增量:课题经费拨付对接财务报销——新建 yudao-module-finance-api(FinanceReimbursementApi:建单+提交/改单+重提/删除/查询四方法,本地 Spring Bean 调用,无需 Feign),课题侧登记拨款时 1:1 自动生成 finance_reimbursement(系统生成 1 行明细:费用类型=其他 5、发票金额=拨付金额、发票日期=拨付日期、说明=「课题〔名〕第 N 期拨款」)并立即提交 BPM,回写 reimbursement_id/reimbursement_no、台账置「报销审批中(15)」;凭证改为登记时必填并双绑(research_fund_record + finance_reimbursement);新增 ResearchFundStatusListener(第 15 个业务监听器,与 finance 自己的 FinanceReimbursementStatusListener 订阅同一流程 key 并行触发)按审批结果回写台账:通过→已拨付(20)、驳回→已驳回(30)+驳回原因/时间、取消流程→退回待拨付(0)可改后可重新发起(发起人撤回只把实例退回发起节点、流程未结束,不触发回写,台账保持 15);新造 2 节点 BPMN docs/sql/finance_reimbursement_approve.bpmn(财务审核 → 财务主管审批,category id=216 已存在),2026-09-29 已在 mom-jssm 部署为版本 1(form_type=20、自定义表单创建路径 /finance/reimbursement/index、查看路径 /finance/reimbursement/detail/approve/index.vue)并并入 config_export_all_20260929 阶段一,两级审批全通过/驳回/取消三条回写链路均已端到端验证"
  "analysisBasis": "基于 dev_business 分支 87bf4a99 源码,6 组并行源码走读(MES 生产质量 / MES 仓储 / ERP / CRM+SRM / 售后+HRM / AI+BI+MDM+BPM+底座);2026-09-28 增量补充 yudao-module-finance 独立财务报销模块(报销单 + 明细 + 发票附件 + BPM 审批 + 归档)与 yudao-module-ums 独立会员管理模块(入会申请 + BPM 两级审批 + 审批通过自动建会员与登录账号 + 会员列表/通讯录);2026-09-28 增量:BPM 流程定义 ums_membership_approve(入会审批)已在 mom-jssm 部署并并入 config_export_all 阶段一(分类 ums_membership_approve,秘书处初审 → 理事会审议,两节点审批人均为「角色」策略、角色=超级管理员(1) 兜底,表单类型=自定义表单,查看路径 /ums/application/detail/approve/index.vue);同时修复 mom-jssm 由 CREATE TABLE ... LIKE 克隆导致的 47 个指向 ruoyi-vue-pro 的 act_*/flw_* 跨库外键(重建为指向 mom-jssm 自身,孤儿行预检为 0);2026-09-28 增量:新增 yudao-module-research 独立科研课题模块一期(课题指南发布 + 在线申报 + 专家评审明细 + BPM 三级立项审批 + 立项通知公告 + 经费拨付记录,4 张 research_* 表 / 5 个字典 / bpm_category id=8002 / 流程 research_topic_approve / 菜单 1075510~1075553),并并入 config_export_all_20260928 阶段一;申报人取 ums_member(软关联)、立项通知复用 system_notice 公告、拨款凭证走 system 附件中心 recordType=research_fund_record;2026-09-29 增量:课题经费拨付对接财务报销——新建 yudao-module-finance-api(FinanceReimbursementApi:建单+提交/改单+重提/删除/查询四方法,本地 Spring Bean 调用,无需 Feign),课题侧登记拨款时 1:1 自动生成 finance_reimbursement(系统生成 1 行明细:费用类型=其他 5、发票金额=拨付金额、发票日期=拨付日期、说明=「课题〔名〕第 N 期拨款」)并立即提交 BPM,回写 reimbursement_id/reimbursement_no、台账置「报销审批中(15)」;凭证改为登记时必填并双绑(research_fund_record + finance_reimbursement);新增 ResearchFundStatusListener(第 15 个业务监听器,与 finance 自己的 FinanceReimbursementStatusListener 订阅同一流程 key 并行触发)按审批结果回写台账:通过→已拨付(20)、驳回→已驳回(30)+驳回原因/时间、取消流程→退回待拨付(0)可改后可重新发起(发起人撤回只把实例退回发起节点、流程未结束,不触发回写,台账保持 15);新造 2 节点 BPMN docs/sql/finance_reimbursement_approve.bpmn(财务审核 → 财务主管审批,category id=216 已存在),2026-09-29 已在 mom-jssm 部署为版本 1(form_type=20、自定义表单创建路径 /finance/reimbursement/index、查看路径 /finance/reimbursement/detail/approve/index.vue)并并入 config_export_all_20260929 阶段一,两级审批全通过/驳回/取消三条回写链路均已端到端验证;2026-09-29 增量:新增 yudao-module-archive 独立档案管理模块 + yudao-module-archive-api(ArchiveDocumentApi:archiveBySource 按 sourceType+sourceId 幂等归档 / isArchived / getBySource 三方法,本地 Spring Bean 调用,无 Feign),覆盖书架分类(archive_category 树形、code 唯一、defaultSecretLevel 默认密级、6 条初始分类:会员/课题/会议/财务/文书/党建,财务默认密级=保密 3)、档案管理(archive_document:DA+yyyyMMdd+6 位流水编号、密级三档 1 公开 2 内部 3 保密、载体三型 1 电子 2 实体 3 电子+实体、实体位置四字段 shelfNo/layerNo/columnNo/boxNo + storePlace、来源四类 sourceType 1 手工 2 课题 3 会员 4 财务带 sourceNo/sourceId/sourceTitle 冗余快照、状态 10 在库 20 借出中、电子附件走 system 附件中心 recordType=archive_document、archiveBySource 幂等短路 + 三方表 archive_document_id 回写作为已归档硬标记,重复归档由来源侧错误码拦截且 archive 侧 DOCUMENT_DUPLICATE_SOURCE 兜底)、借阅登记与审批(archive_borrow:JY+同级流水编号、借阅人信息/借阅目的/归还期限、状态 0 草稿 15 审批中 20 借出中 30 已归还 35 已驳回,仅 0/35 可改可重提、仅 0 可删、仅 20 可登记归还;submit 前校验同档案不得已有 15/20 在途借阅,先解析流程再建单杜绝孤儿草稿;BPM 流程 archive_borrow_approve 两级:档案管理员审核 → 分管领导审批;监听器 ArchiveBorrowStatusListener 按 businessKey 回写 20+approveTime / 35+驳回原因时间 / 退回 0,审批通过时条件更新档案 SET status=20 WHERE status=10,0 行则报档案已被占用并回滚)、归还登记(条件更新 20→30 + returnTime/归还确认人,再把档案条件更新回 10,形成闭环)、逾期实时计算(overdue=status==20 且 returnDeadline<今天,不建 infra_job 不发站内信,列表「逾期」列 + /archive/borrow/overdue-page 独立入口)、档案统计(4 卡片:总数/在库/借出/逾期 + 分类/密级/载体三组 GROUP BY 聚合,无 N+1);敏感档案用密级字段 + 独立权限点 archive:document:sensitive,/get 越权抛 DOCUMENT_SENSITIVE_NO_PERMISSION、/page 与 /export-excel 强制过滤 secret_level<>3,统一走 applySecretLevelFilter / validateSecretLevelVisible 两私有方法;新增 3 张表 archive_category/archive_document/archive_borrow、6 个字典(82000~82005)、bpm_category id=8003 + 手写 docs/sql/archive_borrow_approve.bpmn(category=archive_borrow_approve、form_type=20、创建路径 /archive/borrow/index、查看路径 /archive/borrow/detail/approve/index.vue)已在 mom-jssm 部署为版本 1、菜单 1075600~1075699;三方归档联动为列表页手动「归档」按钮(非事件驱动,归档不回写来源业务状态):课题 research_application status=20 已立项 → sourceType=2 密级 2 内部 sourceNo=立项编号;会员 ums_member status=1 正常 → sourceType=3;财务 finance_reimbursement status=20 → sourceType=4 密级 3 保密,与既有 20→40 + archiveTime 同事务叠加;三张来源表各新增可空列 archive_document_id(archive_module_migration.sql 用 information_schema 守卫保证幂等)。全库表数 427→430;业务状态监听器实际计数修正为 24 个 *StatusListener(14 个继承 BpmProcessInstanceStatusEventListener)。本模块不反向依赖 ums/finance/research,仅提供 -api 子模块由三方手动调用;依赖方向 research/ums/finance → archive-api,无环。本次同步更新的业务可视化产物:新增 mermaid/15-archive-flow.mmd,增量修订 01-business-mindmap / 08-module-relation / 09-data-flow / 10-business-object,以及 data/modules.json(新增 arc 模块、bpm 监听器计数 15→24)、objects.json(新增档案分类/档案/借阅单 3 对象 + 课题申报书/会员/报销单各补 archive_document_id)、flows.json(新增 archive 流程 9 步)、roles.json(新增档案管理员/借阅人/借阅审批人/归档经办人 4 角色)、business.json"
}</script>
<script type="application/json" id="data-modules">{
  "modules": [
@@ -464,10 +475,19 @@
     "upstream": ["会员管理(ums_member 取申报人姓名/单位/职称/电话)", "BPM(流程定义 research_topic_approve / finance_reimbursement_approve)"],
     "downstream": ["system(system_notice 立项通知公告)", "system(附件中心)", "财务(经费拨付生成 finance_reimbursement 报销单·已对接)"],
     "coreTables": ["research_guideline", "research_application", "research_topic_review", "research_fund_record"]},
    {"key": "arc", "name": "档案管理(独立)", "color": "#7fb3d5", "tag": "ARC", "flow": "archive",
     "positioning": "学会/协会型实体与电子档案全生命周期:分类书架规整 → 档案登记与检索 → 借阅审批 → 归还闭环 → 存量与流转统计,并接收课题/会员/财务三方的归档联动",
     "problem": "课题材料、会员材料、财务凭证散落各模块无处归集;纸质档案存放位置靠线下台账,借阅与归还无留痕、逾期无人管;财务等敏感档案无密级管控",
     "features": ["档案分类树(书架·分层分列):会员/课题/会议/财务/文书/党建 6 条初始分类·编码唯一·支持父子层级", "分类默认密级(财务分类=保密)·分类有子分类或下有档案禁删", "档案主表:电子附件 + 实体位置四字段(书架号/层号/列号/册号档案盒)+存放位置描述", "档案编号 DA+yyyyMMdd+6位流水(Redis 每日重置)·借阅单号 JY+同日流水", "密级三档 公开1/内部2/保密3 + 独立权限点 archive:document:sensitive(无权限时列表与导出强制过滤、详情报错)", "载体三型 电子1/实体2/电子+实体3", "来源四类 手工1/课题2/会员3/财务4(记录来源单号/ID/标题快照便于检索)", "全字段检索:标题/关键词 tags/来源单号/分类/密级/载体/状态/归档日期区间 + Excel 导出", "借阅登记(借阅人/部门/电话/日期/目的/归还期限)+BPM 两级审批(档案管理员审核→分管领导审批)·流程 key=archive_borrow_approve", "归还登记:实时更新档案状态回「在库」,形成完整流转闭环", "逾期未还仅查询时实时计算(overdueDays)·列表红色「逾期 N 天」Tag + /overdue-page 独立入口 + 「只看逾期」切换·不建 infra_job 不发站内信", "档案统计:总数/在库/借出中/逾期未还 + 按分类/密级/载体三组分布(4 卡片 + 3 图表)", "对外提供 yudao-module-archive-api(ArchiveDocumentApi:archiveBySource 幂等/ isArchived / getBySource)供课题·会员·财务三方手动归档", "附件走 system 附件中心(recordType=archive_document / archive_borrow)"],
     "objects": ["档案分类", "档案", "借阅单"],
     "roles": ["档案管理员", "分管领导(借阅审批)", "借阅人", "归档经办人(课题/会员/财务)"],
     "upstream": ["课题管理(已立项申报书·archiveApplication)", "会员管理(正常会员·archiveMember)", "财务报销(已通过报销单·既有 archive 叠加)", "BPM(流程定义 archive_borrow_approve)"],
     "downstream": ["system(附件中心 storage_attachment)", "来源表回写 archive_document_id"],
     "coreTables": ["archive_category", "archive_document", "archive_borrow"]},
    {"key": "bpm", "name": "协同审批", "color": "#e6a23c", "tag": "BPM", "flow": null,
     "positioning": "全系统单据审批中枢(Flowable)",
     "problem": "多模块单据需要灵活可配的多级审批",
     "features": ["BPMN+钉钉风格双设计器", "流程定义部署", "审批事件统一回调(BpmProcessInstanceStatusEvent)", "15个业务监听器(同一流程 key 允许多个监听器并行·各自按 key 过滤)", "表单·用户组·抄送·加签"],
     "features": ["BPMN+钉钉风格双设计器", "流程定义部署", "审批事件统一回调(BpmProcessInstanceStatusEvent)", "24个业务状态监听器(*StatusListener·同一流程 key 允许多个监听器并行·各自按 key 过滤·档案借阅 ArchiveBorrowStatusListener 与财务/课题监听器订阅不同 key 互不干扰)", "表单·用户组·抄送·加签"],
     "objects": ["流程模型", "流程实例", "审批任务"],
     "roles": ["审批人(按流程配置)", "流程管理员"],
     "upstream": ["各业务提交审批"], "downstream": ["回调更新各业务单据状态"],
@@ -537,13 +557,16 @@
    {"name": "排班计划", "module": "设备", "table": "mes_cal_plan", "doc": "班组×班次×日期排班,供生产与考勤引用", "upstream": [], "downstream": ["生产任务", "考勤"], "keywords": "排班 班组 班次 日历"},
    {"name": "报告模板", "module": "质检报告", "table": "qc_report_template", "doc": "智能质检报告模板,启用0/停用1;画布内容存在 qc_report_template_version(草稿0/已发布1/已停用2,已发布不可覆盖),currentVersion 指向当前已发布版本;源文件经 AI 导入识别成草稿后由人工确认才成为版本;同一模板重复导入按【替换】处理——先删旧附件(连带 blob 行与磁盘文件)再绑新的,不留孤儿文件;删除模板会连带清附件", "upstream": ["人工设计(GrapesJS 设计器)", "AI 导入草稿(qc-report/ai-import/draft)"], "downstream": ["模板版本", "报告实例"], "keywords": "报告模板 质检报告 template 设计器 版本 AI导入 识别 草稿 源文件替换"},
    {"name": "报告实例", "module": "质检报告", "table": "qc_report_instance", "doc": "出件产物,编号 QR+yyyyMMdd+4位流水按天独立且业务唯一,可显式指定覆盖(注意 uk_report_no 不区分软删除,删掉的号不回收);两条出件入口:通用 generate(调用方自带 context)与 generate-from-qc(数据从 MES 质检单取,权限码 qc-report:instance:generate 已入 system_menu id=1075416,五道校验按业务优先级只报第一处:105_000 类型非法 / 105_001 单据不存在 / 105_002 未完成 / 105_003 未判定 / 105_005 模板类型不符 / 105_006 无可用检验项;四张质检单列表的行操作「出报告」仅在 status=已完成时可见,弹窗只列 reportType 一致、模板启用、且 currentVersion 指向的版本已发布的模板(后端 /qc-report/template/selectable 判定——停用版本不清空 currentVersion,前端拿分页结果自己推导会漏),结果就地展示并跳本页列表);冻结 data_snapshot(判定后数据,含后端算好的 PASS/FAIL 与合格率)与 render_html;regenerate 只重渲排版、数据与编号不变;business_id/business_type 存 MES 表名(mes_qc_iqc 等)与单据 ID,可反查、一单可出多份;报告头另带单据原判定 qcResult(数)/qcResultText(中文,合格/特采/不合格退货/不合格报废),与引擎三态判定并存互不覆盖;响应带 undecidableCount=快照中 result 为空串的项数与 warnings(分组标题跳过/指标已删/未录实测值/样品超3),两者都不落库、事后看不到", "upstream": ["报告模板版本", "质检单上下文(通用 generate 由调用方传入)", "MES 质检单 IQC/IPQC/OQC/RQC(generate-from-qc 经 MesQcReportApi 取数)"], "downstream": ["前端实例页 /qc/report-instance(列表·iframe预览·快照页签·导出PDF)", "PDF归档(system_storage_attachment recordType=qc_report_instance)"], "keywords": "报告实例 出件 QR编号 快照 复现 regenerate PDF归档 报告实例页 导出PDF generate-from-qc 质检单出报告 出报告弹窗 qcResult undecidableCount warnings 待判定 反查 业务单据筛选"},
    {"name": "报销单", "module": "财务报销", "table": "finance_reimbursement", "doc": "单号可自定义(中间不允许空格,与已有单号重复则报错);新增时留空或纯空格由系统生成 BX+yyyyMMdd+6位流水(Redis 每日重置),修改时留空表示保持不变。status: 0草稿/15审批中/20已通过/35已驳回/40已归档;仅草稿可删、草稿与已驳回可改、仅已通过可归档;提交后由 BPM 监听器按结果回写状态(取消退回草稿),审批中 processInstanceId 被回写。来源两条:① 财务模块页面人工填报 ②课题管理「经费拨付」经 FinanceReimbursementApi(yudao-module-finance-api)自动建单并立即提交(1:1、金额一致、系统固定 1 行明细·费用类型=其他)——后者的审批结果由课题侧 ResearchFundStatusListener 订阅同一流程回写拨款台账,报销单本身不回写任何外部单据", "upstream": ["课题管理(经费拨付·经 FinanceReimbursementApi 自动建单)", "人工填报"], "downstream": ["报销明细", "发票附件(storage_attachment·recordType=finance_reimbursement)", "课题拨款台账(仅经 BPM 事件回写状态)"], "keywords": "报销单 报销 发票 reimbursement BX 归档 财务 费用 自定义单号 课题经费拨付 自动建单 FinanceReimbursementApi"},
    {"name": "报销单", "module": "财务报销", "table": "finance_reimbursement", "doc": "单号可自定义(中间不允许空格,与已有单号重复则报错);新增时留空或纯空格由系统生成 BX+yyyyMMdd+6位流水(Redis 每日重置),修改时留空表示保持不变。status: 0草稿/15审批中/20已通过/35已驳回/40已归档;仅草稿可删、草稿与已驳回可改、仅已通过可归档;提交后由 BPM 监听器按结果回写状态(取消退回草稿),审批中 processInstanceId 被回写。来源两条:① 财务模块页面人工填报 ②课题管理「经费拨付」经 FinanceReimbursementApi(yudao-module-finance-api)自动建单并立即提交(1:1、金额一致、系统固定 1 行明细·费用类型=其他)——后者的审批结果由课题侧 ResearchFundStatusListener 订阅同一流程回写拨款台账,报销单本身不回写任何外部单据;archive_document_id 非空表示已归档", "upstream": ["课题管理(经费拨付·经 FinanceReimbursementApi 自动建单)", "人工填报"], "downstream": ["报销明细", "发票附件(storage_attachment·recordType=finance_reimbursement)", "课题拨款台账(仅经 BPM 事件回写状态)", "档案管理(既有归档动作同事务叠加·生成「保密 3」级财务档案并回写 archive_document_id)"], "keywords": "报销单 报销 发票 reimbursement BX 归档 财务 费用 自定义单号 课题经费拨付 自动建单 FinanceReimbursementApi 财务档案 保密 archive_document_id"},
    {"name": "报销明细", "module": "财务报销", "table": "finance_reimbursement_item", "doc": "报销单的费用行:费用类型(1差旅/2办公/3招待/4交通/5其他)、发票号码、发票金额、发票日期、开票方、费用说明;随主表一次性提交(先删后增全量覆盖),提交时必须剥掉行 id 与 reimbursementId —— 明细删除是软删,回传原 id 会与已软删行主键冲突", "upstream": ["报销单"], "downstream": [], "keywords": "报销明细 费用明细 费用类型 发票金额 item 明细行 差旅"},
    {"name": "入会申请单", "module": "会员管理", "table": "ums_application", "doc": "单号 SQ+yyyyMMdd+6位流水(Redis 每日重置),后端生成不可自定义;memberType 1个人/2单位决定字段分叉(个人用 workUnit/title,单位用 legalPerson/organizationCode);memberGrade 按类型取不同字典;status: 0草稿/15审批中/20已通过/35已驳回。仅草稿可删(连带清附件)、草稿与已驳回可改可重提;提交后由 BPM 监听器按结果回写(取消退回草稿),审批中回写 processInstanceId;审批通过触发自动建会员与系统账号。独立模块,不与其它业务模块产生单据关联", "upstream": ["人工填报(申请人)", "证明材料附件(storage_attachment·recordType=ums_application)"], "downstream": ["会员(审批通过自动创建)", "BPM 流程实例(ums_membership_approve 分类)"], "keywords": "入会申请 入会 会员申请 application SQ 秘书处 理事会 审批 会员类型 个人 单位 法定代表人 研究方向 申请等级"},
    {"name": "会员", "module": "会员管理", "table": "ums_member", "doc": "单号 HY+yyyyMMdd+6位流水(Redis 每日重置);两个来源:①入会申请审批通过自动创建(回填 applicationId 与 userName/系统账号) ②会员列表手工新增。status: 1正常/0暂停;memberGrade 按 memberType 取对应字典,校验规则是单位会员(type=2)不可选『理事长』(grade=5)。自动建档时入会日期=当天、不搬运 contactUser/unitIntro/expireDate(申请单无对应字段);自动建的系统账号用户名为联系电话且初始密码同为联系电话,部门固定为「学会会员」;手机号重复会明确报错且整单事务回滚", "upstream": ["入会申请单(审批通过)", "人工新增", "附件(storage_attachment·recordType=ums_member)"], "downstream": ["会员通讯录(按 regionCode/industry 检索)", "system_users(登录账号)"], "keywords": "会员 member HY 会员编号 会员等级 会员类型 通讯录 地区 行业 入会日期 有效期"},
    {"name": "会员", "module": "会员管理", "table": "ums_member", "doc": "单号 HY+yyyyMMdd+6位流水(Redis 每日重置);两个来源:①入会申请审批通过自动创建(回填 applicationId 与 userName/系统账号) ②会员列表手工新增。status: 1正常/0暂停;memberGrade 按 memberType 取对应字典,校验规则是单位会员(type=2)不可选『理事长』(grade=5)。自动建档时入会日期=当天、不搬运 contactUser/unitIntro/expireDate(申请单无对应字段);自动建的系统账号用户名为联系电话且初始密码同为联系电话,部门固定为「学会会员」;手机号重复会明确报错且整单事务回滚;archive_document_id 非空表示已归档(归档后列表页隐藏「归档」按钮)", "upstream": ["入会申请单(审批通过)", "人工新增", "附件(storage_attachment·recordType=ums_member)"], "downstream": ["会员通讯录(按 regionCode/industry 检索)", "档案管理(手动「归档」·仅正常状态可归档·经 yudao-module-archive-api 生成档案并回写 archive_document_id)", "system_users(登录账号)"], "keywords": "会员 member HY 会员编号 会员等级 会员类型 通讯录 地区 行业 入会日期 有效期 归档 archive_document_id"},
    {"name": "课题指南", "module": "课题管理", "table": "research_guideline", "doc": "指南编号 GL+yyyyMMdd+6位流水(Redis 每日重置);category 1重点课题/2一般课题;publishStatus 0草稿/20已发布/30已截止,仅草稿可改可删,publish 发布回写 publishTime,close 截止置 30;已产生申报单(applicationMapper.selectCountByGuidelineId 大于 0)的指南禁止删除并在提示中报出该指南下已有多少张申报单;正文 content 为长文本;附件 recordType=research_guideline", "upstream": ["人工维护(学会秘书处)", "指南附件(storage_attachment·recordType=research_guideline)"], "downstream": ["课题申报书(申报时引用且必须已发布并在申报期内)"], "keywords": "课题指南 指南 发布 截止 重点课题 一般课题 GL 指南编号 申报期 申报起止"},
    {"name": "课题申报书", "module": "课题管理", "table": "research_application", "doc": "申报编号 SB+yyyyMMdd+6位流水(Redis 每日重置);guidelineId 关联指南、memberId 关联 ums_member(软关联无外键,会员删除后会留下悬空 memberId 需容错显示);applicantName/workUnit/jobTitle/contactPhone/contactEmail 由选会员自动带出可手改;category 冗余自指南且不信任前端传值;budgetAmount 申请经费为拨付上限;status: 0草稿/15审批中/20已立项/35已驳回。仅草稿可删(连带清附件)、草稿与已驳回可改可重提;submit 前逐条校验「指南已发布」与「现在在申报期内」,任一不满足即拒绝并按维度给出指南名与实际值;审批通过由监听器生成立项编号 researchNo(LX+同日流水)与 approveTime(已有编号幂等跳过);reviewAvgScore/reviewPass 为评审汇总回写值,明细删空时清成未汇总;noticeId 记录已发布的立项通知公告,重复发布被拦截", "upstream": ["课题指南(必须已发布且在申报期内)", "会员(ums_member·带出申报人信息)", "申报附件(storage_attachment·recordType=research_application)"], "downstream": ["专家评审明细", "经费拨付记录", "立项通知(system_notice 公告)", "BPM 流程实例(research_topic_approve 分类)", "附件中心"], "keywords": "课题申报 申报书 申报单 SB 申报编号 立项 立项编号 LX 申请经费 申报书正文 课题组成员 专家评审 评审汇总 立项通知 发布通知 提交审批 驳回 重提"},
    {"name": "课题申报书", "module": "课题管理", "table": "research_application", "doc": "申报编号 SB+yyyyMMdd+6位流水(Redis 每日重置);guidelineId 关联指南、memberId 关联 ums_member(软关联无外键,会员删除后会留下悬空 memberId 需容错显示);applicantName/workUnit/jobTitle/contactPhone/contactEmail 由选会员自动带出可手改;category 冗余自指南且不信任前端传值;budgetAmount 申请经费为拨付上限;status: 0草稿/15审批中/20已立项/35已驳回。仅草稿可删(连带清附件)、草稿与已驳回可改可重提;submit 前逐条校验「指南已发布」与「现在在申报期内」,任一不满足即拒绝并按维度给出指南名与实际值;审批通过由监听器生成立项编号 researchNo(LX+同日流水)与 approveTime(已有编号幂等跳过);reviewAvgScore/reviewPass 为评审汇总回写值,明细删空时清成未汇总;noticeId 记录已发布的立项通知公告,重复发布被拦截;archive_document_id 非空表示已归档(归档后列表页隐藏「归档」按钮)", "upstream": ["课题指南(必须已发布且在申报期内)", "会员(ums_member·带出申报人信息)", "申报附件(storage_attachment·recordType=research_application)"], "downstream": ["专家评审明细", "经费拨付记录", "立项通知(system_notice 公告)", "BPM 流程实例(research_topic_approve 分类)", "档案管理(手动「归档」·仅已立项可归档·经 yudao-module-archive-api 生成档案并回写 archive_document_id)", "附件中心"], "keywords": "课题申报 申报书 申报单 SB 申报编号 立项 立项编号 LX 申请经费 申报书正文 课题组成员 专家评审 评审汇总 立项通知 发布通知 提交审批 驳回 重提 归档 archive_document_id"},
    {"name": "专家评审明细", "module": "课题管理", "table": "research_topic_review", "doc": "一位专家一行的一主多行子表:evaluatorName/evaluatorUnit/evaluatorTitle + topicScore 选题价值与意义(权重0.3) + planScore 研究方案可行性(0.3) + teamScore 团队与研究基础(0.2) + resultScore 预期成果与效益(0.2) + conclusion 1推荐立项/2不推荐立项 + opinion 评审意见 + reviewTime。compositeScore 由后端 weightedScore 计算、ranking 由后端按加权分降序重排,均不接受前端传值;每次增删改后调 recalculate 回写主单 reviewAvgScore(全部专家加权分均值·保留2位)与 reviewPass(均分达标 且 多数结论为推荐立项时为 1);四项分值超出 0~100 时提示指出具体维度与实际值;仅在申报单 status=15 审批中可增删改", "upstream": ["课题申报书(仅审批中可写)"], "downstream": ["课题申报书(回写 reviewAvgScore/reviewPass)"], "keywords": "专家评审 评审明细 评分 加权 权重 排名 ranking compositeScore 推荐立项 评审意见 均分"},
    {"name": "档案分类", "module": "档案管理", "table": "archive_category", "doc": "树形书架分类(parentId·0=顶级),承载「分层分列」规整:6 条初始分类 会员档案 member / 课题档案 research / 会议档案 meeting / 财务档案 finance / 文书档案 document / 党建档案 party;code 全局唯一 uk_code;defaultSecretLevel 为该分类下档案的默认密级(1公开/2内部/3保密,财务分类=3);status 0启用/1停用。仅可改可删,有子分类禁删、该分类下有档案禁删、父分类不能设为自身或其子分类。会议/党建档案系统内无来源模块,仅支持手工录入档案", "upstream": ["人工维护(档案管理员)"], "downstream": ["档案(新增时带出默认密级)"], "keywords": "档案分类 书架 分层分列 会员档案 课题档案 会议档案 财务档案 文书档案 党建档案 category 默认密级"},
    {"name": "档案", "module": "档案管理", "table": "archive_document", "doc": "档案主表,编号 DA+yyyyMMdd+6位流水(Redis 每日重置)。电子与实体兼具:电子走 system 附件中心 recordType=archive_document(表内不存文件地址)、实体记 shelfNo 书架号/layerNo 层号/columnNo 列号/boxNo 册号档案盒 + storePlace 存放位置描述。carrierType 1电子/2实体/3电子+实体;secretLevel 1公开/2内部/3保密(为 3 且当前用户无 archive:document:sensitive 时详情报错、列表与导出强制过滤);sourceType 1手工/2课题/3会员/4财务 + sourceNo/sourceId/sourceTitle 记录来源快照以便检索;status 10在库/20借出中(借出中禁改、存在未归还借阅单时禁删)。来源为 2/3/4 的档案由三方列表页「归档」按钮经 ArchiveDocumentApi.archiveBySource 生成(幂等),并回写来源表 archive_document_id", "upstream": ["档案分类", "档案登记(人工)", "课题归档(已立项申报书)", "会员归档(正常会员)", "财务归档(已通过报销单)"], "downstream": ["借阅单", "附件中心(recordType=archive_document)", "来源表 archive_document_id 回写"], "keywords": "档案 文档 document DA 档案编号 密级 保密 公开 内部 敏感档案 载体 电子 实体 书架号 层号 列号 册号 档案盒 归档日期 在库 借出中 检索 关键词 tags 来源单号 归档联动"},
    {"name": "借阅单", "module": "档案管理", "table": "archive_borrow", "doc": "借阅与归还合一,编号 JY+yyyyMMdd+6位流水(Redis 每日重置)。记录借阅人/部门/电话、借阅日期、借阅目的、归还期限(returnDeadline·逾期实时计算基准);documentNo/documentTitle 为档案快照。status 0草稿/15审批中/20借出中/30已归还/35已驳回:仅 0 与 35 可改可重提、仅 0 可删、仅 20 可登记归还。submit 前校验同一档案不得已有 15/20 的借阅单(命中报已借用并带档案名与已存在借阅单号);流程 key archive_borrow_approve 两级(档案管理员审核→分管领导审批),前端不写死 key。审批通过由 ArchiveBorrowStatusListener 回写 20+approveTime 并条件更新档案 SET status=20 WHERE status=10(影响 0 行报档案已被占用并回滚);归还登记条件更新 20→30 并回写 returnTime/归还确认人。逾期不落库,查询时实时算 overdueDays 并在列表渲染红色「逾期 N 天」,另有 /overdue-page 独立入口", "upstream": ["档案(仅 在库 10 可选)", "BPM(流程 archive_borrow_approve)", "人工登记"], "downstream": ["档案(状态 20 借出中 / 归还回 10 在库)"], "keywords": "借阅 借阅单 借阅登记 归还 归还登记 逾期 逾期未还 借阅人 借阅目的 归还期限 JY 借阅单号 档案管理员审核 分管领导审批 流转闭环"},
    {"name": "经费拨付记录", "module": "课题管理", "table": "research_fund_record", "doc": "一主多行的拨款台账:batchName 批次名称/amount 拨付金额/payDate 拨付日期/payee 收款单位/remark,凭证附件走 system 附件中心 recordType=research_fund_record(表内不存文件地址)。status: 0待拨付/15报销审批中/20已拨付/30已驳回,由系统与 BPM 驱动,新增/修改接口已移除 status 入参(防伪造「已拨付」)。登记即一条龙:落台账 → 同一批 blob 双绑 → 经 FinanceReimbursementApi 自动生成 1:1 的 finance_reimbursement 并立即提交 BPM → 回写 reimbursement_id/reimbursement_no 并置 15;审批结果由监听器回写:通过→20、驳回→30(+reject_reason/reject_time)、取消流程→退回 0(发起人撤回只退回发起节点、流程未结束,状态不变)。仅申报单 status=20 已立项可登记;凭证必填;金额校验:已登记金额(该单全部记录求和) + 本次金额 不得超出申报单 budgetAmount,超出时提示报出本次、已登记、合计、预算四项数值;仅「待拨付」可删(联动删除财务侧草稿报销单,非草稿则拒绝),「待拨付」「已驳回」可改并重新发起报销(已驳回改后清空 reject_reason/reject_time),编辑时把本行金额加回可用余额展示避免误解。与报销单为软关联(无外键),财务侧直接删单会留下悬空 reimbursement_id,此时修改报「报销单已不存在,请删除本条记录后重新登记」", "upstream": ["课题申报书(必须已立项)", "财务报销单(1:1 自动生成·软关联 reimbursement_id)"], "downstream": ["拨付凭证(storage_attachment·recordType=research_fund_record)", "财务报销单(生成并提交出账·审批结果回写本台账)"], "keywords": "经费拨付 拨款 拨付记录 批次 拨付金额 凭证 待拨付 报销审批中 已拨付 已驳回 驳回原因 财务报销单号 reimbursement_id 收款单位 资助金额 预算 超额 重新发起报销"}
  ]
}</script>
@@ -631,7 +654,19 @@
       {"stage": "专家评审", "action": "申报单处于审批中(15)时录入专家评分明细(一位专家一行:姓名/单位/职称 + 选题价值0.3/研究方案0.3/团队基础0.2/预期成果0.2 四项分值 + 结论 + 意见);后端每次增删改后重算 compositeScore 加权合计、按加权分降序重排 ranking,并回写主单 reviewAvgScore(全部专家均分)与 reviewPass(均分达标且多数结论为推荐立项);明细全部删除时汇总值清空为未汇总;四项分值均在 0~100 之外时提示指出具体维度与实际值", "roles": ["评审专家", "学会秘书处", "课题管理员"]},
       {"stage": "立项审批", "action": "BPM 流程 research_topic_approve 顺序走三节点:秘书处形式审查 → 专家评审 → 学会立项审批。审批方法与审批人在流程定义内配置,部署后由管理员在 BPM 流程设计器按学会实际组织调整;审批中心内的自定义表单只读回显申报单 + 评审明细 + 拨付记录。通过→20 已立项、驳回→35 已驳回、取消→退回 0 草稿", "roles": ["学会秘书处(形式审查)", "评审专家(评审节点)", "学会理事会(立项审批)"]},
       {"stage": "立项与通知", "action": "监听器 ResearchApplicationStatusListener 先回写审批状态,审批通过后再调 approveApplication:生成立项编号 LX+yyyyMMdd+6位流水 与 approveTime(已有编号则幂等跳过)。点「发布立项通知」生成 system_notice 公告(标题『关于公布立项课题的通知』,正文含课题名/立项编号/类别/申报人/单位/资助金额),写回 noticeId 防重复——重复点击按已发布拦截并告知上次发布时间", "roles": ["课题管理员", "学会秘书处"]},
       {"stage": "经费拨付", "action": "仅「已立项(20)」的申报单可登记拨款记录(批次名称/拨付金额/拨付日期/收款单位/备注/凭证附件),凭证必填。登记时一条龙完成:① 课题侧落 research_fund_record 台账(先置待拨付)② 同一批 blob 双绑到课题台账与财务报销单 ③ 经 yudao-module-finance-api 自动生成 1:1 的 finance_reimbursement 报销单(1 行明细:费用类型=其他、发票金额=拨付金额、发票日期=拨付日期、费用说明=「课题〔课题名〕第N期/第N次经费拨款」)④ 立即提交 BPM 报销审批 ⑤ 台账回写报销单号并置「报销审批中(15)」。金额校验:已登记金额 + 本次金额 不得超出该单申请经费,超出时提示报出本次、已登记、合计、预算四项数值。状态由系统驱动:0待拨付/15报销审批中/20已拨付/30已驳回;只有「待拨付」可删(删除联动清理财务侧草稿报销单),「待拨付」「已驳回」可改并重新发起报销(已驳回改后清空驳回原因与时间);取消流程则退回「待拨付(0)」(发起人撤回只把实例退回发起节点、流程未结束,台账保持「报销审批中(15)」,需重新提交后才继续走审批)。财务审批分类下没有已发布流程时直接报错且不建单,不留孤儿草稿报销单", "roles": ["学会财务", "课题管理员", "财务审核人", "财务主管"]}]},
     {"stage": "经费拨付", "action": "仅「已立项(20)」的申报单可登记拨款记录(批次名称/拨付金额/拨付日期/收款单位/备注/凭证附件),凭证必填。登记时一条龙完成:① 课题侧落 research_fund_record 台账(先置待拨付)② 同一批 blob 双绑到课题台账与财务报销单 ③ 经 yudao-module-finance-api 自动生成 1:1 的 finance_reimbursement 报销单(1 行明细:费用类型=其他、发票金额=拨付金额、发票日期=拨付日期、费用说明=「课题〔课题名〕第N期/第N次经费拨款」)④ 立即提交 BPM 报销审批 ⑤ 台账回写报销单号并置「报销审批中(15)」。金额校验:已登记金额 + 本次金额 不得超出该单申请经费,超出时提示报出本次、已登记、合计、预算四项数值。状态由系统驱动:0待拨付/15报销审批中/20已拨付/30已驳回;只有「待拨付」可删(删除联动清理财务侧草稿报销单),「待拨付」「已驳回」可改并重新发起报销(已驳回改后清空驳回原因与时间);取消流程则退回「待拨付(0)」(发起人撤回只把实例退回发起节点、流程未结束,台账保持「报销审批中(15)」,需重新提交后才继续走审批)。财务审批分类下没有已发布流程时直接报错且不建单,不留孤儿草稿报销单", "roles": ["学会财务", "课题管理员", "财务审核人", "财务主管"]}]},
    {"id": "archive", "name": "档案管理流程", "mermaid": "mermaid/15-archive-flow.mmd", "color": "#7fb3d5",
     "summary": "独立档案模块(yudao-module-archive):书架分类(分层分列)规整 → 档案登记(电子附件 + 实体位置四字段,密级三档)→ 借阅登记走 BPM 两级审批(档案管理员审核 → 分管领导审批)→ 审批通过档案转「借出中」→ 归还登记回「在库」形成流转闭环 → 逾期未还查询时实时计算并在列表标红 → 存量与流转统计(总数/在库/借出中/逾期 + 分类·密级·载体三组分布)。同时接收课题(已立项)、会员(正常)、财务(已通过)三方的「归档」联动,经新建的 yudao-module-archive-api 生成档案并回写来源表 archive_document_id。会议/党建档案系统内无来源模块,仅手工录入。",
     "steps": [
       {"stage": "建分类", "action": "新建分类可挂父分类形成分类树(编码 code 全局唯一),设排序、说明、默认密级与启用状态;6 条初始分类:会员档案/课题档案/会议档案/财务档案(默认密级=保密 3)/文书档案/党建档案。有子分类或该分类下已有档案时禁止删除;父分类不能设为自身或其子分类", "roles": ["档案管理员"]},
       {"stage": "登记档案", "action": "填标题、分类、密级(1公开/2内部/3保密)、载体(1电子/2实体/3电子+实体)、归档日期、摘要、关键词;选电子则上传附件(走 system 附件中心,recordType=archive_document,先 /system/storage-blob/upload 取 blobId 再随保存请求的 blobIds 提交,全量替换语义),选实体则填书架号/层号/列号/册号档案盒与存放位置描述;后端生成档案编号 DA+yyyyMMdd+6位流水(Redis 每日重置),状态「在库(10)」", "roles": ["档案管理员"]},
       {"stage": "检索", "action": "按档案编号/标题/关键词 tags/来源单号/分类/密级/载体/状态/归档日期区间多条件检索,支持 Excel 导出。密级=保密(3) 的档案:当前用户无 archive:document:sensitive 时列表与导出强制过滤掉、直连详情接口报无权限错误", "roles": ["档案管理员", "全员可查公开档"]},
       {"stage": "三方归档", "action": "课题申报书(仅已立项 20)、会员(仅正常 1)、财务报销单(仅已通过 20)的列表页各有一个「归档」按钮,经 yudao-module-archive-api 的 archiveBySource 按「来源类型 + 来源单据 ID」幂等生成档案(来源单号/标题作为快照存入档案,源单附件一并带入档案;财务档案密级固定为「保密」),并回写来源表 archive_document_id 作为已归档硬标记;重复点击由来源侧拦截并提示已生成的档案编号。财务侧「归档」与其既有 20→40 状态推进在同一事务内叠加执行", "roles": ["课题管理员", "会员管理员", "财务"]},
       {"stage": "借阅登记", "action": "选档案(仅「在库(10)」可选)、填借阅人/部门/联系电话、借阅日期、借阅目的、归还期限;生成借阅单号 JY+yyyyMMdd+6位流水,状态「草稿(0)」。提交前校验同一档案不得存在「审批中(15)」或「借出中(20)」的借阅单,命中时按已存在的借阅单号精确报错;submit 先解析流程列表(无已发布流程直接报错、不留孤儿草稿)再建单,回写 processInstanceId 并置「审批中(15)」", "roles": ["借阅人", "档案管理员"]},
       {"stage": "借阅审批", "action": "BPM 流程 archive_borrow_approve 两级顺序审批:档案管理员审核 → 分管领导审批(审批方法与审批人在流程定义内配置,前端只选流程不写死 key;审批中心经自定义表单查看路径 /archive/borrow/detail/approve/index.vue 只读回显借阅单与档案信息)。审批通过由 ArchiveBorrowStatusListener 置「借出中(20)」并回写 approveTime,同时条件更新档案状态为「借出中」(影响 0 行说明档案已被其它流程占用 → 报错并回滚,保证同一档案不会被两条流程同时借出);驳回置「已驳回(35)」并回写驳回原因与时间,修改后可重新提交;取消流程退回「草稿(0)」", "roles": ["档案管理员(审核)", "分管领导(审批)"]},
       {"stage": "归还登记", "action": "仅「借出中(20)」可登记归还:填归还备注 → 条件更新借阅单状态到「已归还(30)」并回写 returnTime 与归还确认人,同时条件更新档案回「在库(10)」,形成完整流转闭环;更新 0 行说明状态已变化,报明确错误", "roles": ["档案管理员"]},
       {"stage": "逾期提醒", "action": "不建定时任务、不发站内信:逾期仅在查询时实时计算(状态=借出中 且 归还期限早于今天,逾期天数=今天−归还期限),借阅列表的「逾期」列渲染红色「逾期 N 天」标签;另提供 /archive/borrow/overdue-page 独立入口,列表页有「只看逾期」切换在 /page 与 /overdue-page 之间切换数据源", "roles": ["档案管理员"]},
       {"stage": "档案统计", "action": "统计页展示档案总数、在库数、借出中数、逾期未还数四张卡片,以及按分类分布(饼图)、按密级分布(柱图)、按载体分布(饼图)三组分布,数据来自 /archive/stat/overview 的单次聚合查询", "roles": ["档案管理员", "管理层"]}]},
    {"id": "ai", "name": "AI 业务流程", "mermaid": "mermaid/11-ai-business-flow.mmd", "color": "#56c8d8",
     "summary": "统一模式:业务侧收集上下文(必要时调 MDM/SRM/CRM API 取名称)→组装 Prompt→chat/chatWithImage→解析 JSON→前端预填或建议;无 Function Calling;RAG 知识库已建成但暂无业务消费。",
     "steps": [
@@ -667,6 +702,10 @@
    {"role": "入会申请人/会员管理员", "modules": ["UMS"], "operations": ["填报与修改入会申请(个人/单位)", "上传证明材料附件", "提交 BPM 审批", "会员列表维护与会员通讯录检索"], "data": ["ums_application", "ums_member"], "scope": "权限码 ums:application:create/update/delete/submit · ums:member:create/update/delete/query · ums:member:directory;无数据权限隔离(全员可查通讯录,维护类按钮另凭权限码)"},
    {"role": "秘书处/理事会(审批人)", "modules": ["UMS", "BPM"], "operations": ["入会申请两级审批:秘书处初审 → 理事会审议"], "data": ["ums_application(状态回写)", "bpm_task"], "scope": "审批人由 BPM 流程定义配置,后端不写死;通过后系统自动建会员与登录账号"},
    {"role": "课题申报人/课题管理员", "modules": ["RES"], "operations": ["课题指南发布与截止(课题管理员)", "新建与修改课题申报书(选会员带出申报人信息、上传申报附件)", "提交 BPM 审批、驳回后修改重提", "每月/每批次登记经费拨付记录与凭证", "发布立项通知"], "data": ["research_guideline", "research_application", "research_topic_review", "research_fund_record"], "scope": "权限码 research:guideline:create/update/delete/publish · research:application:create/update/delete/submit/notice · research:review:create/update/delete · research:fund:create/update/delete;无数据权限隔离(列表不按申请人过滤),按钮凭权限码控制"},
    {"role": "档案管理员", "modules": ["ARC"], "operations": ["档案分类(书架)维护:分层建类、设默认密级、启用停用", "档案登记与多条件检索/导出(电子附件 + 实体位置四字段、密级三档)", "借阅登记、提交审批", "归还登记与归还备注", "查看档案统计(存量与流转)"], "data": ["archive_category", "archive_document", "archive_borrow"], "scope": "权限码 archive:category:create/update/delete/query · archive:document:create/update/delete/query/export · archive:borrow:create/update/delete/query/submit/return · archive:stat:query;密级=保密(3) 的档案另需 archive:document:sensitive 才能查看,无该权限时列表与导出强制过滤;无数据权限隔离(列表不按人过滤),按钮凭权限码控制"},
    {"role": "借阅人", "modules": ["ARC"], "operations": ["登记借阅单(选在库档案、填借阅人信息/借阅日期/借阅目的/归还期限)", "提交 BPM 借阅审批", "查看借阅进度(跳 BPM 流程实例详情)"], "data": ["archive_borrow", "archive_document(仅 在库 10 可选)"], "scope": "权限码 archive:borrow:create/query/submit;仅草稿(0)与已驳回(35)可改可重提、仅草稿可删;同一档案不得同时存在审批中(15)或借出中(20)的借阅单"},
    {"role": "档案管理员/分管领导(借阅审批人)", "modules": ["ARC", "BPM"], "operations": ["借阅审批两级:档案管理员审核 → 分管领导审批", "在审批中心通过自定义表单只读查看借阅单与档案信息"], "data": ["archive_borrow(状态回写)", "archive_document(状态随审批结果条件更新)", "bpm_task"], "scope": "审批人与审批方法在 BPM 流程定义 archive_borrow_approve 内配置(默认依次审批·角色兜底),后端不写死审批人,部署后由管理员在流程设计器按实际组织调整"},
    {"role": "归档经办人(课题/会员/财务)", "modules": ["ARC", "RES", "UMS", "FIN"], "operations": ["在课题申报书列表对「已立项」单据点「归档」", "在会员列表对「正常」会员点「归档」", "在报销单列表对「已通过」单据点「归档」(与其既有 20→40 归档同事务叠加)"], "data": ["archive_document(生成)", "research_application / ums_member / finance_reimbursement(回写 archive_document_id)"], "scope": "权限码 research:application:archive · ums:member:archive · finance:reimbursement:archive;调用 yudao-module-archive-api 的 archiveBySource 幂等生成档案,重复点击由来源侧按错误码拦截并给出已生成档案编号"},
    {"role": "评审专家/学会秘书处·理事会(课题审批人)", "modules": ["RES", "BPM"], "operations": ["在审批中(15)录入本人的专家评分明细(四项分值 + 结论 + 意见)", "秘书处形式审查 → 专家评审 → 学会立项审批 三节点顺序审批", "在审批中心通过自定义表单只读查看申报书正文、评审明细与拨付记录"], "data": ["research_topic_review", "research_application(状态回写)", "bpm_task"], "scope": "评分录入要求申报单处于审批中(15)·由课题管理员或专家依据 research:review:* 权限码执行;审批人与审批方法在 BPM 流程定义 research_topic_approve 内配置(默认依次审批·角色兜底),后端不写死审批人,部署后由管理员在流程设计器按学会实际组织调整"}
  ]
}</script>
@@ -725,6 +764,16 @@
      秘书处理事会三级审批
      立项编号与立项通知公告
      经费拨付记录与凭证
    档案管理 ARCHIVE 独立
      档案分类书架分层分列
      档案文档集中存储与检索
      电子附件与实体位置兼具
      密级管控与敏感权限
      借阅登记与两级审批
      归还登记与流转闭环
      逾期未还实时提醒
      档案存量与流转统计
      课题会员财务三方归档联动
    生产管理 MES
      主生产计划 MPS
      生产工单
@@ -1041,6 +1090,12 @@
  RES -->|立项通知写 system_notice 公告| SYS
  RES -->|经费拨付 1:1 自动生成 finance_reimbursement 报销单并提交审批·走新建的 yudao-module-finance-api| FIN
  FIN -.->|报销审批结果经 BPM 事件回调 ResearchFundStatusListener 回写课题拨款台账| RES
  ARC[档案管理 独立模块 yudao-module-archive 分类 档案 借阅 归还 统计] -.->|复用 BPM 两级审批与状态回调·流程 key=archive_borrow_approve| BPM
  ARC -.->|档案电子附件走附件中心 recordType=archive_document / archive_borrow| STG
  RES -->|已立项申报单归档·经 yudao-module-archive-api 生成档案并回写 archive_document_id| ARC
  UMS -->|正常状态会员归档·经 yudao-module-archive-api 生成档案并回写 archive_document_id| ARC
  FIN -->|已通过报销单归档·同事务叠加生成「保密」档案并回写 archive_document_id| ARC
  ARC -.->|不反向依赖 ums / finance / research·仅提供 -api 子模块由三方手动调归档| RES
</pre>
<pre style="display:none" class="mmd-src" data-mmd="09-data-flow">
flowchart LR
@@ -1149,6 +1204,27 @@
  RBM -->|"报销单进入同一条 BPM 流程 finance_reimbursement_approve(财务审核 → 财务主管审批)·businessKey=报销单 ID"| RBS
  RBS -.->|"BPM 监听器 ResearchFundStatusListener 回写课题台账 通过20 驳回30(+驳回原因/时间) 撤回0"| RFR
  RESNOTE[一期已对接财务·课题台账为拨款台账·报销单为财务出账凭证·两边以 reimbursement_id 软关联无外键·财务侧直接删单会留下悬空 ID 由业务报错兜底] -.-> RFR
  subgraph S7 [独立档案管理 archive]
    ACD[档案分类 archive_category 树形] --> ADO[档案 archive_document]
    ADO --> ABR[借阅单 archive_borrow]
    ADO --> AST[档案状态 10在库 20借出中]
    ABR --> ABS[借阅状态 0草稿 15审批中 20借出中 30已归还 35已驳回]
  end
  ACD -->|"新建档案按分类带出 default_secret_level 默认密级·财务分类=3 保密"| ADO
  ADO -.->|"电子附件 recordType=archive_document·表内不存文件地址"| PDFARCH
  ADO -->|"档案编号 DA + yyyyMMdd + 6位流水(Redis·每日重置)·借阅单号 JY + 同日流水"| ADO
  RAP -->|"手动「归档」经 yudao-module-archive-api.archiveBySource(sourceType=2·密级 2内部·sourceNo=立项编号·blobIds=申报书附件)·幂等"| ADO
  UMSM -->|"手动「归档」(sourceType=3·密级 2内部·sourceNo=会员编号·blobIds=会员材料)"| ADO
  RBM -->|"既有 archive 归档同事务叠加 archiveBySource(sourceType=4·密级 3保密·sourceNo=报销单号·blobIds=发票附件)·报销单 20→40 与生成档案两表并写"| ADO
  ADO -->|"回写来源表 archive_document_id 作为已归档硬标记·来源侧重复点归档按其错误码拦截并给出已生成档案编号"| RAP
  ADO -->|"回写 archive_document_id"| RBM
  ABR -->|"submit 前校验: 同一档案不得已有 审批中 15 或 借出中 20 的借阅单·命中报已借用(带档案名与已存在借阅单号)"| ABS
  ABS -.->|"BPM 监听器 ArchiveBorrowStatusListener 回写 通过20 驳回35 取消退回0"| ABR
  ABS -->|"业务动作: 归还登记 仅放行 20 借出中 → 30 已归还·回写 returnTime 与归还确认人"| ABR
  ABR -->|"审批通过条件更新 archive_document SET status=20 WHERE status=10·归还条件更新回 10·影响 0 行即报冲突并回滚"| AST
  ABR -.->|"逾期不落库·查询时实时计算 status=20 且 return_deadline 早于今天·overdue-page 为独立入口非查询参数"| ABS
  ADO -.->|"密级=3 保密 且无 archive:document:sensitive 时·详情报错·列表与导出强制过滤 secret_level 不等于 3"| SEC3[权限点 archive:document:sensitive]
  ARCNOTE[独立模块·三方归档为列表页手动按钮而非事件驱动·归档只生成档案不回写来源单据业务状态(财务侧 20→40 是既有逻辑·本模块仅叠加)] -.-> ADO
</pre>
<pre style="display:none" class="mmd-src" data-mmd="10-business-object">
erDiagram
@@ -1196,6 +1272,11 @@
  research_application ||--o{ research_fund_record : "经费拨付记录"
  research_fund_record ||--|| finance_reimbursement : "1:1 生成出账报销单(软关联 reimbursement_id)"
  ums_member ||--o{ research_application : "申报人(软关联无外键)"
  archive_category ||--o{ archive_document : "分类归档(树形书架)"
  archive_document ||--o{ archive_borrow : "借阅登记"
  research_application ||--o| archive_document : "已立项归档(archive_document_id)"
  ums_member ||--o| archive_document : "正常会员归档(archive_document_id)"
  finance_reimbursement ||--o| archive_document : "已通过报销归档(archive_document_id)"
</pre>
<pre style="display:none" class="mmd-src" data-mmd="11-ai-business-flow">
flowchart TD
@@ -1351,6 +1432,58 @@
  BOUND["独立模块 yudao-module-research·对 ums_member 为软关联(无外键)·对财务模块走 -api 子模块本地调用·仅复用 BPM 审批、system 公告与附件中心"] --- K1
</pre>
<pre style="display:none" class="mmd-src" data-mmd="15-archive-flow">
flowchart TD
  subgraph P1 [档案分类·书架管理 archive_category]
    C1[新建分类·可选父分类形成分类树] --> C2["填 分类名称 · 编码 code · 排序 · 分类说明 · 默认密级 · 状态"]
    C2 --> C3["编码全局唯一 uk_code · 状态 0启用 1停用 · 默认密级 1公开 2内部 3保密"]
    C3 --> C4["初始 6 条分类: 会员档案 member · 课题档案 research · 会议档案 meeting · 财务档案 finance(默认密级=保密 3) · 文书档案 document · 党建档案 party"]
    C4 --> C5["可改可删 · 有子分类禁删 · 该分类下有档案禁删 · 父分类不能是自身或其子分类 · 停用分类不能新增档案"]
  end
  subgraph P2 [档案管理 archive_document]
    D1["新建档案: 标题 · 分类 · 密级 · 载体(1电子 2实体 3电子+实体) · 归档日期 · 摘要 · 关键词 tags"] --> D2["实体位置四字段: 书架号 shelfNo · 层号 layerNo · 列号 columnNo · 册号档案盒 boxNo · 存放位置描述 storePlace"]
    D2 --> D3["电子附件走 system 附件中心 · recordType=archive_document · 表内不存文件地址 · blobIds 为全量替换语义"]
    D3 --> D4["档案编号 DA + yyyyMMdd + 6位流水 (Redis·每日重置)"]
    D4 --> D5["状态 10 在库 · 可改可删"]
    D5 -->|"借阅审批通过"| D6["状态 20 借出中 · 禁改 · 存在未归还借阅单时禁删"]
    D6 -->|"归还登记"| D5
  end
  subgraph P3 [三方归档联动·列表页手动「归档」按钮→yudao-module-archive-api]
    AD["ArchiveDocumentApi.archiveBySource 幂等: 先按 source_type + source_id 查 · 命中直接返回既有档案 ID"]
    AD2["按 categoryCode 取分类(member / research / finance) · 分类不存在报 DOCUMENT_SOURCE_CATEGORY_NOT_EXISTS"]
    AD3["生成 DA 编号 + 落库 + bindAttachments(recordType=archive_document)"]
    AD4["回写来源表 archive_document_id 作为已归档硬标记 · 来源侧重复归档按其自身错误码拦截并给出已生成档案编号(archive 侧 DOCUMENT_DUPLICATE_SOURCE 为兜底)"]
    R1["课题申报书 research_application · 仅 status=20 已立项 · 权限 research:application:archive"] -->|"sourceType=2 · 密级 2内部 · sourceNo=立项编号 · blobIds=申报书附件"| AD
    M1["会员 ums_member · 仅 status=1 正常 · 权限 ums:member:archive"] -->|"sourceType=3 · 密级 2内部 · sourceNo=会员编号"| AD
    F1["财务报销单 finance_reimbursement · 仅 status=20 已通过 · 权限 finance:reimbursement:archive"] -->|"sourceType=4 · 密级 3保密 · sourceNo=报销单号 · blobIds=发票附件 · 与既有 20→40 归档同事务叠加"| AD
    AD --> AD2
    AD2 --> AD3
    AD3 --> AD4
  end
  AD3 -->|"归档结果: 新档案直接落为 在库 10"| D5
  subgraph P4 [借阅登记与审批 archive_borrow]
    B1["登记借阅: 选档案(仅 在库 10 可选) · 借阅人 · 部门 · 联系电话 · 借阅日期 · 借阅目的 · 归还期限"] --> B2["借阅单号 JY + yyyyMMdd + 6位流水 (Redis·每日重置) · 状态 0 草稿"]
    B2 --> B3["submit 前校验: 同一档案不得存在 审批中 15 或 借出中 20 的借阅单 · 命中报 已借用(带档案名与已存在借阅单号)"]
    B3 --> B4["submit 传 id 与 processDefinitionKey (query 参数) · 先解析流程列表再建单(无已发布流程则直接报错·不留孤儿草稿) · 状态 15 审批中 · 回写 processInstanceId"]
    B4 --> B5["BPM 流程 archive_borrow_approve 两级: 档案管理员审核 → 分管领导审批"]
  end
  B5 -->|"审批通过"| B6["状态 20 借出中 · 回写 approveTime · 条件更新档案 SET status=20 WHERE status=10(影响 0 行则报 档案已被占用 并回滚)"]
  B5 -->|"审批驳回"| B7["状态 35 已驳回 · 回写驳回原因与时间 · 修改后可重新 submit"]
  B5 -->|"取消流程"| B2
  B6 -->|"归还登记 return · 条件更新 status=20 → 30"| B8["状态 30 已归还 · 回写 returnTime 与归还确认人 · 归还备注"]
  B8 -->|"条件更新档案 SET status=10 WHERE status=20"| D5
  B6 -->|"仅 0 草稿 与 35 已驳回 可改可重提 · 仅 0 草稿 可删"| B2
  B6 -->|"仅 20 借出中 可登记归还"| B8
  OV["逾期不落库·查询时实时计算: status=20 且 return_deadline 早于今天 · overdueDays = 今天 减 归还期限"] -.-> B6
  OVP["GET /archive/borrow/overdue-page 独立入口(非查询参数) · 列表「逾期」列渲染红色「逾期 N 天」 · 不建 infra_job 不发站内信 · 列表页另有「只看逾期」切换"] -.-> OV
  ST["档案统计 GET /archive/stat/overview: 档案总数 · 在库数 · 借出中数 · 逾期未还数 + 按分类/按密级/按载体 三组分布"] -.-> D5
  SEC["敏感档案管控: 密级=3 保密 且当前用户无 archive:document:sensitive 时 · 详情接口直接报错 · 列表与导出强制过滤 secret_level 不等于 3"] -.-> D1
  ATT["附件 recordType = archive_document / archive_borrow"] -.-> D3
  ROL["审批中心看单: 流程定义表单类型=自定义表单 · 创建路径 /archive/borrow/index · 查看路径 /archive/borrow/detail/approve/index.vue · 按 businessKey 回显借阅单"] -.-> B5
  LIS["监听器 ArchiveBorrowStatusListener(流程 key=archive_borrow_approve · businessKey=借阅单 ID): 通过→20 借出中 + approveTime 并条件更新档案 → 20 · 驳回→35 + 原因与时间 · 取消→退回 0 · 与 finance/research 监听器订阅不同 key 互不干扰"] -.-> B5
  BOUND["独立模块 yudao-module-archive(含 -api 子模块)·依赖 system/bpm·不反向依赖 ums/finance/research(避免循环依赖)·三方仅依赖 archive-api 手动调归档"] --- D1
</pre>
<script type="module">
const DATA = {};
async function loadJson(key){
@@ -1369,7 +1502,7 @@
const mmdSrc = {};
document.querySelectorAll('pre.mmd-src').forEach(p=>{ mmdSrc[p.dataset.mmd]=p.textContent.trim(); });
const flowColor = {sales:'var(--c-sale)',purchase:'var(--c-erp)',production:'var(--c-prod)',quality:'var(--c-qc)',warehouse:'var(--c-wm)',aftersales:'var(--c-as)',finance:'var(--c-fin)',ums:'var(--c-ums)',research:'var(--c-res)',ai:'var(--c-ai)'};
const flowColor = {sales:'var(--c-sale)',purchase:'var(--c-erp)',production:'var(--c-prod)',quality:'var(--c-qc)',warehouse:'var(--c-wm)',aftersales:'var(--c-as)',finance:'var(--c-fin)',ums:'var(--c-ums)',research:'var(--c-res)',archive:'var(--c-arch)',ai:'var(--c-ai)'};
async function boot(){
  DATA.business = await loadJson('business');
@@ -1406,8 +1539,8 @@
  </div>
  <h3 class="sec">业务模块</h3>
  <div class="grid cards">`;
  const targets = {crm:'flow-sales',erp:'flow-purchase',pro:'flow-production',wm:'flow-warehouse',qc:'flow-quality',aftersales:'flow-aftersales',fin:'flow-finance',ums:'flow-ums',res:'flow-research',ai:'ai',srm:'flow-purchase',mdm:'objects',dv:'objects',hrm:'objects',bpm:'relation'};
  const accs = {mdm:'var(--c-base)',crm:'var(--c-sale)',srm:'var(--c-sup)',erp:'var(--c-erp)',fin:'var(--c-fin)',ums:'var(--c-ums)',res:'var(--c-res)',pro:'var(--c-prod)',wm:'var(--c-wm)',qc:'var(--c-qc)',dv:'var(--c-dv)',aftersales:'var(--c-as)',hrm:'var(--c-hrm)',bpm:'var(--c-bpm)',ai:'var(--c-ai)'};
  const targets = {crm:'flow-sales',erp:'flow-purchase',pro:'flow-production',wm:'flow-warehouse',qc:'flow-quality',aftersales:'flow-aftersales',fin:'flow-finance',ums:'flow-ums',res:'flow-research',arc:'flow-archive',ai:'ai',srm:'flow-purchase',mdm:'objects',dv:'objects',hrm:'objects',bpm:'relation'};
  const accs = {mdm:'var(--c-base)',crm:'var(--c-sale)',srm:'var(--c-sup)',erp:'var(--c-erp)',fin:'var(--c-fin)',ums:'var(--c-ums)',res:'var(--c-res)',arc:'var(--c-arch)',pro:'var(--c-prod)',wm:'var(--c-wm)',qc:'var(--c-qc)',dv:'var(--c-dv)',aftersales:'var(--c-as)',hrm:'var(--c-hrm)',bpm:'var(--c-bpm)',ai:'var(--c-ai)'};
  DATA.modules.modules.forEach(m=>{
    html += `<div class="card" style="--acc:${accs[m.key]||'#2c5cff'}" data-goto="${targets[m.key]||'panorama'}">
      <h3>${esc(m.name)}<span class="tag">${esc(m.tag)}</span></h3>