From adb79299e86660a7f205466cf1ea48c6b25b1398 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 18 六月 2026 13:14:37 +0800
Subject: [PATCH] 1.计量器具台账上传附件报错 2.质量拉的数据不对(未明确) 3.计量器具台账逾期的做标红提醒 4.设备保养定时任务和记录要加上具体的保养内容 5.质量要区分质检规则抽检还是全检,抽检的话是抽多少百分比 6.供应商管理东西太少了,没有资质文件啊这些东西(是不是可以参考pro) 7.采购审批把人从李莹莹改成龙红星
---
src/views/basicData/supplierManage/index.vue | 44
src/views/qualityManagement/rawMaterialInspection/components/inspectionFormDia.vue | 2
src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue | 40
src/views/qualityManagement/processInspection/components/quickCheckDia.vue | 150 ++
src/views/qualityManagement/rawMaterialInspection/components/quickCheckDia.vue | 150 ++
src/views/reportAnalysis/dataDashboard/index.vue | 52
src/views/reportAnalysis/qualityAnalysis/components/center-center.vue | 143 ++
src/views/qualityManagement/metricMaintenance/index0.vue | 6
src/views/qualityManagement/finalInspection/components/inspectionFormDia.vue | 2
src/views/qualityManagement/rawMaterialInspection/index.vue | 16
src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue | 28
src/views/qualityManagement/metricMaintenance/ParamFormDialog.vue | 4
src/views/qualityManagement/finalInspection/index.vue | 16
src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue | 28
src/views/reportAnalysis/PSIDataAnalysis/index.vue | 52
src/views/qualityManagement/processInspection/index.vue | 16
src/views/reportAnalysis/qualityAnalysis/components/PanelHeader.vue | 35
src/views/reportAnalysis/qualityAnalysis/components/right-top.vue | 186 ++
src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue | 26
src/views/reportAnalysis/qualityAnalysis/components/right-bottom.vue | 65
src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue | 26
src/views/qualityManagement/metricMaintenance/index.vue | 23
src/views/basicData/supplierManage/components/HomeTab.vue | 758 +++++++---
src/views/qualityManagement/processInspection/components/inspectionFormDia.vue | 2
src/views/qualityManagement/processInspection/components/formDia.vue | 38
src/views/reportAnalysis/qualityAnalysis/components/center-bottom.vue | 87 +
src/views/qualityManagement/finalInspection/components/quickCheckDia.vue | 154 ++
doc/quality_inspect_rule.md | 108 +
src/views/reportAnalysis/qualityAnalysis/components/left-top.vue | 130 +
src/views/qualityManagement/finalInspection/components/formDia.vue | 36
doc/20260618_home_quality_query_fix.md | 129 +
src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue | 38
src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue | 38
src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue | 28
src/views/reportAnalysis/qualityAnalysis/index.vue | 351 ++++-
src/views/equipmentManagement/measurementEquipment/index.vue | 35
src/views/qualityManagement/metricMaintenance/StandardFormDialog.vue | 9
src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue | 26
src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue | 55
src/views/qualityManagement/rawMaterialInspection/components/formDia.vue | 38
src/api/equipmentManagement/measuringInstrumentFile.js | 28
doc/20260618_quick_inspect_sample.md | 393 +++++
src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue | 32
src/views/reportAnalysis/qualityAnalysis/components/center-top.vue | 134 +
src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue | 138 ++
src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue | 38
46 files changed, 3,448 insertions(+), 485 deletions(-)
diff --git a/doc/20260618_home_quality_query_fix.md b/doc/20260618_home_quality_query_fix.md
new file mode 100644
index 0000000..1caa274
--- /dev/null
+++ b/doc/20260618_home_quality_query_fix.md
@@ -0,0 +1,129 @@
+# 棣栭〉璐ㄩ噺绫绘煡璇慨澶嶄笌浼樺寲鍓嶇鑱旇皟鏂囨。
+
+> 淇 `home` 妯″潡涓嬭川閲忕被鎺ュ彛鐨勮嫢骞查棶棰橈紝骞朵紭鍖栨煡璇㈡�ц兘銆�
+> 鏈鏀瑰姩**鍙秹鍙婂搷搴旀暟鍊�**锛�**鎺ュ彛璺緞銆佽姹傚弬鏁般�佸搷搴斿瓧娈靛悕鍧囨湭鍙樺寲**銆�
+
+## 娑夊強椤甸潰
+
+- 棣栭〉 / 鏁版嵁鐪嬫澘 - 璐ㄩ噺鍒嗘瀽妯″潡
+- 棣栭〉 / 鏁版嵁鐪嬫澘 - 璐ㄩ噺妫�楠屾暟閲忓崱鐗�
+- 棣栭〉 / 鏁版嵁鐪嬫澘 - 涓嶅悎鏍奸璀�
+- 棣栭〉 / 鏁版嵁鐪嬫澘 - 瀹屾垚妫�楠屾暟瓒嬪娍
+- 棣栭〉 / 鏁版嵁鐪嬫澘 - 涓嶅悎鏍间骇鍝佹帓鍚�
+- 棣栭〉 / 鏁版嵁鐪嬫澘 - 鍘熸潗鏂�/杩囩▼/鍑哄巶妫�娴嬪悎鏍肩巼
+- 棣栭〉 / 鏁版嵁鐪嬫澘 - 璐ㄩ噺缁熻 (鍛�/鏈�/瀛�)
+
+## 鍙楀奖鍝嶆帴鍙d竴瑙�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | /home/qualityInspectionCount | 璐ㄩ噺妫�楠屾暟閲� (璇箟鏈夊彉鏇�) |
+| GET | /home/nonComplianceWarning | 杩戜竷澶╀笉鍚堟牸棰勮 |
+| GET | /home/completedInspectionCount | 杩戜竷澶╁畬鎴愭楠屾暟 |
+| GET | /home/unqualifiedProductRanking | 涓嶅悎鏍间骇鍝佹帓鍚� (鍙e緞鍙樻洿) |
+| 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 鏄ㄦ棩鏂板"锛岄伩鍏嶈瑙d负绱鍚屾瘮銆�
+
+```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` (鍙e緞鍙樻洿锛屽墠绔渶鍏虫敞)
+
+### 鍙樻洿鍘熷洜
+
+鍘熷疄鐜版媺鍙栨墍鏈� `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 澶�)`锛�**鍝嶅簲瀛楁銆佸瓧娈佃涔変笉鍙�**锛屽彧鏄綋澶╂暟鎹笉鍐嶄涪澶便��
+
+### 鍓嶇淇敼鐐�
+
+鏃犻渶鏀瑰姩浠g爜銆備絾寤鸿鑱旇皟鏃舵牳瀵癸細鍛�/鏈�/瀛h鍥炬渶鍚庝竴澶╂槸鍚﹀嚭鐜颁互鍓嶇己澶辩殑妫�楠岃褰曘��
+
+## 鍥涖�佸叾浠栧唴閮ㄤ紭鍖� (鍓嶇鏃犳劅)
+
+- `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 鐨勬楠岃褰曟槸鍚﹁姝g‘缁熻 (鍛�/鏈堣鍥炬渶鍚庝竴澶�)銆�
+ - 浠婃棩鎵�鏈夋姤妫�鐨�"寰呭畬鎴� / 宸插畬鎴�"鏁版嵁鏄惁鑳藉疄鏃跺弽鏄犲埌棣栭〉鍗$墖銆�
+- 鑻ユ煇鎺ュ彛闇�瑕佷繚鐣欐棫鐨勫叏鍘嗗彶鍙e緞 (渚嬪瀵煎嚭銆佸璐�)锛岃鍗曠嫭鎻愰渶姹傚鍔犳柊鎺ュ彛锛岄伩鍏嶆敼鍥為椤垫帴鍙c��
diff --git a/doc/20260618_quick_inspect_sample.md b/doc/20260618_quick_inspect_sample.md
new file mode 100644
index 0000000..6fa0888
--- /dev/null
+++ b/doc/20260618_quick_inspect_sample.md
@@ -0,0 +1,393 @@
+# 璐ㄦ蹇�熸楠屾娊妫�鍔熻兘鍓嶇鑱旇皟鏂囨。
+
+> 鎵╁睍鎵归噺蹇�熸楠屾帴鍙o紝鏀寔鍏ㄦ鍜屾娊妫�涓ょ妫�楠屾ā寮忥紝鑷姩濉厖鎶芥鏁伴噺銆�
+
+## 娑夊強椤甸潰
+
+- 璐ㄩ噺绠$悊 / 妫�楠屽崟鍒楄〃 - 鎵归噺蹇�熸楠屽脊绐�
+- 璐ㄩ噺绠$悊 / 鍘熸潗鏂欐楠� / 杩囩▼妫�楠� / 鍑哄巶妫�楠� - 蹇�熸楠屾搷浣�
+
+## API
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | /qualityInspect/batchQuickInspect | 鎵归噺蹇�熸楠� (鎵╁睍鍙傛暟) |
+
+**璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| ids | List\<Long\> | 鏄� | 妫�楠屽崟ID鍒楄〃 |
+| checkResult | String | 鏄� | 妫�娴嬬粨鏋滐細鍚堟牸/涓嶅悎鏍�/閮ㄥ垎鍚堟牸 |
+| testStandardId | Long | 鏄� | 鎸囨爣鏍囧噯ID |
+| checkCompany | String | 鍚� | 妫�娴嬪崟浣� |
+| checkName | String | 鍚� | 妫�楠屽憳濮撳悕 |
+| checkTime | String | 鍚� | 妫�娴嬫棩鏈燂紝鏍煎紡锛歒YYY-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. 鏍¢獙锛氭娊妫�鏁伴噺涓嶈兘瓒呰繃鎬绘暟閲忥紝瓒呰繃鍒欒嚜鍔ㄤ慨姝d负鎬绘暟閲�
+
+### 鍚堟牸/涓嶅悎鏍兼暟閲�
+
+| 鍦烘櫙 | 澶勭悊閫昏緫 |
+|------|----------|
+| 鍓嶇浼犲叆浜� 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` 鎴栨寜姣斾緥璁$畻鐨勯粯璁ゅ�硷紝鍑忓皯鐢ㄦ埛杈撳叆璐熸媴銆�
\ No newline at end of file
diff --git a/doc/quality_inspect_rule.md b/doc/quality_inspect_rule.md
new file mode 100644
index 0000000..a321694
--- /dev/null
+++ b/doc/quality_inspect_rule.md
@@ -0,0 +1,108 @@
+# 璐ㄩ噺妫�楠岃鍒欙紙鍏ㄦ/鎶芥锛�
+
+## 娑夊強椤甸潰
+
+- 妫�娴嬫爣鍑嗙鐞嗛〉闈紙鏂板/缂栬緫寮圭獥銆佸垪琛級
+- 鍘熸潗鏂欐楠岄〉闈紙鍒楄〃銆佹柊澧�/缂栬緫寮圭獥锛�
+- 杩囩▼妫�楠岄〉闈紙鍒楄〃銆佹柊澧�/缂栬緫寮圭獥锛�
+- 鍑哄巶妫�楠岄〉闈紙鍒楄〃銆佹柊澧�/缂栬緫寮圭獥锛�
+
+## API
+
+### 妫�娴嬫爣鍑�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | /qualityTestStandard/add | 鏂板妫�娴嬫爣鍑嗭紙鏂板 inspectRule銆乻ampleRatio 瀛楁锛� |
+| POST | /qualityTestStandard/update | 淇敼妫�娴嬫爣鍑嗭紙鏂板 inspectRule銆乻ampleRatio 瀛楁锛� |
+| GET | /qualityTestStandard/listPage | 鍒楄〃鏌ヨ锛堣繑鍥炴柊澧炲瓧娈碉級 |
+
+**鏂板璇锋眰/鍝嶅簲鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| inspectRule | Integer | 鍚� | 妫�楠岃鍒�: 0=鍏ㄦ, 1=鎶芥锛岄粯璁�0 |
+| sampleRatio | BigDecimal | 鍚� | 鎶芥姣斾緥(鐧惧垎姣�)锛屼粎inspectRule=1鏃舵湁鏁堬紝濡�10琛ㄧず10% |
+
+### 璐ㄦ璁板綍锛堝師鏉愭枡/杩囩▼/鍑哄巶妫�楠岋級
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | /qualityInspect/add | 鏂板璐ㄦ璁板綍锛堟柊澧� inspectRule銆乻ampleRatio銆乻ampleQuantity 瀛楁锛� |
+| 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`锛堝悜涓婂彇鏁达級锛屾棤闇�鎵嬪姩濉啓
diff --git a/src/api/equipmentManagement/measuringInstrumentFile.js b/src/api/equipmentManagement/measuringInstrumentFile.js
new file mode 100644
index 0000000..6804cba
--- /dev/null
+++ b/src/api/equipmentManagement/measuringInstrumentFile.js
@@ -0,0 +1,28 @@
+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],
+ });
+}
\ No newline at end of file
diff --git a/src/views/basicData/supplierManage/components/HomeTab.vue b/src/views/basicData/supplierManage/components/HomeTab.vue
index b594c2f..da62ca4 100644
--- a/src/views/basicData/supplierManage/components/HomeTab.vue
+++ b/src/views/basicData/supplierManage/components/HomeTab.vue
@@ -1,63 +1,135 @@
<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>
@@ -65,12 +137,17 @@
<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>
@@ -78,14 +155,34 @@
<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>
@@ -97,231 +194,402 @@
</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>浠呭厑璁稿鍏ls銆亁lsx鏍煎紡鏂囦欢銆�</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>
+
diff --git a/src/views/basicData/supplierManage/index.vue b/src/views/basicData/supplierManage/index.vue
index d68600e..538c153 100644
--- a/src/views/basicData/supplierManage/index.vue
+++ b/src/views/basicData/supplierManage/index.vue
@@ -1,9 +1,43 @@
+<!-- 鍦ㄤ綘鐨勪富椤甸潰涓� -->
<template>
- <div>
- <HomeTab />
+ <div class="app-container">
+ <el-tabs v-model="activeTab" @tab-change="handleTabChange">
+ <el-tab-pane label="姝e父渚涘簲鍟�" 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>
\ No newline at end of file
diff --git a/src/views/equipmentManagement/measurementEquipment/index.vue b/src/views/equipmentManagement/measurementEquipment/index.vue
index 46ca100..20ea038 100644
--- a/src/views/equipmentManagement/measurementEquipment/index.vue
+++ b/src/views/equipmentManagement/measurementEquipment/index.vue
@@ -42,11 +42,18 @@
: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>
@@ -61,7 +68,8 @@
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()
@@ -178,7 +186,13 @@
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,
@@ -188,8 +202,9 @@
// 鎵撳紑闄勪欢寮规
const openFilesFormDia = (row) => {
- filesDia.value?.openDialog(row,'璁¢噺鍣ㄥ叿鍙拌处')
-};
+ currentRecordId.value = row.id
+ fileDialogVisible.value = true
+}
const dbRowClick = (row)=>{
rowClickData.value?.openDialog(row)
@@ -295,4 +310,14 @@
<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>
\ No newline at end of file
diff --git a/src/views/qualityManagement/finalInspection/components/formDia.vue b/src/views/qualityManagement/finalInspection/components/formDia.vue
index 9fcb6b1..5e640e8 100644
--- a/src/views/qualityManagement/finalInspection/components/formDia.vue
+++ b/src/views/qualityManagement/finalInspection/components/formDia.vue
@@ -119,6 +119,26 @@
</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>
@@ -214,6 +234,9 @@
checkResult: "",
salesLedgerId: "",
salesContractNo: "",
+ inspectRule: 0,
+ sampleRatio: undefined,
+ sampleQuantity: undefined,
},
rules: {
checkTime: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
@@ -250,7 +273,7 @@
prop: "unit",
},
{
- label: "鏍囧噯鍊�",
+ label: "鍘傚鏍囧噯鍊�",
prop: "standardValue",
},
{
@@ -422,6 +445,7 @@
if (productData) {
// 鍙嚜鍔ㄥ甫鍏ユ暟閲�
form.value.quantity = productData.quantity || 0;
+ calcSampleQuantity();
}
} catch (e) {
console.error('鏌ヨ閿�鍞鍗曚骇鍝佷俊鎭け璐�', e);
@@ -455,6 +479,16 @@
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) {
diff --git a/src/views/qualityManagement/finalInspection/components/inspectionFormDia.vue b/src/views/qualityManagement/finalInspection/components/inspectionFormDia.vue
index 411856c..e24e8d4 100644
--- a/src/views/qualityManagement/finalInspection/components/inspectionFormDia.vue
+++ b/src/views/qualityManagement/finalInspection/components/inspectionFormDia.vue
@@ -58,7 +58,7 @@
prop: "unit",
},
{
- label: "鏍囧噯鍊�",
+ label: "鍘傚鏍囧噯鍊�",
prop: "standardValue",
},
{
diff --git a/src/views/qualityManagement/finalInspection/components/quickCheckDia.vue b/src/views/qualityManagement/finalInspection/components/quickCheckDia.vue
index d4aef09..ba5f406 100644
--- a/src/views/qualityManagement/finalInspection/components/quickCheckDia.vue
+++ b/src/views/qualityManagement/finalInspection/components/quickCheckDia.vue
@@ -9,6 +9,14 @@
<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="鍚堟牸" />
@@ -17,6 +25,8 @@
</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">
@@ -29,12 +39,27 @@
</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">
@@ -46,12 +71,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>
@@ -101,7 +126,7 @@
</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";
@@ -115,12 +140,14 @@
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: '',
@@ -140,6 +167,59 @@
});
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: "鎸囨爣",
@@ -150,7 +230,7 @@
prop: "unit",
},
{
- label: "鏍囧噯鍊�",
+ label: "鍘傚鏍囧噯鍊�",
prop: "standardValue",
},
{
@@ -172,14 +252,22 @@
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 = {
@@ -191,20 +279,21 @@
} 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();
};
@@ -233,14 +322,16 @@
// 妫�娴嬬粨鏋滃彉鍖栧鐞�
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;
}
};
@@ -259,7 +350,7 @@
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 {
@@ -272,7 +363,7 @@
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 {
@@ -286,7 +377,7 @@
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) {
@@ -300,6 +391,15 @@
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,
@@ -327,4 +427,16 @@
</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>
diff --git a/src/views/qualityManagement/finalInspection/index.vue b/src/views/qualityManagement/finalInspection/index.vue
index 88ba755..5ee6e26 100644
--- a/src/views/qualityManagement/finalInspection/index.vue
+++ b/src/views/qualityManagement/finalInspection/index.vue
@@ -237,6 +237,22 @@
},
},
{
+ 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",
diff --git a/src/views/qualityManagement/metricMaintenance/ParamFormDialog.vue b/src/views/qualityManagement/metricMaintenance/ParamFormDialog.vue
index 4c958a0..dc9ca8b 100644
--- a/src/views/qualityManagement/metricMaintenance/ParamFormDialog.vue
+++ b/src/views/qualityManagement/metricMaintenance/ParamFormDialog.vue
@@ -20,8 +20,8 @@
<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="璇疯緭鍏ュ唴鎺у��" />
diff --git a/src/views/qualityManagement/metricMaintenance/StandardFormDialog.vue b/src/views/qualityManagement/metricMaintenance/StandardFormDialog.vue
index 381dac4..6b69740 100644
--- a/src/views/qualityManagement/metricMaintenance/StandardFormDialog.vue
+++ b/src/views/qualityManagement/metricMaintenance/StandardFormDialog.vue
@@ -42,6 +42,15 @@
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>
diff --git a/src/views/qualityManagement/metricMaintenance/index.vue b/src/views/qualityManagement/metricMaintenance/index.vue
index 8d1dd1c..d07893a 100644
--- a/src/views/qualityManagement/metricMaintenance/index.vue
+++ b/src/views/qualityManagement/metricMaintenance/index.vue
@@ -122,7 +122,7 @@
<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">
@@ -213,7 +213,9 @@
remark: '',
state: '0',
inspectType: '',
- processId: ''
+ processId: '',
+ inspectRule: 0,
+ sampleRatio: undefined
},
standardRules: {
standardNo: [{ required: true, message: '璇疯緭鍏ユ爣鍑嗙紪鍙�', trigger: 'blur' }],
@@ -333,6 +335,19 @@
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'
},
{
@@ -583,7 +598,9 @@
remark: '',
state: '0',
inspectType: '',
- processId: ''
+ processId: '',
+ inspectRule: 0,
+ sampleRatio: undefined
})
} else if (type === 'edit' && row) {
Object.assign(standardForm.value, {
diff --git a/src/views/qualityManagement/metricMaintenance/index0.vue b/src/views/qualityManagement/metricMaintenance/index0.vue
index 016a4c1..875985f 100644
--- a/src/views/qualityManagement/metricMaintenance/index0.vue
+++ b/src/views/qualityManagement/metricMaintenance/index0.vue
@@ -110,10 +110,10 @@
</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>
@@ -176,7 +176,7 @@
prop: "unit",
},
{
- label: "鏍囧噯鍊�",
+ label: "鍘傚鏍囧噯鍊�",
prop: "standardValue",
},
{
diff --git a/src/views/qualityManagement/processInspection/components/formDia.vue b/src/views/qualityManagement/processInspection/components/formDia.vue
index 3dac79e..0a37130 100644
--- a/src/views/qualityManagement/processInspection/components/formDia.vue
+++ b/src/views/qualityManagement/processInspection/components/formDia.vue
@@ -131,6 +131,26 @@
</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"
@@ -252,6 +272,9 @@
checkCompany: "",
checkResult: "",
purchaseContractNo: "",
+ inspectRule: 0,
+ sampleRatio: undefined,
+ sampleQuantity: undefined,
},
rules: {
checkTime: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
@@ -291,7 +314,7 @@
prop: "unit",
},
{
- label: "鏍囧噯鍊�",
+ label: "鍘傚鏍囧噯鍊�",
prop: "standardValue",
},
{
@@ -341,6 +364,9 @@
checkCompany: "",
checkResult: "",
purchaseContractNo: "",
+ inspectRule: 0,
+ sampleRatio: undefined,
+ sampleQuantity: undefined,
};
testStandardOptions.value = [];
tableData.value = [];
@@ -468,6 +494,16 @@
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) {
diff --git a/src/views/qualityManagement/processInspection/components/inspectionFormDia.vue b/src/views/qualityManagement/processInspection/components/inspectionFormDia.vue
index 411856c..e24e8d4 100644
--- a/src/views/qualityManagement/processInspection/components/inspectionFormDia.vue
+++ b/src/views/qualityManagement/processInspection/components/inspectionFormDia.vue
@@ -58,7 +58,7 @@
prop: "unit",
},
{
- label: "鏍囧噯鍊�",
+ label: "鍘傚鏍囧噯鍊�",
prop: "standardValue",
},
{
diff --git a/src/views/qualityManagement/processInspection/components/quickCheckDia.vue b/src/views/qualityManagement/processInspection/components/quickCheckDia.vue
index 0aa069b..718b12b 100644
--- a/src/views/qualityManagement/processInspection/components/quickCheckDia.vue
+++ b/src/views/qualityManagement/processInspection/components/quickCheckDia.vue
@@ -9,6 +9,14 @@
<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="鍚堟牸" />
@@ -17,6 +25,8 @@
</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">
@@ -29,12 +39,27 @@
</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">
@@ -46,12 +71,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>
@@ -101,7 +126,7 @@
</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";
@@ -115,12 +140,14 @@
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: '',
@@ -140,6 +167,59 @@
});
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: "鎸囨爣",
@@ -150,7 +230,7 @@
prop: "unit",
},
{
- label: "鏍囧噯鍊�",
+ label: "鍘傚鏍囧噯鍊�",
prop: "standardValue",
},
{
@@ -172,11 +252,18 @@
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 = {
@@ -188,12 +275,16 @@
} 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: '',
@@ -201,7 +292,7 @@
checkTime: '',
};
tableData.value = [];
-
+
await nextTick();
proxy.$refs.formRef?.clearValidate();
};
@@ -230,14 +321,16 @@
// 妫�娴嬬粨鏋滃彉鍖栧鐞�
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;
}
};
@@ -256,7 +349,7 @@
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 {
@@ -269,7 +362,7 @@
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 {
@@ -283,7 +376,7 @@
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) {
@@ -297,6 +390,15 @@
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,
@@ -324,4 +426,16 @@
</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>
diff --git a/src/views/qualityManagement/processInspection/index.vue b/src/views/qualityManagement/processInspection/index.vue
index a4f6add..066813a 100644
--- a/src/views/qualityManagement/processInspection/index.vue
+++ b/src/views/qualityManagement/processInspection/index.vue
@@ -237,6 +237,22 @@
},
},
{
+ 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",
diff --git a/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue b/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
index 723d542..ff30667 100644
--- a/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
+++ b/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
@@ -109,6 +109,26 @@
</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>
@@ -203,6 +223,9 @@
stockInRatio: 100.00,
checkCompany: "",
checkResult: "",
+ inspectRule: 0,
+ sampleRatio: undefined,
+ sampleQuantity: undefined,
},
rules: {
checkTime: [{required: false, message: "璇疯緭鍏�", trigger: "blur"},],
@@ -245,7 +268,7 @@
prop: "unit",
},
{
- label: "鏍囧噯鍊�",
+ label: "鍘傚鏍囧噯鍊�",
prop: "standardValue",
},
{
@@ -308,6 +331,9 @@
stockInRatio: 100.00,
checkCompany: "",
checkResult: "",
+ inspectRule: 0,
+ sampleRatio: undefined,
+ sampleQuantity: undefined,
}
testStandardOptions.value = [];
tableData.value = [];
@@ -403,6 +429,16 @@
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) {
diff --git a/src/views/qualityManagement/rawMaterialInspection/components/inspectionFormDia.vue b/src/views/qualityManagement/rawMaterialInspection/components/inspectionFormDia.vue
index 411856c..e24e8d4 100644
--- a/src/views/qualityManagement/rawMaterialInspection/components/inspectionFormDia.vue
+++ b/src/views/qualityManagement/rawMaterialInspection/components/inspectionFormDia.vue
@@ -58,7 +58,7 @@
prop: "unit",
},
{
- label: "鏍囧噯鍊�",
+ label: "鍘傚鏍囧噯鍊�",
prop: "standardValue",
},
{
diff --git a/src/views/qualityManagement/rawMaterialInspection/components/quickCheckDia.vue b/src/views/qualityManagement/rawMaterialInspection/components/quickCheckDia.vue
index 5a6c20f..b690d66 100644
--- a/src/views/qualityManagement/rawMaterialInspection/components/quickCheckDia.vue
+++ b/src/views/qualityManagement/rawMaterialInspection/components/quickCheckDia.vue
@@ -9,6 +9,14 @@
<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="鍚堟牸" />
@@ -17,6 +25,8 @@
</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">
@@ -29,12 +39,27 @@
</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">
@@ -46,12 +71,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>
@@ -108,7 +133,7 @@
</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";
@@ -122,12 +147,14 @@
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,
@@ -164,6 +191,59 @@
});
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: "鎸囨爣",
@@ -174,7 +254,7 @@
prop: "unit",
},
{
- label: "鏍囧噯鍊�",
+ label: "鍘傚鏍囧噯鍊�",
prop: "standardValue",
},
{
@@ -196,11 +276,18 @@
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 = {
@@ -212,12 +299,16 @@
} 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,
@@ -226,7 +317,7 @@
checkTime: '',
};
tableData.value = [];
-
+
await nextTick();
proxy.$refs.formRef?.clearValidate();
};
@@ -255,14 +346,16 @@
// 妫�娴嬬粨鏋滃彉鍖栧鐞�
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;
}
};
@@ -281,7 +374,7 @@
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 {
@@ -294,7 +387,7 @@
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 {
@@ -308,7 +401,7 @@
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) {
@@ -322,6 +415,15 @@
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,
@@ -349,4 +451,16 @@
</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>
diff --git a/src/views/qualityManagement/rawMaterialInspection/index.vue b/src/views/qualityManagement/rawMaterialInspection/index.vue
index df33f61..03a5771 100644
--- a/src/views/qualityManagement/rawMaterialInspection/index.vue
+++ b/src/views/qualityManagement/rawMaterialInspection/index.vue
@@ -232,6 +232,22 @@
},
},
{
+ 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",
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue
index 313f1df..96ec5cb 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue
@@ -1,5 +1,6 @@
<template>
<div class="panel-header">
+ <span class="header-dot"></span>
<span class="panel-title">{{ title }}</span>
</div>
</template>
@@ -20,6 +21,23 @@
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 {
@@ -27,7 +45,13 @@
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>
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
index f4e49b6..0aab3e3 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-bottom.vue
@@ -183,6 +183,32 @@
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>
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
index 6e39eb1..81bb2f5 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-center.vue
@@ -101,6 +101,32 @@
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 {
@@ -132,5 +158,11 @@
.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>
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
index 055fb66..5842f9e 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/center-top.vue
@@ -79,12 +79,53 @@
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 {
@@ -95,16 +136,22 @@
.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);
}
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
index 65a72fe..b636458 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/left-bottom.vue
@@ -234,6 +234,32 @@
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 {
@@ -241,6 +267,12 @@
width: 100%;
height: 320px;
background: transparent;
+ animation: pieFloat 4s ease-in-out infinite;
+}
+
+@keyframes pieFloat {
+ 0%, 100% { transform: translateY(0); }
+ 50% { transform: translateY(-3px); }
}
@@ -258,5 +290,11 @@
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>
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue b/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
index f5dac31..e3a3663 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/components/left-top.vue
@@ -204,12 +204,46 @@
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%;
@@ -223,5 +257,11 @@
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>
diff --git a/src/views/reportAnalysis/PSIDataAnalysis/index.vue b/src/views/reportAnalysis/PSIDataAnalysis/index.vue
index 6947dbb..57eb98a 100644
--- a/src/views/reportAnalysis/PSIDataAnalysis/index.vue
+++ b/src/views/reportAnalysis/PSIDataAnalysis/index.vue
@@ -183,6 +183,25 @@
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); }
}
/* 鍐呴儴鍐呭鍖哄煙 - 鍥哄畾璁捐灏哄 */
@@ -246,6 +265,12 @@
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 {
@@ -286,6 +311,33 @@
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;
diff --git a/src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue b/src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue
index 313f1df..96ec5cb 100644
--- a/src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/PanelHeader.vue
@@ -1,5 +1,6 @@
<template>
<div class="panel-header">
+ <span class="header-dot"></span>
<span class="panel-title">{{ title }}</span>
</div>
</template>
@@ -20,6 +21,23 @@
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 {
@@ -27,7 +45,13 @@
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>
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue b/src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue
index c28c2fa..f3cf759 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/center-bottom.vue
@@ -172,6 +172,32 @@
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 {
@@ -179,6 +205,12 @@
width: 100%;
height: 320px;
background: transparent;
+ animation: pieFloat 4s ease-in-out infinite;
+}
+
+@keyframes pieFloat {
+ 0%, 100% { transform: translateY(0); }
+ 50% { transform: translateY(-3px); }
}
@@ -194,5 +226,11 @@
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>
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue b/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
index d795f50..f4e086e 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
@@ -305,12 +305,52 @@
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 {
@@ -321,16 +361,22 @@
.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);
}
@@ -373,6 +419,32 @@
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 {
@@ -419,7 +491,7 @@
.equipment-value {
display: block;
font-weight: 500;
- font-size: 40px;
+ font-size: 36px;
color: #ffffff;
width: 120px;
height: 110px;
@@ -429,6 +501,13 @@
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 {
@@ -446,6 +525,32 @@
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 {
@@ -482,6 +587,29 @@
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 {
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue b/src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue
index bab6024..989dd06 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/left-bottom.vue
@@ -47,7 +47,7 @@
import { customerRevenueAnalysis } from '@/api/viewIndex.js'
import { listCustomer } from '@/api/basicData/customer.js'
-const dateType = ref(1) // 1=鍛� 2=鏈� 3=瀛e害
+const dateType = ref(3) // 1=鍛� 2=鏈� 3=瀛e害
const customerValue = ref(null)
const customerOptions = ref([])
@@ -249,6 +249,32 @@
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>
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue b/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
index 16791de..28c85a1 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
@@ -230,6 +230,32 @@
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 {
@@ -237,6 +263,12 @@
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 {
@@ -253,5 +285,11 @@
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>
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue b/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
index 6fcd80f..77ed7b4 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/right-bottom.vue
@@ -33,7 +33,7 @@
height: '100%',
}
-const dateType = ref(1) // 1=鍛� 2=鏈� 3=瀛e害
+const dateType = ref(3) // 1=鍛� 2=鏈� 3=瀛e害
// 椋炴満鍥炬爣 SVG path锛堜笌 right-top 涓�鑷达級
const aircraft =
@@ -326,6 +326,32 @@
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 {
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue b/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
index 96e4548..90ca942 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/right-top.vue
@@ -32,7 +32,7 @@
height: '100%',
}
-const radio1 = ref(1)
+const radio1 = ref(3)
// 椋炴満鍥炬爣 SVG path
const aircraft =
@@ -349,6 +349,32 @@
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 {
diff --git a/src/views/reportAnalysis/dataDashboard/index.vue b/src/views/reportAnalysis/dataDashboard/index.vue
index 9b46494..3ef2658 100644
--- a/src/views/reportAnalysis/dataDashboard/index.vue
+++ b/src/views/reportAnalysis/dataDashboard/index.vue
@@ -180,6 +180,25 @@
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); }
}
/* 鍐呴儴鍐呭鍖哄煙 - 鍥哄畾璁捐灏哄 */
@@ -243,6 +262,12 @@
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 {
@@ -283,6 +308,33 @@
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;
diff --git a/src/views/reportAnalysis/qualityAnalysis/components/PanelHeader.vue b/src/views/reportAnalysis/qualityAnalysis/components/PanelHeader.vue
index 313f1df..3416ee0 100644
--- a/src/views/reportAnalysis/qualityAnalysis/components/PanelHeader.vue
+++ b/src/views/reportAnalysis/qualityAnalysis/components/PanelHeader.vue
@@ -1,6 +1,9 @@
<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>
@@ -20,14 +23,44 @@
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>
diff --git a/src/views/reportAnalysis/qualityAnalysis/components/center-bottom.vue b/src/views/reportAnalysis/qualityAnalysis/components/center-bottom.vue
index fe875d0..d15352c 100644
--- a/src/views/reportAnalysis/qualityAnalysis/components/center-bottom.vue
+++ b/src/views/reportAnalysis/qualityAnalysis/components/center-bottom.vue
@@ -190,10 +190,29 @@
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 {
@@ -207,5 +226,73 @@
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>
diff --git a/src/views/reportAnalysis/qualityAnalysis/components/center-center.vue b/src/views/reportAnalysis/qualityAnalysis/components/center-center.vue
index 8d28f7a..a99afe1 100644
--- a/src/views/reportAnalysis/qualityAnalysis/components/center-center.vue
+++ b/src/views/reportAnalysis/qualityAnalysis/components/center-center.vue
@@ -175,6 +175,51 @@
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 {
@@ -188,6 +233,8 @@
#007eff 78%,
#007eff 100%) 1;
padding: 10px 0 6px;
+ position: relative;
+ z-index: 1;
}
.warn-header-left {
@@ -202,6 +249,12 @@
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 {
@@ -212,6 +265,12 @@
-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 {
@@ -226,6 +285,13 @@
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 {
@@ -233,6 +299,8 @@
gap: 18px;
align-items: stretch;
min-height: 260px;
+ position: relative;
+ z-index: 1;
}
.warn-list {
@@ -252,12 +320,41 @@
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 {
@@ -273,6 +370,31 @@
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 {
@@ -299,6 +421,11 @@
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 {
@@ -335,6 +462,12 @@
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); }
}
/* 鍗佸瓧杈呭姪绾� */
@@ -351,5 +484,11 @@
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>
diff --git a/src/views/reportAnalysis/qualityAnalysis/components/center-top.vue b/src/views/reportAnalysis/qualityAnalysis/components/center-top.vue
index 8e46770..7703892 100644
--- a/src/views/reportAnalysis/qualityAnalysis/components/center-top.vue
+++ b/src/views/reportAnalysis/qualityAnalysis/components/center-top.vue
@@ -2,17 +2,26 @@
<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>
@@ -70,11 +79,14 @@
<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');
@@ -82,47 +94,134 @@
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;
}
@@ -134,7 +233,12 @@
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,
diff --git a/src/views/reportAnalysis/qualityAnalysis/components/left-top.vue b/src/views/reportAnalysis/qualityAnalysis/components/left-top.vue
index cce4894..5036d17 100644
--- a/src/views/reportAnalysis/qualityAnalysis/components/left-top.vue
+++ b/src/views/reportAnalysis/qualityAnalysis/components/left-top.vue
@@ -89,7 +89,7 @@
{
key: 'raw',
title: '鍘熸潗鏂欐娴�',
- dateType: 1,
+ dateType: 3,
qualifiedCount: 0,
unqualifiedCount: 0,
qualifiedRate: 0,
@@ -98,7 +98,7 @@
{
key: 'process',
title: '杩囩▼妫�娴�',
- dateType: 1,
+ dateType: 3,
qualifiedCount: 0,
unqualifiedCount: 0,
qualifiedRate: 0,
@@ -107,7 +107,7 @@
{
key: 'final',
title: '鎴愬搧鍑哄巶妫�娴�',
- dateType: 1,
+ dateType: 3,
qualifiedCount: 0,
unqualifiedCount: 0,
qualifiedRate: 0,
@@ -238,17 +238,13 @@
.filters-row-left {
width: 50%;
color: white;
- /* 鐢╢lex鏇夸唬float锛岃瀛愬厓绱犲榻愭洿绋冲畾 */
display: flex;
align-items: center;
span {
- /* 鏍稿績锛氱埗绾х浉瀵瑰畾浣嶏紝浣滀负浼厓绱犲熀鍑� */
position: relative;
display: inline-block;
- /* 缁欎吉鍏冪礌鍜屾枃瀛楃暀绌洪棿 */
padding-left: 22px;
- /* 鏂囧瓧鍨傜洿灞呬腑 */
line-height: 23px;
margin-right: 8px;
@@ -263,8 +259,8 @@
top: 50%;
left: 0;
transform: translateY(-50%);
- /* 纭繚鑿卞舰鍦ㄦ笎鍙樺潡涓婃柟 */
z-index: 1;
+ animation: diamondPulse 2s ease-in-out infinite;
}
&::before {
@@ -277,7 +273,6 @@
position: absolute;
top: 50%;
left: -1px;
- /* 绮惧噯璐村湪鑿卞舰姝d笅鏂� */
transform: translateY(calc(0% + 8px));
z-index: 0;
}
@@ -286,18 +281,25 @@
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 {
@@ -306,6 +308,31 @@
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 {
@@ -316,7 +343,24 @@
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: '';
@@ -346,9 +390,15 @@
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;
@@ -361,9 +411,15 @@
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;
@@ -372,6 +428,12 @@
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 {
@@ -392,6 +454,32 @@
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 {
@@ -408,6 +496,12 @@
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 {
@@ -431,6 +525,12 @@
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 {
diff --git a/src/views/reportAnalysis/qualityAnalysis/components/right-bottom.vue b/src/views/reportAnalysis/qualityAnalysis/components/right-bottom.vue
index f4b0a0c..c88483b 100644
--- a/src/views/reportAnalysis/qualityAnalysis/components/right-bottom.vue
+++ b/src/views/reportAnalysis/qualityAnalysis/components/right-bottom.vue
@@ -164,12 +164,65 @@
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 {
@@ -185,5 +238,17 @@
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>
\ No newline at end of file
diff --git a/src/views/reportAnalysis/qualityAnalysis/components/right-top.vue b/src/views/reportAnalysis/qualityAnalysis/components/right-top.vue
index 890e99a..3e117b0 100644
--- a/src/views/reportAnalysis/qualityAnalysis/components/right-top.vue
+++ b/src/views/reportAnalysis/qualityAnalysis/components/right-top.vue
@@ -1,6 +1,10 @@
<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">
@@ -71,39 +75,115 @@
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;
}
}
}
@@ -128,5 +208,57 @@
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>
diff --git a/src/views/reportAnalysis/qualityAnalysis/index.vue b/src/views/reportAnalysis/qualityAnalysis/index.vue
index 59fcc9b..2f2c2d3 100644
--- a/src/views/reportAnalysis/qualityAnalysis/index.vue
+++ b/src/views/reportAnalysis/qualityAnalysis/index.vue
@@ -157,132 +157,313 @@
<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;
}
/* 鍏ㄥ睆鐘舵�佺殑鏍峰紡 - 浣滅敤浜巗cale-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>
\ No newline at end of file
--
Gitblit v1.9.3