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;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
@@ -111,6 +111,9 @@
  <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>
  <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 +140,9 @@
<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="relation">
  <h2 class="pt">系统关系</h2>
  <p class="desc">模块之间的调用与数据依赖:实线=单据/数据流向,虚线=审批回调与辅助能力。</p>
@@ -186,6 +192,9 @@
    "subSystems": [
      "MES(生产·仓储·质量·设备)",
      "ERP(进销存·财务)",
      "FIN(发票报销,独立模块)",
      "UMS(学会会员,独立模块)",
      "RES(科研课题,独立模块)",
      "CRM(客户关系)",
      "SRM(供应商关系)",
      "HRM(人力资源)",
@@ -197,14 +206,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 共 427 张表(含 system_*、bpm_*、act_* 底座表与 mes_*/erp_*/crm_*/srm_*/hrm_*/mdm_*/ai_*/finance_*/ums_*/research_* 业务表),多租户已关闭",
    "frontend": "mom-pro2-before(Vue3 管理后台,同仓库存放,只读参考)"
  },
  "stats": {
    "businessModules": 13,
    "coreObjects": 48,
    "documentFlows": 6,
    "approvalListeners": 13,
    "businessModules": 16,
    "coreObjects": 56,
    "documentFlows": 9,
    "approvalListeners": 14,
    "aiCapabilities": 8,
    "wmBillTypes": 15
  },
@@ -323,10 +332,21 @@
    "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)不一致",
    "财务报销:BPM 分类 finance_reimbursement_approve 下尚无已发布的流程定义(act_re_cprocdef 为空),且流程需把「自定义表单路径」配为 /finance/reimbursement/detail/approve/index.vue,否则前端「提交审批」被禁用、审批中心看不到报销单内容【需 BPM 设计器侧配置】",
    "财务报销:菜单仅授予 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 且 多数结论为推荐立项」的通过阈值是占位规则,需学会最终确认;已集中为常量便于调整【待确认,改动只需改常量】",
    "课题管理:一期经费拨付只在本模块落拨款记录,与财务模块无任何数据同步,同一笔钱在两处记录存在不一致风险;二期对接时需明确以哪侧为准【待确认】",
    "课题管理:申报单与 ums_member 是软关联(无外键),会员被删除后申报单会留下悬空 memberId;成员列表需容错展示「会员已删除」【待确认是否加外键或删除保护】",
    "课题管理:BPM 流程 research_topic_approve 三节点默认审批人为「角色=超级管理员(1) + 依次审批」,该 dev 库超级管理员角色下有 4 个用户(admin/张娟/马芳/马贞),每个节点需 4 人会签才推进;全新安装库该角色仅 admin 一人、流程可开箱即用。dev 库需减少超级管理员用户或改在 BPM 设计器中为每节点指定审批人【环境配置项,非代码缺陷】",
    "课题管理:立项通知复用 system_notice 系统公告,不新增 system_notify_template、不发站内信;如需短信/站内信定向通知需另行配置【待确认通知渠道】"
  ],
  "generatedAt": "2026-09-10",
  "analysisBasis": "基于 dev_business 分支 87bf4a99 源码,6 组并行源码走读(MES 生产质量 / MES 仓储 / ERP / CRM+SRM / 售后+HRM / AI+BI+MDM+BPM+底座)"
  "generatedAt": "2026-09-28",
  "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"
}</script>
<script type="application/json" id="data-modules">{
  "modules": [
@@ -362,6 +382,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 导出"],
     "objects": ["报销单", "报销明细"],
     "roles": ["报销人", "财务", "审批人"],
     "upstream": [], "downstream": [],
     "coreTables": ["finance_reimbursement", "finance_reimbursement_item"]},
    {"key": "pro", "name": "生产管理", "color": "#e0b34f", "tag": "MES-PRO", "flow": "production",
     "positioning": "生产执行核心:计划-工单-任务-报工",
     "problem": "订单到车间执行的逐层拆解与过程可控",
@@ -418,10 +446,27 @@
     "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 防重复)", "经费拨付记录(批次/金额/日期/收款单位/状态/凭证附件)·金额不得超申请经费", "附件走 system 附件中心(recordType=research_guideline / research_application / research_fund_record)"],
     "objects": ["课题指南", "课题申报书", "专家评审明细", "经费拨付记录"],
     "roles": ["课题申报人(会员)", "课题管理员", "评审专家", "学会秘书处", "学会理事会"],
     "upstream": ["会员管理(ums_member 取申报人姓名/单位/职称/电话)", "BPM(流程定义 research_topic_approve)"],
     "downstream": ["system(system_notice 立项通知公告)", "system(附件中心)", "财务(二期预期待对接·一期不接)"],
     "coreTables": ["research_guideline", "research_application", "research_topic_review", "research_fund_record"]},
    {"key": "bpm", "name": "协同审批", "color": "#e6a23c", "tag": "BPM", "flow": null,
     "positioning": "全系统单据审批中枢(Flowable)",
     "problem": "多模块单据需要灵活可配的多级审批",
     "features": ["BPMN+钉钉风格双设计器", "流程定义部署", "审批事件统一回调(BpmProcessInstanceStatusEvent)", "13个业务监听器", "表单·用户组·抄送·加签"],
     "features": ["BPMN+钉钉风格双设计器", "流程定义部署", "审批事件统一回调(BpmProcessInstanceStatusEvent)", "14个业务监听器", "表单·用户组·抄送·加签"],
     "objects": ["流程模型", "流程实例", "审批任务"],
     "roles": ["审批人(按流程配置)", "流程管理员"],
     "upstream": ["各业务提交审批"], "downstream": ["回调更新各业务单据状态"],
@@ -438,7 +483,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 +535,15 @@
    {"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 被回写;独立模块,不与其它业务模块产生单据关联", "upstream": [], "downstream": ["报销明细", "发票附件(storage_attachment·recordType=finance_reimbursement)"], "keywords": "报销单 报销 发票 reimbursement BX 归档 财务 费用 自定义单号"},
    {"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": "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_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": "research_fund_record", "doc": "一主多行的拨款记录:batchName 批次名称/amount 拨付金额/payDate 拨付日期/payee 收款单位/status 0待拨付 20已拨付/remark,凭证附件走 system 附件中心 recordType=research_fund_record(表内不存文件地址)。仅申报单 status=20 已立项可登记;金额校验:已登记金额(该单全部记录求和) + 本次金额 不得超出申报单 budgetAmount,超出时提示报出本次、已登记、合计、预算四项数值;status=20 已拨付 时凭证附件必填(前端先行拦截,后端 validateVoucherRequired 兜底);仅待拨付状态可改可删,编辑时把本行金额加回可用余额展示避免误解", "upstream": ["课题申报书(必须已立项)"], "downstream": ["拨付凭证(storage_attachment·recordType=research_fund_record)", "财务(二期预期待对接·一期不接)"], "keywords": "经费拨付 拨款 拨付记录 批次 拨付金额 凭证 待拨付 已拨付 收款单位 资助金额 预算 超额"}
  ]
}</script>
<script type="application/json" id="data-flows">{
@@ -548,6 +601,36 @@
       {"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 三级审批(秘书处形式审查 → 专家评审 → 学会立项审批),专家评分以结构化明细子表记录并由后端自动汇总加权均分、排名与推荐结论 → 审批通过生成立项编号并发布系统公告 → 按批次登记经费拨付记录(含凭证附件)。院级二期再补结项验收与成果归档。",
     "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)」的申报单可登记拨款记录(批次名称/拨付金额/拨付日期/收款单位/状态/备注/凭证附件);金额校验:已登记金额 + 本次金额 不得超出该单申请经费,超出时提示报出本次、已登记、合计、预算四项数值;status: 0待拨付/20已拨付,凭证明细走 system 附件中心 recordType=research_fund_record,状态改为已拨付时凭证必填;仅待拨付状态可改可删,编辑时会把本行金额加回余额显示", "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 +662,11 @@
    {"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": ["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 +700,30 @@
      付款单
      收款单
      结算账户
    财务报销 FIN 独立
      报销单主表
      报销明细行
      发票附件上传
      提交审批与驳回重提
      归档终态
    会员管理 UMS 独立
      入会申请单
      个人与单位二型字段
      会员等级个人与单位两套
      秘书处理事会两级审批
      审批通过自动建会员
      自动创建系统登录账号
      会员列表与通讯录检索
    课题管理 RES 独立
      课题指南发布
      重点与一般课题分类
      指导申报期与截止
      在线课题申报书
      从会员带出申报人信息
      专家评审明细与加权排名
      秘书处理事会三级审批
      立项编号与立项通知公告
      经费拨付记录与凭证
    生产管理 MES
      主生产计划 MPS
      生产工单
@@ -808,7 +919,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 +1010,7 @@
  MES -->|退货质检入库回调| AS[售后工单维修退货]
  CRM -->|客户主数据| AS
  HRM[HRM 员工入转调离交接考勤薪酬] -.->|expandUserIds 数据可见性扩展·接口已就绪待各模块接入| CRM
  BPM[BPM Flowable 审批引擎] -.->|状态事件回调·13个监听器| ERP
  BPM[BPM Flowable 审批引擎] -.->|状态事件回调·14个监听器| ERP
  BPM -.-> CRM
  BPM -.-> SRM
  BPM -.-> MES
@@ -916,6 +1027,17 @@
  SYS[系统底座 认证·RBAC·字典·附件中心·定时任务] --- MDM
  SYS --- MES
  STG[附件中心 storage-blob+attachment 全模块统一挂附件] --- ERP
  FIN[财务报销 独立模块 yudao-module-finance 报销单 明细 发票附件] -.->|复用 BPM 审批与状态回调| BPM
  FIN -.->|发票走附件中心 recordType=finance_reimbursement| STG
  FIN -.->|独立模块·不与其它业务模块产生单据或数据关联| 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
</pre>
<pre style="display:none" class="mmd-src" data-mmd="09-data-flow">
flowchart LR
@@ -990,6 +1112,37 @@
  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·表内不存文件地址"| PDFARCH
  RAP -.->|"申报附件 recordType=research_application"| PDFARCH
  RGL -.->|"指南附件 recordType=research_guideline"| PDFARCH
  RESNOTE[独立模块·一期经费拨付只在本模块落记录·与财务模块无数据同步·二期再对接] -.-> RFR
</pre>
<pre style="display:none" class="mmd-src" data-mmd="10-business-object">
erDiagram
@@ -1027,9 +1180,15 @@
  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 : "经费拨付记录"
  ums_member ||--o{ research_application : "申报人(软关联无外键)"
</pre>
<pre style="display:none" class="mmd-src" data-mmd="11-ai-business-flow">
flowchart TD
@@ -1074,6 +1233,108 @@
  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["独立模块·不与其他业务模块产生单据或字段带入"] --- 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 -->|"金额校验: 已登记金额 + 本次金额 不得超出申报单申请经费·超出时报出本次 已登记 合计 预算四项数值"| F2[待拨付 0]
  F2 -->|"仅待拨付 0 可改可删"| F2
  F2 -->|"状态改为已拨付时必须已有凭证附件"| F3[已拨付 20]
  ATT1["附件 recordType = research_guideline"] -.-> G3
  ATT2["附件 recordType = research_application"] -.-> K1
  ATT3["附件 recordType = research_fund_record"] -.-> F1
  ROL["审批中心看单: 流程定义表单类型=自定义表单·创建路径 /research/application/index · 查看路径 /research/application/detail/approve/index.vue·按 businessKey 回显申报单"] -.-> K3
  ROL2["审批人取值: 三节点在流程定义内配好审批方法(依次审批)与审批人策略·部署后由管理员在 BPM 流程设计器按学会实际组织调整·提交时前端只让选流程不选审批人"] -.-> K3
  RES1["一期边界: 经费拨付只在本模块落拨款记录·与财务模块无数据同步(不做跨模块对接)"] -.-> F1
  RES2["二期范围(本图未覆盖): 结项验收 结项证书 成果归档知识库 采纳情况与社会效益标注"] -.-> K4
  BOUND["独立模块 yudao-module-research·对 ums_member 为软关联(无外键)·仅复用 BPM 审批、system 公告与附件中心"] --- K1
</pre>
<script type="module">
const DATA = {};
@@ -1093,7 +1354,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)',ai:'var(--c-ai)'};
async function boot(){
  DATA.business = await loadJson('business');
@@ -1130,8 +1391,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',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)'};
  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>