doc/20260617_quality_inspect_rule.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,11 @@ -- è´¨éæ£éªè§åï¼å ¨æ£/æ½æ£ + æ½æ£æ¯ä¾ -- 2026-06-17 -- æ£æµæ åä¸»è¡¨ï¼æ°å¢æ£éªè§ååæ½æ£æ¯ä¾ ALTER TABLE quality_test_standard ADD COLUMN inspect_rule INT DEFAULT 0 COMMENT 'æ£éªè§å: 0=å ¨æ£, 1=æ½æ£'; ALTER TABLE quality_test_standard ADD COLUMN sample_ratio DECIMAL(5,2) DEFAULT NULL COMMENT 'æ½æ£æ¯ä¾(ç¾åæ¯), ä» inspect_rule=1æ¶ææ, å¦10表示10%'; -- è´¨æ£è®°å½è¡¨ï¼æ°å¢æ£éªè§åãæ½æ£æ¯ä¾ãæ½æ£æ°é ALTER TABLE quality_inspect ADD COLUMN inspect_rule INT DEFAULT NULL COMMENT 'æ£éªè§å: 0=å ¨æ£, 1=æ½æ£'; ALTER TABLE quality_inspect ADD COLUMN sample_ratio DECIMAL(5,2) DEFAULT NULL COMMENT 'æ½æ£æ¯ä¾(ç¾åæ¯), ä» inspectRule=1æ¶ææ'; ALTER TABLE quality_inspect ADD COLUMN sample_quantity DECIMAL(16,2) DEFAULT NULL COMMENT 'æ½æ£æ°é, ä» inspectRule=1æ¶ææ'; docs/20260618_git_commits_summary.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,316 @@ # dev_æ°ç马éè¯pro 忝 Git æäº¤è®°å½æ´ç > ç¸å¯¹äº master 忝ï¼å ±æ **1260 æ¡æäº¤**ï¼å«åå¹¶æäº¤ï¼ > 以䏿åè½æ¨¡ååç±»æ´çä¸»è¦æäº¤å 容 --- ## ä¸ãæäº¤ç»è®¡æ¦è§ | 模å | æäº¤æ° | 说æ | |------|--------|------| | production | 58 | çäº§ç®¡çæ¨¡å | | sales | 43 | éå®ç®¡ç模å | | stock | 31 | åºåç®¡çæ¨¡å | | quality | 18 | è´¨éç®¡çæ¨¡å | | purchase | 17 | éè´ç®¡ç模å | | account | 17 | è´¢å¡ç®¡ç模å | | approve | 15 | å®¡æ¹æµç¨æ¨¡å | | home | 12 | é¦é¡µæ°æ®çæ¿ | | ai | 12 | AI婿åè½ | | technology | 11 | å·¥èºè·¯çº¿æ¨¡å | | staff | 8 | åå·¥ç®¡çæ¨¡å | | device | 4 | 设å¤ç®¡ç模å | | config | 4 | é ç½®ç¸å ³ | | other | - | å ¶ä»æé¡¹ | --- ## äºãè¿æä¸»è¦åè½æäº¤ï¼ææ°50æ¡ï¼ ### 2026å¹´6æ | æ¥æ | æäº¤è¯´æ | |------|----------| | ææ° | `e772b3d8c` 设å¤ä¿å »å 容忮µå¢å | | ææ° | `50c67ada0` feat(config): æ·»å Pinecone åéæ°æ®åºé ç½® | | ææ° | `eb832a81f` refactor(ai): éæ Pinecone åéåå¨é ç½®åæå¡å®ç° | | ææ° | `a61d5a200` refactor(knowledge-base): éæRAGåéæ£ç´¢åè½çæä»¶å ³èå弿¥å¤ç | | ææ° | `29ccd9919` feat(financial): æ°å¢åè¯åå½ç§ç®æç»å段 | | ææ° | `4b91241e4` feat(database): æ·»å éä»¶æ°æ®è¿ç§»èæ¬ä»common_fileå°storage_blob_storage_attachment | | ææ° | `feb86efc4` feat(iot): ç©èè®¾å¤æ¥å£æ°å¢åæ¾ä½ç½®å段 | | ææ° | `789ee31d8` feat(vehicle): æ·»å 车è¾ç®¡ç模ååå½è¿éç¨åè½ | | ææ° | `a217dbfc7` feat(device): æ·»å 设å¤ä¿å »éªæ¶åè½åå¹´åº¦å®æ¶ä»»å¡æ¯æ | | ææ° | `284034e85` feat(stock): æ·»å åºåç©è设å¤ç»å®å宿¶æ°éåè½ | | ææ° | `f80eee649` feat(home): æ°å¢ä¸æéå®éè´éé¢ç»è®¡åè½ | | ææ° | `3d048a0ff` feat(shipping): åè´§å¡«åºåºæ¹å·ï¼ææ¹å·æ¹éå ¥åºï¼éå®éè´§æ¹åºåºæ¹å· | | ææ° | `48c1deafd` feat(quality): ä¼åæ¹éå¿«éæ£éªåè½ | | ææ° | `1baf55456` feat(quality): å¢å æ£éªç®¡çåè½å¹¶å®ååºåé¢è¦ | | ææ° | `a0f6e4436` feat(ai): æ·»å AIä¼è¯æ¸ çä»»å¡å¹¶ä¼åè´¢å¡åæåè½ | | ææ° | `261a7d264` fix(ai): ä¼åè´¢å¡AI婿çå·¥ä½è§ååæ°æ®åæåè½ | --- ## ä¸ãæåè½æ¨¡å详ç»è¯´æ ### 1. çäº§ç®¡çæ¨¡å (production) - 58æ¡ **æ ¸å¿åè½ï¼** - ç产订å管çä¸å·¥èºè·¯çº¿ - ç产æ¥å·¥ä¸äº§åºå ¥åº - çäº§æ ¸ç®åè½ - çäº§çæ¿æ°æ®ç»è®¡ **ä¸»è¦æäº¤ï¼** ``` feat(production): æ·»å çäº§æ ¸ç®åè½åç¸å ³æ¥å£ feat(production): æ°å¢ç产订ååè½å¹¶ä¼åå·¥åå·çæé»è¾ feat(production): ç产æ¥å·¥ç¸å ³åè½ feat(production): æ·»å ç产订åå·¥èºè·¯çº¿å ³è refactor(production): ä¼åç产订åå·¥èºè·¯çº¿æä½æå¡æ¥å£ fix(production): ä¿®å¤çäº§äº§åæ°éæ´æ°é»è¾ ``` --- ### 2. éå®ç®¡ç模å (sales) - 43æ¡ **æ ¸å¿åè½ï¼** - éå®å°è´¦ä¸é宿¥ä»· - éå®åè´§ä¸åºåº - éå®é货管ç - éå®åå管ç **ä¸»è¦æäº¤ï¼** ``` feat(sales): éå®éè´§æ¨¡åæ¥å£å¼å feat(sales): æ·»å é宿¥ä»·åIDæ¥è¯¢æ¡ä»¶æ¯æ feat(sales): åè´§å®¡æ¹æµç¨ feat(sales): å®¢æ·æ¡£æ¡ç®¡çä¼å fix(sales): éå®å°è´¦ç¼è¾é»è¾ä¿®å¤ ``` --- ### 3. åºåç®¡çæ¨¡å (stock) - 31æ¡ **æ ¸å¿åè½ï¼** - åºåçç¹ä¸é¢è¦ - å ¥åº/åºåºè®°å½ç®¡ç - æ¹æ¬¡å·ç®¡ç - åºå导åºåè½ **ä¸»è¦æäº¤ï¼** ``` feat(stock): æ·»å åºåç©è设å¤ç»å®å宿¶æ°éåè½ feat(stock): åºåå¯¼åºæ¥å£å¼å feat(stock): æ·»å æ¹å·å段并ä¼ååºå ¥åºè®°å½å¯¼åºåè½ feat(stock): ä¸åæ ¼åºåå¯¼åº refactor(stock): éæåºåç¸å ³æä¸¾ç±»ä»¥åºååºå ¥åºç±»å ``` --- ### 4. è´¨éç®¡çæ¨¡å (quality) - 18æ¡ **æ ¸å¿åè½ï¼** - æ£éªç®¡çï¼åææ/è¿ç¨/åºåæ£éªï¼ - æ¹éå¿«éæ£éª - ä¸åæ ¼å管ç - æ£éªæ åé ç½® **ä¸»è¦æäº¤ï¼** ``` feat(quality): å¢å æ£éªç®¡çåè½å¹¶å®ååºåé¢è¦ feat(quality): ä¼åæ¹éå¿«éæ£éªåè½ feat(quality): æ·»å ä¸åæ ¼åå¤çæ è¯å段 fix(quality): è´¨æ£æäº¤æ°æ®éªè¯ fix(quality): é¦é¡µè´¨éæ°æ®ç»è®¡éè¯¯ä¿®å¤ ``` --- ### 5. è´¢å¡ç®¡ç模å (account) - 17æ¡ **æ ¸å¿åè½ï¼** - åºæ¶åºä»ç®¡ç - è´¢å¡æ¥è¡¨ç»è®¡ - åè¯ç®¡ç - æåº¦è¥æ¶æ°æ® **ä¸»è¦æäº¤ï¼** ``` feat(account): ä¼ååºæ¶åºä»éé¢åæåº¦ç»è®¡æ°æ®è®¡ç® feat(account): éåè´¢å¡æ¥è¡¨ç»è®¡åè½ feat(account): æ·»å æ¯å¦çæå¯¹è´¦ååæ®µ refactor(account): éæè´¢å¡æ¥è¡¨ç¸å ³ä»£ç feat(financial): æ°å¢åè¯åå½ç§ç®æç»å段 ``` --- ### 6. å®¡æ¹æµç¨æ¨¡å (approve) - 15æ¡ **æ ¸å¿åè½ï¼** - ååå®¡æ¹æµç¨ - 审æ¹å®ä¾ç®¡ç - åºå·®ç³è¯· - æ¥é忍¡å **ä¸»è¦æäº¤ï¼** ``` refactor(approve): éæå®¡æ¹ä¸å¡ç¶æåæ¥é»è¾ feat(approve): æ·»å 审æ¹å®ä¾æå½åç¨æ·è¿æ»¤åè½ feat(approve): å®å审æ¹å®ä¾ç®¡çåè½å¹¶æ°å¢æ¥é忍¡å feat(approve): æ·»å æä½æ¥å¿è®°å½ fix(approve): ä¿®å¤å®¡æ¹å®ä¾æ¥è¯¢æ¡ä»¶åæµç¨æ§å¶é®é¢ ``` --- ### 7. é¦é¡µæ°æ®çæ¿ (home) - 12æ¡ **æ ¸å¿åè½ï¼** - çäº§çæ¿ - è´¨éç»è®¡ - è´¢å¡ç»è®¡ - ä¸ææ°æ®ç»è®¡ **ä¸»è¦æäº¤ï¼** ``` feat(home): æ·»å çäº§çæ¿åè½å¹¶ä¼åè®¢åæ¥è¯¢æ§è½ feat(home): æ°å¢ä¸æéå®éè´éé¢ç»è®¡åè½ refactor(home): éæé¦é¡µè´¢å¡ç»è®¡åè½å®ç° fix(home): é¦é¡µè´¨éæ°æ®ç»è®¡éè¯¯ä¿®å¤ ``` --- ### 8. AI婿åè½ (ai) - 12æ¡ **æ ¸å¿åè½ï¼** - 审æ¹å¾ å婿 - è´¢å¡AI婿 - éè´AI婿 - RAGåéæ£ç´¢ **ä¸»è¦æäº¤ï¼** ``` feat(ai): æ·»å 审æ¹å¾ å婿åè½ feat(ai): æ´æ°éè´åéå®AIå·¥å ·çæ°æ®æ¥è¯¢åè½ feat(ai): æ·»å AIä¼è¯æ¸ çä»»å¡å¹¶ä¼åè´¢å¡åæåè½ refactor(ai): éæ Pinecone åéåå¨é ç½®åæå¡å®ç° fix(ai): ä¼åè´¢å¡AI婿çå·¥ä½è§ååæ°æ®åæåè½ ``` --- ### 9. 设å¤ç®¡ç模å (device) - 4æ¡ **ä¸»è¦æäº¤ï¼** ``` feat(device): æ·»å 设å¤ä¿å »éªæ¶åè½åå¹´åº¦å®æ¶ä»»å¡æ¯æ feat(device): 设å¤å°è´¦æ°å¢éä»¶å¾çä¸ä¼ feat(iot): ç©èè®¾å¤æ¥å£æ°å¢åæ¾ä½ç½®å段 ``` --- ### 10. å·¥èºè·¯çº¿æ¨¡å (technology) - 11æ¡ **ä¸»è¦æäº¤ï¼** ``` refactor(technology): 使ç¨DTOåVOéæå·¥èºè·¯çº¿æ¨¡å refactor(technology): ä¼åå·¥èºè·¯çº¿æå¡å®ç° feat(technology): å·¥åºç®¡çç¸å ³åè½ ``` --- ### 11. åå·¥ç®¡çæ¨¡å (staff) - 8æ¡ **ä¸»è¦æäº¤ï¼** ``` feat(staff): ä¿®æ¹åå·¥å ¥èæå¡æ¥å£å¢å ç¨æ·æ·»å æ è¯åæ° feat(staff): æ·»å å¨èåå·¥å¯¼å ¥åè½ fix(staff): è§£å³å¯¼åºæ°æ®åæ°ä¸ä¸è´é®é¢ ``` --- ### 12. å ¶ä»éè¦åè½ **车è¾ç®¡çï¼** ``` feat(vehicle): æ·»å 车è¾ç®¡ç模ååå½è¿éç¨åè½ ``` **ç¥è¯åº/åéæ£ç´¢ï¼** ``` refactor(knowledge-base): éæRAGåéæ£ç´¢åè½çæä»¶å ³èå弿¥å¤ç feat(config): æ·»å Pinecone åéæ°æ®åºé ç½® ``` **æ°æ®è¿ç§»ï¼** ``` feat(database): æ·»å éä»¶æ°æ®è¿ç§»èæ¬ä»common_fileå°storage_blob_storage_attachment ``` --- ## åãé ç½®æä»¶æ´æ° å¤ä¸ªå®¢æ·ç¯å¢é ç½®æä»¶æ´æ°ï¼ - `dev_æ°ç马éè¯pro` (å½å忝) - `dev_山西_æåå_pro` - `dev_æ²³å_鹤å£` - `dev_天津_*` ç³»å - `dev_å®å¤_*` ç³»å - å ¶ä»å®¢æ·å®å¶ç¯å¢ --- ## äºãä¾èµæ´æ° ``` chore(deps): æ´æ° mybatis-plus çæ¬å° 3.5.15 chore(deps): æ´æ° MyBatis-Plus ä¾èµçæ¬ ``` --- ## å ãéæä¸ä¼å | ç±»å | 说æ | |------|------| | refactor | éæå®¡æ¹ä¸å¡ç¶æåæ¥é»è¾ | | refactor | éæé¦é¡µè´¢å¡ç»è®¡åè½å®ç° | | refactor | éæåºåç¸å ³æä¸¾ç±» | | refactor | éæéè´AIæ§å¶å¨ | | refactor | éæå·¥èºè·¯çº¿æ¨¡å使ç¨DTO/VO | | refactor | è¿ç§»Swagger注解å°OpenAPI 3.0 | | refactor | ä¼å订åç¼å·çæé»è¾ | | refactor | ç®ååºåçç¹æå¡éå¤ä»£ç | --- ## ä¸ãBugä¿®å¤ç²¾é | é®é¢ | ä¿®å¤å 容 | |------|----------| | è´¨éç»è®¡é误 | é¦é¡µè´¨éæ°æ®åæ ¼/ä¸åæ ¼çç»è®¡é误 | | å®¡æ¹æµç¨å¼å¸¸ | ä¿®å¤å®¡æ¹èç¹å®¡æ¹äººä¸ºç©ºæ¶çå¼å¸¸å¤ç | | ç产æ°éæ´æ° | ä¿®å¤çäº§äº§åæ°éæ´æ°é»è¾ | | 订åç¼å·çæ | ä¿®å¤å段åä¸ä¸è´é®é¢ | | åºåæ¥è¯¢SQL | ä¿®å¤å¤ä½å符导è´SQLè¯æ³é误 | | å¯¼åºæ°æ® | è§£å³å¯¼åºæ°æ®åæ°ä¸ä¸è´é®é¢ | --- ## å «ã夿³¨ - 忝åç§°ï¼`dev_æ°ç马éè¯pro` - åºå忝ï¼`master` - æäº¤æ»æ°ï¼1260æ¡ï¼å«åå¹¶ï¼ - 主è¦å¼åè ï¼yys åå¢éæå - æ¶å客æ·ï¼æ°ç马éè¯é¡¹ç®åå¤ä¸ªå®å¶å忝 docs/20260618_home_quality_query_fix.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,194 @@ # é¦é¡µè´¨éç±»æ¥è¯¢ä¿®å¤ä¸ä¼åå端èè°ææ¡£ > ä¿®å¤ `home` 模åä¸è´¨éç±»æ¥å£çè¥å¹²é®é¢ï¼å¹¶ä¼åæ¥è¯¢æ§è½ã > æ¬æ¬¡æ¹å¨**åªæ¶åååºæ°å¼**ï¼**æ¥å£è·¯å¾ã请æ±åæ°ãååºå段ååæªåå**ã ## æ¶åé¡µé¢ - é¦é¡µ / æ°æ®çæ¿ - è´¨éåææ¨¡å - é¦é¡µ / æ°æ®çæ¿ - è´¨éæ£éªæ°éå¡ç - é¦é¡µ / æ°æ®çæ¿ - ä¸åæ ¼é¢è¦ - é¦é¡µ / æ°æ®çæ¿ - 宿æ£éªæ°è¶å¿ - é¦é¡µ / æ°æ®çæ¿ - ä¸åæ ¼äº§åæå - é¦é¡µ / æ°æ®çæ¿ - åææ/è¿ç¨/åºåæ£æµåæ ¼ç - é¦é¡µ / æ°æ®çæ¿ - è´¨éç»è®¡ (å¨/æ/å£) - è´¨é管ç - æ£éªåæ°å¢/ç¼è¾é¡µ (æ£éªè§ååæ®µ) ## å影忥å£ä¸è§ | æ¹æ³ | è·¯å¾ | 说æ | |------|------|------| | GET | /home/qualityInspectionCount | è´¨éæ£éªæ°é (è¯ä¹æåæ´) | | GET | /home/nonComplianceWarning | è¿ä¸å¤©ä¸åæ ¼é¢è¦ | | GET | /home/completedInspectionCount | è¿ä¸å¤©å®ææ£éªæ° | | GET | /home/unqualifiedProductRanking | ä¸åæ ¼äº§åæå (å£å¾åæ´) | | GET | /home/rawMaterialDetection | åæææ£æµåæ ¼ç | | GET | /home/processDetection | è¿ç¨æ£æµåæ ¼ç | | GET | /home/factoryDetection | åºåæ£æµåæ ¼ç | | GET | /home/qualityInspectionStatistics | è´¨éç»è®¡ (å¨/æ/å£) | | POST | /qualityInspect | æ°å¢æ£éªå (inspectRule é»è®¤å¼é»è¾) | ## ä¸ã`/home/qualityInspectionCount` (è¯ä¹åæ´ï¼å端éå ³æ³¨) ### åæ´åå - åå®ç°æå ¨è¡¨å è½½å°å åè¿è¡æ±åï¼ä¸ `totalCountGrowthRate` ç¨ *æªæ¢ä»æ¥ç´¯è®¡ vs æªæ¢æ¨æ¥ç´¯è®¡* 计ç®ï¼å¾å°çå®è´¨æ¯ `today_only / yesterday_cumulative`ï¼æ ä¸å¡æä¹ã - åå®ç°å¯¹ `checkTime` ç¨ `eq(checkTime, "yyyy-MM-dd")`ï¼è¥æ°æ®åº `check_time` å«é 0 æ¶åç§ä¼å ¨é¨æ¼å¹é ï¼å¯¼è´ `todayPendingCount`/`todayCompletedCount` å¶å为 0ã ### æ°å£å¾ | åæ®µ | æ§å£å¾ | æ°å£å¾ | |------|--------|--------| | `totalCount` | æªæ¢ä»æ¥ææ `quantity` ç´¯å | ä¸åï¼ä»æ¯åå²ç´¯è®¡ (æ¹ç¨ SQL `SUM` èå) | | `totalCountGrowthRate` | (仿¥ç´¯è®¡ - æ¨æ¥ç´¯è®¡) / æ¨æ¥ç´¯è®¡ à 100 | **(仿¥åæ¥é - æ¨æ¥åæ¥é) / æ¨æ¥åæ¥é à 100** | | `todayPendingCount` | `inspect_state=0` ä¸ `check_time = ä»å¤© 00:00:00` | `inspect_state=0` ä¸ `check_time` â \[ä»å¤© 00:00, æå¤© 00:00) | | `todayPendingCountGrowthRate` | (仿¥å¾ 宿 - æ¨æ¥å¾ 宿) / æ¨æ¥å¾ 宿 à 100 | ä¸åï¼ä½åå忝齿¯çæ£"彿¥é" | | `todayCompletedCount` | åä¸ | åä¸ | | `todayCompletedCountGrowthRate` | åä¸ | åä¸ | ### ååºç¤ºä¾ ```json { "code": 200, "msg": "æä½æå", "data": { "totalCount": 12345.00, "totalCountGrowthRate": 8.50, "todayPendingCount": 12.00, "todayPendingCountGrowthRate": -20.00, "todayCompletedCount": 80.00, "todayCompletedCountGrowthRate": 15.50 } } ``` ### å端修æ¹ç¹ `totalCountGrowthRate` çè§è§æç¤ºææ¡å»ºè®®ä» "æ»æ£éªæ°åæ¯å¢é¿" æ¹ä¸º "仿¥æ°å¢ vs æ¨æ¥æ°å¢"ï¼é¿å è¯¯è§£ä¸ºç´¯è®¡åæ¯ã ```html <el-tooltip content="仿¥åæ¥æ£éªæ°ç¸å¯¹æ¨æ¥åæ¥æ£éªæ°çå¢é¿ç"> <span>æ»æ£éªæ°åæ¯ {{ formatRate(data.totalCountGrowthRate) }}</span> </el-tooltip> ``` ```js methods: { formatRate(rate) { if (rate === null || rate === undefined) return '0%'; const sign = rate > 0 ? '+' : ''; return `${sign}${rate}%`; } } ``` ## äºã`/home/unqualifiedProductRanking` (å£å¾åæ´ï¼å端éå ³æ³¨) ### åæ´åå åå®ç°æåææ `inspect_state=1` çè®°å½å°å ååèåæåºï¼æ°æ®é大æ¶åå¨ OOM é£é©ã ### æ°å£å¾ | 维度 | æ§ | æ° | |------|----|----| | æ¶é´èå´ | å ¨åå² | **è¿ 30 天 (å«ä»å¤©)** | | æåº | åæ ¼çååº Top5 | ä¸å | | åæ®µ | `productName / totalCount / completedCount / passRate` | ä¸å | ### å端修æ¹ç¹ 妿å½å页颿 "å ¨åå²" ä¹ç±»çææ¡ï¼è¯·æ¹æ "è¿ 30 天"ã ```html <div class="card-title">ä¸åæ ¼äº§åæå <span class="sub">(è¿ 30 天)</span></div> ``` ## ä¸ãæ¥æä¸çç»ä¸æ¹ä¸ºå³å¼åºé´ (è¯ä¹æªåï¼ä½è¡¥å ¨æ°æ®) `commonDetection` (rawMaterial / process / factoryDetection)ã`nonComplianceWarning`ã`completedInspectionCount`ã`qualityInspectionStatistics` ä¹åé½ç¨ `le(checkTime, endDate)`ã å½ `check_time` æ¯ `datetime` åæ¶ï¼`<= "yyyy-MM-dd"` çä»·äº `<= "yyyy-MM-dd 00:00:00"`ï¼ä¼æ¼æå½å¤© 00:00:00 ä¹åçææè®°å½ã å端已ç»ä¸æ¹ä¸º `lt(checkTime, endDate + 1 天)`ï¼**ååºå段ãåæ®µè¯ä¹ä¸å**ï¼åªæ¯å½å¤©æ°æ®ä¸å丢失ã ### å端修æ¹ç¹ æ éæ¹å¨ä»£ç ãä½å»ºè®®èè°æ¶æ ¸å¯¹ï¼å¨/æ/å£è§å¾æåä¸å¤©æ¯å¦åºç°ä»¥åç¼ºå¤±çæ£éªè®°å½ã ## åãå ¶ä»å é¨ä¼å (åç«¯æ æ) - `qualityInspectionCount` æ¹ç¨ `SELECT COALESCE(SUM(quantity), 0)` èåï¼å次 SQL æ¿ä»£ä¹åç 6 æ¬¡å ¨è¡¨ `selectList`ã - `qualityInspectionStatistics` ä¸ `i.getInspectType() == 0` ä¿®å¤ä¸º `Objects.equals(...)`ï¼é¿å Integer èªå¨è£ ç®±ç¼åèå´å¤ççå¼è¯¯å¤ã ## 注æäºé¡¹ - `qualityInspectionCount` ç `totalCountGrowthRate` ç°å¨åæ çæ¯"æ¥ç¯æ¯å¢é¿ç"ï¼ä¸å¡ä¾§ææ¡ä¸å¾è¡¨è¯´æéåæ¥è°æ´ã - `unqualifiedProductRanking` æ¹ä¸ºè¿ 30 天åï¼**Top5 å表å¯è½åå**ï¼è¯·éç¥ä¸å¡ç¡®è®¤ã - ä¸çº¿å建议èè°ä»¥ä¸åºæ¯ï¼ - `check_time` 为é 00:00:00 çæ£éªè®°å½æ¯å¦è¢«æ£ç¡®ç»è®¡ (å¨/æè§å¾æåä¸å¤©)ã - 仿¥æææ¥æ£ç"å¾ å®æ / 已宿"æ°æ®æ¯å¦è½å®æ¶åæ å°é¦é¡µå¡çã - è¥ææ¥å£éè¦ä¿çæ§çå ¨åå²å£å¾ (ä¾å¦å¯¼åºã对账)ï¼è¯·åç¬æéæ±å¢å æ°æ¥å£ï¼é¿å æ¹åé¦é¡µæ¥å£ã --- ## äºãæ£éªè§åé»è®¤å¼é»è¾åæ´ (æ°å¢æ£éªå) ### ä¸å¡è§å 彿°å»ºæ£éªåæ¶ï¼åç«¯ä¼æ ¹æ® `inspectRule` èªå¨è¡¥å ¨ `sampleRatio` å `sampleQuantity`ï¼ | inspectRule | å«ä¹ | sampleRatio | sampleQuantity | |-------------|------|-------------|----------------| | 0 æ null | å ¨æ£ | 100 (åºå®) | `quantity` (å ¨é¨æ°é) | | 1 | æ½æ£ | å `sampleRatio` ä¼ å ¥å¼ (è¥ä¸ºç©ºå 0) | `quantity à sampleRatio / 100` (åä¸åæ´) | ### å端修æ¹ç¹ æ°å¢æ£éªå页é¢ï¼æ£éªè§å䏿鿩åï¼ ```html <el-form-item label="æ£éªè§å"> <el-select v-model="form.inspectRule" @change="onInspectRuleChange"> <el-option label="å ¨æ£" :value="0" /> <el-option label="æ½æ£" :value="1" /> </el-select> </el-form-item> <el-form-item label="æ½æ£æ¯ä¾(%)" v-if="form.inspectRule === 1"> <el-input-number v-model="form.sampleRatio" :min="0" :max="100" /> </el-form-item> <el-form-item label="æ½æ£æ°é"> <el-input :value="computedSampleQuantity" disabled /> </el-form-item> ``` ```js computed: { computedSampleQuantity() { if (this.form.inspectRule === 0 || this.form.inspectRule === null) { // å ¨æ£æ¶ï¼æ½æ£æ°é = æ»æ°é return this.form.quantity || 0; } // æ½æ£æ¶ï¼æ½æ£æ°é = æ»æ°é à æ¯ä¾ / 100 (åä¸åæ´) const qty = this.form.quantity || 0; const ratio = this.form.sampleRatio || 0; return Math.ceil(qty * ratio / 100); } }, methods: { onInspectRuleChange(val) { if (val === 0) { // å ¨æ£æ¶èªå¨æ¸ ç©ºæ½æ£æ¯ä¾è¾å ¥æ¡ this.form.sampleRatio = 100; } } } ``` ### 注æäºé¡¹ - å端已åå åºå¤çï¼å³ä½¿å端ä¸ä¼ `sampleRatio/sampleQuantity`ï¼ä¹ä¼èªå¨è¡¥å ¨ã - 建议åç«¯å¨æäº¤ååé¢è®¡ç®å±ç¤ºï¼æåç¨æ·ä½éªã - éè´å ¥åºèªå¨çææ£éªåãæ¥å·¥çæè¿ç¨/åºåæ£éªåæ¶ï¼åæ ·ä¼ææ¤è§åèªå¨å¡«å ã docs/20260618_quick_inspect_sample.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,393 @@ # è´¨æ£å¿«éæ£éªæ½æ£åè½å端èè°ææ¡£ > æ©å±æ¹éå¿«éæ£éªæ¥å£ï¼æ¯æå ¨æ£åæ½æ£ä¸¤ç§æ£éªæ¨¡å¼ï¼èªå¨å¡«å æ½æ£æ°éã ## æ¶åé¡µé¢ - è´¨é管ç / æ£éªåå表 - æ¹éå¿«éæ£éªå¼¹çª - è´¨é管ç / åæææ£éª / è¿ç¨æ£éª / åºåæ£éª - å¿«éæ£éªæä½ ## API | æ¹æ³ | è·¯å¾ | 说æ | |------|------|------| | POST | /qualityInspect/batchQuickInspect | æ¹éå¿«éæ£éª (æ©å±åæ°) | **请æ±åæ°ï¼** | åæ° | ç±»å | å¿ å¡« | 说æ | |------|------|------|------| | ids | List\<Long\> | æ¯ | æ£éªåIDå表 | | checkResult | String | æ¯ | æ£æµç»æï¼åæ ¼/ä¸åæ ¼/é¨ååæ ¼ | | testStandardId | Long | æ¯ | ææ æ åID | | checkCompany | String | å¦ | æ£æµåä½ | | checkName | String | å¦ | æ£éªåå§å | | checkTime | String | å¦ | æ£æµæ¥æï¼æ ¼å¼ï¼YYYY-MM-DD | | paramList | List | å¦ | æ£éªåæ°å表 | | **sampleQuantity** | BigDecimal | å¦ | **æ½æ£æ°éï¼æ°å¢ï¼** | | **qualifiedQuantity** | BigDecimal | å¦ | **åæ ¼æ°éï¼æ°å¢ï¼** | | **unqualifiedQuantity** | BigDecimal | å¦ | **ä¸åæ ¼æ°éï¼æ°å¢ï¼** | **ååºï¼** ```json { "code": 200, "msg": "å¿«éæ£éªå®æï¼æå 3 æ¡" } ``` ## ä¸å¡è§å说æ ### æ£éªæ¨¡å¼å¤æ æ ¹æ®æ£éªåç `inspectRule` åæ®µå¤ææ£éªæ¨¡å¼ï¼ | inspectRule | æ£éªæ¨¡å¼ | å¤çé»è¾ | |-------------|----------|----------| | 0 æ null | å ¨æ£ | æ£éªæ°é = æ»æ°éï¼é»è®¤å ¨é¨åæ ¼ | | 1 | æ½æ£ | æ£éªæ°é = æ½æ£æ ·æ¬æ°é | ### æ½æ£æ°éæ¥æºä¼å 级 彿£éªåä¸ºæ½æ£æ¨¡å¼æ¶ï¼æ½æ£æ°éæä»¥ä¸ä¼å 级确å®ï¼ 1. **åç«¯ä¼ å ¥** `sampleQuantity`ï¼æé«ä¼å çº§ï¼ 2. **æ£éªåå·²æ** `sampleQuantity` 3. **ææ½æ£æ¯ä¾è®¡ç®**ï¼`æ»æ°é à sampleRatio / 100`ï¼åä¸åæ´ï¼ 4. æ ¡éªï¼æ½æ£æ°éä¸è½è¶ è¿æ»æ°éï¼è¶ è¿åèªå¨ä¿®æ£ä¸ºæ»æ°é ### åæ ¼/ä¸åæ ¼æ°é | åºæ¯ | å¤çé»è¾ | |------|----------| | åç«¯ä¼ å ¥äº qualifiedQuantity/unqualifiedQuantity | 使ç¨åç«¯ä¼ å ¥å¼ | | å端æªä¼ å ¥ | é»è®¤å ¨é¨åæ ¼ï¼åæ ¼æ°=æ£éªæ°éï¼ä¸åæ ¼æ°=0ï¼ | ### å ¥åºå¤ç - å ¥åºæ°é = åæ ¼æ°é Ã å ¥åºæ¯ä¾ / 100 - å ¥åºæ¯ä¾é»è®¤ 100%ï¼å¯éè¿ `stockInRatio` åæ®µè°æ´ ## å端修æ¹ç¹ ### 1. å¿«éæ£éªå¼¹çªå¢å æ½æ£å段 ```html <el-dialog title="æ¹éå¿«éæ£éª" v-model="quickInspectVisible"> <el-form :model="quickInspectForm" label-width="100px"> <!-- åºç¡å段 --> <el-form-item label="æ£æµç»æ" required> <el-select v-model="quickInspectForm.checkResult"> <el-option label="åæ ¼" value="åæ ¼" /> <el-option label="ä¸åæ ¼" value="ä¸åæ ¼" /> <el-option label="é¨ååæ ¼" value="é¨ååæ ¼" /> </el-select> </el-form-item> <el-form-item label="ææ æ å" required> <el-select v-model="quickInspectForm.testStandardId"> <!-- ææ æ åå表 --> </el-select> </el-form-item> <el-form-item label="æ£éªå"> <el-input v-model="quickInspectForm.checkName" /> </el-form-item> <el-form-item label="æ£æµæ¥æ"> <el-date-picker v-model="quickInspectForm.checkTime" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD" /> </el-form-item> <!-- æ½æ£ç¸å ³åæ®µï¼æ ¹æ®æ£éªå模å¼å¨ææ¾ç¤ºï¼ --> <el-form-item label="æ£éªæ¨¡å¼"> <el-tag :type="inspectModeTag">{{ inspectModeLabel }}</el-tag> </el-form-item> <!-- æ½æ£æ¨¡å¼ä¸æ¾ç¤º --> <el-form-item label="æ½æ£æ°é" v-if="showSampleFields"> <el-input-number v-model="quickInspectForm.sampleQuantity" :min="1" :max="maxSampleQuantity" :precision="0" /> <span class="tip">æå¤§å¯æ½æ£æ°éï¼{{ maxSampleQuantity }}</span> </el-form-item> <!-- é¨ååæ ¼æä¸åæ ¼æ¶æ¾ç¤º --> <el-form-item label="åæ ¼æ°é" v-if="showQuantityFields"> <el-input-number v-model="quickInspectForm.qualifiedQuantity" :min="0" :max="quickInspectForm.sampleQuantity || totalQuantity" :precision="0" /> </el-form-item> <el-form-item label="ä¸åæ ¼æ°é" v-if="showQuantityFields"> <el-input-number v-model="quickInspectForm.unqualifiedQuantity" :min="0" :max="quickInspectForm.sampleQuantity || totalQuantity" :precision="0" /> </el-form-item> </el-form> <template #footer> <el-button @click="quickInspectVisible = false">åæ¶</el-button> <el-button type="primary" @click="submitQuickInspect">确认æ£éª</el-button> </template> </el-dialog> ``` ### 2. data æ°æ® ```js data() { return { quickInspectVisible: false, quickInspectForm: { ids: [], checkResult: 'åæ ¼', testStandardId: null, checkCompany: '', checkName: '', checkTime: '', paramList: [], sampleQuantity: null, qualifiedQuantity: null, unqualifiedQuantity: null, }, // éä¸çæ£éªåå表 selectedInspects: [], // å½åæ£éªåä¿¡æ¯ï¼ç¨äºåæ¡å¿«éæ£éªï¼ currentInspect: null, } } ``` ### 3. computed 计ç®å±æ§ ```js computed: { // æ£éªæ¨¡å¼æ ç¾ inspectModeLabel() { if (!this.currentInspect) return 'æªç¥'; return this.currentInspect.inspectRule === 1 ? 'æ½æ£' : 'å ¨æ£'; }, inspectModeTag() { if (!this.currentInspect) return 'info'; return this.currentInspect.inspectRule === 1 ? 'warning' : 'success'; }, // æ¯å¦æ¾ç¤ºæ½æ£å段 showSampleFields() { return this.currentInspect && this.currentInspect.inspectRule === 1; }, // æ¯å¦æ¾ç¤ºåæ ¼/ä¸åæ ¼æ°éè¾å ¥ï¼é¨ååæ ¼æä¸åæ ¼æ¶ï¼ showQuantityFields() { return this.quickInspectForm.checkResult === 'é¨ååæ ¼' || this.quickInspectForm.checkResult === 'ä¸åæ ¼'; }, // æ»æ°é totalQuantity() { return this.currentInspect?.quantity || 0; }, // æå¤§æ½æ£æ°é maxSampleQuantity() { return this.totalQuantity; }, // é»è®¤æ½æ£æ°éï¼ä»æ£éªåè·åæææ¯ä¾è®¡ç®ï¼ defaultSampleQuantity() { if (!this.currentInspect) return 0; if (this.currentInspect.sampleQuantity) { return this.currentInspect.sampleQuantity; } if (this.currentInspect.sampleRatio) { return Math.ceil(this.totalQuantity * this.currentInspect.sampleRatio / 100); } return this.totalQuantity; }, } ``` ### 4. methods æ¹æ³ ```js methods: { // æå¼å¿«éæ£éªå¼¹çª openQuickInspectDialog(row) { // åæ¡å¿«éæ£éª this.currentInspect = row; this.quickInspectForm.ids = [row.id]; // æ½æ£æ¨¡å¼ä¸èªå¨å¡«å æ½æ£æ°é if (row.inspectRule === 1) { this.quickInspectForm.sampleQuantity = this.defaultSampleQuantity; } // å ¶ä»å段åå§å this.quickInspectForm.checkResult = 'åæ ¼'; this.quickInspectForm.testStandardId = row.testStandardId; this.quickInspectForm.checkTime = new Date().toISOString().slice(0, 10); this.quickInspectForm.qualifiedQuantity = null; this.quickInspectForm.unqualifiedQuantity = null; this.quickInspectVisible = true; }, // æ¹éå¿«éæ£éª openBatchQuickInspectDialog(selection) { this.selectedInspects = selection; this.quickInspectForm.ids = selection.map(s => s.id); // æ¹éæ£éªæ¶ï¼åç¬¬ä¸æ¡æ£éªåçä¿¡æ¯ä½ä¸ºåè this.currentInspect = selection[0]; // æ½æ£æ¨¡å¼ä¸èªå¨å¡«å if (this.currentInspect?.inspectRule === 1) { this.quickInspectForm.sampleQuantity = this.defaultSampleQuantity; } this.quickInspectVisible = true; }, // æ£æµç»æååæ¶èªå¨è°æ´æ°é onCheckResultChange(val) { if (val === 'åæ ¼') { // åæ ¼æ¶ï¼æ¸ 空æå¨è¾å ¥çæ°é this.quickInspectForm.qualifiedQuantity = null; this.quickInspectForm.unqualifiedQuantity = null; } else if (val === 'ä¸åæ ¼') { // ä¸åæ ¼æ¶ï¼é»è®¤å ¨é¨ä¸åæ ¼ const qty = this.showSampleFields ? this.quickInspectForm.sampleQuantity : this.totalQuantity; this.quickInspectForm.qualifiedQuantity = 0; this.quickInspectForm.unqualifiedQuantity = qty; } else if (val === 'é¨ååæ ¼') { // é¨ååæ ¼æ¶ï¼éè¦ç¨æ·æå¨è¾å ¥ this.quickInspectForm.qualifiedQuantity = null; this.quickInspectForm.unqualifiedQuantity = null; } }, // æäº¤å¿«éæ£éª async submitQuickInspect() { // æ ¡éªå¿ å¡«åæ®µ if (!this.quickInspectForm.checkResult) { this.$message.warning('è¯·éæ©æ£æµç»æ'); return; } if (!this.quickInspectForm.testStandardId) { this.$message.warning('è¯·éæ©ææ æ å'); return; } // æ½æ£æ¨¡å¼ä¸æ ¡éªæ½æ£æ°é if (this.showSampleFields && !this.quickInspectForm.sampleQuantity) { this.$message.warning('请è¾å ¥æ½æ£æ°é'); return; } // é¨ååæ ¼æ¶æ ¡éªæ°é if (this.quickInspectForm.checkResult === 'é¨ååæ ¼') { if (!this.quickInspectForm.qualifiedQuantity && !this.quickInspectForm.unqualifiedQuantity) { this.$message.warning('请è¾å ¥åæ ¼æ°éåä¸åæ ¼æ°é'); return; } const total = this.showSampleFields ? this.quickInspectForm.sampleQuantity : this.totalQuantity; const sum = (this.quickInspectForm.qualifiedQuantity || 0) + (this.quickInspectForm.unqualifiedQuantity || 0); if (sum > total) { this.$message.warning('åæ ¼æ°é+ä¸åæ ¼æ°éä¸è½è¶ è¿æ£éªæ°é'); return; } } try { const res = await axios.post('/qualityInspect/batchQuickInspect', this.quickInspectForm); if (res.code === 200) { this.$message.success(res.msg); this.quickInspectVisible = false; this.refreshList(); } else { this.$message.error(res.msg); } } catch (e) { this.$message.error('å¿«éæ£éªå¤±è´¥'); } }, } ``` ### 5. æ£éªåå表æ¾ç¤ºæ½æ£ä¿¡æ¯ å»ºè®®å¨æ£éªåå表ä¸å¢å 以ä¸åï¼ ```html <el-table-column label="æ£éªè§å" width="100"> <template #default="{ row }"> <el-tag :type="row.inspectRule === 1 ? 'warning' : 'success'" size="small"> {{ row.inspectRule === 1 ? 'æ½æ£' : 'å ¨æ£' }} </el-tag> </template> </el-table-column> <el-table-column label="æ½æ£æ¯ä¾" width="100"> <template #default="{ row }"> {{ row.inspectRule === 1 ? (row.sampleRatio || 0) + '%' : '-' }} </template> </el-table-column> <el-table-column label="æ½æ£æ°é" width="100"> <template #default="{ row }"> {{ row.inspectRule === 1 ? (row.sampleQuantity || '-') : row.quantity }} </template> </el-table-column> ``` ## 请æ±ç¤ºä¾ ### å ¨æ£æ¨¡å¼ ```json { "ids": [1, 2, 3], "checkResult": "åæ ¼", "testStandardId": 100, "checkName": "å¼ ä¸", "checkTime": "2026-06-18" } ``` ### æ½æ£æ¨¡å¼ - å ¨é¨åæ ¼ ```json { "ids": [4], "checkResult": "åæ ¼", "testStandardId": 100, "checkName": "å¼ ä¸", "checkTime": "2026-06-18", "sampleQuantity": 50 } ``` ### æ½æ£æ¨¡å¼ - é¨ååæ ¼ ```json { "ids": [5], "checkResult": "é¨ååæ ¼", "testStandardId": 100, "checkName": "å¼ ä¸", "checkTime": "2026-06-18", "sampleQuantity": 50, "qualifiedQuantity": 45, "unqualifiedQuantity": 5 } ``` ## 注æäºé¡¹ - æ¹éå¿«éæ£éªæ¶ï¼å¦æéä¸çæ£éªåæä¸åçæ£éªè§åï¼å ¨æ£/æ½æ£ï¼ï¼å»ºè®®æç¤ºç¨æ·åå¼å¤çï¼æå端æç¬¬ä¸æ¡æ£éªåçæ¨¡å¼ç»ä¸å¤çã - æ½æ£æ°éç±åç«¯ä¼ å ¥æ¶ï¼åç«¯ä¼æ ¡éªä¸è¶ è¿æ»æ°éï¼è¶ åºèªå¨ä¿®æ£ã - æ½æ£æ¨¡å¼ä¸ï¼å ¥åºæ°éææ½æ£æ ·æ¬çåæ ¼æ°é计ç®ï¼èéæ¨ç®æ»éã - å¦é卿½æ£æ¨¡å¼ä¸æ ¹æ®æ ·æ¬åæ ¼çæ¨ç®æ»éå ¥åºæ¯ä¾ï¼è¯·å¦è¡æåºéæ±ã - åç«¯å¨æå¼å¼¹çªæ¶ï¼åºèªå¨å¡«å æ£éªåå·²æç `sampleQuantity` æææ¯ä¾è®¡ç®çé»è®¤å¼ï¼åå°ç¨æ·è¾å ¥è´æ ã docs/quality_inspect_rule.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,108 @@ # è´¨éæ£éªè§åï¼å ¨æ£/æ½æ£ï¼ ## æ¶åé¡µé¢ - æ£æµæ å管ç页é¢ï¼æ°å¢/ç¼è¾å¼¹çªãåè¡¨ï¼ - åæææ£éªé¡µé¢ï¼åè¡¨ãæ°å¢/ç¼è¾å¼¹çªï¼ - è¿ç¨æ£éªé¡µé¢ï¼åè¡¨ãæ°å¢/ç¼è¾å¼¹çªï¼ - åºåæ£éªé¡µé¢ï¼åè¡¨ãæ°å¢/ç¼è¾å¼¹çªï¼ ## API ### æ£æµæ å | æ¹æ³ | è·¯å¾ | 说æ | |------|------|------| | POST | /qualityTestStandard/add | æ°å¢æ£æµæ åï¼æ°å¢ inspectRuleãsampleRatio åæ®µï¼ | | POST | /qualityTestStandard/update | ä¿®æ¹æ£æµæ åï¼æ°å¢ inspectRuleãsampleRatio åæ®µï¼ | | GET | /qualityTestStandard/listPage | å表æ¥è¯¢ï¼è¿åæ°å¢åæ®µï¼ | **æ°å¢è¯·æ±/ååºåæ°ï¼** | åæ° | ç±»å | å¿ å¡« | 说æ | |------|------|------|------| | inspectRule | Integer | å¦ | æ£éªè§å: 0=å ¨æ£, 1=æ½æ£ï¼é»è®¤0 | | sampleRatio | BigDecimal | å¦ | æ½æ£æ¯ä¾(ç¾åæ¯)ï¼ä» inspectRule=1æ¶ææï¼å¦10表示10% | ### è´¨æ£è®°å½ï¼åææ/è¿ç¨/åºåæ£éªï¼ | æ¹æ³ | è·¯å¾ | 说æ | |------|------|------| | POST | /qualityInspect/add | æ°å¢è´¨æ£è®°å½ï¼æ°å¢ inspectRuleãsampleRatioãsampleQuantity åæ®µï¼ | | POST | /qualityInspect/update | ä¿®æ¹è´¨æ£è®°å½ï¼æ°å¢åæ®µï¼ | | GET | /qualityInspect/listPage | å表æ¥è¯¢ï¼è¿åæ°å¢åæ®µï¼ | | POST | /qualityInspect/export | 导åºExcelï¼æ°å¢"æ£éªè§å"ã"æ½æ£æ¯ä¾"ã"æ½æ£æ°é"åï¼ | **æ°å¢ååºåæ°ï¼** | åæ° | ç±»å | 说æ | |------|------|------| | inspectRule | Integer | æ£éªè§å: 0=å ¨æ£, 1=æ½æ£ | | sampleRatio | BigDecimal | æ½æ£æ¯ä¾(%) | | sampleQuantity | BigDecimal | æ½æ£æ°é | **说æï¼** ç产æ¥å·¥èªå¨å建质æ£è®°å½æ¶ï¼ä¼ä»å ³èçæ£æµæ åå¤å¶ `inspectRule` å `sampleRatio`ï¼å¹¶èªå¨è®¡ç® `sampleQuantity = æ»æ°é Ã æ½æ£æ¯ä¾ / 100`ï¼åä¸åæ´ï¼ã ## å端修æ¹ç¹ ### 1. æ£æµæ å - æ°å¢/ç¼è¾å¼¹çª ```html <el-form-item label="æ£éªè§å" prop="inspectRule"> <el-radio-group v-model="form.inspectRule"> <el-radio :label="0">å ¨æ£</el-radio> <el-radio :label="1">æ½æ£</el-radio> </el-radio-group> </el-form-item> <el-form-item label="æ½æ£æ¯ä¾(%)" prop="sampleRatio" v-if="form.inspectRule === 1"> <el-input-number v-model="form.sampleRatio" :min="0.01" :max="100" :precision="2" placeholder="请è¾å ¥æ½æ£æ¯ä¾" /> </el-form-item> ``` ### 2. æ£æµæ å - å表 ```html <el-table-column label="æ£éªè§å" prop="inspectRule" min-width="100"> <template #default="{ row }"> {{ row.inspectRule === 0 ? 'å ¨æ£' : row.inspectRule === 1 ? 'æ½æ£' : '' }} </template> </el-table-column> <el-table-column label="æ½æ£æ¯ä¾(%)" prop="sampleRatio" min-width="120" /> ``` ### 3. è´¨æ£è®°å½ - å表ï¼åææ/è¿ç¨/åºåæ£éªé¡µé¢ï¼ ```html <el-table-column label="æ£éªè§å" prop="inspectRule" min-width="100"> <template #default="{ row }"> {{ row.inspectRule === 0 ? 'å ¨æ£' : row.inspectRule === 1 ? 'æ½æ£' : '' }} </template> </el-table-column> <el-table-column label="æ½æ£æ¯ä¾(%)" prop="sampleRatio" min-width="120" /> <el-table-column label="æ½æ£æ°é" prop="sampleQuantity" min-width="100" /> ``` ### 4. è´¨æ£è®°å½ - æ°å¢/ç¼è¾å¼¹çªï¼å¯éæå¨å¡«åï¼ ```html <el-form-item label="æ£éªè§å" prop="inspectRule"> <el-radio-group v-model="form.inspectRule"> <el-radio :label="0">å ¨æ£</el-radio> <el-radio :label="1">æ½æ£</el-radio> </el-radio-group> </el-form-item> <el-form-item label="æ½æ£æ¯ä¾(%)" prop="sampleRatio" v-if="form.inspectRule === 1"> <el-input-number v-model="form.sampleRatio" :min="0.01" :max="100" :precision="2" placeholder="请è¾å ¥æ½æ£æ¯ä¾" /> </el-form-item> ``` ### 5. å¯¼åº å¯¼åºExcelèªå¨æ°å¢"æ£éªè§å"ã"æ½æ£æ¯ä¾(%)"ã"æ½æ£æ°é"åï¼æ éå端é¢å¤å¤çã ## 注æäºé¡¹ - æ§è¡æ°æ®åºè¿ç§»èæ¬ `doc/20260617_quality_inspect_rule.sql` ååé¨ç½² - æ£æµæ å设置æ£éªè§ååï¼ç产æ¥å·¥èªå¨çæçè´¨æ£è®°å½ä¼ç»§æ¿è¯¥è§å - æ½æ£æ¯ä¾ä» 卿£éªè§å为"æ½æ£"æ¶æéå¡«å - æ½æ£æ°éç±ç³»ç»èªå¨è®¡ç®ï¼`æ»æ°é Ã æ½æ£æ¯ä¾ / 100`ï¼åä¸åæ´ï¼ï¼æ éæå¨å¡«å src/main/java/com/ruoyi/approve/service/impl/ApproveBusinessStatusService.java
@@ -159,7 +159,26 @@ qualityInspectMapper.insert(qualityInspect); List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(saleProduct.getProductId(), 0, null); if (qualityTestStandard.size() > 0) { qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId()); QualityTestStandard std = qualityTestStandard.get(0); qualityInspect.setTestStandardId(std.getId()); // æ ¹æ® inspectRule è®¾ç½®æ½æ£æ¯ä¾åæ½æ£æ°éé»è®¤å¼ if (std.getInspectRule() == null || std.getInspectRule() == 0) { // å ¨æ£ qualityInspect.setInspectRule(0); qualityInspect.setSampleRatio(java.math.BigDecimal.valueOf(100)); qualityInspect.setSampleQuantity(saleProduct.getQuantity() != null ? saleProduct.getQuantity() : java.math.BigDecimal.ZERO); } else { // æ½æ£ qualityInspect.setInspectRule(1); java.math.BigDecimal ratio = std.getSampleRatio() != null ? std.getSampleRatio() : java.math.BigDecimal.ZERO; qualityInspect.setSampleRatio(ratio); if (saleProduct.getQuantity() != null && ratio.compareTo(java.math.BigDecimal.ZERO) > 0) { qualityInspect.setSampleQuantity(saleProduct.getQuantity().multiply(ratio) .divide(java.math.BigDecimal.valueOf(100), 0, java.math.RoundingMode.CEILING)); } else { qualityInspect.setSampleQuantity(java.math.BigDecimal.ZERO); } } qualityInspectMapper.updateById(qualityInspect); qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery() .eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId())) src/main/java/com/ruoyi/basic/dto/StorageBlobDTO.java
@@ -5,6 +5,8 @@ import com.ruoyi.basic.pojo.StorageBlob; import lombok.Data; import java.util.Map; @Data public class StorageBlobDTO extends StorageBlob { /** @@ -23,7 +25,7 @@ private String application; /** * æ¯æä»æ°åIDååºååï¼å端å¯è½åªä¼ IDï¼ * æ¯æä»æ°åIDæå®æ´JSON对象ååºåå */ @JsonCreator public static StorageBlobDTO from(Object value) { @@ -32,6 +34,47 @@ dto.setId(((Number) value).longValue()); return dto; } if (value instanceof Map) { @SuppressWarnings("unchecked") Map<String, Object> map = (Map<String, Object>) value; StorageBlobDTO dto = new StorageBlobDTO(); if (map.get("id") instanceof Number) { dto.setId(((Number) map.get("id")).longValue()); } if (map.get("resourceKey") instanceof String) { dto.setResourceKey((String) map.get("resourceKey")); } if (map.get("contentType") instanceof String) { dto.setContentType((String) map.get("contentType")); } if (map.get("originalFilename") instanceof String) { dto.setOriginalFilename((String) map.get("originalFilename")); } if (map.get("uidFilename") instanceof String) { dto.setUidFilename((String) map.get("uidFilename")); } if (map.get("byteSize") instanceof Number) { dto.setByteSize(((Number) map.get("byteSize")).longValue()); } if (map.get("path") instanceof String) { dto.setPath((String) map.get("path")); } if (map.get("previewURL") instanceof String) { dto.setPreviewURL((String) map.get("previewURL")); } if (map.get("downloadURL") instanceof String) { dto.setDownloadURL((String) map.get("downloadURL")); } return dto; } if (value instanceof String) { try { StorageBlobDTO dto = new StorageBlobDTO(); dto.setId(Long.parseLong((String) value)); return dto; } catch (NumberFormatException ignored) { } } throw new IllegalArgumentException("æ æ³ååºåå StorageBlobDTO: " + value); } } src/main/java/com/ruoyi/home/dto/QualityQualifiedAnalysisDto.java
@@ -20,12 +20,12 @@ /** * åæ ¼æ° */ private int qualifiedCount; private BigDecimal qualifiedCount; /** * ä¸åæ ¼æ° */ private int unqualifiedCount; private BigDecimal unqualifiedCount; /** * åæ ¼æ¯ä¾ src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -1721,14 +1721,15 @@ LocalDate endDate = range[1]; String startStr = startDate.toString(); String endStr = endDate.toString(); // 使ç¨åºé´å³å¼ï¼< endDate + 1 天ï¼ä¿è¯æ£æµæ¶é´å«æ¶åç§æ¶ä¹è½è¦çå° endDate å½å¤© String endExclusiveStr = endDate.plusDays(1).toString(); List<QualityInspect> list = qualityInspectMapper.selectList( new LambdaQueryWrapper<QualityInspect>() .eq(QualityInspect::getInspectType, inspectType) .eq(QualityInspect::getInspectState, 1) .ge(QualityInspect::getCheckTime, startStr) .le(QualityInspect::getCheckTime, endStr)); .lt(QualityInspect::getCheckTime, endExclusiveStr)); return buildQualifiedAnalysis(list); } @@ -1767,8 +1768,8 @@ QualityQualifiedAnalysisDto dto = new QualityQualifiedAnalysisDto(); if (CollectionUtils.isEmpty(list)) { dto.setQualifiedCount(0); dto.setUnqualifiedCount(0); dto.setQualifiedCount(BigDecimal.valueOf(0)); dto.setUnqualifiedCount(BigDecimal.valueOf(0)); dto.setQualifiedRate(BigDecimal.ZERO.setScale(2)); dto.setUnqualifiedRate(BigDecimal.ZERO.setScale(2)); return dto; @@ -1784,8 +1785,8 @@ BigDecimal totalCount = qualifiedCount.add(unqualifiedCount); dto.setQualifiedCount(qualifiedCount.intValue()); dto.setUnqualifiedCount(unqualifiedCount.intValue()); dto.setQualifiedCount(qualifiedCount); dto.setUnqualifiedCount(unqualifiedCount); if (totalCount.compareTo(BigDecimal.ZERO) == 0) { dto.setQualifiedRate(BigDecimal.ZERO.setScale(2)); @@ -1808,74 +1809,64 @@ @Override public QualityInspectionCountDto qualityInspectionCount() { String todayStr = LocalDate.now().toString(); String prevDayStr = LocalDate.now().minusDays(1).toString(); // æ¥è¯¢åºæªæ¢ä»æ¥çæ»æ£éªæ° List<QualityInspect> todayList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>() .le(QualityInspect::getCheckTime, todayStr)); // æ¥è¯¢åºæªæ¢åä¸å¤©çæ»æ£éªæ° List<QualityInspect> prevList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>() .le(QualityInspect::getCheckTime, prevDayStr)); // 计ç®ä»æ¥çæ»æ£éªæ° BigDecimal todayCount = todayList.stream() .map(QualityInspect::getQuantity) .reduce(BigDecimal.ZERO, BigDecimal::add); // 计ç®åä¸å¤©çæ»æ£éªæ° BigDecimal prevCount = prevList.stream() .map(QualityInspect::getQuantity) .reduce(BigDecimal.ZERO, BigDecimal::add); LocalDate today = LocalDate.now(); String todayStartStr = today.toString(); String tomorrowStartStr = today.plusDays(1).toString(); String yesterdayStartStr = today.minusDays(1).toString(); // 计ç®ä»æ¥ç¸å¯¹æ¨å¤©çä¸ä¸ªæ»æ¯å¢é¿ BigDecimal growthRate = calcGrowthRate(todayCount, prevCount); // ç´¯è®¡æ»æ£éªæ°ï¼æªæ¢ä»æ¥ 24:00 ä¹åçææè®°å½ï¼ BigDecimal totalCount = sumInspectQuantity(null, tomorrowStartStr, null); // 仿¥åæ¥æ£éªæ° BigDecimal todayCount = sumInspectQuantity(todayStartStr, tomorrowStartStr, null); // æ¨æ¥åæ¥æ£éªæ° BigDecimal yesterdayCount = sumInspectQuantity(yesterdayStartStr, todayStartStr, null); // æ»æ£éªæ°åæ¯å¢é¿ = (仿¥åæ¥ - æ¨æ¥åæ¥) / æ¨æ¥åæ¥ Ã 100% BigDecimal growthRate = calcGrowthRate(todayCount, yesterdayCount); // 计ç®ä»å¤©çå¾ å®ææ°é List<QualityInspect> todayPendingList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>() .eq(QualityInspect::getInspectState, 0) .eq(QualityInspect::getCheckTime, todayStr)); // 仿¥å¾ 宿ï¼inspectState=0ï¼ BigDecimal todayPendingCount = sumInspectQuantity(todayStartStr, tomorrowStartStr, 0); BigDecimal yesterdayPendingCount = sumInspectQuantity(yesterdayStartStr, todayStartStr, 0); BigDecimal todayPendingCountGrowthRate = calcGrowthRate(todayPendingCount, yesterdayPendingCount); // 计ç®åä¸å¤©çå¾ å®ææ°é List<QualityInspect> prevPendingList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>() .eq(QualityInspect::getInspectState, 0) .eq(QualityInspect::getCheckTime, prevDayStr)); // 计ç®ä»å¤©çå¾ å®ææ°é BigDecimal todayPendingCount = todayPendingList.stream() .map(QualityInspect::getQuantity) .reduce(BigDecimal.ZERO, BigDecimal::add); // 仿¥å·²å®æï¼inspectState=1ï¼ BigDecimal todayCompletedCount = sumInspectQuantity(todayStartStr, tomorrowStartStr, 1); BigDecimal yesterdayCompletedCount = sumInspectQuantity(yesterdayStartStr, todayStartStr, 1); BigDecimal todayCompletedCountGrowthRate = calcGrowthRate(todayCompletedCount, yesterdayCompletedCount); // 计ç®åä¸å¤©çå¾ å®ææ°é BigDecimal prevPendingCount = prevPendingList.stream() .map(QualityInspect::getQuantity) .reduce(BigDecimal.ZERO, BigDecimal::add); // 计ç®ä»å¤©çå¾ å®ææ°éç¸å¯¹æ¨å¤©çä¸ä¸ªåæ¯å¢é¿ BigDecimal todayPendingCountGrowthRate = calcGrowthRate(todayPendingCount, prevPendingCount); // 计ç®ä»å¤©ç已宿æ°é List<QualityInspect> todayCompletedList = qualityInspectMapper .selectList(new LambdaQueryWrapper<QualityInspect>() .eq(QualityInspect::getInspectState, 1) .eq(QualityInspect::getCheckTime, todayStr)); // 计ç®åä¸å¤©ç已宿æ°é List<QualityInspect> prevCompletedList = qualityInspectMapper .selectList(new LambdaQueryWrapper<QualityInspect>() .eq(QualityInspect::getInspectState, 1) .eq(QualityInspect::getCheckTime, prevDayStr)); // 计ç®ä»å¤©ç已宿æ°é BigDecimal todayCompletedCount = todayCompletedList.stream() .map(QualityInspect::getQuantity) .reduce(BigDecimal.ZERO, BigDecimal::add); // 计ç®åä¸å¤©ç已宿æ°é BigDecimal prevCompletedCount = prevCompletedList.stream() .map(QualityInspect::getQuantity) .reduce(BigDecimal.ZERO, BigDecimal::add); // 计ç®ä»å¤©ç已宿æ°éç¸å¯¹æ¨å¤©çä¸ä¸ªåæ¯å¢é¿ BigDecimal todayCompletedCountGrowthRate = calcGrowthRate(todayCompletedCount, prevCompletedCount); QualityInspectionCountDto dto = new QualityInspectionCountDto(); dto.setTotalCount(todayCount); dto.setTotalCount(totalCount); dto.setTotalCountGrowthRate(growthRate); dto.setTodayPendingCount(todayPendingCount); dto.setTodayPendingCountGrowthRate(todayPendingCountGrowthRate); dto.setTodayCompletedCount(todayCompletedCount); dto.setTodayCompletedCountGrowthRate(todayCompletedCountGrowthRate); return dto; } /** * éè¿ SQL SUM èå quality_inspect.quantityï¼é¿å æå ¨è¡¨å è½½å°å å */ private BigDecimal sumInspectQuantity(String startInclusive, String endExclusive, Integer inspectState) { QueryWrapper<QualityInspect> wrapper = new QueryWrapper<>(); wrapper.select("COALESCE(SUM(quantity), 0) AS total"); if (startInclusive != null) { wrapper.ge("check_time", startInclusive); } if (endExclusive != null) { wrapper.lt("check_time", endExclusive); } if (inspectState != null) { wrapper.eq("inspect_state", inspectState); } List<Map<String, Object>> rows = qualityInspectMapper.selectMaps(wrapper); if (rows == null || rows.isEmpty()) { return BigDecimal.ZERO; } Object total = rows.get(0).get("total"); if (total == null) { return BigDecimal.ZERO; } return total instanceof BigDecimal ? (BigDecimal) total : new BigDecimal(total.toString()); } private BigDecimal calcGrowthRate(BigDecimal today, BigDecimal prev) { @@ -1892,14 +1883,14 @@ public NonComplianceWarningDto nonComplianceWarning() { String[] range = lastSevenDaysDateRange(); String startStr = range[0]; String endStr = range[1]; String endExclusiveStr = range[1]; // æ¥è¯¢è¿ä¸å¤©å·²å¤çä¸åæ ¼æ°æ® List<QualityUnqualified> list = qualityUnqualifiedMapper.selectList( new LambdaQueryWrapper<QualityUnqualified>() .eq(QualityUnqualified::getInspectState, 1) .ge(QualityUnqualified::getCheckTime, startStr) .le(QualityUnqualified::getCheckTime, endStr)); .lt(QualityUnqualified::getCheckTime, endExclusiveStr)); NonComplianceWarningDto dto = new NonComplianceWarningDto(); @@ -1998,24 +1989,24 @@ } /** * è·åè¿ä¸å¤©çæ¥æåºé´ï¼ä» å«å¹´ææ¥ï¼ * è·åè¿ä¸å¤©çæ¥æåºé´ï¼ä» å«å¹´ææ¥ï¼ï¼è¿å [start, endExclusive] ââ endExclusive æ¯ä»å¤© + 1 天ï¼ä¾¿äºä½¿ç¨ lt å å«ä»å¤©å ¨é¨ */ public static String[] lastSevenDaysDateRange() { LocalDate today = LocalDate.now(); return new String[]{today.minusDays(6).toString(), today.toString()}; return new String[]{today.minusDays(6).toString(), today.plusDays(1).toString()}; } @Override public List<CompletedInspectionCountDto> completedInspectionCount() { String[] range = lastSevenDaysDateRange(); String startStr = range[0]; String endStr = range[1]; String endExclusiveStr = range[1]; // æ¥è¯¢è¿ä¸å¤©å·²å®æçæ£éªæ°æ® List<QualityInspect> list = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>() .eq(QualityInspect::getInspectState, 1) .ge(QualityInspect::getCheckTime, startStr) .le(QualityInspect::getCheckTime, endStr)); .lt(QualityInspect::getCheckTime, endExclusiveStr)); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd"); @@ -2067,8 +2058,15 @@ @Override public List<UnqualifiedProductRankDto> unqualifiedProductRanking() { // éå®è¿ 30 天ï¼é¿å å ¨è¡¨å è½½ LocalDate today = LocalDate.now(); String startStr = today.minusDays(29).toString(); String endExclusiveStr = today.plusDays(1).toString(); List<QualityInspect> list = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>() .eq(QualityInspect::getInspectState, 1)); .eq(QualityInspect::getInspectState, 1) .ge(QualityInspect::getCheckTime, startStr) .lt(QualityInspect::getCheckTime, endExclusiveStr)); if (CollectionUtils.isEmpty(list)) { return new ArrayList<>(); @@ -2219,7 +2217,7 @@ List<QualityInspect> qualityInspectList = qualityInspectMapper .selectList(new LambdaQueryWrapper<QualityInspect>() .ge(QualityInspect::getCheckTime, startDate.toString()) .le(QualityInspect::getCheckTime, endDate.toString()) .lt(QualityInspect::getCheckTime, endDate.plusDays(1).toString()) .eq(QualityInspect::getInspectState, 1)); QualityStatisticsDto dto = new QualityStatisticsDto(); @@ -2294,15 +2292,15 @@ // ç»è®¡æ¯ç§æ£éªç±»åçä¸åæ ¼æ°é item.setSupplierNum(list.stream() .filter(i -> i.getInspectType() == 0) .filter(i -> Objects.equals(i.getInspectType(), 0)) .map(i -> i.getUnqualifiedQuantity() != null ? i.getUnqualifiedQuantity() : BigDecimal.ZERO) .reduce(BigDecimal.ZERO, BigDecimal::add)); item.setProcessNum(list.stream() .filter(i -> i.getInspectType() == 1) .filter(i -> Objects.equals(i.getInspectType(), 1)) .map(i -> i.getUnqualifiedQuantity() != null ? i.getUnqualifiedQuantity() : BigDecimal.ZERO) .reduce(BigDecimal.ZERO, BigDecimal::add)); item.setFactoryNum(list.stream() .filter(i -> i.getInspectType() == 2) .filter(i -> Objects.equals(i.getInspectType(), 2)) .map(i -> i.getUnqualifiedQuantity() != null ? i.getUnqualifiedQuantity() : BigDecimal.ZERO) .reduce(BigDecimal.ZERO, BigDecimal::add)); src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -336,7 +336,25 @@ qualityInspectMapper.insert(qualityInspect); List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process); if (!qualityTestStandard.isEmpty()) { qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId()); QualityTestStandard std = qualityTestStandard.get(0); qualityInspect.setTestStandardId(std.getId()); qualityInspect.setInspectRule(std.getInspectRule()); // æ ¹æ® inspectRule è®¾ç½®æ½æ£æ¯ä¾åæ½æ£æ°éé»è®¤å¼ if (std.getInspectRule() == null || std.getInspectRule() == 0) { // å ¨æ£: sampleRatio=100, sampleQuantity=å ¨é¨æ°é qualityInspect.setSampleRatio(java.math.BigDecimal.valueOf(100)); qualityInspect.setSampleQuantity(productQty != null ? productQty : java.math.BigDecimal.ZERO); } else { // æ½æ£: sampleRatio åæ åé ç½®å¼ java.math.BigDecimal ratio = std.getSampleRatio() != null ? std.getSampleRatio() : java.math.BigDecimal.ZERO; qualityInspect.setSampleRatio(ratio); if (productQty != null && ratio.compareTo(java.math.BigDecimal.ZERO) > 0) { qualityInspect.setSampleQuantity(productQty.multiply(ratio) .divide(java.math.BigDecimal.valueOf(100), 0, java.math.RoundingMode.CEILING)); } else { qualityInspect.setSampleQuantity(java.math.BigDecimal.ZERO); } } qualityInspectMapper.updateById(qualityInspect); qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery() .eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId())) src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -424,7 +424,26 @@ qualityInspectMapper.insert(qualityInspect); List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(saleProduct.getProductId(), 0,null); if (qualityTestStandard.size()>0){ qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId()); QualityTestStandard std = qualityTestStandard.get(0); qualityInspect.setTestStandardId(std.getId()); // æ ¹æ® inspectRule è®¾ç½®æ½æ£æ¯ä¾åæ½æ£æ°éé»è®¤å¼ if (std.getInspectRule() == null || std.getInspectRule() == 0) { // å ¨æ£ qualityInspect.setInspectRule(0); qualityInspect.setSampleRatio(java.math.BigDecimal.valueOf(100)); qualityInspect.setSampleQuantity(saleProduct.getQuantity() != null ? saleProduct.getQuantity() : java.math.BigDecimal.ZERO); } else { // æ½æ£ qualityInspect.setInspectRule(1); java.math.BigDecimal ratio = std.getSampleRatio() != null ? std.getSampleRatio() : java.math.BigDecimal.ZERO; qualityInspect.setSampleRatio(ratio); if (saleProduct.getQuantity() != null && ratio.compareTo(java.math.BigDecimal.ZERO) > 0) { qualityInspect.setSampleQuantity(saleProduct.getQuantity().multiply(ratio) .divide(java.math.BigDecimal.valueOf(100), 0, java.math.RoundingMode.CEILING)); } else { qualityInspect.setSampleQuantity(java.math.BigDecimal.ZERO); } } qualityInspectMapper.updateById(qualityInspect); qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery() .eq(QualityTestStandardParam::getTestStandardId,qualityTestStandard.get(0).getId())) src/main/java/com/ruoyi/quality/dto/BatchQuickInspectRequest.java
@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; import java.util.List; @Data @@ -29,4 +30,13 @@ @Schema(description = "æ£éªåæ°å表") private List<QualityInspectParam> paramList; @Schema(description = "æ½æ£æ°éï¼ç¨äºæ½æ£æ¨¡å¼æ¶å¡«åå®é æ½æ£æ ·æ¬æ°é") private BigDecimal sampleQuantity; @Schema(description = "åæ ¼æ°éï¼æ½æ£æ ·æ¬ä¸çåæ ¼æ°ï¼") private BigDecimal qualifiedQuantity; @Schema(description = "ä¸åæ ¼æ°éï¼æ½æ£æ ·æ¬ä¸çä¸åæ ¼æ°ï¼") private BigDecimal unqualifiedQuantity; } src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
@@ -171,6 +171,17 @@ @Schema(description = "å ¥åºæ¯ä¾(ç¾åæ¯)ï¼é»è®¤100") private BigDecimal stockInRatio; @Schema(description = "æ£éªè§å: 0=å ¨æ£, 1=æ½æ£") @Excel(name = "æ£éªè§å", readConverterExp = "0=å ¨æ£,1=æ½æ£") private Integer inspectRule; @Schema(description = "æ½æ£æ¯ä¾(ç¾åæ¯), ä» inspectRule=1æ¶ææ") @Excel(name = "æ½æ£æ¯ä¾(%)") private BigDecimal sampleRatio; @Schema(description = "æ½æ£æ°é, ä» inspectRule=1æ¶ææ") private BigDecimal sampleQuantity; @TableField(fill = FieldFill.INSERT) private Long deptId; } src/main/java/com/ruoyi/quality/pojo/QualityTestStandard.java
@@ -69,6 +69,12 @@ @Schema(description = "å·¥åºid") private Integer processId; @Schema(description = "æ£éªè§å: 0=å ¨æ£, 1=æ½æ£") private Integer inspectRule; @Schema(description = "æ½æ£æ¯ä¾(ç¾åæ¯), ä» inspectRule=1æ¶ææ, å¦10表示10%") private java.math.BigDecimal sampleRatio; @TableField(fill = FieldFill.INSERT) private Long deptId; } src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -80,12 +80,39 @@ QualityInspect qualityInspect = new QualityInspect(); BeanUtils.copyProperties(qualityInspectDto, qualityInspect); qualityInspect.setInspectState(0);//é»è®¤æªæäº¤ // æ ¹æ® inspectRule è¡¥å ¨æ½æ£æ¯ä¾åæ½æ£æ°éé»è®¤å¼ applyInspectRuleDefaults(qualityInspect); qualityInspectMapper.insert(qualityInspect); for (QualityInspectParam qualityInspectParam : qualityInspectDto.getQualityInspectParams()) { qualityInspectParam.setInspectId(qualityInspect.getId()); } qualityInspectParamService.saveBatch(qualityInspectDto.getQualityInspectParams()); return 0; } /** * æ ¹æ® inspectRule è®¾ç½®æ½æ£æ¯ä¾åæ½æ£æ°éé»è®¤å¼ * - inspectRule=0 (å ¨æ£): sampleRatio=100, sampleQuantity=å ¨é¨æ°é * - inspectRule=1 (æ½æ£): sampleRatio åä¼ å ¥å¼æ0, sampleQuantity=æ°éÃæ¯ä¾/100 */ private void applyInspectRuleDefaults(QualityInspect inspect) { Integer rule = inspect.getInspectRule(); java.math.BigDecimal quantity = inspect.getQuantity(); if (rule == null || rule == 0) { // å ¨æ£ inspect.setSampleRatio(java.math.BigDecimal.valueOf(100)); inspect.setSampleQuantity(quantity != null ? quantity : java.math.BigDecimal.ZERO); } else { // æ½æ£ java.math.BigDecimal ratio = inspect.getSampleRatio() != null ? inspect.getSampleRatio() : java.math.BigDecimal.ZERO; inspect.setSampleRatio(ratio); if (quantity != null && ratio.compareTo(java.math.BigDecimal.ZERO) > 0) { inspect.setSampleQuantity(quantity.multiply(ratio) .divide(java.math.BigDecimal.valueOf(100), 0, java.math.RoundingMode.CEILING)); } else { inspect.setSampleQuantity(java.math.BigDecimal.ZERO); } } } @Override @@ -244,7 +271,9 @@ /** * å¨ç¬ç«äºå¡ä¸å¤çå个æ£éªå * æ°éãåæ ¼æ°éé»è®¤ä½¿ç¨æ£éªåèªèº«çæ°éï¼ä¸åæ ¼æ°é为0 * æ¯æå ¨æ£åæ½æ£æ¨¡å¼ï¼ * - å ¨æ£ï¼æ°éãåæ ¼æ°éé»è®¤ä½¿ç¨æ£éªåèªèº«çæ°éï¼ä¸åæ ¼æ°é为0 * - æ½æ£ï¼ä½¿ç¨åç«¯ä¼ å ¥ç sampleQuantity/qualifiedQuantity/unqualifiedQuantity */ @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) public void processSingleInspect(Long id, BatchQuickInspectRequest request, @@ -257,17 +286,66 @@ throw new RuntimeException("æ£éªåå·²æäº¤"); } // æ°éé»è®¤åæ£éªåèªèº«çæ°éï¼ä¸åæ ¼æ°é为0 BigDecimal qty = qualityInspect.getQuantity() != null ? qualityInspect.getQuantity() : BigDecimal.ZERO; BigDecimal qualified = qty; BigDecimal unqualified = BigDecimal.ZERO; // 夿æ£éªè§åï¼å ¨æ£(0/null) æ æ½æ£(1) Integer inspectRule = qualityInspect.getInspectRule(); boolean isFullInspect = inspectRule == null || inspectRule == 0; BigDecimal totalQty = qualityInspect.getQuantity() != null ? qualityInspect.getQuantity() : BigDecimal.ZERO; BigDecimal sampleQty; BigDecimal qualified; BigDecimal unqualified; if (isFullInspect) { // å ¨æ£æ¨¡å¼ï¼æ£éªæ°é = æ»æ°é sampleQty = totalQty; // 妿åç«¯ä¼ å ¥äºåæ ¼/ä¸åæ ¼æ°éå使ç¨ï¼å¦åé»è®¤å ¨é¨åæ ¼ if (request.getQualifiedQuantity() != null && request.getUnqualifiedQuantity() != null) { qualified = request.getQualifiedQuantity(); unqualified = request.getUnqualifiedQuantity(); } else { qualified = totalQty; unqualified = BigDecimal.ZERO; } } else { // æ½æ£æ¨¡å¼ // æ½æ£æ°éï¼ä¼å 使ç¨åç«¯ä¼ å ¥å¼ï¼å ¶æ¬¡ä½¿ç¨æ£éªåå·²æç sampleQuantityï¼æåææ¯ä¾è®¡ç® if (request.getSampleQuantity() != null && request.getSampleQuantity().compareTo(BigDecimal.ZERO) > 0) { sampleQty = request.getSampleQuantity(); } else if (qualityInspect.getSampleQuantity() != null && qualityInspect.getSampleQuantity().compareTo(BigDecimal.ZERO) > 0) { sampleQty = qualityInspect.getSampleQuantity(); } else { // ææ½æ£æ¯ä¾è®¡ç® BigDecimal ratio = qualityInspect.getSampleRatio() != null ? qualityInspect.getSampleRatio() : BigDecimal.ZERO; sampleQty = totalQty.multiply(ratio) .divide(BigDecimal.valueOf(100), 0, BigDecimal.ROUND_CEILING); } // æ ¡éªæ½æ£æ°éä¸è½è¶ è¿æ»æ°é if (sampleQty.compareTo(totalQty) > 0) { sampleQty = totalQty; } // åæ ¼/ä¸åæ ¼æ°éï¼ä¼å 使ç¨åç«¯ä¼ å ¥å¼ if (request.getQualifiedQuantity() != null || request.getUnqualifiedQuantity() != null) { qualified = request.getQualifiedQuantity() != null ? request.getQualifiedQuantity() : BigDecimal.ZERO; unqualified = request.getUnqualifiedQuantity() != null ? request.getUnqualifiedQuantity() : BigDecimal.ZERO; } else { // é»è®¤æ½æ£æ ·æ¬å ¨é¨åæ ¼ qualified = sampleQty; unqualified = BigDecimal.ZERO; } } // 2. æ´æ°æ£éªååæ®µ qualityInspect.setCheckResult(checkResult); qualityInspect.setTestStandardId(request.getTestStandardId()); qualityInspect.setQuantity(qty); // è®°å½å®é æ£éªæ°éï¼æ½æ£æ¶ä¸ºæ ·æ¬æ°éï¼å ¨æ£æ¶ä¸ºæ»æ°éï¼ qualityInspect.setQuantity(sampleQty); qualityInspect.setQualifiedQuantity(qualified); qualityInspect.setUnqualifiedQuantity(unqualified); // æ´æ°æ½æ£æ°éåæ®µ if (!isFullInspect) { qualityInspect.setSampleQuantity(sampleQty); } if (request.getCheckCompany() != null) { qualityInspect.setCheckCompany(request.getCheckCompany()); } src/main/java/com/ruoyi/quality/utils/QualityInspectHelper.java
@@ -15,6 +15,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.util.List; /** @@ -56,6 +57,8 @@ QualityTestStandard firstStandard = qualityTestStandardList.get(0); qualityInspect.setTestStandardId(firstStandard.getId()); // æ ¹æ® inspectRule 设置é»è®¤æ½æ£æ¯ä¾åæ½æ£æ°é applyInspectRuleDefaults(qualityInspect, firstStandard, saleProduct.getQuantity()); qualityInspectMapper.updateById(qualityInspect); List<QualityTestStandardParam> standardParams = qualityTestStandardParamMapper.selectList( @@ -70,4 +73,35 @@ qualityInspectParamMapper.insert(param); } } /** * æ ¹æ® inspectRule è®¾ç½®æ½æ£æ¯ä¾åæ½æ£æ°éé»è®¤å¼ * - inspectRule=0 (å ¨æ£): sampleRatio=100, sampleQuantity=å ¨é¨æ°é * - inspectRule=1 (æ½æ£): sampleRatio åæ åé ç½®å¼, sampleQuantity=æ°éÃæ¯ä¾/100 */ private void applyInspectRuleDefaults(QualityInspect inspect, QualityTestStandard standard, BigDecimal quantity) { Integer rule = standard.getInspectRule(); inspect.setInspectRule(rule); if (rule == null || rule == 0) { // å ¨æ£ inspect.setSampleRatio(BigDecimal.valueOf(100)); inspect.setSampleQuantity(quantity != null ? quantity : BigDecimal.ZERO); } else { // æ½æ£ BigDecimal ratio = standard.getSampleRatio(); if (ratio == null) { ratio = BigDecimal.ZERO; } inspect.setSampleRatio(ratio); if (quantity != null && ratio.compareTo(BigDecimal.ZERO) > 0) { BigDecimal sampleQty = quantity.multiply(ratio) .divide(BigDecimal.valueOf(100), 4, BigDecimal.ROUND_HALF_UP) .setScale(0, BigDecimal.ROUND_HALF_UP); inspect.setSampleQuantity(sampleQty); } else { inspect.setSampleQuantity(BigDecimal.ZERO); } } } } src/main/resources/mapper/sales/SalesQuotationMapper.xml
@@ -11,7 +11,7 @@ AND t1.quotation_no LIKE CONCAT('%',#{salesQuotationDto.quotationNo},'%') </if> <if test="salesQuotationDto.customer != null and salesQuotationDto.customer != '' "> AND t1.customer = #{salesQuotationDto.customer} AND t1.customer like concat("%",#{salesQuotationDto.customer},"%") </if> <if test="salesQuotationDto.status != null and salesQuotationDto.status != '' "> AND t1.status = #{salesQuotationDto.status}