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-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%}
@@ -111,6 +111,10 @@
  <a data-t="flow-quality"><span class="dot" style="background:var(--c-qc)"></span>质量流程</a>
  <a data-t="flow-warehouse"><span class="dot" style="background:var(--c-wm)"></span>仓储流程</a>
  <a data-t="flow-aftersales"><span class="dot" style="background:var(--c-as)"></span>售后流程</a>
  <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>
@@ -137,6 +141,10 @@
<section class="page" id="flow-quality"></section>
<section class="page" id="flow-warehouse"></section>
<section class="page" id="flow-aftersales"></section>
<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>
@@ -186,6 +194,10 @@
    "subSystems": [
      "MES(生产·仓储·质量·设备)",
      "ERP(进销存·财务)",
      "FIN(发票报销,独立模块)",
      "UMS(学会会员,独立模块)",
      "RES(科研课题,独立模块)",
      "ARC(档案管理,独立模块)",
      "CRM(客户关系)",
      "SRM(供应商关系)",
      "HRM(人力资源)",
@@ -197,14 +209,14 @@
    "businessPositioning": "让工厂的订单、物料、生产、库存、质量、人员、资金在一个系统内闭环流转,管理层可通过 BI 大屏掌握全局。",
    "coreChain": "CRM 商机/合同 → ERP 销售订单 → MES 主生产计划/工单/报工 → MES 质检与仓储 → 销售出库发货 → 开票回款 → 售后闭环",
    "techBase": "Spring Boot + MyBatis + Flowable + Redis + Quartz/RocketMQ/Kafka + Milvus 向量库 + 通义千问",
    "database": "MySQL 8.4,413 张表(含 system_*、bpm_*、act_* 底座表与 mes_*/erp_*/crm_*/srm_*/hrm_*/mdm_*/ai_* 业务表),多租户已关闭",
    "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": 13,
    "coreObjects": 48,
    "documentFlows": 6,
    "approvalListeners": 13,
    "businessModules": 17,
    "coreObjects": 59,
    "documentFlows": 10,
    "approvalListeners": 24,
    "aiCapabilities": 8,
    "wmBillTypes": 15
  },
@@ -323,10 +335,30 @@
    "MesWmSnDO 新增的 uuid 字段生成/消费逻辑未在核心 Service 中确认",
    "转正申请(hrm_regularize_application)、培训证书等仅有 SQL 与菜单初始化,Java 侧 Service/Controller 未实现",
    "NCR 处置结果(返工/退货)未回写触发源单据,仅台账记录",
    "MPS 状态枚举独立编号(0/1/2/3),与通用单据常量(0/1/4/5)不一致"
    "MPS 状态枚举独立编号(0/1/2/3),与通用单据常量(0/1/4/5)不一致",
    "财务报销:菜单仅授予 super_admin(超管由代码直返全部菜单),普通角色未配 system_role_menu,非超管登录看不到「报销单」菜单【待确认是否补授权】",
    "会员管理:会员管理菜单(1075490~1075503)仅 super_admin 可见,普通角色未配 system_role_menu,非超管登录看不到会员管理目录【待确认是否补授权】",
    "会员管理:审批通过自动建系统账号用「联系电话」同时作用户名与初始密码,若联系电话为空会用字面量 unknown 兜底,存在弱口令与重名风险【待确认是否改造】",
    "会员管理:自动建档不搬运 contactUser/unitIntro/expireDate(ums_application 无对应字段),单位会员的「联系人/单位简介/有效期」只能在会员列表手工补录【待确认是否需要申请单增字段】",
    "会员管理:单位会员的等级字典 ums_unit_grade 仅到「会长单位」(4),但校验逻辑额外硬编码禁止单位选「理事长」(grade=5)——该值本不在单位字典内,属防御性冗余校验【待确认是否精简】",
    "课题管理:专家评分权重(选题0.3/方案0.3/团队0.2/成果0.2)与「加权均分≥60 且 多数结论为推荐立项」的通过阈值是占位规则,需学会最终确认;已集中为常量便于调整【待确认,改动只需改常量】",
    "课题管理:经费拨付已对接财务报销(1:1 生成 finance_reimbursement 并自动提交审批),但台账与报销单是软关联(无外键,仅靠 reimbursement_id),财务侧直接删除报销单会留下台账的悬空 reimbursement_id;已用 FUND_REIMBURSEMENT_NOT_EXISTS 精确提示兜底,不做数据库级约束【已接受的风险】",
    "课题管理:新建的财务报销审批流程 finance_reimbursement_approve 为 2 节点(财务审核 → 财务主管审批),节点默认审批人策略为「角色 = 超级管理员(1)、依次审批」;上线前需在 BPM 设计器中按学会/财务实际审批人调整,否则该角色下多用户会变成逐人会签【环境配置项,非代码缺陷】",
    "课题管理:经费拨付台账的「已拨付(20)」等价于报销单「已通过(20)」,不含出纳实际付款动作;若日后需要独立的「已付款」状态,需另增状态与审批节点【二期可扩展】",
    "课题管理:申报单与 ums_member 是软关联(无外键),会员被删除后申报单会留下悬空 memberId;成员列表需容错展示「会员已删除」【待确认是否加外键或删除保护】",
    "课题管理:BPM 流程 research_topic_approve 三节点默认审批人为「角色=超级管理员(1) + 依次审批」,该 dev 库超级管理员角色下有 4 个用户(admin/张娟/马芳/马贞),每个节点需 4 人会签才推进;全新安装库该角色仅 admin 一人、流程可开箱即用。dev 库需减少超级管理员用户或改在 BPM 设计器中为每节点指定审批人【环境配置项,非代码缺陷】",
    "课题管理:立项通知复用 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-10",
  "analysisBasis": "基于 dev_business 分支 87bf4a99 源码,6 组并行源码走读(MES 生产质量 / MES 仓储 / ERP / CRM+SRM / 售后+HRM / AI+BI+MDM+BPM+底座)"
  "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 阶段一,两级审批全通过/驳回/取消三条回写链路均已端到端验证;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": [
@@ -362,6 +394,14 @@
     "roles": ["采购员", "销售员", "出纳", "会计"],
     "upstream": ["CRM(合同)", "SRM(定标)", "主数据"], "downstream": ["生产(MPS)", "仓储(收发)"],
     "coreTables": ["erp_purchase_request", "erp_purchase_order", "erp_purchase_invoice", "erp_finance_payment", "erp_sale_order", "erp_finance_receipt", "erp_account"]},
    {"key": "fin", "name": "财务报销(独立)", "color": "#3ec9a7", "tag": "FIN", "flow": "finance",
     "positioning": "独立的发票报销单据与归档",
     "problem": "纸质发票难归集、报销审批无留痕、归档后无法追溯",
     "features": ["报销单(主表 + 1..n 明细行)", "发票附件多文件上传(附件中心多态关联 storage_attachment)", "单号 Redis 生成 BX+yyyyMMdd+6位流水·每日重置", "明细随主表一次性提交(先删后增全量覆盖)", "BPM 审批(通过20/驳回35/取消退回草稿0)", "已驳回可改发票后重新提交", "归档终态 40 并记录归档时间", "费用类型/报销状态双字典 + Excel 导出", "对外提供 FinanceReimbursementApi(yudao-module-finance-api)供课题管理经费拨付自动建单并提交(1 行明细·费用类型=其他·金额一致)"],
     "objects": ["报销单", "报销明细"],
     "roles": ["报销人", "财务", "审批人"],
     "upstream": ["课题管理(经费拨付 1:1 自动生成报销单·走 yudao-module-finance-api·本地 Bean 调用)"], "downstream": [],
     "coreTables": ["finance_reimbursement", "finance_reimbursement_item"]},
    {"key": "pro", "name": "生产管理", "color": "#e0b34f", "tag": "MES-PRO", "flow": "production",
     "positioning": "生产执行核心:计划-工单-任务-报工",
     "problem": "订单到车间执行的逐层拆解与过程可控",
@@ -418,10 +458,36 @@
     "roles": ["HR", "部门主管", "员工本人"],
     "upstream": [], "downstream": ["各模块(数据可见性扩展)", "system(账号)"],
     "coreTables": ["hrm_employee", "hrm_leave_application", "hrm_resignation_application", "hrm_user_handover", "hrm_attendance_record", "hrm_salary_calculation", "hrm_salary_payment"]},
    {"key": "ums", "name": "会员管理(独立)", "color": "#d6955c", "tag": "UMS", "flow": "ums",
     "positioning": "学会/协会型会员全生命周期:入会申请审批 → 自动建档 → 会员列表与通讯录",
     "problem": "会员入会靠线下表格与人工建档,会员等级口径混乱,会员信息无法按地区/行业检索",
     "features": ["入会申请单(个人/单位二型·字段分叉)", "申请等级两级口径(个人 ums_personal_grade / 单位 ums_unit_grade)", "申请编号 SQ+yyyyMMdd+6位流水·会员编号 HY+同日流水(Redis 每日重置)", "BPM 两级审批(秘书处初审→理事会审议)·状态 0草稿/15审批中/20已通过/35已驳回", "审批通过自动建会员 + 自动建系统登录账号(AdminUserApi.createUser·用户名与初始密码=联系电话)", "会员等级与类型匹配校验(单位会员不可选『理事长』)", "会员通讯录只读检索(按地区编码/行业)", "证明材料走 system 附件中心(recordType=ums_application / ums_member)"],
     "objects": ["入会申请单", "会员"],
     "roles": ["入会申请人", "会员管理员", "秘书处(初审)", "理事会(审议)"],
     "upstream": [], "downstream": ["system(自动创建登录账号)"],
     "coreTables": ["ums_application", "ums_member"]},
    {"key": "res", "name": "课题管理(独立)", "color": "#e070a8", "tag": "RES", "flow": "research",
     "positioning": "学会/协会型科研课题全生命周期:指南发布 → 在线申报 → 专家评审 → 立项审批 → 经费拨付(立项通知走系统公告)",
     "problem": "课题指南靠线下发布、申报书靠纸质或邮件收集、专家评分散落在表格里无法自动汇总排名、立项与拨款无留痕",
     "features": ["课题指南(重点1/一般2 分类标注)", "指南状态 0草稿/20已发布/30已截止·发布/截止两个动作", "指南编号 GL+yyyyMMdd+6位流水(Redis 每日重置)", "在线申报书(选指南+选会员带出申报人信息+课题组成员+申请经费+申报书正文)", "申报编号 SB+同日流水·类别冗余自指南不信任前端", "申报状态 0草稿/15审批中/20已立项/35已驳回", "提交前校验指南已发布且在申报期内(逐条报具体维度与时间)", "专家评审明细子表(一位专家一行·四项加权 0.3/0.3/0.2/0.2)", "后端自动重算加权合计与排名·回写主单均分与推荐结论", "BPM 三级审批 research_topic_approve(秘书处形式审查→专家评审→学会立项审批)", "审批通过生成立项编号 LX+同日流水 与立项时间(幂等)", "发布立项通知(生成 system_notice 公告·写回 noticeId 防重复)", "经费拨付记录(批次/金额/日期/收款单位/备注/凭证附件)·凭证必填·金额不得超申请经费", "经费拨付 1:1 自动生成并提交财务报销单(FinanceReimbursementApi·1 行明细·费用类型=其他)", "拨付状态 0待拨付/15报销审批中/20已拨付/30已驳回·由 BPM 监听器回写(含驳回原因与时间)", "已驳回可改金额/凭证后重新发起报销·待拨付可删并联动清理财务侧草稿报销单", "附件走 system 附件中心(recordType=research_guideline / research_application / research_fund_record)"],
     "objects": ["课题指南", "课题申报书", "专家评审明细", "经费拨付记录"],
     "roles": ["课题申报人(会员)", "课题管理员", "评审专家", "学会秘书处", "学会理事会", "学会财务"],
     "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)", "13个业务监听器", "表单·用户组·抄送·加签"],
     "features": ["BPMN+钉钉风格双设计器", "流程定义部署", "审批事件统一回调(BpmProcessInstanceStatusEvent)", "24个业务状态监听器(*StatusListener·同一流程 key 允许多个监听器并行·各自按 key 过滤·档案借阅 ArchiveBorrowStatusListener 与财务/课题监听器订阅不同 key 互不干扰)", "表单·用户组·抄送·加签"],
     "objects": ["流程模型", "流程实例", "审批任务"],
     "roles": ["审批人(按流程配置)", "流程管理员"],
     "upstream": ["各业务提交审批"], "downstream": ["回调更新各业务单据状态"],
@@ -438,7 +504,7 @@
  "platform": {
    "name": "系统底座",
    "capabilities": ["JWT+OAuth2 认证·滑块验证码", "RBAC 角色-菜单-数据范围(全部/部门/本部门及下级/仅本人/自定义)", "字典", "附件中心(storage-blob 文件 + storage-attachment 按 recordType+recordId 多态关联,全模块强制使用)", "编码规则(各业务自实现 Redis 前缀+日期+流水)", "Quartz 定时任务·RocketMQ/Kafka/Redis Stream MQ·WebSocket", "多租户已关闭", "实际 system_role 仅 4 个:超级管理员/普通角色/CRM管理员/租户管理员,业务分工靠数据权限而非多角色"],
    "unused": ["im 模块(IM/RTC,业务未消费)", "member 模块(C端会员,遗留)"]
    "unused": ["im 模块(IM/RTC,业务未消费)", "member 模块(C端商城会员,遗留;与 UMS 学会会员无关,勿混用)"]
  }
}</script>
<script type="application/json" id="data-objects">{
@@ -490,7 +556,18 @@
    {"name": "离职交接", "module": "人力", "table": "hrm_user_handover", "doc": "from→to 映射,已完成20 后 expandUserIds 扩展交接人可见数据(当前各业务模块尚未实际接入调用)", "upstream": ["离职申请"], "downstream": ["各模块我的数据查询"], "keywords": "交接 离职 handover expandUserIds"},
    {"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": "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 订阅同一流程回写拨款台账,报销单本身不回写任何外部单据;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(申请单无对应字段);自动建的系统账号用户名为联系电话且初始密码同为联系电话,部门固定为「学会会员」;手机号重复会明确报错且整单事务回滚;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 记录已发布的立项通知公告,重复发布被拦截;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>
<script type="application/json" id="data-flows">{
@@ -548,6 +625,48 @@
       {"stage": "判定", "action": "问题判定: 一般/维修/退货,严重度 0-3", "roles": ["售后工程师"]},
       {"stage": "维修", "action": "现场/返厂/远程维修,费用与结果记录,完成联动工单完结", "roles": ["维修工程师"]},
       {"stage": "退货", "action": "退货申请审核→自动建 MES 销售退货单(RQC)→质检/入库回调→退款回调→关闭", "roles": ["售后", "质检", "财务"]}]},
    {"id": "finance", "name": "财务报销流程", "mermaid": "mermaid/12-finance-flow.mmd", "color": "#3ec9a7",
     "summary": "独立财务模块(yudao-module-finance):报销单(主表 + 1..n 明细行 + 发票附件) 一次性保存 → 提交 BPM 审批 → 通过后归档终态;驳回可改发票重新提交。附件走 system 附件中心按 recordType=finance_reimbursement 绑定,模块不与其他业务模块产生任何单据关联或字段带入。",
     "steps": [
       {"stage": "填报", "action": "主表(报销标题/报销总金额/申请日期/备注) + 至少 1 行明细(费用类型/发票号码/发票金额/发票日期/开票方/费用说明);总金额由明细求和回填,用户可手改,后端不校验一致性", "roles": ["报销人"]},
       {"stage": "附件", "action": "发票先调 /system/storage-blob/upload 取 blobId;保存时把该单当前全部 blobId 放进 blobIds 一起提交(全量替换语义,传空数组=清空,不传=不动)", "roles": ["报销人"]},
       {"stage": "保存", "action": "create 由 Redis 生成单号 BX+yyyyMMdd+6位流水(每日重置);明细先删后增全量覆盖且提交剥掉行 id;status=0 草稿", "roles": ["报销人"]},
       {"stage": "修改", "action": "update 仅放行 status=0 草稿 与 status=35 已驳回;delete 仅放行草稿(连带清理明细与发票附件)", "roles": ["报销人"]},
       {"stage": "审批", "action": "submit 传 id 与 processDefinitionKey(query 参数,请求体为空)→ status=15 审批中 并回写 processInstanceId;BPM 监听器按结果回写:通过→20 已通过、驳回→35 已驳回、取消→退回 0 草稿;流程 key 取 approve-process-list 实时列表不写死", "roles": ["报销人", "审批人"]},
       {"stage": "归档", "action": "archive 仅放行 status=20 已通过 → status=40 已归档(终态)并写入 archiveTime", "roles": ["财务"]}]},
    {"id": "ums", "name": "会员入会流程", "mermaid": "mermaid/13-ums-membership-flow.mmd", "color": "#d6955c",
     "summary": "独立会员模块(yudao-module-ums):入会申请单(个人/单位二型 + 申请等级 + 证明材料附件) 草稿 → 提交 BPM 两级审批(秘书处初审 → 理事会审议)→ 通过后自动创建系统登录账号与会员记录 → 会员进入列表与通讯录(按地区/行业检索)。驳回可改后重提,取消退回草稿。模块不与其他业务模块产生单据关联,仅复用 BPM 与 system 附件中心。",
     "steps": [
       {"stage": "填报", "action": "选会员类型 1个人 / 2单位(**非租户多类型,而是两套字段**):个人填 姓名/工作单位/职称;单位填 单位名称/法定代表人/统一社会信用代码;共有 研究方向/联系电话/邮箱/行业/地区编码/备注", "roles": ["入会申请人", "会员管理员"]},
       {"stage": "定级", "action": "选申请等级;等级字典随会员类型切换(个人 ums_personal_grade / 单位 ums_unit_grade),前端切换类型时清空已选等级", "roles": ["入会申请人"]},
       {"stage": "附件", "action": "证明材料先调 /system/storage-blob/upload 取 blobId,随保存请求的 blobIds 一起提交;绑定 recordType=ums_application(会员侧为 ums_member)", "roles": ["入会申请人"]},
       {"stage": "保存", "action": "create 由 Redis 生成申请编号 SQ+yyyyMMdd+6位流水(每日重置),后端生成不可自定义;status=0 草稿,表单不填状态", "roles": ["入会申请人"]},
       {"stage": "修改", "action": "update 仅放行 status=0 草稿 与 status=35 已驳回(驳回时提示带申请编号);delete 仅放行草稿,且连带清理该单附件", "roles": ["入会申请人", "会员管理员"]},
       {"stage": "审批", "action": "submit 传 id 与 processDefinitionKey(query 参数)→ status=15 审批中并回写 processInstanceId;BPM 监听器 UmsApplicationStatusListener 按结果回写:通过→20、驳回→35、取消→退回 0;流程列表由 approve-process-list 实时取(先校验 BPM 分类 ums_membership_approve 存在,再按 key 取未挂起的最高版本),不写死 key", "roles": ["入会申请人", "秘书处(初审)", "理事会(审议)"]},
       {"stage": "建档", "action": "审批通过钩子自动建会员:①生成会员编号 HY+yyyyMMdd+6位流水 ②AdminUserApi.createUser 建系统账号(用户名与初始密码=联系电话、昵称=申请人姓名、部门=学会会员)③会员落库(入会日期=当天、状态 1 正常、applicationId 回填来源申请单);手机号重复会明确报错", "roles": ["系统自动"]},
       {"stage": "管理与检索", "action": "会员列表支持手工新增/编辑/删除(等级与类型校验:单位会员不可选『理事长』);会员通讯录为只读页,按地区编码与行业检索", "roles": ["会员管理员", "全体可查通讯录"]}]},
    {"id": "research", "name": "课题管理流程", "mermaid": "mermaid/14-research-flow.mmd", "color": "#e070a8",
     "summary": "独立科研模块(yudao-module-research):学会发布课题指南(重点/一般分类)→ 会员在线提交课题申报书 → 提交 BPM 三级审批(秘书处形式审查 → 专家评审 → 学会立项审批),专家评分以结构化明细子表记录并由后端自动汇总加权均分、排名与推荐结论 → 审批通过生成立项编号并发布系统公告 → 按批次登记经费拨付(凭证必填),每条拨款记录自动生成并提交一张 1:1 的财务报销单(finance_reimbursement),走 BPM 两级审批后由监听器把结果回写台账。院级二期再补结项验收与成果归档。",
     "steps": [
       {"stage": "发布指南", "action": "新建指南选类别 1重点课题 / 2一般课题,填申报起止时间与指南正文;编号 GL+yyyyMMdd+6位流水(Redis 每日重置);status: 0草稿/20已发布/30已截止。仅草稿可改可删,发布后即冻结;已产生申报单的指南禁止删除(提示该指南下已有 N 张申报单)", "roles": ["学会秘书处", "课题管理员"]},
       {"stage": "在线申报", "action": "从已发布且在申报期内的指南新建申报书;选会员(ums_member)自动带出姓名/工作单位/职称/联系电话/邮箱,可改;填课题名称、课题组成员、申请经费、申报书正文;编号 SB+yyyyMMdd+6位流水;类别冗余自指南,不信任前端传值;status: 0草稿", "roles": ["课题申报人(会员)", "课题管理员"]},
       {"stage": "提交审批", "action": "submit 传 id 与 processDefinitionKey(query 参数)→ status=15 审批中并回写 processInstanceId。提交前逐条校验:① 指南必须已发布 ② 当前时间必须在申报起止期内——任一不满足即拒绝,提示带指南名与实际状态或起止时间;仅草稿与已驳回可改可重提,仅草稿可删(连带清附件)", "roles": ["课题申报人"]},
       {"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": ["学会财务", "课题管理员", "财务审核人", "财务主管"]}]},
    {"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": [
@@ -579,7 +698,15 @@
    {"role": "客服/售后工程师", "modules": ["售后"], "operations": ["工单受理派工", "维修", "退货申请"], "data": ["after_sale_*"], "scope": "行级数据权限四视图:我负责/我参与/下属负责/全部(aftersales:view-all)"},
    {"role": "财务", "modules": ["ERP", "CRM"], "operations": ["收款单", "付款单", "开票审核", "结算账户"], "data": ["erp_finance_*", "crm_invoice", "crm_receivable"], "scope": "financeUserId 归属"},
    {"role": "HR", "modules": ["HRM"], "operations": ["员工档案入转调离", "考勤规则排班", "薪酬核算发放", "离职交接"], "data": ["hrm_*"], "scope": "部门范围 dataScope"},
    {"role": "管理层", "modules": ["BI"], "operations": ["查看采购销售/仓库/生产设备/质量/人力五大主题大屏"], "data": ["bi_dashboard"], "scope": "只读"}
    {"role": "管理层", "modules": ["BI"], "operations": ["查看采购销售/仓库/生产设备/质量/人力五大主题大屏"], "data": ["bi_dashboard"], "scope": "只读"},
    {"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>
<pre style="display:none" class="mmd-src" data-mmd="01-business-mindmap">
@@ -613,6 +740,40 @@
      付款单
      收款单
      结算账户
    财务报销 FIN 独立
      报销单主表
      报销明细行
      发票附件上传
      提交审批与驳回重提
      归档终态
    会员管理 UMS 独立
      入会申请单
      个人与单位二型字段
      会员等级个人与单位两套
      秘书处理事会两级审批
      审批通过自动建会员
      自动创建系统登录账号
      会员列表与通讯录检索
    课题管理 RES 独立
      课题指南发布
      重点与一般课题分类
      指导申报期与截止
      在线课题申报书
      从会员带出申报人信息
      专家评审明细与加权排名
      秘书处理事会三级审批
      立项编号与立项通知公告
      经费拨付记录与凭证
    档案管理 ARCHIVE 独立
      档案分类书架分层分列
      档案文档集中存储与检索
      电子附件与实体位置兼具
      密级管控与敏感权限
      借阅登记与两级审批
      归还登记与流转闭环
      逾期未还实时提醒
      档案存量与流转统计
      课题会员财务三方归档联动
    生产管理 MES
      主生产计划 MPS
      生产工单
@@ -808,7 +969,7 @@
  RCTX --> RCITEM[检验项=样品×指标交叉展开·全指标进不过滤·多样品时样品号折进 remark]
  RCTX --> RCQC[携带单据原判定 qcResult 数·qcResultText 中文·与引擎判定并存互不覆盖]
  MESMAP -->|分组项 item_type=2 与它的子项按 parent_id 还原两层·归属不看 type 也不看行序| RCTXG
  RCTXG["分组还原·组头行背组名与 formula_text 公式·组内第一行背 span=该组总行数·同组其余行 span=1 且 hidden 让位·只合并检验项目一列"] --- RCTX
  RCTXG["分组还原·组头行背组名与 formula_text 公式·组内第一行背 span=该组总行数·同组其余行 span=1 且 hidden 让位·合并的是模板 columns 里带 # 的那一列(默认列即检验项目)·合并行数是本单该组实际行数而非主数据子项数·该组本单无子项行则不合并"] --- RCTX
  MESMAP -.->|分组项本单没有属于它的子项 / 组头本单没有行由后端补一行| RCWARN
  MESMAP -.->|指标已删 / 未录实测值(组头锚点行按定义无值·不报) / 样品超 3 个·进 warnings| RCWARN
  RCWARN[warnings 软提示·不落库·事后看不到需自行留痕] --- RCTX
@@ -899,7 +1060,7 @@
  MES -->|退货质检入库回调| AS[售后工单维修退货]
  CRM -->|客户主数据| AS
  HRM[HRM 员工入转调离交接考勤薪酬] -.->|expandUserIds 数据可见性扩展·接口已就绪待各模块接入| CRM
  BPM[BPM Flowable 审批引擎] -.->|状态事件回调·13个监听器| ERP
  BPM[BPM Flowable 审批引擎] -.->|状态事件回调·15个监听器| ERP
  BPM -.-> CRM
  BPM -.-> SRM
  BPM -.-> MES
@@ -916,6 +1077,25 @@
  SYS[系统底座 认证·RBAC·字典·附件中心·定时任务] --- MDM
  SYS --- MES
  STG[附件中心 storage-blob+attachment 全模块统一挂附件] --- ERP
  FIN[财务报销 独立模块 yudao-module-finance 报销单 明细 发票附件] -.->|复用 BPM 审批与状态回调| BPM
  FIN -.->|发票走附件中心 recordType=finance_reimbursement| STG
  FIN -.->|"对外仅提供 yudao-module-finance-api(FinanceReimbursementApi)供他模块建单"| ERP
  UMS[会员管理 独立模块 yudao-module-ums 入会申请 会员 通讯录] -.->|复用 BPM 两级审批与状态回调| BPM
  UMS -.->|证明材料走附件中心 recordType=ums_application / ums_member| STG
  UMS -.->|审批通过经 AdminUserApi.createUser 建系统登录账号| SYS
  UMS -.->|独立模块·不与其它业务模块产生单据或数据关联| ERP
  RES[课题管理 独立模块 yudao-module-research 指南 申报书 专家评审 经费拨付] -.->|复用 BPM 三级审批与状态回调·流程 key=research_topic_approve| BPM
  RES -.->|附件走附件中心 recordType=research_guideline / research_application / research_fund_record| STG
  RES -->|选会员取申报人姓名 工作单位 职称 联系电话| UMS
  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
@@ -990,6 +1170,61 @@
  UIREP -.->|结果就地展示 reportNo itemCount 与 undecidableCount 告警| QCFE
  QCFE -.->|进入时带 businessType+businessId 路由 query·预填搜索表单的「业务单据」字段| UIREP
  RPT -.->|权限码 qc-report:template:ai-import 已入 system_menu| SYS1
  subgraph S5 [独立财务报销 finance]
    RBM[报销单 finance_reimbursement] --> RBI[报销明细 finance_reimbursement_item]
    RBM --> RBA[发票附件 recordType=finance_reimbursement]
    RBM --> RBS[状态 草稿0 审批中15 已通过20 已驳回35 已归档40]
  end
  RBM -->|create 带主表与 items 数组与 blobIds 一次性提交| RBI
  RBI -.->|invoiceAmount 求和回填 totalAmount·用户可手改·后端不校验一致性| RBM
  RBM -->|submit 带 id 与 processDefinitionKey 走 query| RBS
  RBS -.->|BPM 监听器结果回写 通过20 驳回35 取消退回0| RBM
  RBA -.->|上传与保存分离·禁在业务表存文件地址| PDFARCH
  FINNOTE[独立模块·销售采购链条任意单据均不生成报销单·报销单亦不回写任何外部单据·唯一例外是课题经费拨付] -.-> RBM
  subgraph S6 [独立课题管理 research]
    RGL[课题指南 research_guideline] --> RAP[课题申报书 research_application]
    RAP --> RRV[专家评审明细 research_topic_review]
    RAP --> RFR[经费拨付记录 research_fund_record]
    RAP --> RST[状态 草稿0 审批中15 已立项20 已驳回35]
  end
  UMSM[会员 ums_member] -->|"选会员带出 applicantName workUnit jobTitle contactPhone contactEmail·软关联无外键"| RAP
  RGL -->|"申报时引用·要求 publishStatus=已发布20 且 现在在 applyStartTime 至 applyEndTime 内"| RAP
  RAP -->|"category 冗余自指南·不信任前端传值"| RAP
  RAP -->|"submit 带 id 与 processDefinitionKey 走 query·回写 processInstanceId"| RST
  RST -.->|"BPM 监听器 ResearchApplicationStatusListener 回写 通过20 驳回35 取消退回0"| RAP
  RAP -->|"审批通过后 approveApplication 生成 researchNo LX 与 approveTime·已有编号幂等跳过"| RAP
  RRV -->|"recalculate: compositeScore 加权 0.3/0.3/0.2/0.2 → ranking 降序重排 → 主单 reviewAvgScore 与 reviewPass"| RAP
  RRV -.->|"明细删空时主单汇总清为 null"| RAP
  RAP -->|"publishNotice 生成 system_notice 公告并回写 noticeId·重复发布拦截"| SYS2[system_notice 系统公告]
  RFR -->|"金额校验 已登记 + 本次 不得超出 budgetAmount 申请经费"| RAP
  RFR -.->|"凭证走附件中心 recordType=research_fund_record·同一批 blob 双绑 finance_reimbursement·表内不存文件地址"| PDFARCH
  RAP -.->|"申报附件 recordType=research_application"| PDFARCH
  RGL -.->|"指南附件 recordType=research_guideline"| PDFARCH
  RFR -->|"1:1 生成报销单·经 FinanceReimbursementApi 本地 Bean 建单并立即 submit·回写 reimbursement_id/reimbursement_no·台账置 15 报销审批中"| RBM
  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
@@ -1027,9 +1262,21 @@
  srm_supplier ||--o{ mes_wm_arrival_notice : "到货来源"
  erp_purchase_order ||--o{ erp_purchase_invoice : "来票"
  erp_purchase_invoice ||--o{ erp_finance_payment : "付款"
  ums_application ||--o| ums_member : "审批通过自动建档"
  hrm_employee ||--o| hrm_user_handover : "离职交接映射"
  qc_report_template ||--o{ qc_report_template_version : "多版本"
  qc_report_template_version ||--o{ qc_report_instance : "冻结出件版本"
  finance_reimbursement ||--o{ finance_reimbursement_item : "费用明细"
  research_guideline ||--o{ research_application : "被申报引用"
  research_application ||--o{ research_topic_review : "专家评分明细"
  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
@@ -1074,6 +1321,168 @@
  MODE[模型层:通义千问为主·预留DeepSeek/OpenAI/Ollama未实现] --- O2
  NOTE[全项目无Function Calling·AI只输出结构化JSON由业务侧解析] --- J2
</pre>
<pre style="display:none" class="mmd-src" data-mmd="12-finance-flow">
flowchart TD
  U1["报销人填报报销单·主表: 报销单号(选填) 报销标题 报销总金额 申请日期 备注"] --> U2["录入报销明细 1..n 行: 费用类型 发票号码 发票金额 发票日期 开票方 费用说明"]
  U2 --> U3[发票附件: 图片或 PDF 先传 system storage-blob upload 取 blobId]
  U3 --> S1[保存 create·主表与明细与全部 blobIds 一次性提交]
  S1 --> G1["报销单号:可自定义;留空(含纯空格)则由后端生成 BX + yyyyMMdd + 6位流水(Redis·每日重置)"]
  G1 --> B1["明细先删后增全量覆盖·提交剥掉行 id(软删后重插避免主键冲突)"]
  B1 --> A1["附件绑定 recordType = finance_reimbursement·按该单全部 blobId 全量替换"]
  A1 --> K1[草稿 0]
  K1 -->|update 修改主表 明细 附件| K1
  K1 -->|submit 选审批流程 processDefinitionKey| K2[审批中 15·回写 processInstanceId]
  K2 -->|BPM 审批通过| K3[已通过 20]
  K2 -->|BPM 审批驳回| K4[已驳回 35]
  K2 -->|BPM 审批取消| K1
  K4 -->|改发票后重新 submit| K2
  K3 -->|archive 归档| K5[已归档 40·终态·写入 archiveTime]
  D1["仅草稿 0 可 delete·连带清理明细与发票附件"] -.-> K1
  E1["仅草稿 0 与已驳回 35 可 update·其余状态只读"] -.-> K4
  N1["独立模块·与销售采购链条任何单据均无关联;唯一例外是被课题经费拨付 1:1 自动生成(经 yudao-module-finance-api)"] --- K1
</pre>
<pre style="display:none" class="mmd-src" data-mmd="13-ums-membership-flow">
flowchart TD
  A1[填报入会申请·选会员类型 1个人 / 2单位] --> A2[个人分支: 姓名 联系电话 邮箱 工作单位 职称 研究方向 行业 地区]
  A1 --> A3[单位分支: 单位名称 法定代表人 统一社会信用代码 研究方向 行业 地区]
  A2 --> A4[选申请等级·按会员类型切换字典 ums_personal_grade / ums_unit_grade]
  A3 --> A4
  A4 --> A5[证明材料附件: 先传 system storage-blob upload 取 blobId]
  A5 --> S1[保存 create·附件按该单全部 blobIds 绑定]
  S1 --> G1["申请编号 SQ + yyyyMMdd + 6位流水(Redis·每日重置)·后端生成不可改"]
  G1 --> K1[草稿 0]
  K1 -->|update 修改申请| K1
  K1 -->|submit 选审批流程 processDefinitionKey| K2[审批中 15·回写 processInstanceId]
  K2 -->|BPM 审批通过| K3[已通过 20]
  K2 -->|BPM 审批驳回| K4[已驳回 35]
  K2 -->|BPM 审批取消| K1
  K4 -->|修改后重新 submit| K2
  K3 --> M1["审批通过钩子: 自动创建会员 ums_member (内部先查状态确为已通过才执行)"]
  M1 --> M2["会员编号 HY + yyyyMMdd + 6位流水(Redis)"]
  M2 --> M3["创建系统登录账号 AdminUserApi.createUser·用户名与初始密码=联系电话·昵称=申请人姓名·部门=学会会员"]
  M3 --> M4[会员落库·入会日期=当天·状态 1正常·来源申请单 applicationId 回填]
  M4 --> D2[会员列表·可手工 create / update / delete]
  D2 --> V1["等级类型校验: 单位会员(memberType=2) 不可选『理事长』(memberGrade=5) 直接拒绝"]
  M4 --> D1[会员通讯录·只读·按地区 regionCode 与行业 industry 检索]
  ATT1["附件 recordType = ums_application"] -.-> K1
  ATT2["附件 recordType = ums_member"] -.-> M4
  RES1["仅草稿 0 可 delete·连带清理附件"] -.-> K1
  RES2["仅草稿 0 与已驳回 35 可 update·其余状态只读"] -.-> K4
  ROL["审批链: BPM 流程定义 ums_membership_approve(归属分类 ums_membership_approve) 秘书处初审 → 理事会审议·两节点审批人=角色策略(超管角色兜底)·后端按分类实时取流程、不写死 key"] -.-> K2
  F1["审批中心看单: 流程定义表单类型=自定义表单·查看路径 /ums/application/detail/approve/index.vue·按 businessKey 回显申请单"] -.-> K2
  N1["独立模块·不与其他业务模块产生单据关联·仅复用 BPM 审批与 system 附件中心"] --- K1
</pre>
<pre style="display:none" class="mmd-src" data-mmd="14-research-flow">
flowchart TD
  subgraph P1 [课题指南发布]
    G0[新建指南·选类别 1重点课题 / 2一般课题] --> G1[填指南名称 申报起止时间 指南正文 附件]
    G1 --> G2["指南编号 GL + yyyyMMdd + 6位流水(Redis·每日重置)"]
    G2 --> G3[草稿 0·仅草稿可改可删]
    G3 -->|已产生申报单则禁止删除| G3B["提示该指南下已有 N 张申报单·需先处理申报单"]
    G3 -->|publish 发布| G4["已发布 20·回写 publishTime"]
    G4 -->|close 截止| G5[已截止 30]
  end
  G4 -->|"指南已发布才可作为申报前提"| A1
  subgraph P2 [在线申报]
    A1[选指南·要求已发布 且在申报期内] --> A2[选会员 ums_member 自动带出 姓名 工作单位 职称 电话 邮箱]
    A2 --> A3[填课题名称 课题组成员 申请经费 申报书正文 申报附件]
    A3 --> A4["申报编号 SB + yyyyMMdd + 6位流水·类别冗余自指南不信任前端传值"]
    A4 --> K1[草稿 0]
  end
  K1 -->|update 修改·仅草稿 0 与已驳回 35 放行| K1
  K1 -->|delete 删除·仅草稿 0 放行·连带清理附件| K1
  K1 -->|submit 选审批流程 processDefinitionKey| K2["审批中 15·回写 processInstanceId"]
  K1 -->|"submit 前逐条校验: ① 指南必须已发布 ② 当前时间必须在申报起止期内"| KERR["任一不满足即拒绝提交·提示带指南名与实际状态或起止时间"]
  K2 -->|"仅审批中可增删改专家评分"| RK[专家评审明细 research_topic_review·一位专家一行]
  RK -->|"后端逐行重算 compositeScore = 选题0.3 + 方案0.3 + 团队0.2 + 成果0.2"| RC[按加权分降序重排名次 ranking]
  RC -->|"回写主单: reviewAvgScore=全部专家均分 · reviewPass=均分达标 且 多数结论为推荐立项"| SUM[申报单评审汇总·删除最后一条明细时清空汇总]
  SUM -->|"秘书处汇总申报书与评审结果"| K3
  K2 --> K3
  subgraph P3 [立项审批 BPM research_topic_approve]
    K3["三节点顺序·审批方法与审批人在流程定义内配置"] --> KA[Activity_secretariat_review 秘书处形式审查]
    KA -->|通过| KB[Activity_expert_review 专家评审]
    KB -->|通过| KC[Activity_council_approve 学会立项审批]
  end
  KC -->|BPM 审批通过| K4["已立项 20·监听器生成 立项编号 LX + yyyyMMdd + 6位流水 与 approveTime·已有编号则幂等跳过"]
  KC -->|BPM 审批驳回| K5[已驳回 35]
  KC -->|BPM 审批取消| K1
  KA -->|驳回| K5
  K5 -->|修改后重新 submit| K2
  K4 -->|publishNotice 发布立项通知| N1["system_notice 公告·标题『关于公布立项课题的通知』·正文含课题名 立项编号 类别 申报人 单位 资助金额·回写 noticeId·重复发布被拦截"]
  K4 -->|登记拨款记录 research_fund_record| F1[填批次名称 拨付金额 拨付日期 收款单位 备注·凭证附件必填]
  F1 -->|"金额校验: 已登记金额 + 本次金额 不得超出申报单申请经费·超出时报出本次 已登记 合计 预算四项数值"| FGEN["自动生成 1:1 财务报销单 finance_reimbursement(1 行明细: 费用类型=其他 发票金额=拨付金额 发票日期=拨付日期 费用说明=课题名+批次)·附同一批凭证·立即提交 BPM·回写报销单号"]
  FGEN -->|回写台账状态| F3[报销审批中 15]
  F3 -->|"财务审核 Activity_finance_review"| FAPP[财务主管审批 Activity_finance_approve]
  FAPP -->|BPM 审批通过| F4[已拨付 20]
  FAPP -->|BPM 审批驳回| F5["已驳回 30·回写驳回原因与驳回时间"]
  F5 -->|"修改金额或凭证后重新发起报销"| F3
  FAPP -->|"发起人/管理员取消流程"| F2["待拨付 0·可编辑可删除"]
  F2 -->|"仅待拨付 0 可改可删·删除时联动清理财务侧草稿报销单"| F2
  F2 -->|"修改后重新发起报销"| F3
  ATT1["附件 recordType = research_guideline"] -.-> G3
  ATT2["附件 recordType = research_application"] -.-> K1
  ATT3["附件 recordType = research_fund_record·同一批 blob 双绑 finance_reimbursement(按 recordType+recordId 隔离互不影响)"] -.-> F1
  ROL["审批中心看单: 流程定义表单类型=自定义表单·创建路径 /research/application/index · 查看路径 /research/application/detail/approve/index.vue·按 businessKey 回显申报单"] -.-> K3
  ROL2["审批人取值: 三节点在流程定义内配好审批方法(依次审批)与审批人策略·部署后由管理员在 BPM 流程设计器按学会实际组织调整·提交时前端只让选流程不选审批人"] -.-> K3
  LIS2["监听器 ResearchFundStatusListener(流程 key=finance_reimbursement_approve·businessKey=报销单 ID): 通过→台账已拨付 20·驳回→已驳回 30+原因与时间·取消流程→退回待拨付 0(发起人撤回仅退回发起节点、流程未结束,不触发回写)·与 finance 自己的监听器订阅同一 key 并行触发"] -.-> F3
  FINAPI["跨模块走新建的 yudao-module-finance-api(FinanceReimbursementApi·本地 Bean 非 HTTP): 无已发布报销审批流程时先解析即报错·不建单·避免留下孤儿草稿报销单"] -.-> FGEN
  RES1["一期已对接财务: 拨款必须走 finance_reimbursement 报销单出账·课题侧台账=拨款台账·财务报销单=出账凭证·两边以 reimbursement_id 软关联(无外键)·财务审批结果自动回写本台账"] -.-> F1
  RES2["二期范围(本图未覆盖): 结项验收 结项证书 成果归档知识库 采纳情况与社会效益标注"] -.-> K4
  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 = {};
@@ -1093,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)',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');
@@ -1130,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',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)',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>