From a0dd2bd1be4e97a93443a48b86c719930d0a268a Mon Sep 17 00:00:00 2001 From: yaowanxin <3588231647@qq.com> Date: 星期二, 12 八月 2025 16:13:44 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/dev_ai' into ywx --- src/views/personnelManagement/payrollManagement/components/formDia.vue | 315 +++ src/views/personnelManagement/payrollManagement/index.vue | 291 +++ src/assets/img/emoji/slightly-smiling-face.png | 0 src/assets/img/fileImg/txt.png | 0 src/views/qualityManagement/rawMaterialInspection/index.vue | 157 + src/views/inventoryManagement/stockWarning/index.vue | 1137 ++++++++++++ src/assets/img/emoji/取消.png | 0 src/views/chatHome/chatHomeIndex/home.vue | 175 + src/assets/img/emoji/thumbs-up-yellow.png | 0 src/views/equipmentManagement/ledger/Form.vue | 2 src/assets/img/emoji/money-bag.png | 0 src/assets/img/emoji/new-moon-face.png | 0 src/views/equipmentManagement/gasTank/simple.vue | 566 ++++++ src/api/personnelManagement/payrollManagement.js | 35 src/api/inventoryManagement/stockWarning.js | 81 src/api/qualityManagement/rawMaterialInspection.js | 23 src/views/energyManagement/waterManagement/components/waterBillForm.vue | 210 ++ src/assets/img/emoji/clown-face.png | 0 src/assets/img/emoji/ok-hand-yellow.png | 0 src/views/equipmentManagement/ledger/index.vue | 73 src/assets/img/emoji/rainbow.png | 0 src/assets/img/fileImg/unknowfile.png | 0 src/views/energyManagement/waterManagement/waterBill.vue | 181 ++ src/assets/img/emoji/thinking-face.png | 0 src/assets/img/emoji/hibiscus.png | 0 src/api/qualityManagement/metricMaintenance.js | 11 src/assets/img/fileImg/word.png | 0 src/router/index.js | 15 src/assets/img/emoji/jack-o-lantern.png | 0 src/views/energyManagement/waterManagement/components/formDia.vue | 221 ++ src/assets/img/emoji/rocket.png | 0 src/views/qualityManagement/rawMaterialInspection/components/formDia.vue | 137 + src/assets/img/fileImg/ppt.png | 0 src/assets/img/emoji/money-mouth-face.png | 0 src/assets/img/emoji/smiling-face-with-horns.png | 0 src/assets/img/emoji/shamrock.png | 0 src/assets/img/emoji/face-screaming-in-fear.png | 0 src/assets/img/emoji/lips.png | 0 src/assets/img/emoji/two-hearts.png | 0 src/assets/img/head_portrait.jpg | 0 src/assets/img/emoji/face-with-tongue.png | 0 src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue | 127 + src/assets/img/emoji/smiling-face-with-sunglasses.png | 0 src/assets/img/emoji/thought-balloon.png | 0 src/components/FileCard.vue | 81 src/utils/util.js | 92 + src/assets/img/emoji/smiling-face-with-heart-eyes.png | 0 src/assets/img/emoji/victory-hand-yellow.png | 0 src/assets/img/fileImg/excel.png | 0 src/assets/img/fileImg/zpi.png | 0 src/assets/img/emoji/pouting-face.png | 0 src/views/chatHome/chatHomeIndex/ai-jz.js | 3 src/assets/img/emoji/shangchuan.png | 0 src/assets/img/emoji/sparkles.png | 0 src/assets/img/emoji/loudly-crying-face.png | 0 src/views/chatHome/chatHomeIndex/MobileChat.vue | 461 +++++ src/assets/img/emoji/star.png | 0 src/views/energyManagement/waterManagement/index.vue | 312 +++ src/views/energyManagement/waterManagement/waterTrends.vue | 118 + src/assets/img/emoji/tired-face.png | 0 src/assets/styles/element-ui.scss | 2 src/views/chatHome/chatHomeIndex/ai-wd.js | 393 ++++ src/assets/img/emoji/face-vomiting.png | 0 src/assets/img/logo.png | 0 src/assets/img/emoji/ghost.png | 0 src/assets/img/emoji/pile-of-poo.png | 0 package.json | 2 src/assets/img/fileImg/pdf.png | 0 src/assets/img/emoji/face-without-mouth.png | 0 src/assets/img/emoji/smiling-face.png | 0 src/api/energyManagement/waterManagement.js | 92 + src/assets/img/head_portrait1.png | 0 72 files changed, 5,246 insertions(+), 67 deletions(-) diff --git a/package.json b/package.json index 15334fa..2ffdd34 100644 --- a/package.json +++ b/package.json @@ -33,10 +33,12 @@ "jsencrypt": "3.3.2", "nprogress": "0.2.0", "pinia": "2.1.7", + "qrcode": "^1.5.4", "sortablejs": "^1.15.6", "splitpanes": "3.1.5", "vue": "3.4.31", "vue-cropper": "1.1.1", + "vue-esign": "^1.1.4", "vue-router": "4.4.0", "vuedraggable": "4.1.0" }, diff --git a/src/api/energyManagement/waterManagement.js b/src/api/energyManagement/waterManagement.js new file mode 100644 index 0000000..caa82bf --- /dev/null +++ b/src/api/energyManagement/waterManagement.js @@ -0,0 +1,92 @@ +// 鐢ㄦ按绠$悊 +import request from "@/utils/request"; + +// 鐢ㄦ按璁惧-鍒嗛〉鏌ヨ +export function waterEquipmentListPage(query) { + return request({ + url: '/waterRecord/listPage', + method: 'get', + params: query, + }) +} + +// 鐢ㄦ按瓒嬪娍-鍒嗛〉鏌ヨ +export function listPageByWaterTrend(query) { + return request({ + url: '/waterRecord/listPageByTrend', + method: 'get', + params: query, + }) +} + +// 鐢ㄦ按璁惧-鍒犻櫎 +export function waterEquipmentDelete(query) { + return request({ + url: '/waterRecord/delete', + method: 'delete', + data: query, + }) +} + +// 鐢ㄦ按璁惧-鏂板 +export function waterEquipmentAdd(query) { + return request({ + url: '/waterRecord/add', + method: 'post', + data: query, + }) +} + +// 鐢ㄦ按璁惧-淇敼 +export function waterEquipmentUpdate(query) { + return request({ + url: '/waterRecord/update', + method: 'post', + data: query, + }) +} + +// 鐢ㄦ按璁惧涓嬫媺妗嗘煡璇� +export function waterDeviceList(query) { + return request({ + url: '/device/ledger/page', + method: 'get', + params: query, + }) +} + +// 姘磋垂绠$悊-鍒嗛〉鏌ヨ +export function waterBillListPage(query) { + return request({ + url: '/waterBill/listPage', + method: 'get', + params: query, + }) +} + +// 姘磋垂绠$悊-鏂板 +export function waterBillAdd(query) { + return request({ + url: '/waterBill/add', + method: 'post', + data: query, + }) +} + +// 姘磋垂绠$悊-淇敼 +export function waterBillUpdate(query) { + return request({ + url: '/waterBill/update', + method: 'post', + data: query, + }) +} + +// 姘磋垂绠$悊-鍒犻櫎 +export function waterBillDelete(query) { + return request({ + url: '/waterBill/delete', + method: 'delete', + data: query, + }) +} diff --git a/src/api/inventoryManagement/stockWarning.js b/src/api/inventoryManagement/stockWarning.js new file mode 100644 index 0000000..092fb80 --- /dev/null +++ b/src/api/inventoryManagement/stockWarning.js @@ -0,0 +1,81 @@ +import request from "@/utils/request"; + +// 鏌ヨ鍌ㄦ皵缃愰璀﹀垪琛� +export const getStockWarningPage = (params) => { + return request({ + url: "/gasTankWarning/listPage", + method: "get", + params, + }); +}; + +// 鏂板鍌ㄦ皵缃愰璀﹁鍒� +export const addStockWarning = (data) => { + return request({ + url: "/gasTankWarning/add", + method: "post", + data, + }); +}; + +// 淇敼鍌ㄦ皵缃愰璀﹁鍒� +export const updateStockWarning = (data) => { + return request({ + url: "/gasTankWarning/update", + method: "put", + data, + }); +}; + +// 鍒犻櫎鍌ㄦ皵缃愰璀﹁鍒� +export const deleteStockWarning = (ids) => { + return request({ + url: "/gasTankWarning/delete", + method: "delete", + data: { ids }, + }); +}; + +// 鎵归噺澶勭悊鍌ㄦ皵缃愰璀� +export const batchProcessStockWarning = (data) => { + return request({ + url: "/gasTankWarning/batchProcess", + method: "post", + data, + }); +}; + +// 瀵煎嚭鍌ㄦ皵缃愰璀︽暟鎹� +export const exportStockWarning = (params) => { + return request({ + url: "/gasTankWarning/export", + method: "get", + params, + responseType: "blob", + }); +}; + +// 鏍规嵁ID鑾峰彇鍌ㄦ皵缃愰璀﹁鎯� +export const getStockWarningById = (id) => { + return request({ + url: `/gasTankWarning/${id}`, + method: "get", + }); +}; + +// 鍚敤/绂佺敤棰勮瑙勫垯 +export const toggleStockWarningStatus = (data) => { + return request({ + url: "/gasTankWarning/toggleStatus", + method: "put", + data, + }); +}; + +// 鑾峰彇棰勮缁熻淇℃伅 +export const getStockWarningStatistics = () => { + return request({ + url: "/gasTankWarning/statistics", + method: "get", + }); +}; diff --git a/src/api/personnelManagement/payrollManagement.js b/src/api/personnelManagement/payrollManagement.js new file mode 100644 index 0000000..c29a6b1 --- /dev/null +++ b/src/api/personnelManagement/payrollManagement.js @@ -0,0 +1,35 @@ +// 钖叕绠$悊 +import request from "@/utils/request"; + +// 鏌ヨ鍒楄〃 +export function compensationListPage(query) { + return request({ + url: "/compensationPerformance/listPage", + method: "get", + params: query, + }); +} +// 鏂板 +export function compensationAdd(query) { + return request({ + url: "/compensationPerformance/add", + method: "post", + data: query, + }); +} +// 淇敼 +export function compensationUpdate(query) { + return request({ + url: "/compensationPerformance/update", + method: "post", + data: query, + }); +} +// 鍒犻櫎 +export function compensationDelete(query) { + return request({ + url: "/compensationPerformance/delete", + method: "delete", + data: query, + }); +} \ No newline at end of file diff --git a/src/api/qualityManagement/metricMaintenance.js b/src/api/qualityManagement/metricMaintenance.js index 8857387..9bdff23 100644 --- a/src/api/qualityManagement/metricMaintenance.js +++ b/src/api/qualityManagement/metricMaintenance.js @@ -8,6 +8,7 @@ params: query, }) } + // 鏂板鎸囨爣鍒楄〃 export function qualityTestStandardAdd(query) { return request({ @@ -16,6 +17,7 @@ data: query, }) } + // 淇敼鎸囨爣鍒楄〃 export function qualityTestStandardUpdate(query) { return request({ @@ -24,6 +26,7 @@ data: query, }) } + // 鍒犻櫎鎸囨爣鍒楄〃 export function qualityTestStandardDel(query) { return request({ @@ -31,4 +34,12 @@ method: 'delete', data: query, }) +} + +// 鍒犻櫎鎸囨爣鍒楄〃 +export function qualityInspectDetailByProductId(productId) { + return request({ + url: '/quality/qualityTestStandard/product/' + productId, + method: 'get', + }) } \ No newline at end of file diff --git a/src/api/qualityManagement/rawMaterialInspection.js b/src/api/qualityManagement/rawMaterialInspection.js index e909d1a..dcb3869 100644 --- a/src/api/qualityManagement/rawMaterialInspection.js +++ b/src/api/qualityManagement/rawMaterialInspection.js @@ -8,6 +8,7 @@ params: query, }) } + // 鏂板鍘熸潗鏂欐楠� export function qualityInspectAdd(query) { return request({ @@ -16,6 +17,7 @@ data: query, }) } + // 淇敼鍘熸潗鏂欐楠� export function qualityInspectUpdate(query) { return request({ @@ -24,6 +26,7 @@ data: query, }) } + // 鍒犻櫎鍘熸潗鏂欐楠� export function qualityInspectDel(query) { return request({ @@ -32,3 +35,23 @@ data: query, }) } + +// 鎻愪氦鍘熸潗鏂欐楠� +export function submitQualityInspect(data) { + return request({ + url: '/quality/qualityInspect/submit', + method: 'post', + data: data, + }) +} + +// 鎻愪氦鍘熸潗鏂欐楠� +export function downloadQualityInspect(data) { + return request({ + url: '/quality/qualityInspect/down', + method: 'post', + data: data, + responseType: "blob", + }) +} + diff --git a/src/assets/img/emoji/clown-face.png b/src/assets/img/emoji/clown-face.png new file mode 100644 index 0000000..fd77228 --- /dev/null +++ b/src/assets/img/emoji/clown-face.png Binary files differ diff --git a/src/assets/img/emoji/face-screaming-in-fear.png b/src/assets/img/emoji/face-screaming-in-fear.png new file mode 100644 index 0000000..d6332ce --- /dev/null +++ b/src/assets/img/emoji/face-screaming-in-fear.png Binary files differ diff --git a/src/assets/img/emoji/face-vomiting.png b/src/assets/img/emoji/face-vomiting.png new file mode 100644 index 0000000..dcc556f --- /dev/null +++ b/src/assets/img/emoji/face-vomiting.png Binary files differ diff --git a/src/assets/img/emoji/face-with-tongue.png b/src/assets/img/emoji/face-with-tongue.png new file mode 100644 index 0000000..b2e228e --- /dev/null +++ b/src/assets/img/emoji/face-with-tongue.png Binary files differ diff --git a/src/assets/img/emoji/face-without-mouth.png b/src/assets/img/emoji/face-without-mouth.png new file mode 100644 index 0000000..e48a05a --- /dev/null +++ b/src/assets/img/emoji/face-without-mouth.png Binary files differ diff --git a/src/assets/img/emoji/ghost.png b/src/assets/img/emoji/ghost.png new file mode 100644 index 0000000..8a4b03a --- /dev/null +++ b/src/assets/img/emoji/ghost.png Binary files differ diff --git a/src/assets/img/emoji/hibiscus.png b/src/assets/img/emoji/hibiscus.png new file mode 100644 index 0000000..5fddeb5 --- /dev/null +++ b/src/assets/img/emoji/hibiscus.png Binary files differ diff --git a/src/assets/img/emoji/jack-o-lantern.png b/src/assets/img/emoji/jack-o-lantern.png new file mode 100644 index 0000000..7014639 --- /dev/null +++ b/src/assets/img/emoji/jack-o-lantern.png Binary files differ diff --git a/src/assets/img/emoji/lips.png b/src/assets/img/emoji/lips.png new file mode 100644 index 0000000..40915bd --- /dev/null +++ b/src/assets/img/emoji/lips.png Binary files differ diff --git a/src/assets/img/emoji/loudly-crying-face.png b/src/assets/img/emoji/loudly-crying-face.png new file mode 100644 index 0000000..d72008d --- /dev/null +++ b/src/assets/img/emoji/loudly-crying-face.png Binary files differ diff --git a/src/assets/img/emoji/money-bag.png b/src/assets/img/emoji/money-bag.png new file mode 100644 index 0000000..df46b05 --- /dev/null +++ b/src/assets/img/emoji/money-bag.png Binary files differ diff --git a/src/assets/img/emoji/money-mouth-face.png b/src/assets/img/emoji/money-mouth-face.png new file mode 100644 index 0000000..f7c4cdf --- /dev/null +++ b/src/assets/img/emoji/money-mouth-face.png Binary files differ diff --git a/src/assets/img/emoji/new-moon-face.png b/src/assets/img/emoji/new-moon-face.png new file mode 100644 index 0000000..8942b8b --- /dev/null +++ b/src/assets/img/emoji/new-moon-face.png Binary files differ diff --git a/src/assets/img/emoji/ok-hand-yellow.png b/src/assets/img/emoji/ok-hand-yellow.png new file mode 100644 index 0000000..4dbd427 --- /dev/null +++ b/src/assets/img/emoji/ok-hand-yellow.png Binary files differ diff --git a/src/assets/img/emoji/pile-of-poo.png b/src/assets/img/emoji/pile-of-poo.png new file mode 100644 index 0000000..28f149a --- /dev/null +++ b/src/assets/img/emoji/pile-of-poo.png Binary files differ diff --git a/src/assets/img/emoji/pouting-face.png b/src/assets/img/emoji/pouting-face.png new file mode 100644 index 0000000..0265aa2 --- /dev/null +++ b/src/assets/img/emoji/pouting-face.png Binary files differ diff --git a/src/assets/img/emoji/rainbow.png b/src/assets/img/emoji/rainbow.png new file mode 100644 index 0000000..7794ded --- /dev/null +++ b/src/assets/img/emoji/rainbow.png Binary files differ diff --git a/src/assets/img/emoji/rocket.png b/src/assets/img/emoji/rocket.png new file mode 100644 index 0000000..04a7619 --- /dev/null +++ b/src/assets/img/emoji/rocket.png Binary files differ diff --git a/src/assets/img/emoji/shamrock.png b/src/assets/img/emoji/shamrock.png new file mode 100644 index 0000000..8fe0836 --- /dev/null +++ b/src/assets/img/emoji/shamrock.png Binary files differ diff --git a/src/assets/img/emoji/shangchuan.png b/src/assets/img/emoji/shangchuan.png new file mode 100644 index 0000000..af16fb4 --- /dev/null +++ b/src/assets/img/emoji/shangchuan.png Binary files differ diff --git a/src/assets/img/emoji/slightly-smiling-face.png b/src/assets/img/emoji/slightly-smiling-face.png new file mode 100644 index 0000000..be7dd9f --- /dev/null +++ b/src/assets/img/emoji/slightly-smiling-face.png Binary files differ diff --git a/src/assets/img/emoji/smiling-face-with-heart-eyes.png b/src/assets/img/emoji/smiling-face-with-heart-eyes.png new file mode 100644 index 0000000..c838d4f --- /dev/null +++ b/src/assets/img/emoji/smiling-face-with-heart-eyes.png Binary files differ diff --git a/src/assets/img/emoji/smiling-face-with-horns.png b/src/assets/img/emoji/smiling-face-with-horns.png new file mode 100644 index 0000000..b79738c --- /dev/null +++ b/src/assets/img/emoji/smiling-face-with-horns.png Binary files differ diff --git a/src/assets/img/emoji/smiling-face-with-sunglasses.png b/src/assets/img/emoji/smiling-face-with-sunglasses.png new file mode 100644 index 0000000..58b8604 --- /dev/null +++ b/src/assets/img/emoji/smiling-face-with-sunglasses.png Binary files differ diff --git a/src/assets/img/emoji/smiling-face.png b/src/assets/img/emoji/smiling-face.png new file mode 100644 index 0000000..3c2915b --- /dev/null +++ b/src/assets/img/emoji/smiling-face.png Binary files differ diff --git a/src/assets/img/emoji/sparkles.png b/src/assets/img/emoji/sparkles.png new file mode 100644 index 0000000..4d11a1b --- /dev/null +++ b/src/assets/img/emoji/sparkles.png Binary files differ diff --git a/src/assets/img/emoji/star.png b/src/assets/img/emoji/star.png new file mode 100644 index 0000000..44f80bb --- /dev/null +++ b/src/assets/img/emoji/star.png Binary files differ diff --git a/src/assets/img/emoji/thinking-face.png b/src/assets/img/emoji/thinking-face.png new file mode 100644 index 0000000..33d791d --- /dev/null +++ b/src/assets/img/emoji/thinking-face.png Binary files differ diff --git a/src/assets/img/emoji/thought-balloon.png b/src/assets/img/emoji/thought-balloon.png new file mode 100644 index 0000000..892eedc --- /dev/null +++ b/src/assets/img/emoji/thought-balloon.png Binary files differ diff --git a/src/assets/img/emoji/thumbs-up-yellow.png b/src/assets/img/emoji/thumbs-up-yellow.png new file mode 100644 index 0000000..c30b6ae --- /dev/null +++ b/src/assets/img/emoji/thumbs-up-yellow.png Binary files differ diff --git a/src/assets/img/emoji/tired-face.png b/src/assets/img/emoji/tired-face.png new file mode 100644 index 0000000..d1deba8 --- /dev/null +++ b/src/assets/img/emoji/tired-face.png Binary files differ diff --git a/src/assets/img/emoji/two-hearts.png b/src/assets/img/emoji/two-hearts.png new file mode 100644 index 0000000..4259b46 --- /dev/null +++ b/src/assets/img/emoji/two-hearts.png Binary files differ diff --git a/src/assets/img/emoji/victory-hand-yellow.png b/src/assets/img/emoji/victory-hand-yellow.png new file mode 100644 index 0000000..fc46ce2 --- /dev/null +++ b/src/assets/img/emoji/victory-hand-yellow.png Binary files differ diff --git "a/src/assets/img/emoji/\345\217\226\346\266\210.png" "b/src/assets/img/emoji/\345\217\226\346\266\210.png" new file mode 100644 index 0000000..30df0a9 --- /dev/null +++ "b/src/assets/img/emoji/\345\217\226\346\266\210.png" Binary files differ diff --git a/src/assets/img/fileImg/excel.png b/src/assets/img/fileImg/excel.png new file mode 100644 index 0000000..ae8929c --- /dev/null +++ b/src/assets/img/fileImg/excel.png Binary files differ diff --git a/src/assets/img/fileImg/pdf.png b/src/assets/img/fileImg/pdf.png new file mode 100644 index 0000000..3653045 --- /dev/null +++ b/src/assets/img/fileImg/pdf.png Binary files differ diff --git a/src/assets/img/fileImg/ppt.png b/src/assets/img/fileImg/ppt.png new file mode 100644 index 0000000..2362d61 --- /dev/null +++ b/src/assets/img/fileImg/ppt.png Binary files differ diff --git a/src/assets/img/fileImg/txt.png b/src/assets/img/fileImg/txt.png new file mode 100644 index 0000000..0ce91dc --- /dev/null +++ b/src/assets/img/fileImg/txt.png Binary files differ diff --git a/src/assets/img/fileImg/unknowfile.png b/src/assets/img/fileImg/unknowfile.png new file mode 100644 index 0000000..75e22fb --- /dev/null +++ b/src/assets/img/fileImg/unknowfile.png Binary files differ diff --git a/src/assets/img/fileImg/word.png b/src/assets/img/fileImg/word.png new file mode 100644 index 0000000..97e8a69 --- /dev/null +++ b/src/assets/img/fileImg/word.png Binary files differ diff --git a/src/assets/img/fileImg/zpi.png b/src/assets/img/fileImg/zpi.png new file mode 100644 index 0000000..de3c681 --- /dev/null +++ b/src/assets/img/fileImg/zpi.png Binary files differ diff --git a/src/assets/img/head_portrait.jpg b/src/assets/img/head_portrait.jpg new file mode 100644 index 0000000..dd345b3 --- /dev/null +++ b/src/assets/img/head_portrait.jpg Binary files differ diff --git a/src/assets/img/head_portrait1.png b/src/assets/img/head_portrait1.png new file mode 100644 index 0000000..3134bd5 --- /dev/null +++ b/src/assets/img/head_portrait1.png Binary files differ diff --git a/src/assets/img/logo.png b/src/assets/img/logo.png new file mode 100644 index 0000000..b53ef8a --- /dev/null +++ b/src/assets/img/logo.png Binary files differ diff --git a/src/assets/styles/element-ui.scss b/src/assets/styles/element-ui.scss index 4eae8b2..8c741af 100644 --- a/src/assets/styles/element-ui.scss +++ b/src/assets/styles/element-ui.scss @@ -67,7 +67,7 @@ } .el-dialog__body { padding: 16px 40px 0 40px; - max-height: 90vh; + max-height: 74vh; overflow-y: auto; } .el-dialog__footer { diff --git a/src/components/FileCard.vue b/src/components/FileCard.vue new file mode 100644 index 0000000..d14ec48 --- /dev/null +++ b/src/components/FileCard.vue @@ -0,0 +1,81 @@ +<template> + <div class="file-card"> + <img src="@/assets/img/fileImg/unknowfile.png" alt="" v-if="fileType == 0"/> + <img src="@/assets/img/fileImg/word.png" alt="" v-else-if="fileType == 1"/> + <img src="@/assets/img/fileImg/excel.png" alt="" v-else-if="fileType == 2"/> + <img src="@/assets/img/fileImg/ppt.png" alt="" v-else-if="fileType == 3"/> + <img src="@/assets/img/fileImg/pdf.png" alt="" v-else-if="fileType == 4"/> + <img src="@/assets/img/fileImg/zpi.png" alt="" v-else-if="fileType == 5"/> + <img src="@/assets/img/fileImg/txt.png" alt="" v-else/> + <div class="word"> + <span + >{{file.name || '鏈煡'}}</span + > + <span>154kb</span> + </div> + </div> +</template> + +<script> +export default { + // props: ["fileType", "file"], + props: { + fileType: Number, + file: File, + default() { + return {}; + }, + }, + watch: { + file() { + console.log(this.file); + }, + }, + mounted() { + console.log(this.file); + console.log(this.fileType); + } +}; +</script> + +<style lang="scss" scoped> +.file-card { + width: 250px; + height: 100px; + background-color: rgb(45, 48, 63); + border-radius: 20px; + display: flex; + justify-content: center; + align-items: center; + padding: 10px; + box-sizing: border-box; + cursor: pointer; + &:hover { + background-color: rgb(33, 36, 54); + } + img { + width: 60px; + height: 60px; + } + .word { + width: 60%; + margin-left: 10px; + overflow: hidden; + span { + width: 90%; + display: inline-block; + color: #fff; + } + span:first-child { + font-size: 14px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + span:last-child { + font-size: 12px; + color: rgb(180, 180, 180); + } + } +} +</style> \ No newline at end of file diff --git a/src/router/index.js b/src/router/index.js index 3c69a74..10adf72 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -57,6 +57,7 @@ component: () => import('@/views/error/401'), hidden: true }, + { path: '', component: Layout, @@ -71,6 +72,20 @@ ] }, { + path: '/main/MobileChat', + component: Layout, + redirect: '', + hidden: true, + children: [ + { + path: '', + component: () => import('@/views/chatHome/chatHomeIndex/MobileChat'), + name: 'MobileChat', + meta: { title: 'AI瀵硅瘽', icon: 'dashboard', affix: true} + } + ] + }, + { path: '/user', component: Layout, hidden: true, diff --git a/src/utils/util.js b/src/utils/util.js new file mode 100644 index 0000000..78846dc --- /dev/null +++ b/src/utils/util.js @@ -0,0 +1,92 @@ +//闃叉姈 +export function debounce(fn) { + console.log(1) + let t = null //鍙細鎵ц涓�娆� + debugger + + return function (){ + if(t){ + clearTimeout(t) + } + t = setTimeout(()=>{ + console.log(temp); //鍙互鑾峰彇 + // console.log(arguments[0]) //undefined + fn.apply(this,arguments) + //鍦ㄨ繖涓洖璋冨嚱鏁伴噷闈㈢殑argument鏄繖涓洖璋冨嚱鏁扮殑鍙傛暟锛屽洜涓烘病鏈夊弬鏁版墍浠ndefined锛屽彲浠ラ�氳繃澶栭潰鐨勫嚱鏁拌祴鍊兼潵杩涜璁块棶 + //涔熷彲浠ユ敼鍙樻垚绠ご鍑芥暟,绠ご鍑芥暟鐨則his鏄寚鍚戝畾涔夊嚱鏁扮殑閭d竴灞傜殑锛屾墍浠ヨ闂埌鐨刟rguments鏄笂涓�灞傚嚱鏁扮殑arguments + },1000) + + } +} +//鑺傛祦 +export function throttle(fn, delay = 200) { + let timer = null + console.log(fn); + debugger + return function () { + if(timer) return + timer = setTimeout(() => { + debugger + fn.apply(this,arguments) + timer = null + }) + } + } +//涓嬫媺鍔ㄧ敾 + export function animation(obj, target, fn1) { + // console.log(fn1); + // fn鏄竴涓洖璋冨嚱鏁帮紝鍦ㄥ畾鏃跺櫒缁撴潫鐨勬椂鍊欐坊鍔� + // 姣忔寮�瀹氭椂鍣ㄤ箣鍓嶅厛娓呴櫎鎺夊畾鏃跺櫒 + clearInterval(obj.timer); + obj.timer = setInterval(function () { + // 姝ラ暱璁$畻鍏紡 瓒婃潵瓒婂皬 + // 姝ラ暱鍙栨暣 + var step = (target - obj.scrollTop) / 10; + step = step > 0 ? Math.ceil(step) : Math.floor(step); + if (obj.scrollTop >= target) { + clearInterval(obj.timer); + // 濡傛灉fn1瀛樺湪锛岃皟鐢╢n + if (fn1) { + fn1(); + } + } else { + // 姣�30姣灏卞皢鏂扮殑鍊肩粰obj.left + obj.scrollTop = obj.scrollTop + step; + } + }, 10); + } + + //鍒ゆ柇鏂囦欢绫诲瀷 + export function judgeFileType(file) { + if (file == null||file == ""){ + alert("璇烽�夋嫨瑕佷笂浼犵殑鍥剧墖!"); + return false; + } + if (file.lastIndexOf('.')==-1){ //濡傛灉涓嶅瓨鍦�"." + alert("璺緞涓嶆纭�!"); + return false; + } + var AllImgExt=".jpg|.jpeg|.gif|.bmp|.png|"; + var extName = file.substring(file.lastIndexOf(".")).toLowerCase();//锛堟妸璺緞涓殑鎵�鏈夊瓧姣嶅叏閮ㄨ浆鎹负灏忓啓锛� + if(AllImgExt.indexOf(extName+"|")==-1) + { + ErrMsg="璇ユ枃浠剁被鍨嬩笉鍏佽涓婁紶銆傝涓婁紶 "+AllImgExt+" 绫诲瀷鐨勬枃浠讹紝褰撳墠鏂囦欢绫诲瀷涓�"+extName; + alert(ErrMsg); + return false; + } + } + + //鏂囦欢绫诲瀷 + export function fileType() { + return { + 'application/msword': 'word', + 'application/pdf': 'pdf', + 'application/vnd.ms-powerpoint': 'ppt', + 'application/vnd.ms-excel': 'excel', + 'aplication/zip': 'zpi', + } + } + + export function filterArr(arr) { + return arr.filter(item => item.flag !== false); + } \ No newline at end of file diff --git a/src/views/chatHome/chatHomeIndex/MobileChat.vue b/src/views/chatHome/chatHomeIndex/MobileChat.vue new file mode 100644 index 0000000..f8bc625 --- /dev/null +++ b/src/views/chatHome/chatHomeIndex/MobileChat.vue @@ -0,0 +1,461 @@ +<template> + <div class="mobile-chat-wrapper" style="height: 91vh;"> + <div class="chat-history"> + <div class="chat-content" ref="chatContent"> + <div class="chat-wrapper" v-for="(item, index) in chatList" :key="index"> + <div class="chat-friend" v-if="item.uid !== '1001'"> + <div class="info-time"> + <img :src="item.headImg" alt="" /> + <span>{{ item.name }}</span> + <span>{{ item.time }}</span> + </div> + <div class="chat-text" v-if="item.chatType == 0"> + <template v-if="isSend && index === chatList.length - 1"> + <span class="flash_cursor"></span> + </template> + <template v-else> + <pre>{{ item.msg }}</pre> + </template> + </div> + <div class="chat-img" v-if="item.chatType == 1"> + <img :src="item.msg" alt="琛ㄦ儏" v-if="item.extend.imgType == 1" style="width: 100px; height: 100px" /> + <el-image :src="item.msg" :preview-src-list="srcImgList" v-else> </el-image> + </div> + <div class="chat-img" v-if="item.chatType == 2"> + <div class="word-file"> + <FileCard :fileType="item.extend.fileType" :file="item.msg"></FileCard> + </div> + </div> + </div> + <div class="chat-me" v-else> + <div class="info-time"> + <span>{{ item.name }}</span> + <span>{{ item.time }}</span> + <img :src="item.headImg" alt="" /> + </div> + <div class="chat-text" v-if="item.chatType == 0"> + {{ item.msg }} + </div> + <div class="chat-img" v-if="item.chatType == 1"> + <img :src="item.msg" alt="琛ㄦ儏" v-if="item.extend.imgType == 1" style="width: 100px; height: 100px" /> + <el-image style="max-width: 300px; border-radius: 10px" :src="item.msg" :preview-src-list="srcImgList" v-else> </el-image> + </div> + <div class="chat-img" v-if="item.chatType == 2"> + <div class="word-file"> + <FileCard :fileType="item.extend.fileType" :file="item.msg"></FileCard> + </div> + </div> + </div> + </div> + </div> + </div> + <div class="chat-input-wrapper"> + <div style="display: flex; align-items: center"> + <input v-model="inputMsg" @change="sendText" :disabled="loading" class="input-text" autofocus placeholder="缁欏皬鏅哄彂閫佹秷鎭�" /> + <img class="send-icon" src="@/assets/img/emoji/rocket.png" alt="" @click="sendText" /> + + </div> + </div> + </div> +</template> + +<script setup> +import { ref, reactive, onMounted, nextTick,onActivated } from 'vue' +import { useRoute } from 'vue-router' +import { animation } from '@/utils/util' +import chatGPTHeadImg from '@/assets/img/head_portrait1.png' +import headPortrait from '@/assets/img/head_portrait.jpg' +import FileCard from '@/components/FileCard.vue' +import { ElMessage } from "element-plus" +import {checking} from './ai-wd.js' + +// 瀹氫箟鍝嶅簲寮忔暟鎹� +const route = useRoute() +const chatContent = ref(null) +const ws = ref(null) +const chatList = ref([ + { + headImg: chatGPTHeadImg, + name: '灏忔櫤', + time: new Date().toLocaleTimeString(), + msg: ' 灏忔櫤涓烘偍鏈嶅姟', + chatType: 0, + uid: '1002' + } +]) +const inputMsg = ref('') +const isSend = ref(false) +const fileList = ref([]) +const isProcessing = ref(false) +const loading = ref(true) +const srcImgList = ref([]) + +// 鍒犻櫎鍥剧墖 +const deleteImg = (index) => { + if (index >= 0 && index < fileList.value.length) { + fileList.value.splice(index, 1) + } +} + +// WebSocket娑堟伅鎺ユ敹 +const websocketonmessage = (e) => { + const redata = JSON.parse(e.data) + //鏁版嵁鎺ユ敹 + let chatGPT = { + headImg: headPortrait, + name: 'DeepSeek', + time: new Date().toLocaleTimeString(), + msg: redata[0].text, + chatType: 0, //淇℃伅绫诲瀷锛�0鏂囧瓧锛�1鍥剧墖 + uid: '1002' //uid + } + sendMsg(chatGPT) + isSend.value = false +} + +// WebSocket鍙戦�佹秷鎭� +const websocketsend = (Data) => { + console.log("鍗冲皢鍙戦�佹秷鎭�", Data) + if (ws.value && ws.value.readyState === WebSocket.OPEN) { + console.log("鍙戦�佹秷鎭�", ws.value) + console.log("鍙戦�佹秷鎭�", Data) + let fileUrls = fileList.value.map(item => item.file.fileUrl) + //鏁版嵁鍙戦�� + ws.value.send(Data + ":" + fileUrls.join(",")) + fileList.value = [] + inputMsg.value = '' + } +} + +// 鍙戦�佹枃鏈秷鎭� +const sendText = () => { + if (inputMsg.value) { + let chatMsg = { + headImg: headPortrait, + name: '鍗ч緳', + time: new Date().toLocaleTimeString(), + msg: inputMsg.value, + chatType: 0, //淇℃伅绫诲瀷锛�0鏂囧瓧锛�1鍥剧墖 + uid: '1001' //uid + } + chatList.value.push(chatMsg) + let chatGPT = { + headImg: headPortrait, + name: '灏忔櫤', + time: new Date().toLocaleTimeString(), + msg: "", + chatType: 0, //淇℃伅绫诲瀷锛�0鏂囧瓧锛�1鍥剧墖 + uid: '1002' //uid + } + chatList.value.push(chatGPT) // 灏嗘帴鏀跺埌鐨勬秷鎭瓨鍌ㄥ埌 messages 鏁扮粍 + simulateStreamingOutput(chatGPT, inputMsg.value) + inputMsg.value = '' + + } else { + ElMessage({ + message: '娑堟伅涓嶈兘涓虹┖鍝', + type: 'warning' + }) + } +} + +// 鍙戦�佷俊鎭� +const sendMsg = (msgList) => { + chatList.value.push(msgList) + scrollBottom() +} + +// 鑾峰彇绐楀彛楂樺害骞舵粴鍔ㄨ嚦鏈�搴曞眰 +const scrollBottom = () => { + nextTick(() => { + const scrollDom = chatContent.value + animation(scrollDom, scrollDom.scrollHeight - scrollDom.offsetHeight) + }) +} + +// 缁勪欢鎸傝浇鏃舵墽琛� +onActivated(() => { + chatList.value = [] + chatList.value.push({ + headImg: chatGPTHeadImg, + name: '灏忔櫤', + time: new Date().toLocaleTimeString(), + msg: '灏忔櫤涓烘偍鏈嶅姟', + chatType: 0, + uid: '1002' + }) + chatList.value.push({ + headImg: chatGPTHeadImg, + name: '鍗ч緳', + time: new Date().toLocaleTimeString(), + msg: route.query.keyWord, + chatType: 0, + uid: '1001' + }) + // 娣诲姞涓�涓┖鐨勫洖澶嶆秷鎭崰浣� + const replyMsg = { + headImg: chatGPTHeadImg, + name: '灏忔櫤', + time: new Date().toLocaleTimeString(), + msg: '', + chatType: 0, + uid: '1002' + } + chatList.value.push(replyMsg) + scrollBottom() + + // 濡傛灉鏈夋煡璇㈠叧閿瓧锛屽垯妯℃嫙娴佸紡杈撳嚭 + if (route.query.keyWord) { + simulateStreamingOutput(replyMsg, route.query.keyWord) + } +}) +// 妯℃嫙娴佸紡杈撳嚭 +const simulateStreamingOutput = async (msgObj, keyWord) => { + loading.value = true + // 鐢熸垚0.8-1.3绉掍箣闂寸殑闅忔満寤惰繜 + const delay = Math.random() * 500 + 800 + + // 妯℃嫙鍥炲鍐呭锛堝疄闄呭簲鐢ㄤ腑搴斾粠API鑾峰彇锛� + const responseText = `鍏充簬"${keyWord}"鐨勯棶棰橈紝鎴戞潵涓烘偍瑙g瓟锛歕n` + checking(keyWord) + + isSend.value = true + + let index = 0 + setTimeout(() => { + const interval = setInterval(() => { + isSend.value = true + if (index < responseText.length) { + msgObj.msg += responseText.charAt(index) + index++ + isSend.value = false + scrollBottom() + } else { + clearInterval(interval) + isSend.value = false + loading.value = false + } + }, 50) // 姣�50ms杈撳嚭涓�涓瓧绗︼紝妯℃嫙娴佸紡鏁堟灉 + }, delay) + +} +</script> + +<style lang="scss" scoped> +.mobile-chat-wrapper { + display: flex; + flex-direction: column; + overflow: hidden; + height: 91vh; + position: relative; + background-color: white; + + .chat-history { + flex: 1 1 0; + overflow-y: auto; + } + + .chat-input-wrapper { + padding: 8px 16px 8px 8px; + position: absolute; + left: 0; + right: 0; + bottom: 0; + .file-tt{ + flex-direction: column; + width: 200px; + display: flex; + padding: 5px; + border-radius: 5px; + margin-right: 5px; + background: #cacaca; + .file-item{ + width: 200px; + overflow:hidden; + word-wrap: break-word; + text-overflow:ellipsis; + display:-webkit-box; + -webkit-box-orient:vertical; + -webkit-line-clamp:2; + } + } + + .send-icon { + height: 40px; + margin-left: 16px; + } + .input-text{ + font-size: 18px; + width: 100%; + border-radius: 20px; + height: 80px; + padding-left: 10px; + //padding-top: 10px; + border: none; + color: black; /* 淇敼鏂囨湰棰滆壊涓虹櫧鑹� */ + background-color: #f5f4f4; /* 淇敼鑳屾櫙棰滆壊涓烘繁鐏拌壊 */ + } + } + + .chat-content { + width: 100%; + height: 80%; + overflow-y: scroll; + padding: 20px; + box-sizing: border-box; + + &::-webkit-scrollbar { + width: 0; + /* Safari,Chrome 闅愯棌婊氬姩鏉� */ + height: 0; + /* Safari,Chrome 闅愯棌婊氬姩鏉� */ + display: none; + /* 绉诲姩绔�乸ad 涓奡afari锛孋hrome锛岄殣钘忔粴鍔ㄦ潯 */ + } + + .chat-wrapper { + position: relative; + word-break: break-all; + + .chat-friend { + width: 100%; + float: left; + margin-bottom: 20px; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + + .chat-text { + max-width: 90%; + padding: 20px; + border-radius: 20px 20px 20px 5px; + background-color: rgb(245, 248, 248); + color: black; + + &:hover { + background-color: rgb(232, 232, 232); + } + + pre { + white-space: break-spaces; + } + } + + .chat-img { + img { + width: 100px; + height: 100px; + } + } + + .info-time { + margin: 10px 0; + color: black; + font-size: 14px; + + img { + width: 30px; + height: 30px; + border-radius: 50%; + vertical-align: middle; + margin-right: 10px; + } + + span:last-child { + color: rgb(101, 104, 115); + margin-left: 10px; + vertical-align: middle; + } + } + } + + .chat-me { + width: 100%; + float: right; + margin-bottom: 20px; + position: relative; + display: flex; + flex-direction: column; + justify-content: flex-end; + align-items: flex-end; + + .chat-text { + float: right; + max-width: 90%; + padding: 20px; + border-radius: 20px 20px 5px 20px; + background-color: rgb(29, 144, 245); + color: #fff; + + &:hover { + background-color: rgb(26, 129, 219); + } + } + + .chat-img { + img { + max-width: 300px; + max-height: 200px; + border-radius: 10px; + } + } + + .info-time { + margin: 10px 0; + color: black; + font-size: 14px; + display: flex; + justify-content: flex-end; + + img { + width: 30px; + height: 30px; + border-radius: 50%; + vertical-align: middle; + margin-left: 10px; + } + + span { + line-height: 30px; + } + + span:first-child { + color: rgb(101, 104, 115); + margin-right: 10px; + vertical-align: middle; + } + } + } + } + } + .flash_cursor { + width: 20px; + height: 30px; + display: inline-block; + background: #d6e3f5; + opacity: 1; + animation: glow 800ms ease-out infinite alternate; + } + @keyframes glow { + 0% { + opacity: 1; + } + + 25% { + opacity: 0.5; + } + + 50% { + opacity: 0; + } + + 75% { + opacity: 0.5; + } + + 100% { + opacity: 1; + } + } +} +</style> diff --git a/src/views/chatHome/chatHomeIndex/ai-jz.js b/src/views/chatHome/chatHomeIndex/ai-jz.js new file mode 100644 index 0000000..02ee6dc --- /dev/null +++ b/src/views/chatHome/chatHomeIndex/ai-jz.js @@ -0,0 +1,3 @@ +export function jam() { + return "" +} \ No newline at end of file diff --git a/src/views/chatHome/chatHomeIndex/ai-wd.js b/src/views/chatHome/chatHomeIndex/ai-wd.js new file mode 100644 index 0000000..c5b83d5 --- /dev/null +++ b/src/views/chatHome/chatHomeIndex/ai-wd.js @@ -0,0 +1,393 @@ +export function gasLeaks() { + return "1. 璁捐涓庤澶囬�夋嫨\n" + + "閫夌敤楂樿川閲忔潗鏂欙細绠¢亾銆侀榾闂ㄣ�佸偍缃愮瓑璁惧搴旈�夌敤鑰愯厫铓�銆佽�愰珮鍘嬬殑鏉愭枡锛屽苟绗﹀悎瀹夊叏鏍囧噯锛堝ASME銆丄PI绛夛級銆俓n" + + "\n" + + "瀹夊叏璁捐锛歕n" + + "\n" + + "瀹夎鍐椾綑鐨勫畨鍏ㄨ缃紙濡傚弻閲嶉榾闂ㄣ�佺垎鐮寸墖銆佸畨鍏ㄩ榾绛夛級銆俓n" + + "\n" + + "璁剧疆姘斾綋娉勬紡妫�娴嬬郴缁燂紙濡傚彲鐕冩皵浣撴姤璀﹀櫒銆佹湁姣掓皵浣撲紶鎰熷櫒锛夈�俓n" + + "\n" + + "閲囩敤灏侀棴寮忕郴缁熻璁★紝鍑忓皯寮�鏀炬帴鍙c�俓n" + + "\n" + + "閫氶绯荤粺锛氬湪鍙兘娉勬紡鐨勫尯鍩熷畨瑁呭己鍒堕�氶璁惧锛岄槻姝㈡皵浣撹仛闆嗐�俓n" + + "\n" + + "2. 瀹夎涓庣淮鎶n" + + "瑙勮寖瀹夎锛氱敱涓撲笟浜哄憳杩涜璁惧瀹夎锛岀‘淇濈閬撶剨鎺ャ�佸瘑灏佺瓑鐜妭鏃犵己闄枫�俓n" + + "\n" + + "瀹氭湡妫�鏌ワ細\n" + + "\n" + + "瀵圭閬撱�侀榾闂ㄣ�佽繛鎺ュ杩涜娉勬紡妫�娴嬶紙濡傚帇鍔涙祴璇曘�佽秴澹版尝妫�娴嬨�佽偉鐨傛按妫�婕忥級銆俓n" + + "\n" + + "鏇存崲鑰佸寲鎴栬厫铓�鐨勯儴浠躲�俓n" + + "\n" + + "棰勯槻鎬х淮鎶わ細鍒跺畾缁存姢璁″垝锛屽畾鏈熸鼎婊戦榾闂ㄣ�佹洿鎹㈠瘑灏佷欢绛夈�俓n" + + "\n" + + "3. 鎿嶄綔绠$悊\n" + + "涓ユ牸鎿嶄綔瑙勭▼锛歕n" + + "\n" + + "鎿嶄綔浜哄憳闇�鍩硅涓婂矖锛岀啛鎮夋皵浣撶壒鎬у拰搴旀�ユ祦绋嬨�俓n" + + "\n" + + "閬垮厤瓒呭帇銆佽秴娓╂垨閿欒鎿嶄綔銆俓n" + + "\n" + + "鐩戞帶绯荤粺锛歕n" + + "\n" + + "瀹炴椂鐩戞祴鍘嬪姏銆佹俯搴︺�佹祦閲忕瓑鍙傛暟锛岃缃嚜鍔ㄦ姤璀﹀拰鑱旈攣鍋滄満瑁呯疆銆俓n" + + "\n" + + "浣跨敤姘斾綋妫�娴嬩华锛堝绾㈠銆佺數鍖栧浼犳劅鍣級鐩戞祴鐜娴撳害銆俓n" + + "\n" + + "鏄庣‘鏍囪瘑锛氬湪鍗遍櫓鍖哄煙鏍囨槑姘斾綋绫诲瀷銆侀闄╃瓑绾у強闃叉姢瑕佹眰銆俓n" + + "\n" + + "4. 娉勬紡搴旀�ユ帾鏂絓n" + + "搴旀�ヨ澶囷細\n" + + "\n" + + "閰嶅闃叉瘨闈㈠叿銆佸懠鍚稿櫒銆侀槻鎶ゆ湇绛変釜浜洪槻鎶よ澶囷紙PPE锛夈�俓n" + + "\n" + + "灏辫繎鏀剧疆娉勬紡搴旀�ュ寘锛堝鍫垫紡鑳躲�佸瘑灏佸甫锛夈�俓n" + + "\n" + + "绱ф�ュ搷搴旓細\n" + + "\n" + + "绔嬪嵆鍒囨柇姘旀簮锛堝叧闂笂娓搁榾闂ㄦ垨鍚姩绱ф�ュ垏鏂郴缁燂級銆俓n" + + "\n" + + "鍚姩閫氶璁惧绋�閲婃皵浣撴祿搴︺�俓n" + + "\n" + + "鐤忔暎浜哄憳骞朵笂鎶ヤ笓涓氶儴闂紙濡傛秷闃层�佺幆淇濓級銆俓n" + + "\n" + + "搴旀�ラ妗堬細瀹氭湡婕旂粌娉勬紡澶勭疆娴佺▼锛岀‘淇濅汉鍛樼啛鎮夊垎宸ャ�俓n" + + "\n" + + "5. 鍌ㄥ瓨涓庤繍杈撳畨鍏╘n" + + "鍌ㄥ瓨瑕佹眰锛歕n" + + "\n" + + "鍌ㄧ綈杩滅鐏簮銆侀珮娓╁尯锛屽苟璁剧疆鍥村牥闃叉鎵╂暎銆俓n" + + "\n" + + "娑插寲姘斾綋鍌ㄧ綈闇�閰嶅娉勫帇瑁呯疆銆俓n" + + "\n" + + "杩愯緭瀹夊叏锛歕n" + + "\n" + + "浣跨敤鍚堣鐨勮繍杈撹溅杈嗭紝鍥哄畾姘旂摱闃叉纰版挒銆俓n" + + "\n" + + "杩愯緭閫斾腑鐩戞帶杞﹁締鐘舵�侊紙濡侴PS銆佹俯搴︿紶鎰熷櫒锛夈�俓n" + + "\n" + + "6. 浜哄憳鍩硅涓庢枃鍖朶n" + + "瀹夊叏鍩硅锛氬畾鏈熷紑灞曟皵浣撳嵄瀹炽�侀槻鎶ゆ帾鏂藉拰搴旀�ュ鐞嗙殑鍩硅銆俓n" + + "\n" + + "瀹夊叏鏂囧寲锛氶紦鍔卞憳宸ユ姤鍛婃綔鍦ㄩ闄╋紝寤虹珛鈥滈浂娉勬紡鈥濈鐞嗙洰鏍囥�俓n" + + "\n" + + "7. 娉曡涓庢爣鍑哱n" + + "閬靛畧鐩稿叧娉曡锛堝OSHA銆丟B 50493銆婄煶娌瑰寲宸ュ彲鐕冩皵浣撳拰鏈夋瘨姘斾綋妫�娴嬫姤璀﹁璁¤鑼冦�嬶級銆俓n" + + "\n" + + "瀹氭湡杩涜瀹夊叏瀹¤锛岀‘淇濈鍚堣涓氭爣鍑嗐�俓n" + + "\n" + + "甯歌鍗遍櫓姘斾綋娉勬紡鐨勯拡瀵规�ф帾鏂絓n" + + "鍙噧姘斾綋锛堝鐢茬兎銆佹阿姘旓級锛氶槻鐖嗙數鍣ㄣ�佹秷闄ら潤鐢点�俓n" + + "\n" + + "鏈夋瘨姘斾綋锛堝姘皵銆佺~鍖栨阿锛夛細閰嶅涓撶敤杩囨护寮忔垨渚涙哀寮忓懠鍚稿櫒銆俓n" + + "\n" + + "绐掓伅鎬ф皵浣擄紙濡傛爱姘斻�佷簩姘у寲纰筹級锛氱洃娴嬫哀姘旀祿搴︼紝閬垮厤瀵嗛棴绌洪棿浣滀笟銆俓n" + + "\n" + + "閫氳繃浠ヤ笂鎺柦鐨勭患鍚堝簲鐢紝鍙ぇ骞呴檷浣庢皵浣撴硠婕忛闄╋紝淇濋殰浜哄憳瀹夊叏鍜岀幆澧冨仴搴枫�傝嫢鍙戠敓娉勬紡锛岄渶浼樺厛纭繚浜哄憳鎾ょ锛屽啀鐢变笓涓氫汉鍛樺缃�俓n" + + "\n" + + "鏈洖绛旂敱 AI 鐢熸垚锛屽唴瀹逛粎渚涘弬鑰冿紝璇蜂粩缁嗙攧鍒��" +} + +export function shipping() { + return "涓�銆佺珛鍗冲簲鎬ュ搷搴擻n" + + "1. 鍙戠幇娉勬紡鏃剁殑绱ф�ヨ鍔╘n" + + "鍋滆溅骞堕殧绂荤幇鍦猴細\n" + + "\n" + + "杩愯緭杞﹁締绔嬪嵆鍋滈潬鍦ㄧ┖鏃枫�佽繙绂讳汉缇ゅ拰鐏簮鐨勪綅缃�俓n" + + "\n" + + "璁剧疆璀︽垝绾匡紙鑷冲皯50~100绫冲崐寰勶紝鏍规嵁姘斾綋鎬ц川璋冩暣锛夛紝绂佹鏃犲叧浜哄憳杩涘叆銆俓n" + + "\n" + + "鍒囨柇娉勬紡婧愶細\n" + + "\n" + + "鍏抽棴瀹瑰櫒闃�闂ㄦ垨灏佸牭鐮存崯澶勶紙濡備娇鐢ㄥ簲鎬ュ牭婕忓伐鍏凤級銆俓n" + + "\n" + + "鑻ラ榾闂ㄦ崯鍧忥紝灏濊瘯杞Щ鍓╀綑姘斾綋鑷冲鐢ㄥ鍣紙闇�涓撲笟浜哄憳鎿嶄綔锛夈�俓n" + + "\n" + + "鎶ヨ涓庝笂鎶ワ細\n" + + "\n" + + "鎷ㄦ墦搴旀�ョ數璇濓紙濡傛秷闃�119銆佺幆淇濋儴闂級锛岃鏄庢皵浣撶被鍨嬨�佹硠婕忛噺銆佷綅缃瓑淇℃伅銆俓n" + + "\n" + + "鑱旂郴杩愯緭鍏徃鍙婅揣涓伙紝鑾峰彇鎶�鏈敮鎻达紙濡侻SDS瀹夊叏鏁版嵁琛級銆俓n" + + "\n" + + "2. 浜哄憳闃叉姢涓庣枏鏁n" + + "绌挎埓闃叉姢瑁呭锛歕n" + + "\n" + + "鍙噧姘斾綋锛氶槻鐖嗗伐鍏�+闃查潤鐢垫湇锛涙湁姣掓皵浣擄細姝e帇寮忓懠鍚稿櫒+闃插寲鏈嶃�俓n" + + "\n" + + "鏃犻槻鎶よ澶囨椂锛岀珛鍗虫挙绂昏嚦涓婇鏂瑰悜銆俓n" + + "\n" + + "鐤忔暎鍛ㄨ竟鍖哄煙锛歕n" + + "\n" + + "鏍规嵁姘斾綋鎵╂暎鑼冨洿锛堝弬鑰冨簲鎬ュ搷搴旀寚鍗桬RG锛夌枏鏁e眳姘戞垨浣滀笟浜哄憳銆俓n" + + "\n" + + "閬垮厤浣庢醇澶勬粸鐣欙紙鏌愪簺姘斾綋姣旂┖姘旈噸锛屽纭寲姘級銆俓n" + + "\n" + + "3. 鎺у埗娉勬紡鎵╂暎\n" + + "鐗╃悊鏂规硶锛歕n" + + "\n" + + "瑕嗙洊娉勬紡鍙o紙濡傜敤娴告按妫夎鍑忓皯鎸ュ彂锛屼絾绂佺敤浜庨亣姘村弽搴旀皵浣撳姘皵锛夈�俓n" + + "\n" + + "绛戝牑鍥村牭娑蹭綋娉勬紡鐗╋紝闃叉娴佸叆涓嬫按閬撴垨娌虫祦銆俓n" + + "\n" + + "鍖栧鏂规硶锛歕n" + + "\n" + + "涓拰澶勭悊锛堝姘ㄦ皵娉勬紡鍠锋磼绋�鐩愰吀锛岄渶涓撲笟浜哄憳鎿嶄綔锛夈�俓n" + + "\n" + + "浣跨敤鍚搁檮鏉愭枡锛堝娲绘�х偔銆佹矙鍦熷惛闄勬湁鏈烘皵浣擄級銆�" +} + +export function operate(){ + return "涓�銆佹搷浣滀笉褰撳彂鐢熷悗鐨勫簲鎬ュ鐞哱n" + + "1. 绔嬪嵆鎺у埗浜嬫晠\n" + + "鍋滄鎿嶄綔锛歕n" + + "\n" + + "鎸変笅绱ф�ュ仠鏈烘寜閽紝鍏抽棴鏈�杩戠殑涓婃父闃�闂ㄣ�俓n" + + "\n" + + "鍚姩搴旀�ラ妗堬細\n" + + "\n" + + "灏忓瀷娉勬紡锛氫娇鐢ㄥ簲鎬ュ牭婕忓伐鍏凤紙濡傚瘑灏佽兌銆佸す鍏凤級銆俓n" + + "\n" + + "澶у瀷娉勬紡锛氱枏鏁d汉鍛橈紝鎶ヨ姹傚姪锛�119/鐜繚閮ㄩ棬锛夈�俓n" + + "\n" + + "2. 浜哄憳瀹夊叏\n" + + "鎾ょ涓庨殧绂伙細\n" + + "\n" + + "閫嗛鎾ょ鑷充笂椋庡悜瀹夊叏鍖猴紝閬垮厤浣庢醇澶勶紙閲嶆皵浣撶Н鑱氾級銆俓n" + + "\n" + + "鎬ユ晳鎺柦锛歕n" + + "\n" + + "鍚稿叆鏈夋瘨姘斾綋锛氱Щ鑷崇┖姘旀柊椴滃锛屽繀瑕佹椂浜哄伐鍛煎惛銆俓n" + + "\n" + + "鐨偆鎺ヨЕ锛氱珛鍗崇敤娓呮按鍐叉礂15鍒嗛挓锛堣厫铓�鎬ф皵浣擄級銆俓n" + + "\n" + + "3. 浜嬫晠璋冩煡涓庢暣鏀筡n" + + "鏍规湰鍘熷洜鍒嗘瀽锛圧CA锛夛細\n" + + "\n" + + "鏄搷浣滃け璇�佸煿璁笉瓒筹紝杩樻槸璁惧缂洪櫡锛焅n" + + "\n" + + "鏀硅繘鎺柦锛歕n" + + "\n" + + "淇鎿嶄綔瑙勭▼锛屽鍔犺绀烘爣璇嗐�俓n" + + "\n" + + "瀵硅矗浠讳汉鍐嶅煿璁紝蹇呰鏃惰皟宀椼��" +} + +export function emergency(){ + return "涓�銆佷紭鍖栧簲鎬ュ搷搴旂殑鍏抽敭鎺柦\n" + + "1. 瀹屽杽搴旀�ラ妗圽n" + + "閽堝鎬ц璁★細\n" + + "\n" + + "鍩轰簬HAZOP锛堝嵄闄╀笌鍙搷浣滄�у垎鏋愶級璇嗗埆鎵�鏈夋綔鍦ㄩ闄╁満鏅�俓n" + + "\n" + + "鍒跺畾鍒嗙骇鍝嶅簲鏈哄埗锛堝皬娉勬紡鐜板満澶勭疆銆佸ぇ娉勬紡鍏ㄥ憳鐤忔暎锛夈�俓n" + + "\n" + + "鏄庣‘鑱岃矗锛歕n" + + "\n" + + "璁剧珛搴旀�ユ寚鎸ラ儴锛屾寚瀹氭�绘寚鎸ャ�侀�氳缁勩�佹姠闄╃粍銆佸尰鐤楃粍绛夈�俓n" + + "\n" + + "纭繚24灏忔椂鍊肩彮鍒跺害锛岃仈绯绘柟寮忓疄鏃舵洿鏂般�俓n" + + "\n" + + "鑱斿姩澶栭儴璧勬簮锛歕n" + + "\n" + + "涓庢秷闃层�佺幆淇濄�佸尰闄㈡彁鍓嶇璁㈡晳鎻村崗璁紝鏄庣‘鍗忎綔娴佺▼銆俓n" + + "\n" + + "2. 寮哄寲搴旀�ヨ祫婧愪繚闅淺n" + + "瑁呭涓庣墿璧勶細\n" + + "\n" + + "閰嶅瓒抽噺涓旀湁鏁堢殑搴旀�ヨ澶囷紝鍖呮嫭锛歕n" + + "\n" + + "涓汉闃叉姢瑁呭锛圥PE锛夛細闃叉瘨闈㈠叿銆佸寲瀛﹂槻鎶ゆ湇銆俓n" + + "\n" + + "鍫垫紡宸ュ叿锛氬瘑灏佽兌銆佸す鍏枫�佸揩閫熷皝鍫靛櫒銆俓n" + + "\n" + + "鍚搁檮/涓拰鏉愭枡锛氭椿鎬х偔銆佹矙鍦熴�佺█纰辨恫锛堢敤浜庨吀鎬ф皵浣擄級銆俓n" + + "\n" + + "瀹氭湡妫�鏌ャ�佺淮鎶ゅ拰鏇存崲锛堝姘旂摱鍘嬪姏銆佷紶鎰熷櫒鐢垫睜锛夈�俓n" + + "\n" + + "搴旀�ヨ溅杈嗕笌閫氶亾锛歕n" + + "\n" + + "纭繚鏁戞彺杞﹁締鍙揩閫熸姷杈炬硠婕忕偣锛堟竻闄よ矾闅滐紝鏍囪瘑搴旀�ヨ矾绾匡級銆俓n" + + "\n" + + "鍏抽敭鍖哄煙璁剧疆搴旀�ユ礂鐪煎櫒銆佸柗娣嬬郴缁熴�俓n" + + "\n" + + "3. 鍔犲己浜哄憳鍩硅涓庤兘鍔涘缓璁綷n" + + "鍒嗗眰鍩硅锛歕n" + + "\n" + + "鍩哄眰浜哄憳锛氭帉鎻″熀鏈簲鎬ュ缃紙濡傚叧闂榾闂ㄣ�佷娇鐢ㄧ伃鐏櫒锛夈�俓n" + + "\n" + + "搴旀�ュ皬缁勶細涓撲笟鍫垫紡銆佷激鍛樻�ユ晳銆佹皵浣撴娴嬫妧鑳姐�俓n" + + "\n" + + "绠$悊灞傦細鎸囨尌鍐崇瓥銆佸獟浣撴矡閫氥�佹硶寰嬪悎瑙勩�俓n" + + "\n" + + "瀹炴垬鍖栬�冩牳锛歕n" + + "\n" + + "閫氳繃妯℃嫙绐佸彂娉勬紡锛堝鐩叉紨锛夋楠屽搷搴旈�熷害銆俓n" + + "\n" + + "涓嶅悎鏍艰�呴渶閲嶆柊鍩硅銆俓n" + + "\n" + + "4. 瀹氭湡婕旂粌涓庢寔缁敼杩沑n" + + "婕旂粌棰戠巼锛歕n" + + "\n" + + "姣忓搴﹁嚦灏�1娆℃闈㈡帹婕旓紝姣忓勾2娆$患鍚堝疄鎴樻紨缁冦�俓n" + + "\n" + + "鍦烘櫙璁捐锛歕n" + + "\n" + + "妯℃嫙澶嶆潅鎯呭喌锛堝澶滈棿鍋滅數銆佸浜哄彈浼わ級銆俓n" + + "\n" + + "寮曞叆鈥滅獊鍙戝彉閲忊�濓紙濡傞鍚戠獊鍙樸�佷簩娆℃硠婕忥級銆俓n" + + "\n" + + "澶嶇洏涓庝紭鍖栵細\n" + + "\n" + + "璁板綍婕旂粌涓殑闂锛堝閫氳寤惰繜銆佽澶囩己澶憋級銆俓n" + + "\n" + + "鏇存柊棰勬骞朵笅鍙戝涔犮�俓n" + + "\n" + + "5. 鎶�鏈崌绾т笌鏅鸿兘鍖栨敮鎸乗n" + + "瀹炴椂鐩戞祴涓庨璀︼細\n" + + "\n" + + "閮ㄧ讲鐗╄仈缃戯紙IoT锛変紶鎰熷櫒锛岀洃娴嬫皵浣撴祿搴︺�佽澶囩姸鎬併�俓n" + + "\n" + + "璁剧疆鑷姩鑱旈攣鎺у埗锛堝娉勬紡鏃惰仈鍔ㄥ叧闂榾闂ㄥ苟鍚姩閫氶锛夈�俓n" + + "\n" + + "搴旀�ラ�氳绯荤粺锛歕n" + + "\n" + + "浣跨敤闃茬垎瀵硅鏈恒�佸崼鏄熺數璇濓紙淇濋殰淇″彿瑕嗙洊锛夈�俓n" + + "\n" + + "寤虹珛搴旀�ュ箍鎾郴缁燂紙濡傚巶鍖鸿鎶ャ�佺煭淇$兢鍙戯級銆俓n" + + "\n" + + "鏁板瓧鍖栭妗堬細\n" + + "\n" + + "灏嗗簲鎬ラ妗堝綍鍏ョЩ鍔ㄧ粓绔紝瀹炵幇涓�閿皟闃呫�佹楠ゆ寚寮曘��" +} + +export function compliance(){ + return "涓�銆佸父瑙佺殑鍚堣鎬ч棶棰榎n" + + "1. 璁稿彲涓庤祫璐ㄧ己澶盶n" + + "闂锛歕n" + + "\n" + + "鏈彇寰楀嵄闄╁寲瀛﹀搧缁忚惀璁稿彲璇佹垨瀹夊叏鐢熶骇璁稿彲璇併�俓n" + + "\n" + + "鐗圭浣滀笟浜哄憳锛堝鍘嬪姏瀹瑰櫒鎿嶄綔宸ワ級鏃犺瘉涓婂矖銆俓n" + + "\n" + + "椋庨櫓锛歕n" + + "\n" + + "鐩戠閮ㄩ棬澶勭綒锛堝缃氭銆佽矗浠ゅ仠浜э級銆俓n" + + "\n" + + "淇濋櫓鎷掕禂锛堜簨鏁呭彂鐢熸椂锛夈�俓n" + + "\n" + + "2. 瀹夊叏璁捐涓嶈揪鏍嘰n" + + "闂锛歕n" + + "\n" + + "鍌ㄧ綈銆佺閬撴湭鎸塆B/T 150锛堝帇鍔涘鍣ㄦ爣鍑嗭級璁捐銆俓n" + + "\n" + + "鏈畨瑁呭彲鐕�/鏈夋瘨姘斾綋鎶ヨ鍣紙杩濆弽GB 50493锛夈�俓n" + + "\n" + + "椋庨櫓锛歕n" + + "\n" + + "璁惧澶辨晥瀵艰嚧娉勬紡鎴栫垎鐐搞�俓n" + + "\n" + + "涓嶇鍚堝簲鎬ョ鐞嗛儴鎴朞SHA妫�鏌ヨ姹傘�俓n" + + "\n" + + "3. 鎿嶄綔涓庣淮鎶よ繚瑙刓n" + + "闂锛歕n" + + "\n" + + "鏈墽琛屼綔涓氱エ鍒跺害锛堝鍔ㄧ伀浣滀笟鏈鎵癸級銆俓n" + + "\n" + + "鏈畾鏈熸楠屽帇鍔涘鍣紙杩濆弽TSG 21-2016锛夈�俓n" + + "\n" + + "椋庨櫓锛歕n" + + "\n" + + "杩濊鎿嶄綔寮曞彂浜嬫晠锛堝鐒婃帴寮曞彂鍙噧姘斾綋鐖嗙偢锛夈�俓n" + + "\n" + + "璁惧鑰佸寲瀵艰嚧绐佸彂娉勬紡銆俓n" + + "\n" + + "4. 搴旀�ョ鐞嗕笉鍚堣\n" + + "闂锛歕n" + + "\n" + + "鏈埗瀹氬簲鎬ラ妗堟垨鏈妗堬紙杩濆弽銆婄敓浜у畨鍏ㄤ簨鏁呭簲鎬ユ潯渚嬨�嬶級銆俓n" + + "\n" + + "鏈厤澶囧簲鎬ョ墿璧勶紙濡傞槻姣掗潰鍏枫�佸牭婕忓伐鍏凤級銆俓n" + + "\n" + + "椋庨櫓锛歕n" + + "\n" + + "浜嬫晠鍙戠敓鏃舵棤娉曟湁鏁堟帶鍒讹紝瀵艰嚧鎹熷け鎵╁ぇ銆俓n" + + "\n" + + "闈复鐢熸�佺幆澧冮儴杩借矗锛堝鍖栧鍝佹薄鏌撳湡澹�/姘翠綋锛夈�俓n" + + "\n" + + "5. 璁板綍涓庢姤鍛婄己澶盶n" + + "闂锛歕n" + + "\n" + + "鏈繚瀛樺畨鍏ㄦ鏌ヨ褰曟垨鍩硅妗f銆俓n" + + "\n" + + "鏈寜瑙勫畾涓婃姤娉勬紡浜嬫晠锛堝鐬掓姤銆佽繜鎶ワ級銆俓n" + + "\n" + + "椋庨櫓锛歕n" + + "\n" + + "浜嬫晠璋冩煡鏃舵棤娉曡嚜璇佸悎瑙勶紝鎵挎媴鍏ㄨ矗銆俓n" + + "\n" + + "琚垪鍏ュ畨鍏ㄧ敓浜ч粦鍚嶅崟锛屽奖鍝嶄紒涓氫俊瑾夈��" +} + +export function monitoring(){ + return "涓�銆佸浐瀹氬紡鐩戞祴鎶�鏈痋n" + + "1. 鍌寲鐕冪儳寮忎紶鎰熷櫒\n" + + "鍘熺悊锛氬彲鐕冩皵浣撳湪閾備笣琛ㄩ潰鐕冪儳瀵艰嚧鐢甸樆鍙樺寲\n" + + "\n" + + "浼樺娍锛氭垚鏈綆锛堬骏500-2000/涓級銆佸搷搴斿揩锛�<10s锛塡n" + + "\n" + + "灞�闄愶細鏄撲腑姣掞紙纭�/纭寲鍚堢墿锛夈�佸鍛界煭锛�2-3骞达級\n" + + "\n" + + "閫傜敤锛氱煶鍖栧巶鍙噧姘旂洃娴嬶紙鐢茬兎銆佹阿姘旂瓑锛塡n" + + "\n" + + "2. 鐢靛寲瀛︿紶鎰熷櫒\n" + + "鍘熺悊锛氭皵浣撲笌鐢佃В娑插彂鐢熸哀鍖栬繕鍘熷弽搴斾骇鐢熺數娴乗n" + + "\n" + + "浼樺娍锛歱pb绾ф娴嬶紙濡侶2S妫�娴嬩笅闄�0.1ppm锛塡n" + + "\n" + + "灞�闄愶細鍙楁俯婀垮害褰卞搷锛堥渶瀹氭湡鏍″噯锛塡n" + + "\n" + + "閫傜敤锛氭湁姣掓皵浣擄紙Cl鈧傘�丯H鈧冦�丆O绛夛級\n" + + "\n" + + "3. 绾㈠鍚告敹寮忥紙NDIR锛塡n" + + "鍘熺悊锛氭皵浣撳鐗瑰畾绾㈠娉㈡鐨勫惛鏀剁巼妫�娴媆n" + + "\n" + + "浼樺娍锛氬厤鏍″噯锛堝鍛�5-10骞达級銆佹姉涓瘨\n" + + "\n" + + "灞�闄愶細楂樻垚鏈紙锟�5000+/涓級\n" + + "\n" + + "閫傜敤锛欳O鈧傘�丆H鈧勭瓑娓╁姘斾綋鐩戞祴\n" + + "\n" + + "4. 婵�鍏夊厜璋憋紙TDLAS锛塡n" + + "鍘熺悊锛氬彲璋冭皭婵�鍏変簩鏋佺鎵弿姘斾綋鍚告敹绾縗n" + + "\n" + + "浼樺娍锛歱pm绾х簿搴︺�佸搷搴攎s绾n" + + "\n" + + "灞�闄愶細闇�鍏夊瀵瑰噯锛堝畨瑁呭鏉傦級\n" + + "\n" + + "閫傜敤锛氱閬撳井娉勬紡妫�娴嬶紙澶╃劧姘旈暱杈撶绾匡級" +} + +export function checking(keyWord){ + if(keyWord.includes("姘斾綋娉勬紡")){ + return gasLeaks(); + } + if(keyWord.includes("瀹瑰櫒澶辨晥")){ + return shipping(); + } + if(keyWord.includes("鎿嶄綔涓嶅綋")){ + return operate(); + } + if(keyWord.includes("鍝嶅簲涓嶈冻")){ + return emergency(); + } + if(keyWord.includes("鍚堣鎬�")){ + return compliance(); + } + if(keyWord.includes("鐩戞祴鎶�鏈�")){ + return monitoring(); + } + return "涓嶅ソ鎰忔�濓紝灏忔櫤杩樺湪鎴愰暱杩囩▼涓紝鎮ㄧ殑闂宸茬粡瓒呰繃灏忔櫤鐨勫鐞嗚寖鍥翠簡銆�"; + +} \ No newline at end of file diff --git a/src/views/chatHome/chatHomeIndex/home.vue b/src/views/chatHome/chatHomeIndex/home.vue new file mode 100644 index 0000000..7796284 --- /dev/null +++ b/src/views/chatHome/chatHomeIndex/home.vue @@ -0,0 +1,175 @@ +<template> +<div class="home"> + <div style="background: white;color: black;font-size: 30px;" class="logo"> + <div class="logo-one" style="font-weight: bold"> +<!-- <img src="/src/assets/img/logo.png" style="width: 50px;height: 50px;margin: 0 10px" />--> + <div><i>澶фā鍨婣I灏忔櫤姝e湪涓烘偍鏈嶅姟</i></div> + </div> + <div class="input"> + <input type="text" v-model="keyWord" class="input-text" placeholder="缁欏皬鏅哄彂閫佹秷鎭�" @keyup.enter="sendMsg" /> + <div style="font-size: 13px;color: #808080;display: flex;justify-content: space-between;padding: 10px;"> + <div style="display: flex;justify-content: center;align-items: center;"> +<!-- <div style="display: flex;justify-content: center;align-items: center;">--> +<!-- <img src="/src/assets/img/logo.png" style="width: 15px;height: 15px;margin: 0 5px" />--> +<!-- <span>娣卞害鎬濊��(R1)</span>--> +<!-- </div>--> +<!-- <div style="display: flex;justify-content: center;align-items: center;">--> +<!-- <img src="/src/assets/img/logo.png" style="width: 15px;height: 15px;margin: 0 5px" />--> +<!-- <span>鑱旂綉鎼滅储</span>--> +<!-- </div>--> + </div> + <div style="display: flex;justify-content: center;align-items: center;margin-right: 5px;"> +<!-- <img src="/src/assets/img/logo.png" style="width: 25px;height: 25px;margin: 0 5px" />--> + <img src="@/assets/img/emoji/rocket.png" style="width: 25px;height: 25px;margin: 0 5px" @click="sendMsg"/> + </div> + </div> + </div> + <div style="width: 780px;"> + <div style="font-weight: bold;margin: 30px 0;">鐑棬鎺ㄨ崘</div> + <div class="keywords"> + <div class="keywordss" @click="sendMsgDefault(keyWordOne)"> + <p class="fontSize aaa">{{keyWordOne}}</p> + <p class="fontSize">闃�闂ㄣ�佺閬撴垨瀹瑰櫒瀵嗗皝澶辨晥瀵艰嚧姘斾綋娉勬紡锛堝姘皵銆佹皑姘旓級銆�</p> + <p class="fontSize">鍚庢灉锛氫腑姣掋�佺垎鐐搞�佺幆澧冩薄鏌撱��</p> + </div> + <div class="keywordss" @click="sendMsgDefault(keyWordTwo)"> + <p class="fontSize aaa">{{keyWordTwo}}</p> + <p class="fontSize">閽㈢摱鎴栫綈浣撳洜鏉愭枡鐤插姵銆佽厫铓�鎴栬秴鍘嬬牬瑁�</p> + <p class="fontSize">鍘熷洜锛氭湭瀹氭湡妫�娴嬨�佽繚瑙勫厖瑁呮垨澶栭儴鎾炲嚮銆傘��</p> + </div> + </div> + <div class="keywords"> + <div class="keywordss" @click="sendMsgDefault(keyWordFive)"> + <p class="fontSize aaa">{{keyWordFive}}</p> + <p class="fontSize">瑁呭嵏杩囩▼涓繚瑙勬搷浣滐紙濡傞噹铔惉杩愩�佹贩瑁呯蹇岀墿璐級銆�</p> + <p class="fontSize">杩愯緭閫斾腑鏈浐瀹氬鍣紝瀵艰嚧纰版挒鎴栧�惧�掋��</p> + </div> + <div class="keywordss" @click="sendMsgDefault(keyWordSix)"> + <p class="fontSize aaa">{{keyWordSix}}</p> + <p class="fontSize">缂轰箯娉勬紡搴旀�ラ妗堬紝浜哄憳鍩硅涓嶈冻銆�</p> + <p class="fontSize">鏁戞彺璁惧锛堝闃叉瘨闈㈠叿銆佸牭婕忓伐鍏凤級缂哄け鎴栧け鏁堛��</p> + </div> + </div> + <div class="keywords"> + <div class="keywordss" @click="sendMsgDefault(keyWordServen)"> + <p class="fontSize aaa">{{keyWordServen}}</p> + <p class="fontSize">鏈彇寰楄繍杈撹祫璐紙濡侫DR/RID绛夊浗闄呰鑼冿級銆�</p> + <p class="fontSize">璺嚎瑙勫垝涓嶅悎瑙勶紙濡傜┛瓒婁汉鍙e瘑闆嗗尯锛夈��</p> + </div> + <div class="keywordss" @click="sendMsgDefault(keyWordEight)"> + <p class="fontSize aaa">{{keyWordEight}}</p> + <p class="fontSize">浼犳劅鍣ㄩ儴缃诧紙濡傜孩澶栨皵浣撴帰娴嬪櫒銆佺數鍖栧浼犳劅鍣級銆�</p> + <p class="fontSize">瀹炴椂鏁版嵁浼犺緭鑷崇洃鎺у钩鍙帮紝瑙﹀彂鎶ヨ銆�</p> + </div> + </div> + </div> + </div> + + <div></div> +</div> +</template> + +<script setup> +import { ref,onMounted } from "vue"; +import {useRoute,useRouter} from "vue-router" +const route = useRoute(); +const router = useRouter(); +const keyWord = ref(''); +const keyWordOne = ref('鍗遍櫓姘斾綋娉勬紡鎬庝箞鍔�'); +const keyWordTwo = ref('杩愯緭瀹瑰櫒澶辨晥鎬庝箞鍔�'); +const keyWordFive = ref('鎿嶄綔涓嶅綋鎬庝箞鍔�'); +const keyWordSix = ref('搴旀�ュ搷搴斾笉瓒虫�庝箞鍔�'); +const keyWordServen = ref('鍚堣鎬ч棶棰�'); +const keyWordEight = ref('娉勬紡鐩戞祴鎶�鏈湁鍝簺'); + +const sendMsg = () => { + router.push({ path: '/main/MobileChat',query:{ keyWord: keyWord.value} }) +} + +const sendMsgDefault = (value) => { + router.push({ path: '/main/MobileChat',query:{ keyWord: value} }) +} + +</script> + +<style lang="scss" scoped> +.home { + width: 100%; + height: 91vh; + display: flex; + flex-direction: column; + align-items: center; + + .logo { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + z-index: 99; + width: 100%; + height: 100%; + color: #fff; + cursor: pointer; + overflow: hidden; + background-color: #F0F6F9; + + .keywords { + display: flex; + width: 100%; + height: 90px; + line-height: 80px; + justify-content: space-between; + margin: 10px 0; + + .keywordss { + box-shadow: 0px 2px 5px #b8b8b8; + width: 48%; + background: #e0edfc; + border-radius: 10px; + + .aaa { + font-weight: bold; + font-size: 15px !important; + } + + .fontSize { + font-size: 13px; + height: 20px; + line-height: 20px; + margin: 6px; + } + } + } + + .logo-one { + display: flex; + justify-content: center; + align-items: center; + margin-bottom: 20px; + } + + .input { + width: 780px; + height: 150px; + background: #f5f4f4; + border-radius: 20px; + + .input-text { + font-size: 18px; + width: 568px; + border-radius: 20px 20px 0 0; + height: 90px; + padding-left: 10px; + border: none; + color: black; + background-color: #f5f4f4; + } + + .input-text:focus { + outline: none; + border: none; + } + } + } +} +</style> diff --git a/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue b/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue index 847f4c4..403cab6 100644 --- a/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue +++ b/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue @@ -102,6 +102,10 @@ <div v-if="!activity.isShen" class="node-reason"> <span>瀹℃壒鎰忚锛�</span>{{ activity.approveNodeReason }} </div> + <div v-if="!activity.isShen" class="node-reason"> + <span>绛惧悕锛�</span> + <img :src="activity.urlTem" class="signImg" alt="" v-if="activity.urlTem"/> + </div> <div v-else-if="activity.isShen"> <el-form-item :prop="'activities.' + index + '.approveNodeReason'" @@ -117,16 +121,33 @@ <template #footer v-if="operationType === 'approval'"> <div class="dialog-footer"> <el-button type="primary" @click="submitForm(2)">涓嶉�氳繃</el-button> - <el-button type="primary" @click="submitForm(1)">閫氳繃</el-button> + <el-button type="primary" @click="openSignatureDialog(1)">閫氳繃</el-button> <el-button @click="closeDia">鍙栨秷</el-button> </div> </template> + </el-dialog> + <!-- 鐢靛瓙绛惧悕寮圭獥锛坴ue3-signature-pad锛� --> + <el-dialog v-model="signatureDialogVisible" title="鐢靛瓙绛惧悕" width="600px" append-to-body> + <vueEsign + ref="esign" + class="mySign" + :width="800" + :height="300" + :isCrop="isCrop" + :lineWidth="lineWidth" + :lineColor="lineColor" + /> + <div style="margin-top:10px;"> + <el-button @click="clearSignature">娓呴櫎</el-button> + <el-button type="primary" @click="confirmSignature">纭畾</el-button> + </div> </el-dialog> </div> </template> <script setup> -import {getCurrentInstance, reactive, ref, toRefs} from "vue"; +import { getCurrentInstance, reactive, ref, toRefs } from "vue"; +import vueEsign from "vue-esign"; import { approveProcessDetails, getDept, @@ -135,6 +156,7 @@ import useUserStore from "@/store/modules/user.js"; import {userListNoPageByTenantId} from "@/api/system/user.js"; import { WarningFilled, Edit, Check, MoreFilled } from '@element-plus/icons-vue' +import { getToken } from "@/utils/auth"; const emit = defineEmits(['close']) const { proxy } = getCurrentInstance() @@ -156,6 +178,22 @@ }, }); const { form } = toRefs(data); +const signatureDialogVisible = ref(false); +const signatureImg = ref(''); +let submitStatus = null; // 涓存椂瀛樺偍閫氳繃/涓嶉�氳繃鐘舵�� +const isCrop = ref(""); +const esign = ref(null); +const lineWidth = ref(0); +const lineColor = ref("#000000"); + +// 涓婁紶閰嶇疆 +const upload = reactive({ + // 涓婁紶鐨勫湴鍧� + url: import.meta.env.VITE_APP_BASE_API + "/file/upload", + // 璁剧疆涓婁紶鐨勮姹傚ご閮� + headers: { Authorization: "Bearer " + getToken() }, +}); + // 鑺傜偣鏍囬 const getNodeTitle = (index, len) => { if (index === len - 1) return '缁撴潫'; @@ -190,6 +228,11 @@ activities.value = res.data // 澧炲姞isApproval瀛楁 activities.value.forEach(item => { + if (item.url && item.url.includes('word')) { + item.urlTem = item.url.replaceAll('word', 'img') + } else { + item.urlTem = item.url + } if (item.approveNodeStatus === 2) { item.isApproval = '宸查┏鍥�'; } else if (item.approveNodeStatus === 1) { @@ -205,17 +248,84 @@ productOptions.value = res.data; }); }; +// 鎵撳紑绛惧悕寮圭獥 +const openSignatureDialog = (status) => { + submitStatus = status; + signatureDialogVisible.value = true; +}; +// 娓呴櫎绛惧悕 +const clearSignature = () => { + esign.value.reset(); +}; +// 纭绛惧悕 +const confirmSignature = () => { + esign.value.generate().then((res) => { + console.log(res); + // 灏哹ase64杞崲涓轰簩杩涘埗 + const base64Data = res.split(',')[1]; // 绉婚櫎data:image/png;base64,鍓嶇紑 + const binaryString = atob(base64Data); + const bytes = new Uint8Array(binaryString.length); + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + signatureImg.value = bytes; + + // 鍒涘缓鏂囦欢瀵硅薄鐢ㄤ簬涓婁紶 + const blob = new Blob([bytes], { type: 'image/png' }); + const file = new File([blob], 'signature.png', { type: 'image/png' }); + + // 鍒涘缓FormData + const formData = new FormData(); + formData.append('file', file); + + // 涓婁紶绛惧悕鍥剧墖 + fetch(upload.url, { + method: 'POST', + headers: upload.headers, + body: formData + }) + .then(response => response.json()) + .then(data => { + if (data.code === 200) { + console.log('data---', data) + let tempFileIds = []; + tempFileIds.push(data.data.tempId); + signatureDialogVisible.value = false; + clearSignature(); + // 鍙湁閫氳繃鏃舵墠浼犻�掔鍚嶆枃浠禝D + if (submitStatus === 1) { + submitForm(submitStatus, tempFileIds); + } else { + submitForm(submitStatus); + } + } else { + proxy.$modal.msgError("绛惧悕鍥剧墖涓婁紶澶辫触锛�" + data.msg); + } + }) + .catch(error => { + console.error('涓婁紶澶辫触:', error); + proxy.$modal.msgError("绛惧悕鍥剧墖涓婁紶澶辫触"); + }); + }).catch((err) => { + console.log(err); + proxy.$modal.msgWarning("璇峰厛绛惧悕锛�"); + }) +}; // 鎻愪氦瀹℃壒 -const submitForm = (status) => { +const submitForm = (status, tempFileIds) => { const filteredActivities = activities.value.filter(activity => activity.isShen); - filteredActivities[0].approveNodeStatus = status + filteredActivities[0].approveNodeStatus = status; + // 鍙湁閫氳繃鏃舵墠闇�瑕佺鍚� + if (status === 1 && tempFileIds) { + filteredActivities[0].tempFileIds = tempFileIds; + } // 鍒ゆ柇鏄惁涓烘渶鍚庝竴姝� const isLast = activities.value.findIndex(a => a.isShen) === activities.value.length-1; updateApproveNode({ ...filteredActivities[0], isLast }).then(() => { proxy.$modal.msgSuccess("鎻愪氦鎴愬姛"); closeDia(); - }) -} + }); +}; // 鍏抽棴寮规 const closeDia = () => { proxy.resetForm("formRef"); @@ -253,4 +363,9 @@ height: 30px; border-radius: 50px; } +.signImg { + cursor: pointer; + width: 200px; + height: 60px; +} </style> \ No newline at end of file diff --git a/src/views/energyManagement/waterManagement/components/formDia.vue b/src/views/energyManagement/waterManagement/components/formDia.vue new file mode 100644 index 0000000..2e58ea0 --- /dev/null +++ b/src/views/energyManagement/waterManagement/components/formDia.vue @@ -0,0 +1,221 @@ +<template> + <div> + <el-dialog + v-model="dialogFormVisible" + title="鐢ㄦ按璁惧" + width="70%" + @close="closeDia" + > + <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="璁惧锛�" prop="deviceModel"> + <el-select + v-model="form.deviceModel" + placeholder="璇烽�夋嫨" + clearable + @change="setName" + :disabled="operationType !== 'add'" + > + <el-option + v-for="item in codeList" + :key="item.deviceModel" + :label="item.deviceName" + :value="item.deviceModel" + > + {{item.deviceName + '--' + item.deviceModel}} + </el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="姣忔棩闄愬埗姘撮噺锛�" prop="waterDayLimit"> + <el-input + v-model="form.waterDayLimit" + placeholder="璇疯緭鍏�" + clearable + /> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="棰濆畾娴侀噺锛�" prop="ratedRate"> + <el-input + v-model="form.ratedRate" + placeholder="璇疯緭鍏�" + clearable + /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="瀹為檯娴侀噺锛�" prop="actualTraffic"> + <el-input + v-model="form.actualTraffic" + placeholder="璇疯緭鍏�" + clearable + /> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="杩愯鏃堕棿锛�" prop="runTime"> + <el-date-picker + style="width: 100%" + v-model="form.runTime" + value-format="YYYY-MM-DD" + format="YYYY-MM-DD" + type="date" + placeholder="璇烽�夋嫨" + clearable + /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="褰撴棩鐢ㄦ按閲忥細" prop="waterDay"> + <el-input + v-model="form.waterDay" + placeholder="璇疯緭鍏�" + clearable + /> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="姘磋垂鍗曚环锛�" prop="waterPrice"> + <el-input + v-model="form.waterPrice" + placeholder="璇疯緭鍏�" + clearable + /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="鐢ㄦ按绫诲瀷锛�" prop="type"> + <el-select + v-model="form.type" + placeholder="璇烽�夋嫨" + clearable + > + <el-option label="宸ヤ笟鐢ㄦ按" value="industrial" /> + <el-option label="鐢熸椿鐢ㄦ按" value="domestic" /> + <el-option label="娑堥槻鐢ㄦ按" value="fire" /> + <el-option label="缁垮寲鐢ㄦ按" value="greening" /> + </el-select> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <div class="dialog-footer"> + <el-button type="primary" @click="submitForm">纭</el-button> + <el-button @click="closeDia">鍙栨秷</el-button> + </div> + </template> + </el-dialog> + </div> +</template> + +<script setup> +import {ref, reactive, nextTick} from "vue"; +import useUserStore from "@/store/modules/user.js"; +import {waterDeviceList, waterEquipmentAdd, waterEquipmentUpdate} from "@/api/energyManagement/waterManagement.js"; +const { proxy } = getCurrentInstance() +const emit = defineEmits(['close']) +const dialogFormVisible = ref(false); +const operationType = ref('') +const userStore = useUserStore(); + +const data = reactive({ + form: { + deviceName: "", + deviceModel: "", + waterDayLimit: "", + ratedRate: "", + actualTraffic: "", + runTime: "", + waterDay: "", + waterPrice: "", + type: "", + }, + rules: { + deviceModel: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }], + runTime: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }], + waterDayLimit: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + ratedRate: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + actualTraffic: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + waterDay: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + waterPrice: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + type: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }], + }, +}) +const { form, rules } = toRefs(data); +const codeList = ref([]) + +// 鎵撳紑寮规 +const openDialog = (type, row) => { + operationType.value = type; + dialogFormVisible.value = true; + form.value = {} + proxy.resetForm("formRef"); + waterDeviceList({size: -1}).then((res) => { + codeList.value = res.data.records; + }); + if (type === "edit") { + form.value = {...row} + } +} +const setName = (code) => { + const index = codeList.value.findIndex(item => item.deviceModel === code); + if (index > -1) { + console.log(codeList) + form.value.name = codeList.value[index].deviceName; + } +} +const submitForm = () => { + proxy.$refs["formRef"].validate(valid => { + if (valid) { + if (operationType.value === "add") { + waterEquipmentAdd(form.value).then(response => { + proxy.$modal.msgSuccess("鏂板鎴愬姛") + closeDia() + }) + } else { + waterEquipmentUpdate(form.value).then(response => { + proxy.$modal.msgSuccess("淇敼鎴愬姛") + closeDia() + }) + } + } + }) +} +// 鍏抽棴寮规 +const closeDia = () => { + proxy.resetForm("formRef"); + dialogFormVisible.value = false; + emit('close') +}; +// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� 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}`; +} +defineExpose({ + openDialog, +}); +</script> + +<style scoped> + +</style> diff --git a/src/views/energyManagement/waterManagement/components/waterBillForm.vue b/src/views/energyManagement/waterManagement/components/waterBillForm.vue new file mode 100644 index 0000000..a132041 --- /dev/null +++ b/src/views/energyManagement/waterManagement/components/waterBillForm.vue @@ -0,0 +1,210 @@ +<template> + <div> + <el-dialog + v-model="dialogFormVisible" + title="姘磋垂绠$悊" + width="70%" + @close="closeDia" + > + <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="璁惧锛�" prop="code"> + <el-select + v-model="form.code" + placeholder="璇烽�夋嫨" + clearable + @change="setName" + :disabled="operationType !== 'add'" + > + <el-option + v-for="item in codeList" + :key="item.deviceModel" + :label="item.deviceName" + :value="item.deviceModel" + > + {{item.deviceName + '--' + item.deviceModel}} + </el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="鐢ㄦ按閲忥細" prop="waterConsumption"> + <el-input + v-model="form.waterConsumption" + placeholder="璇疯緭鍏�" + clearable + /> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="姘磋垂鍗曚环锛�" prop="waterPrice"> + <el-input + v-model="form.waterPrice" + placeholder="璇疯緭鍏�" + clearable + /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="姘磋垂閲戦锛�" prop="waterBill"> + <el-input + v-model="form.waterBill" + placeholder="鑷姩璁$畻" + clearable + disabled + /> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="璁¤垂鏃ユ湡锛�" prop="billDate"> + <el-date-picker + style="width: 100%" + v-model="form.billDate" + value-format="YYYY-MM-DD" + format="YYYY-MM-DD" + type="date" + placeholder="璇烽�夋嫨" + clearable + /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="鐢ㄦ按绫诲瀷锛�" prop="waterType"> + <el-select + v-model="form.waterType" + placeholder="璇烽�夋嫨" + clearable + > + <el-option label="宸ヤ笟鐢ㄦ按" value="industrial" /> + <el-option label="鐢熸椿鐢ㄦ按" value="domestic" /> + <el-option label="娑堥槻鐢ㄦ按" value="fire" /> + <el-option label="缁垮寲鐢ㄦ按" value="greening" /> + </el-select> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <div class="dialog-footer"> + <el-button type="primary" @click="submitForm">纭</el-button> + <el-button @click="closeDia">鍙栨秷</el-button> + </div> + </template> + </el-dialog> + </div> +</template> + +<script setup> +import {ref, reactive, nextTick, watch} from "vue"; +import useUserStore from "@/store/modules/user.js"; +import {waterDeviceList, waterBillAdd, waterBillUpdate} from "@/api/energyManagement/waterManagement.js"; +const { proxy } = getCurrentInstance() +const emit = defineEmits(['close']) +const dialogFormVisible = ref(false); +const operationType = ref('') +const userStore = useUserStore(); + +const data = reactive({ + form: { + name: "", + code: "", + waterConsumption: "", + waterPrice: "", + waterBill: "", + billDate: "", + waterType: "", + }, + rules: { + code: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }], + waterConsumption: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + waterPrice: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + billDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }], + waterType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }], + }, +}) +const { form, rules } = toRefs(data); +const codeList = ref([]) + +// 鎵撳紑寮规 +const openDialog = (type, row) => { + operationType.value = type; + dialogFormVisible.value = true; + form.value = {} + proxy.resetForm("formRef"); + waterDeviceList().then((res) => { + codeList.value = res.data; + }); + if (type === "edit") { + form.value = {...row} + } +} +const setName = (code) => { + const index = codeList.value.findIndex(item => item.deviceModel === code); + if (index > -1) { + console.log(codeList) + form.value.name = codeList.value[index].deviceName; + } +} + +// 璁$畻姘磋垂閲戦 +const calculateWaterBill = () => { + if (form.value.waterConsumption && form.value.waterPrice) { + form.value.waterBill = (parseFloat(form.value.waterConsumption) * parseFloat(form.value.waterPrice)).toFixed(2); + } +} + +// 鐩戝惉鐢ㄦ按閲忓拰姘磋垂鍗曚环鍙樺寲 +watch([() => form.value.waterConsumption, () => form.value.waterPrice], () => { + calculateWaterBill(); +}); + +const submitForm = () => { + proxy.$refs["formRef"].validate(valid => { + if (valid) { + if (operationType.value === "add") { + waterBillAdd(form.value).then(response => { + proxy.$modal.msgSuccess("鏂板鎴愬姛") + closeDia() + }) + } else { + waterBillUpdate(form.value).then(response => { + proxy.$modal.msgSuccess("淇敼鎴愬姛") + closeDia() + }) + } + } + }) +} +// 鍏抽棴寮规 +const closeDia = () => { + proxy.resetForm("formRef"); + dialogFormVisible.value = false; + emit('close') +}; +// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� 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}`; +} +defineExpose({ + openDialog, +}); +</script> + +<style scoped> + +</style> diff --git a/src/views/energyManagement/waterManagement/index.vue b/src/views/energyManagement/waterManagement/index.vue new file mode 100644 index 0000000..181ae88 --- /dev/null +++ b/src/views/energyManagement/waterManagement/index.vue @@ -0,0 +1,312 @@ +<template> + <div class="app-container"> + <div class="search_form"> + <div> + <span class="search_title">璁惧鍚嶇О锛�</span> + <el-input + v-model="searchForm.deviceName" + style="width: 240px" + placeholder="璇疯緭鍏�" + @change="handleQuery" + clearable + :prefix-icon="Search" + /> + <el-button type="primary" @click="handleQuery" style="margin-left: 10px" + >鎼滅储</el-button + > + </div> + <div> + <el-button type="primary" @click="openForm('add')">鏂板</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"> + <PIMTable + rowKey="id" + :column="tableColumn" + :tableData="tableData" + :page="page" + :isSelection="true" + @selection-change="handleSelectionChange" + :tableLoading="tableLoading" + @pagination="pagination" + ></PIMTable> + </div> + <form-dia ref="formDia" @close="handleQuery"></form-dia> + <el-dialog + :title="upload.title" + v-model="upload.open" + width="400px" + append-to-body + @close="handleDialogClose" + > + <el-upload + ref="uploadRef" + :limit="1" + accept=".xlsx, .xls" + :headers="upload.headers" + :action="upload.url" + :disabled="upload.isUploading" + :before-upload="upload.beforeUpload" + :on-progress="upload.onProgress" + :on-success="upload.onSuccess" + :on-error="upload.onError" + :on-change="upload.onChange" + :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> + </div> +</template> + +<script setup> +import {Search} from "@element-plus/icons-vue"; +import {onMounted, ref, reactive, nextTick} from "vue"; +import FormDia from "@/views/energyManagement/waterManagement/components/formDia.vue"; +import {ElMessageBox} from "element-plus"; +import {getToken} from "@/utils/auth.js"; +import {waterEquipmentDelete, waterEquipmentListPage} from "@/api/energyManagement/waterManagement.js"; +const { proxy } = getCurrentInstance(); + +const data = reactive({ + searchForm: { + name: "", + }, +}); +const { searchForm } = toRefs(data); + +const selectedRows = ref([]); +const tableColumn = ref([ + { + label: "璁惧鍚嶇О", + prop: "deviceName", + width: 200, + }, + { + label: "瑙勬牸鍨嬪彿", + prop: "deviceModel", + width: 200, + }, + { + label: "棰濆畾娴侀噺", + prop: "ratedRate", + }, + { + label: "瀹為檯娴侀噺", + prop: "actualTraffic", + }, + { + label: "杩愯鏃堕棿", + prop: "runTime", + width:150 + }, + { + label: "褰撴棩鐢ㄦ按閲�", + prop: "waterDay", + width: 150, + }, + { + label: "姣忔棩闄愬埗姘撮噺", + prop: "waterDayLimit", + width:220 + }, + { + label: "姘磋垂鍗曚环", + prop: "waterPrice", + width: 120, + }, + { + dataType: "action", + label: "鎿嶄綔", + align: "center", + fixed: 'right', + operation: [ + { + name: "缂栬緫", + type: "text", + clickFun: (row) => { + openForm("edit", row); + }, + }, + ], + }, +]); +const tableData = ref([]); +const tableLoading = ref(false); +const page = reactive({ + current: 1, + size: 100, + total: 0, +}); +// 琛ㄦ牸閫夋嫨鏁版嵁 +const handleSelectionChange = (selection) => { + selectedRows.value = selection; +}; +const formDia = ref() +const upload = reactive({ + // 鏄惁鏄剧ず寮瑰嚭灞傦紙瀹㈡埛瀵煎叆锛� + open: false, + // 寮瑰嚭灞傛爣棰橈紙瀹㈡埛瀵煎叆锛� + title: "", + // 鏄惁绂佺敤涓婁紶 + isUploading: false, + // 璁剧疆涓婁紶鐨勮姹傚ご閮� + headers: { Authorization: "Bearer " + getToken() }, + // 涓婁紶鐨勫湴鍧� + url: import.meta.env.VITE_APP_BASE_API + "/waterRecord/importData", + // 鏂囦欢涓婁紶鍓嶇殑鍥炶皟 + beforeUpload: (file) => { + console.log('鏂囦欢鍗冲皢涓婁紶', file); + // 鍙互鍦ㄦ澶勫仛鏂囦欢绫诲瀷鎴栧ぇ灏忔牎楠� + const isValid = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || file.name.endsWith('.xlsx') || file.name.endsWith('.xls'); + if (!isValid) { + proxy.$modal.msgError("鍙兘涓婁紶 Excel 鏂囦欢"); + } + return isValid; + }, + // 鏂囦欢鐘舵�佹敼鍙樻椂鐨勫洖璋� + onChange: (file, fileList) => { + console.log('鏂囦欢鐘舵�佹敼鍙�', file, fileList); + }, + // 鏂囦欢涓婁紶鎴愬姛鏃剁殑鍥炶皟 + onSuccess: (response, file, fileList) => { + console.log('涓婁紶鎴愬姛', response, file, fileList); + if(response.code === 200){ + proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛"); + }else if(response.code === 500){ + proxy.$modal.msgError(response.msg); + }else{ + proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触"); + } + upload.open = false; + getList(); + }, + // 鏂囦欢涓婁紶澶辫触鏃剁殑鍥炶皟 + onError: (error, file, fileList) => { + console.log('涓婁紶澶辫触', error, file, fileList); + proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触"); + upload.open = false; + }, + // 鏂囦欢涓婁紶杩涘害鏀瑰彉鏃剁殑鍥炶皟 + onProgress: (event, file, fileList) => { + console.log('涓婁紶杩涘害', event, file, fileList); + upload.isUploading = true; + }, +}); + +// 鏌ヨ鍒楄〃 +/** 鎼滅储鎸夐挳鎿嶄綔 */ +const handleQuery = () => { + page.current = 1; + getList(); +}; +const pagination = (obj) => { + page.current = obj.page; + page.size = obj.limit; + getList(); +}; + +const getList = () => { + tableLoading.value = true; + waterEquipmentListPage({ ...searchForm.value, ...page }).then((res) => { + tableLoading.value = false; + tableData.value = res.data.records; + page.total = res.data.total; + }).catch(() => { + tableLoading.value = false; + }) +}; + +// 鎵撳紑寮规 +const openForm = (type, row) => { + nextTick(() => { + formDia.value?.openDialog(type, row) + }) +}; + +/** 瀵煎叆鎸夐挳鎿嶄綔 */ +function handleImport() { + upload.title = "鐢ㄦ按璁惧"; + upload.open = true; + // 娓呯┖涓婃涓婁紶鐨勬枃浠跺垪琛� + nextTick(() => { + proxy.$refs["uploadRef"]?.clearFiles(); + }); +} +function importTemplate() { + proxy.download( + "/waterRecord/export", + {}, + '鐢ㄦ按璁惧瀵煎叆妯$増.xlsx' + ); +} +/** 鎻愪氦涓婁紶鏂囦欢 */ +function submitFileForm() { + proxy.$refs["uploadRef"].submit(); +} + +/** 寮规鍏抽棴鏃舵竻绌烘枃浠跺垪琛� */ +function handleDialogClose() { + nextTick(() => { + proxy.$refs["uploadRef"]?.clearFiles(); + }); +} + +const handleDelete = () => { + let ids = []; + if (selectedRows.value.length > 0) { + ids = selectedRows.value.map((item) => item.id); + } else { + proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁"); + return; + } + ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", { + confirmButtonText: "纭", + cancelButtonText: "鍙栨秷", + type: "warning", + }) + .then(() => { + tableLoading.value = true; + waterEquipmentDelete(ids) + .then((res) => { + proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛"); + getList(); + }) + .finally(() => { + tableLoading.value = false; + }); + }) + .catch(() => { + proxy.$modal.msg("宸插彇娑�"); + }); +}; +onMounted(() => { + getList(); +}); +</script> + +<style scoped> + +</style> diff --git a/src/views/energyManagement/waterManagement/waterBill.vue b/src/views/energyManagement/waterManagement/waterBill.vue new file mode 100644 index 0000000..ea382f0 --- /dev/null +++ b/src/views/energyManagement/waterManagement/waterBill.vue @@ -0,0 +1,181 @@ +<template> + <div class="app-container"> + <div class="search_form"> + <div> + <span class="search_title">璁惧鍚嶇О锛�</span> + <el-input + v-model="searchForm.name" + style="width: 240px" + placeholder="璇疯緭鍏�" + @change="handleQuery" + clearable + :prefix-icon="Search" + /> + <el-button type="primary" @click="handleQuery" style="margin-left: 10px" + >鎼滅储</el-button + > + </div> + <div> + <el-button type="primary" @click="openForm('add')">鏂板</el-button> + <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button> + </div> + </div> + <div class="table_list"> + <PIMTable + rowKey="id" + :column="tableColumn" + :tableData="tableData" + :page="page" + :isSelection="true" + @selection-change="handleSelectionChange" + :tableLoading="tableLoading" + @pagination="pagination" + ></PIMTable> + </div> + <form-dia ref="formDia" @close="handleQuery"></form-dia> + </div> +</template> + +<script setup> +import {Search} from "@element-plus/icons-vue"; +import {onMounted, ref, reactive, nextTick} from "vue"; +import FormDia from "@/views/energyManagement/waterManagement/components/waterBillForm.vue"; +import {ElMessageBox} from "element-plus"; +import {waterBillDelete, waterBillListPage} from "@/api/energyManagement/waterManagement.js"; +const { proxy } = getCurrentInstance(); + +const data = reactive({ + searchForm: { + name: "", + }, +}); +const { searchForm } = toRefs(data); + +const selectedRows = ref([]); +const tableColumn = ref([ + { + label: "璁惧鍚嶇О", + prop: "name", + width: 200, + }, + { + label: "瑙勬牸鍨嬪彿", + prop: "code", + width: 200, + }, + { + label: "鐢ㄦ按閲�", + prop: "waterConsumption", + }, + { + label: "姘磋垂鍗曚环", + prop: "waterPrice", + }, + { + label: "姘磋垂閲戦", + prop: "waterBill", + width:150 + }, + { + label: "璁¤垂鏃ユ湡", + prop: "billDate", + width: 150, + }, + { + label: "鐢ㄦ按绫诲瀷", + prop: "waterType", + width:120 + }, + { + dataType: "action", + label: "鎿嶄綔", + align: "center", + fixed: 'right', + operation: [ + { + name: "缂栬緫", + type: "text", + clickFun: (row) => { + openForm("edit", row); + }, + }, + ], + }, +]); +const tableData = ref([]); +const tableLoading = ref(false); +const page = reactive({ + current: 1, + size: 100, + total: 0, +}); +// 琛ㄦ牸閫夋嫨鏁版嵁 +const handleSelectionChange = (selection) => { + selectedRows.value = selection; +}; +const formDia = ref() + +// 鏌ヨ鍒楄〃 +/** 鎼滅储鎸夐挳鎿嶄綔 */ +const handleQuery = () => { + page.current = 1; + getList(); +}; +const pagination = (obj) => { + page.current = obj.page; + page.size = obj.limit; + getList(); +}; + +const getList = () => { + tableLoading.value = true; + waterBillListPage({ ...searchForm.value, ...page }).then((res) => { + tableLoading.value = false; + tableData.value = res.data.records; + page.total = res.data.total; + }); +}; + +// 鎵撳紑寮规 +const openForm = (type, row) => { + nextTick(() => { + formDia.value?.openDialog(type, row) + }) +}; + +const handleDelete = () => { + let ids = []; + if (selectedRows.value.length > 0) { + ids = selectedRows.value.map((item) => item.id); + } else { + proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁"); + return; + } + ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", { + confirmButtonText: "纭", + cancelButtonText: "鍙栨秷", + type: "warning", + }) + .then(() => { + tableLoading.value = true; + waterBillDelete(ids) + .then((res) => { + proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛"); + getList(); + }) + .finally(() => { + tableLoading.value = false; + }); + }) + .catch(() => { + proxy.$modal.msg("宸插彇娑�"); + }); +}; +onMounted(() => { + getList(); +}); +</script> + +<style scoped> + +</style> diff --git a/src/views/energyManagement/waterManagement/waterTrends.vue b/src/views/energyManagement/waterManagement/waterTrends.vue new file mode 100644 index 0000000..12e45fc --- /dev/null +++ b/src/views/energyManagement/waterManagement/waterTrends.vue @@ -0,0 +1,118 @@ +<template> + <div class="app-container"> + <div class="search_form"> + <div> + <span class="search_title">璁惧鍚嶇О锛�</span> + <el-input + v-model="searchForm.name" + style="width: 240px" + placeholder="璇疯緭鍏�" + @change="handleQuery" + clearable + :prefix-icon="Search" + /> + <el-button type="primary" @click="handleQuery" style="margin-left: 10px" + >鎼滅储</el-button + > + </div> + </div> + <div class="table_list"> + <PIMTable + rowKey="id" + :column="tableColumn" + :tableData="tableData" + :page="page" + :isSelection="true" + @selection-change="handleSelectionChange" + :tableLoading="tableLoading" + @pagination="pagination" + ></PIMTable> + </div> + </div> +</template> + +<script setup> +import {Search} from "@element-plus/icons-vue"; +import {onMounted, ref, reactive} from "vue"; +import {listPageByWaterTrend} from "@/api/energyManagement/waterManagement.js"; + +const data = reactive({ + searchForm: { + name: "", + }, +}); +const { searchForm } = toRefs(data); + +const selectedRows = ref([]); +const tableColumn = ref([ + { + label: "璁惧鍚嶇О", + prop: "name", + width: 220, + }, + { + label: "瑙勬牸鍨嬪彿", + prop: "code", + width: 220, + }, + { + label: "杩愯鏃堕棿", + prop: "runDate", + width: 250, + }, + { + label: "鏄ㄦ棩鐢ㄦ按閲�", + prop: "toDayNum", + }, + { + label: "鏈湀骞冲潎姘撮噺", + prop: "avgNum", + width:150 + }, + { + label: "瓒嬪娍", + prop: "trend", + width: 220, + }, +]); +const tableData = ref([]); +const tableLoading = ref(false); +const page = reactive({ + current: 1, + size: 100, + total: 0, +}); +// 琛ㄦ牸閫夋嫨鏁版嵁 +const handleSelectionChange = (selection) => { + selectedRows.value = selection; +}; + +// 鏌ヨ鍒楄〃 +/** 鎼滅储鎸夐挳鎿嶄綔 */ +const handleQuery = () => { + page.current = 1; + getList(); +}; +const pagination = (obj) => { + page.current = obj.page; + page.size = obj.limit; + getList(); +}; + +const getList = () => { + tableLoading.value = true; + listPageByWaterTrend({ ...searchForm.value, ...page }).then((res) => { + tableLoading.value = false; + tableData.value = res.data.records; + page.total = res.data.total; + }); +}; + +onMounted(() => { + getList(); +}); +</script> + +<style scoped> + +</style> diff --git a/src/views/equipmentManagement/gasTank/simple.vue b/src/views/equipmentManagement/gasTank/simple.vue new file mode 100644 index 0000000..92e88df --- /dev/null +++ b/src/views/equipmentManagement/gasTank/simple.vue @@ -0,0 +1,566 @@ +<template> + <div class="app-container"> + <!-- 椤甸潰鏍囬 --> + <div class="page-header"> + <h2>閲嶅瀷缃愬紡璐ц溅鐩戞帶</h2> + <div class="header-actions"> +<!-- <el-button type="primary" @click="addTank">鏂板鍌ㄧ綈</el-button>--> +<!-- <el-button @click="exportData">瀵煎嚭鏁版嵁</el-button>--> + </div> + </div> + + <!-- 鍥涗釜涓昏妯″潡 --> + <div class="modules-container"> + <!-- 1. 鍩烘湰淇℃伅妯″潡 --> + <el-card class="module-card"> + <template #header> + <div class="card-header"> + <span>1. 鍩烘湰淇℃伅</span> + <el-button type="text" @click="handleEditBasicInfo">缂栬緫</el-button> + </div> + </template> + <div class="info-grid"> + <div class="info-item"> + <label>鍌ㄧ綈缂栧彿锛�</label> + <span>{{ basicInfo.tankCode }}</span> + </div> + <div class="info-item"> + <label>鍌ㄧ綈鍚嶇О锛�</label> + <span>{{ basicInfo.tankName }}</span> + </div> + <div class="info-item"> + <label>鍌ㄧ綈绫诲瀷锛�</label> + <span>{{ basicInfo.tankType }}</span> + </div> + <div class="info-item"> + <label>璁捐鍘嬪姏锛�</label> + <span>{{ basicInfo.designPressure }} MPa</span> + </div> + <div class="info-item"> + <label>宸ヤ綔鍘嬪姏锛�</label> + <span>{{ basicInfo.workingPressure }} MPa</span> + </div> + <div class="info-item"> + <label>瀹圭Н锛�</label> + <span>{{ basicInfo.volume }} m鲁</span> + </div> + </div> + </el-card> + + <!-- 2. 鐩戞祴鍙傛暟妯″潡 --> + <el-card class="module-card"> + <template #header> + <div class="card-header"> + <span>2. 鐩戞祴鍙傛暟</span> + <el-button type="text" @click="refreshMonitoring">鍒锋柊</el-button> + </div> + </template> + <div class="monitoring-grid"> + <div class="monitor-item"> + <div class="monitor-label">鍘嬪姏</div> + <div class="monitor-value" :class="getStatusClass(monitoringData.pressureStatus)"> + {{ monitoringData.pressure }} MPa + </div> + <div class="monitor-status">{{ monitoringData.pressureStatus === 'normal' ? '姝e父' : '寮傚父' }}</div> + </div> + <div class="monitor-item"> + <div class="monitor-label">娓╁害</div> + <div class="monitor-value" :class="getStatusClass(monitoringData.temperatureStatus)"> + {{ monitoringData.temperature }} 鈩� + </div> + <div class="monitor-status">{{ monitoringData.temperatureStatus === 'normal' ? '姝e父' : '寮傚父' }}</div> + </div> + <div class="monitor-item"> + <div class="monitor-label">姘斾綋娴撳害</div> + <div class="monitor-value" :class="getStatusClass(monitoringData.gasStatus)"> + {{ monitoringData.gasConcentration }} ppm + </div> + <div class="monitor-status">{{ monitoringData.gasStatus === 'normal' ? '姝e父' : '寮傚父' }}</div> + </div> + <div class="monitor-item"> + <div class="monitor-label">娴侀噺</div> + <div class="monitor-value" :class="getStatusClass(monitoringData.flowStatus)"> + {{ monitoringData.flow }} m鲁/h + </div> + <div class="monitor-status">{{ monitoringData.flowStatus === 'normal' ? '姝e父' : '寮傚父' }}</div> + </div> + </div> + </el-card> + + <!-- 3. 瀹夊叏瑁呯疆妯″潡 --> + <el-card class="module-card"> + <template #header> + <div class="card-header"> + <span>3. 瀹夊叏瑁呯疆</span> + <el-button type="text" @click="checkSafetyDevices">妫�鏌�</el-button> + </div> + </template> + <div class="safety-grid"> + <div class="safety-item" v-for="device in safetyDevices" :key="device.name"> + + <div class="device-info"> + <div class="device-name">{{ device.name }}</div> + <div class="device-status" :class="device.status"> + {{ device.status === 'normal' ? '姝e父' : '寮傚父' }} + </div> + </div> + </div> + </div> + </el-card> + + <!-- 4. 缁存姢璁板綍妯″潡 --> + <el-card class="module-card"> + <template #header> + <div class="card-header"> + <span>4. 缁存姢璁板綍</span> + <el-button type="text" @click="addMaintenanceRecord">娣诲姞璁板綍</el-button> + </div> + </template> + <div class="maintenance-list"> + <div class="maintenance-item" v-for="record in maintenanceRecords" :key="record.id"> + <div class="record-header"> + <span class="record-date">{{ record.date }}</span> + <el-tag :type="record.type === 'inspection' ? 'primary' : 'success'" size="small"> + {{ record.type === 'inspection' ? '妫�楠�' : '缁存姢' }} + </el-tag> + </div> + <div class="record-content"> + <div class="record-title">{{ record.title }}</div> + <div class="record-desc">{{ record.description }}</div> + <div class="record-operator">鎿嶄綔浜猴細{{ record.operator }}</div> + </div> + </div> + </div> + </el-card> + </div> + + <!-- 缂栬緫鍩烘湰淇℃伅寮圭獥 --> + <el-dialog v-model="basicInfoDialogVisible" title="缂栬緫鍩烘湰淇℃伅" width="600px"> + <el-form :model="editBasicInfo" label-width="120px"> + <el-form-item label="鍌ㄧ綈缂栧彿"> + <el-input v-model="editBasicInfo.tankCode" /> + </el-form-item> + <el-form-item label="鍌ㄧ綈鍚嶇О"> + <el-input v-model="editBasicInfo.tankName" /> + </el-form-item> + <el-form-item label="鍌ㄧ綈绫诲瀷"> + <el-select v-model="editBasicInfo.tankType" style="width: 100%"> + <el-option label="娑插寲姘斾綋鍌ㄧ綈" value="娑插寲姘斾綋鍌ㄧ綈" /> + <el-option label="鍘嬪姏瀹瑰櫒" value="鍘嬪姏瀹瑰櫒" /> + <el-option label="甯稿帇鍌ㄧ綈" value="甯稿帇鍌ㄧ綈" /> + </el-select> + </el-form-item> + <el-form-item label="璁捐鍘嬪姏"> + <el-input-number v-model="editBasicInfo.designPressure" :precision="2" style="width: 100%" /> + </el-form-item> + <el-form-item label="宸ヤ綔鍘嬪姏"> + <el-input-number v-model="editBasicInfo.workingPressure" :precision="2" style="width: 100%" /> + </el-form-item> + <el-form-item label="瀹圭Н"> + <el-input-number v-model="editBasicInfo.volume" :precision="2" style="width: 100%" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="basicInfoDialogVisible = false">鍙栨秷</el-button> + <el-button type="primary" @click="saveBasicInfo">淇濆瓨</el-button> + </template> + </el-dialog> + + <!-- 娣诲姞缁存姢璁板綍寮圭獥 --> + <el-dialog v-model="maintenanceDialogVisible" title="娣诲姞缁存姢璁板綍" width="600px"> + <el-form :model="newMaintenanceRecord" label-width="120px"> + <el-form-item label="璁板綍绫诲瀷"> + <el-select v-model="newMaintenanceRecord.type" style="width: 100%"> + <el-option label="妫�楠�" value="inspection" /> + <el-option label="缁存姢" value="maintenance" /> + </el-select> + </el-form-item> + <el-form-item label="鏍囬"> + <el-input v-model="newMaintenanceRecord.title" /> + </el-form-item> + <el-form-item label="鎻忚堪"> + <el-input type="textarea" v-model="newMaintenanceRecord.description" :rows="3" /> + </el-form-item> + <el-form-item label="鎿嶄綔浜�"> + <el-input v-model="newMaintenanceRecord.operator" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="maintenanceDialogVisible = false">鍙栨秷</el-button> + <el-button type="primary" @click="saveMaintenanceRecord">淇濆瓨</el-button> + </template> + </el-dialog> + </div> +</template> + +<script setup> +import { ref, reactive, onMounted } from 'vue' +import { ElMessage } from 'element-plus' + +// 鍩烘湰淇℃伅 +const basicInfo = reactive({ + tankCode: 'GT001', + tankName: '娑插寲姘斿偍缃怉', + tankType: '娑插寲姘斾綋鍌ㄧ綈', + designPressure: 1.6, + workingPressure: 0.8, + volume: 100.5 +}) + +// 鐩戞祴鍙傛暟 +const monitoringData = reactive({ + pressure: 0.8, + pressureStatus: 'normal', + temperature: 25.5, + temperatureStatus: 'normal', + gasConcentration: 0.1, + gasStatus: 'normal', + flow: 15.2, + flowStatus: 'normal' +}) + +// 瀹夊叏瑁呯疆 +const safetyDevices = ref([ + { name: '瀹夊叏闃�', status: 'normal' }, + { name: '鍘嬪姏浼犳劅鍣�', status: 'normal' }, + { name: '娓╁害浼犳劅鍣�', status: 'normal' }, + { name: '姘斾綋妫�娴嬪櫒', status: 'normal' }, + { name: '鐖嗙牬鐗�', status: 'normal' }, + { name: '娉勫帇瑁呯疆', status: 'normal' } +]) + +// 缁存姢璁板綍 +const maintenanceRecords = ref([ + { + id: 1, + date: '2024-01-15', + type: 'inspection', + title: '骞村害妫�楠�', + description: '鎸夌収TSG 21-2016鏍囧噯杩涜骞村害妫�楠岋紝璁惧鐘舵�佽壇濂�', + operator: '寮犲伐绋嬪笀' + }, + { + id: 2, + date: '2024-02-20', + type: 'maintenance', + title: '瀹夊叏闃�缁存姢', + description: '鏇存崲瀹夊叏闃�瀵嗗皝鍦堬紝鏍″噯鍘嬪姏璁惧畾鍊�', + operator: '鏉庢妧甯�' + }, + { + id: 3, + date: '2024-03-10', + type: 'inspection', + title: '鍘嬪姏娴嬭瘯', + description: '杩涜鍘嬪姏瀹瑰櫒姘村帇璇曢獙锛岀鍚堣璁¤姹�', + operator: '鐜嬫楠屽憳' + } +]) + +// 寮圭獥鎺у埗 +const basicInfoDialogVisible = ref(false) +const maintenanceDialogVisible = ref(false) + +// 缂栬緫琛ㄥ崟鏁版嵁 +const editBasicInfo = reactive({ ...basicInfo }) +const newMaintenanceRecord = reactive({ + type: 'inspection', + title: '', + description: '', + operator: '' +}) + +// 鑾峰彇鐘舵�佹牱寮忕被 +const getStatusClass = (status) => { + return status === 'normal' ? 'status-normal' : 'status-warning' +} + +// 鏂板鍌ㄧ綈 +const addTank = () => { + ElMessage.success('鏂板鍌ㄧ綈鍔熻兘') +} + +// 瀵煎嚭鏁版嵁 +const exportData = () => { + ElMessage.success('瀵煎嚭鎴愬姛') +} + +// 缂栬緫鍩烘湰淇℃伅 +const handleEditBasicInfo = () => { + Object.assign(editBasicInfo, basicInfo) + basicInfoDialogVisible.value = true +} + +// 淇濆瓨鍩烘湰淇℃伅 +const saveBasicInfo = () => { + Object.assign(basicInfo, editBasicInfo) + basicInfoDialogVisible.value = false + ElMessage.success('淇濆瓨鎴愬姛') +} + +// 鍒锋柊鐩戞祴鏁版嵁 +const refreshMonitoring = () => { + // 妯℃嫙鏁版嵁鏇存柊 + monitoringData.pressure = (Math.random() * 0.5 + 0.6).toFixed(2) + monitoringData.temperature = (Math.random() * 10 + 20).toFixed(1) + monitoringData.gasConcentration = (Math.random() * 0.2).toFixed(2) + monitoringData.flow = (Math.random() * 10 + 10).toFixed(1) + ElMessage.success('鏁版嵁宸插埛鏂�') +} + +// 妫�鏌ュ畨鍏ㄨ缃� +const checkSafetyDevices = () => { + // 妯℃嫙妫�鏌ヨ繃绋� + safetyDevices.value.forEach(device => { + device.status = Math.random() > 0.1 ? 'normal' : 'warning' + }) + ElMessage.success('瀹夊叏瑁呯疆妫�鏌ュ畬鎴�') +} + +// 娣诲姞缁存姢璁板綍 +const addMaintenanceRecord = () => { + newMaintenanceRecord.type = 'inspection' + newMaintenanceRecord.title = '' + newMaintenanceRecord.description = '' + newMaintenanceRecord.operator = '' + maintenanceDialogVisible.value = true +} + +// 淇濆瓨缁存姢璁板綍 +const saveMaintenanceRecord = () => { + const record = { + id: Date.now(), + date: new Date().toISOString().split('T')[0], + ...newMaintenanceRecord + } + maintenanceRecords.value.unshift(record) + maintenanceDialogVisible.value = false + ElMessage.success('璁板綍娣诲姞鎴愬姛') +} + +// 妯℃嫙瀹炴椂鏁版嵁鏇存柊 +onMounted(() => { + setInterval(() => { + monitoringData.pressure = (Math.random() * 0.5 + 0.6).toFixed(2) + monitoringData.temperature = (Math.random() * 10 + 20).toFixed(1) + monitoringData.gasConcentration = (Math.random() * 0.2).toFixed(2) + monitoringData.flow = (Math.random() * 10 + 10).toFixed(1) + }, 5000) +}) +</script> + +<style lang="scss" scoped> +.app-container { + padding: 20px; + background: #f5f5f5; + min-height: 100vh; +} + +.page-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + padding: 20px; + background: white; + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + + h2 { + margin: 0; + color: #303133; + } + + .header-actions { + display: flex; + gap: 10px; + } +} + +.modules-container { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 20px; +} + +.module-card { + .card-header { + display: flex; + justify-content: space-between; + align-items: center; + font-weight: bold; + color: #303133; + } +} + +.info-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 15px; + + .info-item { + display: flex; + justify-content: space-between; + padding: 10px; + background: #f8f9fa; + border-radius: 4px; + + label { + font-weight: bold; + color: #606266; + } + + span { + color: #303133; + } + } +} + +.monitoring-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 15px; + + .monitor-item { + text-align: center; + padding: 15px; + background: #f8f9fa; + border-radius: 8px; + border: 2px solid transparent; + + .monitor-label { + font-size: 14px; + color: #606266; + margin-bottom: 8px; + } + + .monitor-value { + font-size: 20px; + font-weight: bold; + margin-bottom: 5px; + + &.status-normal { + color: #67c23a; + } + + &.status-warning { + color: #e6a23c; + } + } + + .monitor-status { + font-size: 12px; + color: #909399; + } + } +} + +.safety-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 15px; + + .safety-item { + display: flex; + align-items: center; + padding: 15px; + background: #f8f9fa; + border-radius: 8px; + border: 2px solid transparent; + + .device-icon { + margin-right: 15px; + } + + .device-info { + flex: 1; + + .device-name { + font-weight: bold; + color: #303133; + margin-bottom: 5px; + } + + .device-status { + font-size: 12px; + padding: 2px 8px; + border-radius: 10px; + display: inline-block; + + &.normal { + background: #f0f9ff; + color: #409eff; + } + + &.warning { + background: #fef7e0; + color: #e6a23c; + } + } + } + } +} + +.maintenance-list { + max-height: 300px; + overflow-y: auto; + + .maintenance-item { + padding: 15px; + border-bottom: 1px solid #ebeef5; + margin-bottom: 10px; + + &:last-child { + border-bottom: none; + margin-bottom: 0; + } + + .record-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; + + .record-date { + font-size: 14px; + color: #909399; + } + } + + .record-content { + .record-title { + font-weight: bold; + color: #303133; + margin-bottom: 5px; + } + + .record-desc { + font-size: 14px; + color: #606266; + margin-bottom: 5px; + line-height: 1.4; + } + + .record-operator { + font-size: 12px; + color: #909399; + } + } + } +} + +// 鍝嶅簲寮忚璁� +@media (max-width: 1200px) { + .modules-container { + grid-template-columns: 1fr; + } +} + +@media (max-width: 768px) { + .info-grid, + .monitoring-grid, + .safety-grid { + grid-template-columns: 1fr; + } +} +</style> diff --git a/src/views/equipmentManagement/ledger/Form.vue b/src/views/equipmentManagement/ledger/Form.vue index f7029ee..c1daab7 100644 --- a/src/views/equipmentManagement/ledger/Form.vue +++ b/src/views/equipmentManagement/ledger/Form.vue @@ -8,7 +8,7 @@ </el-col> <el-col :span="12"> <el-form-item label="瑙勬牸鍨嬪彿" prop="deviceModel"> - <el-input v-model="form.deviceModel" placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�" /> + <el-input v-model="form.deviceModel" :disabled="form.deviceModel != null ? true : false" placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�" /> </el-form-item> </el-col> <el-col :span="12"> diff --git a/src/views/equipmentManagement/ledger/index.vue b/src/views/equipmentManagement/ledger/index.vue index ba17f7e..16fbbc6 100644 --- a/src/views/equipmentManagement/ledger/index.vue +++ b/src/views/equipmentManagement/ledger/index.vue @@ -79,22 +79,17 @@ @selection-change="handleSelectionChange" @pagination="changePage" > - <template #operation="{ row }"> - <el-button type="primary" text @click="edit(row.id)" icon="editPen"> - 缂栬緫 - </el-button> - <el-button - type="danger" - text - icon="delete" - @click="deleteRow(row.id)" - > - 鍒犻櫎 - </el-button> - </template> </PIMTable> </div> <Modal ref="modalRef" @success="getTableData"></Modal> + <el-dialog v-model="qrDialogVisible" title="浜岀淮鐮�" width="300px"> + <div style="text-align:center;"> + <img :src="qrCodeUrl" alt="浜岀淮鐮�" style="width:200px;height:200px;" /> + <div style="margin:10px 0;"> + <el-button type="primary" @click="downloadQRCode">涓嬭浇浜岀淮鐮佸浘鐗�</el-button> + </div> + </div> + </el-dialog> </div> </template> @@ -106,6 +101,8 @@ import Modal from "./Modal.vue"; import { ElMessageBox, ElMessage } from "element-plus"; import dayjs from "dayjs"; +import QRCode from "qrcode"; +import { ref } from "vue"; defineOptions({ name: "璁惧鍙拌处", @@ -115,6 +112,10 @@ const multipleList = ref([]); const { proxy } = getCurrentInstance(); const modalRef = ref(); +const qrDialogVisible = ref(false); +const qrCodeUrl = ref(""); +const qrRowData = ref(null); + const { filters, columns, @@ -184,14 +185,29 @@ align: "center", prop: "createTime", }, - { - fixed: "right", - label: "鎿嶄綔", - dataType: "slot", - slot: "operation", - align: "center", - width: "200px", - }, + { + dataType: "action", + label: "鎿嶄綔", + align: "center", + fixed: 'right', + width: 140, + operation: [ + { + name: "缂栬緫", + type: "text", + clickFun: (row) => { + edit(row.id) + }, + }, + { + name: "鐢熸垚浜岀淮鐮�", + type: "text", + clickFun: (row) => { + showQRCode(row) + }, + }, + ], + }, ] ); @@ -253,6 +269,21 @@ }); }; +const showQRCode = async (row) => { + // 浣犲彲浠ヨ嚜瀹氫箟浜岀淮鐮佸唴瀹癸紝姣斿 row.id 鎴� row.deviceName + const qrContent = JSON.stringify(row); // 鎴� `${row.id}` + qrCodeUrl.value = await QRCode.toDataURL(qrContent); + qrRowData.value = row; + qrDialogVisible.value = true; +}; + +const downloadQRCode = () => { + const a = document.createElement("a"); + a.href = qrCodeUrl.value; + a.download = `${qrRowData.value.deviceName || "浜岀淮鐮�"}.png`; + a.click(); +}; + onMounted(() => { filters.entryDate = [ dayjs().format("YYYY-MM-DD"), diff --git a/src/views/inventoryManagement/stockWarning/index.vue b/src/views/inventoryManagement/stockWarning/index.vue new file mode 100644 index 0000000..3694265 --- /dev/null +++ b/src/views/inventoryManagement/stockWarning/index.vue @@ -0,0 +1,1137 @@ +<template> + <div class="app-container"> + <!-- 鎼滅储琛ㄥ崟 --> + <div class="search_form"> + <el-form :model="searchForm" :inline="true"> + <el-form-item label="鍌ㄦ皵缃愬悕绉帮細"> + <el-input v-model="searchForm.tankName" placeholder="璇疯緭鍏ュ偍姘旂綈鍚嶇О" clearable style="width: 200px" /> + </el-form-item> + <el-form-item label="鍌ㄦ皵缃愮被鍨嬶細"> + <el-select v-model="searchForm.tankType" placeholder="璇烽�夋嫨鍌ㄦ皵缃愮被鍨�" clearable style="width: 200px"> + <el-option label="娑插寲姘斿偍缃�" value="娑插寲姘斿偍缃�" /> + <el-option label="鍘嬬缉姘斿偍缃�" value="鍘嬬缉姘斿偍缃�" /> + <el-option label="澶╃劧姘斿偍缃�" value="澶╃劧姘斿偍缃�" /> + <el-option label="姘ф皵鍌ㄧ綈" value="姘ф皵鍌ㄧ綈" /> + </el-select> + </el-form-item> + <el-form-item label="棰勮绫诲瀷锛�"> + <el-select v-model="searchForm.warningType" placeholder="璇烽�夋嫨棰勮绫诲瀷" clearable style="width: 200px"> + <el-option label="姘斾綋涓嶈冻" value="姘斾綋涓嶈冻" /> + <el-option label="鍘嬪姏寮傚父" value="鍘嬪姏寮傚父" /> + <el-option label="娓╁害寮傚父" value="娓╁害寮傚父" /> + <el-option label="娉勬紡棰勮" value="娉勬紡棰勮" /> + </el-select> + </el-form-item> + <el-form-item label="棰勮绾у埆锛�"> + <el-select v-model="searchForm.warningLevel" placeholder="璇烽�夋嫨棰勮绾у埆" clearable style="width: 200px"> + <el-option label="绱ф��" value="绱ф��" /> + <el-option label="閲嶈" value="閲嶈" /> + <el-option label="涓�鑸�" value="涓�鑸�" /> + </el-select> + </el-form-item> + <el-form-item> + <el-button type="primary" @click="handleQuery">鎼滅储</el-button> + <el-button @click="resetQuery">閲嶇疆</el-button> + </el-form-item> + </el-form> + </div> + + <!-- 鏁版嵁琛ㄦ牸 --> + <div class="table_list"> + <!-- 鎿嶄綔鎸夐挳 --> + <div class="table-operations"> + <el-button type="primary" @click="handleAdd">鏂板棰勮瑙勫垯</el-button> + <el-button type="success" @click="handleBatchProcess">鎵归噺澶勭悊</el-button> + <el-button @click="handleExport">瀵煎嚭</el-button> + </div> + <el-table + :data="tableData" + border + v-loading="tableLoading" + @selection-change="handleSelectionChange" + style="width: 100%" + height="calc(100vh - 280px)" + > + <el-table-column align="center" type="selection" width="55" /> + <el-table-column align="center" label="搴忓彿" type="index" width="60" /> + + <!-- 鍩虹淇℃伅瀛楁 --> + <el-table-column label="鍌ㄦ皵缃愮紪鐮�" prop="tankCode" width="120" show-overflow-tooltip /> + <el-table-column label="鍌ㄦ皵缃愬悕绉�" prop="tankName" width="200" show-overflow-tooltip /> + <el-table-column label="鍌ㄦ皵缃愮被鍨�" prop="tankType" width="120" show-overflow-tooltip /> + <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" width="150" show-overflow-tooltip /> + <el-table-column label="瀹圭Н(m鲁)" prop="volume" width="100" show-overflow-tooltip /> + + <!-- 搴撳瓨鐩稿叧瀛楁 --> + <el-table-column label="褰撳墠姘斾綋閲�" prop="currentGasLevel" width="120" show-overflow-tooltip> + <template #default="scope"> + <span :class="getGasLevelClass(scope.row)">{{ scope.row.currentGasLevel }}%</span> + </template> + </el-table-column> + <el-table-column label="瀹夊叏姘斾綋閲�" prop="safetyGasLevel" width="120" show-overflow-tooltip /> + <el-table-column label="鏈�浣庢皵浣撻噺" prop="minGasLevel" width="120" show-overflow-tooltip /> + <el-table-column label="鏈�楂樻皵浣撻噺" prop="maxGasLevel" width="120" show-overflow-tooltip /> + <el-table-column label="褰撳墠鍘嬪姏(MPa)" prop="currentPressure" width="140" show-overflow-tooltip /> + + <!-- 棰勮瑙勫垯瀛楁 --> + <el-table-column label="棰勮绫诲瀷" prop="warningType" width="100" show-overflow-tooltip> + <template #default="scope"> + <el-tag :type="getWarningTypeTag(scope.row.warningType)"> + {{ scope.row.warningType }} + </el-tag> + </template> + </el-table-column> + <el-table-column label="棰勮绾у埆" prop="warningLevel" width="100" show-overflow-tooltip> + <template #default="scope"> + <el-tag :type="getWarningLevelTag(scope.row.warningLevel)"> + {{ scope.row.warningLevel }} + </el-tag> + </template> + </el-table-column> + <el-table-column label="棰勮闃堝��" prop="warningThreshold" width="100" show-overflow-tooltip /> + <el-table-column label="鏄惁鍚敤" prop="isEnabled" width="100" show-overflow-tooltip> + <template #default="scope"> + <el-switch v-model="scope.row.isEnabled" @change="handleEnableChange(scope.row)" /> + </template> + </el-table-column> + + <!-- 鏃堕棿鐩稿叧瀛楁 --> + <el-table-column label="棰勮鏃堕棿" prop="warningTime" width="150" show-overflow-tooltip /> + <el-table-column label="棰勮鎸佺画澶╂暟" prop="warningDuration" width="120" show-overflow-tooltip /> + <el-table-column label="鏈�鍚庢洿鏂版椂闂�" prop="lastUpdateTime" width="150" show-overflow-tooltip /> + <el-table-column label="棰勮鍏呰鏃堕棿" prop="expectedRefillTime" width="150" show-overflow-tooltip /> + <el-table-column label="棰勮缂烘皵鏃堕棿" prop="expectedShortageTime" width="150" show-overflow-tooltip> + <template #default="scope"> + <div v-if="scope.row.expectedShortageTime"> + <div v-if="getCountdown(scope.row.expectedShortageTime).isExpired" class="countdown-expired"> + <el-tag type="danger">宸茬己姘�</el-tag> + </div> + <div v-else class="countdown-timer"> + <span :class="getCountdownClass(scope.row.expectedShortageTime)"> + {{ getCountdown(scope.row.expectedShortageTime).text }} + </span> + </div> + </div> + <span v-else>-</span> + </template> + </el-table-column> + + <!-- 鎿嶄綔鍒� --> + <el-table-column fixed="right" label="鎿嶄綔" width="200" align="center"> + <template #default="scope"> + <el-button link type="primary" size="small" @click="handleEdit(scope.row)">缂栬緫</el-button> + <el-button link type="success" size="small" @click="handleProcess(scope.row)">澶勭悊</el-button> + <el-button link type="danger" size="small" @click="handleDelete(scope.row)">鍒犻櫎</el-button> + </template> + </el-table-column> + </el-table> + + <!-- 鍒嗛〉 --> + <pagination + v-show="total > 0" + :total="total" + layout="total, sizes, prev, pager, next, jumper" + :page="page.current" + :limit="page.size" + @pagination="paginationChange" + /> + </div> + + <!-- 鏂板/缂栬緫棰勮瑙勫垯寮圭獥 --> + <el-dialog + v-model="dialogFormVisible" + :title="operationType === 'add' ? '鏂板棰勮瑙勫垯' : '缂栬緫棰勮瑙勫垯'" + width="50%" + @close="closeDialog" + > + <el-form :model="form" :rules="rules" ref="formRef" label-width="140px"> + <el-row :gutter="20"> + <!-- 鍩虹淇℃伅 --> + <el-col :span="12"> + <el-form-item label="鍌ㄦ皵缃愮紪鐮侊細" prop="tankCode"> + <el-input v-model="form.tankCode" placeholder="璇疯緭鍏ュ偍姘旂綈缂栫爜" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="鍌ㄦ皵缃愬悕绉帮細" prop="tankName"> + <el-input v-model="form.tankName" placeholder="璇疯緭鍏ュ偍姘旂綈鍚嶇О" /> + </el-form-item> + </el-col> + </el-row> + + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="鍌ㄦ皵缃愮被鍨嬶細" prop="tankType"> + <el-select v-model="form.tankType" placeholder="璇烽�夋嫨鍌ㄦ皵缃愮被鍨�" style="width: 100%"> + <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="specificationModel"> + <el-input v-model="form.specificationModel" placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�" /> + </el-form-item> + </el-col> + </el-row> + + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="瀹圭Н(m鲁)锛�" prop="volume"> + <el-input-number v-model="form.volume" :min="0" :precision="2" style="width: 100%" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="褰撳墠姘斾綋閲�(%)锛�" prop="currentGasLevel"> + <el-input-number v-model="form.currentGasLevel" :min="0" :max="100" :precision="1" style="width: 100%" /> + </el-form-item> + </el-col> + </el-row> + + <!-- 搴撳瓨鐩稿叧 --> + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="瀹夊叏姘斾綋閲�(%)锛�" prop="safetyGasLevel"> + <el-input-number v-model="form.safetyGasLevel" :min="0" :max="100" :precision="1" style="width: 100%" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="鏈�浣庢皵浣撻噺(%)锛�" prop="minGasLevel"> + <el-input-number v-model="form.minGasLevel" :min="0" :max="100" :precision="1" style="width: 100%" /> + </el-form-item> + </el-col> + </el-row> + + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="鏈�楂樻皵浣撻噺(%)锛�" prop="maxGasLevel"> + <el-input-number v-model="form.maxGasLevel" :min="0" :max="100" :precision="1" style="width: 100%" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="褰撳墠鍘嬪姏(MPa)锛�" prop="currentPressure"> + <el-input-number v-model="form.currentPressure" :min="0" :precision="2" style="width: 100%" /> + </el-form-item> + </el-col> + </el-row> + + <!-- 棰勮瑙勫垯 --> + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="棰勮绫诲瀷锛�" prop="warningType"> + <el-select v-model="form.warningType" placeholder="璇烽�夋嫨棰勮绫诲瀷" style="width: 100%"> + <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="warningLevel"> + <el-select v-model="form.warningLevel" placeholder="璇烽�夋嫨棰勮绾у埆" style="width: 100%"> + <el-option label="绱ф��" value="绱ф��" /> + <el-option label="閲嶈" value="閲嶈" /> + <el-option label="涓�鑸�" value="涓�鑸�" /> + </el-select> + </el-form-item> + </el-col> + </el-row> + + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="棰勮闃堝�硷細" prop="warningThreshold"> + <el-input-number v-model="form.warningThreshold" :min="0" :precision="2" style="width: 100%" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="鏄惁鍚敤锛�" prop="isEnabled"> + <el-switch v-model="form.isEnabled" /> + </el-form-item> + </el-col> + </el-row> + + <!-- 鏃堕棿鐩稿叧 --> + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="棰勮鏃堕棿锛�" prop="warningTime"> + <el-date-picker + v-model="form.warningTime" + type="datetime" + placeholder="璇烽�夋嫨棰勮鏃堕棿" + style="width: 100%" + value-format="YYYY-MM-DD HH:mm:ss" + /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="棰勮鍏呰鏃堕棿锛�" prop="expectedRefillTime"> + <el-date-picker + v-model="form.expectedRefillTime" + type="datetime" + placeholder="璇烽�夋嫨棰勮鍏呰鏃堕棿" + style="width: 100%" + value-format="YYYY-MM-DD HH:mm:ss" + /> + </el-form-item> + </el-col> + </el-row> + + <el-row :gutter="20"> + <el-col :span="12"> + <el-form-item label="棰勮缂烘皵鏃堕棿锛�" prop="expectedShortageTime"> + <el-date-picker + v-model="form.expectedShortageTime" + type="datetime" + placeholder="璇烽�夋嫨棰勮缂烘皵鏃堕棿" + style="width: 100%" + value-format="YYYY-MM-DD HH:mm:ss" + /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="棰勮瑙勫垯鎻忚堪锛�" prop="warningRule"> + <el-input + v-model="form.warningRule" + type="textarea" + :rows="3" + placeholder="璇疯緭鍏ラ璀﹁鍒欐弿杩�" + /> + </el-form-item> + </el-col> + </el-row> + </el-form> + + <template #footer> + <div class="dialog-footer"> + <el-button @click="closeDialog">鍙栨秷</el-button> + <el-button type="primary" @click="submitForm">纭</el-button> + </div> + </template> + </el-dialog> + + <!-- 缂烘皵棰勮寮规 --> + <el-dialog + v-model="shortageWarningVisible" + title="鈿狅笍 缂烘皵棰勮" + width="400px" + :close-on-click-modal="false" + :close-on-press-escape="false" + :show-close="false" + > + <div class="shortage-warning-content"> + <div class="warning-icon"> + <el-icon size="48" color="#f56c6c"><WarningFilled /></el-icon> + </div> + <div class="warning-message"> + <h3>{{ currentWarningTank.tankName }}</h3> + <p>鍌ㄦ皵缃愬凡缂烘皵锛岃鍙婃椂澶勭悊锛�</p> + <p class="warning-details"> + 鍌ㄦ皵缃愮紪鐮侊細{{ currentWarningTank.tankCode }}<br> + 鍌ㄦ皵缃愮被鍨嬶細{{ currentWarningTank.tankType }}<br> + 褰撳墠姘斾綋閲忥細{{ currentWarningTank.currentGasLevel }}% + </p> + </div> + </div> + <template #footer> + <div class="dialog-footer"> + <el-button type="primary" @click="handleShortageWarning">绔嬪嵆澶勭悊</el-button> + <el-button @click="closeShortageWarning">绋嶅悗澶勭悊</el-button> + </div> + </template> + </el-dialog> + + <!-- 缂烘皵棰勮寮规 --> + <el-dialog + v-model="shortageWarningVisible" + title="鈿狅笍 缂烘皵棰勮" + width="400px" + :close-on-click-modal="false" + :close-on-press-escape="false" + :show-close="false" + > + <div class="shortage-warning-content"> + <div class="warning-icon"> + <el-icon size="48" color="#f56c6c"><WarningFilled /></el-icon> + </div> + <div class="warning-message"> + <h3>{{ currentWarningTank.tankName }}</h3> + <p>鍌ㄦ皵缃愬凡缂烘皵锛岃鍙婃椂澶勭悊锛�</p> + <p class="warning-details"> + 鍌ㄦ皵缃愮紪鐮侊細{{ currentWarningTank.tankCode }}<br> + 鍌ㄦ皵缃愮被鍨嬶細{{ currentWarningTank.tankType }}<br> + 褰撳墠姘斾綋閲忥細{{ currentWarningTank.currentGasLevel }}% + </p> + </div> + </div> + <template #footer> + <div class="dialog-footer"> + <el-button type="primary" @click="handleShortageWarning">绔嬪嵆澶勭悊</el-button> + <el-button @click="closeShortageWarning">绋嶅悗澶勭悊</el-button> + </div> + </template> + </el-dialog> + </div> +</template> + +<script setup> +import { ref, reactive, onMounted, onUnmounted } from 'vue' +import { ElMessage, ElMessageBox } from 'element-plus' +import { WarningFilled } from '@element-plus/icons-vue' +import pagination from '@/components/PIMTable/Pagination.vue' +// 娉ㄩ噴鎺堿PI瀵煎叆锛屼娇鐢ㄥ亣鏁版嵁 +// import { +// getStockWarningPage, +// addStockWarning, +// updateStockWarning, +// deleteStockWarning, +// batchProcessStockWarning, +// exportStockWarning, +// toggleStockWarningStatus +// } from '@/api/inventoryManagement/stockWarning.js' + +const { proxy } = getCurrentInstance() + +// 鍝嶅簲寮忔暟鎹� +const tableData = ref([]) +const tableLoading = ref(false) +const selectedRows = ref([]) +const dialogFormVisible = ref(false) +const operationType = ref('add') +const total = ref(0) + +// 缂烘皵棰勮鐩稿叧 +const shortageWarningVisible = ref(false) +const currentWarningTank = ref({}) +const countdownTimer = ref(null) + +// 鍒嗛〉鍙傛暟 +const page = reactive({ + current: 1, + size: 10 +}) + +// 鎼滅储琛ㄥ崟 +const searchForm = reactive({ + tankName: '', + tankType: '', + warningType: '', + warningLevel: '' +}) + +// 琛ㄥ崟鏁版嵁 +const form = reactive({ + id: null, + tankCode: '', + tankName: '', + tankType: '', + specificationModel: '', + volume: 0, + currentGasLevel: 0, + safetyGasLevel: 0, + minGasLevel: 0, + maxGasLevel: 0, + currentPressure: 0, + warningType: '', + warningLevel: '', + warningThreshold: 0, + isEnabled: true, + warningTime: '', + warningDuration: 0, + lastUpdateTime: '', + expectedRefillTime: '', + expectedShortageTime: '', + warningRule: '' +}) + +// 琛ㄥ崟楠岃瘉瑙勫垯 +const rules = { + tankCode: [{ required: true, message: '璇疯緭鍏ュ偍姘旂綈缂栫爜', trigger: 'blur' }], + tankName: [{ required: true, message: '璇疯緭鍏ュ偍姘旂綈鍚嶇О', trigger: 'blur' }], + tankType: [{ required: true, message: '璇烽�夋嫨鍌ㄦ皵缃愮被鍨�', trigger: 'change' }], + warningType: [{ required: true, message: '璇烽�夋嫨棰勮绫诲瀷', trigger: 'change' }], + warningLevel: [{ required: true, message: '璇烽�夋嫨棰勮绾у埆', trigger: 'change' }], + warningThreshold: [{ required: true, message: '璇疯緭鍏ラ璀﹂槇鍊�', trigger: 'blur' }] +} + +// 鑾峰彇鍊掕鏃朵俊鎭� +const getCountdown = (expectedTime) => { + if (!expectedTime) return { text: '-', isExpired: false } + + const now = new Date().getTime() + const expected = new Date(expectedTime).getTime() + const diff = expected - now + + if (diff <= 0) { + return { text: '宸茬己姘�', isExpired: true } + } + + const days = Math.floor(diff / (1000 * 60 * 60 * 24)) + const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)) + const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)) + + if (days > 0) { + return { text: `${days}澶�${hours}灏忔椂`, isExpired: false } + } else if (hours > 0) { + return { text: `${hours}灏忔椂${minutes}鍒嗛挓`, isExpired: false } + } else { + return { text: `${minutes}鍒嗛挓`, isExpired: false } + } +} + +// 鑾峰彇鍊掕鏃舵牱寮忕被 +const getCountdownClass = (expectedTime) => { + if (!expectedTime) return '' + + const now = new Date().getTime() + const expected = new Date(expectedTime).getTime() + const diff = expected - now + + if (diff <= 0) { + return 'countdown-expired' + } else if (diff <= 24 * 60 * 60 * 1000) { // 24灏忔椂鍐� + return 'countdown-urgent' + } else if (diff <= 7 * 24 * 60 * 60 * 1000) { // 7澶╁唴 + return 'countdown-warning' + } else { + return 'countdown-normal' + } +} + +// 妫�鏌ョ己姘旈璀� +const checkShortageWarnings = () => { + tableData.value.forEach(tank => { + if (tank.expectedShortageTime) { + const countdown = getCountdown(tank.expectedShortageTime) + if (countdown.isExpired && !tank.warningShown) { + // 鏍囪宸叉樉绀洪璀︼紝閬垮厤閲嶅寮规 + tank.warningShown = true + showShortageWarning(tank) + } + } + }) +} + +// 鏄剧ず缂烘皵棰勮寮规 +const showShortageWarning = (tank) => { + currentWarningTank.value = tank + shortageWarningVisible.value = true + + // 鎾斁鎻愮ず闊筹紙鍙�夛級 + // const audio = new Audio('/path/to/warning-sound.mp3') + // audio.play() +} + +// 澶勭悊缂烘皵棰勮 +const handleShortageWarning = () => { + ElMessage.success(`姝e湪澶勭悊鍌ㄦ皵缃� ${currentWarningTank.value.tankName} 鐨勭己姘旈棶棰榒) + shortageWarningVisible.value = false + // 杩欓噷鍙互璋冪敤澶勭悊API +} +// 澶勭悊缂烘皵棰勮 +const closeShortageWarning = () => { + // ElMessage.success(`姝e湪澶勭悊鍌ㄦ皵缃� ${currentWarningTank.value.tankName} 鐨勭己姘旈棶棰榒) + shortageWarningVisible.value = false + // 杩欓噷鍙互璋冪敤澶勭悊API +} + + + +// 鐢熸垚鍋囨暟鎹� +const generateMockData = () => { + const mockData = [ + { + id: 1, + tankCode: 'TANK001', + tankName: '娑插寲姘斿偍缃怉', + tankType: '娑插寲姘斿偍缃�', + specificationModel: 'LPG-5000L', + volume: 5000, + currentGasLevel: 15, + safetyGasLevel: 30, + minGasLevel: 10, + maxGasLevel: 95, + currentPressure: 2.5, + warningType: '姘斾綋涓嶈冻', + warningLevel: '绱ф��', + warningThreshold: 20, + isEnabled: true, + warningTime: '2024-01-15 08:30:00', + warningDuration: 3, + lastUpdateTime: '2024-01-15 10:00:00', + expectedRefillTime: '2024-01-16 14:00:00', + expectedShortageTime: '2024-01-15 18:30:00', // 浠婂ぉ涓嬪崍6:30缂烘皵 + warningRule: '褰撴皵浣撻噺浣庝簬20%鏃惰Е鍙戦璀�' + }, + { + id: 2, + tankCode: 'TANK002', + tankName: '鍘嬬缉姘斿偍缃怋', + tankType: '鍘嬬缉姘斿偍缃�', + specificationModel: 'COMP-3000L', + volume: 3000, + currentGasLevel: 45, + safetyGasLevel: 25, + minGasLevel: 15, + maxGasLevel: 90, + currentPressure: 8.2, + warningType: '鍘嬪姏寮傚父', + warningLevel: '閲嶈', + warningThreshold: 10, + isEnabled: true, + warningTime: '2024-01-14 16:20:00', + warningDuration: 2, + lastUpdateTime: '2024-01-15 09:15:00', + expectedRefillTime: '2024-01-17 09:00:00', + expectedShortageTime: '2024-01-18 12:00:00', // 3澶╁悗缂烘皵 + warningRule: '褰撳帇鍔涜秴杩�8MPa鏃惰Е鍙戦璀�' + }, + { + id: 3, + tankCode: 'TANK003', + tankName: '澶╃劧姘斿偍缃怌', + tankType: '澶╃劧姘斿偍缃�', + specificationModel: 'NG-8000L', + volume: 8000, + currentGasLevel: 75, + safetyGasLevel: 20, + minGasLevel: 10, + maxGasLevel: 95, + currentPressure: 4.8, + warningType: '娓╁害寮傚父', + warningLevel: '涓�鑸�', + warningThreshold: 5, + isEnabled: true, + warningTime: '2024-01-13 11:45:00', + warningDuration: 1, + lastUpdateTime: '2024-01-15 08:45:00', + expectedRefillTime: '2024-01-20 10:00:00', + expectedShortageTime: '2024-01-22 15:30:00', // 7澶╁悗缂烘皵 + warningRule: '褰撴俯搴﹁秴杩�60掳C鏃惰Е鍙戦璀�' + }, + { + id: 4, + tankCode: 'TANK004', + tankName: '姘ф皵鍌ㄧ綈D', + tankType: '姘ф皵鍌ㄧ綈', + specificationModel: 'O2-2000L', + volume: 2000, + currentGasLevel: 8, + safetyGasLevel: 25, + minGasLevel: 5, + maxGasLevel: 90, + currentPressure: 6.5, + warningType: '娉勬紡棰勮', + warningLevel: '绱ф��', + warningThreshold: 15, + isEnabled: true, + warningTime: '2024-01-15 07:15:00', + warningDuration: 4, + lastUpdateTime: '2024-01-15 11:30:00', + expectedRefillTime: '2024-01-15 16:00:00', + expectedShortageTime: '2024-01-15 14:00:00', // 浠婂ぉ涓嬪崍2鐐圭己姘� + warningRule: '褰撴娴嬪埌姘斾綋娉勬紡鏃惰Е鍙戦璀�' + }, + { + id: 5, + tankCode: 'TANK005', + tankName: '娑插寲姘斿偍缃怑', + tankType: '娑插寲姘斿偍缃�', + specificationModel: 'LPG-6000L', + volume: 6000, + currentGasLevel: 35, + safetyGasLevel: 30, + minGasLevel: 15, + maxGasLevel: 95, + currentPressure: 3.2, + warningType: '姘斾綋涓嶈冻', + warningLevel: '閲嶈', + warningThreshold: 20, + isEnabled: false, + warningTime: '2024-01-14 14:30:00', + warningDuration: 2, + lastUpdateTime: '2024-01-15 09:00:00', + expectedRefillTime: '2024-01-19 08:00:00', + expectedShortageTime: '2024-01-21 10:00:00', // 6澶╁悗缂烘皵 + warningRule: '褰撴皵浣撻噺浣庝簬20%鏃惰Е鍙戦璀�' + }, + { + id: 6, + tankCode: 'TANK006', + tankName: '鍘嬬缉姘斿偍缃怓', + tankType: '鍘嬬缉姘斿偍缃�', + specificationModel: 'COMP-4000L', + volume: 4000, + currentGasLevel: 85, + safetyGasLevel: 20, + minGasLevel: 10, + maxGasLevel: 90, + currentPressure: 7.8, + warningType: '鍘嬪姏寮傚父', + warningLevel: '涓�鑸�', + warningThreshold: 8, + isEnabled: true, + warningTime: '2024-01-12 09:20:00', + warningDuration: 1, + lastUpdateTime: '2024-01-15 08:30:00', + expectedRefillTime: '2024-01-25 14:00:00', + expectedShortageTime: '2024-01-28 16:00:00', // 13澶╁悗缂烘皵 + warningRule: '褰撳帇鍔涜秴杩�8MPa鏃惰Е鍙戦璀�' + }, + { + id: 7, + tankCode: 'TANK007', + tankName: '澶╃劧姘斿偍缃怗', + tankType: '澶╃劧姘斿偍缃�', + specificationModel: 'NG-10000L', + volume: 10000, + currentGasLevel: 92, + safetyGasLevel: 15, + minGasLevel: 8, + maxGasLevel: 95, + currentPressure: 5.2, + warningType: '娓╁害寮傚父', + warningLevel: '閲嶈', + warningThreshold: 6, + isEnabled: true, + warningTime: '2024-01-11 16:45:00', + warningDuration: 1, + lastUpdateTime: '2024-01-15 07:45:00', + expectedRefillTime: '2024-01-30 09:00:00', + expectedShortageTime: '2024-02-05 12:00:00', // 21澶╁悗缂烘皵 + warningRule: '褰撴俯搴﹁秴杩�60掳C鏃惰Е鍙戦璀�' + }, + { + id: 8, + tankCode: 'TANK008', + tankName: '姘ф皵鍌ㄧ綈H', + tankType: '姘ф皵鍌ㄧ綈', + specificationModel: 'O2-1500L', + volume: 1500, + currentGasLevel: 12, + safetyGasLevel: 30, + minGasLevel: 8, + maxGasLevel: 90, + currentPressure: 4.5, + warningType: '娉勬紡棰勮', + warningLevel: '绱ф��', + warningThreshold: 12, + isEnabled: true, + warningTime: '2024-01-15 06:30:00', + warningDuration: 5, + lastUpdateTime: '2024-01-15 12:15:00', + expectedRefillTime: '2024-01-15 20:00:00', + expectedShortageTime: '2024-01-15 17:30:00', // 浠婂ぉ涓嬪崍5:30缂烘皵 + warningRule: '褰撴娴嬪埌姘斾綋娉勬紡鏃惰Е鍙戦璀�' + } + ] + + // 鏍规嵁鎼滅储鏉′欢杩囨护鏁版嵁 + let filteredData = mockData.filter(item => { + if (searchForm.tankName && !item.tankName.includes(searchForm.tankName)) return false + if (searchForm.tankType && item.tankType !== searchForm.tankType) return false + if (searchForm.warningType && item.warningType !== searchForm.warningType) return false + if (searchForm.warningLevel && item.warningLevel !== searchForm.warningLevel) return false + return true + }) + + // 鍒嗛〉澶勭悊 + const start = (page.current - 1) * page.size + const end = start + page.size + const paginatedData = filteredData.slice(start, end) + + return { + records: paginatedData, + total: filteredData.length + } +} + +// 鑾峰彇鍒楄〃鏁版嵁 +const getList = async () => { + tableLoading.value = true + try { + // 妯℃嫙缃戠粶寤惰繜 + await new Promise(resolve => setTimeout(resolve, 500)) + + const result = generateMockData() + tableData.value = result.records + total.value = result.total + + // 妫�鏌ョ己姘旈璀� + checkShortageWarnings() + } catch (error) { + console.error('鑾峰彇鍒楄〃澶辫触:', error) + ElMessage.error('鑾峰彇鍒楄〃澶辫触') + } finally { + tableLoading.value = false + } +} + +// 鎼滅储 +const handleQuery = () => { + page.current = 1 + getList() +} + +// 閲嶇疆鎼滅储 +const resetQuery = () => { + Object.keys(searchForm).forEach(key => { + searchForm[key] = '' + }) + handleQuery() +} + +// 鍒嗛〉鍙樺寲 +const paginationChange = (obj) => { + page.current = obj.page + page.size = obj.limit + getList() +} + +// 琛ㄦ牸閫夋嫨鍙樺寲 +const handleSelectionChange = (selection) => { + selectedRows.value = selection +} + +// 鏂板 +const handleAdd = () => { + operationType.value = 'add' + resetForm() + dialogFormVisible.value = true +} + +// 缂栬緫 +const handleEdit = (row) => { + operationType.value = 'edit' + Object.assign(form, row) + dialogFormVisible.value = true +} + +// 澶勭悊棰勮 +const handleProcess = async (row) => { + try { + // 妯℃嫙API璋冪敤寤惰繜 + await new Promise(resolve => setTimeout(resolve, 300)) + ElMessage.success(`姝e湪澶勭悊棰勮锛�${row.tankName}`) + getList() + } catch (error) { + ElMessage.error('澶勭悊棰勮澶辫触') + } +} + +// 鍒犻櫎 +const handleDelete = async (row) => { + try { + await ElMessageBox.confirm(`纭畾瑕佸垹闄ら璀﹁鍒欙細${row.tankName}鍚楋紵`, '鎻愮ず', { + confirmButtonText: '纭畾', + cancelButtonText: '鍙栨秷', + type: 'warning' + }) + + // 妯℃嫙API璋冪敤寤惰繜 + await new Promise(resolve => setTimeout(resolve, 300)) + ElMessage.success('鍒犻櫎鎴愬姛') + getList() + } catch (error) { + if (error !== 'cancel') { + ElMessage.error('鍒犻櫎澶辫触') + } + } +} + +// 鎵归噺澶勭悊 +const handleBatchProcess = async () => { + if (selectedRows.value.length === 0) { + ElMessage.warning('璇烽�夋嫨瑕佸鐞嗙殑棰勮') + return + } + + try { + // 妯℃嫙API璋冪敤寤惰繜 + await new Promise(resolve => setTimeout(resolve, 500)) + ElMessage.success(`鎵归噺澶勭悊浜� ${selectedRows.value.length} 鏉¢璀) + getList() + } catch (error) { + ElMessage.error('鎵归噺澶勭悊澶辫触') + } +} + +// 瀵煎嚭 +const handleExport = async () => { + try { + // 妯℃嫙API璋冪敤寤惰繜 + await new Promise(resolve => setTimeout(resolve, 800)) + + // 鐢熸垚瀵煎嚭鏁版嵁 + const exportData = generateMockData().records + const csvContent = generateCSV(exportData) + + // 鍒涘缓涓嬭浇閾炬帴 + const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }) + const url = window.URL.createObjectURL(blob) + const link = document.createElement('a') + link.href = url + link.download = `鍌ㄦ皵缃愰璀︽暟鎹甠${new Date().getTime()}.csv` + link.click() + window.URL.revokeObjectURL(url) + + ElMessage.success('瀵煎嚭鎴愬姛') + } catch (error) { + ElMessage.error('瀵煎嚭澶辫触') + } +} + +// 鐢熸垚CSV鍐呭 +const generateCSV = (data) => { + const headers = [ + '鍌ㄦ皵缃愮紪鐮�', '鍌ㄦ皵缃愬悕绉�', '鍌ㄦ皵缃愮被鍨�', '瑙勬牸鍨嬪彿', '瀹圭Н(m鲁)', + '褰撳墠姘斾綋閲�(%)', '瀹夊叏姘斾綋閲�(%)', '鏈�浣庢皵浣撻噺(%)', '鏈�楂樻皵浣撻噺(%)', + '褰撳墠鍘嬪姏(MPa)', '棰勮绫诲瀷', '棰勮绾у埆', '棰勮闃堝��', '鏄惁鍚敤', + '棰勮鏃堕棿', '棰勮鎸佺画澶╂暟', '鏈�鍚庢洿鏂版椂闂�', '棰勮鍏呰鏃堕棿', '棰勮缂烘皵鏃堕棿', '棰勮瑙勫垯鎻忚堪' + ] + + const csvRows = [headers.join(',')] + + data.forEach(item => { + const row = [ + item.tankCode, + item.tankName, + item.tankType, + item.specificationModel, + item.volume, + item.currentGasLevel, + item.safetyGasLevel, + item.minGasLevel, + item.maxGasLevel, + item.currentPressure, + item.warningType, + item.warningLevel, + item.warningThreshold, + item.isEnabled ? '鏄�' : '鍚�', + item.warningTime, + item.warningDuration, + item.lastUpdateTime, + item.expectedRefillTime, + item.expectedShortageTime, + item.warningRule + ] + csvRows.push(row.join(',')) + }) + + return csvRows.join('\n') +} + +// 鍚敤鐘舵�佸彉鍖� +const handleEnableChange = async (row) => { + try { + // 妯℃嫙API璋冪敤寤惰繜 + await new Promise(resolve => setTimeout(resolve, 200)) + ElMessage.success(`${row.tankName} 鐨勫惎鐢ㄧ姸鎬佸凡鏇存柊`) + } catch (error) { + ElMessage.error('鐘舵�佹洿鏂板け璐�') + // 鎭㈠鍘熺姸鎬� + row.isEnabled = !row.isEnabled + } +} + +// 鎻愪氦琛ㄥ崟 +const submitForm = async () => { + try { + await proxy.$refs.formRef.validate() + + // 妯℃嫙API璋冪敤寤惰繜 + await new Promise(resolve => setTimeout(resolve, 500)) + + if (operationType.value === 'add') { + ElMessage.success('鏂板鎴愬姛') + } else { + ElMessage.success('缂栬緫鎴愬姛') + } + + closeDialog() + getList() + } catch (error) { + if (!error.errors) { + ElMessage.error(operationType.value === 'add' ? '鏂板澶辫触' : '缂栬緫澶辫触') + } + } +} + +// 鍏抽棴寮圭獥 +const closeDialog = () => { + dialogFormVisible.value = false + resetForm() +} + +// 閲嶇疆琛ㄥ崟 +const resetForm = () => { + Object.keys(form).forEach(key => { + if (key === 'isEnabled') { + form[key] = true + } else if (typeof form[key] === 'number') { + form[key] = 0 + } else { + form[key] = '' + } + }) + proxy.$refs.formRef?.resetFields() +} + +// 鑾峰彇姘斾綋閲忔牱寮忕被 +const getGasLevelClass = (row) => { + if (row.currentGasLevel < row.minGasLevel) { + return 'text-danger' + } else if (row.currentGasLevel > row.maxGasLevel) { + return 'text-warning' + } + return 'text-success' +} + +// 鑾峰彇棰勮绫诲瀷鏍囩鏍峰紡 +const getWarningTypeTag = (type) => { + const typeMap = { + '姘斾綋涓嶈冻': 'danger', + '鍘嬪姏寮傚父': 'warning', + '娓╁害寮傚父': 'info', + '娉勬紡棰勮': 'danger' + } + return typeMap[type] || 'info' +} + +// 鑾峰彇棰勮绾у埆鏍囩鏍峰紡 +const getWarningLevelTag = (level) => { + const levelMap = { + '绱ф��': 'danger', + '閲嶈': 'warning', + '涓�鑸�': 'info' + } + return levelMap[level] || 'info' +} + +// 鍚姩鍊掕鏃跺畾鏃跺櫒 +const startCountdownTimer = () => { + countdownTimer.value = setInterval(() => { + checkShortageWarnings() + }, 60000) // 姣忓垎閽熸鏌ヤ竴娆� +} + +// 鍋滄鍊掕鏃跺畾鏃跺櫒 +const stopCountdownTimer = () => { + if (countdownTimer.value) { + clearInterval(countdownTimer.value) + countdownTimer.value = null + } +} + +// 椤甸潰鍔犺浇 +onMounted(() => { + getList() + startCountdownTimer() +}) + +// 椤甸潰鍗歌浇 +onUnmounted(() => { + stopCountdownTimer() +}) +</script> + +<style scoped lang="scss"> +.app-container { + padding: 20px; + + .table-operations { + text-align: right; + margin-bottom: 20px; + + .el-button { + margin-right: 10px; + } + } + + .table_list { + background: #fff; + border-radius: 4px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + } + + .text-danger { + color: #f56c6c; + font-weight: bold; + } + + .text-warning { + color: #e6a23c; + font-weight: bold; + } + + .text-success { + color: #67c23a; + font-weight: bold; + } + + .dialog-footer { + text-align: right; + } + + // 鍊掕鏃舵牱寮� + .countdown-timer { + font-weight: bold; + } + + .countdown-normal { + color: #67c23a; + } + + .countdown-warning { + color: #e6a23c; + } + + .countdown-urgent { + color: #f56c6c; + animation: blink 1s infinite; + } + + .countdown-expired { + color: #f56c6c; + font-weight: bold; + } + + @keyframes blink { + 0%, 50% { opacity: 1; } + 51%, 100% { opacity: 0.5; } + } + + // 缂烘皵棰勮寮规鏍峰紡 + .shortage-warning-content { + text-align: center; + padding: 20px 0; + + .warning-icon { + margin-bottom: 20px; + } + + .warning-message { + h3 { + color: #f56c6c; + margin-bottom: 10px; + } + + p { + margin-bottom: 10px; + color: #606266; + } + + .warning-details { + background: #f5f7fa; + padding: 15px; + border-radius: 4px; + text-align: left; + font-size: 14px; + line-height: 1.6; + } + } + } +} +</style> diff --git a/src/views/personnelManagement/payrollManagement/components/formDia.vue b/src/views/personnelManagement/payrollManagement/components/formDia.vue new file mode 100644 index 0000000..6dbc326 --- /dev/null +++ b/src/views/personnelManagement/payrollManagement/components/formDia.vue @@ -0,0 +1,315 @@ +<template> + <div> + <el-dialog + v-model="dialogFormVisible" + :title="operationType === 'add' ? '鏂板鍏ヨ亴' : '缂栬緫浜哄憳'" + width="50%" + @close="closeDia" + > + <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="鏈堜唤锛�" prop="payDate"> + <el-date-picker + v-model="form.payDate" + type="month" + value-format="YYYY-MM-DD" + format="YYYY-MM" + placeholder="璇烽�夋嫨鏈堜唤" + clearable + :disabled="operationType === 'edit'" + style="width: 100%" + /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="濮撳悕锛�" prop="staffId"> + <el-select v-model="form.staffId" placeholder="璇烽�夋嫨浜哄憳" style="width: 100%" @change="handleSelect" :disabled="operationType === 'edit'"> + <el-option + v-for="item in personList" + :key="item.id" + :label="item.staffName" + :value="item.id" + /> + </el-select> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="搴斿嚭鍕ゅぉ鏁帮細" prop="shouldAttendedNum"> + <el-input v-model="form.shouldAttendedNum" placeholder="璇疯緭鍏�" clearable type="number"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="瀹為檯鍑哄嫟澶╂暟锛�" prop="actualAttendedNum"> + <el-input v-model="form.actualAttendedNum" placeholder="璇疯緭鍏�" clearable type="number"/> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="鍩烘湰宸ヨ祫锛�" prop="basicSalary"> + <el-input v-model="form.basicSalary" placeholder="璇疯緭鍏�" clearable type="number"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="宀椾綅宸ヨ祫锛�" prop="postSalary"> + <el-input v-model="form.postSalary" placeholder="璇疯緭鍏�" clearable type="number"/> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="鍏ョ鑱岀己鍕ゆ墸娆撅細" prop="deductionAbsenteeism"> + <el-input v-model="form.deductionAbsenteeism" placeholder="璇疯緭鍏�" clearable type="number"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="鐥呭亣鎵f锛�" prop="sickLeaveDeductions"> + <el-input v-model="form.sickLeaveDeductions" placeholder="璇疯緭鍏�" clearable type="number"/> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="浜嬪亣鎵f锛�" prop="deductionPersonalLeave"> + <el-input v-model="form.deductionPersonalLeave" placeholder="璇疯緭鍏�" clearable type="number"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="蹇樿鎵撳崱鎵f锛�" prop="forgetClockDeduct"> + <el-input v-model="form.forgetClockDeduct" style="width: 100%" type="number"/> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="缁╂晥寰楀垎锛�" prop="performanceScore"> + <el-input v-model="form.performanceScore" placeholder="璇疯緭鍏�" clearable type="number"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="缁╂晥宸ヨ祫锛�" prop="performancePay"> + <el-input v-model="form.performancePay" placeholder="璇疯緭鍏�" clearable type="number"/> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="搴斿彂鍚堣锛�" prop="payableWages"> + <el-input v-model="form.payableWages" placeholder="璇疯緭鍏�" clearable type="number"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="绀句繚涓汉锛�" prop="socialSecurityIndividuals"> + <el-input v-model="form.socialSecurityIndividuals" :precision="0" :step="1" style="width: 100%" type="number"/> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="绀句繚鍏徃锛�" prop="socialSecurityCompanies"> + <el-input v-model="form.socialSecurityCompanies" :precision="0" :step="1" style="width: 100%" type="number"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="绀句繚鍚堣锛�" prop="socialSecurityTotal"> + <el-input v-model="form.socialSecurityTotal" :precision="0" :step="1" style="width: 100%" type="number"/> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="鍏Н閲戜釜浜猴細" prop="providentFundIndividuals"> + <el-input v-model="form.providentFundIndividuals" :precision="0" :step="1" style="width: 100%" type="number"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="鍏Н閲戝叕鍙革細" prop="providentFundCompany"> + <el-input v-model="form.providentFundCompany" :precision="0" :step="1" style="width: 100%" type="number"/> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="鍏Н閲戝悎璁★細" prop="providentFundTotal"> + <el-input v-model="form.providentFundTotal" :precision="0" :step="1" style="width: 100%" type="number"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="搴旂◣宸ヨ祫锛�" prop="taxableWaget"> + <el-input v-model="form.taxableWaget" :precision="0" :step="1" style="width: 100%" type="number"/> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="30"> + <el-col :span="12"> + <el-form-item label="涓汉鎵�寰楃◣锛�" prop="personalIncomeTax"> + <el-input v-model="form.personalIncomeTax" :step="0.1" style="width: 100%" type="number"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="瀹炲彂宸ヨ祫锛�" prop="actualWages"> + <el-input v-model="form.actualWages" style="width: 100%" type="number"/> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <div class="dialog-footer"> + <el-button type="primary" @click="submitForm">纭</el-button> + <el-button @click="closeDia">鍙栨秷</el-button> + </div> + </template> + </el-dialog> + </div> +</template> + +<script setup> +import {ref} from "vue"; +import {getStaffJoinInfo, getStaffOnJob, staffJoinAdd, staffJoinUpdate} from "@/api/personnelManagement/onboarding.js"; +import {compensationAdd, compensationUpdate} from "@/api/personnelManagement/payrollManagement.js"; +const { proxy } = getCurrentInstance() +const emit = defineEmits(['close']) + +const dialogFormVisible = ref(false); +const operationType = ref('') +const data = reactive({ + form: { + payDate: "", + staffId: "", + name: "", + shouldAttendedNum: "", + actualAttendedNum: "", + basicSalary: "", + postSalary: "", + deductionAbsenteeism: "", + sickLeaveDeductions: "", + deductionPersonalLeave: "", + forgetClockDeduct: "", + performanceScore: "", + performancePay: "", + payableWages: "", + socialSecurityIndividuals: "", + socialSecurityCompanies: "", + socialSecurityTotal: "", + providentFundIndividuals: "", + providentFundCompany: "", + providentFundTotal: "", + taxableWaget: "", + personalIncomeTax: "", + actualWages: "", + }, + rules: { + payDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" },], + staffId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" },], + staffName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + shouldAttendedNum: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + actualAttendedNum: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + basicSalary: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + postSalary: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + deductionAbsenteeism: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + sickLeaveDeductions: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + deductionPersonalLeave: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + forgetClockDeduct: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + performanceScore: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + performancePay: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + payableWages: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + socialSecurityIndividuals: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + socialSecurityCompanies: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + socialSecurityTotal: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + providentFundIndividuals: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + providentFundCompany: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + providentFundTotal: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + taxableWaget: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + personalIncomeTax: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + actualWages: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], + }, +}); +const { form, rules } = toRefs(data); +const personList = ref([]); + +// 鎵撳紑寮规 +const openDialog = (type, row) => { + operationType.value = type; + dialogFormVisible.value = true; + getStaffOnJob().then(res => { + personList.value = res.data + }) + form.value = {} + if (operationType.value === 'edit') { + getStaffJoinInfo(row.id).then(res => { + form.value = {...row} + form.value.payDate = form.value.payDate + '-01' + }) + } +} +const handleSelect = (value) => { + console.log('value', value) + const index = personList.value.findIndex(row => row.id === value) + if (index > -1) { + form.value.name = personList.value[index].staffName + } +} +// 鎻愪氦浜у搧琛ㄥ崟 +const submitForm = () => { + proxy.$refs.formRef.validate(valid => { + if (valid) { + form.value.staffState = 1 + if (operationType.value === "add") { + compensationAdd(form.value).then(res => { + proxy.$modal.msgSuccess("鎻愪氦鎴愬姛"); + closeDia(); + }) + } else { + compensationUpdate(form.value).then(res => { + proxy.$modal.msgSuccess("鎻愪氦鎴愬姛"); + closeDia(); + }) + } + } + }) +} +// 璁$畻鍚堝悓骞撮檺 +const calculateContractTerm = () => { + if (form.value.contractStartTime && form.value.contractEndTime) { + const startDate = new Date(form.value.contractStartTime); + const endDate = new Date(form.value.contractEndTime); + + if (endDate > startDate) { + // 璁$畻骞翠唤宸� + const yearDiff = endDate.getFullYear() - startDate.getFullYear(); + const monthDiff = endDate.getMonth() - startDate.getMonth(); + const dayDiff = endDate.getDate() - startDate.getDate(); + + let years = yearDiff; + + // 濡傛灉缁撴潫鏃ユ湡鐨勬湀鏃ュ皬浜庡紑濮嬫棩鏈熺殑鏈堟棩锛屽垯鍑忓幓1骞� + if (monthDiff < 0 || (monthDiff === 0 && dayDiff < 0)) { + years = yearDiff - 1; + } + + form.value.contractTerm = Math.max(0, years); + } else { + form.value.contractTerm = 0; + } + } else { + form.value.contractTerm = 0; + } +}; + +// 鍏抽棴寮规 +const closeDia = () => { + proxy.resetForm("formRef"); + dialogFormVisible.value = false; + emit('close') +}; +defineExpose({ + openDialog, +}); +</script> + +<style scoped> + +</style> \ No newline at end of file diff --git a/src/views/personnelManagement/payrollManagement/index.vue b/src/views/personnelManagement/payrollManagement/index.vue new file mode 100644 index 0000000..1de23e4 --- /dev/null +++ b/src/views/personnelManagement/payrollManagement/index.vue @@ -0,0 +1,291 @@ +<template> + <div class="app-container"> + <div class="search_form"> + <div> + <span class="search_title">濮撳悕锛�</span> + <el-input + v-model="searchForm.name" + style="width: 240px" + placeholder="璇疯緭鍏ュ鍚嶆悳绱�" + @change="handleQuery" + clearable + :prefix-icon="Search" + /> + <span class="search_title ml10">鏈堜唤锛�</span> + <el-date-picker + v-model="searchForm.payDateStr" + type="month" + @change="handleQuery" + value-format="YYYY-MM" + format="YYYY-MM" + placeholder="璇烽�夋嫨鏈堜唤" + style="width: 240px" + clearable + /> + <el-button type="primary" @click="handleQuery" style="margin-left: 10px" + >鎼滅储</el-button + > + </div> + <div> + <el-button type="primary" @click="openForm('add')">鏂板钖祫</el-button> +<!-- <el-button @click="handleOut">瀵煎嚭</el-button>--> + <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button> + </div> + </div> + <div class="table_list"> + <PIMTable + rowKey="id" + :column="tableColumn" + :tableData="tableData" + :page="page" + :isSelection="true" + @selection-change="handleSelectionChange" + :tableLoading="tableLoading" + @pagination="pagination" + :total="page.total" + ></PIMTable> + </div> + <form-dia ref="formDia" @close="handleQuery"></form-dia> + </div> +</template> + +<script setup> +import { Search } from "@element-plus/icons-vue"; +import {onMounted, ref} from "vue"; +import FormDia from "@/views/personnelManagement/payrollManagement/components/formDia.vue"; +import {staffJoinDel} from "@/api/personnelManagement/onboarding.js"; +import {ElMessageBox} from "element-plus"; +import dayjs from "dayjs"; +import {compensationDelete, compensationListPage} from "@/api/personnelManagement/payrollManagement.js"; + +const data = reactive({ + searchForm: { + name: "", + payDateStr: "", + }, +}); +const { searchForm } = toRefs(data); +const tableColumn = ref([ + { + label: "钖祫鏈堜唤", + prop: "payDate", + }, + { + label: "濮撳悕", + prop: "name", + }, + { + label: "搴斿嚭鍕ゅぉ鏁�", + prop: "shouldAttendedNum", + width:100 + }, + { + label: "瀹為檯鍑哄嫟澶╂暟", + prop: "actualAttendedNum", + width:110 + }, + { + label: "鍩烘湰宸ヨ祫", + prop: "basicSalary", + }, + { + label: "宀椾綅宸ヨ祫", + prop: "postSalary", + width:100 + }, + { + label: "鍏ョ鑱岀己鍕ゆ墸娆�", + prop: "deductionAbsenteeism", + width:130 + }, + { + label: "鐥呭亣鎵f", + prop: "sickLeaveDeductions", + width:100 + }, + { + label: "浜嬪亣鎵f", + prop: "deductionPersonalLeave", + width:100 + }, + { + label: "蹇樿鎵撳崱鎵f", + prop: "forgetClockDeduct", + width:110 + }, + { + label: "缁╂晥寰楀垎", + prop: "performanceScore", + width:150 + }, + { + label: "缁╂晥宸ヨ祫", + prop: "performancePay", + width: 120 + }, + { + label: "搴斿彂鍚堣", + prop: "payableWages", + width:150 + }, + { + label: "绀句繚涓汉", + prop: "socialSecurityIndividuals", + }, + { + label: "绀句繚鍏徃", + prop: "socialSecurityCompanies", + width: 120 + }, + { + label: "绀句繚鍚堣", + prop: "socialSecurityTotal", + width: 120 + }, + { + label: "鍏Н閲戜釜浜�", + prop: "providentFundIndividuals", + width: 120 + }, + { + label: "鍏Н閲戝叕鍙�", + prop: "providentFundCompany", + width: 120 + }, + { + label: "鍏Н閲戝悎璁�", + prop: "providentFundTotal", + width: 120 + }, + { + label: "搴旂◣宸ヨ祫", + prop: "taxableWaget", + }, + { + label: "涓汉鎵�寰楃◣", + prop: "personalIncomeTax", + width: 120 + }, + { + label: "瀹炲彂宸ヨ祫", + prop: "actualWages", + width: 120 + }, + { + dataType: "action", + label: "鎿嶄綔", + align: "center", + fixed: 'right', + operation: [ + { + name: "缂栬緫", + type: "text", + clickFun: (row) => { + openForm("edit", row); + }, + }, + ], + }, +]); +const tableData = ref([]); +const selectedRows = ref([]); +const tableLoading = ref(false); +const page = reactive({ + current: 1, + size: 100, + total: 0, +}); +const formDia = ref() +const { proxy } = getCurrentInstance() + +const handleDateChange = (value,type) => { + searchForm.value.entryDateEnd = null + searchForm.value.entryDateStart = null + if(type === 1){ + if (value) { + searchForm.value.entryDateStart = dayjs(value).format("YYYY-MM-DD"); + } + }else{ + if (value) { + searchForm.value.entryDateEnd = dayjs(value).format("YYYY-MM-DD"); + } + } + getList(); +}; +// 鏌ヨ鍒楄〃 +/** 鎼滅储鎸夐挳鎿嶄綔 */ +const handleQuery = () => { + page.current = 1; + getList(); +}; +const pagination = (obj) => { + page.current = obj.page; + page.size = obj.limit; + getList(); +}; +const getList = () => { + tableLoading.value = true; + compensationListPage({...page, ...searchForm.value, staffState: 1}).then(res => { + tableLoading.value = false; + tableData.value = res.data.records + page.total = res.data.total; + }).catch(err => { + tableLoading.value = false; + }) +}; +// 琛ㄦ牸閫夋嫨鏁版嵁 +const handleSelectionChange = (selection) => { + selectedRows.value = selection; +}; + +// 鎵撳紑寮规 +const openForm = (type, row) => { + nextTick(() => { + formDia.value?.openDialog(type, row) + }) +}; + +// 鍒犻櫎 +const handleDelete = () => { + let ids = []; + if (selectedRows.value.length > 0) { + ids = selectedRows.value.map((item) => item.id); + } else { + proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁"); + return; + } + ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", { + confirmButtonText: "纭", + cancelButtonText: "鍙栨秷", + type: "warning", + }) + .then(() => { + compensationDelete(ids).then((res) => { + proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛"); + getList(); + }); + }) + .catch(() => { + proxy.$modal.msg("宸插彇娑�"); + }); +}; +// 瀵煎嚭 +const handleOut = () => { + ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", { + confirmButtonText: "纭", + cancelButtonText: "鍙栨秷", + type: "warning", + }) + .then(() => { + proxy.download("/staff/staffJoinLeaveRecord/export", {staffState: 1}, "浜哄憳鍏ヨ亴.xlsx"); + }) + .catch(() => { + proxy.$modal.msg("宸插彇娑�"); + }); +}; +onMounted(() => { + getList(); +}); +</script> + +<style scoped></style> diff --git a/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue b/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue index be15275..b61f84a 100644 --- a/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue +++ b/src/views/qualityManagement/rawMaterialInspection/components/formDia.vue @@ -54,7 +54,8 @@ </el-col> <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"/> + <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="璇疯緭鍏�" + clearable :precision="2"/> </el-form-item> </el-col> </el-row> @@ -67,8 +68,8 @@ <el-col :span="12"> <el-form-item label="妫�娴嬬粨鏋滐細" prop="checkResult"> <el-select v-model="form.checkResult"> - <el-option label="鍚堟牸" value="鍚堟牸" /> - <el-option label="涓嶅悎鏍�" value="涓嶅悎鏍�" /> + <el-option label="鍚堟牸" value="鍚堟牸"/> + <el-option label="涓嶅悎鏍�" value="涓嶅悎鏍�"/> </el-select> </el-form-item> </el-col> @@ -77,7 +78,7 @@ <el-col :span="12"> <el-form-item label="妫�楠屽憳锛�" prop="checkName"> <el-input v-model="form.checkName" placeholder="璇疯緭鍏�" clearable/> - + </el-form-item> </el-col> <el-col :span="12"> @@ -95,6 +96,22 @@ </el-col> </el-row> </el-form> + <div style="margin-bottom: 10px;text-align: right"> + <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button> + </div> + <PIMTable + rowKey="id" + :column="tableColumn" + :tableData="tableData" + :tableLoading="tableLoading" + :isSelection="true" + @selection-change="handleSelectionChange" + height="400" + > + <template #slot="{ row }"> + <el-input v-model="row.testValue" clearable/> + </template> + </PIMTable> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="submitForm">纭</el-button> @@ -110,7 +127,11 @@ import {getOptions} from "@/api/procurementManagement/procurementLedger.js"; import {productTreeList} from "@/api/basicData/product.js"; import {qualityInspectAdd, qualityInspectUpdate} from "@/api/qualityManagement/rawMaterialInspection.js"; -const { proxy } = getCurrentInstance() +import {ElMessageBox} from "element-plus"; +import {qualityInspectParamDel, qualityInspectParamInfo} from "@/api/qualityManagement/qualityInspectParam.js"; +import {qualityInspectDetailByProductId} from "@/api/qualityManagement/metricMaintenance.js"; + +const {proxy} = getCurrentInstance() const emit = defineEmits(['close']) const dialogFormVisible = ref(false); @@ -129,20 +150,48 @@ checkResult: "", }, rules: { - checkTime: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" },], - supplier: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], - checkName: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }], - productId: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], - model: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }], - unit: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }], - quantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }], - checkCompany: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }], - checkResult: [{ required: true, message: "璇烽�夋嫨妫�娴嬬粨鏋�", trigger: "change" }], + checkTime: [{required: false, message: "璇疯緭鍏�", trigger: "blur"},], + supplier: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}], + checkName: [{required: false, message: "璇疯緭鍏�", trigger: "blur"}], + productId: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}], + model: [{required: false, message: "璇疯緭鍏�", trigger: "blur"}], + unit: [{required: false, message: "璇疯緭鍏�", trigger: "blur"}], + quantity: [{required: true, message: "璇疯緭鍏�", trigger: "blur"}], + checkCompany: [{required: false, message: "璇疯緭鍏�", trigger: "blur"}], + checkResult: [{required: true, message: "璇烽�夋嫨妫�娴嬬粨鏋�", trigger: "change"}], }, }); -const { form, rules } = toRefs(data); +const tableColumn = ref([ + { + label: "鎸囨爣", + prop: "parameterItem", + }, + { + label: "鍗曚綅", + prop: "unit", + }, + { + label: "鏍囧噯鍊�", + prop: "standardValue", + }, + { + label: "鍐呮帶鍊�", + prop: "controlValue", + }, + { + label: "妫�楠屽��", + prop: "testValue", + dataType: 'slot', + slot: 'slot', + }, +]); +const tableData = ref([]); +const tableLoading = ref(false); + +const {form, rules} = toRefs(data); const supplierList = ref([]); const productOptions = ref([]); +const currentProductId = ref(0); // 鎵撳紑寮规 const openDialog = (type, row) => { @@ -154,6 +203,8 @@ getProductOptions(); if (operationType.value === 'edit') { form.value = {...row} + currentProductId.value = row.productId || 0 + getQualityInspectParamList(row.id) } } const getProductOptions = () => { @@ -162,7 +213,11 @@ }); }; const getModels = (value) => { + currentProductId.value = value form.value.productName = findNodeById(productOptions.value, value); + if (currentProductId) { + getList(); + } }; const findNodeById = (nodes, productId) => { for (let i = 0; i < nodes.length; i++) { @@ -178,9 +233,10 @@ } return null; // 娌℃湁鎵惧埌鑺傜偣锛岃繑鍥瀗ull }; + function convertIdToValue(data) { return data.map((item) => { - const { id, children, ...rest } = item; + const {id, children, ...rest} = item; const newItem = { ...rest, value: id, // 灏� id 鏀逛负 value @@ -188,22 +244,24 @@ if (children && children.length > 0) { newItem.children = convertIdToValue(children); } - + return newItem; }); } + // 鎻愪氦浜у搧琛ㄥ崟 const submitForm = () => { proxy.$refs.formRef.validate(valid => { if (valid) { form.value.inspectType = 0 + const data = {...form.value, qualityInspectParams: tableData.value} if (operationType.value === "add") { - qualityInspectAdd(form.value).then(res => { + qualityInspectAdd(data).then(res => { proxy.$modal.msgSuccess("鎻愪氦鎴愬姛"); closeDia(); }) } else { - qualityInspectUpdate(form.value).then(res => { + qualityInspectUpdate(data).then(res => { proxy.$modal.msgSuccess("鎻愪氦鎴愬姛"); closeDia(); }) @@ -211,9 +269,50 @@ } }) } + +const handleSelectionChange = (selection) => { + selectedRows.value = selection; +}; + +const handleDelete = () => { + let ids = []; + if (selectedRows.value.length > 0) { + ids = selectedRows.value.map((item) => item.id); + } else { + proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁"); + return; + } + ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", { + confirmButtonText: "纭", + cancelButtonText: "鍙栨秷", + type: "warning", + }) + .then(() => { + qualityInspectParamDel(ids).then((res) => { + proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛"); + getList(); + }); + }) + .catch(() => { + proxy.$modal.msg("宸插彇娑�"); + }); +}; + +const getList = () => { + qualityInspectDetailByProductId(currentProductId.value).then(res => { + tableData.value = res.data; + }) +} + +const getQualityInspectParamList = (id) => { + qualityInspectParamInfo(id).then(res => { + tableData.value = res.data; + }) +} // 鍏抽棴寮规 const closeDia = () => { proxy.resetForm("formRef"); + tableData.value = [] dialogFormVisible.value = false; emit('close') }; diff --git a/src/views/qualityManagement/rawMaterialInspection/index.vue b/src/views/qualityManagement/rawMaterialInspection/index.vue index bbee1bc..16db3eb 100644 --- a/src/views/qualityManagement/rawMaterialInspection/index.vue +++ b/src/views/qualityManagement/rawMaterialInspection/index.vue @@ -11,11 +11,12 @@ clearable :prefix-icon="Search" /> - <span style="margin-left: 10px" class="search_title">妫�娴嬫棩鏈燂細</span> - <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" - placeholder="璇烽�夋嫨" clearable @change="changeDaterange" /> + <span style="margin-left: 10px" class="search_title">妫�娴嬫棩鏈燂細</span> + <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" + placeholder="璇烽�夋嫨" clearable @change="changeDaterange"/> <el-button type="primary" @click="handleQuery" style="margin-left: 10px" - >鎼滅储</el-button + >鎼滅储 + </el-button > </div> <div> @@ -40,18 +41,42 @@ <InspectionFormDia ref="inspectionFormDia" @close="handleQuery"></InspectionFormDia> <FormDia ref="formDia" @close="handleQuery"></FormDia> <files-dia ref="filesDia" @close="handleQuery"></files-dia> + <el-dialog v-model="dialogFormVisible" title="缂栬緫妫�楠屽憳" width="70%" + @close="closeDia"> + <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> + <el-form-item label="妫�楠屽憳锛�" prop="checkName"> + <el-select v-model="form.checkName" placeholder="璇烽�夋嫨" clearable> + <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" + :value="item.nickName"/> + </el-select> + </el-form-item> + </el-form> + <template #footer> + <div class="dialog-footer"> + <el-button type="primary" @click="submitForm">纭</el-button> + <el-button @click="closeDia">鍙栨秷</el-button> + </div> + </template> + </el-dialog> + </div> </template> <script setup> -import { Search } from "@element-plus/icons-vue"; +import {Search} from "@element-plus/icons-vue"; import {onMounted, ref} from "vue"; import InspectionFormDia from "@/views/qualityManagement/rawMaterialInspection/components/inspectionFormDia.vue"; import FormDia from "@/views/qualityManagement/rawMaterialInspection/components/formDia.vue"; import {ElMessageBox} from "element-plus"; -import {qualityInspectDel, qualityInspectListPage} from "@/api/qualityManagement/rawMaterialInspection.js"; +import { + downloadQualityInspect, + qualityInspectDel, + qualityInspectListPage, qualityInspectUpdate, + submitQualityInspect +} from "@/api/qualityManagement/rawMaterialInspection.js"; import FilesDia from "@/views/qualityManagement/rawMaterialInspection/components/filesDia.vue"; import dayjs from "dayjs"; +import {userListNoPage} from "@/api/system/user.js"; const data = reactive({ searchForm: { @@ -63,8 +88,11 @@ entryDateStart: dayjs().format("YYYY-MM-DD"), entryDateEnd: dayjs().add(1, "day").format("YYYY-MM-DD"), }, + rules: { + checkName: [{required: true, message: "璇烽�夋嫨", trigger: "change"}], + }, }); -const { searchForm } = toRefs(data); +const {searchForm, rules} = toRefs(data); const tableColumn = ref([ { label: "妫�娴嬫棩鏈�", @@ -107,12 +135,23 @@ prop: "checkResult", dataType: "tag", formatType: (params) => { - if (params == '涓嶅悎鏍�') { + if (params === '涓嶅悎鏍�') { return "danger"; - } else if (params == '鍚堟牸') { + } else if (params === '鍚堟牸') { return "success"; } else { return null; + } + }, + }, + { + label: "鎻愪氦鐘舵��", + prop: "inspectState", + formatData: (params) => { + if (params) { + return "宸叉彁浜�"; + } else { + return "鏈彁浜�"; } }, }, @@ -121,7 +160,7 @@ label: "鎿嶄綔", align: "center", fixed: "right", - width: 190, + width: 250, operation: [ { name: "缂栬緫", @@ -131,17 +170,35 @@ }, }, { - name: "鏂板妫�楠岃褰�", - type: "text", - clickFun: (row) => { - openInspectionForm("edit", row); - }, - }, - { name: "闄勪欢", type: "text", clickFun: (row) => { openFilesFormDia(row); + }, + }, + { + name: "鎻愪氦", + type: "text", + clickFun: (row) => { + submit(row.id); + }, + }, + { + name: "鍒嗛厤妫�楠屽憳", + type: "text", + clickFun: (row) => { + if (!row.checkName) { + open(row) + } else { + proxy.$modal.msgError("妫�楠屽憳宸插瓨鍦�"); + } + }, + }, + { + name: "涓嬭浇", + type: "text", + clickFun: (row) => { + downLoadFile(row); }, }, ], @@ -150,15 +207,21 @@ const tableData = ref([]); const selectedRows = ref([]); const tableLoading = ref(false); +const userList = ref([]); +const dialogFormVisible = ref(false); +const form = ref({ + checkName: "" +}); const page = reactive({ current: 1, size: 100, total: 0 }); +const currentRow = ref(null) const formDia = ref() const filesDia = ref() const inspectionFormDia = ref() -const { proxy } = getCurrentInstance() +const {proxy} = getCurrentInstance() const changeDaterange = (value) => { searchForm.value.entryDateStart = undefined; searchForm.value.entryDateEnd = undefined; @@ -181,7 +244,7 @@ }; const getList = () => { tableLoading.value = true; - const params = { ...searchForm.value, ...page }; + const params = {...searchForm.value, ...page}; params.entryDate = undefined qualityInspectListPage({...params, inspectType: 0}).then(res => { tableLoading.value = false; @@ -253,6 +316,62 @@ proxy.$modal.msg("宸插彇娑�"); }); }; + +// 鎻愪环 +const submit = async (id) => { + const res = await submitQualityInspect({id: id}) + if (res.code === 200) { + proxy.$modal.msgSuccess("鎻愪氦鎴愬姛"); + getList(); + } +} + +// 鍏抽棴寮规 +const closeDia = () => { + proxy.resetForm("formRef"); + dialogFormVisible.value = false; +}; + +const submitForm = () => { + if (currentRow.value) { + const data = { + ...form.value, + id: currentRow.value.id + } + qualityInspectUpdate(data).then(res => { + proxy.$modal.msgSuccess("鎻愪氦鎴愬姛"); + closeDia(); + getList(); + }) + } +}; + +const open = async (row) => { + let userLists = await userListNoPage(); + userList.value = userLists.data; + currentRow.value = row + dialogFormVisible.value = true +} + +const downLoadFile = (row) => { + downloadQualityInspect({id: row.id}).then(res => { + // 鍒涘缓 blob 瀵硅薄 + const blob = new Blob([res.data], {type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'}) + const downloadUrl = window.URL.createObjectURL(blob) + + // 鍒涘缓涓存椂 <a> 鏍囩杩涜涓嬭浇 + const link = document.createElement('a') + link.href = downloadUrl + link.download = '妫�楠屾姤鍛�.docx' // 杩欓噷鍜屽悗绔竴鑷� + document.body.appendChild(link) + link.click() + + // 娓呯悊 + document.body.removeChild(link) + window.URL.revokeObjectURL(downloadUrl) + }) +}; + onMounted(() => { getList(); }); -- Gitblit v1.9.3