docs(project-business): 更新项目业务文档增加财务报销会员管理和课题管理模块
- 在业务思维导图中添加财务报销、会员管理和课题管理三个独立模块及其功能点
- 更新模块关系图,添加新模块与BPM、附件中心等系统的关联关系
- 在数据流图中添加财务报销和课题管理的子图及详细数据流向
- 扩展业务对象关系图,添加新模块间的数据关联关系
- 新增财务报销流程图,详细描述报销单填报、审批、归档全流程
- 更新业务JSON数据,添加新模块信息、统计数据和待解决问题
- 扩展流程JSON,添加财务报销、会员入会、课题管理三个新业务流程
- 更新首页样式,为新模块添加颜色主题和导航链接
- 在系统概览中添加新子系统标识和数据库表统计信息
- 完善模块详情,为财务、会员、课题模块添加功能特性描述
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 课é¢ç³æ¥ä¹¦éä»¶ï¼E2E æµè¯ï¼ |
| | | |
| | | 课é¢åç§°ï¼é¢åæºè½å·¥åçæ°ååªçå
³é®ææ¯ç ç©¶ |
| | | ç³æ¥äººï¼å¼ ä¼ |
| | | |
| | | æ¬æä»¶ç¨äºç«¯å°ç«¯éªè¯éä»¶ä¸ä¼ ä¸ç»å®æµç¨ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | {"code":0,"data":{"userId":1,"accessToken":"ad2605f793b2406cb951c18105d4c834","refreshToken":"8c2f2683b9cf43c6842cbd72a98b4841","expiresTime":1790590394166},"msg":""} |
| | |
| | | - **ä¸å¡å®ä½**ï¼ç¦»æ£å¶é å·¥å产ä¾é人财ç©ä¸ä½åï¼è¦çãé宿¥å â éè´/ç产 â è´¨æ£ â ä»å¨ â åè´§ â 忬¾ â å®åãå
¨é¾è·¯éç¯ |
| | | - **ææ¯åºåº§**ï¼yudaoï¼ruoyi-vue-proï¼äºå¼ï¼Spring Boot + MyBatis + Flowable + Redis + MySQL 8.4 + Milvus + éä¹åé®ï¼å端 mom-pro2-beforeï¼Vue3ï¼ |
| | | - **æ ¸å¿ä¸»çº¿**ï¼CRM åå â ERP éå®è®¢å â MES 主计å/å·¥å/æ¥å·¥ â è´¨æ£ä¸ä»å¨ â éå®åºåº â å¼ç¥¨å款 â å®åéç¯ |
| | | - **ç¬ç«æ¨¡å**ï¼è´¢å¡æ¥éï¼`yudao-module-finance`ï¼æ¥éå/æç»/å票éä»¶/审æ¹/彿¡£ï¼ä¸ä¼å管çï¼`yudao-module-ums`ï¼å
¥ä¼ç³è¯·/ç§ä¹¦å¤ä¸çäºä¼ä¸¤çº§å®¡æ¹/ä¼å/é讯å½ï¼åèªæä¸æ¡é¾è·¯ï¼åä¸ä¸å
¶ä»ä¸å¡æ¨¡å产çåæ®å
³èï¼UMS ä¾å¤ï¼å®¡æ¹éè¿ä¼ç» AdminUserApi å建系ç»ç»å½è´¦å·ï¼ï¼è¯¾é¢ç®¡çï¼`yudao-module-research`ï¼è¯¾é¢æå/å¨çº¿ç³æ¥/ä¸å®¶è¯å®¡/ä¸çº§ç«é¡¹å®¡æ¹/ç«é¡¹éç¥/ç»è´¹æ¨ä»ï¼ä¸ºå¦ä¸æ¡ç¬ç«ç§ç 主线ï¼ä»
åå¤å `ums_member` ä½ä¸ºç³æ¥äººãåå
å `system_notice` ç«é¡¹å
Œ |
| | | |
| | | ## 2. ç®å½ç»æ |
| | | |
| | | ```text |
| | | docs/project-business/ |
| | | âââ index.html # å¯è§å页é¢ï¼åå»ç´æ¥æå¼ï¼file:// å³å¯ï¼æ é任使å¡ï¼ |
| | | âââ mermaid/ # 11 å¼ Mermaid ä¸å¡å¾ï¼æå¨æºï¼æ¹è¿éï¼ |
| | | âââ mermaid/ # 14 å¼ Mermaid ä¸å¡å¾ï¼æå¨æºï¼æ¹è¿éï¼ |
| | | âââ data/ # ä¸å¡æ°æ®ï¼æå¨æºï¼æ¹è¿éï¼ |
| | | â âââ business.json # 项ç®å
ä¿¡æ¯/ä¸å¡åé®/AIè½å/å¾
确认äºé¡¹ |
| | | â âââ modules.json # 12 个ä¸å¡æ¨¡åå®ä¹ |
| | | â âââ modules.json # 16 个ä¸å¡æ¨¡åå®ä¹ |
| | | â âââ objects.json # æ ¸å¿ä¸å¡å¯¹è±¡ï¼ä½ç¨/䏿¸¸/䏿¸¸/表åï¼ |
| | | â âââ flows.json # 7 æ¡æµç¨ï¼æè¦+æ¥éª¤+è§è²ï¼ |
| | | â âââ flows.json # 9 æ¡æµç¨ï¼æè¦+æ¥éª¤+è§è²ï¼ |
| | | â âââ roles.json # è§è²æé |
| | | âââ README.md |
| | | ``` |
| | |
| | | | 09-data-flow | è·¨æ¨¡åæ°æ®æµï¼åæ®çæãåæ®µå¸¦å
¥ãæ°éååãäºä»¶ï¼ | |
| | | | 10-business-object | æ ¸å¿ä¸å¡å¯¹è±¡ ERï¼åªå«ä¸å¡å¯¹è±¡ï¼éå
¨åºè¡¨ï¼ | |
| | | | 11-ai-business-flow | AI ä¸å¡é¾è·¯ï¼OCR/è´¨æ£å¤å®/åç±»é¢æµ/RAGï¼å« API ä¾èµï¼ | |
| | | | 12-finance-flow | è´¢å¡æ¥éï¼ç¬ç«æ¨¡åï¼ï¼æ¥éå+æç»+å票éä»¶ â æäº¤ BPM å®¡æ¹ â éè¿/驳å â 彿¡£ç»æ | |
| | | | 13-ums-membership-flow | ä¼åå
¥ä¼ï¼ç¬ç«æ¨¡åï¼ï¼å
¥ä¼ç³è¯· + ææéä»¶ â æäº¤ BPM 两级审æ¹ï¼ç§ä¹¦å¤å审âçäºä¼å®¡è®®ï¼â éè¿èªå¨å»ºä¼åä¸ç»å½è´¦å· â ä¼åå表/éè®¯å½æ£ç´¢ | |
| | | | 14-research-flow | 课é¢ç®¡çï¼ç¬ç«æ¨¡åï¼ï¼æååå¸(éç¹/ä¸è¬)âå¨çº¿ç³æ¥(éä¼å带åºç³æ¥äºº)âä¸å®¶è¯åæç»å ææåâBPM ä¸çº§å®¡æ¹(ç§ä¹¦å¤å½¢å¼å®¡æ¥âä¸å®¶è¯å®¡âå¦ä¼ç«é¡¹å®¡æ¹)âç«é¡¹ç¼å·ä¸å
¬åâç»è´¹æ¨ä»è®°å½ | |
| | | |
| | | å¾ä¸ç¶ææ°åå为æºç æä¸¾çå®å¼ï¼å¦å·¥å 0è稿/1已确认/2宿/3åæ¶ï¼ERP å®¡æ¹ 15审æ¹ä¸/20å·²å®¡æ ¸ï¼ã |
| | | |
| | |
| | | - æ¬ç®å½ç±é¡¹ç®æè½ **project-business-analysis** 管çï¼`.claude/skills/project-business-analysis/`ï¼ï¼å¹¶æè§å `.claude/rules/business-visualization-maintenance.md` 强å¶ï¼ä¸å¡æ¨¡å/æµç¨/ç¶æ/对象/è§è²/AI åæ´åéåæ¥ç»´æ¤æ¬ç®å½ã |
| | | - å¢éç»´æ¤ï¼æ¹å¯¹åºç `mermaid/*.mmd` + `data/*.json` â è¿è¡ä¸é¢ç sync èæ¬ â æµè§å¨éªè¯åå½±åå¾ã |
| | | - å
¨ééåï¼åå·®è¿å¤§æ¶ï¼ï¼å¯¹ Claude 说ãéæ°çæä¸å¡å
¨æ¯ãï¼æè½ä¼éæ°èµ°è¯»æºç å¹¶æçææ¨¡å¼é建ã |
| | | - çæåºçº¿ï¼dev_business @ 87bf4a99ï¼2026-09-10ã |
| | | - çæåºçº¿ï¼dev_business @ 87bf4a99ï¼2026-09-10ï¼2026-09-28 å¢éè¡¥å
è´¢å¡æ¥é模åï¼`yudao-module-finance`ï¼ãä¼åç®¡çæ¨¡åï¼`yudao-module-ums`ï¼ä¸è¯¾é¢ç®¡ç模åï¼`yudao-module-research`ï¼ä¸æé¡¹ 1~5ï¼äºæç»é¡¹éªæ¶ä¸ææå½æ¡£å°æªåï¼å¾ä¸å·²æ 注æªè¦çèå´ï¼ã |
| | | |
| | | ## 7. å·²ç¥å¾
确认ä¸å¡ |
| | | |
| | | è§ `data/business.json` ç `pendingConfirm`ï¼é¡µé¢ãå¾
确认äºé¡¹ãæ ï¼ï¼è¦ç¹ï¼ä»åºç±»å/åæ ¼ä»æ¹é æªè½å°ãHRM äº¤æ¥ expandUserIds å°æªè¢«ä¸å¡æ¥è¯¢æ¥å
¥ã忬¾ä¸æ¶æ¬¾åæªèµ° BPMãè´¢å¡å¾ç¨½ååæ¹æ³ä¸ºç©ºãNCR å¤ç½®ä¸ååæºåçã |
| | | è§ `data/business.json` ç `pendingConfirm`ï¼é¡µé¢ãå¾
确认äºé¡¹ãæ ï¼ï¼è¦ç¹ï¼ä»åºç±»å/åæ ¼ä»æ¹é æªè½å°ãHRM äº¤æ¥ expandUserIds å°æªè¢«ä¸å¡æ¥è¯¢æ¥å
¥ã忬¾ä¸æ¶æ¬¾åæªèµ° BPMãè´¢å¡å¾ç¨½ååæ¹æ³ä¸ºç©ºãNCR å¤ç½®ä¸ååæºåãè´¢å¡æ¥éç BPM æµç¨å®ä¹æªåå¸ä¸æ®éè§è²æªæèåãä¼å管çç BPM æµç¨æªåå¸ä¸ç¼ºå®¡æ¹èªå®ä¹è¡¨å页ãèªå¨å»ºè´¦å·ç¨ææºå·ä½åå§å¯ç åå¨å¼±å£ä»¤é£é©ã课é¢ç®¡ççè¯åæéä¸éè¿éå¼ä¸ºå ä½è§åå¾
å¦ä¼ç¡®è®¤ã䏿ç»è´¹æ¨ä»ä¸è´¢å¡æ¨¡åæ æ°æ®åæ¥ãç³æ¥åä¸ä¼å为软å
³èå¯è½æ¬ç©ºçã |
| | |
| | | "subSystems": [ |
| | | "MESï¼ç产·ä»å¨Â·è´¨é·设å¤ï¼", |
| | | "ERPï¼è¿éå·财å¡ï¼", |
| | | "FINï¼å票æ¥éï¼ç¬ç«æ¨¡åï¼", |
| | | "UMSï¼å¦ä¼ä¼åï¼ç¬ç«æ¨¡åï¼", |
| | | "RESï¼ç§ç 课é¢ï¼ç¬ç«æ¨¡åï¼", |
| | | "CRMï¼å®¢æ·å
³ç³»ï¼", |
| | | "SRMï¼ä¾åºåå
³ç³»ï¼", |
| | | "HRMï¼äººåèµæºï¼", |
| | |
| | | "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 |
| | | }, |
| | |
| | | "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" |
| | | } |
| | |
| | | {"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": [ |
| | |
| | | "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": "订åå°è½¦é´æ§è¡çéå±æè§£ä¸è¿ç¨å¯æ§", |
| | |
| | | "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": ["åè°æ´æ°åä¸å¡åæ®ç¶æ"], |
| | |
| | | "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 å¦ä¼ä¼åæ å
³ï¼å¿æ··ç¨)"] |
| | | } |
| | | } |
| | |
| | | {"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": "ç»è´¹æ¨ä» æ¨æ¬¾ æ¨ä»è®°å½ æ¹æ¬¡ æ¨ä»éé¢ åè¯ å¾
æ¨ä» å·²æ¨ä» æ¶æ¬¾åä½ èµå©éé¢ é¢ç® è¶
é¢"} |
| | | ] |
| | | } |
| | |
| | | {"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 å
é
ç½®(é»è®¤ä¾æ¬¡å®¡æ¹Â·è§è²å
åº)ï¼å端ä¸åæ»å®¡æ¹äººï¼é¨ç½²åç±ç®¡çå卿µç¨è®¾è®¡å¨æå¦ä¼å®é
ç»ç»è°æ´"} |
| | | ] |
| | | } |
| | |
| | | --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%} |
| | |
| | | <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> |
| | |
| | | <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> |
| | |
| | | "subSystems": [ |
| | | "MESï¼ç产·ä»å¨Â·è´¨é·设å¤ï¼", |
| | | "ERPï¼è¿éå·财å¡ï¼", |
| | | "FINï¼å票æ¥éï¼ç¬ç«æ¨¡åï¼", |
| | | "UMSï¼å¦ä¼ä¼åï¼ç¬ç«æ¨¡åï¼", |
| | | "RESï¼ç§ç 课é¢ï¼ç¬ç«æ¨¡åï¼", |
| | | "CRMï¼å®¢æ·å
³ç³»ï¼", |
| | | "SRMï¼ä¾åºåå
³ç³»ï¼", |
| | | "HRMï¼äººåèµæºï¼", |
| | |
| | | "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 |
| | | }, |
| | |
| | | "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": [ |
| | |
| | | "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": "订åå°è½¦é´æ§è¡çéå±æè§£ä¸è¿ç¨å¯æ§", |
| | |
| | | "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": ["åè°æ´æ°åä¸å¡åæ®ç¶æ"], |
| | |
| | | "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">{ |
| | |
| | | {"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">{ |
| | |
| | | {"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": [ |
| | |
| | | {"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"> |
| | |
| | | 仿¬¾å |
| | | æ¶æ¬¾å |
| | | ç»ç®è´¦æ· |
| | | è´¢å¡æ¥é FIN ç¬ç« |
| | | æ¥éå主表 |
| | | æ¥éæç»è¡ |
| | | å票éä»¶ä¸ä¼ |
| | | æäº¤å®¡æ¹ä¸é©³åéæ |
| | | 彿¡£ç»æ |
| | | ä¼å管ç UMS ç¬ç« |
| | | å
¥ä¼ç³è¯·å |
| | | 个人ä¸åä½äºååæ®µ |
| | | ä¼åç级个人ä¸åä½ä¸¤å¥ |
| | | ç§ä¹¦å¤çäºä¼ä¸¤çº§å®¡æ¹ |
| | | 审æ¹éè¿èªå¨å»ºä¼å |
| | | èªå¨å建系ç»ç»å½è´¦å· |
| | | ä¼åå表ä¸éè®¯å½æ£ç´¢ |
| | | 课é¢ç®¡ç RES ç¬ç« |
| | | è¯¾é¢æååå¸ |
| | | éç¹ä¸ä¸è¬è¯¾é¢åç±» |
| | | æå¯¼ç³æ¥æä¸æªæ¢ |
| | | å¨çº¿è¯¾é¢ç³æ¥ä¹¦ |
| | | ä»ä¼å带åºç³æ¥äººä¿¡æ¯ |
| | | ä¸å®¶è¯å®¡æç»ä¸å ææå |
| | | ç§ä¹¦å¤çäºä¼ä¸çº§å®¡æ¹ |
| | | ç«é¡¹ç¼å·ä¸ç«é¡¹éç¥å
Œ |
| | | ç»è´¹æ¨ä»è®°å½ä¸åè¯ |
| | | ç产管ç MES |
| | | 主ç产计å MPS |
| | | ç产工å |
| | |
| | | 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 |
| | |
| | | MES -->|éè´§è´¨æ£å
¥åºåè°| AS[å®åå·¥åç»´ä¿®éè´§] |
| | | CRM -->|客æ·ä¸»æ°æ®| AS |
| | | HRM[HRM åå·¥å
¥è½¬è°ç¦»äº¤æ¥èå¤èªé
¬] -.->|expandUserIds æ°æ®å¯è§æ§æ©å±Â·æ¥å£å·²å°±ç»ªå¾
忍¡åæ¥å
¥| CRM |
| | | BPM[BPM Flowable 审æ¹å¼æ] -.->|ç¶æäºä»¶åè°Â·13个çå¬å¨| ERP |
| | | BPM[BPM Flowable 审æ¹å¼æ] -.->|ç¶æäºä»¶åè°Â·14个çå¬å¨| ERP |
| | | BPM -.-> CRM |
| | | BPM -.-> SRM |
| | | BPM -.-> MES |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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 = {}; |
| | |
| | | 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'); |
| | |
| | | </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> |
| | |
| | | 仿¬¾å |
| | | æ¶æ¬¾å |
| | | ç»ç®è´¦æ· |
| | | è´¢å¡æ¥é FIN ç¬ç« |
| | | æ¥éå主表 |
| | | æ¥éæç»è¡ |
| | | å票éä»¶ä¸ä¼ |
| | | æäº¤å®¡æ¹ä¸é©³åéæ |
| | | 彿¡£ç»æ |
| | | ä¼å管ç UMS ç¬ç« |
| | | å
¥ä¼ç³è¯·å |
| | | 个人ä¸åä½äºååæ®µ |
| | | ä¼åç级个人ä¸åä½ä¸¤å¥ |
| | | ç§ä¹¦å¤çäºä¼ä¸¤çº§å®¡æ¹ |
| | | 审æ¹éè¿èªå¨å»ºä¼å |
| | | èªå¨å建系ç»ç»å½è´¦å· |
| | | ä¼åå表ä¸éè®¯å½æ£ç´¢ |
| | | 课é¢ç®¡ç RES ç¬ç« |
| | | è¯¾é¢æååå¸ |
| | | éç¹ä¸ä¸è¬è¯¾é¢åç±» |
| | | æå¯¼ç³æ¥æä¸æªæ¢ |
| | | å¨çº¿è¯¾é¢ç³æ¥ä¹¦ |
| | | ä»ä¼å带åºç³æ¥äººä¿¡æ¯ |
| | | ä¸å®¶è¯å®¡æç»ä¸å ææå |
| | | ç§ä¹¦å¤çäºä¼ä¸çº§å®¡æ¹ |
| | | ç«é¡¹ç¼å·ä¸ç«é¡¹éç¥å
Œ |
| | | ç»è´¹æ¨ä»è®°å½ä¸åè¯ |
| | | ç产管ç MES |
| | | 主ç产计å MPS |
| | | ç产工å |
| | |
| | | MES -->|éè´§è´¨æ£å
¥åºåè°| AS[å®åå·¥åç»´ä¿®éè´§] |
| | | CRM -->|客æ·ä¸»æ°æ®| AS |
| | | HRM[HRM åå·¥å
¥è½¬è°ç¦»äº¤æ¥èå¤èªé
¬] -.->|expandUserIds æ°æ®å¯è§æ§æ©å±Â·æ¥å£å·²å°±ç»ªå¾
忍¡åæ¥å
¥| CRM |
| | | BPM[BPM Flowable 审æ¹å¼æ] -.->|ç¶æäºä»¶åè°Â·13个çå¬å¨| ERP |
| | | BPM[BPM Flowable 审æ¹å¼æ] -.->|ç¶æäºä»¶åè°Â·14个çå¬å¨| ERP |
| | | BPM -.-> CRM |
| | | BPM -.-> SRM |
| | | BPM -.-> MES |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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 : "ç³æ¥äºº(软å
³èæ å¤é®)" |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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 |
| | |
| | | <module>yudao-module-bi</module> |
| | | <!-- æºè½è´¨æ£æ¥åè®¾è®¡å¹³å°æ¨¡å --> |
| | | <module>yudao-module-qcreport</module> |
| | | <!-- è´¢å¡ç®¡ç模å --> |
| | | <module>yudao-module-finance</module> |
| | | <!-- ä¼åç®¡çæ¨¡å --> |
| | | <module>yudao-module-ums</module> |
| | | <!-- 课é¢ç®¡ç模å --> |
| | | <module>yudao-module-research</module> |
| | | </modules> |
| | | |
| | | <name>${project.artifactId}</name> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <project xmlns="http://maven.apache.org/POM/4.0.0" |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao</artifactId> |
| | | <version>${revision}</version> |
| | | </parent> |
| | | <modelVersion>4.0.0</modelVersion> |
| | | <artifactId>yudao-module-finance</artifactId> |
| | | <packaging>jar</packaging> |
| | | |
| | | <name>${project.artifactId}</name> |
| | | <description> |
| | | finance å
ä¸ï¼è´¢å¡ç®¡ç模åï¼å票æ¥éï¼ã |
| | | </description> |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-system</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- BPM 工使µ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-bpm</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- Web ç¸å
³ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-web</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-security</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- DB ç¸å
³ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-mybatis</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-redis</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- å·¥å
·ç±»ç¸å
³ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-excel</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- Test æµè¯ç¸å
³ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-test</artifactId> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | </project> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.controller.admin.reimbursement; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| | | import cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo.FinanceReimbursementPageReqVO; |
| | | import cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo.FinanceReimbursementRespVO; |
| | | import cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo.FinanceReimbursementSaveReqVO; |
| | | import cn.iocoder.yudao.module.finance.dal.dataobject.reimbursement.FinanceReimbursementDO; |
| | | import cn.iocoder.yudao.module.finance.dal.dataobject.reimbursement.FinanceReimbursementItemDO; |
| | | import cn.iocoder.yudao.module.finance.service.reimbursement.FinanceReimbursementService; |
| | | import cn.iocoder.yudao.module.finance.service.reimbursement.FinanceReimbursementServiceImpl; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.annotation.Resource; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import jakarta.validation.Valid; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; |
| | | |
| | | @Tag(name = "管çåå° - è´¢å¡æ¥éå") |
| | | @RestController |
| | | @RequestMapping("/finance/reimbursement") |
| | | @Validated |
| | | public class FinanceReimbursementController { |
| | | |
| | | public static final String REIMBURSEMENT_RECORD_TYPE = |
| | | FinanceReimbursementServiceImpl.REIMBURSEMENT_RECORD_TYPE; |
| | | |
| | | @Resource |
| | | private FinanceReimbursementService reimbursementService; |
| | | |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @PostMapping("/create") |
| | | @Operation(summary = "å建æ¥éå") |
| | | @PreAuthorize("@ss.hasPermission('finance:reimbursement:create')") |
| | | public CommonResult<Long> createReimbursement(@Valid @RequestBody FinanceReimbursementSaveReqVO createReqVO) { |
| | | return success(reimbursementService.createReimbursement(createReqVO)); |
| | | } |
| | | |
| | | @PutMapping("/update") |
| | | @Operation(summary = "æ´æ°æ¥éå") |
| | | @PreAuthorize("@ss.hasPermission('finance:reimbursement:update')") |
| | | public CommonResult<Boolean> updateReimbursement(@Valid @RequestBody FinanceReimbursementSaveReqVO updateReqVO) { |
| | | reimbursementService.updateReimbursement(updateReqVO); |
| | | return success(true); |
| | | } |
| | | |
| | | @DeleteMapping("/delete") |
| | | @Operation(summary = "å 餿¥éå") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('finance:reimbursement:delete')") |
| | | public CommonResult<Boolean> deleteReimbursement(@RequestParam("id") Long id) { |
| | | reimbursementService.deleteReimbursement(id); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/get") |
| | | @Operation(summary = "è·å¾æ¥éå") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true, example = "1024") |
| | | @PreAuthorize("@ss.hasPermission('finance:reimbursement:query')") |
| | | public CommonResult<FinanceReimbursementRespVO> getReimbursement(@RequestParam("id") Long id) { |
| | | FinanceReimbursementDO reimbursement = reimbursementService.getReimbursement(id); |
| | | return success(buildReimbursementDetail(reimbursement)); |
| | | } |
| | | |
| | | @GetMapping("/page") |
| | | @Operation(summary = "è·å¾æ¥éåå页") |
| | | @PreAuthorize("@ss.hasPermission('finance:reimbursement:query')") |
| | | public CommonResult<PageResult<FinanceReimbursementRespVO>> getReimbursementPage( |
| | | @Valid FinanceReimbursementPageReqVO pageReqVO) { |
| | | PageResult<FinanceReimbursementDO> pageResult = reimbursementService.getReimbursementPage(pageReqVO); |
| | | return success(new PageResult<>(buildReimbursementDetailList(pageResult.getList()), pageResult.getTotal())); |
| | | } |
| | | |
| | | @GetMapping("/export-excel") |
| | | @Operation(summary = "å¯¼åºæ¥éå Excel") |
| | | @PreAuthorize("@ss.hasPermission('finance:reimbursement:export')") |
| | | @ApiAccessLog(operateType = EXPORT) |
| | | public void exportReimbursementExcel(@Valid FinanceReimbursementPageReqVO pageReqVO, |
| | | HttpServletResponse response) throws IOException { |
| | | pageReqVO.setPageSize(PAGE_SIZE_NONE); |
| | | List<FinanceReimbursementDO> list = reimbursementService.getReimbursementPage(pageReqVO).getList(); |
| | | ExcelUtils.write(response, "æ¥éå.xls", "æ°æ®", FinanceReimbursementRespVO.class, |
| | | buildReimbursementDetailList(list)); |
| | | } |
| | | |
| | | @PostMapping("/submit") |
| | | @Operation(summary = "æäº¤æ¥éå审æ¹") |
| | | @PreAuthorize("@ss.hasPermission('finance:reimbursement:update-status')") |
| | | public CommonResult<Boolean> submitReimbursement(@RequestParam("id") Long id, |
| | | @RequestParam("processDefinitionKey") String processDefinitionKey) { |
| | | reimbursementService.submitReimbursement(id, processDefinitionKey, getLoginUserId()); |
| | | return success(true); |
| | | } |
| | | |
| | | @PostMapping("/archive") |
| | | @Operation(summary = "彿¡£æ¥éå") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('finance:reimbursement:archive')") |
| | | public CommonResult<Boolean> archiveReimbursement(@RequestParam("id") Long id) { |
| | | reimbursementService.archiveReimbursement(id); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/approve-process-list") |
| | | @Operation(summary = "è·åæ¥éåå®¡æ¹æµç¨å表") |
| | | @PreAuthorize("@ss.hasPermission('finance:reimbursement:query')") |
| | | public CommonResult<List<Map<String, Object>>> getReimbursementApproveProcessDefinitionList() { |
| | | return success(reimbursementService.getReimbursementApproveProcessDefinitionList()); |
| | | } |
| | | |
| | | // ==================== å
鍿¹æ³ ==================== |
| | | |
| | | private FinanceReimbursementRespVO buildReimbursementDetail(FinanceReimbursementDO reimbursement) { |
| | | if (reimbursement == null) { |
| | | return null; |
| | | } |
| | | return buildReimbursementDetailList(Collections.singletonList(reimbursement)).get(0); |
| | | } |
| | | |
| | | private List<FinanceReimbursementRespVO> buildReimbursementDetailList(List<FinanceReimbursementDO> list) { |
| | | if (CollUtil.isEmpty(list)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | // 1.1 è·åç³è¯·äºº |
| | | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( |
| | | convertSet(list, FinanceReimbursementDO::getApplicantId)); |
| | | // 1.2 è·åå建人 |
| | | Map<Long, AdminUserRespDTO> creatorMap = adminUserApi.getUserMap( |
| | | convertSet(list, invoice -> NumberUtils.parseLong(invoice.getCreator()))); |
| | | // 1.3 è·åæç» |
| | | Map<Long, List<FinanceReimbursementItemDO>> itemMap = list.stream() |
| | | .collect(Collectors.toMap( |
| | | FinanceReimbursementDO::getId, |
| | | r -> reimbursementService.getReimbursementItemListByReimbursementId(r.getId()))); |
| | | // 1.4 è·åéä»¶ |
| | | Map<Long, List<cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO>> attachmentMap = list.stream() |
| | | .collect(Collectors.toMap( |
| | | FinanceReimbursementDO::getId, |
| | | r -> storageAttachmentApi.listAttachments(REIMBURSEMENT_RECORD_TYPE, r.getId()))); |
| | | |
| | | // 2. æ¼æ¥ç»æ |
| | | return BeanUtils.toBean(list, FinanceReimbursementRespVO.class, (vo) -> { |
| | | // 2.1 ç³è¯·äººå§å |
| | | findAndThen(userMap, vo.getApplicantId(), user -> vo.setApplicantName(user.getNickname())); |
| | | // 2.2 å建人åç§° |
| | | findAndThen(creatorMap, NumberUtils.parseLong(vo.getCreator()), |
| | | user -> vo.setCreatorName(user.getNickname())); |
| | | // 2.3 æç»å表 |
| | | vo.setItems(BeanUtils.toBean(itemMap.getOrDefault(vo.getId(), Collections.emptyList()), |
| | | cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo.item.FinanceReimbursementItemRespVO.class)); |
| | | // 2.4 éä»¶å表 |
| | | vo.setAttachmentList(attachmentMap.getOrDefault(vo.getId(), Collections.emptyList())); |
| | | vo.setHasAttachment(CollUtil.isNotEmpty(vo.getAttachmentList())); |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * è·åå½åç»å½ç¨æ·ID |
| | | */ |
| | | private static Long getLoginUserId() { |
| | | return cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId(); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | import lombok.ToString; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.time.LocalDate; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; |
| | | |
| | | @Schema(description = "管çåå° - æ¥éåå页 Request VO") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | public class FinanceReimbursementPageReqVO extends PageParam { |
| | | |
| | | @Schema(description = "æ¥éåå·", example = "BX20260928000001") |
| | | private String no; |
| | | |
| | | @Schema(description = "æ¥éæ é¢", example = "9æå·®æ
æ¥é") |
| | | private String title; |
| | | |
| | | @Schema(description = "ç¶æ", example = "0") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "ç³è¯·äººID", example = "1") |
| | | private Long applicantId; |
| | | |
| | | @Schema(description = "ç³è¯·æ¥æ") |
| | | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) |
| | | private LocalDate[] applyDate; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo; |
| | | |
| | | import cn.idev.excel.annotation.ExcelIgnoreUnannotated; |
| | | import cn.idev.excel.annotation.ExcelProperty; |
| | | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| | | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| | | import cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo.item.FinanceReimbursementItemRespVO; |
| | | import cn.iocoder.yudao.module.finance.enums.DictTypeConstants; |
| | | import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - æ¥éå Response VO") |
| | | @Data |
| | | @ExcelIgnoreUnannotated |
| | | public class FinanceReimbursementRespVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "æ¥éåå·", example = "BX20260928000001") |
| | | @ExcelProperty("æ¥éåå·") |
| | | private String no; |
| | | |
| | | @Schema(description = "æ¥éæ é¢", example = "9æå·®æ
æ¥é") |
| | | @ExcelProperty("æ¥éæ é¢") |
| | | private String title; |
| | | |
| | | @Schema(description = "æ¥éæ»éé¢", example = "1000.00") |
| | | @ExcelProperty("æ¥éæ»éé¢") |
| | | private BigDecimal totalAmount; |
| | | |
| | | @Schema(description = "ç¶æ", example = "0") |
| | | @ExcelProperty(value = "ç¶æ", converter = DictConvert.class) |
| | | @DictFormat(DictTypeConstants.REIMBURSEMENT_STATUS) |
| | | private Integer status; |
| | | |
| | | @Schema(description = "ç³è¯·äººID", example = "1") |
| | | private Long applicantId; |
| | | |
| | | @Schema(description = "ç³è¯·äººå§å", example = "å¼ ä¸") |
| | | @ExcelProperty("ç³è¯·äºº") |
| | | private String applicantName; |
| | | |
| | | @Schema(description = "ç³è¯·æ¥æ") |
| | | @ExcelProperty("ç³è¯·æ¥æ") |
| | | private LocalDate applyDate; |
| | | |
| | | @Schema(description = "BPMæµç¨å®ä¾ID") |
| | | private String processInstanceId; |
| | | |
| | | @Schema(description = "彿¡£æ¶é´") |
| | | @ExcelProperty("彿¡£æ¶é´") |
| | | private LocalDateTime archiveTime; |
| | | |
| | | @Schema(description = "夿³¨", example = "åºå·®å京") |
| | | @ExcelProperty("夿³¨") |
| | | private String remark; |
| | | |
| | | @Schema(description = "å建æ¶é´") |
| | | @ExcelProperty("å建æ¶é´") |
| | | private LocalDateTime createTime; |
| | | |
| | | @Schema(description = "æ´æ°æ¶é´") |
| | | private LocalDateTime updateTime; |
| | | |
| | | @Schema(description = "å建人åç§°") |
| | | private String creatorName; |
| | | |
| | | @Schema(description = "å建è
") |
| | | private String creator; |
| | | |
| | | /** æ¥éæç»å表 */ |
| | | @Schema(description = "æ¥éæç»å表") |
| | | private List<FinanceReimbursementItemRespVO> items; |
| | | |
| | | /** å票éä»¶å表 */ |
| | | @Schema(description = "å票éä»¶å表") |
| | | private List<StorageBlobRespDTO> attachmentList; |
| | | |
| | | /** æ¯å¦æéä»¶ */ |
| | | @Schema(description = "æ¯å¦æéä»¶") |
| | | @ExcelProperty("æ¯å¦ä¸ä¼ å票") |
| | | private Boolean hasAttachment; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo; |
| | | |
| | | import cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo.item.FinanceReimbursementItemSaveReqVO; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotEmpty; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import jakarta.validation.constraints.Size; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - æ¥éåæ°å¢/ä¿®æ¹ Request VO") |
| | | @Data |
| | | public class FinanceReimbursementSaveReqVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "æ¥éåå·ãç空ï¼å«åªå¡«ç©ºæ ¼ï¼åç±ç³»ç»æ BX+æ¥æ+6使µæ°´èªå¨çæï¼" |
| | | + "ä¿®æ¹æ¶ä¸ä¼ æçç©ºè¡¨ç¤ºä¿æååå·ä¸å", example = "BX20260928000001") |
| | | @Size(max = 36, message = "æ¥éåå·é¿åº¦ä¸è½è¶
è¿ 36 个å符") |
| | | private String no; |
| | | |
| | | @Schema(description = "æ¥éæ é¢", requiredMode = Schema.RequiredMode.REQUIRED, example = "9æå·®æ
æ¥é") |
| | | @NotEmpty(message = "æ¥éæ é¢ä¸è½ä¸ºç©º") |
| | | private String title; |
| | | |
| | | @Schema(description = "æ¥éæ»éé¢", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000.00") |
| | | @NotNull(message = "æ¥éæ»éé¢ä¸è½ä¸ºç©º") |
| | | private BigDecimal totalAmount; |
| | | |
| | | @Schema(description = "ç³è¯·æ¥æ", requiredMode = Schema.RequiredMode.REQUIRED) |
| | | @NotNull(message = "ç³è¯·æ¥æä¸è½ä¸ºç©º") |
| | | private LocalDate applyDate; |
| | | |
| | | @Schema(description = "夿³¨", example = "åºå·®å京") |
| | | private String remark; |
| | | |
| | | @Schema(description = "å票éä»¶BlobIdå表") |
| | | private List<Long> blobIds; |
| | | |
| | | @Schema(description = "æ¥éæç»å表") |
| | | @NotEmpty(message = "æ¥éæç»ä¸è½ä¸ºç©º") |
| | | private List<FinanceReimbursementItemSaveReqVO> items; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo.item; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | |
| | | @Schema(description = "管çåå° - æ¥éæç» Response VO") |
| | | @Data |
| | | public class FinanceReimbursementItemRespVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "æ¥éåID", example = "1") |
| | | private Long reimbursementId; |
| | | |
| | | @Schema(description = "è´¹ç¨ç±»å", example = "1") |
| | | private Integer expenseType; |
| | | |
| | | @Schema(description = "å票å·ç ", example = "12345678") |
| | | private String invoiceNo; |
| | | |
| | | @Schema(description = "å票éé¢", example = "500.00") |
| | | private BigDecimal invoiceAmount; |
| | | |
| | | @Schema(description = "åç¥¨æ¥æ") |
| | | private LocalDate invoiceDate; |
| | | |
| | | @Schema(description = "å¼ç¥¨æ¹", example = "XXå
¬å¸") |
| | | private String drawer; |
| | | |
| | | @Schema(description = "è´¹ç¨è¯´æ", example = "åºå·®ç«è½¦ç¥¨") |
| | | private String description; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo.item; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | |
| | | @Schema(description = "管çåå° - æ¥éæç»æ°å¢/ä¿®æ¹ Request VO") |
| | | @Data |
| | | public class FinanceReimbursementItemSaveReqVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "è´¹ç¨ç±»å", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "è´¹ç¨ç±»åä¸è½ä¸ºç©º") |
| | | private Integer expenseType; |
| | | |
| | | @Schema(description = "å票å·ç ", example = "12345678") |
| | | private String invoiceNo; |
| | | |
| | | @Schema(description = "å票éé¢", requiredMode = Schema.RequiredMode.REQUIRED, example = "500.00") |
| | | @NotNull(message = "å票éé¢ä¸è½ä¸ºç©º") |
| | | private BigDecimal invoiceAmount; |
| | | |
| | | @Schema(description = "åç¥¨æ¥æ") |
| | | private LocalDate invoiceDate; |
| | | |
| | | @Schema(description = "å¼ç¥¨æ¹", example = "XXå
¬å¸") |
| | | private String drawer; |
| | | |
| | | @Schema(description = "è´¹ç¨è¯´æ", example = "åºå·®ç«è½¦ç¥¨") |
| | | private String description; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.dal.dataobject.reimbursement; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import lombok.*; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * è´¢å¡-æ¥éå DO |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @TableName("finance_reimbursement") |
| | | @KeySequence("finance_reimbursement_seq") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class FinanceReimbursementDO extends BaseDO { |
| | | |
| | | @TableId |
| | | private Long id; |
| | | |
| | | /** æ¥éåå· */ |
| | | private String no; |
| | | |
| | | /** æ¥éæ é¢ */ |
| | | private String title; |
| | | |
| | | /** æ¥éæ»éé¢ */ |
| | | private BigDecimal totalAmount; |
| | | |
| | | /** ç¶æï¼0-è稿 15-审æ¹ä¸ 20-å·²éè¿ 35-已驳å 40-已彿¡£ */ |
| | | private Integer status; |
| | | |
| | | /** ç³è¯·äººID */ |
| | | private Long applicantId; |
| | | |
| | | /** ç³è¯·æ¥æ */ |
| | | private LocalDate applyDate; |
| | | |
| | | /** BPMæµç¨å®ä¾ID */ |
| | | private String processInstanceId; |
| | | |
| | | /** 彿¡£æ¶é´ */ |
| | | private LocalDateTime archiveTime; |
| | | |
| | | /** 夿³¨ */ |
| | | private String remark; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.dal.dataobject.reimbursement; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import lombok.*; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | |
| | | /** |
| | | * è´¢å¡-æ¥éæç» DO |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @TableName("finance_reimbursement_item") |
| | | @KeySequence("finance_reimbursement_item_seq") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class FinanceReimbursementItemDO extends BaseDO { |
| | | |
| | | @TableId |
| | | private Long id; |
| | | |
| | | /** æ¥éåID */ |
| | | private Long reimbursementId; |
| | | |
| | | /** è´¹ç¨ç±»åï¼1-å·®æ
2-åå
¬ 3-æå¾
4-交é 5-å
¶ä» */ |
| | | private Integer expenseType; |
| | | |
| | | /** å票å·ç */ |
| | | private String invoiceNo; |
| | | |
| | | /** å票éé¢ */ |
| | | private BigDecimal invoiceAmount; |
| | | |
| | | /** åç¥¨æ¥æ */ |
| | | private LocalDate invoiceDate; |
| | | |
| | | /** å¼ç¥¨æ¹ */ |
| | | private String drawer; |
| | | |
| | | /** è´¹ç¨è¯´æ */ |
| | | private String description; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.dal.mysql.reimbursement; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.finance.dal.dataobject.reimbursement.FinanceReimbursementItemDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | public interface FinanceReimbursementItemMapper extends BaseMapperX<FinanceReimbursementItemDO> { |
| | | |
| | | default List<FinanceReimbursementItemDO> selectListByReimbursementId(Long reimbursementId) { |
| | | return selectList(FinanceReimbursementItemDO::getReimbursementId, reimbursementId); |
| | | } |
| | | |
| | | default int deleteByReimbursementId(Long reimbursementId) { |
| | | return delete(FinanceReimbursementItemDO::getReimbursementId, reimbursementId); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.dal.mysql.reimbursement; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo.FinanceReimbursementPageReqVO; |
| | | import cn.iocoder.yudao.module.finance.dal.dataobject.reimbursement.FinanceReimbursementDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | @Mapper |
| | | public interface FinanceReimbursementMapper extends BaseMapperX<FinanceReimbursementDO> { |
| | | |
| | | default FinanceReimbursementDO selectByNo(String no) { |
| | | return selectOne(FinanceReimbursementDO::getNo, no); |
| | | } |
| | | |
| | | default PageResult<FinanceReimbursementDO> selectPage(FinanceReimbursementPageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<FinanceReimbursementDO>() |
| | | .likeIfPresent(FinanceReimbursementDO::getNo, reqVO.getNo()) |
| | | .likeIfPresent(FinanceReimbursementDO::getTitle, reqVO.getTitle()) |
| | | .eqIfPresent(FinanceReimbursementDO::getStatus, reqVO.getStatus()) |
| | | .eqIfPresent(FinanceReimbursementDO::getApplicantId, reqVO.getApplicantId()) |
| | | .betweenIfPresent(FinanceReimbursementDO::getApplyDate, reqVO.getApplyDate()) |
| | | .orderByDesc(FinanceReimbursementDO::getId)); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.dal.redis; |
| | | |
| | | import cn.hutool.core.date.DatePattern; |
| | | import cn.hutool.core.date.DateUtil; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.data.redis.core.StringRedisTemplate; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | import java.time.Duration; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * Finance 订ååºå·ç Redis DAO |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Repository |
| | | public class FinanceNoRedisDAO { |
| | | |
| | | /** |
| | | * æ¥éå {@link cn.iocoder.yudao.module.finance.dal.dataobject.reimbursement.FinanceReimbursementDO} |
| | | */ |
| | | public static final String REIMBURSEMENT_NO_PREFIX = "BX"; |
| | | |
| | | @Resource |
| | | private StringRedisTemplate stringRedisTemplate; |
| | | |
| | | /** |
| | | * çæåºå·ï¼ä½¿ç¨å½åæ¥æï¼æ ¼å¼ä¸º {PREFIX} + yyyyMMdd + 6 ä½èªå¢ |
| | | * |
| | | * @param prefix åç¼ |
| | | * @return åºå· |
| | | */ |
| | | public String generate(String prefix) { |
| | | String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN); |
| | | String key = RedisKeyConstants.NO + noPrefix; |
| | | Long no = stringRedisTemplate.opsForValue().increment(key); |
| | | stringRedisTemplate.expire(key, Duration.ofDays(1L)); |
| | | return noPrefix + String.format("%06d", no); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.dal.redis; |
| | | |
| | | /** |
| | | * Finance Redis Key æä¸¾ç±» |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | public interface RedisKeyConstants { |
| | | |
| | | /** |
| | | * åºå·çç¼å |
| | | * |
| | | * KEY æ ¼å¼ï¼trade_no:{prefix} |
| | | * VALUE æ°æ®æ ¼å¼ï¼ç¼å·èªå¢ |
| | | */ |
| | | String NO = "finance:seq_no:"; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.enums; |
| | | |
| | | /** |
| | | * Finance åå
¸ç±»åçæä¸¾ç±» |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | public interface DictTypeConstants { |
| | | |
| | | String REIMBURSEMENT_STATUS = "finance_reimbursement_status"; // æ¥éç¶æ |
| | | String EXPENSE_TYPE = "finance_expense_type"; // è´¹ç¨ç±»å |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.enums; |
| | | |
| | | import cn.iocoder.yudao.framework.common.exception.ErrorCode; |
| | | |
| | | /** |
| | | * Finance éè¯¯ç æä¸¾ç±» |
| | | * <p> |
| | | * finance ç³»ç»ï¼ä½¿ç¨ 1-030-107-000 æ®µï¼æ¥å¨ ERP 1-030-106 ä¹åï¼ |
| | | */ |
| | | public interface ErrorCodeConstants { |
| | | |
| | | // ========== æ¥éåï¼1-030-107-000ï¼ ========== |
| | | ErrorCode REIMBURSEMENT_NOT_EXISTS = new ErrorCode(1_030_107_000, "æ¥éåä¸åå¨"); |
| | | ErrorCode REIMBURSEMENT_NO_EXISTS = new ErrorCode(1_030_107_001, "çææ¥éåå·å¤±è´¥ï¼è¯·éæ°æäº¤"); |
| | | ErrorCode REIMBURSEMENT_DELETE_FAIL_NOT_DRAFT = new ErrorCode(1_030_107_002, "æ¥éå({})䏿¯èç¨¿ç¶æï¼æ æ³å é¤"); |
| | | ErrorCode REIMBURSEMENT_UPDATE_FAIL_NOT_DRAFT = new ErrorCode(1_030_107_003, "æ¥éå({})䏿¯è稿æå·²é©³åç¶æï¼æ æ³ä¿®æ¹ï¼åªæè稿å已驳åçæ¥éåå¯ä»¥ç¼è¾"); |
| | | ErrorCode REIMBURSEMENT_SUBMIT_FAIL_STATUS = new ErrorCode(1_030_107_004, "æäº¤å®¡æ¹å¤±è´¥ï¼åªæè稿æå·²é©³åç¶æçæ¥éåæè½æäº¤"); |
| | | ErrorCode REIMBURSEMENT_SUBMIT_FAIL_ITEM_EMPTY = new ErrorCode(1_030_107_005, "æäº¤å®¡æ¹å¤±è´¥ï¼æ¥éåæ²¡ææç»è¡ï¼æ æ³æäº¤"); |
| | | ErrorCode REIMBURSEMENT_ARCHIVE_FAIL_STATUS = new ErrorCode(1_030_107_006, "彿¡£å¤±è´¥ï¼åªæå·²éè¿ç¶æçæ¥éåæè½å½æ¡£"); |
| | | ErrorCode REIMBURSEMENT_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_030_107_007, "æ´æ°å®¡æ¹ç¶æå¤±è´¥ï¼åªæå®¡æ¹ä¸çæ¥éåæè½æ´æ°"); |
| | | ErrorCode REIMBURSEMENT_BPM_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_107_008, "æ¥é审æ¹åç±»ä¸åå¨ï¼è¯·å
å¨BPM模åå建æ¥éå®¡æ¹æµç¨åç±»"); |
| | | ErrorCode REIMBURSEMENT_BPM_PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_030_107_009, "æ¥é审æ¹åç±»ä¸æ²¡æå¯ç¨çæµç¨æ¨¡åï¼è¯·å
å建并å叿µç¨"); |
| | | ErrorCode REIMBURSEMENT_CUSTOM_NO_EXISTS = new ErrorCode(1_030_107_010, "æ¥éåå·({})已被å
¶ä»æ¥éå使ç¨ï¼è¯·æ´æ¢å
¶ä»åå·ï¼ææ¸
ç©ºè¯¥åæ®µç±ç³»ç»èªå¨çæ"); |
| | | ErrorCode REIMBURSEMENT_CUSTOM_NO_INVALID = new ErrorCode(1_030_107_011, "æ¥éåå·({})ä¸é´ä¸è½å
å«ç©ºæ ¼ï¼è¯·å»æç©ºæ ¼åéæ°è¾å
¥ï¼ææ¸
ç©ºè¯¥åæ®µç±ç³»ç»èªå¨çæ"); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.enums; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * æ¥éåç¶ææä¸¾ |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum FinanceReimbursementStatusEnum { |
| | | |
| | | DRAFT(0, "è稿"), |
| | | APPROVING(15, "审æ¹ä¸"), |
| | | APPROVED(20, "å·²éè¿"), |
| | | REJECTED(35, "已驳å"), |
| | | ARCHIVED(40, "已彿¡£"); |
| | | |
| | | private final Integer status; |
| | | private final String name; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.framework.web.config; |
| | | |
| | | import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; |
| | | import org.springdoc.core.models.GroupedOpenApi; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | |
| | | @Configuration(proxyBeanMethods = false) |
| | | public class FinanceWebConfiguration { |
| | | |
| | | @Bean |
| | | public GroupedOpenApi financeGroupedOpenApi() { |
| | | return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("finance"); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.service.reimbursement; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo.FinanceReimbursementPageReqVO; |
| | | import cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo.FinanceReimbursementSaveReqVO; |
| | | import cn.iocoder.yudao.module.finance.dal.dataobject.reimbursement.FinanceReimbursementDO; |
| | | import cn.iocoder.yudao.module.finance.dal.dataobject.reimbursement.FinanceReimbursementItemDO; |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * æ¥éå Service æ¥å£ |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | public interface FinanceReimbursementService { |
| | | |
| | | Long createReimbursement(FinanceReimbursementSaveReqVO createReqVO); |
| | | |
| | | void updateReimbursement(FinanceReimbursementSaveReqVO updateReqVO); |
| | | |
| | | void deleteReimbursement(Long id); |
| | | |
| | | FinanceReimbursementDO getReimbursement(Long id); |
| | | |
| | | PageResult<FinanceReimbursementDO> getReimbursementPage(FinanceReimbursementPageReqVO pageReqVO); |
| | | |
| | | List<FinanceReimbursementItemDO> getReimbursementItemListByReimbursementId(Long reimbursementId); |
| | | |
| | | void submitReimbursement(Long id, String processDefinitionKey, Long userId); |
| | | |
| | | void archiveReimbursement(Long id); |
| | | |
| | | List<Map<String, Object>> getReimbursementApproveProcessDefinitionList(); |
| | | |
| | | void updateReimbursementAuditStatus(Long id, Integer bpmResult); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.service.reimbursement; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; |
| | | import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; |
| | | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; |
| | | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; |
| | | import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; |
| | | import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; |
| | | import cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo.FinanceReimbursementPageReqVO; |
| | | import cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo.FinanceReimbursementSaveReqVO; |
| | | import cn.iocoder.yudao.module.finance.controller.admin.reimbursement.vo.item.FinanceReimbursementItemSaveReqVO; |
| | | import cn.iocoder.yudao.module.finance.dal.dataobject.reimbursement.FinanceReimbursementDO; |
| | | import cn.iocoder.yudao.module.finance.dal.dataobject.reimbursement.FinanceReimbursementItemDO; |
| | | import cn.iocoder.yudao.module.finance.dal.mysql.reimbursement.FinanceReimbursementItemMapper; |
| | | import cn.iocoder.yudao.module.finance.dal.mysql.reimbursement.FinanceReimbursementMapper; |
| | | import cn.iocoder.yudao.module.finance.dal.redis.FinanceNoRedisDAO; |
| | | import cn.iocoder.yudao.module.finance.enums.FinanceReimbursementStatusEnum; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.flowable.engine.repository.ProcessDefinition; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| | | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| | | import static cn.iocoder.yudao.module.finance.enums.ErrorCodeConstants.*; |
| | | |
| | | /** |
| | | * æ¥éå Service å®ç°ç±» |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Service |
| | | @Validated |
| | | @Slf4j |
| | | public class FinanceReimbursementServiceImpl implements FinanceReimbursementService { |
| | | |
| | | /** |
| | | * BPM æ¥é审æ¹åç±»ç¼ç |
| | | */ |
| | | private static final String REIMBURSEMENT_APPROVE_CATEGORY_CODE = "finance_reimbursement_approve"; |
| | | |
| | | /** |
| | | * éä»¶å
³èçä¸å¡ç±»å |
| | | */ |
| | | public static final String REIMBURSEMENT_RECORD_TYPE = "finance_reimbursement"; |
| | | |
| | | @Resource |
| | | private FinanceReimbursementMapper reimbursementMapper; |
| | | @Resource |
| | | private FinanceReimbursementItemMapper reimbursementItemMapper; |
| | | |
| | | @Resource |
| | | private FinanceNoRedisDAO noRedisDAO; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @Resource |
| | | private BpmProcessInstanceApi processInstanceApi; |
| | | @Resource |
| | | private BpmCategoryService bpmCategoryService; |
| | | @Resource |
| | | private BpmProcessDefinitionService bpmProcessDefinitionService; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createReimbursement(FinanceReimbursementSaveReqVO createReqVO) { |
| | | // 1. æ¥éåå·ï¼å
è®¸ç¨æ·èªå®ä¹ï¼æªå¡«æ¶ç±ç³»ç»çæ |
| | | String no = resolveCreateNo(createReqVO.getNo()); |
| | | |
| | | // 2.1 æå
¥æ¥éå |
| | | FinanceReimbursementDO reimbursement = BeanUtils.toBean(createReqVO, FinanceReimbursementDO.class, in -> in |
| | | .setNo(no) |
| | | .setStatus(FinanceReimbursementStatusEnum.DRAFT.getStatus()) |
| | | .setApplicantId(getLoginUserId()) |
| | | .setApplyDate(createReqVO.getApplyDate() != null ? createReqVO.getApplyDate() : LocalDate.now())); |
| | | reimbursementMapper.insert(reimbursement); |
| | | |
| | | // 2.2 æå
¥æ¥éæç» |
| | | List<FinanceReimbursementItemDO> items = buildItems(reimbursement.getId(), createReqVO.getItems()); |
| | | if (CollUtil.isNotEmpty(items)) { |
| | | reimbursementItemMapper.insertBatch(items); |
| | | } |
| | | |
| | | // 2.3 ç»å®å票éä»¶ |
| | | storageAttachmentApi.bindAttachments("file", REIMBURSEMENT_RECORD_TYPE, |
| | | reimbursement.getId(), createReqVO.getBlobIds()); |
| | | |
| | | return reimbursement.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateReimbursement(FinanceReimbursementSaveReqVO updateReqVO) { |
| | | // 1.1 æ ¡éªåå¨ |
| | | FinanceReimbursementDO reimbursement = validateReimbursementExists(updateReqVO.getId()); |
| | | // 1.2 åªæè稿ã已驳åç¶ææè½ä¿®æ¹ |
| | | Integer status = reimbursement.getStatus(); |
| | | if (!FinanceReimbursementStatusEnum.DRAFT.getStatus().equals(status) |
| | | && !FinanceReimbursementStatusEnum.REJECTED.getStatus().equals(status)) { |
| | | throw exception(REIMBURSEMENT_UPDATE_FAIL_NOT_DRAFT, reimbursement.getNo()); |
| | | } |
| | | |
| | | // 2.1 æ´æ°æ¥éå |
| | | FinanceReimbursementDO updateObj = BeanUtils.toBean(updateReqVO, FinanceReimbursementDO.class); |
| | | // æ¥éåå·ï¼æªå¡«è¡¨ç¤ºä¸åæ´ï¼å¡«äºåæ ¡éªåè¦ç |
| | | String customNo = StrUtil.trimToNull(updateReqVO.getNo()); |
| | | if (customNo == null || customNo.equals(reimbursement.getNo())) { |
| | | updateObj.setNo(reimbursement.getNo()); |
| | | } else { |
| | | validateCustomNoFormat(customNo); |
| | | if (reimbursementMapper.selectByNo(customNo) != null) { |
| | | throw exception(REIMBURSEMENT_CUSTOM_NO_EXISTS, customNo); |
| | | } |
| | | updateObj.setNo(customNo); |
| | | } |
| | | reimbursementMapper.updateById(updateObj); |
| | | |
| | | // 2.2 æ´æ°æç»ï¼å
å åå¢ |
| | | reimbursementItemMapper.deleteByReimbursementId(updateReqVO.getId()); |
| | | List<FinanceReimbursementItemDO> items = buildItems(updateReqVO.getId(), updateReqVO.getItems()); |
| | | if (CollUtil.isNotEmpty(items)) { |
| | | reimbursementItemMapper.insertBatch(items); |
| | | } |
| | | |
| | | // 2.3 æ´æ°å票éä»¶ |
| | | storageAttachmentApi.updateAttachments("file", REIMBURSEMENT_RECORD_TYPE, |
| | | updateReqVO.getId(), updateReqVO.getBlobIds()); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteReimbursement(Long id) { |
| | | // 1. æ ¡éªåå¨ + èç¨¿ç¶æ |
| | | FinanceReimbursementDO reimbursement = validateReimbursementExists(id); |
| | | if (!FinanceReimbursementStatusEnum.DRAFT.getStatus().equals(reimbursement.getStatus())) { |
| | | throw exception(REIMBURSEMENT_DELETE_FAIL_NOT_DRAFT, reimbursement.getNo()); |
| | | } |
| | | |
| | | // 2. å é¤æç» |
| | | reimbursementItemMapper.deleteByReimbursementId(id); |
| | | // 3. å é¤ä¸»è¡¨ |
| | | reimbursementMapper.deleteById(id); |
| | | // 4. å é¤å票éä»¶ |
| | | storageAttachmentApi.deleteAttachmentsByRecord(REIMBURSEMENT_RECORD_TYPE, id); |
| | | } |
| | | |
| | | @Override |
| | | public FinanceReimbursementDO getReimbursement(Long id) { |
| | | return reimbursementMapper.selectById(id); |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<FinanceReimbursementDO> getReimbursementPage(FinanceReimbursementPageReqVO pageReqVO) { |
| | | return reimbursementMapper.selectPage(pageReqVO); |
| | | } |
| | | |
| | | @Override |
| | | public List<FinanceReimbursementItemDO> getReimbursementItemListByReimbursementId(Long reimbursementId) { |
| | | return reimbursementItemMapper.selectListByReimbursementId(reimbursementId); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void submitReimbursement(Long id, String processDefinitionKey, Long userId) { |
| | | // 1. æ ¡éªåå¨ + å¯æäº¤ç¶æï¼è稿æå·²é©³åï¼ |
| | | FinanceReimbursementDO reimbursement = validateReimbursementExists(id); |
| | | Integer status = reimbursement.getStatus(); |
| | | if (!FinanceReimbursementStatusEnum.DRAFT.getStatus().equals(status) |
| | | && !FinanceReimbursementStatusEnum.REJECTED.getStatus().equals(status)) { |
| | | throw exception(REIMBURSEMENT_SUBMIT_FAIL_STATUS); |
| | | } |
| | | // 1.2 æ ¡éªå¿
é¡»ææç» |
| | | List<FinanceReimbursementItemDO> items = reimbursementItemMapper.selectListByReimbursementId(id); |
| | | if (CollUtil.isEmpty(items)) { |
| | | throw exception(REIMBURSEMENT_SUBMIT_FAIL_ITEM_EMPTY); |
| | | } |
| | | |
| | | // 2. å建 BPM æµç¨å®ä¾ |
| | | String processInstanceId = processInstanceApi.createProcessInstance(userId, |
| | | new BpmProcessInstanceCreateReqDTO() |
| | | .setProcessDefinitionKey(processDefinitionKey) |
| | | .setBusinessKey(String.valueOf(id))); |
| | | |
| | | // 3. æ´æ°ç¶æä¸ºå®¡æ¹ä¸ |
| | | reimbursementMapper.updateById(new FinanceReimbursementDO() |
| | | .setId(id) |
| | | .setStatus(FinanceReimbursementStatusEnum.APPROVING.getStatus()) |
| | | .setProcessInstanceId(processInstanceId)); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void archiveReimbursement(Long id) { |
| | | // 1. æ ¡éªåå¨ + å·²éè¿ç¶æ |
| | | FinanceReimbursementDO reimbursement = validateReimbursementExists(id); |
| | | if (!FinanceReimbursementStatusEnum.APPROVED.getStatus().equals(reimbursement.getStatus())) { |
| | | throw exception(REIMBURSEMENT_ARCHIVE_FAIL_STATUS); |
| | | } |
| | | |
| | | // 2. æ´æ°ä¸ºå·²å½æ¡£ |
| | | reimbursementMapper.updateById(new FinanceReimbursementDO() |
| | | .setId(id) |
| | | .setStatus(FinanceReimbursementStatusEnum.ARCHIVED.getStatus()) |
| | | .setArchiveTime(LocalDateTime.now())); |
| | | } |
| | | |
| | | @Override |
| | | public List<Map<String, Object>> getReimbursementApproveProcessDefinitionList() { |
| | | // 1. æ ¡éªåç±»åæµç¨å®ä¹æ¯å¦åå¨ |
| | | validateReimbursementApproveCategoryAndProcessDefinition(); |
| | | |
| | | // 2. è·ååç±»ä¸çæµç¨å®ä¹ä¿¡æ¯ |
| | | List<BpmProcessDefinitionInfoDO> definitionInfoList = bpmProcessDefinitionService |
| | | .getProcessDefinitionInfoListByCategory(REIMBURSEMENT_APPROVE_CATEGORY_CODE); |
| | | if (CollUtil.isEmpty(definitionInfoList)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | // 3. éåè·åæµç¨å®ä¹è¯¦æ
ï¼è¿æ»¤æ¿æ´»ç¶æï¼ä¿çææ°çæ¬ |
| | | Map<String, ProcessDefinition> latestVersionMap = new HashMap<>(); |
| | | for (BpmProcessDefinitionInfoDO info : definitionInfoList) { |
| | | ProcessDefinition pd = bpmProcessDefinitionService.getProcessDefinition(info.getProcessDefinitionId()); |
| | | if (pd == null || pd.isSuspended()) { |
| | | continue; |
| | | } |
| | | ProcessDefinition existing = latestVersionMap.get(pd.getKey()); |
| | | if (existing == null || pd.getVersion() > existing.getVersion()) { |
| | | latestVersionMap.put(pd.getKey(), pd); |
| | | } |
| | | } |
| | | |
| | | // 4. è¿åæµç¨å®ä¹å表 |
| | | List<Map<String, Object>> result = new ArrayList<>(); |
| | | for (ProcessDefinition pd : latestVersionMap.values()) { |
| | | Map<String, Object> item = new HashMap<>(); |
| | | item.put("id", pd.getId()); |
| | | item.put("key", pd.getKey()); |
| | | item.put("name", pd.getName()); |
| | | result.add(item); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateReimbursementAuditStatus(Long id, Integer bpmResult) { |
| | | // 1. æ ¡éªåå¨ |
| | | FinanceReimbursementDO reimbursement = validateReimbursementExists(id); |
| | | if (!FinanceReimbursementStatusEnum.APPROVING.getStatus().equals(reimbursement.getStatus())) { |
| | | log.warn("[updateReimbursementAuditStatus] æ¥éå({}) ä¸å¤äºå®¡æ¹ä¸ç¶æ", id); |
| | | return; |
| | | } |
| | | |
| | | // 2. æ ¹æ®å®¡æ¹ç»ææ´æ°ç¶æ |
| | | Integer newStatus = convertBpmResultToStatus(bpmResult); |
| | | if (newStatus != null) { |
| | | reimbursementMapper.updateById(new FinanceReimbursementDO() |
| | | .setId(id).setStatus(newStatus)); |
| | | } |
| | | } |
| | | |
| | | // ==================== å
鍿¹æ³ ==================== |
| | | |
| | | private FinanceReimbursementDO validateReimbursementExists(Long id) { |
| | | FinanceReimbursementDO reimbursement = reimbursementMapper.selectById(id); |
| | | if (reimbursement == null) { |
| | | throw exception(REIMBURSEMENT_NOT_EXISTS); |
| | | } |
| | | return reimbursement; |
| | | } |
| | | |
| | | /** |
| | | * è§£ææ°å¢æ¶çæ¥éåå·ï¼å»æé¦å°¾ç©ºæ ¼åè¥ä¸ºç©ºï¼åç±ç³»ç»æ BX + æ¥æ + 6 使µæ°´çæï¼ |
| | | * å¦å使ç¨ç¨æ·èªå®ä¹åå·ã |
| | | * <p> |
| | | * 注æï¼åªç±ç©ºæ ¼ï¼å«å
¨è§ç©ºæ ¼ï¼ç»æçè¾å
¥çåäºæªå¡«ï¼ä¸ä¼ä½ä¸ºåå·è½åºã |
| | | */ |
| | | private String resolveCreateNo(String customNo) { |
| | | String no = StrUtil.trimToNull(customNo); |
| | | if (no == null) { |
| | | no = noRedisDAO.generate(FinanceNoRedisDAO.REIMBURSEMENT_NO_PREFIX); |
| | | if (reimbursementMapper.selectByNo(no) != null) { |
| | | throw exception(REIMBURSEMENT_NO_EXISTS); |
| | | } |
| | | return no; |
| | | } |
| | | validateCustomNoFormat(no); |
| | | if (reimbursementMapper.selectByNo(no) != null) { |
| | | throw exception(REIMBURSEMENT_CUSTOM_NO_EXISTS, no); |
| | | } |
| | | return no; |
| | | } |
| | | |
| | | /** èªå®ä¹åå·ä¸é´ä¸å
许åºç°ç©ºæ ¼ï¼é¦å°¾ç©ºæ ¼å·²å¨è§£ææ¶å»æï¼ */ |
| | | private void validateCustomNoFormat(String no) { |
| | | if (StrUtil.containsAny(no, ' ', '\t', 'ã')) { |
| | | throw exception(REIMBURSEMENT_CUSTOM_NO_INVALID, no); |
| | | } |
| | | } |
| | | |
| | | private List<FinanceReimbursementItemDO> buildItems(Long reimbursementId, |
| | | List<FinanceReimbursementItemSaveReqVO> itemVOs) { |
| | | if (CollUtil.isEmpty(itemVOs)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | return itemVOs.stream() |
| | | .map(item -> BeanUtils.toBean(item, FinanceReimbursementItemDO.class, |
| | | in -> in.setReimbursementId(reimbursementId))) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | private void validateReimbursementApproveCategoryAndProcessDefinition() { |
| | | List<BpmCategoryDO> categories = bpmCategoryService.getCategoryListByCode( |
| | | Collections.singletonList(REIMBURSEMENT_APPROVE_CATEGORY_CODE)); |
| | | if (CollUtil.isEmpty(categories)) { |
| | | throw exception(REIMBURSEMENT_BPM_CATEGORY_NOT_EXISTS); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è½¬æ¢ BPM 审æ¹ç»æä¸ºæ¥éåç¶æ |
| | | */ |
| | | private Integer convertBpmResultToStatus(Integer bpmResult) { |
| | | if (cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum.APPROVE.getStatus().equals(bpmResult)) { |
| | | return FinanceReimbursementStatusEnum.APPROVED.getStatus(); |
| | | } else if (cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum.REJECT.getStatus().equals(bpmResult)) { |
| | | return FinanceReimbursementStatusEnum.REJECTED.getStatus(); |
| | | } else if (cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum.CANCEL.getStatus().equals(bpmResult)) { |
| | | return FinanceReimbursementStatusEnum.DRAFT.getStatus(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.finance.service.reimbursement.listener; |
| | | |
| | | import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent; |
| | | import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener; |
| | | import cn.iocoder.yudao.module.finance.service.reimbursement.FinanceReimbursementService; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * æ¥éå审æ¹ç¶æçå¬å¨ |
| | | * |
| | | * çå¬ BPM æµç¨å®ä¾ç¶æåæ´äºä»¶ï¼æ´æ°æ¥éåç审æ¹ç¶æï¼åååå
¬å®¡æ¹åååï¼ |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Component |
| | | @Slf4j |
| | | public class FinanceReimbursementStatusListener extends BpmProcessInstanceStatusEventListener { |
| | | |
| | | /** |
| | | * æ¥éåå®¡æ¹æµç¨å®ä¹ Key |
| | | */ |
| | | private static final String PROCESS_DEFINITION_KEY = "finance_reimbursement_approve"; |
| | | |
| | | @Resource |
| | | private FinanceReimbursementService reimbursementService; |
| | | |
| | | @Override |
| | | protected String getProcessDefinitionKey() { |
| | | return PROCESS_DEFINITION_KEY; |
| | | } |
| | | |
| | | @Override |
| | | protected void onEvent(BpmProcessInstanceStatusEvent event) { |
| | | Long reimbursementId; |
| | | try { |
| | | reimbursementId = Long.parseLong(event.getBusinessKey()); |
| | | } catch (NumberFormatException e) { |
| | | log.warn("[onEvent] businessKey({}) 䏿¯ææçæ¥éåç¼å·", event.getBusinessKey()); |
| | | return; |
| | | } |
| | | |
| | | log.info("[onEvent] æ¶å°BPM审æ¹äºä»¶ï¼reimbursementId={}, status={}", reimbursementId, event.getStatus()); |
| | | |
| | | try { |
| | | reimbursementService.updateReimbursementAuditStatus(reimbursementId, event.getStatus()); |
| | | log.info("[onEvent] æ¥éå({}) 审æ¹ç¶ææ´æ°å®æ", reimbursementId); |
| | | } catch (Exception e) { |
| | | log.error("[onEvent] æ´æ°æ¥éå审æ¹ç¶æå¤±è´¥ï¼reimbursementId={}", reimbursementId, e); |
| | | } |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <project xmlns="http://maven.apache.org/POM/4.0.0" |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao</artifactId> |
| | | <version>${revision}</version> |
| | | </parent> |
| | | <modelVersion>4.0.0</modelVersion> |
| | | <artifactId>yudao-module-research</artifactId> |
| | | <packaging>jar</packaging> |
| | | |
| | | <name>${project.artifactId}</name> |
| | | <description> |
| | | research å
ä¸ï¼è¯¾é¢ç®¡ç模åï¼å¦ä¼/åä¼åç§ç 课é¢ï¼è¯¾é¢æååå¸ãå¨çº¿ç³æ¥ãä¸å®¶è¯å®¡ãç«é¡¹å®¡æ¹ãç»è´¹æ¨ä»ï¼ã |
| | | </description> |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-system</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- BPM 工使µï¼ç§ä¹¦å¤å½¢å¼å®¡æ¥ â ä¸å®¶è¯å®¡ â å¦ä¼ç«é¡¹å®¡æ¹ ä¸èç¹å®¡æ¹ï¼ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-bpm</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- UMS ä¼å模åï¼ç³æ¥äººå
³èä¼åï¼è¯»åä¼åä¿¡æ¯èªå¨å¸¦å
¥ï¼ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-ums</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- Web ç¸å
³ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-web</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-security</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- DB ç¸å
³ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-mybatis</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-redis</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- å·¥å
·ç±»ç¸å
³ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-excel</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- Test æµè¯ç¸å
³ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-test</artifactId> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | </project> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.controller.admin.application; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.research.controller.admin.application.vo.ResearchApplicationPageReqVO; |
| | | import cn.iocoder.yudao.module.research.controller.admin.application.vo.ResearchApplicationRespVO; |
| | | import cn.iocoder.yudao.module.research.controller.admin.application.vo.ResearchApplicationSaveReqVO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.application.ResearchApplicationDO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.guideline.ResearchGuidelineDO; |
| | | import cn.iocoder.yudao.module.research.service.application.ResearchApplicationService; |
| | | import cn.iocoder.yudao.module.research.service.application.ResearchApplicationServiceImpl; |
| | | import cn.iocoder.yudao.module.research.service.guideline.ResearchGuidelineService; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.annotation.Resource; |
| | | import jakarta.validation.Valid; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; |
| | | |
| | | @Tag(name = "管çåå° - 课é¢ç³æ¥") |
| | | @RestController |
| | | @RequestMapping("/research/application") |
| | | @Validated |
| | | public class ResearchApplicationController { |
| | | |
| | | public static final String APPLICATION_RECORD_TYPE = |
| | | ResearchApplicationServiceImpl.APPLICATION_RECORD_TYPE; |
| | | |
| | | @Resource |
| | | private ResearchApplicationService applicationService; |
| | | |
| | | @Resource |
| | | private ResearchGuidelineService guidelineService; |
| | | |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @PostMapping("/create") |
| | | @Operation(summary = "å建课é¢ç³æ¥ä¹¦") |
| | | @PreAuthorize("@ss.hasPermission('research:application:create')") |
| | | public CommonResult<Long> createApplication(@Valid @RequestBody ResearchApplicationSaveReqVO createReqVO) { |
| | | return success(applicationService.createApplication(createReqVO)); |
| | | } |
| | | |
| | | @PutMapping("/update") |
| | | @Operation(summary = "æ´æ°è¯¾é¢ç³æ¥ä¹¦") |
| | | @PreAuthorize("@ss.hasPermission('research:application:update')") |
| | | public CommonResult<Boolean> updateApplication(@Valid @RequestBody ResearchApplicationSaveReqVO updateReqVO) { |
| | | applicationService.updateApplication(updateReqVO); |
| | | return success(true); |
| | | } |
| | | |
| | | @DeleteMapping("/delete") |
| | | @Operation(summary = "å é¤è¯¾é¢ç³æ¥ä¹¦") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('research:application:delete')") |
| | | public CommonResult<Boolean> deleteApplication(@RequestParam("id") Long id) { |
| | | applicationService.deleteApplication(id); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/get") |
| | | @Operation(summary = "è·å¾è¯¾é¢ç³æ¥ä¹¦") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true, example = "1024") |
| | | @PreAuthorize("@ss.hasPermission('research:application:query')") |
| | | public CommonResult<ResearchApplicationRespVO> getApplication(@RequestParam("id") Long id) { |
| | | return success(buildApplicationDetail(applicationService.getApplication(id))); |
| | | } |
| | | |
| | | @GetMapping("/page") |
| | | @Operation(summary = "è·å¾è¯¾é¢ç³æ¥ä¹¦å页") |
| | | @PreAuthorize("@ss.hasPermission('research:application:query')") |
| | | public CommonResult<PageResult<ResearchApplicationRespVO>> getApplicationPage( |
| | | @Valid ResearchApplicationPageReqVO pageReqVO) { |
| | | PageResult<ResearchApplicationDO> pageResult = applicationService.getApplicationPage(pageReqVO); |
| | | return success(new PageResult<>(buildApplicationDetailList(pageResult.getList()), pageResult.getTotal())); |
| | | } |
| | | |
| | | @PostMapping("/submit") |
| | | @Operation(summary = "æäº¤è¯¾é¢ç³æ¥ä¹¦å®¡æ¹") |
| | | @PreAuthorize("@ss.hasPermission('research:application:submit')") |
| | | public CommonResult<Boolean> submitApplication(@RequestParam("id") Long id, |
| | | @RequestParam("processDefinitionKey") String processDefinitionKey) { |
| | | applicationService.submitApplication(id, processDefinitionKey); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/approve-process-list") |
| | | @Operation(summary = "è·å课é¢ç«é¡¹å®¡æ¹æµç¨å表") |
| | | @PreAuthorize("@ss.hasPermission('research:application:query')") |
| | | public CommonResult<List<Map<String, Object>>> getApproveProcessDefinitionList() { |
| | | return success(applicationService.getApproveProcessDefinitionList()); |
| | | } |
| | | |
| | | @PostMapping("/publish-notice") |
| | | @Operation(summary = "åå¸ç«é¡¹éç¥") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('research:application:notice')") |
| | | public CommonResult<Boolean> publishNotice(@RequestParam("id") Long id) { |
| | | applicationService.publishNotice(id); |
| | | return success(true); |
| | | } |
| | | |
| | | // ==================== å
鍿¹æ³ ==================== |
| | | |
| | | private ResearchApplicationRespVO buildApplicationDetail(ResearchApplicationDO application) { |
| | | if (application == null) { |
| | | return null; |
| | | } |
| | | return buildApplicationDetailList(Collections.singletonList(application)).get(0); |
| | | } |
| | | |
| | | private List<ResearchApplicationRespVO> buildApplicationDetailList(List<ResearchApplicationDO> list) { |
| | | if (CollUtil.isEmpty(list)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | // 1.1 è·åå建人 |
| | | Set<Long> creatorIds = convertSet(list, application -> NumberUtils.parseLong(application.getCreator())); |
| | | Map<Long, AdminUserRespDTO> creatorMap = adminUserApi.getUserMap(creatorIds); |
| | | // 1.2 è·åéä»¶ |
| | | Map<Long, List<StorageBlobRespDTO>> attachmentMap = list.stream() |
| | | .collect(Collectors.toMap(ResearchApplicationDO::getId, |
| | | r -> storageAttachmentApi.listAttachments(APPLICATION_RECORD_TYPE, r.getId()))); |
| | | // 1.3 è·åæååç§° |
| | | Set<Long> guidelineIds = convertSet(list, ResearchApplicationDO::getGuidelineId); |
| | | Map<Long, ResearchGuidelineDO> guidelineMap = guidelineService.getGuidelineList(guidelineIds).stream() |
| | | .collect(Collectors.toMap(ResearchGuidelineDO::getId, g -> g)); |
| | | |
| | | // 2. æ¼æ¥ç»æ |
| | | return BeanUtils.toBean(list, ResearchApplicationRespVO.class, (vo) -> { |
| | | findAndThen(creatorMap, NumberUtils.parseLong(vo.getCreator()), |
| | | user -> vo.setCreatorName(user.getNickname())); |
| | | List<StorageBlobRespDTO> attachments = attachmentMap.getOrDefault(vo.getId(), Collections.emptyList()); |
| | | vo.setAttachmentList(attachments); |
| | | vo.setHasAttachment(CollUtil.isNotEmpty(attachments)); |
| | | if (vo.getGuidelineId() != null) { |
| | | findAndThen(guidelineMap, vo.getGuidelineId(), g -> vo.setGuidelineTitle(g.getTitle())); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.controller.admin.application.vo; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| | | |
| | | @Schema(description = "管çåå° - 课é¢ç³æ¥ä¹¦å页 Request VO") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | public class ResearchApplicationPageReqVO extends PageParam { |
| | | |
| | | @Schema(description = "ç³æ¥ç¼å·", example = "SB20260928000001") |
| | | private String no; |
| | | |
| | | @Schema(description = "课é¢åç§°", example = "æºè½å¶é 产线æ°ååªçå
³é®ææ¯ç ç©¶") |
| | | private String title; |
| | | |
| | | @Schema(description = "æå±è¯¾é¢æå ID", example = "1") |
| | | private Long guidelineId; |
| | | |
| | | @Schema(description = "课é¢ç±»å«", example = "1") |
| | | private Integer category; |
| | | |
| | | @Schema(description = "ç³æ¥ä¼å ID", example = "1") |
| | | private Long memberId; |
| | | |
| | | @Schema(description = "ç¶æ", example = "0") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "å建æ¶é´") |
| | | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| | | private LocalDateTime[] createTime; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.controller.admin.application.vo; |
| | | |
| | | import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - 课é¢ç³æ¥ä¹¦ Response VO") |
| | | @Data |
| | | public class ResearchApplicationRespVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "ç³æ¥ç¼å·", example = "SB20260928000001") |
| | | private String no; |
| | | |
| | | @Schema(description = "æå±è¯¾é¢æå ID", example = "1") |
| | | private Long guidelineId; |
| | | |
| | | @Schema(description = "æå±è¯¾é¢æååç§°") |
| | | private String guidelineTitle; |
| | | |
| | | @Schema(description = "课é¢åç§°", example = "æºè½å¶é 产线æ°ååªçå
³é®ææ¯ç ç©¶") |
| | | private String title; |
| | | |
| | | @Schema(description = "课é¢ç±»å«ï¼1-éç¹è¯¾é¢ 2-ä¸è¬è¯¾é¢", example = "1") |
| | | private Integer category; |
| | | |
| | | @Schema(description = "ç³æ¥ä¼å ID", example = "1") |
| | | private Long memberId; |
| | | |
| | | @Schema(description = "ç³æ¥äººå§å/åä½åç§°", example = "å¼ ä¸") |
| | | private String applicantName; |
| | | |
| | | @Schema(description = "ç³æ¥ç»å½ç¨æ· ID") |
| | | private Long applicantUserId; |
| | | |
| | | @Schema(description = "å·¥ä½åä½", example = "XX大å¦") |
| | | private String workUnit; |
| | | |
| | | @Schema(description = "èç§°", example = "ææ") |
| | | private String jobTitle; |
| | | |
| | | @Schema(description = "èç³»çµè¯", example = "13800138000") |
| | | private String contactPhone; |
| | | |
| | | @Schema(description = "èç³»é®ç®±", example = "zhangsan@example.com") |
| | | private String contactEmail; |
| | | |
| | | @Schema(description = "课é¢ç»æå") |
| | | private String teamMembers; |
| | | |
| | | @Schema(description = "ç³è¯·ç»è´¹ï¼å
ï¼", example = "100000.00") |
| | | private BigDecimal budgetAmount; |
| | | |
| | | @Schema(description = "ç³æ¥ä¹¦æ£æ") |
| | | private String planContent; |
| | | |
| | | @Schema(description = "ç¶æï¼0-è稿 15-审æ¹ä¸ 20-å·²ç«é¡¹ 35-已驳å", example = "0") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "BPM æµç¨å®ä¾ ID", example = "1001") |
| | | private String processInstanceId; |
| | | |
| | | @Schema(description = "ä¸å®¶è¯å®¡å æåå", example = "86.50") |
| | | private BigDecimal reviewAvgScore; |
| | | |
| | | @Schema(description = "è¯å®¡ç»è®ºï¼0-æªéè¿ 1-æ¨èç«é¡¹", example = "1") |
| | | private Integer reviewPass; |
| | | |
| | | @Schema(description = "ç«é¡¹ç¼å·", example = "LX20260928000001") |
| | | private String researchNo; |
| | | |
| | | @Schema(description = "ç«é¡¹æ¶é´") |
| | | private LocalDateTime approveTime; |
| | | |
| | | @Schema(description = "ç«é¡¹éç¥å
Œ ID") |
| | | private Long noticeId; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | | @Schema(description = "å建è
") |
| | | private String creator; |
| | | |
| | | @Schema(description = "å建è
åç§°") |
| | | private String creatorName; |
| | | |
| | | @Schema(description = "å建æ¶é´") |
| | | private LocalDateTime createTime; |
| | | |
| | | @Schema(description = "éä»¶å表") |
| | | private List<StorageBlobRespDTO> attachmentList; |
| | | |
| | | @Schema(description = "æ¯å¦æéä»¶") |
| | | private Boolean hasAttachment; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.controller.admin.application.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotEmpty; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import jakarta.validation.constraints.PositiveOrZero; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - 课é¢ç³æ¥ä¹¦æ°å¢/ä¿®æ¹ Request VO") |
| | | @Data |
| | | public class ResearchApplicationSaveReqVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "æå±è¯¾é¢æå ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "æå±è¯¾é¢æåä¸è½ä¸ºç©º") |
| | | private Long guidelineId; |
| | | |
| | | @Schema(description = "课é¢åç§°", requiredMode = Schema.RequiredMode.REQUIRED, example = "æºè½å¶é 产线æ°ååªçå
³é®ææ¯ç ç©¶") |
| | | @NotEmpty(message = "课é¢åç§°ä¸è½ä¸ºç©º") |
| | | private String title; |
| | | |
| | | @Schema(description = "ç³æ¥ä¼å IDï¼å
³è ums_memberï¼", example = "1") |
| | | private Long memberId; |
| | | |
| | | @Schema(description = "ç³æ¥äººå§å/åä½åç§°", requiredMode = Schema.RequiredMode.REQUIRED, example = "å¼ ä¸") |
| | | @NotEmpty(message = "ç³æ¥äººå§åä¸è½ä¸ºç©º") |
| | | private String applicantName; |
| | | |
| | | @Schema(description = "å·¥ä½åä½", example = "XX大å¦") |
| | | private String workUnit; |
| | | |
| | | @Schema(description = "èç§°", example = "ææ") |
| | | private String jobTitle; |
| | | |
| | | @Schema(description = "èç³»çµè¯", example = "13800138000") |
| | | private String contactPhone; |
| | | |
| | | @Schema(description = "èç³»é®ç®±", example = "zhangsan@example.com") |
| | | private String contactEmail; |
| | | |
| | | @Schema(description = "课é¢ç»æåï¼æ¯è¡ä¸æ¡ï¼å§å|åä½|èç§°ï¼") |
| | | private String teamMembers; |
| | | |
| | | @Schema(description = "ç³è¯·ç»è´¹ï¼å
ï¼", example = "100000.00") |
| | | @PositiveOrZero(message = "ç³è¯·ç»è´¹ä¸è½ä¸ºè´æ°") |
| | | private BigDecimal budgetAmount; |
| | | |
| | | @Schema(description = "ç³æ¥ä¹¦æ£æï¼ç ç©¶èæ¯/ç®æ /æ¹æ¡/颿ææï¼") |
| | | private String planContent; |
| | | |
| | | @Schema(description = "夿³¨", example = "便åä½å·²åæç³æ¥") |
| | | private String remark; |
| | | |
| | | @Schema(description = "éä»¶BlobIdå表") |
| | | private List<Long> blobIds; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.controller.admin.fund; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.research.controller.admin.fund.vo.ResearchFundRecordRespVO; |
| | | import cn.iocoder.yudao.module.research.controller.admin.fund.vo.ResearchFundRecordSaveReqVO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.fund.ResearchFundRecordDO; |
| | | import cn.iocoder.yudao.module.research.service.fund.ResearchFundRecordService; |
| | | import cn.iocoder.yudao.module.research.service.fund.ResearchFundRecordServiceImpl; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.annotation.Resource; |
| | | import jakarta.validation.Valid; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; |
| | | |
| | | @Tag(name = "管çåå° - 课é¢ç»è´¹æ¨ä»") |
| | | @RestController |
| | | @RequestMapping("/research/fund-record") |
| | | @Validated |
| | | public class ResearchFundRecordController { |
| | | |
| | | public static final String FUND_RECORD_TYPE = |
| | | ResearchFundRecordServiceImpl.FUND_RECORD_TYPE; |
| | | |
| | | @Resource |
| | | private ResearchFundRecordService fundRecordService; |
| | | |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @PostMapping("/create") |
| | | @Operation(summary = "ç»è®°ç»è´¹æ¨ä»") |
| | | @PreAuthorize("@ss.hasPermission('research:fund:create')") |
| | | public CommonResult<Long> createFundRecord(@Valid @RequestBody ResearchFundRecordSaveReqVO createReqVO) { |
| | | return success(fundRecordService.createFundRecord(createReqVO)); |
| | | } |
| | | |
| | | @PutMapping("/update") |
| | | @Operation(summary = "æ´æ°ç»è´¹æ¨ä»") |
| | | @PreAuthorize("@ss.hasPermission('research:fund:update')") |
| | | public CommonResult<Boolean> updateFundRecord(@Valid @RequestBody ResearchFundRecordSaveReqVO updateReqVO) { |
| | | fundRecordService.updateFundRecord(updateReqVO); |
| | | return success(true); |
| | | } |
| | | |
| | | @DeleteMapping("/delete") |
| | | @Operation(summary = "å é¤ç»è´¹æ¨ä»") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('research:fund:delete')") |
| | | public CommonResult<Boolean> deleteFundRecord(@RequestParam("id") Long id) { |
| | | fundRecordService.deleteFundRecord(id); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/list") |
| | | @Operation(summary = "è·å¾æè¯¾é¢ç³æ¥ä¹¦çç»è´¹æ¨ä»è®°å½å表") |
| | | @Parameter(name = "applicationId", description = "课é¢ç³æ¥ä¹¦ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('research:fund:query')") |
| | | public CommonResult<List<ResearchFundRecordRespVO>> getFundRecordList( |
| | | @RequestParam("applicationId") Long applicationId) { |
| | | List<ResearchFundRecordDO> list = fundRecordService.getFundRecordListByApplicationId(applicationId); |
| | | if (CollUtil.isEmpty(list)) { |
| | | return success(Collections.emptyList()); |
| | | } |
| | | |
| | | Set<Long> creatorIds = convertSet(list, record -> NumberUtils.parseLong(record.getCreator())); |
| | | Map<Long, AdminUserRespDTO> creatorMap = adminUserApi.getUserMap(creatorIds); |
| | | Map<Long, List<StorageBlobRespDTO>> attachmentMap = list.stream() |
| | | .collect(Collectors.toMap(ResearchFundRecordDO::getId, |
| | | r -> storageAttachmentApi.listAttachments(FUND_RECORD_TYPE, r.getId()))); |
| | | |
| | | return success(BeanUtils.toBean(list, ResearchFundRecordRespVO.class, (vo) -> { |
| | | findAndThen(creatorMap, NumberUtils.parseLong(vo.getCreator()), |
| | | user -> vo.setCreatorName(user.getNickname())); |
| | | List<StorageBlobRespDTO> attachments = attachmentMap.getOrDefault(vo.getId(), Collections.emptyList()); |
| | | vo.setAttachmentList(attachments); |
| | | vo.setHasAttachment(CollUtil.isNotEmpty(attachments)); |
| | | })); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.controller.admin.fund.vo; |
| | | |
| | | import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - ç»è´¹æ¨ä»è®°å½ Response VO") |
| | | @Data |
| | | public class ResearchFundRecordRespVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "课é¢ç³æ¥ä¹¦ ID", example = "1") |
| | | private Long applicationId; |
| | | |
| | | @Schema(description = "æ¨ä»æ¹æ¬¡", example = "ç¬¬ä¸æ") |
| | | private String batchName; |
| | | |
| | | @Schema(description = "æ¨ä»éé¢ï¼å
ï¼", example = "50000.00") |
| | | private BigDecimal amount; |
| | | |
| | | @Schema(description = "æ¨ä»æ¥æ", example = "2026-12-01") |
| | | private LocalDate payDate; |
| | | |
| | | @Schema(description = "æ¶æ¬¾åä½/è´¦æ·å", example = "XX大å¦") |
| | | private String payee; |
| | | |
| | | @Schema(description = "ç¶æï¼0-å¾
æ¨ä» 20-å·²æ¨ä»", example = "20") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | | @Schema(description = "å建è
") |
| | | private String creator; |
| | | |
| | | @Schema(description = "å建è
åç§°") |
| | | private String creatorName; |
| | | |
| | | @Schema(description = "å建æ¶é´") |
| | | private LocalDateTime createTime; |
| | | |
| | | @Schema(description = "åè¯éä»¶å表") |
| | | private List<StorageBlobRespDTO> attachmentList; |
| | | |
| | | @Schema(description = "æ¯å¦æåè¯éä»¶") |
| | | private Boolean hasAttachment; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.controller.admin.fund.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import jakarta.validation.constraints.PositiveOrZero; |
| | | import lombok.Data; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; |
| | | |
| | | @Schema(description = "管çåå° - ç»è´¹æ¨ä»è®°å½æ°å¢/ä¿®æ¹ Request VO") |
| | | @Data |
| | | public class ResearchFundRecordSaveReqVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "课é¢ç³æ¥ä¹¦ ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "课é¢ç³æ¥ä¹¦ä¸è½ä¸ºç©º") |
| | | private Long applicationId; |
| | | |
| | | @Schema(description = "æ¨ä»æ¹æ¬¡", example = "ç¬¬ä¸æ") |
| | | private String batchName; |
| | | |
| | | @Schema(description = "æ¨ä»éé¢ï¼å
ï¼", requiredMode = Schema.RequiredMode.REQUIRED, example = "50000.00") |
| | | @NotNull(message = "æ¨ä»éé¢ä¸è½ä¸ºç©º") |
| | | @PositiveOrZero(message = "æ¨ä»éé¢ä¸è½ä¸ºè´æ°") |
| | | private BigDecimal amount; |
| | | |
| | | @Schema(description = "æ¨ä»æ¥æ", example = "2026-12-01") |
| | | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) |
| | | private LocalDate payDate; |
| | | |
| | | @Schema(description = "æ¶æ¬¾åä½/è´¦æ·å", example = "XX大å¦") |
| | | private String payee; |
| | | |
| | | @Schema(description = "ç¶æï¼0-å¾
æ¨ä» 20-å·²æ¨ä»", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") |
| | | @NotNull(message = "æ¨ä»ç¶æä¸è½ä¸ºç©º") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | | @Schema(description = "åè¯éä»¶BlobIdå表") |
| | | private List<Long> blobIds; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.controller.admin.guideline; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.research.controller.admin.guideline.vo.ResearchGuidelinePageReqVO; |
| | | import cn.iocoder.yudao.module.research.controller.admin.guideline.vo.ResearchGuidelineRespVO; |
| | | import cn.iocoder.yudao.module.research.controller.admin.guideline.vo.ResearchGuidelineSaveReqVO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.guideline.ResearchGuidelineDO; |
| | | import cn.iocoder.yudao.module.research.service.guideline.ResearchGuidelineService; |
| | | import cn.iocoder.yudao.module.research.service.guideline.ResearchGuidelineServiceImpl; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.annotation.Resource; |
| | | import jakarta.validation.Valid; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; |
| | | |
| | | @Tag(name = "管çåå° - è¯¾é¢æå") |
| | | @RestController |
| | | @RequestMapping("/research/guideline") |
| | | @Validated |
| | | public class ResearchGuidelineController { |
| | | |
| | | public static final String GUIDELINE_RECORD_TYPE = |
| | | ResearchGuidelineServiceImpl.GUIDELINE_RECORD_TYPE; |
| | | |
| | | @Resource |
| | | private ResearchGuidelineService guidelineService; |
| | | |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @PostMapping("/create") |
| | | @Operation(summary = "åå»ºè¯¾é¢æå") |
| | | @PreAuthorize("@ss.hasPermission('research:guideline:create')") |
| | | public CommonResult<Long> createGuideline(@Valid @RequestBody ResearchGuidelineSaveReqVO createReqVO) { |
| | | return success(guidelineService.createGuideline(createReqVO)); |
| | | } |
| | | |
| | | @PutMapping("/update") |
| | | @Operation(summary = "æ´æ°è¯¾é¢æå") |
| | | @PreAuthorize("@ss.hasPermission('research:guideline:update')") |
| | | public CommonResult<Boolean> updateGuideline(@Valid @RequestBody ResearchGuidelineSaveReqVO updateReqVO) { |
| | | guidelineService.updateGuideline(updateReqVO); |
| | | return success(true); |
| | | } |
| | | |
| | | @DeleteMapping("/delete") |
| | | @Operation(summary = "å é¤è¯¾é¢æå") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('research:guideline:delete')") |
| | | public CommonResult<Boolean> deleteGuideline(@RequestParam("id") Long id) { |
| | | guidelineService.deleteGuideline(id); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/get") |
| | | @Operation(summary = "è·å¾è¯¾é¢æå") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true, example = "1024") |
| | | @PreAuthorize("@ss.hasPermission('research:guideline:query')") |
| | | public CommonResult<ResearchGuidelineRespVO> getGuideline(@RequestParam("id") Long id) { |
| | | return success(buildGuidelineDetail(guidelineService.getGuideline(id))); |
| | | } |
| | | |
| | | @GetMapping("/page") |
| | | @Operation(summary = "è·å¾è¯¾é¢æåå页") |
| | | @PreAuthorize("@ss.hasPermission('research:guideline:query')") |
| | | public CommonResult<PageResult<ResearchGuidelineRespVO>> getGuidelinePage( |
| | | @Valid ResearchGuidelinePageReqVO pageReqVO) { |
| | | PageResult<ResearchGuidelineDO> pageResult = guidelineService.getGuidelinePage(pageReqVO); |
| | | return success(new PageResult<>(buildGuidelineDetailList(pageResult.getList()), pageResult.getTotal())); |
| | | } |
| | | |
| | | @GetMapping("/published-list") |
| | | @Operation(summary = "è·å¾å·²åå¸çè¯¾é¢æåå表ï¼ä¾ç³æ¥éæåï¼") |
| | | @PreAuthorize("@ss.hasPermission('research:guideline:query')") |
| | | public CommonResult<List<ResearchGuidelineRespVO>> getPublishedGuidelineList() { |
| | | return success(buildGuidelineDetailList(guidelineService.getPublishedGuidelineList())); |
| | | } |
| | | |
| | | @PutMapping("/publish") |
| | | @Operation(summary = "åå¸è¯¾é¢æå") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('research:guideline:publish')") |
| | | public CommonResult<Boolean> publishGuideline(@RequestParam("id") Long id) { |
| | | guidelineService.publishGuideline(id); |
| | | return success(true); |
| | | } |
| | | |
| | | @PutMapping("/close") |
| | | @Operation(summary = "æªæ¢è¯¾é¢æå") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('research:guideline:publish')") |
| | | public CommonResult<Boolean> closeGuideline(@RequestParam("id") Long id) { |
| | | guidelineService.closeGuideline(id); |
| | | return success(true); |
| | | } |
| | | |
| | | // ==================== å
鍿¹æ³ ==================== |
| | | |
| | | private ResearchGuidelineRespVO buildGuidelineDetail(ResearchGuidelineDO guideline) { |
| | | if (guideline == null) { |
| | | return null; |
| | | } |
| | | return buildGuidelineDetailList(Collections.singletonList(guideline)).get(0); |
| | | } |
| | | |
| | | private List<ResearchGuidelineRespVO> buildGuidelineDetailList(List<ResearchGuidelineDO> list) { |
| | | if (CollUtil.isEmpty(list)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | // 1.1 è·åå建人 |
| | | Set<Long> creatorIds = convertSet(list, guideline -> NumberUtils.parseLong(guideline.getCreator())); |
| | | Map<Long, AdminUserRespDTO> creatorMap = adminUserApi.getUserMap(creatorIds); |
| | | // 1.2 è·åéä»¶ |
| | | Map<Long, List<StorageBlobRespDTO>> attachmentMap = list.stream() |
| | | .collect(Collectors.toMap(ResearchGuidelineDO::getId, |
| | | r -> storageAttachmentApi.listAttachments(GUIDELINE_RECORD_TYPE, r.getId()))); |
| | | |
| | | // 2. æ¼æ¥ç»æ |
| | | return BeanUtils.toBean(list, ResearchGuidelineRespVO.class, (vo) -> { |
| | | findAndThen(creatorMap, NumberUtils.parseLong(vo.getCreator()), |
| | | user -> vo.setCreatorName(user.getNickname())); |
| | | List<StorageBlobRespDTO> attachments = attachmentMap.getOrDefault(vo.getId(), Collections.emptyList()); |
| | | vo.setAttachmentList(attachments); |
| | | vo.setHasAttachment(CollUtil.isNotEmpty(attachments)); |
| | | }); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.controller.admin.guideline.vo; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | @Schema(description = "管çåå° - è¯¾é¢æåå页 Request VO") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | public class ResearchGuidelinePageReqVO extends PageParam { |
| | | |
| | | @Schema(description = "æåç¼å·", example = "GL20260928000001") |
| | | private String no; |
| | | |
| | | @Schema(description = "æååç§°", example = "2026年度å¦ä¼ç§ç è¯¾é¢æå") |
| | | private String title; |
| | | |
| | | @Schema(description = "课é¢ç±»å«", example = "1") |
| | | private Integer category; |
| | | |
| | | @Schema(description = "åå¸ç¶æ", example = "20") |
| | | private Integer publishStatus; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.controller.admin.guideline.vo; |
| | | |
| | | import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - è¯¾é¢æå Response VO") |
| | | @Data |
| | | public class ResearchGuidelineRespVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "æåç¼å·", example = "GL20260928000001") |
| | | private String no; |
| | | |
| | | @Schema(description = "æååç§°", example = "2026年度å¦ä¼ç§ç è¯¾é¢æå") |
| | | private String title; |
| | | |
| | | @Schema(description = "课é¢ç±»å«ï¼1-éç¹è¯¾é¢ 2-ä¸è¬è¯¾é¢", example = "1") |
| | | private Integer category; |
| | | |
| | | @Schema(description = "ç³æ¥å¼å§æ¶é´") |
| | | private LocalDateTime applyStartTime; |
| | | |
| | | @Schema(description = "ç³æ¥æªæ¢æ¶é´") |
| | | private LocalDateTime applyEndTime; |
| | | |
| | | @Schema(description = "æåæ£æ") |
| | | private String content; |
| | | |
| | | @Schema(description = "åå¸ç¶æï¼0-è稿 20-å·²åå¸ 30-å·²æªæ¢", example = "0") |
| | | private Integer publishStatus; |
| | | |
| | | @Schema(description = "å叿¶é´") |
| | | private LocalDateTime publishTime; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | | @Schema(description = "å建è
") |
| | | private String creator; |
| | | |
| | | @Schema(description = "å建è
åç§°") |
| | | private String creatorName; |
| | | |
| | | @Schema(description = "å建æ¶é´") |
| | | private LocalDateTime createTime; |
| | | |
| | | @Schema(description = "éä»¶å表") |
| | | private List<StorageBlobRespDTO> attachmentList; |
| | | |
| | | @Schema(description = "æ¯å¦æéä»¶") |
| | | private Boolean hasAttachment; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.controller.admin.guideline.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotEmpty; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import lombok.Data; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| | | |
| | | @Schema(description = "管çåå° - è¯¾é¢æåæ°å¢/ä¿®æ¹ Request VO") |
| | | @Data |
| | | public class ResearchGuidelineSaveReqVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "æååç§°", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026年度å¦ä¼ç§ç è¯¾é¢æå") |
| | | @NotEmpty(message = "æååç§°ä¸è½ä¸ºç©º") |
| | | private String title; |
| | | |
| | | @Schema(description = "课é¢ç±»å«ï¼1-éç¹è¯¾é¢ 2-ä¸è¬è¯¾é¢", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "课é¢ç±»å«ä¸è½ä¸ºç©º") |
| | | private Integer category; |
| | | |
| | | @Schema(description = "ç³æ¥å¼å§æ¶é´", example = "2026-10-01 00:00:00") |
| | | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| | | private LocalDateTime applyStartTime; |
| | | |
| | | @Schema(description = "ç³æ¥æªæ¢æ¶é´", example = "2026-11-30 23:59:59") |
| | | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| | | private LocalDateTime applyEndTime; |
| | | |
| | | @Schema(description = "æåæ£æ") |
| | | private String content; |
| | | |
| | | @Schema(description = "夿³¨") |
| | | private String remark; |
| | | |
| | | @Schema(description = "éä»¶BlobIdå表") |
| | | private List<Long> blobIds; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.controller.admin.review; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.research.controller.admin.review.vo.ResearchTopicReviewRespVO; |
| | | import cn.iocoder.yudao.module.research.controller.admin.review.vo.ResearchTopicReviewSaveReqVO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.review.ResearchTopicReviewDO; |
| | | import cn.iocoder.yudao.module.research.service.review.ResearchTopicReviewService; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.annotation.Resource; |
| | | import jakarta.validation.Valid; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; |
| | | |
| | | @Tag(name = "管çåå° - ä¸å®¶è¯å®¡æç»") |
| | | @RestController |
| | | @RequestMapping("/research/topic-review") |
| | | @Validated |
| | | public class ResearchTopicReviewController { |
| | | |
| | | @Resource |
| | | private ResearchTopicReviewService reviewService; |
| | | |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | |
| | | @PostMapping("/create") |
| | | @Operation(summary = "å½å
¥ä¸å®¶è¯å®¡æç»") |
| | | @PreAuthorize("@ss.hasPermission('research:review:create')") |
| | | public CommonResult<Long> createReview(@Valid @RequestBody ResearchTopicReviewSaveReqVO createReqVO) { |
| | | return success(reviewService.createReview(createReqVO)); |
| | | } |
| | | |
| | | @PutMapping("/update") |
| | | @Operation(summary = "æ´æ°ä¸å®¶è¯å®¡æç»") |
| | | @PreAuthorize("@ss.hasPermission('research:review:update')") |
| | | public CommonResult<Boolean> updateReview(@Valid @RequestBody ResearchTopicReviewSaveReqVO updateReqVO) { |
| | | reviewService.updateReview(updateReqVO); |
| | | return success(true); |
| | | } |
| | | |
| | | @DeleteMapping("/delete") |
| | | @Operation(summary = "å é¤ä¸å®¶è¯å®¡æç»") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('research:review:delete')") |
| | | public CommonResult<Boolean> deleteReview(@RequestParam("id") Long id) { |
| | | reviewService.deleteReview(id); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/list") |
| | | @Operation(summary = "è·å¾æè¯¾é¢ç³æ¥ä¹¦çä¸å®¶è¯å®¡æç»å表") |
| | | @Parameter(name = "applicationId", description = "课é¢ç³æ¥ä¹¦ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('research:review:query')") |
| | | public CommonResult<List<ResearchTopicReviewRespVO>> getReviewList( |
| | | @RequestParam("applicationId") Long applicationId) { |
| | | List<ResearchTopicReviewDO> list = reviewService.getReviewListByApplicationId(applicationId); |
| | | if (CollUtil.isEmpty(list)) { |
| | | return success(Collections.emptyList()); |
| | | } |
| | | Map<Long, AdminUserRespDTO> creatorMap = adminUserApi.getUserMap( |
| | | convertSet(list, review -> NumberUtils.parseLong(review.getCreator()))); |
| | | return success(BeanUtils.toBean(list, ResearchTopicReviewRespVO.class, (vo) -> |
| | | findAndThen(creatorMap, NumberUtils.parseLong(vo.getCreator()), |
| | | user -> vo.setCreatorName(user.getNickname())))); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.controller.admin.review.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Schema(description = "管çåå° - ä¸å®¶è¯å®¡æç» Response VO") |
| | | @Data |
| | | public class ResearchTopicReviewRespVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "课é¢ç³æ¥ä¹¦ ID", example = "1") |
| | | private Long applicationId; |
| | | |
| | | @Schema(description = "ä¸å®¶å§å", example = "æå") |
| | | private String evaluatorName; |
| | | |
| | | @Schema(description = "ä¸å®¶æå¨åä½", example = "XX大å¦") |
| | | private String evaluatorUnit; |
| | | |
| | | @Schema(description = "ä¸å®¶èç§°", example = "ææ") |
| | | private String evaluatorTitle; |
| | | |
| | | @Schema(description = "éé¢ä»·å¼ä¸æä¹å¾å", example = "85.00") |
| | | private BigDecimal topicScore; |
| | | |
| | | @Schema(description = "ç ç©¶æ¹æ¡å¯è¡æ§å¾å", example = "90.00") |
| | | private BigDecimal planScore; |
| | | |
| | | @Schema(description = "å¢éä¸ç ç©¶åºç¡å¾å", example = "80.00") |
| | | private BigDecimal teamScore; |
| | | |
| | | @Schema(description = "颿ææä¸æçå¾å", example = "75.00") |
| | | private BigDecimal resultScore; |
| | | |
| | | @Schema(description = "å æå计å¾åï¼å端计ç®ï¼", example = "84.00") |
| | | private BigDecimal compositeScore; |
| | | |
| | | @Schema(description = "æ¬ç³æ¥åå
è¯åæåï¼å端计ç®ï¼", example = "1") |
| | | private Integer ranking; |
| | | |
| | | @Schema(description = "è¯å®¡ç»è®ºï¼1-æ¨èç«é¡¹ 2-䏿¨èç«é¡¹", example = "1") |
| | | private Integer conclusion; |
| | | |
| | | @Schema(description = "è¯å®¡æè§", example = "建议ç«é¡¹æ¯æ") |
| | | private String opinion; |
| | | |
| | | @Schema(description = "è¯å®¡æ¶é´") |
| | | private LocalDateTime reviewTime; |
| | | |
| | | @Schema(description = "å建è
") |
| | | private String creator; |
| | | |
| | | @Schema(description = "å建è
åç§°") |
| | | private String creatorName; |
| | | |
| | | @Schema(description = "å建æ¶é´") |
| | | private LocalDateTime createTime; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.controller.admin.review.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotEmpty; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | @Schema(description = "管çåå° - ä¸å®¶è¯å®¡æç»æ°å¢/ä¿®æ¹ Request VO") |
| | | @Data |
| | | public class ResearchTopicReviewSaveReqVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "课é¢ç³æ¥ä¹¦ ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "课é¢ç³æ¥ä¹¦ä¸è½ä¸ºç©º") |
| | | private Long applicationId; |
| | | |
| | | @Schema(description = "ä¸å®¶å§å", requiredMode = Schema.RequiredMode.REQUIRED, example = "æå") |
| | | @NotEmpty(message = "ä¸å®¶å§åä¸è½ä¸ºç©º") |
| | | private String evaluatorName; |
| | | |
| | | @Schema(description = "ä¸å®¶æå¨åä½", example = "XX大å¦") |
| | | private String evaluatorUnit; |
| | | |
| | | @Schema(description = "ä¸å®¶èç§°", example = "ææ") |
| | | private String evaluatorTitle; |
| | | |
| | | @Schema(description = "éé¢ä»·å¼ä¸æä¹å¾åï¼0~100ï¼æé0.3ï¼", example = "85.00") |
| | | private BigDecimal topicScore; |
| | | |
| | | @Schema(description = "ç ç©¶æ¹æ¡å¯è¡æ§å¾åï¼0~100ï¼æé0.3ï¼", example = "90.00") |
| | | private BigDecimal planScore; |
| | | |
| | | @Schema(description = "å¢éä¸ç ç©¶åºç¡å¾åï¼0~100ï¼æé0.2ï¼", example = "80.00") |
| | | private BigDecimal teamScore; |
| | | |
| | | @Schema(description = "颿ææä¸æçå¾åï¼0~100ï¼æé0.2ï¼", example = "75.00") |
| | | private BigDecimal resultScore; |
| | | |
| | | @Schema(description = "è¯å®¡ç»è®ºï¼1-æ¨èç«é¡¹ 2-䏿¨èç«é¡¹", example = "1") |
| | | private Integer conclusion; |
| | | |
| | | @Schema(description = "è¯å®¡æè§", example = "éé¢ç¬¦åå¦ä¼å¹´åº¦æ¹åï¼æ¹æ¡å¯è¡ï¼å»ºè®®ç«é¡¹æ¯æ") |
| | | private String opinion; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.dal.dataobject.application; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import lombok.*; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * 课é¢-ç³æ¥ä¹¦ DO |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @TableName("research_application") |
| | | @KeySequence("research_application_seq") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class ResearchApplicationDO extends BaseDO { |
| | | |
| | | @TableId |
| | | private Long id; |
| | | |
| | | /** ç³æ¥ç¼å· */ |
| | | private String no; |
| | | |
| | | /** æå±è¯¾é¢æå ID */ |
| | | private Long guidelineId; |
| | | |
| | | /** 课é¢åç§° */ |
| | | private String title; |
| | | |
| | | /** 课é¢ç±»å«ï¼1-éç¹è¯¾é¢ 2-ä¸è¬è¯¾é¢ï¼åä½èªæåï¼ */ |
| | | private Integer category; |
| | | |
| | | /** ç³æ¥ä¼å IDï¼å
³è ums_memberï¼ */ |
| | | private Long memberId; |
| | | |
| | | /** ç³æ¥äººå§å/åä½åç§° */ |
| | | private String applicantName; |
| | | |
| | | /** ç³æ¥ç»å½ç¨æ· ID */ |
| | | private Long applicantUserId; |
| | | |
| | | /** å·¥ä½åä½ */ |
| | | private String workUnit; |
| | | |
| | | /** èç§° */ |
| | | private String jobTitle; |
| | | |
| | | /** èç³»çµè¯ */ |
| | | private String contactPhone; |
| | | |
| | | /** èç³»é®ç®± */ |
| | | private String contactEmail; |
| | | |
| | | /** 课é¢ç»æåï¼æ¯è¡ä¸æ¡ï¼å§å|åä½|èç§°ï¼ */ |
| | | private String teamMembers; |
| | | |
| | | /** ç³è¯·ç»è´¹ï¼å
ï¼ */ |
| | | private BigDecimal budgetAmount; |
| | | |
| | | /** ç³æ¥ä¹¦æ£æ */ |
| | | private String planContent; |
| | | |
| | | /** ç¶æï¼0-è稿 15-审æ¹ä¸ 20-å·²ç«é¡¹ 35-已驳å */ |
| | | private Integer status; |
| | | |
| | | /** BPM æµç¨å®ä¾ ID */ |
| | | private String processInstanceId; |
| | | |
| | | /** ä¸å®¶è¯å®¡å æååï¼åç«¯æ±æ»ï¼ */ |
| | | private BigDecimal reviewAvgScore; |
| | | |
| | | /** è¯å®¡ç»è®ºï¼0-æªéè¿ 1-æ¨èç«é¡¹ï¼åç«¯æ±æ»ï¼ */ |
| | | private Integer reviewPass; |
| | | |
| | | /** ç«é¡¹ç¼å·ï¼å®¡æ¹éè¿åçæï¼ */ |
| | | private String researchNo; |
| | | |
| | | /** ç«é¡¹æ¶é´ */ |
| | | private LocalDateTime approveTime; |
| | | |
| | | /** å·²åå¸çç«é¡¹éç¥å
Œ ID */ |
| | | private Long noticeId; |
| | | |
| | | /** 夿³¨ */ |
| | | private String remark; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.dal.dataobject.fund; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import lombok.*; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | |
| | | /** |
| | | * 课é¢-ç»è´¹æ¨ä»è®°å½ DO |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @TableName("research_fund_record") |
| | | @KeySequence("research_fund_record_seq") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class ResearchFundRecordDO extends BaseDO { |
| | | |
| | | @TableId |
| | | private Long id; |
| | | |
| | | /** 课é¢ç³æ¥ä¹¦ ID */ |
| | | private Long applicationId; |
| | | |
| | | /** æ¨ä»æ¹æ¬¡ï¼å¦ï¼ç¬¬ä¸æï¼ */ |
| | | private String batchName; |
| | | |
| | | /** æ¨ä»éé¢ï¼å
ï¼ */ |
| | | private BigDecimal amount; |
| | | |
| | | /** æ¨ä»æ¥æ */ |
| | | private LocalDate payDate; |
| | | |
| | | /** æ¶æ¬¾åä½/è´¦æ·å */ |
| | | private String payee; |
| | | |
| | | /** ç¶æï¼0-å¾
æ¨ä» 20-å·²æ¨ä» */ |
| | | private Integer status; |
| | | |
| | | /** 夿³¨ */ |
| | | private String remark; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.dal.dataobject.guideline; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import lombok.*; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * 课é¢-æå DO |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @TableName("research_guideline") |
| | | @KeySequence("research_guideline_seq") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class ResearchGuidelineDO extends BaseDO { |
| | | |
| | | @TableId |
| | | private Long id; |
| | | |
| | | /** æåç¼å· */ |
| | | private String no; |
| | | |
| | | /** æååç§° */ |
| | | private String title; |
| | | |
| | | /** 课é¢ç±»å«ï¼1-éç¹è¯¾é¢ 2-ä¸è¬è¯¾é¢ */ |
| | | private Integer category; |
| | | |
| | | /** ç³æ¥å¼å§æ¶é´ */ |
| | | private LocalDateTime applyStartTime; |
| | | |
| | | /** ç³æ¥æªæ¢æ¶é´ */ |
| | | private LocalDateTime applyEndTime; |
| | | |
| | | /** æåæ£æ */ |
| | | private String content; |
| | | |
| | | /** åå¸ç¶æï¼0-è稿 20-å·²åå¸ 30-å·²æªæ¢ */ |
| | | private Integer publishStatus; |
| | | |
| | | /** å叿¶é´ */ |
| | | private LocalDateTime publishTime; |
| | | |
| | | /** 夿³¨ */ |
| | | private String remark; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.dal.dataobject.review; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import lombok.*; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * 课é¢-ä¸å®¶è¯å®¡æç» DO |
| | | * |
| | | * ä¸ä¸»åï¼è¯¾é¢ç³æ¥ä¹¦ï¼æå¤è¡ï¼æ¯è¡ä¸ä½ä¸å®¶ |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @TableName("research_topic_review") |
| | | @KeySequence("research_topic_review_seq") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class ResearchTopicReviewDO extends BaseDO { |
| | | |
| | | @TableId |
| | | private Long id; |
| | | |
| | | /** 课é¢ç³æ¥ä¹¦ ID */ |
| | | private Long applicationId; |
| | | |
| | | /** ä¸å®¶å§å */ |
| | | private String evaluatorName; |
| | | |
| | | /** ä¸å®¶æå¨åä½ */ |
| | | private String evaluatorUnit; |
| | | |
| | | /** ä¸å®¶èç§° */ |
| | | private String evaluatorTitle; |
| | | |
| | | /** éé¢ä»·å¼ä¸æä¹å¾åï¼æé 0.3ï¼ */ |
| | | private BigDecimal topicScore; |
| | | |
| | | /** ç ç©¶æ¹æ¡å¯è¡æ§å¾åï¼æé 0.3ï¼ */ |
| | | private BigDecimal planScore; |
| | | |
| | | /** å¢éä¸ç ç©¶åºç¡å¾åï¼æé 0.2ï¼ */ |
| | | private BigDecimal teamScore; |
| | | |
| | | /** 颿ææä¸æçå¾åï¼æé 0.2ï¼ */ |
| | | private BigDecimal resultScore; |
| | | |
| | | /** å æå计å¾åï¼å端计ç®ï¼ */ |
| | | private BigDecimal compositeScore; |
| | | |
| | | /** æ¬ç³æ¥åå
è¯åæåï¼å端计ç®ï¼ */ |
| | | private Integer ranking; |
| | | |
| | | /** è¯å®¡ç»è®ºï¼1-æ¨èç«é¡¹ 2-䏿¨èç«é¡¹ */ |
| | | private Integer conclusion; |
| | | |
| | | /** è¯å®¡æè§ */ |
| | | private String opinion; |
| | | |
| | | /** è¯å®¡æ¶é´ */ |
| | | private LocalDateTime reviewTime; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.dal.mysql.application; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.research.controller.admin.application.vo.ResearchApplicationPageReqVO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.application.ResearchApplicationDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | @Mapper |
| | | public interface ResearchApplicationMapper extends BaseMapperX<ResearchApplicationDO> { |
| | | |
| | | default ResearchApplicationDO selectByNo(String no) { |
| | | return selectOne(ResearchApplicationDO::getNo, no); |
| | | } |
| | | |
| | | default PageResult<ResearchApplicationDO> selectPage(ResearchApplicationPageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<ResearchApplicationDO>() |
| | | .likeIfPresent(ResearchApplicationDO::getNo, reqVO.getNo()) |
| | | .likeIfPresent(ResearchApplicationDO::getTitle, reqVO.getTitle()) |
| | | .eqIfPresent(ResearchApplicationDO::getGuidelineId, reqVO.getGuidelineId()) |
| | | .eqIfPresent(ResearchApplicationDO::getCategory, reqVO.getCategory()) |
| | | .eqIfPresent(ResearchApplicationDO::getMemberId, reqVO.getMemberId()) |
| | | .eqIfPresent(ResearchApplicationDO::getStatus, reqVO.getStatus()) |
| | | .betweenIfPresent(ResearchApplicationDO::getCreateTime, reqVO.getCreateTime()) |
| | | .orderByDesc(ResearchApplicationDO::getId)); |
| | | } |
| | | |
| | | /** æè¯¾é¢æåä¸çç³æ¥åæ°éï¼ç¨äºå 餿ååçå ç¨æ ¡éªï¼ */ |
| | | default Long selectCountByGuidelineId(Long guidelineId) { |
| | | return selectCount(ResearchApplicationDO::getGuidelineId, guidelineId); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.dal.mysql.fund; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.fund.ResearchFundRecordDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | public interface ResearchFundRecordMapper extends BaseMapperX<ResearchFundRecordDO> { |
| | | |
| | | default List<ResearchFundRecordDO> selectListByApplicationId(Long applicationId) { |
| | | return selectList(ResearchFundRecordDO::getApplicationId, applicationId); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.dal.mysql.guideline; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.research.controller.admin.guideline.vo.ResearchGuidelinePageReqVO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.guideline.ResearchGuidelineDO; |
| | | import cn.iocoder.yudao.module.research.enums.ResearchGuidelineStatusEnum; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | public interface ResearchGuidelineMapper extends BaseMapperX<ResearchGuidelineDO> { |
| | | |
| | | default ResearchGuidelineDO selectByNo(String no) { |
| | | return selectOne(ResearchGuidelineDO::getNo, no); |
| | | } |
| | | |
| | | default PageResult<ResearchGuidelineDO> selectPage(ResearchGuidelinePageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<ResearchGuidelineDO>() |
| | | .likeIfPresent(ResearchGuidelineDO::getNo, reqVO.getNo()) |
| | | .likeIfPresent(ResearchGuidelineDO::getTitle, reqVO.getTitle()) |
| | | .eqIfPresent(ResearchGuidelineDO::getCategory, reqVO.getCategory()) |
| | | .eqIfPresent(ResearchGuidelineDO::getPublishStatus, reqVO.getPublishStatus()) |
| | | .orderByDesc(ResearchGuidelineDO::getId)); |
| | | } |
| | | |
| | | /** å·²åå¸ï¼å¯ç³æ¥ï¼çæåå表ï¼ä¾ç³æ¥åéæ©æåä½¿ç¨ */ |
| | | default List<ResearchGuidelineDO> selectPublishedList() { |
| | | return selectList(new LambdaQueryWrapperX<ResearchGuidelineDO>() |
| | | .eq(ResearchGuidelineDO::getPublishStatus, ResearchGuidelineStatusEnum.PUBLISHED.getStatus()) |
| | | .orderByDesc(ResearchGuidelineDO::getId)); |
| | | } |
| | | |
| | | /** æ id éåæ¹éæ¥è¯¢ï¼ç³æ¥ååè¡¨åæ¾æååç§°ç¨ï¼ */ |
| | | default List<ResearchGuidelineDO> selectListByIds(Collection<Long> ids) { |
| | | return CollUtil.isEmpty(ids) ? Collections.emptyList() |
| | | : selectList(ResearchGuidelineDO::getId, ids); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.dal.mysql.review; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.review.ResearchTopicReviewDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | public interface ResearchTopicReviewMapper extends BaseMapperX<ResearchTopicReviewDO> { |
| | | |
| | | default List<ResearchTopicReviewDO> selectListByApplicationId(Long applicationId) { |
| | | return selectList(ResearchTopicReviewDO::getApplicationId, applicationId); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.dal.redis; |
| | | |
| | | /** |
| | | * Research Redis Key 常é |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | public interface RedisKeyConstants { |
| | | |
| | | String NO = "research:seq_no:"; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.dal.redis; |
| | | |
| | | import cn.hutool.core.date.DatePattern; |
| | | import cn.hutool.core.date.DateUtil; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.data.redis.core.StringRedisTemplate; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | import java.time.Duration; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * Research ç¼å· Redis DAO |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Repository |
| | | public class ResearchNoRedisDAO { |
| | | |
| | | /** |
| | | * è¯¾é¢æå {@link cn.iocoder.yudao.module.research.dal.dataobject.guideline.ResearchGuidelineDO} |
| | | */ |
| | | public static final String GUIDELINE_NO_PREFIX = "GL"; |
| | | |
| | | /** |
| | | * 课é¢ç³æ¥ä¹¦ {@link cn.iocoder.yudao.module.research.dal.dataobject.application.ResearchApplicationDO} |
| | | */ |
| | | public static final String APPLICATION_NO_PREFIX = "SB"; |
| | | |
| | | /** |
| | | * ç«é¡¹ç¼å·ï¼è¯¾é¢ç³æ¥ä¹¦å®¡æ¹éè¿åçæï¼ |
| | | */ |
| | | public static final String PROJECT_NO_PREFIX = "LX"; |
| | | |
| | | @Resource |
| | | private StringRedisTemplate stringRedisTemplate; |
| | | |
| | | public String generate(String prefix) { |
| | | String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN); |
| | | String key = RedisKeyConstants.NO + noPrefix; |
| | | Long no = stringRedisTemplate.opsForValue().increment(key); |
| | | stringRedisTemplate.expire(key, Duration.ofDays(1L)); |
| | | return noPrefix + String.format("%06d", no); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.enums; |
| | | |
| | | /** |
| | | * Research åå
¸ç±»å常é |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | public interface DictTypeConstants { |
| | | |
| | | /** è¯¾é¢æåç±»å«ï¼éç¹/ä¸è¬ */ |
| | | String GUIDELINE_CATEGORY = "research_guideline_category"; |
| | | |
| | | /** è¯¾é¢æååå¸ç¶æ */ |
| | | String GUIDELINE_STATUS = "research_guideline_status"; |
| | | |
| | | /** 课é¢ç³æ¥ä¹¦ç¶æ */ |
| | | String APPLICATION_STATUS = "research_application_status"; |
| | | |
| | | /** ä¸å®¶è¯å®¡ç»è®º */ |
| | | String REVIEW_CONCLUSION = "research_review_conclusion"; |
| | | |
| | | /** ç»è´¹æ¨ä»ç¶æ */ |
| | | String FUND_STATUS = "research_fund_status"; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.enums; |
| | | |
| | | import cn.iocoder.yudao.framework.common.exception.ErrorCode; |
| | | |
| | | /** |
| | | * Research éè¯¯ç æä¸¾ç±» |
| | | * |
| | | * research 模åï¼ä½¿ç¨ 1-030-109-000 段 |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | public interface ErrorCodeConstants { |
| | | |
| | | // ========== è¯¾é¢æå 1_030_109_000 ========== |
| | | ErrorCode GUIDELINE_NOT_EXISTS = new ErrorCode(1_030_109_000, "è¯¾é¢æåä¸åå¨"); |
| | | ErrorCode GUIDELINE_NO_EXISTS = new ErrorCode(1_030_109_001, "çææåç¼å·å¤±è´¥ï¼è¯·éæ°æäº¤"); |
| | | ErrorCode GUIDELINE_UPDATE_FAIL_NOT_DRAFT = new ErrorCode(1_030_109_002, "è¯¾é¢æå({})䏿¯èç¨¿ç¶æï¼æ æ³ä¿®æ¹"); |
| | | ErrorCode GUIDELINE_DELETE_FAIL_NOT_DRAFT = new ErrorCode(1_030_109_003, "è¯¾é¢æå({})䏿¯èç¨¿ç¶æï¼æ æ³å é¤"); |
| | | ErrorCode GUIDELINE_PUBLISH_FAIL_STATUS = new ErrorCode(1_030_109_004, "åå¸å¤±è´¥ï¼åªæèç¨¿ç¶æçè¯¾é¢æåæè½åå¸"); |
| | | ErrorCode GUIDELINE_CLOSE_FAIL_STATUS = new ErrorCode(1_030_109_005, "æªæ¢å¤±è´¥ï¼åªæå·²åå¸ç¶æçè¯¾é¢æåæè½æªæ¢"); |
| | | ErrorCode GUIDELINE_APPLY_TIME_INVALID = new ErrorCode(1_030_109_006, "ä¿å失败ï¼ç³æ¥æªæ¢æ¶é´({})ä¸è½æ©äºç³æ¥å¼å§æ¶é´({})ï¼è¯·éæ°éæ©ç³æ¥èµ·æ¢æ¶é´"); |
| | | ErrorCode GUIDELINE_HAS_APPLICATION = new ErrorCode(1_030_109_007, "å é¤å¤±è´¥ï¼è¯¾é¢æå({})ä¸å·²åå¨ {} 份课é¢ç³æ¥ä¹¦ï¼è¯·å
å¤çè¿äºç³æ¥ä¹¦ååå 餿å"); |
| | | |
| | | // ========== 课é¢ç³æ¥ä¹¦ 1_030_109_100 ========== |
| | | ErrorCode APPLICATION_NOT_EXISTS = new ErrorCode(1_030_109_100, "课é¢ç³æ¥ä¹¦ä¸åå¨"); |
| | | ErrorCode APPLICATION_NO_EXISTS = new ErrorCode(1_030_109_101, "çæç³æ¥ç¼å·å¤±è´¥ï¼è¯·éæ°æäº¤"); |
| | | ErrorCode APPLICATION_UPDATE_FAIL_NOT_DRAFT = new ErrorCode(1_030_109_102, "课é¢ç³æ¥ä¹¦({})å½åç¶æä¸ºã{}ãï¼åªæè稿æå·²é©³åç¶ææè½ä¿®æ¹"); |
| | | ErrorCode APPLICATION_DELETE_FAIL_NOT_DRAFT = new ErrorCode(1_030_109_103, "å é¤å¤±è´¥ï¼è¯¾é¢ç³æ¥ä¹¦({})å½åç¶æä¸ºã{}ãï¼åªæèç¨¿ç¶ææè½å é¤"); |
| | | ErrorCode APPLICATION_SUBMIT_FAIL_STATUS = new ErrorCode(1_030_109_104, "æäº¤å®¡æ¹å¤±è´¥ï¼è¯¾é¢ç³æ¥ä¹¦({})å½åç¶æä¸ºã{}ãï¼åªæè稿æå·²é©³åç¶ææè½æäº¤"); |
| | | ErrorCode APPLICATION_BPM_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_109_105, "课é¢ç«é¡¹å®¡æ¹æµç¨åç±»ä¸åå¨ï¼è¯·å
å¨BPM模åå建课é¢ç«é¡¹å®¡æ¹æµç¨åç±»"); |
| | | ErrorCode APPLICATION_SUBMIT_FAIL_GUIDELINE_STATUS = new ErrorCode(1_030_109_106, "æäº¤å¤±è´¥ï¼æå±è¯¾é¢æåã{}ãå½åç¶æä¸ºã{}ãï¼åªæå·²åå¸çæåæè½æäº¤ç³æ¥ï¼è¯·èç³»ç§ä¹¦å¤ç¡®è®¤æåå叿
åµ"); |
| | | ErrorCode APPLICATION_SUBMIT_FAIL_NOT_IN_PERIOD = new ErrorCode(1_030_109_107, "æäº¤å¤±è´¥ï¼å½åæ¶é´({})ä¸å¨è¯¾é¢æåã{}ãçç³æ¥æå
ï¼{} è³ {}ï¼ï¼è¯·èç³»ç§ä¹¦å¤ç¡®è®¤ç³æ¥æ¶é´"); |
| | | ErrorCode APPLICATION_CREATE_FAIL_GUIDELINE_STATUS = new ErrorCode(1_030_109_108, "ä¿åå¤±è´¥ï¼æéè¯¾é¢æåã{}ãå½åç¶æä¸ºã{}ãï¼åªæå·²åå¸çæåæè½ç³æ¥ï¼è¯·éæ°éæ©æå"); |
| | | ErrorCode APPLICATION_PUBLISH_NOTICE_FAIL_STATUS = new ErrorCode(1_030_109_109, "åå¸ç«é¡¹éç¥å¤±è´¥ï¼è¯¾é¢ç³æ¥ä¹¦({})å½åç¶æä¸ºã{}ãï¼åªæå·²ç«é¡¹çè¯¾é¢æè½åå¸ç«é¡¹éç¥"); |
| | | ErrorCode APPLICATION_NOTICE_EXISTS = new ErrorCode(1_030_109_110, "åå¸å¤±è´¥ï¼è¯¥è¯¾é¢({})çç«é¡¹éç¥å·²äº {} åå¸ï¼è¯·å¿éå¤åå¸"); |
| | | ErrorCode APPLICATION_MEMBER_NOT_EXISTS = new ErrorCode(1_030_109_111, "ä¿åå¤±è´¥ï¼æéç³æ¥ä¼å(ID={})å·²ä¸åå¨ï¼è¯·éæ°ä»ä¼ååè¡¨éæ©ç³æ¥äºº"); |
| | | |
| | | // ========== ä¸å®¶è¯å®¡æç» 1_030_109_200 ========== |
| | | ErrorCode REVIEW_NOT_EXISTS = new ErrorCode(1_030_109_200, "ä¸å®¶è¯å®¡è®°å½ä¸åå¨"); |
| | | ErrorCode REVIEW_CREATE_FAIL_STATUS = new ErrorCode(1_030_109_201, "å½å
¥å¤±è´¥ï¼è¯¾é¢ç³æ¥ä¹¦({})å½åç¶æä¸ºã{}ãï¼åªæå®¡æ¹ä¸çç³æ¥ä¹¦æè½å½å
¥ä¸å®¶è¯å®¡"); |
| | | ErrorCode REVIEW_UPDATE_FAIL_STATUS = new ErrorCode(1_030_109_202, "æ´æ°å¤±è´¥ï¼è¯¾é¢ç³æ¥ä¹¦({})å½åç¶æä¸ºã{}ãï¼åªæå®¡æ¹ä¸çç³æ¥ä¹¦æè½ä¿®æ¹ä¸å®¶è¯å®¡"); |
| | | ErrorCode REVIEW_DELETE_FAIL_STATUS = new ErrorCode(1_030_109_203, "å é¤å¤±è´¥ï¼è¯¾é¢ç³æ¥ä¹¦({})å½åç¶æä¸ºã{}ãï¼åªæå®¡æ¹ä¸çç³æ¥ä¹¦æè½å é¤ä¸å®¶è¯å®¡"); |
| | | ErrorCode REVIEW_SCORE_OUT_OF_RANGE = new ErrorCode(1_030_109_204, "å½å
¥å¤±è´¥ï¼{}å¾å为 {}ï¼è¶
åº 0~100 çå
许èå´ï¼è¯·ä¿®æ£åéæ°æäº¤"); |
| | | |
| | | // ========== ç»è´¹æ¨ä»è®°å½ 1_030_109_300 ========== |
| | | ErrorCode FUND_NOT_EXISTS = new ErrorCode(1_030_109_300, "ç»è´¹æ¨ä»è®°å½ä¸åå¨"); |
| | | ErrorCode FUND_RECORD_FAIL_STATUS = new ErrorCode(1_030_109_301, "ç»è®°å¤±è´¥ï¼è¯¾é¢ç³æ¥ä¹¦({})å½åç¶æä¸ºã{}ãï¼åªæå·²ç«é¡¹çè¯¾é¢æè½ç»è®°ç»è´¹æ¨ä»"); |
| | | ErrorCode FUND_AMOUNT_EXCEEDED = new ErrorCode(1_030_109_302, "ç»è®°å¤±è´¥ï¼æ¬æ¬¡æ¨ä» {} å
ï¼å·²ç»è®° {} å
ï¼å计 {} å
ï¼è¶
åºè¯¥è¯¾é¢ç³è¯·é¢ç® {} å
ï¼è¯·è°ä½æ¬æ¬¡æ¨ä»éé¢"); |
| | | ErrorCode FUND_VOUCHER_REQUIRED = new ErrorCode(1_030_109_303, "ç»è®°å¤±è´¥ï¼ç¶æä¸ºãå·²æ¨ä»ãæ¶å¿
é¡»ä¸ä¼ åè¯éä»¶ï¼è¯·å
ä¸ä¼ åè¯éä»¶ååä¿å"); |
| | | ErrorCode FUND_UPDATE_FAIL_STATUS = new ErrorCode(1_030_109_304, "æ´æ°å¤±è´¥ï¼ç»è´¹æ¨ä»è®°å½({})å½åç¶æä¸ºã{}ãï¼åªæå¾
æ¨ä»ç¶ææè½ä¿®æ¹"); |
| | | ErrorCode FUND_DELETE_FAIL_STATUS = new ErrorCode(1_030_109_305, "å é¤å¤±è´¥ï¼ç»è´¹æ¨ä»è®°å½({})å½åç¶æä¸ºã{}ãï¼åªæå¾
æ¨ä»ç¶ææè½å é¤"); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.enums; |
| | | |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * 课é¢ç³æ¥ä¹¦ç¶ææä¸¾ |
| | | * |
| | | * ä¸ä»åºæ¢æåæ®ï¼å
¥ä¼ç³è¯·ãæ¥éåï¼ä¿æä¸è´çç¶ææºåå¼ |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum ResearchApplicationStatusEnum { |
| | | |
| | | DRAFT(0, "è稿"), |
| | | APPROVING(15, "审æ¹ä¸"), |
| | | APPROVED(20, "å·²ç«é¡¹"), |
| | | REJECTED(35, "已驳å"), |
| | | ; |
| | | |
| | | private final Integer status; |
| | | private final String name; |
| | | |
| | | public static ResearchApplicationStatusEnum valueOf(Integer status) { |
| | | return ArrayUtil.firstMatch(e -> e.getStatus().equals(status), values()); |
| | | } |
| | | |
| | | /** æç¶æå¼å䏿åï¼æªå¹é
æ¶åéåå§å¼ï¼ä¾¿äºé误æç¤ºå¯è¯» */ |
| | | public static String nameOf(Integer status) { |
| | | ResearchApplicationStatusEnum item = valueOf(status); |
| | | return item != null ? item.getName() : String.valueOf(status); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.enums; |
| | | |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * ç»è´¹æ¨ä»ç¶ææä¸¾ |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum ResearchFundStatusEnum { |
| | | |
| | | PENDING(0, "å¾
æ¨ä»"), |
| | | PAID(20, "å·²æ¨ä»"), |
| | | ; |
| | | |
| | | private final Integer status; |
| | | private final String name; |
| | | |
| | | public static ResearchFundStatusEnum valueOf(Integer status) { |
| | | return ArrayUtil.firstMatch(e -> e.getStatus().equals(status), values()); |
| | | } |
| | | |
| | | /** æç¶æå¼å䏿åï¼æªå¹é
æ¶åéåå§å¼ï¼ä¾¿äºé误æç¤ºå¯è¯» */ |
| | | public static String nameOf(Integer status) { |
| | | ResearchFundStatusEnum item = valueOf(status); |
| | | return item != null ? item.getName() : String.valueOf(status); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.enums; |
| | | |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * è¯¾é¢æåç±»å«æä¸¾ï¼éç¹/ä¸è¬åç±»æ æ³¨ï¼ |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum ResearchGuidelineCategoryEnum { |
| | | |
| | | KEY(1, "éç¹è¯¾é¢"), |
| | | GENERAL(2, "ä¸è¬è¯¾é¢"), |
| | | ; |
| | | |
| | | private final Integer category; |
| | | private final String name; |
| | | |
| | | public static ResearchGuidelineCategoryEnum valueOf(Integer category) { |
| | | return ArrayUtil.firstMatch(e -> e.getCategory().equals(category), values()); |
| | | } |
| | | |
| | | /** æç±»å«å¼å䏿åï¼æªå¹é
æ¶åéåå§å¼ï¼ä¾¿äºé误æç¤ºå¯è¯» */ |
| | | public static String nameOf(Integer category) { |
| | | ResearchGuidelineCategoryEnum item = valueOf(category); |
| | | return item != null ? item.getName() : String.valueOf(category); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.enums; |
| | | |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * è¯¾é¢æååå¸ç¶ææä¸¾ |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum ResearchGuidelineStatusEnum { |
| | | |
| | | DRAFT(0, "è稿"), |
| | | PUBLISHED(20, "å·²åå¸"), |
| | | CLOSED(30, "å·²æªæ¢"), |
| | | ; |
| | | |
| | | private final Integer status; |
| | | private final String name; |
| | | |
| | | public static ResearchGuidelineStatusEnum valueOf(Integer status) { |
| | | return ArrayUtil.firstMatch(e -> e.getStatus().equals(status), values()); |
| | | } |
| | | |
| | | /** æç¶æå¼å䏿åï¼æªå¹é
æ¶åéåå§å¼ï¼ä¾¿äºé误æç¤ºå¯è¯» */ |
| | | public static String nameOf(Integer status) { |
| | | ResearchGuidelineStatusEnum item = valueOf(status); |
| | | return item != null ? item.getName() : String.valueOf(status); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.enums; |
| | | |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * ä¸å®¶è¯å®¡ç»è®ºæä¸¾ |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum ResearchReviewConclusionEnum { |
| | | |
| | | RECOMMEND(1, "æ¨èç«é¡¹"), |
| | | REJECT(2, "䏿¨èç«é¡¹"), |
| | | ; |
| | | |
| | | private final Integer conclusion; |
| | | private final String name; |
| | | |
| | | public static ResearchReviewConclusionEnum valueOf(Integer conclusion) { |
| | | return ArrayUtil.firstMatch(e -> e.getConclusion().equals(conclusion), values()); |
| | | } |
| | | |
| | | /** æç»è®ºå¼å䏿åï¼æªå¹é
æ¶åéåå§å¼ï¼ä¾¿äºé误æç¤ºå¯è¯» */ |
| | | public static String nameOf(Integer conclusion) { |
| | | ResearchReviewConclusionEnum item = valueOf(conclusion); |
| | | return item != null ? item.getName() : String.valueOf(conclusion); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.framework.web.config; |
| | | |
| | | import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; |
| | | import org.springdoc.core.models.GroupedOpenApi; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | |
| | | @Configuration(proxyBeanMethods = false) |
| | | public class ResearchWebConfiguration { |
| | | |
| | | @Bean |
| | | public GroupedOpenApi researchGroupedOpenApi() { |
| | | return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("research"); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.service.application; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.research.controller.admin.application.vo.ResearchApplicationPageReqVO; |
| | | import cn.iocoder.yudao.module.research.controller.admin.application.vo.ResearchApplicationSaveReqVO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.application.ResearchApplicationDO; |
| | | |
| | | import jakarta.validation.Valid; |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | public interface ResearchApplicationService { |
| | | |
| | | Long createApplication(@Valid ResearchApplicationSaveReqVO createReqVO); |
| | | |
| | | void updateApplication(@Valid ResearchApplicationSaveReqVO updateReqVO); |
| | | |
| | | void deleteApplication(Long id); |
| | | |
| | | ResearchApplicationDO getApplication(Long id); |
| | | |
| | | PageResult<ResearchApplicationDO> getApplicationPage(ResearchApplicationPageReqVO pageReqVO); |
| | | |
| | | void submitApplication(Long id, String processDefinitionKey); |
| | | |
| | | List<Map<String, Object>> getApproveProcessDefinitionList(); |
| | | |
| | | void updateApplicationAuditStatus(Long id, Integer bpmResult); |
| | | |
| | | /** 审æ¹éè¿åçæç«é¡¹ç¼å·ä¸ç«é¡¹æ¶é´ï¼å¹çï¼ */ |
| | | void approveApplication(Long id); |
| | | |
| | | /** åå¸ç«é¡¹éç¥ï¼çæç³»ç»å
¬åï¼é²éå¤ï¼ */ |
| | | void publishNotice(Long id); |
| | | |
| | | /** ä¸å®¶è¯å®¡æ±æ»ç»æåå主åï¼ç±è¯å®¡æå¡è°ç¨ï¼ */ |
| | | void updateReviewSummary(Long id, BigDecimal reviewAvgScore, Integer reviewPass); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.service.application; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.hutool.http.HtmlUtil; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; |
| | | import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; |
| | | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; |
| | | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; |
| | | import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; |
| | | import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; |
| | | import cn.iocoder.yudao.module.research.controller.admin.application.vo.ResearchApplicationPageReqVO; |
| | | import cn.iocoder.yudao.module.research.controller.admin.application.vo.ResearchApplicationSaveReqVO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.application.ResearchApplicationDO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.guideline.ResearchGuidelineDO; |
| | | import cn.iocoder.yudao.module.research.dal.mysql.application.ResearchApplicationMapper; |
| | | import cn.iocoder.yudao.module.research.dal.redis.ResearchNoRedisDAO; |
| | | import cn.iocoder.yudao.module.research.enums.ResearchApplicationStatusEnum; |
| | | import cn.iocoder.yudao.module.research.enums.ResearchGuidelineCategoryEnum; |
| | | import cn.iocoder.yudao.module.research.enums.ResearchGuidelineStatusEnum; |
| | | import cn.iocoder.yudao.module.research.service.guideline.ResearchGuidelineService; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticeSaveReqVO; |
| | | import cn.iocoder.yudao.module.system.dal.dataobject.notice.NoticeDO; |
| | | import cn.iocoder.yudao.module.system.service.notice.NoticeService; |
| | | import cn.iocoder.yudao.module.ums.dal.dataobject.member.UmsMemberDO; |
| | | import cn.iocoder.yudao.module.ums.service.member.UmsMemberService; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.flowable.engine.repository.ProcessDefinition; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.*; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| | | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| | | import static cn.iocoder.yudao.module.research.enums.ErrorCodeConstants.*; |
| | | |
| | | @Service |
| | | @Validated |
| | | @Slf4j |
| | | public class ResearchApplicationServiceImpl implements ResearchApplicationService { |
| | | |
| | | private static final String APPLICATION_APPROVE_CATEGORY_CODE = "research_topic_approve"; |
| | | public static final String APPLICATION_RECORD_TYPE = "research_application"; |
| | | |
| | | /** ç«é¡¹éç¥ä½¿ç¨ãå
¬åãç±»åï¼system_notice_type: 1-éç¥ 2-å
¬åï¼ */ |
| | | private static final Integer NOTICE_TYPE_ANNOUNCEMENT = 2; |
| | | |
| | | private static final DateTimeFormatter DATE_TIME_FORMATTER = |
| | | DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND); |
| | | |
| | | @Resource |
| | | private ResearchApplicationMapper applicationMapper; |
| | | |
| | | @Resource |
| | | private ResearchNoRedisDAO noRedisDAO; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @Resource |
| | | private BpmProcessInstanceApi processInstanceApi; |
| | | |
| | | @Resource |
| | | private BpmCategoryService bpmCategoryService; |
| | | |
| | | @Resource |
| | | private BpmProcessDefinitionService bpmProcessDefinitionService; |
| | | |
| | | @Resource |
| | | private ResearchGuidelineService guidelineService; |
| | | |
| | | @Resource |
| | | private UmsMemberService umsMemberService; |
| | | |
| | | @Resource |
| | | private NoticeService noticeService; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createApplication(ResearchApplicationSaveReqVO createReqVO) { |
| | | // 1. æ ¡éªæåä¸ä¼å |
| | | ResearchGuidelineDO guideline = validateGuidelineForSave(createReqVO.getGuidelineId()); |
| | | validateMemberExists(createReqVO.getMemberId()); |
| | | |
| | | // 2. çæç¼å·ï¼SB åç¼ï¼ |
| | | String no = noRedisDAO.generate(ResearchNoRedisDAO.APPLICATION_NO_PREFIX); |
| | | if (applicationMapper.selectByNo(no) != null) { |
| | | throw exception(APPLICATION_NO_EXISTS); |
| | | } |
| | | |
| | | // 3. ä¿åãç±»å«åä½èªæåï¼ä¸ä¿¡ä»»åç«¯ä¼ å¼ |
| | | ResearchApplicationDO application = BeanUtils.toBean(createReqVO, ResearchApplicationDO.class, in -> in |
| | | .setNo(no) |
| | | .setCategory(guideline.getCategory()) |
| | | .setApplicantUserId(getLoginUserId()) |
| | | .setStatus(ResearchApplicationStatusEnum.DRAFT.getStatus()) |
| | | .setBudgetAmount(in.getBudgetAmount() == null ? BigDecimal.ZERO : in.getBudgetAmount())); |
| | | applicationMapper.insert(application); |
| | | |
| | | storageAttachmentApi.bindAttachments("file", APPLICATION_RECORD_TYPE, |
| | | application.getId(), createReqVO.getBlobIds()); |
| | | return application.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateApplication(ResearchApplicationSaveReqVO updateReqVO) { |
| | | ResearchApplicationDO application = validateApplicationExists(updateReqVO.getId()); |
| | | if (!ResearchApplicationStatusEnum.DRAFT.getStatus().equals(application.getStatus()) |
| | | && !ResearchApplicationStatusEnum.REJECTED.getStatus().equals(application.getStatus())) { |
| | | throw exception(APPLICATION_UPDATE_FAIL_NOT_DRAFT, |
| | | application.getNo(), ResearchApplicationStatusEnum.nameOf(application.getStatus())); |
| | | } |
| | | ResearchGuidelineDO guideline = validateGuidelineForSave(updateReqVO.getGuidelineId()); |
| | | validateMemberExists(updateReqVO.getMemberId()); |
| | | |
| | | ResearchApplicationDO updateObj = BeanUtils.toBean(updateReqVO, ResearchApplicationDO.class); |
| | | updateObj.setCategory(guideline.getCategory()); |
| | | applicationMapper.updateById(updateObj); |
| | | |
| | | storageAttachmentApi.updateAttachments("file", APPLICATION_RECORD_TYPE, |
| | | updateReqVO.getId(), updateReqVO.getBlobIds()); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteApplication(Long id) { |
| | | ResearchApplicationDO application = validateApplicationExists(id); |
| | | if (!ResearchApplicationStatusEnum.DRAFT.getStatus().equals(application.getStatus())) { |
| | | throw exception(APPLICATION_DELETE_FAIL_NOT_DRAFT, |
| | | application.getNo(), ResearchApplicationStatusEnum.nameOf(application.getStatus())); |
| | | } |
| | | |
| | | applicationMapper.deleteById(id); |
| | | storageAttachmentApi.deleteAttachmentsByRecord(APPLICATION_RECORD_TYPE, id); |
| | | } |
| | | |
| | | @Override |
| | | public ResearchApplicationDO getApplication(Long id) { |
| | | return applicationMapper.selectById(id); |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<ResearchApplicationDO> getApplicationPage(ResearchApplicationPageReqVO pageReqVO) { |
| | | return applicationMapper.selectPage(pageReqVO); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void submitApplication(Long id, String processDefinitionKey) { |
| | | ResearchApplicationDO application = validateApplicationExists(id); |
| | | Integer status = application.getStatus(); |
| | | if (!ResearchApplicationStatusEnum.DRAFT.getStatus().equals(status) |
| | | && !ResearchApplicationStatusEnum.REJECTED.getStatus().equals(status)) { |
| | | throw exception(APPLICATION_SUBMIT_FAIL_STATUS, |
| | | application.getNo(), ResearchApplicationStatusEnum.nameOf(status)); |
| | | } |
| | | // æäº¤æ¶ä¸¥æ ¼æ ¡éªæåãå·²åå¸ + å¨ç³æ¥æå
ã |
| | | guidelineService.validateGuidelineSubmittable(application.getGuidelineId()); |
| | | |
| | | String processInstanceId = processInstanceApi.createProcessInstance(getLoginUserId(), |
| | | new BpmProcessInstanceCreateReqDTO() |
| | | .setProcessDefinitionKey(processDefinitionKey) |
| | | .setBusinessKey(String.valueOf(id))); |
| | | |
| | | applicationMapper.updateById(new ResearchApplicationDO() |
| | | .setId(id) |
| | | .setStatus(ResearchApplicationStatusEnum.APPROVING.getStatus()) |
| | | .setProcessInstanceId(processInstanceId)); |
| | | } |
| | | |
| | | @Override |
| | | public List<Map<String, Object>> getApproveProcessDefinitionList() { |
| | | validateApplicationApproveCategory(); |
| | | |
| | | List<BpmProcessDefinitionInfoDO> definitionInfoList = |
| | | bpmProcessDefinitionService.getProcessDefinitionInfoListByCategory(APPLICATION_APPROVE_CATEGORY_CODE); |
| | | if (CollUtil.isEmpty(definitionInfoList)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | Map<String, ProcessDefinition> latestVersionMap = new HashMap<>(); |
| | | for (BpmProcessDefinitionInfoDO info : definitionInfoList) { |
| | | ProcessDefinition pd = bpmProcessDefinitionService.getProcessDefinition(info.getProcessDefinitionId()); |
| | | if (pd == null || pd.isSuspended()) { |
| | | continue; |
| | | } |
| | | ProcessDefinition existing = latestVersionMap.get(pd.getKey()); |
| | | if (existing == null || pd.getVersion() > existing.getVersion()) { |
| | | latestVersionMap.put(pd.getKey(), pd); |
| | | } |
| | | } |
| | | |
| | | List<Map<String, Object>> result = new ArrayList<>(); |
| | | for (ProcessDefinition pd : latestVersionMap.values()) { |
| | | Map<String, Object> item = new HashMap<>(); |
| | | item.put("id", pd.getId()); |
| | | item.put("key", pd.getKey()); |
| | | item.put("name", pd.getName()); |
| | | result.add(item); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateApplicationAuditStatus(Long id, Integer bpmResult) { |
| | | ResearchApplicationDO application = validateApplicationExists(id); |
| | | if (!ResearchApplicationStatusEnum.APPROVING.getStatus().equals(application.getStatus())) { |
| | | log.warn("[updateApplicationAuditStatus] 课é¢ç³æ¥ä¹¦({}) ä¸å¤äºå®¡æ¹ä¸ç¶æ", id); |
| | | return; |
| | | } |
| | | |
| | | Integer newStatus = convertBpmResultToStatus(bpmResult); |
| | | if (newStatus != null) { |
| | | applicationMapper.updateById(new ResearchApplicationDO().setId(id).setStatus(newStatus)); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void approveApplication(Long id) { |
| | | ResearchApplicationDO application = validateApplicationExists(id); |
| | | if (!ResearchApplicationStatusEnum.APPROVED.getStatus().equals(application.getStatus())) { |
| | | log.warn("[approveApplication] 课é¢ç³æ¥ä¹¦({}) 䏿¯å·²ç«é¡¹ç¶æï¼è·³è¿çæç«é¡¹ç¼å·", id); |
| | | return; |
| | | } |
| | | // å¹çï¼å·²çæç«é¡¹ç¼å·åç´æ¥è¿å |
| | | if (StrUtil.isNotBlank(application.getResearchNo())) { |
| | | return; |
| | | } |
| | | String researchNo = noRedisDAO.generate(ResearchNoRedisDAO.PROJECT_NO_PREFIX); |
| | | applicationMapper.updateById(new ResearchApplicationDO() |
| | | .setId(id) |
| | | .setResearchNo(researchNo) |
| | | .setApproveTime(LocalDateTime.now())); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void publishNotice(Long id) { |
| | | ResearchApplicationDO application = validateApplicationExists(id); |
| | | if (!ResearchApplicationStatusEnum.APPROVED.getStatus().equals(application.getStatus())) { |
| | | throw exception(APPLICATION_PUBLISH_NOTICE_FAIL_STATUS, |
| | | application.getNo(), ResearchApplicationStatusEnum.nameOf(application.getStatus())); |
| | | } |
| | | if (application.getNoticeId() != null) { |
| | | NoticeDO existNotice = noticeService.getNotice(application.getNoticeId()); |
| | | throw exception(APPLICATION_NOTICE_EXISTS, application.getNo(), |
| | | existNotice != null ? format(existNotice.getCreateTime()) : "æ¤å"); |
| | | } |
| | | |
| | | ResearchGuidelineDO guideline = guidelineService.getGuideline(application.getGuidelineId()); |
| | | NoticeSaveReqVO noticeReqVO = new NoticeSaveReqVO(); |
| | | noticeReqVO.setTitle(buildNoticeTitle(guideline)); |
| | | noticeReqVO.setType(NOTICE_TYPE_ANNOUNCEMENT); |
| | | noticeReqVO.setContent(buildNoticeContent(application, guideline)); |
| | | noticeReqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); |
| | | Long noticeId = noticeService.createNotice(noticeReqVO); |
| | | |
| | | applicationMapper.updateById(new ResearchApplicationDO().setId(id).setNoticeId(noticeId)); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateReviewSummary(Long id, BigDecimal reviewAvgScore, Integer reviewPass) { |
| | | // ç¨ UpdateWrapper æ¾å¼ setï¼ä¿è¯ãè¯å®¡æç»è¢«å ç©ºãæ¶è½ææ±æ»å¼æ¸
æ null |
| | | applicationMapper.update(null, new LambdaUpdateWrapper<ResearchApplicationDO>() |
| | | .eq(ResearchApplicationDO::getId, id) |
| | | .set(ResearchApplicationDO::getReviewAvgScore, reviewAvgScore) |
| | | .set(ResearchApplicationDO::getReviewPass, reviewPass)); |
| | | } |
| | | |
| | | // =================== å
鍿¹æ³ =================== |
| | | |
| | | private ResearchApplicationDO validateApplicationExists(Long id) { |
| | | ResearchApplicationDO application = applicationMapper.selectById(id); |
| | | if (application == null) { |
| | | throw exception(APPLICATION_NOT_EXISTS); |
| | | } |
| | | return application; |
| | | } |
| | | |
| | | /** ä¿åï¼è稿ï¼é¶æ®µæ ¡éªæåï¼å¿
é¡»åå¨ä¸å·²åå¸ */ |
| | | private ResearchGuidelineDO validateGuidelineForSave(Long guidelineId) { |
| | | ResearchGuidelineDO guideline = guidelineService.getGuideline(guidelineId); |
| | | if (guideline == null) { |
| | | throw exception(GUIDELINE_NOT_EXISTS); |
| | | } |
| | | if (!ResearchGuidelineStatusEnum.PUBLISHED.getStatus().equals(guideline.getPublishStatus())) { |
| | | throw exception(APPLICATION_CREATE_FAIL_GUIDELINE_STATUS, |
| | | guideline.getTitle(), ResearchGuidelineStatusEnum.nameOf(guideline.getPublishStatus())); |
| | | } |
| | | return guideline; |
| | | } |
| | | |
| | | private void validateMemberExists(Long memberId) { |
| | | if (memberId == null) { |
| | | return; |
| | | } |
| | | UmsMemberDO member = umsMemberService.getMember(memberId); |
| | | if (member == null) { |
| | | throw exception(APPLICATION_MEMBER_NOT_EXISTS, memberId); |
| | | } |
| | | } |
| | | |
| | | private void validateApplicationApproveCategory() { |
| | | List<BpmCategoryDO> categories = bpmCategoryService.getCategoryListByCode( |
| | | Collections.singletonList(APPLICATION_APPROVE_CATEGORY_CODE)); |
| | | if (CollUtil.isEmpty(categories)) { |
| | | throw exception(APPLICATION_BPM_CATEGORY_NOT_EXISTS); |
| | | } |
| | | } |
| | | |
| | | private Integer convertBpmResultToStatus(Integer bpmResult) { |
| | | if (cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum.APPROVE.getStatus().equals(bpmResult)) { |
| | | return ResearchApplicationStatusEnum.APPROVED.getStatus(); |
| | | } else if (cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum.REJECT.getStatus().equals(bpmResult)) { |
| | | return ResearchApplicationStatusEnum.REJECTED.getStatus(); |
| | | } else if (cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum.CANCEL.getStatus().equals(bpmResult)) { |
| | | return ResearchApplicationStatusEnum.DRAFT.getStatus(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private String buildNoticeTitle(ResearchGuidelineDO guideline) { |
| | | String title = "å
³äºå
¬å¸ç«é¡¹è¯¾é¢çéç¥"; |
| | | if (guideline != null && StrUtil.isNotBlank(guideline.getTitle())) { |
| | | title = "å
³äºå
¬å¸" + guideline.getTitle() + "ç«é¡¹è¯¾é¢çéç¥"; |
| | | } |
| | | // system_notice.title ä¸é 50 å符 |
| | | return StrUtil.maxLength(title, 50); |
| | | } |
| | | |
| | | private String buildNoticeContent(ResearchApplicationDO application, ResearchGuidelineDO guideline) { |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("<p>ç»å¦ä¼ç«é¡¹å®¡æ¹éè¿ï¼ç°å°ç«é¡¹è¯¾é¢å
¬å¸å¦ä¸ï¼</p><ol>"); |
| | | sb.append("<li><strong>").append(HtmlUtil.escape(application.getTitle())).append("</strong>") |
| | | .append("ï¼ç«é¡¹ç¼å·ï¼").append(HtmlUtil.escape(application.getResearchNo())).append("ï¼<br/>") |
| | | .append("课é¢ç±»å«ï¼").append(HtmlUtil.escape(ResearchGuidelineCategoryEnum.nameOf(application.getCategory()))) |
| | | .append("ï¼ç³æ¥äººï¼").append(HtmlUtil.escape(application.getApplicantName())) |
| | | .append("ï¼å·¥ä½åä½ï¼").append(HtmlUtil.escape(StrUtil.nullToDefault(application.getWorkUnit(), "-"))) |
| | | .append("ï¼èµå©éé¢ï¼").append(application.getBudgetAmount()).append(" å
"); |
| | | if (guideline != null && StrUtil.isNotBlank(guideline.getTitle())) { |
| | | sb.append("<br/>æå±æåï¼").append(HtmlUtil.escape(guideline.getTitle())); |
| | | } |
| | | sb.append("</li></ol>"); |
| | | sb.append("<p>请课é¢è´è´£äººæç³æ¥ä¹¦çº¦å®æ¨è¿ç ç©¶å·¥ä½ï¼ç»è´¹æ¨ä»äºå®å¦è¡éç¥ã</p>"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | private static String format(LocalDateTime time) { |
| | | return time == null ? "æªè®°å½" : time.format(DATE_TIME_FORMATTER); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.service.application.listener; |
| | | |
| | | import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent; |
| | | import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener; |
| | | import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; |
| | | import cn.iocoder.yudao.module.research.service.application.ResearchApplicationService; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * 课é¢ç³æ¥ä¹¦å®¡æ¹ç¶æçå¬å¨ |
| | | * |
| | | * çå¬ BPM æµç¨å®ä¾ç¶æåæ´äºä»¶ï¼æ´æ°ç³æ¥ä¹¦ç审æ¹ç¶æï¼å¹¶å¨å®¡æ¹éè¿åçæç«é¡¹ç¼å· |
| | | */ |
| | | @Component |
| | | @Slf4j |
| | | public class ResearchApplicationStatusListener extends BpmProcessInstanceStatusEventListener { |
| | | |
| | | private static final String PROCESS_DEFINITION_KEY = "research_topic_approve"; |
| | | |
| | | @Resource |
| | | private ResearchApplicationService applicationService; |
| | | |
| | | @Override |
| | | protected String getProcessDefinitionKey() { |
| | | return PROCESS_DEFINITION_KEY; |
| | | } |
| | | |
| | | @Override |
| | | protected void onEvent(BpmProcessInstanceStatusEvent event) { |
| | | Long applicationId; |
| | | try { |
| | | applicationId = Long.parseLong(event.getBusinessKey()); |
| | | } catch (NumberFormatException e) { |
| | | log.warn("[onEvent] businessKey({}) 䏿¯ææç课é¢ç³æ¥ä¹¦ç¼å·", event.getBusinessKey()); |
| | | return; |
| | | } |
| | | |
| | | log.info("[onEvent] æ¶å°BPM审æ¹äºä»¶ï¼applicationId={}, status={}", applicationId, event.getStatus()); |
| | | |
| | | // 1. æ´æ°ç³æ¥ä¹¦å®¡æ¹ç¶æ |
| | | try { |
| | | applicationService.updateApplicationAuditStatus(applicationId, event.getStatus()); |
| | | log.info("[onEvent] 课é¢ç³æ¥ä¹¦({}) 审æ¹ç¶ææ´æ°å®æ", applicationId); |
| | | } catch (Exception e) { |
| | | log.error("[onEvent] æ´æ°è¯¾é¢ç³æ¥ä¹¦å®¡æ¹ç¶æå¤±è´¥ï¼applicationId={}", applicationId, e); |
| | | return; |
| | | } |
| | | |
| | | // 2. 审æ¹éè¿åçæç«é¡¹ç¼å·ä¸ç«é¡¹æ¶é´ |
| | | if (BpmTaskStatusEnum.APPROVE.getStatus().equals(event.getStatus())) { |
| | | try { |
| | | applicationService.approveApplication(applicationId); |
| | | log.info("[onEvent] 课é¢ç³æ¥ä¹¦({}) 审æ¹éè¿ï¼ç«é¡¹ç¼å·çæå®æ", applicationId); |
| | | } catch (Exception e) { |
| | | log.error("[onEvent] 课é¢ç³æ¥ä¹¦({}) 审æ¹éè¿åçæç«é¡¹ç¼å·å¤±è´¥", applicationId, e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.service.fund; |
| | | |
| | | import cn.iocoder.yudao.module.research.controller.admin.fund.vo.ResearchFundRecordSaveReqVO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.fund.ResearchFundRecordDO; |
| | | |
| | | import jakarta.validation.Valid; |
| | | import java.util.List; |
| | | |
| | | public interface ResearchFundRecordService { |
| | | |
| | | Long createFundRecord(@Valid ResearchFundRecordSaveReqVO createReqVO); |
| | | |
| | | void updateFundRecord(@Valid ResearchFundRecordSaveReqVO updateReqVO); |
| | | |
| | | void deleteFundRecord(Long id); |
| | | |
| | | /** æè¯¾é¢ç³æ¥ä¹¦ä¸çå
¨é¨ç»è´¹æ¨ä»è®°å½ï¼æå建æ¶é´ååºï¼ */ |
| | | List<ResearchFundRecordDO> getFundRecordListByApplicationId(Long applicationId); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.service.fund; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.research.controller.admin.fund.vo.ResearchFundRecordSaveReqVO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.application.ResearchApplicationDO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.fund.ResearchFundRecordDO; |
| | | import cn.iocoder.yudao.module.research.dal.mysql.application.ResearchApplicationMapper; |
| | | import cn.iocoder.yudao.module.research.dal.mysql.fund.ResearchFundRecordMapper; |
| | | import cn.iocoder.yudao.module.research.enums.ResearchApplicationStatusEnum; |
| | | import cn.iocoder.yudao.module.research.enums.ResearchFundStatusEnum; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.module.research.enums.ErrorCodeConstants.*; |
| | | |
| | | /** |
| | | * ç»è´¹æ¨ä»è®°å½ Service å®ç°ç±» |
| | | * |
| | | * 䏿åªå¨æ¬æ¨¡åå
è½å°æ¨æ¬¾è®°å½ï¼æ¹æ¬¡/éé¢/æ¥æ/æ¶æ¬¾æ¹/åè¯éä»¶ï¼ï¼ä¸ä¸è´¢å¡æ¨¡ååæ¥ï¼ |
| | | * 累计æ¨ä»éé¢ä»¥ç³æ¥å budget_amountï¼ç³è¯·é¢ç®ï¼ä¸ºä¸éã |
| | | */ |
| | | @Service |
| | | @Validated |
| | | @Slf4j |
| | | public class ResearchFundRecordServiceImpl implements ResearchFundRecordService { |
| | | |
| | | public static final String FUND_RECORD_TYPE = "research_fund_record"; |
| | | |
| | | @Resource |
| | | private ResearchFundRecordMapper fundRecordMapper; |
| | | |
| | | @Resource |
| | | private ResearchApplicationMapper applicationMapper; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createFundRecord(ResearchFundRecordSaveReqVO createReqVO) { |
| | | ResearchApplicationDO application = validateApplicationApproved(createReqVO.getApplicationId()); |
| | | validateVoucherRequired(createReqVO); |
| | | |
| | | // ç´¯è®¡æ ¡éªï¼æ°ç»è®°éé¢ + è¯¥ç³æ¥åå·²æè®°å½éé¢ï¼ä¸å¾è¶
è¿ç³è¯·é¢ç® |
| | | BigDecimal registered = sumAmount(fundRecordMapper.selectListByApplicationId(application.getId()), null); |
| | | validateAmountNotExceeded(createReqVO.getAmount(), registered, application.getBudgetAmount()); |
| | | |
| | | ResearchFundRecordDO fundRecord = BeanUtils.toBean(createReqVO, ResearchFundRecordDO.class, |
| | | in -> in.setId(null)); |
| | | fundRecordMapper.insert(fundRecord); |
| | | |
| | | storageAttachmentApi.bindAttachments("file", FUND_RECORD_TYPE, |
| | | fundRecord.getId(), createReqVO.getBlobIds()); |
| | | return fundRecord.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateFundRecord(ResearchFundRecordSaveReqVO updateReqVO) { |
| | | ResearchFundRecordDO exist = validateFundRecordExists(updateReqVO.getId()); |
| | | if (!ResearchFundStatusEnum.PENDING.getStatus().equals(exist.getStatus())) { |
| | | throw exception(FUND_UPDATE_FAIL_STATUS, |
| | | exist.getId(), ResearchFundStatusEnum.nameOf(exist.getStatus())); |
| | | } |
| | | // è®°å½å½å±ç³æ¥åä¸å¯åæ´ï¼é²æ¢ææ¨æ¬¾æªå°å«ç课é¢ä¸ |
| | | ResearchApplicationDO application = validateApplicationApproved(exist.getApplicationId()); |
| | | validateVoucherRequired(updateReqVO); |
| | | |
| | | BigDecimal registered = sumAmount(fundRecordMapper.selectListByApplicationId(exist.getApplicationId()), |
| | | exist.getId()); |
| | | validateAmountNotExceeded(updateReqVO.getAmount(), registered, application.getBudgetAmount()); |
| | | |
| | | ResearchFundRecordDO updateObj = BeanUtils.toBean(updateReqVO, ResearchFundRecordDO.class); |
| | | updateObj.setApplicationId(exist.getApplicationId()); |
| | | fundRecordMapper.updateById(updateObj); |
| | | |
| | | storageAttachmentApi.updateAttachments("file", FUND_RECORD_TYPE, |
| | | updateReqVO.getId(), updateReqVO.getBlobIds()); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteFundRecord(Long id) { |
| | | ResearchFundRecordDO exist = validateFundRecordExists(id); |
| | | if (!ResearchFundStatusEnum.PENDING.getStatus().equals(exist.getStatus())) { |
| | | throw exception(FUND_DELETE_FAIL_STATUS, |
| | | exist.getId(), ResearchFundStatusEnum.nameOf(exist.getStatus())); |
| | | } |
| | | |
| | | fundRecordMapper.deleteById(id); |
| | | storageAttachmentApi.deleteAttachmentsByRecord(FUND_RECORD_TYPE, id); |
| | | } |
| | | |
| | | @Override |
| | | public List<ResearchFundRecordDO> getFundRecordListByApplicationId(Long applicationId) { |
| | | return fundRecordMapper.selectListByApplicationId(applicationId); |
| | | } |
| | | |
| | | // =================== å
鍿¹æ³ =================== |
| | | |
| | | private ResearchFundRecordDO validateFundRecordExists(Long id) { |
| | | ResearchFundRecordDO fundRecord = fundRecordMapper.selectById(id); |
| | | if (fundRecord == null) { |
| | | throw exception(FUND_NOT_EXISTS); |
| | | } |
| | | return fundRecord; |
| | | } |
| | | |
| | | /** åªæå·²ç«é¡¹çè¯¾é¢æè½ç»è®°ç»è´¹æ¨ä» */ |
| | | private ResearchApplicationDO validateApplicationApproved(Long applicationId) { |
| | | ResearchApplicationDO application = applicationMapper.selectById(applicationId); |
| | | if (application == null) { |
| | | throw exception(APPLICATION_NOT_EXISTS); |
| | | } |
| | | if (!ResearchApplicationStatusEnum.APPROVED.getStatus().equals(application.getStatus())) { |
| | | throw exception(FUND_RECORD_FAIL_STATUS, application.getNo(), |
| | | ResearchApplicationStatusEnum.nameOf(application.getStatus())); |
| | | } |
| | | return application; |
| | | } |
| | | |
| | | /** ç¶æä¸ºãå·²æ¨ä»ãæ¶å¿
é¡»ä¸ä¼ åè¯éä»¶ */ |
| | | private void validateVoucherRequired(ResearchFundRecordSaveReqVO reqVO) { |
| | | if (ResearchFundStatusEnum.PAID.getStatus().equals(reqVO.getStatus()) |
| | | && CollUtil.isEmpty(reqVO.getBlobIds())) { |
| | | throw exception(FUND_VOUCHER_REQUIRED); |
| | | } |
| | | } |
| | | |
| | | /** ç´¯è®¡æµ®åºæ ¡éªï¼æ¬æ¬¡ + å·²ç»è®°ï¼æé¤ excludeId èªèº«ï¼ä¸å¾è¶
è¿ç³è¯·é¢ç® */ |
| | | private void validateAmountNotExceeded(BigDecimal amount, BigDecimal registered, BigDecimal budget) { |
| | | BigDecimal current = amount == null ? BigDecimal.ZERO : amount; |
| | | BigDecimal total = registered.add(current); |
| | | BigDecimal limit = budget == null ? BigDecimal.ZERO : budget; |
| | | if (total.compareTo(limit) > 0) { |
| | | throw exception(FUND_AMOUNT_EXCEEDED, |
| | | current.toPlainString(), registered.toPlainString(), |
| | | total.toPlainString(), limit.toPlainString()); |
| | | } |
| | | } |
| | | |
| | | private BigDecimal sumAmount(List<ResearchFundRecordDO> list, Long excludeId) { |
| | | if (CollUtil.isEmpty(list)) { |
| | | return BigDecimal.ZERO; |
| | | } |
| | | return list.stream() |
| | | .filter(item -> !Objects.equals(item.getId(), excludeId)) |
| | | .map(item -> item.getAmount() == null ? BigDecimal.ZERO : item.getAmount()) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.service.guideline; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.research.controller.admin.guideline.vo.ResearchGuidelinePageReqVO; |
| | | import cn.iocoder.yudao.module.research.controller.admin.guideline.vo.ResearchGuidelineSaveReqVO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.guideline.ResearchGuidelineDO; |
| | | |
| | | import jakarta.validation.Valid; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | public interface ResearchGuidelineService { |
| | | |
| | | Long createGuideline(@Valid ResearchGuidelineSaveReqVO createReqVO); |
| | | |
| | | void updateGuideline(@Valid ResearchGuidelineSaveReqVO updateReqVO); |
| | | |
| | | void deleteGuideline(Long id); |
| | | |
| | | ResearchGuidelineDO getGuideline(Long id); |
| | | |
| | | PageResult<ResearchGuidelineDO> getGuidelinePage(ResearchGuidelinePageReqVO pageReqVO); |
| | | |
| | | /** å·²åå¸çè¯¾é¢æåå表ï¼ä¾ç³æ¥åéæ©æåï¼ */ |
| | | List<ResearchGuidelineDO> getPublishedGuidelineList(); |
| | | |
| | | /** æ id éåæ¹éæ¥è¯¢æåï¼ç³æ¥ååè¡¨åæ¾æååç§°ï¼ */ |
| | | List<ResearchGuidelineDO> getGuidelineList(Collection<Long> ids); |
| | | |
| | | /** å叿åï¼è稿 â å·²åå¸ */ |
| | | void publishGuideline(Long id); |
| | | |
| | | /** æªæ¢æåï¼å·²åå¸ â å·²æªæ¢ */ |
| | | void closeGuideline(Long id); |
| | | |
| | | /** æ ¡éªæåæ¯å¦å¯ç³æ¥ï¼å·²åå¸ + å¨ç³æ¥æå
ï¼ï¼è¿å该æå */ |
| | | ResearchGuidelineDO validateGuidelineSubmittable(Long guidelineId); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.service.guideline; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.research.controller.admin.guideline.vo.ResearchGuidelinePageReqVO; |
| | | import cn.iocoder.yudao.module.research.controller.admin.guideline.vo.ResearchGuidelineSaveReqVO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.guideline.ResearchGuidelineDO; |
| | | import cn.iocoder.yudao.module.research.dal.mysql.application.ResearchApplicationMapper; |
| | | import cn.iocoder.yudao.module.research.dal.mysql.guideline.ResearchGuidelineMapper; |
| | | import cn.iocoder.yudao.module.research.dal.redis.ResearchNoRedisDAO; |
| | | import cn.iocoder.yudao.module.research.enums.ResearchGuidelineStatusEnum; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| | | import static cn.iocoder.yudao.module.research.enums.ErrorCodeConstants.*; |
| | | |
| | | @Service |
| | | @Validated |
| | | @Slf4j |
| | | public class ResearchGuidelineServiceImpl implements ResearchGuidelineService { |
| | | |
| | | public static final String GUIDELINE_RECORD_TYPE = "research_guideline"; |
| | | |
| | | private static final DateTimeFormatter DATE_TIME_FORMATTER = |
| | | DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND); |
| | | |
| | | @Resource |
| | | private ResearchGuidelineMapper guidelineMapper; |
| | | |
| | | @Resource |
| | | private ResearchApplicationMapper applicationMapper; |
| | | |
| | | @Resource |
| | | private ResearchNoRedisDAO noRedisDAO; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createGuideline(ResearchGuidelineSaveReqVO createReqVO) { |
| | | validateApplyTime(createReqVO); |
| | | |
| | | String no = noRedisDAO.generate(ResearchNoRedisDAO.GUIDELINE_NO_PREFIX); |
| | | if (guidelineMapper.selectByNo(no) != null) { |
| | | throw exception(GUIDELINE_NO_EXISTS); |
| | | } |
| | | |
| | | ResearchGuidelineDO guideline = BeanUtils.toBean(createReqVO, ResearchGuidelineDO.class, in -> in |
| | | .setNo(no) |
| | | .setPublishStatus(ResearchGuidelineStatusEnum.DRAFT.getStatus())); |
| | | guidelineMapper.insert(guideline); |
| | | |
| | | storageAttachmentApi.bindAttachments("file", GUIDELINE_RECORD_TYPE, |
| | | guideline.getId(), createReqVO.getBlobIds()); |
| | | return guideline.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateGuideline(ResearchGuidelineSaveReqVO updateReqVO) { |
| | | ResearchGuidelineDO guideline = validateGuidelineExists(updateReqVO.getId()); |
| | | if (!ResearchGuidelineStatusEnum.DRAFT.getStatus().equals(guideline.getPublishStatus())) { |
| | | throw exception(GUIDELINE_UPDATE_FAIL_NOT_DRAFT, guideline.getNo()); |
| | | } |
| | | validateApplyTime(updateReqVO); |
| | | |
| | | ResearchGuidelineDO updateObj = BeanUtils.toBean(updateReqVO, ResearchGuidelineDO.class); |
| | | guidelineMapper.updateById(updateObj); |
| | | |
| | | storageAttachmentApi.updateAttachments("file", GUIDELINE_RECORD_TYPE, |
| | | updateReqVO.getId(), updateReqVO.getBlobIds()); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteGuideline(Long id) { |
| | | ResearchGuidelineDO guideline = validateGuidelineExists(id); |
| | | if (!ResearchGuidelineStatusEnum.DRAFT.getStatus().equals(guideline.getPublishStatus())) { |
| | | throw exception(GUIDELINE_DELETE_FAIL_NOT_DRAFT, guideline.getNo()); |
| | | } |
| | | // 已产çç³æ¥åæ¶ç¦æ¢å é¤ï¼é¿å
ç³æ¥åæ¬æå¨å·²å 餿åä¸ |
| | | Long applicationCount = applicationMapper.selectCountByGuidelineId(id); |
| | | if (applicationCount != null && applicationCount > 0) { |
| | | throw exception(GUIDELINE_HAS_APPLICATION, guideline.getNo(), applicationCount); |
| | | } |
| | | |
| | | guidelineMapper.deleteById(id); |
| | | storageAttachmentApi.deleteAttachmentsByRecord(GUIDELINE_RECORD_TYPE, id); |
| | | } |
| | | |
| | | @Override |
| | | public ResearchGuidelineDO getGuideline(Long id) { |
| | | return guidelineMapper.selectById(id); |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<ResearchGuidelineDO> getGuidelinePage(ResearchGuidelinePageReqVO pageReqVO) { |
| | | return guidelineMapper.selectPage(pageReqVO); |
| | | } |
| | | |
| | | @Override |
| | | public List<ResearchGuidelineDO> getPublishedGuidelineList() { |
| | | return guidelineMapper.selectPublishedList(); |
| | | } |
| | | |
| | | @Override |
| | | public List<ResearchGuidelineDO> getGuidelineList(Collection<Long> ids) { |
| | | return guidelineMapper.selectListByIds(ids); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void publishGuideline(Long id) { |
| | | ResearchGuidelineDO guideline = validateGuidelineExists(id); |
| | | if (!ResearchGuidelineStatusEnum.DRAFT.getStatus().equals(guideline.getPublishStatus())) { |
| | | throw exception(GUIDELINE_PUBLISH_FAIL_STATUS); |
| | | } |
| | | guidelineMapper.updateById(new ResearchGuidelineDO() |
| | | .setId(id) |
| | | .setPublishStatus(ResearchGuidelineStatusEnum.PUBLISHED.getStatus()) |
| | | .setPublishTime(LocalDateTime.now())); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void closeGuideline(Long id) { |
| | | ResearchGuidelineDO guideline = validateGuidelineExists(id); |
| | | if (!ResearchGuidelineStatusEnum.PUBLISHED.getStatus().equals(guideline.getPublishStatus())) { |
| | | throw exception(GUIDELINE_CLOSE_FAIL_STATUS); |
| | | } |
| | | guidelineMapper.updateById(new ResearchGuidelineDO() |
| | | .setId(id) |
| | | .setPublishStatus(ResearchGuidelineStatusEnum.CLOSED.getStatus())); |
| | | } |
| | | |
| | | @Override |
| | | public ResearchGuidelineDO validateGuidelineSubmittable(Long guidelineId) { |
| | | ResearchGuidelineDO guideline = guidelineMapper.selectById(guidelineId); |
| | | if (guideline == null) { |
| | | throw exception(GUIDELINE_NOT_EXISTS); |
| | | } |
| | | // éç»´åº¦æ ¡éªï¼æç¤ºéç»åºãæåå + å®é
ç¶æ/æ¶é´ + ä¸ä¸æ¥å¨ä½ã |
| | | if (!ResearchGuidelineStatusEnum.PUBLISHED.getStatus().equals(guideline.getPublishStatus())) { |
| | | throw exception(APPLICATION_SUBMIT_FAIL_GUIDELINE_STATUS, |
| | | guideline.getTitle(), ResearchGuidelineStatusEnum.nameOf(guideline.getPublishStatus())); |
| | | } |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | boolean beforeStart = guideline.getApplyStartTime() != null && now.isBefore(guideline.getApplyStartTime()); |
| | | boolean afterEnd = guideline.getApplyEndTime() != null && now.isAfter(guideline.getApplyEndTime()); |
| | | if (beforeStart || afterEnd) { |
| | | throw exception(APPLICATION_SUBMIT_FAIL_NOT_IN_PERIOD, |
| | | format(now), guideline.getTitle(), |
| | | format(guideline.getApplyStartTime()), format(guideline.getApplyEndTime())); |
| | | } |
| | | return guideline; |
| | | } |
| | | |
| | | // =================== å
鍿¹æ³ =================== |
| | | |
| | | private ResearchGuidelineDO validateGuidelineExists(Long id) { |
| | | ResearchGuidelineDO guideline = guidelineMapper.selectById(id); |
| | | if (guideline == null) { |
| | | throw exception(GUIDELINE_NOT_EXISTS); |
| | | } |
| | | return guideline; |
| | | } |
| | | |
| | | private void validateApplyTime(ResearchGuidelineSaveReqVO reqVO) { |
| | | if (reqVO.getApplyStartTime() != null && reqVO.getApplyEndTime() != null |
| | | && reqVO.getApplyEndTime().isBefore(reqVO.getApplyStartTime())) { |
| | | throw exception(GUIDELINE_APPLY_TIME_INVALID, |
| | | format(reqVO.getApplyEndTime()), format(reqVO.getApplyStartTime())); |
| | | } |
| | | } |
| | | |
| | | private static String format(LocalDateTime time) { |
| | | return time == null ? "æªè®¾ç½®" : time.format(DATE_TIME_FORMATTER); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.service.review; |
| | | |
| | | import cn.iocoder.yudao.module.research.controller.admin.review.vo.ResearchTopicReviewSaveReqVO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.review.ResearchTopicReviewDO; |
| | | |
| | | import jakarta.validation.Valid; |
| | | import java.util.List; |
| | | |
| | | public interface ResearchTopicReviewService { |
| | | |
| | | Long createReview(@Valid ResearchTopicReviewSaveReqVO createReqVO); |
| | | |
| | | void updateReview(@Valid ResearchTopicReviewSaveReqVO updateReqVO); |
| | | |
| | | void deleteReview(Long id); |
| | | |
| | | /** æè¯¾é¢ç³æ¥ä¹¦ä¸çå
¨é¨ä¸å®¶è¯å®¡æç»ï¼ææåååºï¼ */ |
| | | List<ResearchTopicReviewDO> getReviewListByApplicationId(Long applicationId); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.research.service.review; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.research.controller.admin.review.vo.ResearchTopicReviewSaveReqVO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.application.ResearchApplicationDO; |
| | | import cn.iocoder.yudao.module.research.dal.dataobject.review.ResearchTopicReviewDO; |
| | | import cn.iocoder.yudao.module.research.dal.mysql.application.ResearchApplicationMapper; |
| | | import cn.iocoder.yudao.module.research.dal.mysql.review.ResearchTopicReviewMapper; |
| | | import cn.iocoder.yudao.module.research.enums.ResearchApplicationStatusEnum; |
| | | import cn.iocoder.yudao.module.research.enums.ResearchReviewConclusionEnum; |
| | | import cn.iocoder.yudao.module.research.service.application.ResearchApplicationService; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDateTime; |
| | | import java.util.Comparator; |
| | | import java.util.List; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.module.research.enums.ErrorCodeConstants.*; |
| | | |
| | | /** |
| | | * ä¸å®¶è¯å®¡æç» Service å®ç°ç±» |
| | | * |
| | | * è¯åæéä¸ãåå + 夿°ç»è®ºãéè¿è§ååè SRM è¯æ |
| | | * ï¼srm_bid_evaluationï¼price*0.4 + tech*0.3 + delivery*0.2 + service*0.1 çå ææ±æ» + calculateRankingï¼ |
| | | */ |
| | | @Service |
| | | @Validated |
| | | @Slf4j |
| | | public class ResearchTopicReviewServiceImpl implements ResearchTopicReviewService { |
| | | |
| | | // ===== è¯åæéï¼å ä½è§åï¼éå¦ä¼æç»ç¡®è®¤ï¼æ¹å¨åªéæ¹è¿éï¼===== |
| | | private static final BigDecimal TOPIC_WEIGHT = new BigDecimal("0.3"); |
| | | private static final BigDecimal PLAN_WEIGHT = new BigDecimal("0.3"); |
| | | private static final BigDecimal TEAM_WEIGHT = new BigDecimal("0.2"); |
| | | private static final BigDecimal RESULT_WEIGHT = new BigDecimal("0.2"); |
| | | |
| | | /** æ¨èç«é¡¹çååéå¼ */ |
| | | private static final BigDecimal PASS_SCORE = new BigDecimal("60"); |
| | | private static final BigDecimal SCORE_MAX = new BigDecimal("100"); |
| | | |
| | | @Resource |
| | | private ResearchTopicReviewMapper reviewMapper; |
| | | |
| | | @Resource |
| | | private ResearchApplicationMapper applicationMapper; |
| | | |
| | | @Resource |
| | | private ResearchApplicationService applicationService; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createReview(ResearchTopicReviewSaveReqVO createReqVO) { |
| | | validateApplicationReviewable(createReqVO.getApplicationId(), REVIEW_CREATE_FAIL_STATUS); |
| | | validateScores(createReqVO); |
| | | |
| | | ResearchTopicReviewDO review = BeanUtils.toBean(createReqVO, ResearchTopicReviewDO.class, in -> in |
| | | .setId(null) |
| | | .setReviewTime(LocalDateTime.now())); |
| | | reviewMapper.insert(review); |
| | | |
| | | recalculate(createReqVO.getApplicationId()); |
| | | return review.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateReview(ResearchTopicReviewSaveReqVO updateReqVO) { |
| | | ResearchTopicReviewDO exist = reviewMapper.selectById(updateReqVO.getId()); |
| | | if (exist == null) { |
| | | throw exception(REVIEW_NOT_EXISTS); |
| | | } |
| | | validateApplicationReviewable(exist.getApplicationId(), REVIEW_UPDATE_FAIL_STATUS); |
| | | validateScores(updateReqVO); |
| | | |
| | | ResearchTopicReviewDO updateObj = BeanUtils.toBean(updateReqVO, ResearchTopicReviewDO.class, in -> |
| | | in.setReviewTime(LocalDateTime.now())); |
| | | reviewMapper.updateById(updateObj); |
| | | |
| | | recalculate(exist.getApplicationId()); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteReview(Long id) { |
| | | ResearchTopicReviewDO exist = reviewMapper.selectById(id); |
| | | if (exist == null) { |
| | | throw exception(REVIEW_NOT_EXISTS); |
| | | } |
| | | validateApplicationReviewable(exist.getApplicationId(), REVIEW_DELETE_FAIL_STATUS); |
| | | |
| | | reviewMapper.deleteById(id); |
| | | recalculate(exist.getApplicationId()); |
| | | } |
| | | |
| | | @Override |
| | | public List<ResearchTopicReviewDO> getReviewListByApplicationId(Long applicationId) { |
| | | return reviewMapper.selectListByApplicationId(applicationId); |
| | | } |
| | | |
| | | // =================== å
鍿¹æ³ =================== |
| | | |
| | | /** |
| | | * éç®æç³æ¥ä¹¦çå
¨é¨è¯å®¡æç»ï¼å æå计 â æå â 䏻忱æ»ååä¸ç»è®º |
| | | */ |
| | | private void recalculate(Long applicationId) { |
| | | List<ResearchTopicReviewDO> list = reviewMapper.selectListByApplicationId(applicationId); |
| | | |
| | | // 1. éè¡éç®å æå计 |
| | | for (ResearchTopicReviewDO review : list) { |
| | | review.setCompositeScore(weightedScore(review)); |
| | | } |
| | | // 2. æå æå计éåºæåï¼å次åå |
| | | List<ResearchTopicReviewDO> ranked = list.stream() |
| | | .sorted(Comparator.comparing(ResearchTopicReviewDO::getCompositeScore, |
| | | Comparator.reverseOrder())) |
| | | .toList(); |
| | | for (int i = 0; i < ranked.size(); i++) { |
| | | ranked.get(i).setRanking(i + 1); |
| | | } |
| | | for (ResearchTopicReviewDO review : list) { |
| | | reviewMapper.updateById(new ResearchTopicReviewDO() |
| | | .setId(review.getId()) |
| | | .setCompositeScore(review.getCompositeScore()) |
| | | .setRanking(review.getRanking())); |
| | | } |
| | | |
| | | // 3. åå主åï¼åå + æ¯å¦æ¨èç«é¡¹ï¼æ æç»æ¶æ¸
ç©ºï¼ |
| | | if (CollUtil.isEmpty(list)) { |
| | | applicationService.updateReviewSummary(applicationId, null, null); |
| | | return; |
| | | } |
| | | BigDecimal sum = list.stream().map(ResearchTopicReviewDO::getCompositeScore) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | BigDecimal avg = sum.divide(BigDecimal.valueOf(list.size()), 2, RoundingMode.HALF_UP); |
| | | long recommendCount = list.stream() |
| | | .filter(r -> ResearchReviewConclusionEnum.RECOMMEND.getConclusion().equals(r.getConclusion())) |
| | | .count(); |
| | | boolean pass = avg.compareTo(PASS_SCORE) >= 0 && recommendCount * 2 > list.size(); |
| | | applicationService.updateReviewSummary(applicationId, avg, pass ? 1 : 0); |
| | | } |
| | | |
| | | private BigDecimal weightedScore(ResearchTopicReviewDO review) { |
| | | return nvl(review.getTopicScore()).multiply(TOPIC_WEIGHT) |
| | | .add(nvl(review.getPlanScore()).multiply(PLAN_WEIGHT)) |
| | | .add(nvl(review.getTeamScore()).multiply(TEAM_WEIGHT)) |
| | | .add(nvl(review.getResultScore()).multiply(RESULT_WEIGHT)) |
| | | .setScale(2, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | private void validateApplicationReviewable(Long applicationId, cn.iocoder.yudao.framework.common.exception.ErrorCode errorCode) { |
| | | ResearchApplicationDO application = applicationMapper.selectById(applicationId); |
| | | if (application == null) { |
| | | throw exception(APPLICATION_NOT_EXISTS); |
| | | } |
| | | if (!ResearchApplicationStatusEnum.APPROVING.getStatus().equals(application.getStatus())) { |
| | | throw exception(errorCode, application.getNo(), |
| | | ResearchApplicationStatusEnum.nameOf(application.getStatus())); |
| | | } |
| | | } |
| | | |
| | | /** éé¡¹æ ¡éªåå¼èå´ï¼æç¤ºéæåºå
·ä½æ¯åªä¸ªç»´åº¦ãå®é
å¼å¤å° */ |
| | | private void validateScores(ResearchTopicReviewSaveReqVO reqVO) { |
| | | checkScore("éé¢ä»·å¼ä¸æä¹", reqVO.getTopicScore()); |
| | | checkScore("ç ç©¶æ¹æ¡å¯è¡æ§", reqVO.getPlanScore()); |
| | | checkScore("å¢éä¸ç ç©¶åºç¡", reqVO.getTeamScore()); |
| | | checkScore("颿ææä¸æç", reqVO.getResultScore()); |
| | | } |
| | | |
| | | private void checkScore(String label, BigDecimal score) { |
| | | if (score == null) { |
| | | return; |
| | | } |
| | | if (score.compareTo(BigDecimal.ZERO) < 0 || score.compareTo(SCORE_MAX) > 0) { |
| | | throw exception(REVIEW_SCORE_OUT_OF_RANGE, label, score); |
| | | } |
| | | } |
| | | |
| | | private static BigDecimal nvl(BigDecimal value) { |
| | | return value != null ? value : BigDecimal.ZERO; |
| | | } |
| | | |
| | | } |
| | |
| | | ERP_FINANCE_RECEIPT("erp_finance_receipt", "ERP æ¶æ¬¾å"), |
| | | ERP_FINANCE_PAYMENT("erp_finance_payment", "ERP 仿¬¾å"), |
| | | |
| | | // ===== è´¢å¡æ¥é ===== |
| | | FINANCE_REIMBURSEMENT("finance_reimbursement", "è´¢å¡æ¥éå"), |
| | | |
| | | // ===== CRM ===== |
| | | CRM_SALE_QUOTATION("crm_sale_quotation", "CRM é宿¥ä»·å"), |
| | | CRM_FOLLOW_UP_RECORD("crm_follow_up_record", "CRM è·è¿è®°å½"), |
| | |
| | | |
| | | // ===== æºè½è´¨æ£æ¥å ===== |
| | | QC_REPORT_INSTANCE("qc_report_instance", "è´¨æ£æ¥åå®ä¾"), |
| | | QC_REPORT_TEMPLATE("qc_report_template", "è´¨æ£æ¥å模æ¿"); |
| | | QC_REPORT_TEMPLATE("qc_report_template", "è´¨æ£æ¥å模æ¿"), |
| | | |
| | | // ===== 课é¢ç®¡ç ===== |
| | | RESEARCH_GUIDELINE("research_guideline", "è¯¾é¢æå"), |
| | | RESEARCH_APPLICATION("research_application", "课é¢ç³æ¥ä¹¦"), |
| | | RESEARCH_FUND_RECORD("research_fund_record", "ç»è´¹æ¨ä»åè¯"); |
| | | |
| | | private final String type; |
| | | private final String description; |
| | |
| | | List<SystemStorageAttachmentDO> attachments = getStorageAttachmentsByApplicationAndRecordTypeAndRecordId( |
| | | application, recordType, recordId); |
| | | if (CollUtil.isEmpty(attachments)) { |
| | | return null; |
| | | // è¿å空éåèé nullï¼è°ç¨æ¹å¸¸æå®ç´æ¥å¡è¿ Collectors.toMap ååç»ï¼value 为 null 伿 NPEï¼ |
| | | return new ArrayList<>(); |
| | | } |
| | | Map<Long, Long> blobIdToAttachmentIdMap = attachments.stream() |
| | | .collect(Collectors.toMap(SystemStorageAttachmentDO::getStorageBlobId, SystemStorageAttachmentDO::getId)); |
| | |
| | | public List<SystemStorageBlobRespVO> getStorageBlobVOsByRecordTypeAndRecordId(String recordType, Long recordId) { |
| | | List<SystemStorageAttachmentDO> attachments = getStorageAttachmentsByRecordTypeAndRecordId(recordType, recordId); |
| | | if (CollUtil.isEmpty(attachments)) { |
| | | return null; |
| | | // è¿å空éåèé nullï¼é¿å
è°ç¨æ¹ç´æ¥ä½¿ç¨è¿å弿¶æ NPE |
| | | return new ArrayList<>(); |
| | | } |
| | | List<Long> storageBlobIds = attachments.stream() |
| | | .map(SystemStorageAttachmentDO::getStorageBlobId) |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <project xmlns="http://maven.apache.org/POM/4.0.0" |
| | | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao</artifactId> |
| | | <version>${revision}</version> |
| | | </parent> |
| | | <modelVersion>4.0.0</modelVersion> |
| | | <artifactId>yudao-module-ums</artifactId> |
| | | <packaging>jar</packaging> |
| | | |
| | | <name>${project.artifactId}</name> |
| | | <description> |
| | | ums å
ä¸ï¼ä¼åç®¡çæ¨¡åï¼å¦ä¼/åä¼åä¼åï¼å
¥ä¼ç³è¯·å®¡æ¹ãä¼åå级ãéè®¯å½æ£ç´¢ï¼ã |
| | | </description> |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-system</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- BPM 工使µï¼å
¥ä¼å®¡æ¹ä¸¤çº§å®¡æ¹ï¼ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-bpm</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- Web ç¸å
³ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-web</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-security</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- DB ç¸å
³ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-mybatis</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-redis</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- å·¥å
·ç±»ç¸å
³ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-excel</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- Test æµè¯ç¸å
³ --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-spring-boot-starter-test</artifactId> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | </project> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.controller.admin.application; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.application.vo.UmsApplicationPageReqVO; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.application.vo.UmsApplicationRespVO; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.application.vo.UmsApplicationSaveReqVO; |
| | | import cn.iocoder.yudao.module.ums.dal.dataobject.application.UmsApplicationDO; |
| | | import cn.iocoder.yudao.module.ums.service.application.UmsApplicationService; |
| | | import cn.iocoder.yudao.module.ums.service.application.UmsApplicationServiceImpl; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.annotation.Resource; |
| | | import jakarta.validation.Valid; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; |
| | | |
| | | @Tag(name = "管çåå° - å
¥ä¼ç³è¯·") |
| | | @RestController |
| | | @RequestMapping("/ums/application") |
| | | @Validated |
| | | public class UmsApplicationController { |
| | | |
| | | public static final String APPLICATION_RECORD_TYPE = |
| | | UmsApplicationServiceImpl.APPLICATION_RECORD_TYPE; |
| | | |
| | | @Resource |
| | | private UmsApplicationService applicationService; |
| | | |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @PostMapping("/create") |
| | | @Operation(summary = "å建å
¥ä¼ç³è¯·") |
| | | @PreAuthorize("@ss.hasPermission('ums:application:create')") |
| | | public CommonResult<Long> createApplication(@Valid @RequestBody UmsApplicationSaveReqVO createReqVO) { |
| | | return success(applicationService.createApplication(createReqVO)); |
| | | } |
| | | |
| | | @PutMapping("/update") |
| | | @Operation(summary = "æ´æ°å
¥ä¼ç³è¯·") |
| | | @PreAuthorize("@ss.hasPermission('ums:application:update')") |
| | | public CommonResult<Boolean> updateApplication(@Valid @RequestBody UmsApplicationSaveReqVO updateReqVO) { |
| | | applicationService.updateApplication(updateReqVO); |
| | | return success(true); |
| | | } |
| | | |
| | | @DeleteMapping("/delete") |
| | | @Operation(summary = "å é¤å
¥ä¼ç³è¯·") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('ums:application:delete')") |
| | | public CommonResult<Boolean> deleteApplication(@RequestParam("id") Long id) { |
| | | applicationService.deleteApplication(id); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/get") |
| | | @Operation(summary = "è·å¾å
¥ä¼ç³è¯·") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true, example = "1024") |
| | | @PreAuthorize("@ss.hasPermission('ums:application:query')") |
| | | public CommonResult<UmsApplicationRespVO> getApplication(@RequestParam("id") Long id) { |
| | | UmsApplicationDO application = applicationService.getApplication(id); |
| | | return success(buildApplicationDetail(application)); |
| | | } |
| | | |
| | | @GetMapping("/page") |
| | | @Operation(summary = "è·å¾å
¥ä¼ç³è¯·å页") |
| | | @PreAuthorize("@ss.hasPermission('ums:application:query')") |
| | | public CommonResult<PageResult<UmsApplicationRespVO>> getApplicationPage( |
| | | @Valid UmsApplicationPageReqVO pageReqVO) { |
| | | PageResult<UmsApplicationDO> pageResult = applicationService.getApplicationPage(pageReqVO); |
| | | return success(new PageResult<>(buildApplicationDetailList(pageResult.getList()), pageResult.getTotal())); |
| | | } |
| | | |
| | | @PostMapping("/submit") |
| | | @Operation(summary = "æäº¤å
¥ä¼ç³è¯·å®¡æ¹") |
| | | @PreAuthorize("@ss.hasPermission('ums:application:submit')") |
| | | public CommonResult<Boolean> submitApplication(@RequestParam("id") Long id, |
| | | @RequestParam("processDefinitionKey") String processDefinitionKey) { |
| | | applicationService.submitApplication(id, processDefinitionKey); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/approve-process-list") |
| | | @Operation(summary = "è·åå
¥ä¼ç³è¯·å®¡æ¹æµç¨å表") |
| | | @PreAuthorize("@ss.hasPermission('ums:application:query')") |
| | | public CommonResult<List<Map<String, Object>>> getApproveProcessDefinitionList() { |
| | | return success(applicationService.getApproveProcessDefinitionList()); |
| | | } |
| | | |
| | | // ==================== å
鍿¹æ³ ==================== |
| | | |
| | | private UmsApplicationRespVO buildApplicationDetail(UmsApplicationDO application) { |
| | | if (application == null) { |
| | | return null; |
| | | } |
| | | return buildApplicationDetailList(Collections.singletonList(application)).get(0); |
| | | } |
| | | |
| | | private List<UmsApplicationRespVO> buildApplicationDetailList(List<UmsApplicationDO> list) { |
| | | if (CollUtil.isEmpty(list)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | // 1.1 è·åå建人 |
| | | Set<Long> creatorIds = convertSet(list, application -> |
| | | NumberUtils.parseLong(application.getCreator())); |
| | | Map<Long, AdminUserRespDTO> creatorMap = adminUserApi.getUserMap(creatorIds); |
| | | // 1.2 è·åéä»¶ |
| | | Map<Long, List<StorageBlobRespDTO>> attachmentMap = list.stream() |
| | | .collect(Collectors.toMap(UmsApplicationDO::getId, |
| | | r -> storageAttachmentApi.listAttachments(APPLICATION_RECORD_TYPE, r.getId()))); |
| | | |
| | | // 2. æ¼æ¥ç»æ |
| | | return BeanUtils.toBean(list, UmsApplicationRespVO.class, (vo) -> { |
| | | findAndThen(creatorMap, NumberUtils.parseLong(vo.getCreator()), |
| | | user -> vo.setCreatorName(user.getNickname())); |
| | | List<StorageBlobRespDTO> attachments = attachmentMap.getOrDefault(vo.getId(), Collections.emptyList()); |
| | | vo.setAttachmentList(attachments); |
| | | vo.setHasAttachment(CollUtil.isNotEmpty(attachments)); |
| | | }); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.controller.admin.application.vo; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.time.LocalDate; |
| | | |
| | | @Schema(description = "管çåå° - å
¥ä¼ç³è¯·å页 Request VO") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | public class UmsApplicationPageReqVO extends PageParam { |
| | | |
| | | @Schema(description = "ç³è¯·ç¼å·", example = "SQ20260928000001") |
| | | private String no; |
| | | |
| | | @Schema(description = "ç¶æ", example = "0") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "ä¼åç±»å", example = "1") |
| | | private Integer memberType; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.controller.admin.application.vo; |
| | | |
| | | import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - å
¥ä¼ç³è¯· Response VO") |
| | | @Data |
| | | public class UmsApplicationRespVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "ç³è¯·ç¼å·", example = "SQ20260928000001") |
| | | private String no; |
| | | |
| | | @Schema(description = "ä¼åç±»å", example = "1") |
| | | private Integer memberType; |
| | | |
| | | @Schema(description = "ç³è¯·äººå§åï¼ä¸ªäººï¼æåä½åç§°ï¼åä½ï¼", example = "å¼ ä¸") |
| | | private String applicantName; |
| | | |
| | | @Schema(description = "èç³»çµè¯", example = "13800138000") |
| | | private String contactPhone; |
| | | |
| | | @Schema(description = "é®ç®±", example = "zhangsan@example.com") |
| | | private String contactEmail; |
| | | |
| | | @Schema(description = "æ³å®ä»£è¡¨äººï¼åä½ä¸æï¼", example = "æå") |
| | | private String legalPerson; |
| | | |
| | | @Schema(description = "ç»ä¸ç¤¾ä¼ä¿¡ç¨ä»£ç ï¼åä½ä¸æï¼", example = "91440101MA5XXXXXX") |
| | | private String organizationCode; |
| | | |
| | | @Schema(description = "ç ç©¶æ¹å", example = "人工æºè½ä¸æºè½å¶é ") |
| | | private String researchDirection; |
| | | |
| | | @Schema(description = "å·¥ä½åä½ï¼ä¸ªäººä¸æï¼", example = "XX大å¦") |
| | | private String workUnit; |
| | | |
| | | @Schema(description = "èç§°ï¼ä¸ªäººä¸æï¼", example = "ææ") |
| | | private String title; |
| | | |
| | | @Schema(description = "ç³è¯·ç级", example = "1") |
| | | private String memberGrade; |
| | | |
| | | @Schema(description = "å°åºç¼ç ", example = "110000") |
| | | private String regionCode; |
| | | |
| | | @Schema(description = "è¡ä¸", example = "1") |
| | | private String industry; |
| | | |
| | | @Schema(description = "ç¶æ", example = "0") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "BPM æµç¨å®ä¾ ID", example = "1001") |
| | | private String processInstanceId; |
| | | |
| | | @Schema(description = "夿³¨", example = "叿å å
¥å¦ä¼") |
| | | private String remark; |
| | | |
| | | @Schema(description = "å建è
") |
| | | private String creator; |
| | | |
| | | @Schema(description = "å建è
åç§°") |
| | | private String creatorName; |
| | | |
| | | @Schema(description = "å建æ¶é´") |
| | | private LocalDateTime createTime; |
| | | |
| | | @Schema(description = "éä»¶å表") |
| | | private List<StorageBlobRespDTO> attachmentList; |
| | | |
| | | @Schema(description = "æ¯å¦æéä»¶") |
| | | private Boolean hasAttachment; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.controller.admin.application.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotEmpty; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import lombok.Data; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - å
¥ä¼ç³è¯·æ°å¢/ä¿®æ¹ Request VO") |
| | | @Data |
| | | public class UmsApplicationSaveReqVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "ä¼åç±»å", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "ä¼åç±»åä¸è½ä¸ºç©º") |
| | | private Integer memberType; |
| | | |
| | | @Schema(description = "ç³è¯·äººå§åï¼ä¸ªäººï¼æåä½åç§°ï¼åä½ï¼", requiredMode = Schema.RequiredMode.REQUIRED, example = "å¼ ä¸") |
| | | @NotEmpty(message = "ç³è¯·äººå§åä¸è½ä¸ºç©º") |
| | | private String applicantName; |
| | | |
| | | @Schema(description = "èç³»çµè¯", example = "13800138000") |
| | | private String contactPhone; |
| | | |
| | | @Schema(description = "é®ç®±", example = "zhangsan@example.com") |
| | | private String contactEmail; |
| | | |
| | | @Schema(description = "æ³å®ä»£è¡¨äººï¼åä½ä¸æï¼", example = "æå") |
| | | private String legalPerson; |
| | | |
| | | @Schema(description = "ç»ä¸ç¤¾ä¼ä¿¡ç¨ä»£ç ï¼åä½ä¸æï¼", example = "91440101MA5XXXXXX") |
| | | private String organizationCode; |
| | | |
| | | @Schema(description = "ç ç©¶æ¹å", example = "人工æºè½ä¸æºè½å¶é ") |
| | | private String researchDirection; |
| | | |
| | | @Schema(description = "å·¥ä½åä½ï¼ä¸ªäººä¸æï¼", example = "XX大å¦") |
| | | private String workUnit; |
| | | |
| | | @Schema(description = "èç§°ï¼ä¸ªäººä¸æï¼", example = "ææ") |
| | | private String title; |
| | | |
| | | @Schema(description = "ç³è¯·ç级", example = "1") |
| | | private String memberGrade; |
| | | |
| | | @Schema(description = "å°åºç¼ç ï¼Area æ æ«çº§ï¼", example = "110000") |
| | | private String regionCode; |
| | | |
| | | @Schema(description = "è¡ä¸", example = "1") |
| | | private String industry; |
| | | |
| | | @Schema(description = "夿³¨", example = "叿å å
¥å¦ä¼") |
| | | private String remark; |
| | | |
| | | @Schema(description = "éä»¶BlobIdå表") |
| | | private List<Long> blobIds; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.controller.admin.member; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.member.vo.UmsMemberPageReqVO; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.member.vo.UmsMemberRespVO; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.member.vo.UmsMemberSaveReqVO; |
| | | import cn.iocoder.yudao.module.ums.dal.dataobject.member.UmsMemberDO; |
| | | import cn.iocoder.yudao.module.ums.service.member.UmsMemberService; |
| | | import cn.iocoder.yudao.module.ums.service.member.UmsMemberServiceImpl; |
| | | import io.swagger.v3.oas.annotations.Operation; |
| | | import io.swagger.v3.oas.annotations.Parameter; |
| | | import io.swagger.v3.oas.annotations.tags.Tag; |
| | | import jakarta.annotation.Resource; |
| | | import jakarta.validation.Valid; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; |
| | | |
| | | @Tag(name = "管çåå° - ä¼å管ç") |
| | | @RestController |
| | | @RequestMapping("/ums/member") |
| | | @Validated |
| | | public class UmsMemberController { |
| | | |
| | | public static final String MEMBER_RECORD_TYPE = |
| | | UmsMemberServiceImpl.MEMBER_RECORD_TYPE; |
| | | |
| | | @Resource |
| | | private UmsMemberService memberService; |
| | | |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @PostMapping("/create") |
| | | @Operation(summary = "å建ä¼å") |
| | | @PreAuthorize("@ss.hasPermission('ums:member:create')") |
| | | public CommonResult<Long> createMember(@Valid @RequestBody UmsMemberSaveReqVO createReqVO) { |
| | | return success(memberService.createMember(createReqVO)); |
| | | } |
| | | |
| | | @PutMapping("/update") |
| | | @Operation(summary = "æ´æ°ä¼å") |
| | | @PreAuthorize("@ss.hasPermission('ums:member:update')") |
| | | public CommonResult<Boolean> updateMember(@Valid @RequestBody UmsMemberSaveReqVO updateReqVO) { |
| | | memberService.updateMember(updateReqVO); |
| | | return success(true); |
| | | } |
| | | |
| | | @DeleteMapping("/delete") |
| | | @Operation(summary = "å é¤ä¼å") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true) |
| | | @PreAuthorize("@ss.hasPermission('ums:member:delete')") |
| | | public CommonResult<Boolean> deleteMember(@RequestParam("id") Long id) { |
| | | memberService.deleteMember(id); |
| | | return success(true); |
| | | } |
| | | |
| | | @GetMapping("/get") |
| | | @Operation(summary = "è·å¾ä¼å") |
| | | @Parameter(name = "id", description = "ç¼å·", required = true, example = "1024") |
| | | @PreAuthorize("@ss.hasPermission('ums:member:query')") |
| | | public CommonResult<UmsMemberRespVO> getMember(@RequestParam("id") Long id) { |
| | | UmsMemberDO member = memberService.getMember(id); |
| | | return success(buildMemberDetail(member)); |
| | | } |
| | | |
| | | @GetMapping("/get-by-user-id") |
| | | @Operation(summary = "éè¿ç¨æ·IDè·å¾ä¼å") |
| | | @Parameter(name = "userId", description = "ç¨æ·ID", required = true, example = "100") |
| | | @PreAuthorize("@ss.hasPermission('ums:member:query')") |
| | | public CommonResult<UmsMemberRespVO> getMemberByUserId(@RequestParam("userId") Long userId) { |
| | | UmsMemberDO member = memberService.getMemberByUserId(userId); |
| | | return success(buildMemberDetail(member)); |
| | | } |
| | | |
| | | @GetMapping("/page") |
| | | @Operation(summary = "è·å¾ä¼å/é讯å½å页") |
| | | @PreAuthorize("@ss.hasPermission('ums:member:query')") |
| | | public CommonResult<PageResult<UmsMemberRespVO>> getMemberPage( |
| | | @Valid UmsMemberPageReqVO pageReqVO) { |
| | | PageResult<UmsMemberDO> pageResult = memberService.getMemberPage(pageReqVO); |
| | | return success(new PageResult<>(buildMemberDetailList(pageResult.getList()), pageResult.getTotal())); |
| | | } |
| | | |
| | | // ==================== å
鍿¹æ³ ==================== |
| | | |
| | | private UmsMemberRespVO buildMemberDetail(UmsMemberDO member) { |
| | | if (member == null) { |
| | | return null; |
| | | } |
| | | return buildMemberDetailList(Collections.singletonList(member)).get(0); |
| | | } |
| | | |
| | | private List<UmsMemberRespVO> buildMemberDetailList(List<UmsMemberDO> list) { |
| | | if (CollUtil.isEmpty(list)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | // 1.1 è·åå
³èç³»ç»ç¨æ·ä¿¡æ¯ |
| | | Set<Long> userIds = convertSet(list, UmsMemberDO::getUserId); |
| | | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds); |
| | | // 1.2 è·åéä»¶ |
| | | Map<Long, List<StorageBlobRespDTO>> attachmentMap = list.stream() |
| | | .collect(Collectors.toMap(UmsMemberDO::getId, |
| | | r -> storageAttachmentApi.listAttachments(MEMBER_RECORD_TYPE, r.getId()))); |
| | | |
| | | // 2. æ¼æ¥ç»æ |
| | | return BeanUtils.toBean(list, UmsMemberRespVO.class, (vo) -> { |
| | | findAndThen(userMap, vo.getUserId(), user -> vo.setUsername(user.getNickname())); |
| | | List<StorageBlobRespDTO> attachments = attachmentMap.getOrDefault(vo.getId(), Collections.emptyList()); |
| | | vo.setAttachmentList(attachments); |
| | | vo.setHasAttachment(CollUtil.isNotEmpty(attachments)); |
| | | }); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.controller.admin.member.vo; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.time.LocalDate; |
| | | |
| | | @Schema(description = "管çåå° - ä¼å/é讯å½å页 Request VO") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | public class UmsMemberPageReqVO extends PageParam { |
| | | |
| | | @Schema(description = "ä¼åç¼å·", example = "HY20260928000001") |
| | | private String no; |
| | | |
| | | @Schema(description = "å§å/åä½åç§°", example = "å¼ ä¸") |
| | | private String name; |
| | | |
| | | @Schema(description = "ä¼åç±»å", example = "1") |
| | | private Integer memberType; |
| | | |
| | | @Schema(description = "ä¼åç级", example = "1") |
| | | private String memberGrade; |
| | | |
| | | @Schema(description = "ç¶æ", example = "1") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "å°åºç¼ç ") |
| | | private String regionCode; |
| | | |
| | | @Schema(description = "è¡ä¸") |
| | | private String industry; |
| | | |
| | | @Schema(description = "å
¥ä¼æ¥æ") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd") |
| | | private LocalDate[] joinDate; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.controller.admin.member.vo; |
| | | |
| | | import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import lombok.Data; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - ä¼å Response VO") |
| | | @Data |
| | | public class UmsMemberRespVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "ä¼åç¼å·", example = "HY20260928000001") |
| | | private String no; |
| | | |
| | | @Schema(description = "å
³èç³»ç»ç¨æ· ID", example = "100") |
| | | private Long userId; |
| | | |
| | | @Schema(description = "å
³èç¨æ·å", example = "zhangsan") |
| | | private String username; |
| | | |
| | | @Schema(description = "æ¥æºç³è¯·å ID", example = "1") |
| | | private Long applicationId; |
| | | |
| | | @Schema(description = "ä¼åç±»å", example = "1") |
| | | private Integer memberType; |
| | | |
| | | @Schema(description = "ä¼åç级", example = "1") |
| | | private String memberGrade; |
| | | |
| | | @Schema(description = "å§åï¼ä¸ªäººï¼æåä½åç§°ï¼åä½ï¼", example = "å¼ ä¸") |
| | | private String name; |
| | | |
| | | @Schema(description = "è系人ï¼åä½ç¨ï¼", example = "çäº") |
| | | private String contactUser; |
| | | |
| | | @Schema(description = "èç³»çµè¯", example = "13800138000") |
| | | private String contactPhone; |
| | | |
| | | @Schema(description = "é®ç®±", example = "zhangsan@example.com") |
| | | private String contactEmail; |
| | | |
| | | @Schema(description = "æ³å®ä»£è¡¨äººï¼åä½ä¸æï¼", example = "æå") |
| | | private String legalPerson; |
| | | |
| | | @Schema(description = "ç»ä¸ç¤¾ä¼ä¿¡ç¨ä»£ç ", example = "91440101MA5XXXXXX") |
| | | private String organizationCode; |
| | | |
| | | @Schema(description = "ç ç©¶æ¹å", example = "人工æºè½ä¸æºè½å¶é ") |
| | | private String researchDirection; |
| | | |
| | | @Schema(description = "å·¥ä½åä½ï¼ä¸ªäººä¸æï¼", example = "XX大å¦") |
| | | private String workUnit; |
| | | |
| | | @Schema(description = "èç§°ï¼ä¸ªäººä¸æï¼", example = "ææ") |
| | | private String title; |
| | | |
| | | @Schema(description = "åä½ç®ä»ï¼åä½ä¸æï¼", example = "䏿³¨äºæºè½å¶é é¢å") |
| | | private String unitIntro; |
| | | |
| | | @Schema(description = "å°åºç¼ç ", example = "110000") |
| | | private String regionCode; |
| | | |
| | | @Schema(description = "è¡ä¸", example = "1") |
| | | private String industry; |
| | | |
| | | @Schema(description = "å
¥ä¼æ¥æ", example = "2026-01-01") |
| | | private LocalDate joinDate; |
| | | |
| | | @Schema(description = "æææè³", example = "2028-01-01") |
| | | private LocalDate expireDate; |
| | | |
| | | @Schema(description = "ç¶æ", example = "1") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "夿³¨", example = "") |
| | | private String remark; |
| | | |
| | | @Schema(description = "å建æ¶é´") |
| | | private LocalDateTime createTime; |
| | | |
| | | @Schema(description = "éä»¶å表") |
| | | private List<StorageBlobRespDTO> attachmentList; |
| | | |
| | | /** æ¯å¦æéä»¶ï¼é讯å½/å表ç¨ï¼ */ |
| | | private Boolean hasAttachment; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.controller.admin.member.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotEmpty; |
| | | import jakarta.validation.constraints.NotNull; |
| | | import lombok.Data; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.List; |
| | | |
| | | @Schema(description = "管çåå° - ä¼åæ°å¢/ä¿®æ¹ Request VO") |
| | | @Data |
| | | public class UmsMemberSaveReqVO { |
| | | |
| | | @Schema(description = "ç¼å·", example = "1") |
| | | private Long id; |
| | | |
| | | @Schema(description = "ä¼åç±»å", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotNull(message = "ä¼åç±»åä¸è½ä¸ºç©º") |
| | | private Integer memberType; |
| | | |
| | | @Schema(description = "ä¼åç级", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| | | @NotEmpty(message = "ä¼åç级ä¸è½ä¸ºç©º") |
| | | private String memberGrade; |
| | | |
| | | @Schema(description = "å§åï¼ä¸ªäººï¼æåä½åç§°ï¼åä½ï¼", requiredMode = Schema.RequiredMode.REQUIRED, example = "å¼ ä¸") |
| | | @NotEmpty(message = "å§åä¸è½ä¸ºç©º") |
| | | private String name; |
| | | |
| | | @Schema(description = "è系人ï¼åä½ç¨ï¼", example = "çäº") |
| | | private String contactUser; |
| | | |
| | | @Schema(description = "èç³»çµè¯", example = "13800138000") |
| | | private String contactPhone; |
| | | |
| | | @Schema(description = "é®ç®±", example = "zhangsan@example.com") |
| | | private String contactEmail; |
| | | |
| | | @Schema(description = "æ³å®ä»£è¡¨äººï¼åä½ä¸æï¼", example = "æå") |
| | | private String legalPerson; |
| | | |
| | | @Schema(description = "ç»ä¸ç¤¾ä¼ä¿¡ç¨ä»£ç ", example = "91440101MA5XXXXXX") |
| | | private String organizationCode; |
| | | |
| | | @Schema(description = "ç ç©¶æ¹å", example = "人工æºè½ä¸æºè½å¶é ") |
| | | private String researchDirection; |
| | | |
| | | @Schema(description = "å·¥ä½åä½ï¼ä¸ªäººä¸æï¼", example = "XX大å¦") |
| | | private String workUnit; |
| | | |
| | | @Schema(description = "èç§°ï¼ä¸ªäººä¸æï¼", example = "ææ") |
| | | private String title; |
| | | |
| | | @Schema(description = "åä½ç®ä»ï¼åä½ä¸æï¼", example = "䏿³¨äºæºè½å¶é é¢å") |
| | | private String unitIntro; |
| | | |
| | | @Schema(description = "å°åºç¼ç ", example = "110000") |
| | | private String regionCode; |
| | | |
| | | @Schema(description = "è¡ä¸", example = "1") |
| | | private String industry; |
| | | |
| | | @Schema(description = "å
¥ä¼æ¥æ", example = "2026-01-01") |
| | | private LocalDate joinDate; |
| | | |
| | | @Schema(description = "æææè³", example = "2028-01-01") |
| | | private LocalDate expireDate; |
| | | |
| | | @Schema(description = "ç¶æ", example = "1") |
| | | private Integer status; |
| | | |
| | | @Schema(description = "夿³¨", example = "") |
| | | private String remark; |
| | | |
| | | @Schema(description = "éä»¶BlobIdå表") |
| | | private List<Long> blobIds; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.dal.dataobject.application; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import lombok.*; |
| | | |
| | | import java.time.LocalDate; |
| | | |
| | | /** |
| | | * ä¼å-å
¥ä¼ç³è¯· DO |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @TableName("ums_application") |
| | | @KeySequence("ums_application_seq") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class UmsApplicationDO extends BaseDO { |
| | | |
| | | @TableId |
| | | private Long id; |
| | | |
| | | /** ç³è¯·ç¼å· */ |
| | | private String no; |
| | | |
| | | /** ä¼åç±»åï¼1-个人 2-åä½ */ |
| | | private Integer memberType; |
| | | |
| | | /** ç³è¯·äººå§åï¼ä¸ªäººï¼æåä½åç§°ï¼åä½ï¼ */ |
| | | private String applicantName; |
| | | |
| | | /** èç³»çµè¯ */ |
| | | private String contactPhone; |
| | | |
| | | /** é®ç®± */ |
| | | private String contactEmail; |
| | | |
| | | /** æ³å®ä»£è¡¨äººï¼åä½ä¸æï¼ */ |
| | | private String legalPerson; |
| | | |
| | | /** ç»ä¸ç¤¾ä¼ä¿¡ç¨ä»£ç ï¼åä½ä¸æï¼ */ |
| | | private String organizationCode; |
| | | |
| | | /** ç ç©¶æ¹å */ |
| | | private String researchDirection; |
| | | |
| | | /** å·¥ä½åä½ï¼ä¸ªäººä¸æï¼ */ |
| | | private String workUnit; |
| | | |
| | | /** èç§°ï¼ä¸ªäººä¸æï¼ */ |
| | | private String title; |
| | | |
| | | /** ç³è¯·ççº§ï¼æ member_type åä¸ååå
¸ï¼ */ |
| | | private String memberGrade; |
| | | |
| | | /** å°åºç¼ç ï¼Area æ æ«çº§ï¼ */ |
| | | private String regionCode; |
| | | |
| | | /** è¡ä¸ï¼åå
¸ ums_industryï¼ */ |
| | | private String industry; |
| | | |
| | | /** ç¶æï¼0-è稿 15-审æ¹ä¸ 20-å·²éè¿ 35-已驳å */ |
| | | private Integer status; |
| | | |
| | | /** BPM æµç¨å®ä¾ ID */ |
| | | private String processInstanceId; |
| | | |
| | | /** 夿³¨ */ |
| | | private String remark; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.dal.dataobject.member; |
| | | |
| | | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| | | import com.baomidou.mybatisplus.annotation.KeySequence; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import lombok.*; |
| | | |
| | | import java.time.LocalDate; |
| | | |
| | | /** |
| | | * ä¼å DO |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @TableName("ums_member") |
| | | @KeySequence("ums_member_seq") |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ToString(callSuper = true) |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class UmsMemberDO extends BaseDO { |
| | | |
| | | @TableId |
| | | private Long id; |
| | | |
| | | /** ä¼åç¼å· */ |
| | | private String no; |
| | | |
| | | /** å
³èç³»ç»ç¨æ· ID */ |
| | | private Long userId; |
| | | |
| | | /** æ¥æºç³è¯·å ID */ |
| | | private Long applicationId; |
| | | |
| | | /** ä¼åç±»åï¼1-个人 2-åä½ */ |
| | | private Integer memberType; |
| | | |
| | | /** ä¼åç级ï¼åå
¸ ums_personal_grade / ums_unit_gradeï¼ */ |
| | | private String memberGrade; |
| | | |
| | | /** å§åï¼ä¸ªäººï¼æåä½åç§°ï¼åä½ï¼ */ |
| | | private String name; |
| | | |
| | | /** è系人ï¼åä½ç¨ï¼ */ |
| | | private String contactUser; |
| | | |
| | | /** èç³»çµè¯ */ |
| | | private String contactPhone; |
| | | |
| | | /** é®ç®± */ |
| | | private String contactEmail; |
| | | |
| | | /** æ³å®ä»£è¡¨äººï¼åä½ä¸æï¼ */ |
| | | private String legalPerson; |
| | | |
| | | /** ç»ä¸ç¤¾ä¼ä¿¡ç¨ä»£ç */ |
| | | private String organizationCode; |
| | | |
| | | /** ç ç©¶æ¹å */ |
| | | private String researchDirection; |
| | | |
| | | /** å·¥ä½åä½ï¼ä¸ªäººä¸æï¼ */ |
| | | private String workUnit; |
| | | |
| | | /** èç§°ï¼ä¸ªäººä¸æï¼ */ |
| | | private String title; |
| | | |
| | | /** åä½ç®ä»ï¼åä½ä¸æï¼ */ |
| | | private String unitIntro; |
| | | |
| | | /** å°åºç¼ç */ |
| | | private String regionCode; |
| | | |
| | | /** è¡ä¸ */ |
| | | private String industry; |
| | | |
| | | /** å
¥ä¼æ¥æ */ |
| | | private LocalDate joinDate; |
| | | |
| | | /** æææè³ */ |
| | | private LocalDate expireDate; |
| | | |
| | | /** ç¶æï¼1-æ£å¸¸ 0-æå */ |
| | | private Integer status; |
| | | |
| | | /** 夿³¨ */ |
| | | private String remark; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.dal.mysql.application; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.application.vo.UmsApplicationPageReqVO; |
| | | import cn.iocoder.yudao.module.ums.dal.dataobject.application.UmsApplicationDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | @Mapper |
| | | public interface UmsApplicationMapper extends BaseMapperX<UmsApplicationDO> { |
| | | |
| | | default UmsApplicationDO selectByNo(String no) { |
| | | return selectOne(UmsApplicationDO::getNo, no); |
| | | } |
| | | |
| | | default PageResult<UmsApplicationDO> selectPage(UmsApplicationPageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<UmsApplicationDO>() |
| | | .likeIfPresent(UmsApplicationDO::getNo, reqVO.getNo()) |
| | | .eqIfPresent(UmsApplicationDO::getStatus, reqVO.getStatus()) |
| | | .eqIfPresent(UmsApplicationDO::getMemberType, reqVO.getMemberType()) |
| | | .orderByDesc(UmsApplicationDO::getId)); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.dal.mysql.member; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.member.vo.UmsMemberPageReqVO; |
| | | import cn.iocoder.yudao.module.ums.dal.dataobject.member.UmsMemberDO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | @Mapper |
| | | public interface UmsMemberMapper extends BaseMapperX<UmsMemberDO> { |
| | | |
| | | default UmsMemberDO selectByNo(String no) { |
| | | return selectOne(UmsMemberDO::getNo, no); |
| | | } |
| | | |
| | | default UmsMemberDO selectByUserId(Long userId) { |
| | | return selectOne(UmsMemberDO::getUserId, userId); |
| | | } |
| | | |
| | | default PageResult<UmsMemberDO> selectPage(UmsMemberPageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<UmsMemberDO>() |
| | | .likeIfPresent(UmsMemberDO::getNo, reqVO.getNo()) |
| | | .likeIfPresent(UmsMemberDO::getName, reqVO.getName()) |
| | | .eqIfPresent(UmsMemberDO::getMemberType, reqVO.getMemberType()) |
| | | .eqIfPresent(UmsMemberDO::getMemberGrade, reqVO.getMemberGrade()) |
| | | .eqIfPresent(UmsMemberDO::getStatus, reqVO.getStatus()) |
| | | .eqIfPresent(UmsMemberDO::getRegionCode, reqVO.getRegionCode()) |
| | | .eqIfPresent(UmsMemberDO::getIndustry, reqVO.getIndustry()) |
| | | .betweenIfPresent(UmsMemberDO::getJoinDate, reqVO.getJoinDate()) |
| | | .orderByDesc(UmsMemberDO::getId)); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.dal.redis; |
| | | |
| | | /** |
| | | * UMS Redis Key 常é |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | public interface RedisKeyConstants { |
| | | |
| | | String NO = "ums:seq_no:"; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.dal.redis; |
| | | |
| | | import cn.hutool.core.date.DatePattern; |
| | | import cn.hutool.core.date.DateUtil; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.data.redis.core.StringRedisTemplate; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | import java.time.Duration; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * UMS ç¼å· Redis DAO |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Repository |
| | | public class UmsNoRedisDAO { |
| | | |
| | | /** |
| | | * å
¥ä¼ç³è¯· {@link cn.iocoder.yudao.module.ums.dal.dataobject.application.UmsApplicationDO} |
| | | */ |
| | | public static final String APPLICATION_NO_PREFIX = "SQ"; |
| | | |
| | | /** |
| | | * ä¼å {@link cn.iocoder.yudao.module.ums.dal.dataobject.member.UmsMemberDO} |
| | | */ |
| | | public static final String MEMBER_NO_PREFIX = "HY"; |
| | | |
| | | @Resource |
| | | private StringRedisTemplate stringRedisTemplate; |
| | | |
| | | public String generate(String prefix) { |
| | | String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN); |
| | | String key = RedisKeyConstants.NO + noPrefix; |
| | | Long no = stringRedisTemplate.opsForValue().increment(key); |
| | | stringRedisTemplate.expire(key, Duration.ofDays(1L)); |
| | | return noPrefix + String.format("%06d", no); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.enums; |
| | | |
| | | /** |
| | | * UMS åå
¸ç±»å常é |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | public interface DictTypeConstants { |
| | | |
| | | String APPLICATION_STATUS = "ums_application_status"; |
| | | String MEMBER_TYPE = "ums_member_type"; |
| | | String MEMBER_STATUS = "ums_member_status"; |
| | | String PERSONAL_GRADE = "ums_personal_grade"; |
| | | String UNIT_GRADE = "ums_unit_grade"; |
| | | String INDUSTRY = "ums_industry"; |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.enums; |
| | | |
| | | import cn.iocoder.yudao.framework.common.exception.ErrorCode; |
| | | |
| | | /** |
| | | * UMS éè¯¯ç æä¸¾ç±» |
| | | * <p> |
| | | * ums ç³»ç»ï¼ä½¿ç¨ 1-030-108-000 æ®µï¼æ¥å¨ finance 1-030-107 ä¹åï¼ |
| | | */ |
| | | public interface ErrorCodeConstants { |
| | | |
| | | // ========== å
¥ä¼ç³è¯·ï¼1-030-108-000 ~ 108-009ï¼ ========== |
| | | ErrorCode APPLICATION_NOT_EXISTS = new ErrorCode(1_030_108_000, "å
¥ä¼ç³è¯·ä¸åå¨"); |
| | | ErrorCode APPLICATION_NO_EXISTS = new ErrorCode(1_030_108_001, "çæç³è¯·ç¼å·å¤±è´¥ï¼è¯·éæ°æäº¤"); |
| | | ErrorCode APPLICATION_UPDATE_FAIL_NOT_DRAFT = new ErrorCode(1_030_108_002, "å
¥ä¼ç³è¯·({})䏿¯è稿æå·²é©³åç¶æï¼æ æ³ä¿®æ¹"); |
| | | ErrorCode APPLICATION_DELETE_FAIL_NOT_DRAFT = new ErrorCode(1_030_108_003, "å
¥ä¼ç³è¯·({})䏿¯èç¨¿ç¶æï¼æ æ³å é¤"); |
| | | ErrorCode APPLICATION_SUBMIT_FAIL_STATUS = new ErrorCode(1_030_108_004, "æäº¤å®¡æ¹å¤±è´¥ï¼åªæè稿æå·²é©³åç¶æçå
¥ä¼ç³è¯·æè½æäº¤"); |
| | | ErrorCode APPLICATION_BPM_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_108_005, "å
¥ä¼å®¡æ¹åç±»ä¸åå¨ï¼è¯·å
å¨BPM模åå建å
¥ä¼å®¡æ¹æµç¨åç±»"); |
| | | |
| | | // ========== ä¼åï¼1-030-108-100 ~ 108-109ï¼ ========== |
| | | ErrorCode MEMBER_NOT_EXISTS = new ErrorCode(1_030_108_100, "ä¼åä¸åå¨"); |
| | | ErrorCode MEMBER_NO_EXISTS = new ErrorCode(1_030_108_101, "çæä¼åç¼å·å¤±è´¥ï¼è¯·éæ°æäº¤"); |
| | | ErrorCode MEMBER_USER_CREATE_FAIL = new ErrorCode(1_030_108_102, "å建ä¼åç³»ç»è´¦å·å¤±è´¥ï¼è¯·è系管çå"); |
| | | ErrorCode MEMBER_USER_MOBILE_EXISTS = new ErrorCode(1_030_108_103, "è¯¥ææºå·å·²è¢«å
¶ä»ä¼åè´¦å·ä½¿ç¨"); |
| | | ErrorCode MEMBER_GRADE_NOT_MATCH_TYPE = new ErrorCode(1_030_108_104, "ä¼åç级ä¸ä¼åç±»åä¸å¹é
ï¼ä¸ªäººä¼åä¸è½éæ©åä½ç级ï¼åä½ä¼åä¸è½éæ©ä¸ªäººç级"); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.enums; |
| | | |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * å
¥ä¼ç³è¯·ç¶ææä¸¾ |
| | | * |
| | | * @author è¶
级管çå |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum UmsApplicationStatusEnum { |
| | | |
| | | DRAFT(0, "è稿"), |
| | | APPROVING(15, "审æ¹ä¸"), |
| | | APPROVED(20, "å·²éè¿"), |
| | | REJECTED(35, "已驳å"), |
| | | ; |
| | | |
| | | private final Integer status; |
| | | private final String name; |
| | | |
| | | public static UmsApplicationStatusEnum valueOf(Integer status) { |
| | | return ArrayUtil.firstMatch(e -> e.getStatus().equals(status), values()); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.framework.web.config; |
| | | |
| | | import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; |
| | | import org.springdoc.core.models.GroupedOpenApi; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | |
| | | @Configuration(proxyBeanMethods = false) |
| | | public class UmsWebConfiguration { |
| | | |
| | | @Bean |
| | | public GroupedOpenApi umsGroupedOpenApi() { |
| | | return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("ums"); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.service.application; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.application.vo.UmsApplicationPageReqVO; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.application.vo.UmsApplicationSaveReqVO; |
| | | import cn.iocoder.yudao.module.ums.dal.dataobject.application.UmsApplicationDO; |
| | | |
| | | import jakarta.validation.Valid; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | public interface UmsApplicationService { |
| | | |
| | | Long createApplication(@Valid UmsApplicationSaveReqVO createReqVO); |
| | | |
| | | void updateApplication(@Valid UmsApplicationSaveReqVO updateReqVO); |
| | | |
| | | void deleteApplication(Long id); |
| | | |
| | | UmsApplicationDO getApplication(Long id); |
| | | |
| | | PageResult<UmsApplicationDO> getApplicationPage(UmsApplicationPageReqVO pageReqVO); |
| | | |
| | | void submitApplication(Long id, String processDefinitionKey); |
| | | |
| | | List<Map<String, Object>> getApproveProcessDefinitionList(); |
| | | |
| | | void updateApplicationAuditStatus(Long id, Integer bpmResult); |
| | | |
| | | void createMemberFromApplicationOnApproved(Long id); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.service.application; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; |
| | | import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; |
| | | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; |
| | | import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; |
| | | import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.application.vo.UmsApplicationPageReqVO; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.application.vo.UmsApplicationSaveReqVO; |
| | | import cn.iocoder.yudao.module.ums.dal.dataobject.application.UmsApplicationDO; |
| | | import cn.iocoder.yudao.module.ums.dal.mysql.application.UmsApplicationMapper; |
| | | import cn.iocoder.yudao.module.ums.dal.redis.UmsNoRedisDAO; |
| | | import cn.iocoder.yudao.module.ums.enums.UmsApplicationStatusEnum; |
| | | import cn.iocoder.yudao.module.ums.service.member.UmsMemberService; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.flowable.engine.repository.ProcessDefinition; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| | | import static cn.iocoder.yudao.module.ums.enums.ErrorCodeConstants.*; |
| | | |
| | | @Service |
| | | @Validated |
| | | @Slf4j |
| | | public class UmsApplicationServiceImpl implements UmsApplicationService { |
| | | |
| | | private static final String APPLICATION_APPROVE_CATEGORY_CODE = "ums_membership_approve"; |
| | | public static final String APPLICATION_RECORD_TYPE = "ums_application"; |
| | | |
| | | @Resource |
| | | private UmsApplicationMapper applicationMapper; |
| | | |
| | | @Resource |
| | | private UmsNoRedisDAO noRedisDAO; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @Resource |
| | | private BpmProcessInstanceApi processInstanceApi; |
| | | |
| | | @Resource |
| | | private BpmCategoryService bpmCategoryService; |
| | | |
| | | @Resource |
| | | private BpmProcessDefinitionService bpmProcessDefinitionService; |
| | | |
| | | @Resource |
| | | private UmsMemberService memberService; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createApplication(UmsApplicationSaveReqVO createReqVO) { |
| | | String no = noRedisDAO.generate(UmsNoRedisDAO.APPLICATION_NO_PREFIX); |
| | | if (applicationMapper.selectByNo(no) != null) { |
| | | throw exception(APPLICATION_NO_EXISTS); |
| | | } |
| | | |
| | | UmsApplicationDO application = BeanUtils.toBean(createReqVO, UmsApplicationDO.class, in -> in |
| | | .setNo(no) |
| | | .setStatus(UmsApplicationStatusEnum.DRAFT.getStatus())); |
| | | applicationMapper.insert(application); |
| | | |
| | | storageAttachmentApi.bindAttachments("file", APPLICATION_RECORD_TYPE, |
| | | application.getId(), createReqVO.getBlobIds()); |
| | | |
| | | return application.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateApplication(UmsApplicationSaveReqVO updateReqVO) { |
| | | UmsApplicationDO application = validateApplicationExists(updateReqVO.getId()); |
| | | Integer status = application.getStatus(); |
| | | if (!UmsApplicationStatusEnum.DRAFT.getStatus().equals(status) |
| | | && !UmsApplicationStatusEnum.REJECTED.getStatus().equals(status)) { |
| | | throw exception(APPLICATION_UPDATE_FAIL_NOT_DRAFT, application.getNo()); |
| | | } |
| | | |
| | | UmsApplicationDO updateObj = BeanUtils.toBean(updateReqVO, UmsApplicationDO.class); |
| | | applicationMapper.updateById(updateObj); |
| | | |
| | | storageAttachmentApi.updateAttachments("file", APPLICATION_RECORD_TYPE, |
| | | updateReqVO.getId(), updateReqVO.getBlobIds()); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteApplication(Long id) { |
| | | UmsApplicationDO application = validateApplicationExists(id); |
| | | if (!UmsApplicationStatusEnum.DRAFT.getStatus().equals(application.getStatus())) { |
| | | throw exception(APPLICATION_DELETE_FAIL_NOT_DRAFT, application.getNo()); |
| | | } |
| | | |
| | | applicationMapper.deleteById(id); |
| | | storageAttachmentApi.deleteAttachmentsByRecord(APPLICATION_RECORD_TYPE, id); |
| | | } |
| | | |
| | | @Override |
| | | public UmsApplicationDO getApplication(Long id) { |
| | | return applicationMapper.selectById(id); |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<UmsApplicationDO> getApplicationPage(UmsApplicationPageReqVO pageReqVO) { |
| | | return applicationMapper.selectPage(pageReqVO); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void submitApplication(Long id, String processDefinitionKey) { |
| | | UmsApplicationDO application = validateApplicationExists(id); |
| | | Integer status = application.getStatus(); |
| | | if (!UmsApplicationStatusEnum.DRAFT.getStatus().equals(status) |
| | | && !UmsApplicationStatusEnum.REJECTED.getStatus().equals(status)) { |
| | | throw exception(APPLICATION_SUBMIT_FAIL_STATUS); |
| | | } |
| | | |
| | | String processInstanceId = processInstanceApi.createProcessInstance(getLoginUserId(), |
| | | new BpmProcessInstanceCreateReqDTO() |
| | | .setProcessDefinitionKey(processDefinitionKey) |
| | | .setBusinessKey(String.valueOf(id))); |
| | | |
| | | applicationMapper.updateById(new UmsApplicationDO() |
| | | .setId(id) |
| | | .setStatus(UmsApplicationStatusEnum.APPROVING.getStatus()) |
| | | .setProcessInstanceId(processInstanceId)); |
| | | } |
| | | |
| | | @Override |
| | | public List<Map<String, Object>> getApproveProcessDefinitionList() { |
| | | validateApplicationApproveCategory(); |
| | | |
| | | List<cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO> definitionInfoList = |
| | | bpmProcessDefinitionService.getProcessDefinitionInfoListByCategory(APPLICATION_APPROVE_CATEGORY_CODE); |
| | | if (CollUtil.isEmpty(definitionInfoList)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | Map<String, ProcessDefinition> latestVersionMap = new HashMap<>(); |
| | | for (cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO info : definitionInfoList) { |
| | | ProcessDefinition pd = bpmProcessDefinitionService.getProcessDefinition(info.getProcessDefinitionId()); |
| | | if (pd == null || pd.isSuspended()) { |
| | | continue; |
| | | } |
| | | ProcessDefinition existing = latestVersionMap.get(pd.getKey()); |
| | | if (existing == null || pd.getVersion() > existing.getVersion()) { |
| | | latestVersionMap.put(pd.getKey(), pd); |
| | | } |
| | | } |
| | | |
| | | List<Map<String, Object>> result = new ArrayList<>(); |
| | | for (ProcessDefinition pd : latestVersionMap.values()) { |
| | | Map<String, Object> item = new HashMap<>(); |
| | | item.put("id", pd.getId()); |
| | | item.put("key", pd.getKey()); |
| | | item.put("name", pd.getName()); |
| | | result.add(item); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateApplicationAuditStatus(Long id, Integer bpmResult) { |
| | | UmsApplicationDO application = validateApplicationExists(id); |
| | | if (!UmsApplicationStatusEnum.APPROVING.getStatus().equals(application.getStatus())) { |
| | | log.warn("[updateApplicationAuditStatus] å
¥ä¼ç³è¯·({}) ä¸å¤äºå®¡æ¹ä¸ç¶æ", id); |
| | | return; |
| | | } |
| | | |
| | | Integer newStatus = convertBpmResultToStatus(bpmResult); |
| | | if (newStatus != null) { |
| | | applicationMapper.updateById(new UmsApplicationDO() |
| | | .setId(id).setStatus(newStatus)); |
| | | } |
| | | } |
| | | |
| | | // =================== å
鍿¹æ³ =================== |
| | | |
| | | private UmsApplicationDO validateApplicationExists(Long id) { |
| | | UmsApplicationDO application = applicationMapper.selectById(id); |
| | | if (application == null) { |
| | | throw exception(APPLICATION_NOT_EXISTS); |
| | | } |
| | | return application; |
| | | } |
| | | |
| | | private void validateApplicationApproveCategory() { |
| | | List<BpmCategoryDO> categories = bpmCategoryService.getCategoryListByCode( |
| | | Collections.singletonList(APPLICATION_APPROVE_CATEGORY_CODE)); |
| | | if (CollUtil.isEmpty(categories)) { |
| | | throw exception(APPLICATION_BPM_CATEGORY_NOT_EXISTS); |
| | | } |
| | | } |
| | | |
| | | private Integer convertBpmResultToStatus(Integer bpmResult) { |
| | | if (cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum.APPROVE.getStatus().equals(bpmResult)) { |
| | | return UmsApplicationStatusEnum.APPROVED.getStatus(); |
| | | } else if (cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum.REJECT.getStatus().equals(bpmResult)) { |
| | | return UmsApplicationStatusEnum.REJECTED.getStatus(); |
| | | } else if (cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum.CANCEL.getStatus().equals(bpmResult)) { |
| | | return UmsApplicationStatusEnum.DRAFT.getStatus(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void createMemberFromApplicationOnApproved(Long id) { |
| | | UmsApplicationDO application = validateApplicationExists(id); |
| | | if (!UmsApplicationStatusEnum.APPROVED.getStatus().equals(application.getStatus())) { |
| | | log.warn("[createMemberFromApplicationOnApproved] å
¥ä¼ç³è¯·({}) 䏿¯å·²éè¿ç¶æï¼è·³è¿å»ºä¼å", id); |
| | | return; |
| | | } |
| | | memberService.createMemberFromApplication(application); |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.service.application.listener; |
| | | |
| | | import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent; |
| | | import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener; |
| | | import cn.iocoder.yudao.module.ums.service.application.UmsApplicationService; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * å
¥ä¼ç³è¯·å®¡æ¹ç¶æçå¬å¨ |
| | | * |
| | | * çå¬ BPM æµç¨å®ä¾ç¶æåæ´äºä»¶ï¼æ´æ°å
¥ä¼ç³è¯·ç审æ¹ç¶æï¼å¹¶å¨å®¡æ¹éè¿åèªå¨å建ä¼å |
| | | */ |
| | | @Component |
| | | @Slf4j |
| | | public class UmsApplicationStatusListener extends BpmProcessInstanceStatusEventListener { |
| | | |
| | | private static final String PROCESS_DEFINITION_KEY = "ums_membership_approve"; |
| | | |
| | | @Resource |
| | | private UmsApplicationService applicationService; |
| | | |
| | | @Override |
| | | protected String getProcessDefinitionKey() { |
| | | return PROCESS_DEFINITION_KEY; |
| | | } |
| | | |
| | | @Override |
| | | protected void onEvent(BpmProcessInstanceStatusEvent event) { |
| | | Long applicationId; |
| | | try { |
| | | applicationId = Long.parseLong(event.getBusinessKey()); |
| | | } catch (NumberFormatException e) { |
| | | log.warn("[onEvent] businessKey({}) 䏿¯ææçå
¥ä¼ç³è¯·ç¼å·", event.getBusinessKey()); |
| | | return; |
| | | } |
| | | |
| | | log.info("[onEvent] æ¶å°BPM审æ¹äºä»¶ï¼applicationId={}, status={}", applicationId, event.getStatus()); |
| | | |
| | | // 1. æ´æ°ç³è¯·å审æ¹ç¶æ |
| | | try { |
| | | applicationService.updateApplicationAuditStatus(applicationId, event.getStatus()); |
| | | log.info("[onEvent] å
¥ä¼ç³è¯·({}) 审æ¹ç¶ææ´æ°å®æ", applicationId); |
| | | } catch (Exception e) { |
| | | log.error("[onEvent] æ´æ°å
¥ä¼ç³è¯·å®¡æ¹ç¶æå¤±è´¥ï¼applicationId={}", applicationId, e); |
| | | return; |
| | | } |
| | | |
| | | // 2. 审æ¹éè¿åèªå¨å建ä¼å |
| | | if (cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum.APPROVE.getStatus().equals(event.getStatus())) { |
| | | try { |
| | | applicationService.createMemberFromApplicationOnApproved(applicationId); |
| | | log.info("[onEvent] å
¥ä¼ç³è¯·({}) 审æ¹éè¿ï¼ä¼ååå»ºå®æ", applicationId); |
| | | } catch (Exception e) { |
| | | log.error("[onEvent] å
¥ä¼ç³è¯·({}) 审æ¹éè¿åå建ä¼å失败", applicationId, e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.service.member; |
| | | |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.member.vo.UmsMemberPageReqVO; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.member.vo.UmsMemberSaveReqVO; |
| | | import cn.iocoder.yudao.module.ums.dal.dataobject.application.UmsApplicationDO; |
| | | import cn.iocoder.yudao.module.ums.dal.dataobject.member.UmsMemberDO; |
| | | |
| | | import jakarta.validation.Valid; |
| | | |
| | | public interface UmsMemberService { |
| | | |
| | | /** |
| | | * ä»å
¥ä¼ç³è¯·åå建ä¼åï¼å®¡æ¹éè¿é©åï¼ |
| | | */ |
| | | UmsMemberDO createMemberFromApplication(UmsApplicationDO application); |
| | | |
| | | Long createMember(@Valid UmsMemberSaveReqVO createReqVO); |
| | | |
| | | void updateMember(@Valid UmsMemberSaveReqVO updateReqVO); |
| | | |
| | | void deleteMember(Long id); |
| | | |
| | | UmsMemberDO getMember(Long id); |
| | | |
| | | UmsMemberDO getMemberByUserId(Long userId); |
| | | |
| | | PageResult<UmsMemberDO> getMemberPage(UmsMemberPageReqVO pageReqVO); |
| | | |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.ums.service.member; |
| | | |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserCreateReqDTO; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.member.vo.UmsMemberPageReqVO; |
| | | import cn.iocoder.yudao.module.ums.controller.admin.member.vo.UmsMemberSaveReqVO; |
| | | import cn.iocoder.yudao.module.ums.dal.dataobject.application.UmsApplicationDO; |
| | | import cn.iocoder.yudao.module.ums.dal.dataobject.member.UmsMemberDO; |
| | | import cn.iocoder.yudao.module.ums.dal.mysql.member.UmsMemberMapper; |
| | | import cn.iocoder.yudao.module.ums.dal.redis.UmsNoRedisDAO; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.Collections; |
| | | import java.util.Set; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.module.ums.enums.ErrorCodeConstants.*; |
| | | |
| | | @Service |
| | | @Validated |
| | | @Slf4j |
| | | public class UmsMemberServiceImpl implements UmsMemberService { |
| | | |
| | | /** |
| | | * ä¼åç³»ç»è´¦å·é»è®¤é¨é¨ IDï¼system_dept ä¸ãå¦ä¼ä¼åãï¼ |
| | | */ |
| | | private static final Long MEMBER_DEPT_ID = 129L; |
| | | |
| | | public static final String MEMBER_RECORD_TYPE = "ums_member"; |
| | | |
| | | @Resource |
| | | private UmsMemberMapper memberMapper; |
| | | |
| | | @Resource |
| | | private UmsNoRedisDAO noRedisDAO; |
| | | |
| | | @Resource |
| | | private AdminUserApi adminUserApi; |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public UmsMemberDO createMemberFromApplication(UmsApplicationDO application) { |
| | | // 1. çæä¼åç¼å· |
| | | String no = noRedisDAO.generate(UmsNoRedisDAO.MEMBER_NO_PREFIX); |
| | | if (memberMapper.selectByNo(no) != null) { |
| | | throw exception(MEMBER_NO_EXISTS); |
| | | } |
| | | |
| | | // 2. å建系ç»ç¨æ·è´¦å· |
| | | Long userId = createSystemUser(application); |
| | | |
| | | // 3. å建ä¼åè®°å½ |
| | | UmsMemberDO member = UmsMemberDO.builder() |
| | | .no(no) |
| | | .userId(userId) |
| | | .applicationId(application.getId()) |
| | | .memberType(application.getMemberType()) |
| | | .memberGrade(application.getMemberGrade()) |
| | | .name(application.getApplicantName()) |
| | | .contactPhone(application.getContactPhone()) |
| | | .contactEmail(application.getContactEmail()) |
| | | .legalPerson(application.getLegalPerson()) |
| | | .organizationCode(application.getOrganizationCode()) |
| | | .researchDirection(application.getResearchDirection()) |
| | | .workUnit(application.getWorkUnit()) |
| | | .title(application.getTitle()) |
| | | .regionCode(application.getRegionCode()) |
| | | .industry(application.getIndustry()) |
| | | .joinDate(LocalDate.now()) |
| | | .status(1) // æ£å¸¸ |
| | | .build(); |
| | | memberMapper.insert(member); |
| | | |
| | | return member; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createMember(UmsMemberSaveReqVO createReqVO) { |
| | | String no = noRedisDAO.generate(UmsNoRedisDAO.MEMBER_NO_PREFIX); |
| | | if (memberMapper.selectByNo(no) != null) { |
| | | throw exception(MEMBER_NO_EXISTS); |
| | | } |
| | | |
| | | // ä¼åç级ä¸ç±»åå¹é
æ ¡éª |
| | | validateMemberGrade(createReqVO.getMemberType(), createReqVO.getMemberGrade()); |
| | | |
| | | UmsMemberDO member = BeanUtils.toBean(createReqVO, UmsMemberDO.class, in -> in |
| | | .setNo(no) |
| | | .setStatus(createReqVO.getStatus() != null ? createReqVO.getStatus() : 1) |
| | | .setJoinDate(createReqVO.getJoinDate() != null ? createReqVO.getJoinDate() : LocalDate.now())); |
| | | memberMapper.insert(member); |
| | | |
| | | storageAttachmentApi.bindAttachments("file", MEMBER_RECORD_TYPE, |
| | | member.getId(), createReqVO.getBlobIds()); |
| | | |
| | | return member.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateMember(UmsMemberSaveReqVO updateReqVO) { |
| | | validateMemberExists(updateReqVO.getId()); |
| | | validateMemberGrade(updateReqVO.getMemberType(), updateReqVO.getMemberGrade()); |
| | | |
| | | UmsMemberDO updateObj = BeanUtils.toBean(updateReqVO, UmsMemberDO.class); |
| | | memberMapper.updateById(updateObj); |
| | | |
| | | storageAttachmentApi.updateAttachments("file", MEMBER_RECORD_TYPE, |
| | | updateReqVO.getId(), updateReqVO.getBlobIds()); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteMember(Long id) { |
| | | validateMemberExists(id); |
| | | memberMapper.deleteById(id); |
| | | storageAttachmentApi.deleteAttachmentsByRecord(MEMBER_RECORD_TYPE, id); |
| | | } |
| | | |
| | | @Override |
| | | public UmsMemberDO getMember(Long id) { |
| | | return memberMapper.selectById(id); |
| | | } |
| | | |
| | | @Override |
| | | public UmsMemberDO getMemberByUserId(Long userId) { |
| | | return memberMapper.selectByUserId(userId); |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<UmsMemberDO> getMemberPage(UmsMemberPageReqVO pageReqVO) { |
| | | return memberMapper.selectPage(pageReqVO); |
| | | } |
| | | |
| | | // =================== å
鍿¹æ³ =================== |
| | | |
| | | private Long createSystemUser(UmsApplicationDO application) { |
| | | // ææºå·å¯ä½ä¸ºç¨æ·å/å¯ç ï¼åè HRM å工模å¼ï¼ |
| | | String mobile = StrUtil.blankToDefault(application.getContactPhone(), "unknown"); |
| | | String username = mobile; |
| | | String nickname = application.getApplicantName(); |
| | | |
| | | try { |
| | | return adminUserApi.createUser(new AdminUserCreateReqDTO() |
| | | .setUsername(username) |
| | | .setNickname(nickname) |
| | | .setDeptId(MEMBER_DEPT_ID) |
| | | .setPostIds(Collections.emptySet()) |
| | | .setMobile(mobile) |
| | | .setPassword(mobile) // é»è®¤å¯ç ä¸ºææºå· |
| | | .setEmail(application.getContactEmail()) |
| | | .setRemark("ç±å
¥ä¼ç³è¯·èªå¨å建ï¼" + application.getNo())); |
| | | } catch (Exception e) { |
| | | log.error("[createSystemUser] å建ä¼åç³»ç»è´¦å·å¤±è´¥ï¼ç³è¯·å={}", application.getId(), e); |
| | | // å¦æææºå·éå¤ï¼ç»åºæç¡®æç¤º |
| | | if (e.getMessage() != null && e.getMessage().contains("ææºå·")) { |
| | | throw exception(MEMBER_USER_MOBILE_EXISTS); |
| | | } |
| | | throw exception(MEMBER_USER_CREATE_FAIL); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ ¡éªä¼åç级ä¸ç±»åå¹é
ï¼åä½ä¼åï¼type=2ï¼ä¸å¯éä¸ªäººä¸æç级ã5-çäºé¿ã |
| | | */ |
| | | private void validateMemberGrade(Integer memberType, String memberGrade) { |
| | | if (memberType == null || StrUtil.isBlank(memberGrade)) { |
| | | return; |
| | | } |
| | | if (memberType == 2 && "5".equals(memberGrade)) { |
| | | throw exception(MEMBER_GRADE_NOT_MATCH_TYPE); |
| | | } |
| | | } |
| | | |
| | | private UmsMemberDO validateMemberExists(Long id) { |
| | | UmsMemberDO member = memberMapper.selectById(id); |
| | | if (member == null) { |
| | | throw exception(MEMBER_NOT_EXISTS); |
| | | } |
| | | return member; |
| | | } |
| | | |
| | | } |
| | |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- è´¢å¡ç®¡ç模å --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-finance</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- ä¼åç®¡çæ¨¡å --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-ums</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- 课é¢ç®¡ç模å --> |
| | | <dependency> |
| | | <groupId>cn.iocoder.boot</groupId> |
| | | <artifactId>yudao-module-research</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- spring boot é
ç½®æéä¾èµ --> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |