1.计量器具台账上传附件报错
2.质量拉的数据不对(未明确)
3.计量器具台账逾期的做标红提醒
4.设备保养定时任务和记录要加上具体的保养内容
5.质量要区分质检规则抽检还是全检,抽检的话是抽多少百分比
6.供应商管理东西太少了,没有资质文件啊这些东西(是不是可以参考pro)
7.采购审批把人从李莹莹改成龙红星
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # é¦é¡µè´¨éç±»æ¥è¯¢ä¿®å¤ä¸ä¼åå端èè°ææ¡£ |
| | | |
| | | > ä¿®å¤ `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 | è´¨éç»è®¡ (å¨/æ/å£) | |
| | | |
| | | ## ä¸ã`/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 çæ£éªè®°å½æ¯å¦è¢«æ£ç¡®ç»è®¡ (å¨/æè§å¾æåä¸å¤©)ã |
| | | - 仿¥æææ¥æ£ç"å¾
宿 / 已宿"æ°æ®æ¯å¦è½å®æ¶åæ å°é¦é¡µå¡çã |
| | | - è¥ææ¥å£éè¦ä¿çæ§çå
¨åå²å£å¾ (ä¾å¦å¯¼åºã对账)ï¼è¯·åç¬æéæ±å¢å æ°æ¥å£ï¼é¿å
æ¹åé¦é¡µæ¥å£ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # è´¨æ£å¿«éæ£éªæ½æ£åè½å端èè°ææ¡£ |
| | | |
| | | > æ©å±æ¹éå¿«éæ£éªæ¥å£ï¼æ¯æå
¨æ£åæ½æ£ä¸¤ç§æ£éªæ¨¡å¼ï¼èªå¨å¡«å
æ½æ£æ°éã |
| | | |
| | | ## æ¶åé¡µé¢ |
| | | |
| | | - è´¨é管ç / æ£éªåå表 - æ¹éå¿«éæ£éªå¼¹çª |
| | | - è´¨é管ç / åæææ£éª / è¿ç¨æ£éª / åºåæ£éª - å¿«éæ£éªæä½ |
| | | |
| | | ## 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` æææ¯ä¾è®¡ç®çé»è®¤å¼ï¼åå°ç¨æ·è¾å
¥è´æ
ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # è´¨éæ£éªè§åï¼å
¨æ£/æ½æ£ï¼ |
| | | |
| | | ## æ¶åé¡µé¢ |
| | | |
| | | - æ£æµæ å管ç页é¢ï¼æ°å¢/ç¼è¾å¼¹çªãåè¡¨ï¼ |
| | | - åæææ£éªé¡µé¢ï¼åè¡¨ãæ°å¢/ç¼è¾å¼¹çªï¼ |
| | | - è¿ç¨æ£éªé¡µé¢ï¼åè¡¨ãæ°å¢/ç¼è¾å¼¹çªï¼ |
| | | - åºåæ£éªé¡µé¢ï¼åè¡¨ãæ°å¢/ç¼è¾å¼¹çªï¼ |
| | | |
| | | ## 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`ï¼åä¸åæ´ï¼ï¼æ éæå¨å¡«å |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // æ¥è¯¢è®¡éå¨å
·éä»¶å表 |
| | | export function listMeasuringInstrumentFiles(query) { |
| | | return request({ |
| | | url: "/measuringInstrumentFile/listPage", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // æ°å¢è®¡éå¨å
·éä»¶ |
| | | export function addMeasuringInstrumentFile(data) { |
| | | return request({ |
| | | url: "/measuringInstrumentFile/add", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // å é¤è®¡éå¨å
·éä»¶ |
| | | export function delMeasuringInstrumentFile(id) { |
| | | return request({ |
| | | url: "/measuringInstrumentFile/del", |
| | | method: "delete", |
| | | data: Array.isArray(id) ? id : [id], |
| | | }); |
| | | } |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div> |
| | | <div class="search_form"> |
| | | <div> |
| | | <div style="margin-bottom: 10px;"> |
| | | <span class="search_title">ä¾åºåæ¡£æ¡ï¼</span> |
| | | <el-input |
| | | v-model="searchForm.supplierName" |
| | | style="width: 240px" |
| | | placeholder="è¾å
¥åç§°æç´¢" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | v-model="searchForm.supplierName" |
| | | style="width: 240px" |
| | | placeholder="è¾å
¥ä¾åºååç§°æç´¢" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | /> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px">æç´¢</el-button> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px" |
| | | >æç´¢</el-button |
| | | > |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" @click="openForm('add')">æ°å¢ä¾åºå</el-button> |
| | | <div style="margin-bottom: 10px;"> |
| | | <el-button type="primary" @click="openForm('add')" |
| | | >æ°å¢ä¾åºå</el-button |
| | | > |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="info" plain icon="Upload" @click="handleImport" |
| | | >导å
¥</el-button |
| | | > |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="table_list" style="margin-top: 20px"> |
| | | <div class="table_list"> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | /> |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | ></PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog |
| | | v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢ä¾åºåä¿¡æ¯' : 'ç¼è¾ä¾åºåä¿¡æ¯'" |
| | | width="600px" |
| | | @close="closeDia" |
| | | v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢ä¾åºåä¿¡æ¯' : 'ç¼è¾ä¾åºåä¿¡æ¯'" |
| | | width="70%" |
| | | @close="closeDia" |
| | | > |
| | | <el-form |
| | | :model="form" |
| | | label-width="120px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef" |
| | | :model="form" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef" |
| | | > |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åç§°ï¼" prop="supplierName"> |
| | | <el-input v-model="form.supplierName" placeholder="请è¾å
¥" clearable /> |
| | | <el-form-item label="ä¾åºååç§°ï¼" prop="supplierName"> |
| | | <el-input |
| | | v-model="form.supplierName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="纳ç¨äººè¯å«å·ï¼" prop="taxpayerIdentificationNum"> |
| | | <el-form-item |
| | | label="纳ç¨äººè¯å«å·ï¼" |
| | | prop="taxpayerIdentificationNum" |
| | | > |
| | | <el-input |
| | | v-model="form.taxpayerIdentificationNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | v-model="form.taxpayerIdentificationNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¬å¸å°åï¼" prop="companyAddress"> |
| | | <el-input |
| | | v-model="form.companyAddress" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¬å¸çµè¯ï¼" prop="companyPhone"> |
| | | <el-input |
| | | v-model="form.companyPhone" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="弿·è¡ï¼" prop="bankAccountName"> |
| | | <el-input |
| | | v-model="form.bankAccountName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è´¦å·ï¼" prop="bankAccountNum"> |
| | | <el-input |
| | | v-model="form.bankAccountNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è系人ï¼" prop="contactUserName"> |
| | | <el-input |
| | | v-model="form.contactUserName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="èç³»çµè¯ï¼" prop="contactUserPhone"> |
| | | <el-input |
| | | v-model="form.contactUserPhone" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»´æ¤äººï¼" prop="maintainUserId"> |
| | | <el-select v-model="form.maintainUserId" placeholder="è¯·éæ©" clearable> |
| | | <el-select |
| | | v-model="form.maintainUserId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | disabled |
| | | > |
| | | <el-option |
| | | v-for="item in userList" |
| | | :key="item.userId" |
| | | :label="item.nickName" |
| | | :value="item.userId" |
| | | v-for="item in userList" |
| | | :key="item.nickName" |
| | | :label="item.nickName" |
| | | :value="item.userId" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»´æ¤æ¶é´ï¼" prop="maintainTime"> |
| | | <el-date-picker |
| | | style="width: 100%" |
| | | v-model="form.maintainTime" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 100%" |
| | | v-model="form.maintainTime" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¾åºåç±»åï¼" prop="supplierType"> |
| | | <el-select v-model="form.supplierType" placeholder="è¯·éæ©" clearable> |
| | | <el-option label="ç²" value="ç²" /> |
| | | <el-option label="ä¹" value="ä¹" /> |
| | | <el-option label="ä¸" value="ä¸" /> |
| | | <el-option label="ä¸" value="ä¸" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¯å¦ç½ååï¼" prop="isWhite"> |
| | | <el-select v-model="form.isWhite" placeholder="è¯·éæ©" clearable> |
| | | <el-option label="æ¯" :value="0" /> |
| | | <el-option label="å¦" :value="1" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- ä¾åºå导å
¥å¯¹è¯æ¡ --> |
| | | <el-dialog |
| | | :title="upload.title" |
| | | v-model="upload.open" |
| | | width="400px" |
| | | append-to-body |
| | | > |
| | | <el-upload |
| | | ref="uploadRef" |
| | | :limit="1" |
| | | accept=".xlsx, .xls" |
| | | :headers="upload.headers" |
| | | :action="upload.url + '?updateSupport=' + upload.updateSupport" |
| | | :disabled="upload.isUploading" |
| | | :on-progress="handleFileUploadProgress" |
| | | :on-success="handleFileSuccess" |
| | | :on-error="handleFileError" |
| | | :auto-upload="false" |
| | | drag |
| | | > |
| | | <el-icon class="el-icon--upload"><upload-filled /></el-icon> |
| | | <div class="el-upload__text">å°æä»¶æå°æ¤å¤ï¼æ<em>ç¹å»ä¸ä¼ </em></div> |
| | | <template #tip> |
| | | <div class="el-upload__tip text-center"> |
| | | <span>ä»
å
许导å
¥xlsãxlsxæ ¼å¼æä»¶ã</span> |
| | | <el-link |
| | | type="primary" |
| | | :underline="false" |
| | | style="font-size: 12px; vertical-align: baseline" |
| | | @click="importTemplate" |
| | | >ä¸è½½æ¨¡æ¿</el-link |
| | | > |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button @click="upload.open = false">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <FileList v-if="fileListDialogVisible" |
| | | v-model:visible="fileListDialogVisible" |
| | | record-type="supplier_manage" |
| | | :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { getCurrentInstance, onMounted, reactive, ref, toRefs } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { addSupplier, delSupplier, getSupplier, listSupplier, updateSupplier } from "@/api/basicData/supplierManageFile.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | import { onMounted, ref } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { delSupplier } from "@/api/basicData/supplierManageFile.js"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { |
| | | addSupplier, |
| | | getSupplier, |
| | | listSupplier, |
| | | updateSupplier, |
| | | } from "@/api/basicData/supplierManageFile.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | const FileList = defineAsyncComponent(() => |
| | | import("@/components/Dialog/FileList.vue") |
| | | ); |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore(); |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore(); |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "ä¾åºååç§°", |
| | | prop: "supplierName", |
| | | width: 250, |
| | | }, |
| | | { |
| | | label: "ä¾åºåç±»å", |
| | | prop: "supplierType", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "纳ç¨äººè¯å«å·", |
| | | prop: "taxpayerIdentificationNum", |
| | | width: 230, |
| | | }, |
| | | { |
| | | label: "å
¬å¸å°å", |
| | | prop: "companyAddress", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "èç³»æ¹å¼", |
| | | prop: "companyPhone", |
| | | width:150 |
| | | }, |
| | | { |
| | | label: "弿·è¡", |
| | | prop: "bankAccountName", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "è´¦å·", |
| | | prop: "bankAccountNum", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "è系人", |
| | | prop: "contactUserName", |
| | | }, |
| | | { |
| | | label: "èç³»çµè¯", |
| | | prop: "contactUserPhone", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "ç»´æ¤äºº", |
| | | prop: "maintainUserName", |
| | | }, |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "åç§°", |
| | | prop: "supplierName", |
| | | }, |
| | | { |
| | | label: "纳ç¨äººè¯å«å·", |
| | | prop: "taxpayerIdentificationNum", |
| | | }, |
| | | { |
| | | label: "ç»´æ¤äºº", |
| | | prop: "maintainUserName", |
| | | }, |
| | | { |
| | | label: "ç»´æ¤æ¶é´", |
| | | prop: "maintainTime", |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 150, |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openForm("edit", row); |
| | | }, |
| | | { |
| | | label: "ç»´æ¤æ¶é´", |
| | | prop: "maintainTime", |
| | | width:100 |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: 'right', |
| | | width: 150, |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | openForm("edit", row); |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const userList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const operationType = ref(""); |
| | | const dialogFormVisible = ref(false); |
| | | const formRef = ref(); |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: "", |
| | | }, |
| | | form: { |
| | | supplierName: "", |
| | | taxpayerIdentificationNum: "", |
| | | maintainUserId: "", |
| | | maintainTime: "", |
| | | }, |
| | | rules: { |
| | | supplierName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | taxpayerIdentificationNum: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | maintainUserId: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | maintainTime: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const { searchForm, form, rules } = toRefs(data); |
| | | |
| | | const upload = reactive({ |
| | | open: false, |
| | | title: "", |
| | | isUploading: false, |
| | | updateSupport: 1, |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import", |
| | | }); |
| | | |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const pagination = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | listSupplier({ ...searchForm.value, ...page, isWhite: 0 }).then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }); |
| | | }; |
| | | |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | |
| | | const openForm = (type, row) => { |
| | | operationType.value = type; |
| | | form.value = { |
| | | supplierName: "", |
| | | taxpayerIdentificationNum: "", |
| | | maintainUserId: userStore.id, |
| | | maintainTime: getCurrentDate(), |
| | | }; |
| | | userListNoPage().then(res => { |
| | | userList.value = res.data; |
| | | }); |
| | | if (type === "edit") { |
| | | getSupplier(row.id).then(res => { |
| | | form.value = { |
| | | id: res.data.id || "", |
| | | supplierName: res.data.supplierName || "", |
| | | taxpayerIdentificationNum: res.data.taxpayerIdentificationNum || "", |
| | | maintainUserId: res.data.maintainUserId || userStore.id, |
| | | maintainTime: res.data.maintainTime || getCurrentDate(), |
| | | }; |
| | | }); |
| | | } |
| | | dialogFormVisible.value = true; |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (!valid) { |
| | | return; |
| | | }, |
| | | { |
| | | //èµè´¨éä»¶ |
| | | name: "èµè´¨æä»¶", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | openFileDialog(row) |
| | | } |
| | | } |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const userList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const fileListDialogVisible = ref(false); |
| | | const recordId = ref(); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | // ç¨æ·ä¿¡æ¯è¡¨åå¼¹æ¡æ°æ® |
| | | const operationType = ref(""); |
| | | const dialogFormVisible = ref(false); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: "", |
| | | }, |
| | | form: { |
| | | supplierName: "", |
| | | taxpayerIdentificationNum: "", |
| | | companyAddress: "", |
| | | companyPhone: "", |
| | | bankAccountName: "", |
| | | bankAccountNum: "", |
| | | contactUserName: "", |
| | | contactUserPhone: "", |
| | | maintainUserId: "", |
| | | maintainTime: "", |
| | | supplierType: "", |
| | | isWhite: "", |
| | | }, |
| | | rules: { |
| | | supplierName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | taxpayerIdentificationNum: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | companyAddress: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | companyPhone: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | bankAccountName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | bankAccountNum: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | contactUserName: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | contactUserPhone: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | maintainUserId: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | maintainTime: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | supplierType: [{ required: true, message: "è¯·éæ©ä¾åºåç±»å", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const { searchForm, form, rules } = toRefs(data); |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const pagination = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | /** æäº¤ä¸ä¼ æä»¶ */ |
| | | function submitFileForm() { |
| | | upload.isUploading = true; |
| | | proxy.$refs["uploadRef"].submit(); |
| | | } |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | listSupplier({ ...searchForm.value, ...page, isWhite: 0 }).then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }); |
| | | }; |
| | | const upload = reactive({ |
| | | // æ¯å¦æ¾ç¤ºå¼¹åºå±ï¼ä¾åºå导å
¥ï¼ |
| | | open: false, |
| | | // å¼¹åºå±æ é¢ï¼ä¾åºå导å
¥ï¼ |
| | | title: "", |
| | | // æ¯å¦ç¦ç¨ä¸ä¼ |
| | | isUploading: false, |
| | | // æ¯å¦æ´æ°å·²ç»åå¨çç¨æ·æ°æ® |
| | | updateSupport: 1, |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import", |
| | | }); |
| | | /** 导å
¥æé®æä½ */ |
| | | function handleImport() { |
| | | upload.title = "ä¾åºå导å
¥"; |
| | | upload.open = true; |
| | | } |
| | | /** ä¸è½½æ¨¡æ¿ */ |
| | | function importTemplate() { |
| | | proxy.download("/system/supplier/downloadTemplate", {}, "ä¾åºå导å
¥æ¨¡æ¿.xlsx"); |
| | | } |
| | | |
| | | /**æä»¶ä¸ä¼ ä¸å¤ç */ |
| | | const handleFileUploadProgress = (event, file, fileList) => { |
| | | upload.isUploading = true; |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ æåå¤ç */ |
| | | const handleFileSuccess = (response, file, fileList) => { |
| | | upload.isUploading = false; |
| | | if(response.code === 200){ |
| | | proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå"); |
| | | upload.open = false; |
| | | proxy.$refs["uploadRef"].clearFiles(); |
| | | getList(); |
| | | }else if(response.code === 500){ |
| | | proxy.$modal.msgError(response.msg); |
| | | }else{ |
| | | proxy.$modal.msgWarning(response.msg); |
| | | } |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ 失败å¤ç */ |
| | | const handleFileError = (error, file, fileList) => { |
| | | upload.isUploading = false; |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = (selection) => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | operationType.value = type; |
| | | form.value = {}; |
| | | form.value.maintainUserId = userStore.id; |
| | | form.value.maintainTime = getCurrentDate(); |
| | | userListNoPage().then((res) => { |
| | | userList.value = res.data; |
| | | }); |
| | | if (type === "edit") { |
| | | getSupplier(row.id).then((res) => { |
| | | form.value = { ...res.data }; |
| | | }); |
| | | } |
| | | dialogFormVisible.value = true; |
| | | }; |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate((valid) => { |
| | | if (valid) { |
| | | if (operationType.value === "edit") { |
| | | updateSupplier(form.value).then(() => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | submitEdit(); |
| | | } else { |
| | | addSupplier(form.value).then(() => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | submitAdd(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | } |
| | | }); |
| | | }; |
| | | // æäº¤æ°å¢ |
| | | const submitAdd = () => { |
| | | addSupplier(form.value).then((res) => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // æäº¤ä¿®æ¹ |
| | | const submitEdit = () => { |
| | | updateSupplier(form.value).then((res) => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/system/supplier/export", { isWhite: 0 }, "ä¾åºåæ¡£æ¡.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | const handleDelete = () => { |
| | | if (selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | }; |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | // æ£æ¥æ¯å¦æä»äººç»´æ¤çæ°æ® |
| | | const unauthorizedData = selectedRows.value.filter(item => item.maintainUserName !== userStore.nickName); |
| | | if (unauthorizedData.length > 0) { |
| | | proxy.$modal.msgWarning("ä¸å¯å é¤ä»äººç»´æ¤çæ°æ®"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | ids = selectedRows.value.map((item) => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | tableLoading.value = true; |
| | | delSupplier(ids) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | .then((res) => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | }; |
| | | |
| | | const getCurrentDate = () => { |
| | | const today = new Date(); |
| | | const year = today.getFullYear(); |
| | | const month = String(today.getMonth() + 1).padStart(2, "0"); |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | }; |
| | | // è·åå½åæ¥æå¹¶æ ¼å¼å为 YYYY-MM-DD |
| | | function getCurrentDate() { |
| | | const today = new Date(); |
| | | const year = today.getFullYear(); |
| | | const month = String(today.getMonth() + 1).padStart(2, "0"); // æä»½ä»0å¼å§ |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async row => { |
| | | recordId.value = row.id; |
| | | fileListDialogVisible.value = true; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | |
| | | defineExpose({ |
| | | getList, |
| | | }); |
| | | defineExpose({ |
| | | getList, |
| | | }); |
| | | </script> |
| | | |
| | |
| | | <!-- å¨ä½ ç主页é¢ä¸ --> |
| | | <template> |
| | | <div> |
| | | <HomeTab /> |
| | | <div class="app-container"> |
| | | <el-tabs v-model="activeTab" @tab-change="handleTabChange"> |
| | | <el-tab-pane label="æ£å¸¸ä¾åºå" name="home"> |
| | | <HomeTab ref="homeTab" /> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="é»åå" name="blacklist"> |
| | | <BlacklistTab ref="blacklistTab" /> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import HomeTab from "./components/HomeTab.vue"; |
| | | </script> |
| | | <script> |
| | | import HomeTab from './components/HomeTab.vue' |
| | | import BlacklistTab from './components/BlacklistTab.vue' |
| | | |
| | | export default { |
| | | name: 'MainPage', |
| | | components: { |
| | | HomeTab, |
| | | BlacklistTab |
| | | }, |
| | | data() { |
| | | return { |
| | | activeTab: 'home' |
| | | } |
| | | }, |
| | | methods: { |
| | | handleTabChange(tabName) { |
| | | this.activeTab = tabName |
| | | this.$nextTick(() => { |
| | | if (tabName === 'home') { |
| | | this.$refs.homeTab && this.$refs.homeTab.getList && this.$refs.homeTab.getList() |
| | | } else if (tabName === 'blacklist') { |
| | | this.$refs.blacklistTab && this.$refs.blacklistTab.getList && this.$refs.blacklistTab.getList() |
| | | } |
| | | }) |
| | | }, |
| | | } |
| | | } |
| | | </script> |
| | |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | :dbRowClick="dbRowClick" |
| | | :rowClassName="overdueRowClass" |
| | | ></PIMTable> |
| | | </div> |
| | | <form-dia ref="formDia" @close="handleQuery"></form-dia> |
| | | <calibration-dia ref="calibrationDia" @close="handleQuery"></calibration-dia> |
| | | <files-dia ref="filesDia"></files-dia> |
| | | <FileList |
| | | v-if="fileDialogVisible" |
| | | v-model:visible="fileDialogVisible" |
| | | record-type="measuring_instrument_ledger" |
| | | :record-id="currentRecordId" |
| | | :editable="true" |
| | | /> |
| | | <rowClickDataForm ref="rowClickData"></rowClickDataForm> |
| | | </div> |
| | | </template> |
| | |
| | | measuringInstrumentDelete, |
| | | measuringInstrumentListPage, |
| | | } from "@/api/equipmentManagement/measurementEquipment.js"; |
| | | import FilesDia from "./filesDia.vue"; |
| | | |
| | | import FileList from "@/components/Dialog/FileList.vue"; |
| | | import rowClickDataForm from "./components/rowClickData.vue" |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore() |
| | |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const rowClickData = ref([]) |
| | | const filesDia = ref() |
| | | const fileDialogVisible = ref(false) |
| | | const currentRecordId = ref(0) |
| | | |
| | | const overdueRowClass = ({ row }) => { |
| | | return row.status === 2 ? "overdue-row" : ""; |
| | | }; |
| | | |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | |
| | | |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFilesFormDia = (row) => { |
| | | filesDia.value?.openDialog(row,'计éå¨å
·å°è´¦') |
| | | }; |
| | | currentRecordId.value = row.id |
| | | fileDialogVisible.value = true |
| | | } |
| | | |
| | | const dbRowClick = (row)=>{ |
| | | rowClickData.value?.openDialog(row) |
| | |
| | | |
| | | <style scoped> |
| | | |
| | | </style> |
| | | |
| | | <style lang="scss"> |
| | | .el-table .overdue-row { |
| | | --el-table-tr-bg-color: var(--el-color-danger-light-9); |
| | | color: var(--el-color-danger); |
| | | } |
| | | .el-table .overdue-row td.el-table__cell { |
| | | background: var(--el-color-danger-light-9) !important; |
| | | } |
| | | </style> |
| | |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <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-col> |
| | | <el-col :span="6" v-if="form.inspectRule === 1"> |
| | | <el-form-item label="æ½æ£æ¯ä¾(%)" prop="sampleRatio"> |
| | | <el-input-number v-model="form.sampleRatio" :min="0.01" :max="100" :precision="2" placeholder="请è¾å
¥æ½æ£æ¯ä¾" style="width: 100%" @change="calcSampleQuantity" :disabled="isViewMode" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6" v-if="form.inspectRule === 1"> |
| | | <el-form-item label="æ½æ£æ°é" prop="sampleQuantity"> |
| | | <el-input-number v-model="form.sampleQuantity" :min="0" :precision="2" style="width: 100%" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£æµåä½ï¼" prop="checkCompany"> |
| | | <el-input v-model="form.checkCompany" placeholder="请è¾å
¥" clearable :disabled="isViewMode"/> |
| | | </el-form-item> |
| | |
| | | checkResult: "", |
| | | salesLedgerId: "", |
| | | salesContractNo: "", |
| | | inspectRule: 0, |
| | | sampleRatio: undefined, |
| | | sampleQuantity: undefined, |
| | | }, |
| | | rules: { |
| | | checkTime: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | |
| | | prop: "unit", |
| | | }, |
| | | { |
| | | label: "æ åå¼", |
| | | label: "åå®¶æ åå¼", |
| | | prop: "standardValue", |
| | | }, |
| | | { |
| | |
| | | if (productData) { |
| | | // åªèªå¨å¸¦å
¥æ°é |
| | | form.value.quantity = productData.quantity || 0; |
| | | calcSampleQuantity(); |
| | | } |
| | | } catch (e) { |
| | | console.error('æ¥è¯¢éå®è®¢å产åä¿¡æ¯å¤±è´¥', e); |
| | |
| | | form.value.qualifiedQuantity = Math.max(0, quantity - unqualified); |
| | | }; |
| | | |
| | | const calcSampleQuantity = () => { |
| | | const q = parseFloat(form.value.quantity) || 0; |
| | | const r = parseFloat(form.value.sampleRatio) || 0; |
| | | if (q > 0 && r > 0) { |
| | | form.value.sampleQuantity = Number((q * r / 100).toFixed(2)); |
| | | } else { |
| | | form.value.sampleQuantity = undefined; |
| | | } |
| | | }; |
| | | |
| | | const findNodeById = (nodes, productId) => { |
| | | for (let i = 0; i < nodes.length; i++) { |
| | | if (nodes[i].value === productId) { |
| | |
| | | prop: "unit", |
| | | }, |
| | | { |
| | | label: "æ åå¼", |
| | | label: "åå®¶æ åå¼", |
| | | prop: "standardValue", |
| | | }, |
| | | { |
| | |
| | | <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£éªæ¨¡å¼ï¼"> |
| | | <el-tag :type="inspectModeTag" size="large">{{ inspectModeLabel }}</el-tag> |
| | | <span v-if="showSampleFields && currentInspect" class="mode-tip"> |
| | | (æ½æ£æ¯ä¾: {{ currentInspect.sampleRatio || 0 }}%) |
| | | </span> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£æµç»æï¼" prop="checkResult"> |
| | | <el-select v-model="form.checkResult" placeholder="è¯·éæ©æ£æµç»æ" style="width: 100%" @change="handleCheckResultChange"> |
| | | <el-option label="åæ ¼" value="åæ ¼" /> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ææ éæ©ï¼" prop="testStandardId"> |
| | | <el-select v-model="form.testStandardId" placeholder="è¯·éæ©ææ " style="width: 100%" @change="handleTestStandardChange"> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="showSampleFields"> |
| | | <el-form-item label="æ½æ£æ°éï¼" prop="sampleQuantity"> |
| | | <el-input-number |
| | | :step="1" |
| | | :min="1" |
| | | :max="maxSampleQuantity" |
| | | style="width: 100%" |
| | | v-model="form.sampleQuantity" |
| | | placeholder="请è¾å
¥æ½æ£æ°é" |
| | | :precision="0" |
| | | /> |
| | | <span class="tip-text">æå¤§å¯æ½æ£: {{ maxSampleQuantity }}</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <template v-if="form.checkResult"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ°éï¼" prop="quantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请è¾å
¥æ°é" clearable :precision="2" @change="handleQuantityChange"/> |
| | | <el-form-item label="æ£éªæ°éï¼" prop="quantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请è¾å
¥æ°é" clearable :precision="2" @change="handleQuantityChange" :disabled="showSampleFields"/> |
| | | <span v-if="showSampleFields" class="tip-text">æ½æ£æ¨¡å¼ä¸æ£éªæ°éçäºæ½æ£æ°é</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åæ ¼æ°éï¼" prop="qualifiedQuantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.qualifiedQuantity" placeholder="请è¾å
¥åæ ¼æ°é" clearable :precision="2" @change="handleQualifiedQuantityChange"/> |
| | | <el-input-number :step="0.01" :min="0" :max="form.quantity" style="width: 100%" v-model="form.qualifiedQuantity" placeholder="请è¾å
¥åæ ¼æ°é" clearable :precision="2" @change="handleQualifiedQuantityChange"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¸åæ ¼æ°éï¼" prop="unqualifiedQuantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.unqualifiedQuantity" placeholder="请è¾å
¥ä¸åæ ¼æ°é" clearable :precision="2" @change="handleUnqualifiedQuantityChange"/> |
| | | <el-input-number :step="0.01" :min="0" :max="form.quantity" style="width: 100%" v-model="form.unqualifiedQuantity" placeholder="请è¾å
¥ä¸åæ ¼æ°é" clearable :precision="2" @change="handleUnqualifiedQuantityChange"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, toRefs, getCurrentInstance, nextTick } from "vue"; |
| | | import { ref, reactive, toRefs, getCurrentInstance, nextTick, computed, watch } from "vue"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { batchQuickInspect } from "@/api/qualityManagement/rawMaterialInspection.js"; |
| | | import { qualityInspectDetailByProductId, getQualityTestStandardParamByTestStandardId } from "@/api/qualityManagement/metricMaintenance.js"; |
| | |
| | | const selectedRows = ref([]); |
| | | const testStandardOptions = ref([]); |
| | | const inspectType = ref(2); // åºåæ£éªç±»å |
| | | const currentInspect = ref(null); |
| | | |
| | | const data = reactive({ |
| | | form: { |
| | | checkResult: '', |
| | | testStandardId: '', |
| | | quantity: undefined, |
| | | sampleQuantity: undefined, |
| | | qualifiedQuantity: undefined, |
| | | unqualifiedQuantity: undefined, |
| | | checkCompany: '', |
| | |
| | | }); |
| | | const { form, rules } = toRefs(data); |
| | | |
| | | // æ£éªæ¨¡å¼æ ç¾ |
| | | const inspectModeLabel = computed(() => { |
| | | if (!currentInspect.value) return 'å
¨æ£'; |
| | | return currentInspect.value.inspectRule === 1 ? 'æ½æ£' : 'å
¨æ£'; |
| | | }); |
| | | |
| | | const inspectModeTag = computed(() => { |
| | | if (!currentInspect.value) return 'success'; |
| | | return currentInspect.value.inspectRule === 1 ? 'warning' : 'success'; |
| | | }); |
| | | |
| | | // æ¯å¦æ¾ç¤ºæ½æ£å段 |
| | | const showSampleFields = computed(() => { |
| | | return currentInspect.value && currentInspect.value.inspectRule === 1; |
| | | }); |
| | | |
| | | // æ»æ°é |
| | | const totalQuantity = computed(() => { |
| | | return currentInspect.value?.quantity || 0; |
| | | }); |
| | | |
| | | // æå¤§æ½æ£æ°é |
| | | const maxSampleQuantity = computed(() => { |
| | | return totalQuantity.value; |
| | | }); |
| | | |
| | | // é»è®¤æ½æ£æ°éï¼ä»æ£éªåè·åæææ¯ä¾è®¡ç®ï¼ |
| | | const defaultSampleQuantity = computed(() => { |
| | | if (!currentInspect.value) return 0; |
| | | if (currentInspect.value.sampleQuantity) { |
| | | return currentInspect.value.sampleQuantity; |
| | | } |
| | | if (currentInspect.value.sampleRatio) { |
| | | return Math.ceil(totalQuantity.value * currentInspect.value.sampleRatio / 100); |
| | | } |
| | | return totalQuantity.value; |
| | | }); |
| | | |
| | | // ç嬿½æ£æ°éåå |
| | | watch(() => form.value.sampleQuantity, (val) => { |
| | | if (showSampleFields.value && val) { |
| | | form.value.quantity = val; |
| | | // æ´æ°åæ ¼/ä¸åæ ¼æ°é |
| | | if (form.value.checkResult === 'åæ ¼') { |
| | | form.value.qualifiedQuantity = val; |
| | | form.value.unqualifiedQuantity = 0; |
| | | } else if (form.value.checkResult === 'ä¸åæ ¼') { |
| | | form.value.qualifiedQuantity = 0; |
| | | form.value.unqualifiedQuantity = val; |
| | | } |
| | | } |
| | | }); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "ææ ", |
| | |
| | | prop: "unit", |
| | | }, |
| | | { |
| | | label: "æ åå¼", |
| | | label: "åå®¶æ åå¼", |
| | | prop: "standardValue", |
| | | }, |
| | | { |
| | |
| | | selectedIds.value = ids; |
| | | selectedRows.value = rows; |
| | | dialogVisible.value = true; |
| | | |
| | | |
| | | // åç¬¬ä¸æ¡æ£éªåçä¿¡æ¯ä½ä¸ºåè |
| | | if (rows && rows.length > 0) { |
| | | currentInspect.value = rows[0]; |
| | | } else { |
| | | currentInspect.value = null; |
| | | } |
| | | |
| | | // 计ç®éä¸è¡çæ»æ°é |
| | | const totalQuantity = rows.reduce((sum, row) => sum + (Number(row.quantity) || 0), 0); |
| | | |
| | | const totalQty = rows.reduce((sum, row) => sum + (Number(row.quantity) || 0), 0); |
| | | const sampleQty = showSampleFields.value ? defaultSampleQuantity.value : undefined; |
| | | |
| | | // å è½½ç¨æ·å表 |
| | | const userListsRes = await userListNoPage(); |
| | | userList.value = userListsRes.data; |
| | | |
| | | |
| | | // å è½½ææ éé¡¹ï¼æ ¹æ®ç¬¬ä¸ä¸ªéä¸è¡ç产åIDï¼ |
| | | if (rows && rows.length > 0 && rows[0].productId) { |
| | | const params = { |
| | |
| | | } else { |
| | | testStandardOptions.value = []; |
| | | } |
| | | |
| | | |
| | | // é置表å |
| | | form.value = { |
| | | checkResult: '', |
| | | testStandardId: '', |
| | | quantity: totalQuantity, |
| | | qualifiedQuantity: totalQuantity, |
| | | quantity: showSampleFields.value ? sampleQty : totalQty, |
| | | sampleQuantity: sampleQty, |
| | | qualifiedQuantity: totalQty, |
| | | unqualifiedQuantity: 0, |
| | | checkCompany: '', |
| | | checkName: '', |
| | | checkTime: '', |
| | | }; |
| | | tableData.value = []; |
| | | |
| | | |
| | | await nextTick(); |
| | | proxy.$refs.formRef?.clearValidate(); |
| | | }; |
| | |
| | | |
| | | // æ£æµç»æååå¤ç |
| | | const handleCheckResultChange = (value) => { |
| | | const qty = form.value.quantity || 0; |
| | | if (value === 'åæ ¼') { |
| | | // åæ ¼æ¶ï¼åæ ¼æ°éçäºæ°éï¼ä¸åæ ¼æ°é为0 |
| | | form.value.qualifiedQuantity = form.value.quantity || 0; |
| | | form.value.qualifiedQuantity = qty; |
| | | form.value.unqualifiedQuantity = 0; |
| | | } else if (value === 'ä¸åæ ¼') { |
| | | // ä¸åæ ¼æ¶ï¼åæ ¼æ°é为0ï¼ä¸åæ ¼æ°éçäºæ°é |
| | | form.value.qualifiedQuantity = 0; |
| | | form.value.unqualifiedQuantity = form.value.quantity || 0; |
| | | form.value.unqualifiedQuantity = qty; |
| | | } else if (value === 'é¨ååæ ¼') { |
| | | form.value.qualifiedQuantity = undefined; |
| | | form.value.unqualifiedQuantity = undefined; |
| | | } |
| | | }; |
| | | |
| | |
| | | const handleQualifiedQuantityChange = (value) => { |
| | | const quantity = form.value.quantity || 0; |
| | | if (value > quantity) { |
| | | proxy.$modal.msgWarning("åæ ¼æ°éä¸è½å¤§äºæ»æ°é"); |
| | | proxy.$modal.msgWarning("åæ ¼æ°éä¸è½å¤§äºæ£éªæ°é"); |
| | | form.value.qualifiedQuantity = quantity; |
| | | form.value.unqualifiedQuantity = 0; |
| | | } else { |
| | |
| | | const handleUnqualifiedQuantityChange = (value) => { |
| | | const quantity = form.value.quantity || 0; |
| | | if (value > quantity) { |
| | | proxy.$modal.msgWarning("ä¸åæ ¼æ°éä¸è½å¤§äºæ»æ°é"); |
| | | proxy.$modal.msgWarning("ä¸åæ ¼æ°éä¸è½å¤§äºæ£éªæ°é"); |
| | | form.value.unqualifiedQuantity = quantity; |
| | | form.value.qualifiedQuantity = 0; |
| | | } else { |
| | |
| | | const qualified = form.value.qualifiedQuantity || 0; |
| | | const unqualified = form.value.unqualifiedQuantity || 0; |
| | | const quantity = form.value.quantity || 0; |
| | | |
| | | |
| | | if (qualified === quantity && unqualified === 0) { |
| | | form.value.checkResult = 'åæ ¼'; |
| | | } else if (unqualified === quantity && qualified === 0) { |
| | |
| | | const submitForm = () => { |
| | | proxy.$refs.formRef.validate((valid) => { |
| | | if (valid) { |
| | | // é¨ååæ ¼æ¶æ ¡éªæ°é |
| | | if (form.value.checkResult === 'é¨ååæ ¼') { |
| | | const sum = (form.value.qualifiedQuantity || 0) + (form.value.unqualifiedQuantity || 0); |
| | | if (sum > (form.value.quantity || 0)) { |
| | | proxy.$modal.msgWarning('åæ ¼æ°é+ä¸åæ ¼æ°éä¸è½è¶
è¿æ£éªæ°é'); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | const data = { |
| | | ids: selectedIds.value, |
| | | inspectType: inspectType.value, |
| | |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .mode-tip { |
| | | margin-left: 10px; |
| | | font-size: 13px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .tip-text { |
| | | display: block; |
| | | font-size: 12px; |
| | | color: #909399; |
| | | margin-top: 4px; |
| | | } |
| | | </style> |
| | |
| | | }, |
| | | }, |
| | | { |
| | | label: "æ£éªè§å", |
| | | prop: "inspectRule", |
| | | width: 100, |
| | | formatData: (val) => val === 0 ? "å
¨æ£" : val === 1 ? "æ½æ£" : "" |
| | | }, |
| | | { |
| | | label: "æ½æ£æ¯ä¾(%)", |
| | | prop: "sampleRatio", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "æ½æ£æ°é", |
| | | prop: "sampleQuantity", |
| | | width: 100, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | |
| | | <el-form-item label="åä½" prop="unit"> |
| | | <el-input v-model="form.unit" placeholder="请è¾å
¥åä½" /> |
| | | </el-form-item> |
| | | <el-form-item label="æ åå¼" prop="standardValue"> |
| | | <el-input v-model="form.standardValue" placeholder="请è¾å
¥æ åå¼" /> |
| | | <el-form-item label="åå®¶æ åå¼" prop="standardValue"> |
| | | <el-input v-model="form.standardValue" placeholder="请è¾å
¥åå®¶æ åå¼" /> |
| | | </el-form-item> |
| | | <el-form-item label="å
æ§å¼" prop="controlValue"> |
| | | <el-input v-model="form.controlValue" placeholder="请è¾å
¥å
æ§å¼" /> |
| | |
| | | placeholder="请è¾å
¥å¤æ³¨" |
| | | /> |
| | | </el-form-item> |
| | | <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="请è¾å
¥æ½æ£æ¯ä¾" style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | </FormDialog> |
| | | </template> |
| | |
| | | <el-table-column type="index" label="åºå·" width="60" align="center" /> |
| | | <el-table-column prop="parameterItem" label="忰项" min-width="120" /> |
| | | <el-table-column prop="unit" label="åä½" width="80" /> |
| | | <el-table-column prop="standardValue" label="æ åå¼" min-width="120" /> |
| | | <el-table-column prop="standardValue" label="åå®¶æ åå¼" min-width="120" /> |
| | | <el-table-column prop="controlValue" label="å
æ§å¼" min-width="120" /> |
| | | <el-table-column prop="defaultValue" label="é»è®¤å¼" min-width="120" /> |
| | | <el-table-column label="æä½" width="140" fixed="right" align="center"> |
| | |
| | | remark: '', |
| | | state: '0', |
| | | inspectType: '', |
| | | processId: '' |
| | | processId: '', |
| | | inspectRule: 0, |
| | | sampleRatio: undefined |
| | | }, |
| | | standardRules: { |
| | | standardNo: [{ required: true, message: '请è¾å
¥æ åç¼å·', trigger: 'blur' }], |
| | |
| | | label: '夿³¨', |
| | | prop: 'remark', |
| | | minWidth: 160, |
| | | align: 'center' |
| | | }, |
| | | { |
| | | label: 'æ£éªè§å', |
| | | prop: 'inspectRule', |
| | | minWidth: 100, |
| | | align: 'center', |
| | | formatData: (val) => val === 0 ? 'å
¨æ£' : val === 1 ? 'æ½æ£' : '' |
| | | }, |
| | | { |
| | | label: 'æ½æ£æ¯ä¾(%)', |
| | | prop: 'sampleRatio', |
| | | minWidth: 120, |
| | | align: 'center' |
| | | }, |
| | | { |
| | |
| | | remark: '', |
| | | state: '0', |
| | | inspectType: '', |
| | | processId: '' |
| | | processId: '', |
| | | inspectRule: 0, |
| | | sampleRatio: undefined |
| | | }) |
| | | } else if (type === 'edit' && row) { |
| | | Object.assign(standardForm.value, { |
| | |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="æ åå¼ï¼" prop="standardValue"> |
| | | <el-form-item label="åå®¶æ åå¼ï¼" prop="standardValue"> |
| | | <el-input |
| | | v-model="modelForm.standardValue" |
| | | placeholder="请è¾å
¥æ åå¼" |
| | | placeholder="请è¾å
¥åå®¶æ åå¼" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | |
| | | prop: "unit", |
| | | }, |
| | | { |
| | | label: "æ åå¼", |
| | | label: "åå®¶æ åå¼", |
| | | prop: "standardValue", |
| | | }, |
| | | { |
| | |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <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-col> |
| | | <el-col :span="6" v-if="form.inspectRule === 1"> |
| | | <el-form-item label="æ½æ£æ¯ä¾(%)" prop="sampleRatio"> |
| | | <el-input-number v-model="form.sampleRatio" :min="0.01" :max="100" :precision="2" placeholder="请è¾å
¥æ½æ£æ¯ä¾" style="width: 100%" @change="calcSampleQuantity" :disabled="isViewMode" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6" v-if="form.inspectRule === 1"> |
| | | <el-form-item label="æ½æ£æ°é" prop="sampleQuantity"> |
| | | <el-input-number v-model="form.sampleQuantity" :min="0" :precision="2" style="width: 100%" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£æµåä½ï¼" |
| | | prop="checkCompany"> |
| | | <el-input v-model="form.checkCompany" |
| | |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | purchaseContractNo: "", |
| | | inspectRule: 0, |
| | | sampleRatio: undefined, |
| | | sampleQuantity: undefined, |
| | | }, |
| | | rules: { |
| | | checkTime: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | |
| | | prop: "unit", |
| | | }, |
| | | { |
| | | label: "æ åå¼", |
| | | label: "åå®¶æ åå¼", |
| | | prop: "standardValue", |
| | | }, |
| | | { |
| | |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | purchaseContractNo: "", |
| | | inspectRule: 0, |
| | | sampleRatio: undefined, |
| | | sampleQuantity: undefined, |
| | | }; |
| | | testStandardOptions.value = []; |
| | | tableData.value = []; |
| | |
| | | form.value.qualifiedQuantity = Math.max(0, quantity - unqualified); |
| | | }; |
| | | |
| | | const calcSampleQuantity = () => { |
| | | const q = parseFloat(form.value.quantity) || 0; |
| | | const r = parseFloat(form.value.sampleRatio) || 0; |
| | | if (q > 0 && r > 0) { |
| | | form.value.sampleQuantity = Number((q * r / 100).toFixed(2)); |
| | | } else { |
| | | form.value.sampleQuantity = undefined; |
| | | } |
| | | }; |
| | | |
| | | const findNodeById = (nodes, productId) => { |
| | | for (let i = 0; i < nodes.length; i++) { |
| | | if (nodes[i].value === productId) { |
| | |
| | | prop: "unit", |
| | | }, |
| | | { |
| | | label: "æ åå¼", |
| | | label: "åå®¶æ åå¼", |
| | | prop: "standardValue", |
| | | }, |
| | | { |
| | |
| | | <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£éªæ¨¡å¼ï¼"> |
| | | <el-tag :type="inspectModeTag" size="large">{{ inspectModeLabel }}</el-tag> |
| | | <span v-if="showSampleFields && currentInspect" class="mode-tip"> |
| | | (æ½æ£æ¯ä¾: {{ currentInspect.sampleRatio || 0 }}%) |
| | | </span> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£æµç»æï¼" prop="checkResult"> |
| | | <el-select v-model="form.checkResult" placeholder="è¯·éæ©æ£æµç»æ" style="width: 100%" @change="handleCheckResultChange"> |
| | | <el-option label="åæ ¼" value="åæ ¼" /> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ææ éæ©ï¼" prop="testStandardId"> |
| | | <el-select v-model="form.testStandardId" placeholder="è¯·éæ©ææ " style="width: 100%" @change="handleTestStandardChange"> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="showSampleFields"> |
| | | <el-form-item label="æ½æ£æ°éï¼" prop="sampleQuantity"> |
| | | <el-input-number |
| | | :step="1" |
| | | :min="1" |
| | | :max="maxSampleQuantity" |
| | | style="width: 100%" |
| | | v-model="form.sampleQuantity" |
| | | placeholder="请è¾å
¥æ½æ£æ°é" |
| | | :precision="0" |
| | | /> |
| | | <span class="tip-text">æå¤§å¯æ½æ£: {{ maxSampleQuantity }}</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <template v-if="form.checkResult"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ°éï¼" prop="quantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请è¾å
¥æ°é" clearable :precision="2" @change="handleQuantityChange"/> |
| | | <el-form-item label="æ£éªæ°éï¼" prop="quantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请è¾å
¥æ°é" clearable :precision="2" @change="handleQuantityChange" :disabled="showSampleFields"/> |
| | | <span v-if="showSampleFields" class="tip-text">æ½æ£æ¨¡å¼ä¸æ£éªæ°éçäºæ½æ£æ°é</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åæ ¼æ°éï¼" prop="qualifiedQuantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.qualifiedQuantity" placeholder="请è¾å
¥åæ ¼æ°é" clearable :precision="2" @change="handleQualifiedQuantityChange"/> |
| | | <el-input-number :step="0.01" :min="0" :max="form.quantity" style="width: 100%" v-model="form.qualifiedQuantity" placeholder="请è¾å
¥åæ ¼æ°é" clearable :precision="2" @change="handleQualifiedQuantityChange"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¸åæ ¼æ°éï¼" prop="unqualifiedQuantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.unqualifiedQuantity" placeholder="请è¾å
¥ä¸åæ ¼æ°é" clearable :precision="2" @change="handleUnqualifiedQuantityChange"/> |
| | | <el-input-number :step="0.01" :min="0" :max="form.quantity" style="width: 100%" v-model="form.unqualifiedQuantity" placeholder="请è¾å
¥ä¸åæ ¼æ°é" clearable :precision="2" @change="handleUnqualifiedQuantityChange"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, toRefs, getCurrentInstance, nextTick } from "vue"; |
| | | import { ref, reactive, toRefs, getCurrentInstance, nextTick, computed, watch } from "vue"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { batchQuickInspect } from "@/api/qualityManagement/rawMaterialInspection.js"; |
| | | import { qualityInspectDetailByProductId, getQualityTestStandardParamByTestStandardId } from "@/api/qualityManagement/metricMaintenance.js"; |
| | |
| | | const selectedRows = ref([]); |
| | | const testStandardOptions = ref([]); |
| | | const inspectType = ref(1); // è¿ç¨æ£éªç±»å |
| | | const currentInspect = ref(null); |
| | | |
| | | const data = reactive({ |
| | | form: { |
| | | checkResult: '', |
| | | testStandardId: '', |
| | | quantity: undefined, |
| | | sampleQuantity: undefined, |
| | | qualifiedQuantity: undefined, |
| | | unqualifiedQuantity: undefined, |
| | | checkCompany: '', |
| | |
| | | }); |
| | | const { form, rules } = toRefs(data); |
| | | |
| | | // æ£éªæ¨¡å¼æ ç¾ |
| | | const inspectModeLabel = computed(() => { |
| | | if (!currentInspect.value) return 'å
¨æ£'; |
| | | return currentInspect.value.inspectRule === 1 ? 'æ½æ£' : 'å
¨æ£'; |
| | | }); |
| | | |
| | | const inspectModeTag = computed(() => { |
| | | if (!currentInspect.value) return 'success'; |
| | | return currentInspect.value.inspectRule === 1 ? 'warning' : 'success'; |
| | | }); |
| | | |
| | | // æ¯å¦æ¾ç¤ºæ½æ£å段 |
| | | const showSampleFields = computed(() => { |
| | | return currentInspect.value && currentInspect.value.inspectRule === 1; |
| | | }); |
| | | |
| | | // æ»æ°é |
| | | const totalQuantity = computed(() => { |
| | | return currentInspect.value?.quantity || 0; |
| | | }); |
| | | |
| | | // æå¤§æ½æ£æ°é |
| | | const maxSampleQuantity = computed(() => { |
| | | return totalQuantity.value; |
| | | }); |
| | | |
| | | // é»è®¤æ½æ£æ°éï¼ä»æ£éªåè·åæææ¯ä¾è®¡ç®ï¼ |
| | | const defaultSampleQuantity = computed(() => { |
| | | if (!currentInspect.value) return 0; |
| | | if (currentInspect.value.sampleQuantity) { |
| | | return currentInspect.value.sampleQuantity; |
| | | } |
| | | if (currentInspect.value.sampleRatio) { |
| | | return Math.ceil(totalQuantity.value * currentInspect.value.sampleRatio / 100); |
| | | } |
| | | return totalQuantity.value; |
| | | }); |
| | | |
| | | // ç嬿½æ£æ°éåå |
| | | watch(() => form.value.sampleQuantity, (val) => { |
| | | if (showSampleFields.value && val) { |
| | | form.value.quantity = val; |
| | | // æ´æ°åæ ¼/ä¸åæ ¼æ°é |
| | | if (form.value.checkResult === 'åæ ¼') { |
| | | form.value.qualifiedQuantity = val; |
| | | form.value.unqualifiedQuantity = 0; |
| | | } else if (form.value.checkResult === 'ä¸åæ ¼') { |
| | | form.value.qualifiedQuantity = 0; |
| | | form.value.unqualifiedQuantity = val; |
| | | } |
| | | } |
| | | }); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "ææ ", |
| | |
| | | prop: "unit", |
| | | }, |
| | | { |
| | | label: "æ åå¼", |
| | | label: "åå®¶æ åå¼", |
| | | prop: "standardValue", |
| | | }, |
| | | { |
| | |
| | | selectedIds.value = ids; |
| | | selectedRows.value = rows; |
| | | dialogVisible.value = true; |
| | | |
| | | |
| | | // åç¬¬ä¸æ¡æ£éªåçä¿¡æ¯ä½ä¸ºåè |
| | | if (rows && rows.length > 0) { |
| | | currentInspect.value = rows[0]; |
| | | } else { |
| | | currentInspect.value = null; |
| | | } |
| | | |
| | | // å è½½ç¨æ·å表 |
| | | const userListsRes = await userListNoPage(); |
| | | userList.value = userListsRes.data; |
| | | |
| | | |
| | | // å è½½ææ éé¡¹ï¼æ ¹æ®ç¬¬ä¸ä¸ªéä¸è¡ç产åIDï¼ |
| | | if (rows && rows.length > 0 && rows[0].productId) { |
| | | const params = { |
| | |
| | | } else { |
| | | testStandardOptions.value = []; |
| | | } |
| | | |
| | | |
| | | // é置表å |
| | | const totalQty = currentInspect.value?.quantity || undefined; |
| | | const sampleQty = showSampleFields.value ? defaultSampleQuantity.value : undefined; |
| | | |
| | | form.value = { |
| | | checkResult: '', |
| | | testStandardId: '', |
| | | quantity: undefined, |
| | | quantity: showSampleFields.value ? sampleQty : totalQty, |
| | | sampleQuantity: sampleQty, |
| | | qualifiedQuantity: undefined, |
| | | unqualifiedQuantity: undefined, |
| | | checkCompany: '', |
| | |
| | | checkTime: '', |
| | | }; |
| | | tableData.value = []; |
| | | |
| | | |
| | | await nextTick(); |
| | | proxy.$refs.formRef?.clearValidate(); |
| | | }; |
| | |
| | | |
| | | // æ£æµç»æååå¤ç |
| | | const handleCheckResultChange = (value) => { |
| | | const qty = form.value.quantity || 0; |
| | | if (value === 'åæ ¼') { |
| | | // åæ ¼æ¶ï¼åæ ¼æ°éçäºæ°éï¼ä¸åæ ¼æ°é为0 |
| | | form.value.qualifiedQuantity = form.value.quantity || 0; |
| | | form.value.qualifiedQuantity = qty; |
| | | form.value.unqualifiedQuantity = 0; |
| | | } else if (value === 'ä¸åæ ¼') { |
| | | // ä¸åæ ¼æ¶ï¼åæ ¼æ°é为0ï¼ä¸åæ ¼æ°éçäºæ°é |
| | | form.value.qualifiedQuantity = 0; |
| | | form.value.unqualifiedQuantity = form.value.quantity || 0; |
| | | form.value.unqualifiedQuantity = qty; |
| | | } else if (value === 'é¨ååæ ¼') { |
| | | form.value.qualifiedQuantity = undefined; |
| | | form.value.unqualifiedQuantity = undefined; |
| | | } |
| | | }; |
| | | |
| | |
| | | const handleQualifiedQuantityChange = (value) => { |
| | | const quantity = form.value.quantity || 0; |
| | | if (value > quantity) { |
| | | proxy.$modal.msgWarning("åæ ¼æ°éä¸è½å¤§äºæ»æ°é"); |
| | | proxy.$modal.msgWarning("åæ ¼æ°éä¸è½å¤§äºæ£éªæ°é"); |
| | | form.value.qualifiedQuantity = quantity; |
| | | form.value.unqualifiedQuantity = 0; |
| | | } else { |
| | |
| | | const handleUnqualifiedQuantityChange = (value) => { |
| | | const quantity = form.value.quantity || 0; |
| | | if (value > quantity) { |
| | | proxy.$modal.msgWarning("ä¸åæ ¼æ°éä¸è½å¤§äºæ»æ°é"); |
| | | proxy.$modal.msgWarning("ä¸åæ ¼æ°éä¸è½å¤§äºæ£éªæ°é"); |
| | | form.value.unqualifiedQuantity = quantity; |
| | | form.value.qualifiedQuantity = 0; |
| | | } else { |
| | |
| | | const qualified = form.value.qualifiedQuantity || 0; |
| | | const unqualified = form.value.unqualifiedQuantity || 0; |
| | | const quantity = form.value.quantity || 0; |
| | | |
| | | |
| | | if (qualified === quantity && unqualified === 0) { |
| | | form.value.checkResult = 'åæ ¼'; |
| | | } else if (unqualified === quantity && qualified === 0) { |
| | |
| | | const submitForm = () => { |
| | | proxy.$refs.formRef.validate((valid) => { |
| | | if (valid) { |
| | | // é¨ååæ ¼æ¶æ ¡éªæ°é |
| | | if (form.value.checkResult === 'é¨ååæ ¼') { |
| | | const sum = (form.value.qualifiedQuantity || 0) + (form.value.unqualifiedQuantity || 0); |
| | | if (sum > (form.value.quantity || 0)) { |
| | | proxy.$modal.msgWarning('åæ ¼æ°é+ä¸åæ ¼æ°éä¸è½è¶
è¿æ£éªæ°é'); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | const data = { |
| | | ids: selectedIds.value, |
| | | inspectType: inspectType.value, |
| | |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .mode-tip { |
| | | margin-left: 10px; |
| | | font-size: 13px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .tip-text { |
| | | display: block; |
| | | font-size: 12px; |
| | | color: #909399; |
| | | margin-top: 4px; |
| | | } |
| | | </style> |
| | |
| | | }, |
| | | }, |
| | | { |
| | | label: "æ£éªè§å", |
| | | prop: "inspectRule", |
| | | width: 100, |
| | | formatData: (val) => val === 0 ? "å
¨æ£" : val === 1 ? "æ½æ£" : "" |
| | | }, |
| | | { |
| | | label: "æ½æ£æ¯ä¾(%)", |
| | | prop: "sampleRatio", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "æ½æ£æ°é", |
| | | prop: "sampleQuantity", |
| | | width: 100, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <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-col> |
| | | <el-col :span="6" v-if="form.inspectRule === 1"> |
| | | <el-form-item label="æ½æ£æ¯ä¾(%)" prop="sampleRatio"> |
| | | <el-input-number v-model="form.sampleRatio" :min="0.01" :max="100" :precision="2" placeholder="请è¾å
¥æ½æ£æ¯ä¾" style="width: 100%" @change="calcSampleQuantity" :disabled="isViewMode" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6" v-if="form.inspectRule === 1"> |
| | | <el-form-item label="æ½æ£æ°é" prop="sampleQuantity"> |
| | | <el-input-number v-model="form.sampleQuantity" :min="0" :precision="2" style="width: 100%" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£æµåä½ï¼" prop="checkCompany"> |
| | | <el-input v-model="form.checkCompany" placeholder="请è¾å
¥" clearable :disabled="isViewMode"/> |
| | | </el-form-item> |
| | |
| | | stockInRatio: 100.00, |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | inspectRule: 0, |
| | | sampleRatio: undefined, |
| | | sampleQuantity: undefined, |
| | | }, |
| | | rules: { |
| | | checkTime: [{required: false, message: "请è¾å
¥", trigger: "blur"},], |
| | |
| | | prop: "unit", |
| | | }, |
| | | { |
| | | label: "æ åå¼", |
| | | label: "åå®¶æ åå¼", |
| | | prop: "standardValue", |
| | | }, |
| | | { |
| | |
| | | stockInRatio: 100.00, |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | inspectRule: 0, |
| | | sampleRatio: undefined, |
| | | sampleQuantity: undefined, |
| | | } |
| | | testStandardOptions.value = []; |
| | | tableData.value = []; |
| | |
| | | form.value.unit = modelOptions.value.find(item => item.id == value)?.unit || ''; |
| | | } |
| | | |
| | | const calcSampleQuantity = () => { |
| | | const q = parseFloat(form.value.quantity) || 0; |
| | | const r = parseFloat(form.value.sampleRatio) || 0; |
| | | if (q > 0 && r > 0) { |
| | | form.value.sampleQuantity = Number((q * r / 100).toFixed(2)); |
| | | } else { |
| | | form.value.sampleQuantity = undefined; |
| | | } |
| | | }; |
| | | |
| | | const findNodeById = (nodes, productId) => { |
| | | for (let i = 0; i < nodes.length; i++) { |
| | | if (nodes[i].value === productId) { |
| | |
| | | prop: "unit", |
| | | }, |
| | | { |
| | | label: "æ åå¼", |
| | | label: "åå®¶æ åå¼", |
| | | prop: "standardValue", |
| | | }, |
| | | { |
| | |
| | | <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£éªæ¨¡å¼ï¼"> |
| | | <el-tag :type="inspectModeTag" size="large">{{ inspectModeLabel }}</el-tag> |
| | | <span v-if="showSampleFields && currentInspect" class="mode-tip"> |
| | | (æ½æ£æ¯ä¾: {{ currentInspect.sampleRatio || 0 }}%) |
| | | </span> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£æµç»æï¼" prop="checkResult"> |
| | | <el-select v-model="form.checkResult" placeholder="è¯·éæ©æ£æµç»æ" style="width: 100%" @change="handleCheckResultChange"> |
| | | <el-option label="åæ ¼" value="åæ ¼" /> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ææ éæ©ï¼" prop="testStandardId"> |
| | | <el-select v-model="form.testStandardId" placeholder="è¯·éæ©ææ " style="width: 100%" @change="handleTestStandardChange"> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="showSampleFields"> |
| | | <el-form-item label="æ½æ£æ°éï¼" prop="sampleQuantity"> |
| | | <el-input-number |
| | | :step="1" |
| | | :min="1" |
| | | :max="maxSampleQuantity" |
| | | style="width: 100%" |
| | | v-model="form.sampleQuantity" |
| | | placeholder="请è¾å
¥æ½æ£æ°é" |
| | | :precision="0" |
| | | /> |
| | | <span class="tip-text">æå¤§å¯æ½æ£: {{ maxSampleQuantity }}</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <template v-if="form.checkResult"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ°éï¼" prop="quantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请è¾å
¥æ°é" clearable :precision="2" @change="handleQuantityChange"/> |
| | | <el-form-item label="æ£éªæ°éï¼" prop="quantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请è¾å
¥æ°é" clearable :precision="2" @change="handleQuantityChange" :disabled="showSampleFields"/> |
| | | <span v-if="showSampleFields" class="tip-text">æ½æ£æ¨¡å¼ä¸æ£éªæ°éçäºæ½æ£æ°é</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åæ ¼æ°éï¼" prop="qualifiedQuantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.qualifiedQuantity" placeholder="请è¾å
¥åæ ¼æ°é" clearable :precision="2" @change="handleQualifiedQuantityChange"/> |
| | | <el-input-number :step="0.01" :min="0" :max="form.quantity" style="width: 100%" v-model="form.qualifiedQuantity" placeholder="请è¾å
¥åæ ¼æ°é" clearable :precision="2" @change="handleQualifiedQuantityChange"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¸åæ ¼æ°éï¼" prop="unqualifiedQuantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.unqualifiedQuantity" placeholder="请è¾å
¥ä¸åæ ¼æ°é" clearable :precision="2" @change="handleUnqualifiedQuantityChange"/> |
| | | <el-input-number :step="0.01" :min="0" :max="form.quantity" style="width: 100%" v-model="form.unqualifiedQuantity" placeholder="请è¾å
¥ä¸åæ ¼æ°é" clearable :precision="2" @change="handleUnqualifiedQuantityChange"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, toRefs, getCurrentInstance, nextTick } from "vue"; |
| | | import { ref, reactive, toRefs, getCurrentInstance, nextTick, computed, watch } from "vue"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { batchQuickInspect } from "@/api/qualityManagement/rawMaterialInspection.js"; |
| | | import { qualityInspectDetailByProductId, getQualityTestStandardParamByTestStandardId } from "@/api/qualityManagement/metricMaintenance.js"; |
| | |
| | | const selectedRows = ref([]); |
| | | const testStandardOptions = ref([]); |
| | | const inspectType = ref(0); // åæææ£éªç±»å |
| | | const currentInspect = ref(null); |
| | | |
| | | const data = reactive({ |
| | | form: { |
| | | checkResult: '', |
| | | testStandardId: '', |
| | | quantity: undefined, |
| | | sampleQuantity: undefined, |
| | | qualifiedQuantity: undefined, |
| | | unqualifiedQuantity: undefined, |
| | | stockInRatio: 100.00, |
| | |
| | | }); |
| | | const { form, rules } = toRefs(data); |
| | | |
| | | // æ£éªæ¨¡å¼æ ç¾ |
| | | const inspectModeLabel = computed(() => { |
| | | if (!currentInspect.value) return 'å
¨æ£'; |
| | | return currentInspect.value.inspectRule === 1 ? 'æ½æ£' : 'å
¨æ£'; |
| | | }); |
| | | |
| | | const inspectModeTag = computed(() => { |
| | | if (!currentInspect.value) return 'success'; |
| | | return currentInspect.value.inspectRule === 1 ? 'warning' : 'success'; |
| | | }); |
| | | |
| | | // æ¯å¦æ¾ç¤ºæ½æ£å段 |
| | | const showSampleFields = computed(() => { |
| | | return currentInspect.value && currentInspect.value.inspectRule === 1; |
| | | }); |
| | | |
| | | // æ»æ°é |
| | | const totalQuantity = computed(() => { |
| | | return currentInspect.value?.quantity || 0; |
| | | }); |
| | | |
| | | // æå¤§æ½æ£æ°é |
| | | const maxSampleQuantity = computed(() => { |
| | | return totalQuantity.value; |
| | | }); |
| | | |
| | | // é»è®¤æ½æ£æ°éï¼ä»æ£éªåè·åæææ¯ä¾è®¡ç®ï¼ |
| | | const defaultSampleQuantity = computed(() => { |
| | | if (!currentInspect.value) return 0; |
| | | if (currentInspect.value.sampleQuantity) { |
| | | return currentInspect.value.sampleQuantity; |
| | | } |
| | | if (currentInspect.value.sampleRatio) { |
| | | return Math.ceil(totalQuantity.value * currentInspect.value.sampleRatio / 100); |
| | | } |
| | | return totalQuantity.value; |
| | | }); |
| | | |
| | | // ç嬿½æ£æ°éåå |
| | | watch(() => form.value.sampleQuantity, (val) => { |
| | | if (showSampleFields.value && val) { |
| | | form.value.quantity = val; |
| | | // æ´æ°åæ ¼/ä¸åæ ¼æ°é |
| | | if (form.value.checkResult === 'åæ ¼') { |
| | | form.value.qualifiedQuantity = val; |
| | | form.value.unqualifiedQuantity = 0; |
| | | } else if (form.value.checkResult === 'ä¸åæ ¼') { |
| | | form.value.qualifiedQuantity = 0; |
| | | form.value.unqualifiedQuantity = val; |
| | | } |
| | | } |
| | | }); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "ææ ", |
| | |
| | | prop: "unit", |
| | | }, |
| | | { |
| | | label: "æ åå¼", |
| | | label: "åå®¶æ åå¼", |
| | | prop: "standardValue", |
| | | }, |
| | | { |
| | |
| | | selectedIds.value = ids; |
| | | selectedRows.value = rows; |
| | | dialogVisible.value = true; |
| | | |
| | | |
| | | // åç¬¬ä¸æ¡æ£éªåçä¿¡æ¯ä½ä¸ºåè |
| | | if (rows && rows.length > 0) { |
| | | currentInspect.value = rows[0]; |
| | | } else { |
| | | currentInspect.value = null; |
| | | } |
| | | |
| | | // å è½½ç¨æ·å表 |
| | | const userListsRes = await userListNoPage(); |
| | | userList.value = userListsRes.data; |
| | | |
| | | |
| | | // å è½½ææ éé¡¹ï¼æ ¹æ®ç¬¬ä¸ä¸ªéä¸è¡ç产åIDï¼ |
| | | if (rows && rows.length > 0 && rows[0].productId) { |
| | | const params = { |
| | |
| | | } else { |
| | | testStandardOptions.value = []; |
| | | } |
| | | |
| | | |
| | | // é置表å |
| | | const totalQty = currentInspect.value?.quantity || undefined; |
| | | const sampleQty = showSampleFields.value ? defaultSampleQuantity.value : undefined; |
| | | |
| | | form.value = { |
| | | checkResult: '', |
| | | testStandardId: '', |
| | | quantity: undefined, |
| | | quantity: showSampleFields.value ? sampleQty : totalQty, |
| | | sampleQuantity: sampleQty, |
| | | qualifiedQuantity: undefined, |
| | | unqualifiedQuantity: undefined, |
| | | stockInRatio: 100.00, |
| | |
| | | checkTime: '', |
| | | }; |
| | | tableData.value = []; |
| | | |
| | | |
| | | await nextTick(); |
| | | proxy.$refs.formRef?.clearValidate(); |
| | | }; |
| | |
| | | |
| | | // æ£æµç»æååå¤ç |
| | | const handleCheckResultChange = (value) => { |
| | | const qty = form.value.quantity || 0; |
| | | if (value === 'åæ ¼') { |
| | | // åæ ¼æ¶ï¼åæ ¼æ°éçäºæ°éï¼ä¸åæ ¼æ°é为0 |
| | | form.value.qualifiedQuantity = form.value.quantity || 0; |
| | | form.value.qualifiedQuantity = qty; |
| | | form.value.unqualifiedQuantity = 0; |
| | | } else if (value === 'ä¸åæ ¼') { |
| | | // ä¸åæ ¼æ¶ï¼åæ ¼æ°é为0ï¼ä¸åæ ¼æ°éçäºæ°é |
| | | form.value.qualifiedQuantity = 0; |
| | | form.value.unqualifiedQuantity = form.value.quantity || 0; |
| | | form.value.unqualifiedQuantity = qty; |
| | | } else if (value === 'é¨ååæ ¼') { |
| | | form.value.qualifiedQuantity = undefined; |
| | | form.value.unqualifiedQuantity = undefined; |
| | | } |
| | | }; |
| | | |
| | |
| | | const handleQualifiedQuantityChange = (value) => { |
| | | const quantity = form.value.quantity || 0; |
| | | if (value > quantity) { |
| | | proxy.$modal.msgWarning("åæ ¼æ°éä¸è½å¤§äºæ»æ°é"); |
| | | proxy.$modal.msgWarning("åæ ¼æ°éä¸è½å¤§äºæ£éªæ°é"); |
| | | form.value.qualifiedQuantity = quantity; |
| | | form.value.unqualifiedQuantity = 0; |
| | | } else { |
| | |
| | | const handleUnqualifiedQuantityChange = (value) => { |
| | | const quantity = form.value.quantity || 0; |
| | | if (value > quantity) { |
| | | proxy.$modal.msgWarning("ä¸åæ ¼æ°éä¸è½å¤§äºæ»æ°é"); |
| | | proxy.$modal.msgWarning("ä¸åæ ¼æ°éä¸è½å¤§äºæ£éªæ°é"); |
| | | form.value.unqualifiedQuantity = quantity; |
| | | form.value.qualifiedQuantity = 0; |
| | | } else { |
| | |
| | | const qualified = form.value.qualifiedQuantity || 0; |
| | | const unqualified = form.value.unqualifiedQuantity || 0; |
| | | const quantity = form.value.quantity || 0; |
| | | |
| | | |
| | | if (qualified === quantity && unqualified === 0) { |
| | | form.value.checkResult = 'åæ ¼'; |
| | | } else if (unqualified === quantity && qualified === 0) { |
| | |
| | | const submitForm = () => { |
| | | proxy.$refs.formRef.validate((valid) => { |
| | | if (valid) { |
| | | // é¨ååæ ¼æ¶æ ¡éªæ°é |
| | | if (form.value.checkResult === 'é¨ååæ ¼') { |
| | | const sum = (form.value.qualifiedQuantity || 0) + (form.value.unqualifiedQuantity || 0); |
| | | if (sum > (form.value.quantity || 0)) { |
| | | proxy.$modal.msgWarning('åæ ¼æ°é+ä¸åæ ¼æ°éä¸è½è¶
è¿æ£éªæ°é'); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | const data = { |
| | | ids: selectedIds.value, |
| | | inspectType: inspectType.value, |
| | |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .mode-tip { |
| | | margin-left: 10px; |
| | | font-size: 13px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .tip-text { |
| | | display: block; |
| | | font-size: 12px; |
| | | color: #909399; |
| | | margin-top: 4px; |
| | | } |
| | | </style> |
| | |
| | | }, |
| | | }, |
| | | { |
| | | label: "æ£éªè§å", |
| | | prop: "inspectRule", |
| | | width: 100, |
| | | formatData: (val) => val === 0 ? "å
¨æ£" : val === 1 ? "æ½æ£" : "" |
| | | }, |
| | | { |
| | | label: "æ½æ£æ¯ä¾(%)", |
| | | prop: "sampleRatio", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "æ½æ£æ°é", |
| | | prop: "sampleQuantity", |
| | | width: 100, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | |
| | | <template> |
| | | <div class="panel-header"> |
| | | <span class="header-dot"></span> |
| | | <span class="panel-title">{{ title }}</span> |
| | | </div> |
| | | </template> |
| | |
| | | background-size: 100% 100%; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .header-dot { |
| | | width: 12px; |
| | | height: 12px; |
| | | background: linear-gradient(135deg, #4ee4ff 0%, #217aff 100%); |
| | | clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); |
| | | animation: dotPulse 2s ease-in-out infinite; |
| | | margin-left: 32px; |
| | | } |
| | | |
| | | @keyframes dotPulse { |
| | | 0%, 100% { opacity: 0.8; transform: scale(1); } |
| | | 50% { opacity: 1; transform: scale(1.1); box-shadow: 0 0 10px rgba(78, 228, 255, 0.5); } |
| | | } |
| | | |
| | | .panel-title { |
| | |
| | | font-weight: 500; |
| | | font-size: 16px; |
| | | color: #D9ECFF; |
| | | padding-left: 46px; |
| | | padding-left: 10px; |
| | | line-height: 36px; |
| | | animation: titleShimmer 3s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes titleShimmer { |
| | | 0%, 100% { opacity: 1; } |
| | | 50% { opacity: 0.85; } |
| | | } |
| | | </style> |
| | |
| | | padding: 18px; |
| | | width: 100%; |
| | | height: 428px; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* 颿¿è§è½è£
饰 */ |
| | | .panel-item-customers::before, |
| | | .panel-item-customers::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .panel-item-customers::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .panel-item-customers::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | </style> |
| | | |
| | |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 16px; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* 颿¿è§è½è£
饰 */ |
| | | .equipment-stats::before, |
| | | .equipment-stats::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .equipment-stats::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .equipment-stats::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | |
| | | .equipment-header { |
| | |
| | | .equipment-icon { |
| | | width: 50px; |
| | | height: 50px; |
| | | animation: iconFloat 4s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes iconFloat { |
| | | 0%, 100% { transform: translateY(0); } |
| | | 50% { transform: translateY(-3px); } |
| | | } |
| | | </style> |
| | |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | height: 142px; |
| | | transition: all 0.3s ease; |
| | | position: relative; |
| | | overflow: hidden; |
| | | animation: cardFadeIn 0.6s ease-out both; |
| | | } |
| | | |
| | | .stat-card:nth-child(1) { animation-delay: 0.1s; } |
| | | .stat-card:nth-child(2) { animation-delay: 0.2s; } |
| | | .stat-card:nth-child(3) { animation-delay: 0.3s; } |
| | | |
| | | @keyframes cardFadeIn { |
| | | from { opacity: 0; transform: translateY(20px); } |
| | | to { opacity: 1; transform: translateY(0); } |
| | | } |
| | | |
| | | .stat-card:hover { |
| | | transform: translateY(-3px); |
| | | box-shadow: 0 10px 30px rgba(0, 212, 255, 0.2); |
| | | } |
| | | |
| | | /* å¡çåºé¨å
线 */ |
| | | .stat-card::after { |
| | | content: ''; |
| | | position: absolute; |
| | | bottom: 0; |
| | | left: 10%; |
| | | right: 10%; |
| | | height: 2px; |
| | | background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.5), transparent); |
| | | opacity: 0; |
| | | transition: opacity 0.3s; |
| | | } |
| | | |
| | | .stat-card:hover::after { |
| | | opacity: 1; |
| | | } |
| | | |
| | | .card-icon { |
| | | width: 100px; |
| | | height: 100px; |
| | | width: 70px; |
| | | height: 70px; |
| | | margin: 20px 20px 0 10px; |
| | | animation: iconFloat 4s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes iconFloat { |
| | | 0%, 100% { transform: translateY(0); } |
| | | 50% { transform: translateY(-5px); } |
| | | } |
| | | |
| | | .card-content { |
| | |
| | | |
| | | .card-value { |
| | | font-weight: 500; |
| | | font-size: 40px; |
| | | font-size: 32px; |
| | | background: linear-gradient(360deg, #008bfd 0%, #ffffff 100%); |
| | | -webkit-background-clip: text; |
| | | -webkit-text-fill-color: transparent; |
| | | background-clip: text; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .stat-card:hover .card-value { |
| | | text-shadow: 0 0 15px rgba(0, 212, 255, 0.4); |
| | | transform: scale(1.05); |
| | | } |
| | | |
| | | .card-label { |
| | | font-weight: 400; |
| | | font-size: 19px; |
| | | font-size: 16px; |
| | | color: rgba(208, 231, 255, 0.7); |
| | | } |
| | | |
| | |
| | | padding: 18px; |
| | | width: 100%; |
| | | height: 449px; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* 颿¿è§è½è£
饰 */ |
| | | .panel-item-customers::before, |
| | | .panel-item-customers::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .panel-item-customers::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .panel-item-customers::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | |
| | | .pie-chart-wrapper { |
| | |
| | | width: 100%; |
| | | height: 320px; |
| | | background: transparent; |
| | | animation: pieFloat 4s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes pieFloat { |
| | | 0%, 100% { transform: translateY(0); } |
| | | 50% { transform: translateY(-3px); } |
| | | } |
| | | |
| | | |
| | |
| | | left: 25%; |
| | | top: 50%; |
| | | transform: translate(-51.5%, -50%); |
| | | animation: pieBgRotate 30s linear infinite; |
| | | } |
| | | |
| | | @keyframes pieBgRotate { |
| | | from { transform: translate(-51.5%, -50%) rotate(0deg); } |
| | | to { transform: translate(-51.5%, -50%) rotate(360deg); } |
| | | } |
| | | </style> |
| | |
| | | padding: 18px; |
| | | width: 100%; |
| | | height: 449px; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* 颿¿è§è½è£
饰 */ |
| | | .panel-item-customers::before, |
| | | .panel-item-customers::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .panel-item-customers::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .panel-item-customers::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | |
| | | .pie-chart-wrapper { |
| | | position: relative; |
| | | width: 100%; |
| | | height: 320px; |
| | | animation: pieFloat 4s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes pieFloat { |
| | | 0%, 100% { transform: translateY(0); } |
| | | 50% { transform: translateY(-3px); } |
| | | } |
| | | |
| | | .pie-background { |
| | | position: absolute; |
| | | left: 25%; |
| | |
| | | background-repeat: no-repeat; |
| | | z-index: 1; |
| | | pointer-events: none; |
| | | animation: pieBgRotate 30s linear infinite; |
| | | } |
| | | |
| | | @keyframes pieBgRotate { |
| | | from { transform: translate(-51.5%, -50%) rotate(0deg); } |
| | | to { transform: translate(-51.5%, -50%) rotate(360deg); } |
| | | } |
| | | </style> |
| | |
| | | justify-content: center; |
| | | background-color: #000; |
| | | overflow: hidden; |
| | | position: relative; |
| | | } |
| | | |
| | | /* å¨æç½æ ¼èæ¯ */ |
| | | .scale-container::before { |
| | | content: ''; |
| | | position: absolute; |
| | | inset: 0; |
| | | background-image: |
| | | linear-gradient(rgba(0, 212, 255, 0.03) 1px, transparent 1px), |
| | | linear-gradient(90deg, rgba(0, 212, 255, 0.03) 1px, transparent 1px); |
| | | background-size: 50px 50px; |
| | | animation: gridMove 20s linear infinite; |
| | | z-index: 0; |
| | | } |
| | | |
| | | @keyframes gridMove { |
| | | 0% { transform: translate(0, 0); } |
| | | 100% { transform: translate(50px, 50px); } |
| | | } |
| | | |
| | | /* å
é¨å
容åºå - åºå®è®¾è®¡å°ºå¯¸ */ |
| | |
| | | color: #FFFFFF; |
| | | top: 16px; |
| | | position: absolute; |
| | | animation: titleGlow 3s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes titleGlow { |
| | | 0%, 100% { text-shadow: 0 0 20px rgba(0, 212, 255, 0.3); } |
| | | 50% { text-shadow: 0 0 40px rgba(0, 212, 255, 0.6), 0 0 60px rgba(0, 212, 255, 0.3); } |
| | | } |
| | | |
| | | .fullscreen-btn { |
| | |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .left-panel { |
| | | animation: slideInLeft 0.8s ease-out; |
| | | } |
| | | |
| | | .right-panel { |
| | | animation: slideInRight 0.8s ease-out; |
| | | } |
| | | |
| | | .center-panel { |
| | | animation: slideInUp 0.8s ease-out; |
| | | } |
| | | |
| | | @keyframes slideInLeft { |
| | | from { opacity: 0; transform: translateX(-50px); } |
| | | to { opacity: 1; transform: translateX(0); } |
| | | } |
| | | |
| | | @keyframes slideInRight { |
| | | from { opacity: 0; transform: translateX(50px); } |
| | | to { opacity: 1; transform: translateX(0); } |
| | | } |
| | | |
| | | @keyframes slideInUp { |
| | | from { opacity: 0; transform: translateY(30px); } |
| | | to { opacity: 1; transform: translateY(0); } |
| | | } |
| | | |
| | | .left-panel, |
| | | .right-panel { |
| | | flex: 1; |
| | |
| | | <template> |
| | | <div class="panel-header"> |
| | | <span class="header-dot"></span> |
| | | <span class="panel-title">{{ title }}</span> |
| | | </div> |
| | | </template> |
| | |
| | | background-size: 100% 100%; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .header-dot { |
| | | width: 12px; |
| | | height: 12px; |
| | | background: linear-gradient(135deg, #4ee4ff 0%, #217aff 100%); |
| | | clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); |
| | | animation: dotPulse 2s ease-in-out infinite; |
| | | margin-left: 32px; |
| | | } |
| | | |
| | | @keyframes dotPulse { |
| | | 0%, 100% { opacity: 0.8; transform: scale(1); } |
| | | 50% { opacity: 1; transform: scale(1.1); box-shadow: 0 0 10px rgba(78, 228, 255, 0.5); } |
| | | } |
| | | |
| | | .panel-title { |
| | |
| | | font-weight: 500; |
| | | font-size: 16px; |
| | | color: #D9ECFF; |
| | | padding-left: 46px; |
| | | padding-left: 10px; |
| | | line-height: 36px; |
| | | animation: titleShimmer 3s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes titleShimmer { |
| | | 0%, 100% { opacity: 1; } |
| | | 50% { opacity: 0.85; } |
| | | } |
| | | </style> |
| | |
| | | padding: 18px; |
| | | width: 100%; |
| | | height: 370px; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* 颿¿è§è½è£
饰 */ |
| | | .panel-item-customers::before, |
| | | .panel-item-customers::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .panel-item-customers::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .panel-item-customers::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | |
| | | .pie-chart-wrapper { |
| | |
| | | width: 100%; |
| | | height: 320px; |
| | | background: transparent; |
| | | animation: pieFloat 4s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes pieFloat { |
| | | 0%, 100% { transform: translateY(0); } |
| | | 50% { transform: translateY(-3px); } |
| | | } |
| | | |
| | | |
| | |
| | | background-repeat: no-repeat; |
| | | z-index: 1; |
| | | pointer-events: none; |
| | | animation: pieBgRotate 30s linear infinite; |
| | | } |
| | | |
| | | @keyframes pieBgRotate { |
| | | from { transform: translate(-113%, -50%) rotate(0deg); } |
| | | to { transform: translate(-113%, -50%) rotate(360deg); } |
| | | } |
| | | </style> |
| | |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | height: 142px; |
| | | transition: all 0.3s ease; |
| | | position: relative; |
| | | overflow: hidden; |
| | | animation: cardFadeIn 0.6s ease-out both; |
| | | } |
| | | |
| | | .stat-card:nth-child(1) { animation-delay: 0.1s; } |
| | | .stat-card:nth-child(2) { animation-delay: 0.2s; } |
| | | |
| | | @keyframes cardFadeIn { |
| | | from { opacity: 0; transform: translateY(20px); } |
| | | to { opacity: 1; transform: translateY(0); } |
| | | } |
| | | |
| | | .stat-card:hover { |
| | | transform: translateY(-3px); |
| | | box-shadow: 0 10px 30px rgba(0, 212, 255, 0.2); |
| | | } |
| | | |
| | | /* å¡çåºé¨å
线 */ |
| | | .stat-card::after { |
| | | content: ''; |
| | | position: absolute; |
| | | bottom: 0; |
| | | left: 10%; |
| | | right: 10%; |
| | | height: 2px; |
| | | background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.5), transparent); |
| | | opacity: 0; |
| | | transition: opacity 0.3s; |
| | | } |
| | | |
| | | .stat-card:hover::after { |
| | | opacity: 1; |
| | | } |
| | | |
| | | .card-icon { |
| | | width: 100px; |
| | | height: 100px; |
| | | width: 70px; |
| | | height: 70px; |
| | | margin: 20px 20px 0 10px; |
| | | animation: iconFloat 4s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes iconFloat { |
| | | 0%, 100% { transform: translateY(0); } |
| | | 50% { transform: translateY(-5px); } |
| | | } |
| | | |
| | | .card-content { |
| | |
| | | |
| | | .card-value { |
| | | font-weight: 500; |
| | | font-size: 40px; |
| | | font-size: 32px; |
| | | background: linear-gradient(360deg, #008bfd 0%, #ffffff 100%); |
| | | -webkit-background-clip: text; |
| | | -webkit-text-fill-color: transparent; |
| | | background-clip: text; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .stat-card:hover .card-value { |
| | | text-shadow: 0 0 15px rgba(0, 212, 255, 0.4); |
| | | transform: scale(1.05); |
| | | } |
| | | |
| | | .card-label { |
| | | font-weight: 400; |
| | | font-size: 19px; |
| | | font-size: 16px; |
| | | color: rgba(208, 231, 255, 0.7); |
| | | } |
| | | |
| | |
| | | height: 240px; |
| | | padding-top: 0px; |
| | | margin-bottom: 20px; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* 设å¤ç»è®¡é¢æ¿è§è½è£
饰 */ |
| | | .equipment-stats::before, |
| | | .equipment-stats::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .equipment-stats::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .equipment-stats::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | |
| | | .equipment-header { |
| | |
| | | .equipment-value { |
| | | display: block; |
| | | font-weight: 500; |
| | | font-size: 40px; |
| | | font-size: 36px; |
| | | color: #ffffff; |
| | | width: 120px; |
| | | height: 110px; |
| | |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | margin-bottom: 8px; |
| | | transition: all 0.3s ease; |
| | | animation: valuePulse 3s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes valuePulse { |
| | | 0%, 100% { text-shadow: 0 0 10px rgba(78, 228, 255, 0.2); } |
| | | 50% { text-shadow: 0 0 20px rgba(78, 228, 255, 0.4); } |
| | | } |
| | | |
| | | .equipment-label { |
| | |
| | | padding-top: 10px; |
| | | height: 480px; |
| | | flex: 1; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* äºä»¶é¢æ¿è§è½è£
饰 */ |
| | | .event-info::before, |
| | | .event-info::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .event-info::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .event-info::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | |
| | | .event-header { |
| | |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | transition: all 0.3s ease; |
| | | position: relative; |
| | | } |
| | | |
| | | .todo-list li:hover { |
| | | background: rgba(0, 212, 255, 0.08); |
| | | transform: translateX(5px); |
| | | } |
| | | |
| | | .todo-list li::after { |
| | | content: ''; |
| | | position: absolute; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | height: 1px; |
| | | background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.3), transparent); |
| | | opacity: 0; |
| | | transition: opacity 0.3s; |
| | | } |
| | | |
| | | .todo-list li:hover::after { |
| | | opacity: 1; |
| | | } |
| | | |
| | | .todo-title { |
| | |
| | | import { customerRevenueAnalysis } from '@/api/viewIndex.js' |
| | | import { listCustomer } from '@/api/basicData/customer.js' |
| | | |
| | | const dateType = ref(1) // 1=å¨ 2=æ 3=å£åº¦ |
| | | const dateType = ref(3) // 1=å¨ 2=æ 3=å£åº¦ |
| | | const customerValue = ref(null) |
| | | const customerOptions = ref([]) |
| | | |
| | |
| | | padding: 18px; |
| | | width: 100%; |
| | | height: 478px; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* 颿¿è§è½è£
饰 */ |
| | | .panel-item-customers::before, |
| | | .panel-item-customers::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .panel-item-customers::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .panel-item-customers::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | </style> |
| | | |
| | |
| | | padding: 18px; |
| | | width: 100%; |
| | | height: 420px; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* 颿¿è§è½è£
饰 */ |
| | | .panel-item-customers::before, |
| | | .panel-item-customers::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .panel-item-customers::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .panel-item-customers::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | |
| | | .pie-chart-wrapper { |
| | |
| | | width: 100%; |
| | | height: 320px; |
| | | background: transparent; |
| | | animation: pieFloat 4s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes pieFloat { |
| | | 0%, 100% { transform: translateY(0); } |
| | | 50% { transform: translateY(-3px); } |
| | | } |
| | | |
| | | .pie-background { |
| | |
| | | left: 50%; |
| | | top: 50%; |
| | | transform: translate(-51.5%, -39%); |
| | | animation: pieBgRotate 30s linear infinite; |
| | | } |
| | | |
| | | @keyframes pieBgRotate { |
| | | from { transform: translate(-51.5%, -39%) rotate(0deg); } |
| | | to { transform: translate(-51.5%, -39%) rotate(360deg); } |
| | | } |
| | | </style> |
| | |
| | | height: '100%', |
| | | } |
| | | |
| | | const dateType = ref(1) // 1=å¨ 2=æ 3=å£åº¦ |
| | | const dateType = ref(3) // 1=å¨ 2=æ 3=å£åº¦ |
| | | |
| | | // 飿ºå¾æ SVG pathï¼ä¸ right-top ä¸è´ï¼ |
| | | const aircraft = |
| | |
| | | padding: 18px; |
| | | width: 100%; |
| | | height: 449px; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* 颿¿è§è½è£
饰 */ |
| | | .panel-item-customers::before, |
| | | .panel-item-customers::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .panel-item-customers::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .panel-item-customers::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | |
| | | .switch-container { |
| | |
| | | height: '100%', |
| | | } |
| | | |
| | | const radio1 = ref(1) |
| | | const radio1 = ref(3) |
| | | |
| | | // 飿ºå¾æ SVG path |
| | | const aircraft = |
| | |
| | | padding: 18px; |
| | | width: 100%; |
| | | height: 449px; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* 颿¿è§è½è£
饰 */ |
| | | .panel-item-customers::before, |
| | | .panel-item-customers::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .panel-item-customers::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .panel-item-customers::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | |
| | | .switch-container { |
| | |
| | | justify-content: center; |
| | | background-color: #000; |
| | | overflow: hidden; |
| | | position: relative; |
| | | } |
| | | |
| | | /* å¨æç½æ ¼èæ¯ */ |
| | | .scale-container::before { |
| | | content: ''; |
| | | position: absolute; |
| | | inset: 0; |
| | | background-image: |
| | | linear-gradient(rgba(0, 212, 255, 0.03) 1px, transparent 1px), |
| | | linear-gradient(90deg, rgba(0, 212, 255, 0.03) 1px, transparent 1px); |
| | | background-size: 50px 50px; |
| | | animation: gridMove 20s linear infinite; |
| | | z-index: 0; |
| | | } |
| | | |
| | | @keyframes gridMove { |
| | | 0% { transform: translate(0, 0); } |
| | | 100% { transform: translate(50px, 50px); } |
| | | } |
| | | |
| | | /* å
é¨å
容åºå - åºå®è®¾è®¡å°ºå¯¸ */ |
| | |
| | | color: #FFFFFF; |
| | | top: 16px; |
| | | position: absolute; |
| | | animation: titleGlow 3s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes titleGlow { |
| | | 0%, 100% { text-shadow: 0 0 20px rgba(0, 212, 255, 0.3); } |
| | | 50% { text-shadow: 0 0 40px rgba(0, 212, 255, 0.6), 0 0 60px rgba(0, 212, 255, 0.3); } |
| | | } |
| | | |
| | | .fullscreen-btn { |
| | |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .left-panel { |
| | | animation: slideInLeft 0.8s ease-out; |
| | | } |
| | | |
| | | .right-panel { |
| | | animation: slideInRight 0.8s ease-out; |
| | | } |
| | | |
| | | .center-panel { |
| | | animation: slideInUp 0.8s ease-out; |
| | | } |
| | | |
| | | @keyframes slideInLeft { |
| | | from { opacity: 0; transform: translateX(-50px); } |
| | | to { opacity: 1; transform: translateX(0); } |
| | | } |
| | | |
| | | @keyframes slideInRight { |
| | | from { opacity: 0; transform: translateX(50px); } |
| | | to { opacity: 1; transform: translateX(0); } |
| | | } |
| | | |
| | | @keyframes slideInUp { |
| | | from { opacity: 0; transform: translateY(30px); } |
| | | to { opacity: 1; transform: translateY(0); } |
| | | } |
| | | |
| | | .left-panel, |
| | | .right-panel { |
| | | flex: 1; |
| | |
| | | <template> |
| | | <div class="panel-header"> |
| | | <span class="panel-title">{{ title }}</span> |
| | | <span v-if="$slots.extra" class="panel-extra"> |
| | | <slot name="extra"></slot> |
| | | </span> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | background-size: 100% 100%; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | position: relative; |
| | | } |
| | | |
| | | /* æ é¢è£
饰å¨ç» */ |
| | | .panel-header::before { |
| | | content: ''; |
| | | position: absolute; |
| | | left: 20px; |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | width: 8px; |
| | | height: 8px; |
| | | background: #00d4ff; |
| | | border-radius: 50%; |
| | | animation: dotPulse 2s ease-in-out infinite; |
| | | box-shadow: 0 0 10px rgba(0, 212, 255, 0.6); |
| | | } |
| | | |
| | | @keyframes dotPulse { |
| | | 0%, 100% { opacity: 0.6; transform: translateY(-50%) scale(1); } |
| | | 50% { opacity: 1; transform: translateY(-50%) scale(1.2); } |
| | | } |
| | | |
| | | .panel-title { |
| | | width: 100%; |
| | | font-weight: 500; |
| | | font-size: 16px; |
| | | color: #D9ECFF; |
| | | padding-left: 46px; |
| | | line-height: 36px; |
| | | position: relative; |
| | | text-shadow: 0 0 10px rgba(0, 212, 255, 0.3); |
| | | } |
| | | |
| | | .panel-extra { |
| | | padding-right: 10px; |
| | | line-height: 36px; |
| | | } |
| | | </style> |
| | |
| | | border: 1px solid rgba(78, 228, 255, 0.25); |
| | | cursor: pointer; |
| | | z-index: 10; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .warn-range:hover { |
| | | background: linear-gradient(180deg, rgba(51, 140, 255, 1) 0%, rgba(0, 184, 237, 1) 100%); |
| | | box-shadow: 0 0 15px rgba(0, 212, 255, 0.4); |
| | | transform: translateY(-1px); |
| | | } |
| | | |
| | | /* æé®å¾®å
ææ */ |
| | | .warn-range::before { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 0; |
| | | left: -100%; |
| | | width: 100%; |
| | | height: 100%; |
| | | background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); |
| | | transition: left 0.5s; |
| | | } |
| | | |
| | | .warn-range:hover::before { |
| | | left: 100%; |
| | | } |
| | | |
| | | .main-panel { |
| | |
| | | padding: 18px; |
| | | width: 100%; |
| | | height: 436px; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* å¾è¡¨é¢æ¿è§è½è£
饰 */ |
| | | .panel-item-customers::before, |
| | | .panel-item-customers::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .panel-item-customers::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .panel-item-customers::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | |
| | | /* å¾è¡¨åºé¨å
线 */ |
| | | .panel-item-customers::before { |
| | | content: ''; |
| | | position: absolute; |
| | | bottom: 0; |
| | | left: 10%; |
| | | right: 10%; |
| | | height: 2px; |
| | | background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.4), transparent); |
| | | animation: bottomGlow 3s ease-in-out infinite; |
| | | z-index: 1; |
| | | } |
| | | |
| | | @keyframes bottomGlow { |
| | | 0%, 100% { opacity: 0.3; } |
| | | 50% { opacity: 0.7; } |
| | | } |
| | | |
| | | /* 深度å¾èæ¯å
æ */ |
| | | .panel-item-customers > div { |
| | | position: relative; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .panel-item-customers::after { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 50%; |
| | | left: 50%; |
| | | transform: translate(-50%, -50%); |
| | | width: 80%; |
| | | height: 80%; |
| | | background: radial-gradient(ellipse, rgba(78, 228, 255, 0.05) 0%, transparent 70%); |
| | | pointer-events: none; |
| | | animation: chartGlow 4s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes chartGlow { |
| | | 0%, 100% { opacity: 0.5; transform: translate(-50%, -50%) scale(1); } |
| | | 50% { opacity: 0.8; transform: translate(-50%, -50%) scale(1.02); } |
| | | } |
| | | </style> |
| | |
| | | gap: 12px; |
| | | height: 100%; |
| | | box-sizing: border-box; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* é¢è¦é¢æ¿è§è½è£
饰 */ |
| | | .warn-panel::before, |
| | | .warn-panel::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(255, 77, 79, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .warn-panel::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .warn-panel::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | |
| | | /* é¢è¦èå²èæ¯ */ |
| | | .warn-panel::after { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: radial-gradient(circle at 50% 50%, rgba(255, 77, 79, 0.05) 0%, transparent 70%); |
| | | pointer-events: none; |
| | | animation: warnPulse 4s ease-in-out infinite; |
| | | z-index: 0; |
| | | } |
| | | |
| | | @keyframes warnPulse { |
| | | 0%, 100% { opacity: 0.3; } |
| | | 50% { opacity: 0.6; } |
| | | } |
| | | |
| | | .warn-header { |
| | |
| | | #007eff 78%, |
| | | #007eff 100%) 1; |
| | | padding: 10px 0 6px; |
| | | position: relative; |
| | | z-index: 1; |
| | | } |
| | | |
| | | .warn-header-left { |
| | |
| | | background: linear-gradient(180deg, #2aa8ff 0%, #4ee4ff 100%); |
| | | clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); |
| | | box-shadow: 0 0 12px rgba(78, 228, 255, 0.25); |
| | | animation: badgePulse 2s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes badgePulse { |
| | | 0%, 100% { transform: scale(1); box-shadow: 0 0 12px rgba(78, 228, 255, 0.25); } |
| | | 50% { transform: scale(1.1); box-shadow: 0 0 20px rgba(78, 228, 255, 0.5); } |
| | | } |
| | | |
| | | .warn-title { |
| | |
| | | -webkit-text-fill-color: transparent; |
| | | background-clip: text; |
| | | line-height: 24px; |
| | | animation: titleGlow 3s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes titleGlow { |
| | | 0%, 100% { filter: brightness(1); } |
| | | 50% { filter: brightness(1.2); } |
| | | } |
| | | |
| | | .warn-range { |
| | |
| | | background: linear-gradient(180deg, rgba(51, 120, 255, 1) 0%, rgba(0, 164, 237, 1) 100%); |
| | | border: 1px solid rgba(78, 228, 255, 0.25); |
| | | cursor: pointer; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .warn-range:hover { |
| | | background: linear-gradient(180deg, rgba(51, 140, 255, 1) 0%, rgba(0, 184, 237, 1) 100%); |
| | | box-shadow: 0 0 15px rgba(0, 212, 255, 0.4); |
| | | transform: translateY(-1px); |
| | | } |
| | | |
| | | .warn-body { |
| | |
| | | gap: 18px; |
| | | align-items: stretch; |
| | | min-height: 260px; |
| | | position: relative; |
| | | z-index: 1; |
| | | } |
| | | |
| | | .warn-list { |
| | |
| | | line-height: 1.2; |
| | | padding: 8px 0; |
| | | border-radius: 4px; |
| | | transition: background-color 0.2s, color 0.2s; |
| | | transition: all 0.3s ease; |
| | | position: relative; |
| | | animation: itemFadeIn 0.5s ease-out both; |
| | | } |
| | | |
| | | @keyframes itemFadeIn { |
| | | from { |
| | | opacity: 0; |
| | | transform: translateX(20px); |
| | | } |
| | | to { |
| | | opacity: 1; |
| | | transform: translateX(0); |
| | | } |
| | | } |
| | | |
| | | .warn-item::before { |
| | | content: ''; |
| | | position: absolute; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | height: 1px; |
| | | background: linear-gradient(90deg, transparent, rgba(255, 77, 79, 0.2), transparent); |
| | | opacity: 0; |
| | | transition: opacity 0.3s; |
| | | } |
| | | |
| | | .warn-item:hover { |
| | | color: #ff4d4f; |
| | | background-color: rgba(255, 77, 79, 0.06); |
| | | background-color: rgba(255, 77, 79, 0.08); |
| | | } |
| | | |
| | | .warn-item:hover::before { |
| | | opacity: 1; |
| | | } |
| | | |
| | | .warn-item:hover .warn-text { |
| | |
| | | justify-content: center; |
| | | font-weight: 700; |
| | | color: #ffffff; |
| | | transition: all 0.3s ease; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* æ ç¾åå
ææ */ |
| | | .warn-tag::after { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 0; |
| | | left: -100%; |
| | | width: 100%; |
| | | height: 100%; |
| | | background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); |
| | | animation: tagShine 3s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes tagShine { |
| | | 0% { left: -100%; } |
| | | 50%, 100% { left: 100%; } |
| | | } |
| | | |
| | | .warn-item:hover .warn-tag { |
| | | transform: scale(1.02); |
| | | box-shadow: 0 0 15px currentColor; |
| | | } |
| | | |
| | | .tag-raw { |
| | |
| | | font-weight: 700; |
| | | white-space: nowrap; |
| | | cursor: pointer; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .warn-item:hover .warn-action { |
| | | text-shadow: 0 0 10px rgba(255, 77, 79, 0.5); |
| | | } |
| | | |
| | | .warn-date { |
| | |
| | | mask: radial-gradient(circle, transparent 62%, #000 63%); |
| | | opacity: 0.5; |
| | | pointer-events: none; |
| | | animation: ringRotate 20s linear infinite; |
| | | } |
| | | |
| | | @keyframes ringRotate { |
| | | from { transform: rotate(0deg); } |
| | | to { transform: rotate(360deg); } |
| | | } |
| | | |
| | | /* ååè¾
å©çº¿ */ |
| | |
| | | background-repeat: no-repeat; |
| | | opacity: 0.35; |
| | | pointer-events: none; |
| | | animation: crossPulse 3s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes crossPulse { |
| | | 0%, 100% { opacity: 0.35; } |
| | | 50% { opacity: 0.5; } |
| | | } |
| | | </style> |
| | |
| | | <div> |
| | | <!-- é¡¶é¨ç»è®¡å¡ç --> |
| | | <div class="stats-cards"> |
| | | <div v-for="item in statItems" :key="item.name" class="stat-card"> |
| | | <img src="@/assets/BI/icon@2x.png" alt="徿 " class="card-icon" /> |
| | | <div v-for="(item, index) in statItems" :key="item.name" class="stat-card" :style="{ animationDelay: `${index * 0.15}s` }"> |
| | | <div class="card-icon-wrapper"> |
| | | <img src="@/assets/BI/icon@2x.png" alt="徿 " class="card-icon" /> |
| | | <div class="icon-ring"></div> |
| | | </div> |
| | | <div class="card-content"> |
| | | <span class="card-label">{{ item.name }}</span> |
| | | <span class="card-value">{{ item.value }}</span> |
| | | <span class="card-value"> |
| | | <span class="value-number">{{ item.value }}</span> |
| | | </span> |
| | | <div class="card-compare" :class="compareClass(Number(item.rate))"> |
| | | <span>忝</span> |
| | | <el-tooltip content="仿¥åæ¥æ£éªæ°ç¸å¯¹æ¨æ¥åæ¥æ£éªæ°çå¢é¿ç" placement="top"> |
| | | <span>{{ item.name === 'æ»æ£éªæ°' ? 'æ¥ç¯æ¯' : '忝' }}</span> |
| | | </el-tooltip> |
| | | <span class="compare-value">{{ formatPercent(item.rate) }}</span> |
| | | <span class="compare-icon">{{ Number(item.rate) >= 0 ? 'â' : 'â' }}</span> |
| | | </div> |
| | | </div> |
| | | <!-- å¡çåºé¨å
线 --> |
| | | <div class="card-glow"></div> |
| | | </div> |
| | | </div> |
| | | |
| | |
| | | <style scoped> |
| | | .stats-cards { |
| | | display: flex; |
| | | gap: 30px; |
| | | gap: 20px; |
| | | width: 100%; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .stat-card { |
| | | flex: 1; |
| | | min-width: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | background-image: url('@/assets/BI/border@2x.png'); |
| | |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | height: 142px; |
| | | padding-right: 10px; |
| | | box-sizing: border-box; |
| | | position: relative; |
| | | overflow: hidden; |
| | | animation: cardFadeIn 0.6s ease-out both; |
| | | } |
| | | |
| | | @keyframes cardFadeIn { |
| | | from { |
| | | opacity: 0; |
| | | transform: translateY(20px); |
| | | } |
| | | to { |
| | | opacity: 1; |
| | | transform: translateY(0); |
| | | } |
| | | } |
| | | |
| | | /* å¡çåºé¨åå
ææ */ |
| | | .card-glow { |
| | | position: absolute; |
| | | bottom: 0; |
| | | left: 10%; |
| | | right: 10%; |
| | | height: 2px; |
| | | background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.6), transparent); |
| | | animation: glowPulse 3s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes glowPulse { |
| | | 0%, 100% { opacity: 0.3; } |
| | | 50% { opacity: 0.8; } |
| | | } |
| | | |
| | | .card-icon-wrapper { |
| | | position: relative; |
| | | width: 70px; |
| | | height: 70px; |
| | | min-width: 70px; |
| | | margin: 0 12px 0 8px; |
| | | } |
| | | |
| | | .card-icon { |
| | | width: 100px; |
| | | height: 100px; |
| | | margin: 20px 20px 0 10px; |
| | | width: 70px; |
| | | height: 70px; |
| | | position: relative; |
| | | z-index: 2; |
| | | animation: iconFloat 3s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes iconFloat { |
| | | 0%, 100% { transform: translateY(0); } |
| | | 50% { transform: translateY(-3px); } |
| | | } |
| | | |
| | | /* 徿 å¤åå
ç¯ */ |
| | | .icon-ring { |
| | | position: absolute; |
| | | top: 50%; |
| | | left: 50%; |
| | | transform: translate(-50%, -50%); |
| | | width: 80px; |
| | | height: 80px; |
| | | border: 1px solid rgba(0, 212, 255, 0.3); |
| | | border-radius: 50%; |
| | | animation: ringRotate 8s linear infinite; |
| | | } |
| | | |
| | | @keyframes ringRotate { |
| | | from { transform: translate(-50%, -50%) rotate(0deg); } |
| | | to { transform: translate(-50%, -50%) rotate(360deg); } |
| | | } |
| | | |
| | | .card-content { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | gap: 6px; |
| | | min-width: 0; |
| | | flex: 1; |
| | | } |
| | | |
| | | .card-value { |
| | | font-weight: 500; |
| | | font-size: 40px; |
| | | font-size: 32px; |
| | | line-height: 1.2; |
| | | background: linear-gradient(360deg, #008bfd 0%, #ffffff 100%); |
| | | -webkit-background-clip: text; |
| | | -webkit-text-fill-color: transparent; |
| | | background-clip: text; |
| | | overflow: hidden; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .value-number { |
| | | display: inline-block; |
| | | animation: countUp 1s ease-out; |
| | | } |
| | | |
| | | @keyframes countUp { |
| | | from { |
| | | opacity: 0; |
| | | transform: translateY(10px); |
| | | } |
| | | to { |
| | | opacity: 1; |
| | | transform: translateY(0); |
| | | } |
| | | } |
| | | |
| | | .card-label { |
| | | font-weight: 400; |
| | | font-size: 16px; |
| | | font-size: 14px; |
| | | color: rgba(208, 231, 255, 0.7); |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .card-compare { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 6px; |
| | | font-size: 15px; |
| | | gap: 4px; |
| | | font-size: 13px; |
| | | color: #d0e7ff; |
| | | white-space: nowrap; |
| | | flex-wrap: nowrap; |
| | | } |
| | | |
| | | .card-compare>span:first-child { |
| | | font-size: 13px; |
| | | font-size: 12px; |
| | | opacity: 0.8; |
| | | } |
| | | |
| | |
| | | font-size: 14px; |
| | | position: relative; |
| | | top: -1px; |
| | | /* 轻微ä¸ç§»ï¼è®©ç®å¤´ä¸æååç´å±
ä¸å¯¹é½ */ |
| | | animation: arrowBounce 1s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes arrowBounce { |
| | | 0%, 100% { transform: translateY(0); } |
| | | 50% { transform: translateY(-2px); } |
| | | } |
| | | |
| | | .compare-up .compare-value, |
| | |
| | | { |
| | | key: 'raw', |
| | | title: 'åæææ£æµ', |
| | | dateType: 1, |
| | | dateType: 3, |
| | | qualifiedCount: 0, |
| | | unqualifiedCount: 0, |
| | | qualifiedRate: 0, |
| | |
| | | { |
| | | key: 'process', |
| | | title: 'è¿ç¨æ£æµ', |
| | | dateType: 1, |
| | | dateType: 3, |
| | | qualifiedCount: 0, |
| | | unqualifiedCount: 0, |
| | | qualifiedRate: 0, |
| | |
| | | { |
| | | key: 'final', |
| | | title: 'æååºåæ£æµ', |
| | | dateType: 1, |
| | | dateType: 3, |
| | | qualifiedCount: 0, |
| | | unqualifiedCount: 0, |
| | | qualifiedRate: 0, |
| | |
| | | .filters-row-left { |
| | | width: 50%; |
| | | color: white; |
| | | /* ç¨flexæ¿ä»£floatï¼è®©åå
ç´ å¯¹é½æ´ç¨³å® */ |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | span { |
| | | /* æ ¸å¿ï¼ç¶çº§ç¸å¯¹å®ä½ï¼ä½ä¸ºä¼ªå
ç´ åºå */ |
| | | position: relative; |
| | | display: inline-block; |
| | | /* ç»ä¼ªå
ç´ åæåçç©ºé´ */ |
| | | padding-left: 22px; |
| | | /* æååç´å±
ä¸ */ |
| | | line-height: 23px; |
| | | margin-right: 8px; |
| | | |
| | |
| | | top: 50%; |
| | | left: 0; |
| | | transform: translateY(-50%); |
| | | /* ç¡®ä¿è±å½¢å¨æ¸åå䏿¹ */ |
| | | z-index: 1; |
| | | animation: diamondPulse 2s ease-in-out infinite; |
| | | } |
| | | |
| | | &::before { |
| | |
| | | position: absolute; |
| | | top: 50%; |
| | | left: -1px; |
| | | /* ç²¾åè´´å¨è±å½¢æ£ä¸æ¹ */ |
| | | transform: translateY(calc(0% + 8px)); |
| | | z-index: 0; |
| | | } |
| | |
| | | p { |
| | | width: 100px; |
| | | height: 23px; |
| | | /* æ¸åèµ·å§è²åè±å½¢ç»ä¸ï¼æ´åè° */ |
| | | background: linear-gradient(90deg, #217AFF 0%, rgba(33, 221, 255, 0) 100%); |
| | | /* ç²¾ååç´å±
ä¸ */ |
| | | line-height: 26px; |
| | | text-align: center; |
| | | color: white; |
| | | /* ç¨é«åº¦çä¸åååè§ï¼ç¡®ä¿å·¦è¾¹æ¯å®ç¾åå */ |
| | | border-radius: 12px 0 0 12px; |
| | | /* å¯éï¼å ä¸ç¹å·¦å
è¾¹è·ï¼è®©æåä¸è´´è¾¹ */ |
| | | padding-left: 4px; |
| | | animation: titleShimmer 3s ease-in-out infinite; |
| | | } |
| | | } |
| | | } |
| | | |
| | | @keyframes diamondPulse { |
| | | 0%, 100% { opacity: 0.8; } |
| | | 50% { opacity: 1; box-shadow: 0 0 10px rgba(33, 133, 255, 0.5); } |
| | | } |
| | | |
| | | @keyframes titleShimmer { |
| | | 0%, 100% { opacity: 1; } |
| | | 50% { opacity: 0.85; } |
| | | } |
| | | |
| | | .panel-item-customers { |
| | |
| | | width: 100%; |
| | | height: 958px; |
| | | box-sizing: border-box; |
| | | position: relative; |
| | | } |
| | | |
| | | /* 颿¿è§è½è£
饰 */ |
| | | .panel-item-customers::before, |
| | | .panel-item-customers::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 20px; |
| | | height: 20px; |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .panel-item-customers::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .panel-item-customers::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | |
| | | .inspect-block { |
| | |
| | | padding: 8px 0; |
| | | gap: 6px; |
| | | position: relative; |
| | | animation: blockFadeIn 0.5s ease-out both; |
| | | animation-delay: calc(var(--index, 0) * 0.1s); |
| | | } |
| | | |
| | | @keyframes blockFadeIn { |
| | | from { |
| | | opacity: 0; |
| | | transform: translateX(-20px); |
| | | } |
| | | to { |
| | | opacity: 1; |
| | | transform: translateX(0); |
| | | } |
| | | } |
| | | |
| | | .inspect-block:nth-child(1) { --index: 0; } |
| | | .inspect-block:nth-child(2) { --index: 1; } |
| | | .inspect-block:nth-child(3) { --index: 2; } |
| | | |
| | | .inspect-block:not(:last-child)::after { |
| | | content: ''; |
| | |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | animation: ringFloat 4s ease-in-out infinite; |
| | | } |
| | | |
| | | /* å¤åå»åº¦ï¼ç¹ç¶ç¯ï¼ */ |
| | | @keyframes ringFloat { |
| | | 0%, 100% { transform: translateY(0); } |
| | | 50% { transform: translateY(-3px); } |
| | | } |
| | | |
| | | /* å¤åå»åº¦ï¼ç¹ç¶ç¯ï¼- æè½¬å¨ç» */ |
| | | .ring::before { |
| | | content: ''; |
| | | position: absolute; |
| | |
| | | mask: radial-gradient(circle, transparent 62%, #000 63%); |
| | | opacity: 0.35; |
| | | pointer-events: none; |
| | | animation: ringRotate 30s linear infinite; |
| | | } |
| | | |
| | | /* æååå
èæ¯ */ |
| | | @keyframes ringRotate { |
| | | from { transform: rotate(0deg); } |
| | | to { transform: rotate(360deg); } |
| | | } |
| | | |
| | | /* æååå
èæ¯ - èå²å¨ç» */ |
| | | .ring::after { |
| | | content: ''; |
| | | position: absolute; |
| | |
| | | background: radial-gradient(circle, rgba(78, 228, 255, 0.18) 0%, rgba(78, 228, 255, 0.06) 40%, rgba(0, 0, 0, 0) 70%); |
| | | filter: blur(0.2px); |
| | | pointer-events: none; |
| | | animation: ringGlow 3s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes ringGlow { |
| | | 0%, 100% { opacity: 0.8; transform: scale(1); } |
| | | 50% { opacity: 1; transform: scale(1.02); } |
| | | } |
| | | |
| | | .stats { |
| | |
| | | border: 1px solid rgba(78, 228, 255, 0.22); |
| | | background: linear-gradient(90deg, rgba(33, 122, 255, 0.28) 0%, rgba(10, 28, 58, 0.35) 55%, rgba(10, 28, 58, 0.2) 100%); |
| | | box-shadow: inset 0 0 18px rgba(16, 45, 95, 0.25); |
| | | transition: all 0.3s ease; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* ç»è®¡è¡æ¬åææ */ |
| | | .stat-row:hover { |
| | | border-color: rgba(0, 212, 255, 0.4); |
| | | box-shadow: inset 0 0 18px rgba(16, 45, 95, 0.25), 0 0 15px rgba(0, 212, 255, 0.15); |
| | | } |
| | | |
| | | /* ç»è®¡è¡åºé¨å
线 */ |
| | | .stat-row::after { |
| | | content: ''; |
| | | position: absolute; |
| | | bottom: 0; |
| | | left: 0; |
| | | right: 0; |
| | | height: 1px; |
| | | background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.4), transparent); |
| | | opacity: 0; |
| | | transition: opacity 0.3s; |
| | | } |
| | | |
| | | .stat-row:hover::after { |
| | | opacity: 1; |
| | | } |
| | | |
| | | .stat-left { |
| | |
| | | border-radius: 2px; |
| | | display: inline-block; |
| | | box-shadow: 0 0 10px rgba(78, 228, 255, 0.25); |
| | | animation: dotPulse 2s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes dotPulse { |
| | | 0%, 100% { box-shadow: 0 0 10px rgba(78, 228, 255, 0.25); } |
| | | 50% { box-shadow: 0 0 15px rgba(78, 228, 255, 0.5); } |
| | | } |
| | | |
| | | .dot-qualified { |
| | |
| | | min-width: 40px; |
| | | text-align: right; |
| | | text-shadow: 0 0 10px rgba(78, 228, 255, 0.15); |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .stat-row:hover .stat-value { |
| | | text-shadow: 0 0 15px rgba(78, 228, 255, 0.4); |
| | | transform: scale(1.05); |
| | | } |
| | | |
| | | .stat-percent { |
| | |
| | | padding: 18px; |
| | | width: 100%; |
| | | height: 449px; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* 颿¿è§è½è£
饰 */ |
| | | .panel-item-customers::before, |
| | | .panel-item-customers::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | z-index: 3; |
| | | } |
| | | |
| | | .panel-item-customers::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .panel-item-customers::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | |
| | | /* 颿¿åå
èæ¯ */ |
| | | .panel-item-customers > div:first-child::before { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 50%; |
| | | left: 50%; |
| | | transform: translate(-50%, -50%); |
| | | width: 200px; |
| | | height: 200px; |
| | | background: radial-gradient(circle, rgba(78, 228, 255, 0.08) 0%, transparent 70%); |
| | | pointer-events: none; |
| | | animation: pieGlow 4s ease-in-out infinite; |
| | | z-index: 0; |
| | | } |
| | | |
| | | @keyframes pieGlow { |
| | | 0%, 100% { opacity: 0.5; transform: translate(-50%, -50%) scale(1); } |
| | | 50% { opacity: 0.8; transform: translate(-50%, -50%) scale(1.1); } |
| | | } |
| | | |
| | | .pie-chart-wrapper { |
| | | position: relative; |
| | | width: 100%; |
| | | height: 320px; |
| | | animation: pieFloat 4s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes pieFloat { |
| | | 0%, 100% { transform: translateY(0); } |
| | | 50% { transform: translateY(-3px); } |
| | | } |
| | | |
| | | .pie-background { |
| | |
| | | left: 50%; |
| | | top: 50%; |
| | | transform: translate(-51.5%, -39%); |
| | | animation: pieBgRotate 30s linear infinite; |
| | | } |
| | | |
| | | @keyframes pieBgRotate { |
| | | from { transform: translate(-51.5%, -39%) rotate(0deg); } |
| | | to { transform: translate(-51.5%, -39%) rotate(360deg); } |
| | | } |
| | | |
| | | /* å¾è¡¨åå
ææ */ |
| | | .land-chart { |
| | | position: relative; |
| | | z-index: 2; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div> |
| | | <PanelHeader title="ä¸åæ ¼äº§åæå" /> |
| | | <PanelHeader title="ä¸åæ ¼äº§åæå"> |
| | | <template #extra> |
| | | <span class="range-tip">(è¿ 30 天)</span> |
| | | </template> |
| | | </PanelHeader> |
| | | <div class="main-panel panel-item-customers"> |
| | | <div class="main-panel-container"> |
| | | <div style="color: white" class="main-panel-box" v-for="(item, index) in panelList" :key="index"> |
| | |
| | | flex-direction: row; |
| | | align-items: center; |
| | | height: 40px; |
| | | transition: all 0.3s ease; |
| | | position: relative; |
| | | animation: rankItemFadeIn 0.5s ease-out both; |
| | | } |
| | | |
| | | .main-panel-box-left { |
| | | background: red; |
| | | border-radius: 20px; |
| | | text-align: center; |
| | | line-height: 32px; |
| | | margin: 0 20px; |
| | | @keyframes rankItemFadeIn { |
| | | from { |
| | | opacity: 0; |
| | | transform: translateX(20px); |
| | | } |
| | | to { |
| | | opacity: 1; |
| | | transform: translateX(0); |
| | | } |
| | | } |
| | | |
| | | .main-panel-box:hover { |
| | | transform: translateX(5px); |
| | | } |
| | | |
| | | /* æå项åºé¨å
线 */ |
| | | .main-panel-box::after { |
| | | content: ''; |
| | | position: absolute; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | height: 1px; |
| | | background: linear-gradient(90deg, transparent, rgba(255, 77, 79, 0.3), transparent); |
| | | opacity: 0; |
| | | transition: opacity 0.3s; |
| | | } |
| | | |
| | | .main-panel-box:hover::after { |
| | | opacity: 1; |
| | | } |
| | | |
| | | .main-panel-box-left { |
| | | background: linear-gradient(135deg, #ff4d4f 0%, #ff7875 100%); |
| | | border-radius: 20px; |
| | | text-align: center; |
| | | line-height: 32px; |
| | | margin: 0 20px; |
| | | padding: 0 12px; |
| | | font-weight: 600; |
| | | font-size: 12px; |
| | | color: white; |
| | | min-width: 60px; |
| | | transition: all 0.3s ease; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* æåæ ç¾åå
*/ |
| | | .main-panel-box-left::before { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 0; |
| | | left: -100%; |
| | | width: 100%; |
| | | height: 100%; |
| | | background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); |
| | | animation: rankShine 2s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes rankShine { |
| | | 0% { left: -100%; } |
| | | 50%, 100% { left: 100%; } |
| | | } |
| | | |
| | | .main-panel-box:hover .main-panel-box-left { |
| | | box-shadow: 0 0 15px rgba(255, 77, 79, 0.5); |
| | | } |
| | | |
| | | .main-panel-box-right { |
| | | display: flex; |
| | | flex-direction: column; |
| | | flex: 1; |
| | | |
| | | .main-panel-box-right-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #ffffff; |
| | | margin-bottom: 6px; |
| | | } |
| | | |
| | | .main-panel-box-right { |
| | | .main-panel-box-right-text { |
| | | font-size: 12px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | flex: 1; |
| | | justify-content: space-between; |
| | | padding-right: 60px; |
| | | margin-bottom: 4px; |
| | | color: rgba(184, 200, 224, 0.8); |
| | | transition: color 0.3s; |
| | | } |
| | | |
| | | .main-panel-box-right-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #ffffff; |
| | | margin-bottom: 6px; |
| | | .main-panel-box:hover .main-panel-box-right-text { |
| | | color: rgba(184, 200, 224, 1); |
| | | } |
| | | |
| | | .main-panel-box-right-progress { |
| | | :deep(.el-progress__text) { |
| | | color: white !important; |
| | | } |
| | | |
| | | .main-panel-box-right-text { |
| | | font-size: 12px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | padding-right: 60px; |
| | | margin-bottom: 4px; |
| | | :deep(.el-progress-bar__outer) { |
| | | background-color: rgba(78, 228, 255, 0.15); |
| | | } |
| | | |
| | | .main-panel-box-right-progress { |
| | | :deep(.el-progress__text) { |
| | | color: white !important; |
| | | } |
| | | :deep(.el-progress-bar__inner) { |
| | | transition: width 0.8s ease; |
| | | } |
| | | } |
| | | } |
| | |
| | | width: 100%; |
| | | height: 449px; |
| | | overflow: hidden; |
| | | position: relative; |
| | | } |
| | | |
| | | /* 颿¿è§è½è£
饰 */ |
| | | .panel-item-customers::before, |
| | | .panel-item-customers::after { |
| | | content: ''; |
| | | position: absolute; |
| | | width: 15px; |
| | | height: 15px; |
| | | border-color: rgba(255, 77, 79, 0.5); |
| | | border-style: solid; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .panel-item-customers::before { |
| | | top: -1px; |
| | | left: -1px; |
| | | border-width: 2px 0 0 2px; |
| | | } |
| | | |
| | | .panel-item-customers::after { |
| | | bottom: -1px; |
| | | right: -1px; |
| | | border-width: 0 2px 2px 0; |
| | | } |
| | | |
| | | /* 颿¿èæ¯èå² */ |
| | | .panel-item-customers::before { |
| | | content: ''; |
| | | position: absolute; |
| | | inset: 0; |
| | | background: radial-gradient(circle at 50% 50%, rgba(255, 77, 79, 0.03) 0%, transparent 70%); |
| | | pointer-events: none; |
| | | animation: panelPulse 5s ease-in-out infinite; |
| | | z-index: 0; |
| | | } |
| | | |
| | | @keyframes panelPulse { |
| | | 0%, 100% { opacity: 0.3; } |
| | | 50% { opacity: 0.5; } |
| | | } |
| | | |
| | | .range-tip { |
| | | font-size: 14px; |
| | | color: rgba(184, 200, 224, 0.75); |
| | | animation: tipFade 2s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes tipFade { |
| | | 0%, 100% { opacity: 0.75; } |
| | | 50% { opacity: 1; } |
| | | } |
| | | </style> |
| | |
| | | <style scoped> |
| | | /* å¤é¨ç¼©æ¾å®¹å¨ - å æ®æ´ä¸ªè§å£ */ |
| | | .scale-container { |
| | | position: relative; |
| | | width: 100%; |
| | | /* 页é¢å¨å¸¸è§å¸å±ä¸ï¼æé¡¶æ ï¼é»è®¤åå» 84pxï¼é¿å
å
容被è£å */ |
| | | height: calc(100vh - 84px); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background-color: #000; |
| | | overflow: hidden; |
| | | position: relative; |
| | | width: 100%; |
| | | /* 页é¢å¨å¸¸è§å¸å±ä¸ï¼æé¡¶æ ï¼é»è®¤åå» 84pxï¼é¿å
å
容被è£å */ |
| | | height: calc(100vh - 84px); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background-color: #000; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* å¨æç½æ ¼èæ¯ */ |
| | | .scale-container::before { |
| | | content: ''; |
| | | position: absolute; |
| | | inset: 0; |
| | | background-image: |
| | | linear-gradient(rgba(0, 150, 255, 0.03) 1px, transparent 1px), |
| | | linear-gradient(90deg, rgba(0, 150, 255, 0.03) 1px, transparent 1px); |
| | | background-size: 50px 50px; |
| | | animation: gridMove 20s linear infinite; |
| | | pointer-events: none; |
| | | z-index: 0; |
| | | } |
| | | |
| | | @keyframes gridMove { |
| | | 0% { transform: translate(0, 0); } |
| | | 100% { transform: translate(50px, 50px); } |
| | | } |
| | | |
| | | /* æ«æçº¿ææ */ |
| | | .scale-container::after { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | height: 2px; |
| | | background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.8), transparent); |
| | | animation: scanLine 4s ease-in-out infinite; |
| | | pointer-events: none; |
| | | z-index: 1; |
| | | } |
| | | |
| | | @keyframes scanLine { |
| | | 0%, 100% { top: 0; opacity: 0; } |
| | | 10% { opacity: 1; } |
| | | 90% { opacity: 1; } |
| | | 100% { top: 100%; opacity: 0; } |
| | | } |
| | | |
| | | /* å
é¨å
容åºå - åºå®è®¾è®¡å°ºå¯¸ */ |
| | | .data-dashboard { |
| | | position: relative; |
| | | width: 1920px; |
| | | height: 1080px; |
| | | background-image: url("@/assets/BI/backImage@2x.png"); |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | transform-origin: center center; |
| | | position: relative; |
| | | width: 1920px; |
| | | height: 1080px; |
| | | background-image: url("@/assets/BI/backImage@2x.png"); |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | transform-origin: center center; |
| | | z-index: 2; |
| | | } |
| | | |
| | | /* å
¨å±ç¶æçæ ·å¼ - ä½ç¨äºscale-container */ |
| | | .scale-container:fullscreen { |
| | | width: 100vw; |
| | | height: 100vh; |
| | | margin: 0; |
| | | padding: 0; |
| | | background-color: #000; |
| | | z-index: 9999; |
| | | width: 100vw; |
| | | height: 100vh; |
| | | margin: 0; |
| | | padding: 0; |
| | | background-color: #000; |
| | | z-index: 9999; |
| | | } |
| | | |
| | | /* Webkitæµè§å¨åç¼ */ |
| | | .scale-container:-webkit-full-screen { |
| | | width: 100vw; |
| | | height: 100vh; |
| | | margin: 0; |
| | | padding: 0; |
| | | background-color: #000; |
| | | z-index: 9999; |
| | | width: 100vw; |
| | | height: 100vh; |
| | | margin: 0; |
| | | padding: 0; |
| | | background-color: #000; |
| | | z-index: 9999; |
| | | } |
| | | |
| | | /* MSæµè§å¨åç¼ */ |
| | | .scale-container:-ms-fullscreen { |
| | | width: 100vw; |
| | | height: 100vh; |
| | | margin: 0; |
| | | padding: 0; |
| | | background-color: #000; |
| | | z-index: 9999; |
| | | width: 100vw; |
| | | height: 100vh; |
| | | margin: 0; |
| | | padding: 0; |
| | | background-color: #000; |
| | | z-index: 9999; |
| | | } |
| | | |
| | | |
| | | .dashboard-header { |
| | | position: relative; |
| | | z-index: 1; |
| | | height: 86px; |
| | | background-image: url("@/assets/BI/biaoti.png"); |
| | | background-size: cover; |
| | | background-repeat: no-repeat; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | position: relative; |
| | | z-index: 1; |
| | | height: 86px; |
| | | background-image: url("@/assets/BI/biaoti.png"); |
| | | background-size: cover; |
| | | background-repeat: no-repeat; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | /* æ é¢è£
饰å
æ */ |
| | | .dashboard-header::before { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 50%; |
| | | left: 50%; |
| | | transform: translate(-50%, -50%); |
| | | width: 400px; |
| | | height: 2px; |
| | | background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.6), transparent); |
| | | animation: titleGlow 3s ease-in-out infinite; |
| | | } |
| | | |
| | | @keyframes titleGlow { |
| | | 0%, 100% { width: 400px; opacity: 0.6; } |
| | | 50% { width: 600px; opacity: 1; } |
| | | } |
| | | |
| | | .factory-name { |
| | | font-weight: 600; |
| | | font-size: 52px; |
| | | color: #FFFFFF; |
| | | top: 16px; |
| | | position: absolute; |
| | | font-weight: 600; |
| | | font-size: 52px; |
| | | color: #FFFFFF; |
| | | top: 16px; |
| | | position: absolute; |
| | | text-shadow: 0 0 20px rgba(0, 212, 255, 0.5), 0 0 40px rgba(0, 150, 255, 0.3); |
| | | animation: titleFloat 4s ease-in-out infinite; |
| | | letter-spacing: 8px; |
| | | } |
| | | |
| | | @keyframes titleFloat { |
| | | 0%, 100% { transform: translateY(0); } |
| | | 50% { transform: translateY(-3px); } |
| | | } |
| | | |
| | | .fullscreen-btn { |
| | | position: absolute; |
| | | top: 10px; |
| | | left: 20px; |
| | | width: 40px; |
| | | height: 40px; |
| | | background: rgba(0, 20, 60, 0.8); |
| | | border: 1px solid rgba(0, 212, 255, 0.3); |
| | | border-radius: 6px; |
| | | color: #00d4ff; |
| | | cursor: pointer; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | transition: all 0.3s; |
| | | z-index: 10000; |
| | | position: absolute; |
| | | top: 10px; |
| | | left: 20px; |
| | | width: 40px; |
| | | height: 40px; |
| | | background: rgba(0, 20, 60, 0.8); |
| | | border: 1px solid rgba(0, 212, 255, 0.3); |
| | | border-radius: 6px; |
| | | color: #00d4ff; |
| | | cursor: pointer; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | transition: all 0.3s; |
| | | z-index: 10000; |
| | | } |
| | | |
| | | .fullscreen-btn:hover { |
| | | background: rgba(0, 30, 90, 0.9); |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | background: rgba(0, 30, 90, 0.9); |
| | | border-color: rgba(0, 212, 255, 0.5); |
| | | box-shadow: 0 0 15px rgba(0, 212, 255, 0.4); |
| | | } |
| | | |
| | | .dashboard-content { |
| | | position: relative; |
| | | z-index: 1; |
| | | display: flex; |
| | | gap: 30px; |
| | | padding: 0 30px; |
| | | height: calc(100% - 86px); |
| | | overflow: hidden; |
| | | position: relative; |
| | | z-index: 1; |
| | | display: flex; |
| | | gap: 30px; |
| | | padding: 0 30px; |
| | | height: calc(100% - 86px); |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* ç¡®ä¿å颿¿è½å¤æ£ç¡®æ¾ç¤º */ |
| | | .left-panel, .center-panel, .right-panel { |
| | | overflow: hidden; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .left-panel, |
| | | .right-panel { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 24px; |
| | | width: 520px; |
| | | /* 颿¿å
¥åºå¨ç» */ |
| | | .left-panel { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 24px; |
| | | width: 520px; |
| | | animation: slideInLeft 0.8s ease-out; |
| | | } |
| | | |
| | | .center-panel { |
| | | flex: 1.5; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 20px; |
| | | flex: 1.5; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 20px; |
| | | animation: slideInUp 0.8s ease-out 0.2s both; |
| | | } |
| | | |
| | | .right-panel { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 24px; |
| | | width: 520px; |
| | | animation: slideInRight 0.8s ease-out; |
| | | } |
| | | |
| | | @keyframes slideInLeft { |
| | | from { |
| | | opacity: 0; |
| | | transform: translateX(-50px); |
| | | } |
| | | to { |
| | | opacity: 1; |
| | | transform: translateX(0); |
| | | } |
| | | } |
| | | |
| | | @keyframes slideInRight { |
| | | from { |
| | | opacity: 0; |
| | | transform: translateX(50px); |
| | | } |
| | | to { |
| | | opacity: 1; |
| | | transform: translateX(0); |
| | | } |
| | | } |
| | | |
| | | @keyframes slideInUp { |
| | | from { |
| | | opacity: 0; |
| | | transform: translateY(30px); |
| | | } |
| | | to { |
| | | opacity: 1; |
| | | transform: translateY(0); |
| | | } |
| | | } |
| | | |
| | | /* 颿¿éç¨åå
è¾¹æ¡ææ - éè¿åç»ä»¶çpanel-item-customersç±»çæ */ |
| | | :deep(.panel-item-customers) { |
| | | position: relative; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | :deep(.panel-item-customers::before) { |
| | | content: ''; |
| | | position: absolute; |
| | | inset: -1px; |
| | | border-radius: 0; |
| | | background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.3), transparent); |
| | | opacity: 0; |
| | | transition: opacity 0.3s; |
| | | pointer-events: none; |
| | | z-index: -1; |
| | | } |
| | | |
| | | :deep(.panel-item-customers:hover::before) { |
| | | opacity: 1; |
| | | animation: borderGlow 2s linear infinite; |
| | | } |
| | | |
| | | @keyframes borderGlow { |
| | | 0% { background-position: -200% 0; } |
| | | 100% { background-position: 200% 0; } |
| | | } |
| | | |
| | | /* ç»è®¡å¡çéªçææ */ |
| | | :deep(.stat-card) { |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | :deep(.stat-card:hover) { |
| | | transform: translateY(-2px); |
| | | box-shadow: 0 5px 20px rgba(0, 150, 255, 0.3); |
| | | } |
| | | |
| | | :deep(.stat-card:hover .card-value) { |
| | | animation: valuePulse 0.5s ease; |
| | | } |
| | | |
| | | @keyframes valuePulse { |
| | | 0%, 100% { transform: scale(1); } |
| | | 50% { transform: scale(1.05); } |
| | | } |
| | | |
| | | /* æ°æ®æµå¨ææèæ¯ */ |
| | | .dashboard-content::before { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 50%; |
| | | left: 0; |
| | | right: 0; |
| | | height: 1px; |
| | | background: linear-gradient(90deg, |
| | | transparent 0%, |
| | | rgba(0, 212, 255, 0.1) 20%, |
| | | rgba(0, 212, 255, 0.3) 50%, |
| | | rgba(0, 212, 255, 0.1) 80%, |
| | | transparent 100%); |
| | | animation: dataFlow 8s linear infinite; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | @keyframes dataFlow { |
| | | 0% { transform: translateX(-100%); } |
| | | 100% { transform: translateX(100%); } |
| | | } |
| | | </style> |