9864d7d41f49ef93cfb681ec20d32da95342563a..f1ee0aa9d6c6c89ee9f0e5d845cd3c64f161aeaf
6 天以前 zouyu
代码调整6
f1ee0a 对比 | 目录
6 天以前 zouyu
代码调整5
09f492 对比 | 目录
6 天以前 zouyu
代码调整4
2d54d8 对比 | 目录
6 天以前 zouyu
代码调整3
ef6afd 对比 | 目录
6 天以前 zouyu
代码调整2
35e2e8 对比 | 目录
6 天以前 zouyu
代码调整
8c04f7 对比 | 目录
已添加9个文件
已修改7个文件
已删除137个文件
45694 ■■■■■ 文件已修改
.env.development 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.production 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
index.html 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/alarmManagement/alarmConfig.js 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/alarmManagement/alarmHistory.js 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/alarmManagement/alarmMonitor.js 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/alarmManagement/alarmStatistics.js 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/customerFile/index.vue 598 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/product/ImportExcel/index.vue 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/product/index.vue 500 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/supplierManage/index.vue 528 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/chatHome/chatHomeIndex/MobileChat.vue 461 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/chatHome/chatHomeIndex/home.vue 175 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue 371 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue 361 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/fileList.vue 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index.vue 272 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index1.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index2.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index3.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index4.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/attendanceManagement/index.vue 714 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/knowledgeBase/index.vue 848 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/meetingBoard/index.vue 498 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/noticeManagement/index.vue 705 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/notificationManagement/index.vue 1187 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/rpaManagement/index.vue 400 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/warningSystem/index.vue 307 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/customerService/afterSalesHandling/components/formDia.vue 212 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/customerService/afterSalesHandling/index.vue 235 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/customerService/feedbackRegistration/components/formDia.vue 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/customerService/feedbackRegistration/index.vue 212 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/Dashboard.vue 301 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/fakePage/index.vue 248 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/device/DeviceManagement.vue 513 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/diagnosis/FaultDiagnosis.vue 411 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/dynamicEnergySaving/index.vue 659 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/energyArea/index.vue 511 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/energyCockpit/index.vue 1380 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/energyPeriodTime/index.vue 444 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/energyPower/components/formDia.vue 235 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/energyPower/index.vue 305 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/energyTrends/index.vue 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/gasManagement/index.vue 624 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/meterCollection/index.vue 556 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/waterManagement/components/formDia.vue 221 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/waterManagement/components/waterBillForm.vue 210 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/waterManagement/index.vue 312 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/waterManagement/waterBill.vue 181 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/waterManagement/waterTrends.vue 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/environmentAccess/accessManagement/index.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/environmentAccess/intelligentInspectionManagement/index.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/environmentAccess/remoteMonitoringOfEquipment/index.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/environmentAccess/vehicleInformationCollection/index.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/calibration/index.vue 218 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/gasTank/simple.vue 566 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/iotMonitor/index.vue 317 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/iotMonitor/indexWD.vue 317 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/ledger/Form.vue 206 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/ledger/Modal.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/ledger/index.vue 330 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/measurementEquipment/components/calibrationDia.vue 267 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/measurementEquipment/components/formDia.vue 253 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/measurementEquipment/filesDia.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/measurementEquipment/index.vue 276 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/Form/MaintainForm.vue 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/Form/RepairForm.vue 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/Modal/MaintainModal.vue 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/Modal/RepairModal.vue 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/index.vue 307 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/MaintenanceForm.vue 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/PlanForm.vue 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Modal/MaintenanceModal.vue 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Modal/PlanModal.vue 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/index.vue 294 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/expenseManagement/Form.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/expenseManagement/Modal.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/expenseManagement/index.vue 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/financialStatements/index.vue 513 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/Form.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/Modal.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/filesDia.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/index.vue 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/index.vue 1149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/dispatchLog/index.vue 285 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/issueManagement/index.vue 282 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/receiptManagement/index.vue 452 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockManagement/index.vue 382 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockWarning/index.vue 1138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/maintenance/MaintenanceManagement.vue 526 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitoring/RealTimeMonitoring.vue 515 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/contractManagement/components/formDia.vue 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/contractManagement/filesDia.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/contractManagement/index.vue 329 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/dimission/components/formDia.vue 290 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/dimission/index.vue 284 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/employeeRecord/components/formDia.vue 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/employeeRecord/index.vue 249 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/onboarding/components/formDia.vue 280 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/onboarding/index.vue 348 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/payrollManagement/components/formDia.vue 315 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/payrollManagement/index.vue 291 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/components/ExpandTable.vue 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/components/Modal.vue 456 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/index.vue 294 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/indexOld.vue 730 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentEntry/index.vue 581 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentHistory/index.vue 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentLedger/index.vue 316 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementInvoiceLedger/Form/EditForm.vue 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementInvoiceLedger/Modal/EditModal.vue 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementInvoiceLedger/Modal/UploadModal.vue 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementInvoiceLedger/index.vue 372 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementInvoiceLedger/indexOld.vue 313 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementLedger/index.vue 1580 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/thePaymentLedger/index.vue 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/operationScheduling/components/formDia.vue 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/operationScheduling/index.vue 258 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionCosting/index.vue 186 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionDispatching/components/formDia.vue 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionDispatching/index.vue 204 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionOrder/index.vue 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionReporting/components/formDia.vue 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionReporting/index.vue 431 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/safetyMonitoring/index.vue 873 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/components/filesDia.vue 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/components/formDia.vue 278 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/components/inspectionFormDia.vue 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/index.vue 381 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/metricMaintenance/index.vue 415 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/nonconformingManagement/components/formDia.vue 249 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/nonconformingManagement/components/inspectionFormDia.vue 257 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/nonconformingManagement/index.vue 306 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/components/filesDia.vue 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/components/formDia.vue 285 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/components/inspectionFormDia.vue 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/index.vue 380 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/rawMaterialInspection/components/filesDia.vue 198 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/rawMaterialInspection/components/formDia.vue 302 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/rawMaterialInspection/components/inspectionFormDia.vue 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/rawMaterialInspection/index.vue 382 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/projectProfit/index.vue 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/taxComparison/index.vue 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/invoiceLedger/index.vue 448 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/invoiceRegistration/index.vue 692 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPayment/index.vue 655 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPaymentHistory/index.vue 221 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPaymentLedger/index.vue 273 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/salesLedger/fileList.vue 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/salesLedger/index.vue 1016 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.development
@@ -1,5 +1,5 @@
# é¡µé¢æ ‡é¢˜
VITE_APP_TITLE = èŠ¯å¯¼äº‘ï¼ˆç®¡ç†ä¿¡æ¯ç³»ç»Ÿï¼‰
VITE_APP_TITLE = è®¾å¤‡åœ¨çº¿ç›‘测诊断及维修系统
# å¼€å‘环境配置
VITE_APP_ENV = 'development'
.env.production
@@ -1,5 +1,5 @@
# é¡µé¢æ ‡é¢˜
VITE_APP_TITLE = MIS(管理信息系统)
VITE_APP_TITLE = è®¾å¤‡åœ¨çº¿ç›‘测诊断及维修系统
# ç”Ÿäº§çŽ¯å¢ƒé…ç½®
VITE_APP_ENV = 'production'
index.html
@@ -7,7 +7,7 @@
  <meta name="renderer" content="webkit">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <link rel="icon" href="/favicon.ico">
  <title>MIS(管理信息系统)</title>
  <title>设备在线监测诊断及维修系统</title>
  <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
  <style>
    html,
src/api/alarmManagement/alarmConfig.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
import request from '@/utils/request';
// æŸ¥è¯¢æŠ¥è­¦é…ç½®åˆ—表
export function listAlarmConfig(query) {
  return request({
    url: '/alarm/config/list',
    method: 'get',
    params: query
  });
}
// èŽ·å–æŠ¥è­¦é…ç½®è¯¦ç»†ä¿¡æ¯
export function getAlarmConfig(configId) {
  return request({
    url: '/alarm/config/' + configId,
    method: 'get'
  });
}
// æ–°å¢žæŠ¥è­¦é…ç½®
export function addAlarmConfig(data) {
  return request({
    url: '/alarm/config',
    method: 'post',
    data: data
  });
}
// ä¿®æ”¹æŠ¥è­¦é…ç½®
export function updateAlarmConfig(data) {
  return request({
    url: '/alarm/config',
    method: 'put',
    data: data
  });
}
// åˆ é™¤æŠ¥è­¦é…ç½®
export function delAlarmConfig(configIds) {
  return request({
    url: '/alarm/config/' + configIds,
    method: 'delete'
  });
}
// ä¿®æ”¹æŠ¥è­¦é…ç½®çŠ¶æ€
export function changeStatus(configId, status) {
  const data = {
    configId,
    status
  };
  return request({
    url: '/alarm/config/changeStatus',
    method: 'put',
    data: data
  });
}
// å¯¼å‡ºæŠ¥è­¦é…ç½®
export function exportAlarmConfig(query) {
  return request({
    url: '/alarm/config/export',
    method: 'get',
    params: query
  });
}
src/api/alarmManagement/alarmHistory.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
import request from '@/utils/request';
// æŸ¥è¯¢æŠ¥è­¦åŽ†å²åˆ—è¡¨
export function listAlarmHistory(query) {
  return request({
    url: '/alarm/history/list',
    method: 'get',
    params: query
  });
}
// èŽ·å–æŠ¥è­¦åŽ†å²è¯¦æƒ…
export function getAlarmHistoryDetail(alarmId) {
  return request({
    url: '/alarm/history/detail/' + alarmId,
    method: 'get'
  });
}
// å¯¼å‡ºæŠ¥è­¦åŽ†å²
export function exportAlarmHistory(query) {
  return request({
    url: '/alarm/history/export',
    method: 'get',
    params: query
  });
}
src/api/alarmManagement/alarmMonitor.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
import request from '@/utils/request';
// æŸ¥è¯¢æŠ¥è­¦ç›‘控列表
export function listAlarmMonitor(query) {
  return request({
    url: '/alarm/monitor/list',
    method: 'get',
    params: query
  });
}
// ç¡®è®¤æŠ¥è­¦
export function confirmAlarm(data) {
  return request({
    url: '/alarm/monitor/confirm',
    method: 'post',
    data: data
  });
}
// è§£å†³æŠ¥è­¦
export function resolveAlarm(data) {
  return request({
    url: '/alarm/monitor/resolve',
    method: 'post',
    data: data
  });
}
// èŽ·å–æŠ¥è­¦è¯¦æƒ…
export function getAlarmDetail(alarmId) {
  return request({
    url: '/alarm/monitor/detail/' + alarmId,
    method: 'get'
  });
}
src/api/alarmManagement/alarmStatistics.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,55 @@
import request from '@/utils/request';
// èŽ·å–æŠ¥è­¦ç»Ÿè®¡æ•°æ®
export function getAlarmStatistics(query) {
  return request({
    url: '/alarm/statistics',
    method: 'get',
    params: query
  });
}
// èŽ·å–æŠ¥è­¦ç±»åž‹åˆ†å¸ƒ
export function getAlarmTypeDistribution(query) {
  return request({
    url: '/alarm/statistics/typeDistribution',
    method: 'get',
    params: query
  });
}
// èŽ·å–æŠ¥è­¦ç­‰çº§åˆ†å¸ƒ
export function getAlarmLevelDistribution(query) {
  return request({
    url: '/alarm/statistics/levelDistribution',
    method: 'get',
    params: query
  });
}
// èŽ·å–æŠ¥è­¦è¶‹åŠ¿åˆ†æž
export function getAlarmTrend(query) {
  return request({
    url: '/alarm/statistics/trend',
    method: 'get',
    params: query
  });
}
// èŽ·å–è®¾å¤‡æŠ¥è­¦æŽ’è¡Œæ¦œ
export function getDeviceAlarmRank(query) {
  return request({
    url: '/alarm/statistics/deviceRank',
    method: 'get',
    params: query
  });
}
// èŽ·å–æŠ¥è­¦å¤„ç†è€—æ—¶ç»Ÿè®¡
export function getHandleTimeStatistics(query) {
  return request({
    url: '/alarm/statistics/handleTime',
    method: 'get',
    params: query
  });
}
src/main.js
@@ -76,7 +76,7 @@
app.config.globalProperties.addDateRange = addDateRange;
app.config.globalProperties.selectDictLabel = selectDictLabel;
app.config.globalProperties.selectDictLabels = selectDictLabels;
app.config.globalProperties.javaApi = "http://114.132.189.42:7004";
app.config.globalProperties.javaApi = "http://10.136.12.71:8020";
app.config.globalProperties.HaveJson = (val) => {
  return JSON.parse(JSON.stringify(val));
};
src/router/index.js
@@ -108,21 +108,21 @@
      }
    ]
  },
  {
    path: '/main/MobileChat',
    component: Layout,
    redirect: '',
    hidden: true,
    permissions: ['MobileChat:edit'],
    children: [
      {
        path: '',
        component: () => import('@/views/chatHome/chatHomeIndex/MobileChat'),
        name: 'MobileChat',
        meta: { title: 'AI对话', activeMenu: '/chatHome/chatHomeIndex'}
      }
    ]
  },
  // {
  //   path: '/main/MobileChat',
  //   component: Layout,
  //   redirect: '',
  //   hidden: true,
  //   permissions: ['MobileChat:edit'],
  //   children: [
  //     {
  //       path: '',
  //       component: () => import('@/views/chatHome/chatHomeIndex/MobileChat'),
  //       name: 'MobileChat',
  //       meta: { title: 'AI对话', activeMenu: '/chatHome/chatHomeIndex'}
  //     }
  //   ]
  // },
  {
    path: '/system/role-auth',
    component: Layout,
src/views/basicData/customerFile/index.vue
ÎļþÒÑɾ³ý
src/views/basicData/product/ImportExcel/index.vue
ÎļþÒÑɾ³ý
src/views/basicData/product/index.vue
ÎļþÒÑɾ³ý
src/views/basicData/supplierManage/index.vue
ÎļþÒÑɾ³ý
src/views/chatHome/chatHomeIndex/MobileChat.vue
ÎļþÒÑɾ³ý
src/views/chatHome/chatHomeIndex/home.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/fileList.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/index1.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/index2.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/index3.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/index4.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/attendanceManagement/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/knowledgeBase/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/meetingBoard/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/noticeManagement/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/notificationManagement/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/rpaManagement/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/warningSystem/index.vue
ÎļþÒÑɾ³ý
src/views/customerService/afterSalesHandling/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/customerService/afterSalesHandling/index.vue
ÎļþÒÑɾ³ý
src/views/customerService/feedbackRegistration/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/customerService/feedbackRegistration/index.vue
ÎļþÒÑɾ³ý
src/views/dashboard/Dashboard.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,301 @@
<template>
  <div class="dashboard-container">
    <!-- ç»Ÿè®¡å¡ç‰‡ -->
    <el-row :gutter="20">
      <el-col :span="6">
        <el-card class="statistics-card" shadow="hover">
          <div class="card-content">
            <div class="card-title">设备在线率</div>
            <div class="card-value">{{ onlineRate }}%</div>
            <div class="card-desc">当前在线设备数:{{ onlineCount }} / {{ totalDevices }}</div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="statistics-card" shadow="hover">
          <div class="card-content">
            <div class="card-title">故障预警数</div>
            <div class="card-value">{{ warningCount }}</div>
            <div class="card-desc">高风险:{{ highRiskCount }} | ä¸­é£Žé™©ï¼š{{ mediumRiskCount }} | ä½Žé£Žé™©ï¼š{{ lowRiskCount }}</div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="statistics-card" shadow="hover">
          <div class="card-content">
            <div class="card-title">待处理维修单</div>
            <div class="card-value">{{ pendingOrders }}</div>
            <div class="card-desc">处理中:{{ processingOrders }} | å·²å®Œæˆï¼š{{ completedOrders }}</div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="statistics-card" shadow="hover">
          <div class="card-content">
            <div class="card-title">重点设备运行状态</div>
            <div class="card-value">{{ normalDevices }} æ­£å¸¸</div>
            <div class="card-desc">异常:{{ abnormalDevices }} | æ•…障:{{ faultDevices }}</div>
          </div>
        </el-card>
      </el-col>
    </el-row>
    <!-- å›¾è¡¨åŒºåŸŸ -->
    <el-row :gutter="20" style="margin-top: 20px;">
      <!-- è®¾å¤‡å¥åº·åº¦è¶‹åŠ¿å›¾ -->
      <el-col :span="12">
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>设备健康度趋势图</span>
            </div>
          </template>
          <div ref="healthChartRef" class="chart-container"></div>
        </el-card>
      </el-col>
      <!-- è¿‘7日故障类型统计 -->
      <el-col :span="12">
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>近7日故障类型统计</span>
            </div>
          </template>
          <div ref="faultChartRef" class="chart-container"></div>
        </el-card>
      </el-col>
    </el-row>
    <!-- é‡ç‚¹è®¾å¤‡è¿è¡ŒçŠ¶æ€å¡ç‰‡ -->
    <el-card shadow="hover" style="margin-top: 20px;">
      <template #header>
        <div class="card-header">
          <span>重点设备运行状态</span>
        </div>
      </template>
      <el-table :data="keyDevices" stripe style="width: 100%">
        <el-table-column prop="name" label="设备名称" width="180"></el-table-column>
        <el-table-column prop="model" label="型号" width="120"></el-table-column>
        <el-table-column prop="ip" label="IP地址" width="150"></el-table-column>
        <el-table-column prop="status" label="状态" width="100">
          <template #default="scope">
            <el-tag :type="scope.row.status === 'online' ? 'success' : scope.row.status === 'warning' ? 'warning' : 'danger'">
              {{ scope.row.status === 'online' ? '在线' : scope.row.status === 'warning' ? '预警' : '故障' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="temperature" label="温度(℃)" width="100"></el-table-column>
        <el-table-column prop="pressure" label="压力(MPa)" width="100"></el-table-column>
        <el-table-column prop="speed" label="转速(rpm)" width="100"></el-table-column>
        <el-table-column prop="health" label="健康度" width="120">
          <template #default="scope">
            <el-progress :percentage="scope.row.health" :stroke-width="10"></el-progress>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
  </div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
// ç»Ÿè®¡æ•°æ®
const onlineRate = ref(85)
const onlineCount = ref(170)
const totalDevices = ref(200)
const warningCount = ref(23)
const highRiskCount = ref(5)
const mediumRiskCount = ref(12)
const lowRiskCount = ref(6)
const pendingOrders = ref(15)
const processingOrders = ref(8)
const completedOrders = ref(45)
const normalDevices = ref(162)
const abnormalDevices = ref(18)
const faultDevices = ref(10)
// é‡ç‚¹è®¾å¤‡åˆ—表
const keyDevices = ref([
  { name: '空压机A-001', model: 'KA-200', ip: '192.168.1.101', status: 'online', temperature: 42, pressure: 0.8, speed: 1450, health: 92 },
  { name: '冷却塔B-002', model: 'CT-300', ip: '192.168.1.102', status: 'warning', temperature: 58, pressure: 0.6, speed: 980, health: 75 },
  { name: 'æ°´æ³µC-003', model: 'WP-150', ip: '192.168.1.103', status: 'online', temperature: 38, pressure: 1.2, speed: 1200, health: 88 },
  { name: '发电机D-004', model: 'GE-500', ip: '192.168.1.104', status: 'danger', temperature: 75, pressure: 0.5, speed: 1500, health: 60 },
  { name: '变压器E-005', model: 'TR-1000', ip: '192.168.1.105', status: 'online', temperature: 45, pressure: 0, speed: 0, health: 95 }
])
// å›¾è¡¨å¼•用
const healthChartRef = ref(null)
const faultChartRef = ref(null)
let healthChart = null
let faultChart = null
// å¥åº·åº¦è¶‹åŠ¿æ•°æ®
const healthTrendData = {
  dates: ['12-10', '12-11', '12-12', '12-13', '12-14', '12-15', '12-16'],
  values: [88, 90, 85, 87, 92, 91, 93]
}
// æ•…障类型统计数据
const faultTypeData = {
  types: ['温度异常', '压力超标', '转速异常', '振动过大', '其他'],
  values: [15, 8, 12, 6, 3]
}
// åˆå§‹åŒ–健康度趋势图
const initHealthChart = () => {
  if (healthChartRef.value) {
    healthChart = echarts.init(healthChartRef.value)
    const option = {
      tooltip: {
        trigger: 'axis',
        axisPointer: {
          type: 'cross',
          label: {
            backgroundColor: '#6a7985'
          }
        }
      },
      grid: {
        left: '3%',
        right: '4%',
        bottom: '3%',
        containLabel: true
      },
      xAxis: {
        type: 'category',
        boundaryGap: false,
        data: healthTrendData.dates
      },
      yAxis: {
        type: 'value',
        min: 70,
        max: 100,
        name: '健康度(%)'
      },
      series: [
        {
          name: '健康度',
          type: 'line',
          stack: '总量',
          areaStyle: {},
          emphasis: {
            focus: 'series'
          },
          data: healthTrendData.values,
          itemStyle: {
            color: '#67c23a'
          },
          lineStyle: {
            width: 3
          }
        }
      ]
    }
    healthChart.setOption(option)
  }
}
// åˆå§‹åŒ–故障类型统计饼图
const initFaultChart = () => {
  if (faultChartRef.value) {
    faultChart = echarts.init(faultChartRef.value)
    const option = {
      tooltip: {
        trigger: 'item'
      },
      legend: {
        orient: 'vertical',
        left: 'left'
      },
      series: [
        {
          name: '故障类型',
          type: 'pie',
          radius: '50%',
          data: faultTypeData.types.map((type, index) => ({
            name: type,
            value: faultTypeData.values[index]
          })),
          emphasis: {
            itemStyle: {
              shadowBlur: 10,
              shadowOffsetX: 0,
              shadowColor: 'rgba(0, 0, 0, 0.5)'
            }
          }
        }
      ]
    }
    faultChart.setOption(option)
  }
}
// ç›‘听窗口大小变化,调整图表大小
const handleResize = () => {
  healthChart?.resize()
  faultChart?.resize()
}
onMounted(() => {
  initHealthChart()
  initFaultChart()
  window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
  healthChart?.dispose()
  faultChart?.dispose()
})
</script>
<style scoped>
.dashboard-container {
  padding: 20px;
  background-color: #f5f7fa;
  min-height: 100vh;
}
.statistics-card {
  height: 180px;
}
.card-content {
  display: flex;
  flex-direction: column;
  height: 100%;
  justify-content: center;
  align-items: center;
}
.card-title {
  font-size: 16px;
  color: #606266;
  margin-bottom: 10px;
}
.card-value {
  font-size: 32px;
  font-weight: bold;
  color: #303133;
  margin-bottom: 8px;
}
.card-desc {
  font-size: 14px;
  color: #909399;
}
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.chart-container {
  width: 100%;
  height: 350px;
}
</style>
src/views/demo/fakePage/index.vue
ÎļþÒÑɾ³ý
src/views/device/DeviceManagement.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,513 @@
<template>
  <div class="device-management-container">
    <el-card shadow="hover">
      <template #header>
        <div class="card-header">
          <span>设备管理</span>
          <div class="header-buttons">
            <el-button type="primary" @click="showAddDeviceDialog">
              <el-icon-plus /> æ·»åŠ è®¾å¤‡
            </el-button>
            <el-button @click="exportDevices">
              <el-icon-download /> å¯¼å‡º
            </el-button>
            <el-button @click="showImportDialog">
              <el-icon-upload /> å¯¼å…¥
            </el-button>
          </div>
        </div>
      </template>
      <!-- ç­›é€‰æ¡ä»¶ -->
      <el-form :inline="true" :model="filterForm" class="device-filter-form">
        <el-form-item label="设备名称">
          <el-input v-model="filterForm.name" placeholder="请输入设备名称" clearable></el-input>
        </el-form-item>
        <el-form-item label="型号">
          <el-input v-model="filterForm.model" placeholder="请输入型号" clearable></el-input>
        </el-form-item>
        <el-form-item label="状态">
          <el-select v-model="filterForm.status" placeholder="请选择状态" clearable>
            <el-option label="在线" value="online"></el-option>
            <el-option label="离线" value="offline"></el-option>
            <el-option label="故障" value="fault"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleFilter">查询</el-button>
          <el-button @click="resetFilter">重置</el-button>
        </el-form-item>
      </el-form>
      <!-- è®¾å¤‡åˆ—表 -->
      <el-table :data="filteredDevices" stripe style="width: 100%" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55"></el-table-column>
        <el-table-column prop="id" label="设备ID" width="100"></el-table-column>
        <el-table-column prop="name" label="设备名称" width="180"></el-table-column>
        <el-table-column prop="model" label="型号" width="120"></el-table-column>
        <el-table-column prop="ip" label="IP地址" width="150"></el-table-column>
        <el-table-column prop="status" label="状态" width="100">
          <template #default="scope">
            <el-tag :type="scope.row.status === 'online' ? 'success' : scope.row.status === 'offline' ? 'info' : 'danger'">
              {{ scope.row.status === 'online' ? '在线' : scope.row.status === 'offline' ? '离线' : '故障' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="location" label="安装位置" width="180"></el-table-column>
        <el-table-column prop="installDate" label="安装日期" width="150"></el-table-column>
        <el-table-column prop="manufacturer" label="制造商" width="150"></el-table-column>
        <el-table-column label="操作" width="220" fixed="right">
          <template #default="scope">
            <el-button type="text" size="small" @click="showDeviceDetail(scope.row)">
              è¯¦æƒ…
            </el-button>
            <el-button type="text" size="small" @click="showEditDeviceDialog(scope.row)">
              ç¼–辑
            </el-button>
            <el-button type="text" size="small" @click="handleDelete(scope.row)">
              åˆ é™¤
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- åˆ†é¡µ -->
      <div class="pagination-container">
        <el-pagination
          background
          layout="total, sizes, prev, pager, next, jumper"
          :total="filteredDevices.length"
          :current-page="currentPage"
          :page-sizes="[10, 20, 50, 100]"
          :page-size="pageSize"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        ></el-pagination>
      </div>
    </el-card>
    <!-- æ·»åŠ è®¾å¤‡å¯¹è¯æ¡† -->
    <el-dialog v-model="addDeviceDialogVisible" title="添加设备" width="600px">
      <el-form :model="deviceForm" :rules="deviceRules" ref="deviceFormRef" label-width="100px">
        <el-form-item label="设备名称" prop="name">
          <el-input v-model="deviceForm.name" placeholder="请输入设备名称"></el-input>
        </el-form-item>
        <el-form-item label="型号" prop="model">
          <el-input v-model="deviceForm.model" placeholder="请输入型号"></el-input>
        </el-form-item>
        <el-form-item label="IP地址" prop="ip">
          <el-input v-model="deviceForm.ip" placeholder="请输入IP地址"></el-input>
        </el-form-item>
        <el-form-item label="安装位置" prop="location">
          <el-input v-model="deviceForm.location" placeholder="请输入安装位置"></el-input>
        </el-form-item>
        <el-form-item label="制造商" prop="manufacturer">
          <el-input v-model="deviceForm.manufacturer" placeholder="请输入制造商"></el-input>
        </el-form-item>
        <el-form-item label="安装日期" prop="installDate">
          <el-date-picker v-model="deviceForm.installDate" type="date" placeholder="选择安装日期" style="width: 100%"></el-date-picker>
        </el-form-item>
        <el-form-item label="状态" prop="status">
          <el-select v-model="deviceForm.status" placeholder="请选择状态">
            <el-option label="在线" value="online"></el-option>
            <el-option label="离线" value="offline"></el-option>
            <el-option label="故障" value="fault"></el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="addDeviceDialogVisible = false">取消</el-button>
          <el-button type="primary" @click="handleAddDevice">确定</el-button>
        </span>
      </template>
    </el-dialog>
    <!-- ç¼–辑设备对话框 -->
    <el-dialog v-model="editDeviceDialogVisible" title="编辑设备" width="600px">
      <el-form :model="deviceForm" :rules="deviceRules" ref="deviceFormRef" label-width="100px">
        <el-form-item label="设备名称" prop="name">
          <el-input v-model="deviceForm.name" placeholder="请输入设备名称"></el-input>
        </el-form-item>
        <el-form-item label="型号" prop="model">
          <el-input v-model="deviceForm.model" placeholder="请输入型号"></el-input>
        </el-form-item>
        <el-form-item label="IP地址" prop="ip">
          <el-input v-model="deviceForm.ip" placeholder="请输入IP地址"></el-input>
        </el-form-item>
        <el-form-item label="安装位置" prop="location">
          <el-input v-model="deviceForm.location" placeholder="请输入安装位置"></el-input>
        </el-form-item>
        <el-form-item label="制造商" prop="manufacturer">
          <el-input v-model="deviceForm.manufacturer" placeholder="请输入制造商"></el-input>
        </el-form-item>
        <el-form-item label="安装日期" prop="installDate">
          <el-date-picker v-model="deviceForm.installDate" type="date" placeholder="选择安装日期" style="width: 100%"></el-date-picker>
        </el-form-item>
        <el-form-item label="状态" prop="status">
          <el-select v-model="deviceForm.status" placeholder="请选择状态">
            <el-option label="在线" value="online"></el-option>
            <el-option label="离线" value="offline"></el-option>
            <el-option label="故障" value="fault"></el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="editDeviceDialogVisible = false">取消</el-button>
          <el-button type="primary" @click="handleEditDevice">确定</el-button>
        </span>
      </template>
    </el-dialog>
    <!-- è®¾å¤‡è¯¦æƒ…对话框 -->
    <el-dialog v-model="deviceDetailDialogVisible" title="设备详情" width="600px">
      <el-descriptions :column="1" border>
        <el-descriptions-item label="设备名称">{{ selectedDevice.name }}</el-descriptions-item>
        <el-descriptions-item label="设备ID">{{ selectedDevice.id }}</el-descriptions-item>
        <el-descriptions-item label="型号">{{ selectedDevice.model }}</el-descriptions-item>
        <el-descriptions-item label="IP地址">{{ selectedDevice.ip }}</el-descriptions-item>
        <el-descriptions-item label="状态">
          <el-tag :type="selectedDevice.status === 'online' ? 'success' : selectedDevice.status === 'offline' ? 'info' : 'danger'">
            {{ selectedDevice.status === 'online' ? '在线' : selectedDevice.status === 'offline' ? '离线' : '故障' }}
          </el-tag>
        </el-descriptions-item>
        <el-descriptions-item label="安装位置">{{ selectedDevice.location }}</el-descriptions-item>
        <el-descriptions-item label="制造商">{{ selectedDevice.manufacturer }}</el-descriptions-item>
        <el-descriptions-item label="安装日期">{{ selectedDevice.installDate }}</el-descriptions-item>
        <el-descriptions-item label="创建时间">{{ selectedDevice.createTime }}</el-descriptions-item>
      </el-descriptions>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="deviceDetailDialogVisible = false">关闭</el-button>
        </span>
      </template>
    </el-dialog>
    <!-- å¯¼å…¥å¯¹è¯æ¡† -->
    <el-dialog v-model="importDialogVisible" title="导入设备" width="400px">
      <el-upload
        class="upload-demo"
        action="#"
        :on-change="handleFileChange"
        :auto-upload="false"
        accept=".xlsx,.xls"
      >
        <el-button type="primary">选择文件</el-button>
        <template #tip>
          <div class="el-upload__tip">
            åªèƒ½ä¸Šä¼  xlsx/xls æ–‡ä»¶ï¼Œä¸”不超过 2MB
          </div>
        </template>
      </el-upload>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="importDialogVisible = false">取消</el-button>
          <el-button type="primary" @click="handleImport">确定</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { ref, computed } from 'vue'
// è®¾å¤‡åˆ—表数据
const devices = ref([
  {
    id: 'D001',
    name: '空压机A-001',
    model: 'KA-200',
    ip: '192.168.1.101',
    status: 'online',
    location: '车间A-1区',
    manufacturer: '康普斯',
    installDate: '2023-05-10',
    createTime: '2023-05-10 10:30:00'
  },
  {
    id: 'D002',
    name: '冷却塔B-002',
    model: 'CT-300',
    ip: '192.168.1.102',
    status: 'warning',
    location: '车间B-2区',
    manufacturer: '良机',
    installDate: '2023-06-15',
    createTime: '2023-06-15 14:20:00'
  },
  {
    id: 'D003',
    name: 'æ°´æ³µC-003',
    model: 'WP-150',
    ip: '192.168.1.103',
    status: 'online',
    location: '车间C-3区',
    manufacturer: '格兰富',
    installDate: '2023-07-20',
    createTime: '2023-07-20 09:15:00'
  },
  {
    id: 'D004',
    name: '发电机D-004',
    model: 'GE-500',
    ip: '192.168.1.104',
    status: 'fault',
    location: '机房',
    manufacturer: '卡特彼勒',
    installDate: '2023-08-25',
    createTime: '2023-08-25 16:45:00'
  },
  {
    id: 'D005',
    name: '变压器E-005',
    model: 'TR-1000',
    ip: '192.168.1.105',
    status: 'online',
    location: '配电房',
    manufacturer: 'ABB',
    installDate: '2023-09-30',
    createTime: '2023-09-30 11:20:00'
  }
])
// ç­›é€‰è¡¨å•
const filterForm = ref({
  name: '',
  model: '',
  status: ''
})
// åˆ†é¡µæ•°æ®
const currentPage = ref(1)
const pageSize = ref(10)
// å¯¹è¯æ¡†çŠ¶æ€
const addDeviceDialogVisible = ref(false)
const editDeviceDialogVisible = ref(false)
const deviceDetailDialogVisible = ref(false)
const importDialogVisible = ref(false)
// è®¾å¤‡è¡¨å•数据
const deviceForm = ref({
  id: '',
  name: '',
  model: '',
  ip: '',
  status: 'online',
  location: '',
  manufacturer: '',
  installDate: ''
})
// è¡¨å•验证规则
const deviceRules = ref({
  name: [{ required: true, message: '请输入设备名称', trigger: 'blur' }],
  model: [{ required: true, message: '请输入型号', trigger: 'blur' }],
  ip: [{ required: true, message: '请输入IP地址', trigger: 'blur' }],
  location: [{ required: true, message: '请输入安装位置', trigger: 'blur' }],
  manufacturer: [{ required: true, message: '请输入制造商', trigger: 'blur' }],
  installDate: [{ required: true, message: '请选择安装日期', trigger: 'change' }],
  status: [{ required: true, message: '请选择状态', trigger: 'change' }]
})
// è¡¨å•引用
const deviceFormRef = ref(null)
// é€‰ä¸­çš„设备
const selectedDevice = ref({})
// é€‰ä¸­çš„设备列表(用于批量操作)
const selectedDevices = ref([])
// å¯¼å…¥çš„æ–‡ä»¶
const importFile = ref(null)
// è¿‡æ»¤åŽçš„设备列表
const filteredDevices = computed(() => {
  let result = [...devices.value]
  // æŒ‰åç§°ç­›é€‰
  if (filterForm.value.name) {
    result = result.filter(device => device.name.includes(filterForm.value.name))
  }
  // æŒ‰åž‹å·ç­›é€‰
  if (filterForm.value.model) {
    result = result.filter(device => device.model.includes(filterForm.value.model))
  }
  // æŒ‰çŠ¶æ€ç­›é€‰
  if (filterForm.value.status) {
    result = result.filter(device => device.status === filterForm.value.status)
  }
  return result
})
// æ˜¾ç¤ºæ·»åŠ è®¾å¤‡å¯¹è¯æ¡†
const showAddDeviceDialog = () => {
  // é‡ç½®è¡¨å•
  deviceForm.value = {
    id: '',
    name: '',
    model: '',
    ip: '',
    status: 'online',
    location: '',
    manufacturer: '',
    installDate: ''
  }
  addDeviceDialogVisible.value = true
}
// æ˜¾ç¤ºç¼–辑设备对话框
const showEditDeviceDialog = (device) => {
  deviceForm.value = { ...device }
  editDeviceDialogVisible.value = true
}
// æ˜¾ç¤ºè®¾å¤‡è¯¦æƒ…
const showDeviceDetail = (device) => {
  selectedDevice.value = { ...device }
  deviceDetailDialogVisible.value = true
}
// æ˜¾ç¤ºå¯¼å…¥å¯¹è¯æ¡†
const showImportDialog = () => {
  importDialogVisible.value = true
}
// å¤„理添加设备
const handleAddDevice = () => {
  // æ¨¡æ‹Ÿæ·»åŠ è®¾å¤‡
  const newDevice = {
    ...deviceForm.value,
    id: `D${String(devices.value.length + 1).padStart(3, '0')}`,
    createTime: new Date().toLocaleString()
  }
  devices.value.push(newDevice)
  addDeviceDialogVisible.value = false
  ElMessage.success('设备添加成功')
}
// å¤„理编辑设备
const handleEditDevice = () => {
  // æ¨¡æ‹Ÿç¼–辑设备
  const index = devices.value.findIndex(device => device.id === deviceForm.value.id)
  if (index !== -1) {
    devices.value[index] = { ...deviceForm.value }
    editDeviceDialogVisible.value = false
    ElMessage.success('设备编辑成功')
  }
}
// å¤„理删除设备
const handleDelete = (device) => {
  ElMessageBox.confirm('确定要删除该设备吗?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    // æ¨¡æ‹Ÿåˆ é™¤è®¾å¤‡
    const index = devices.value.findIndex(item => item.id === device.id)
    if (index !== -1) {
      devices.value.splice(index, 1)
      ElMessage.success('设备删除成功')
    }
  }).catch(() => {
    // å–消删除
  })
}
// å¤„理筛选
const handleFilter = () => {
  // ç­›é€‰é€»è¾‘已经在computed中实现
}
// é‡ç½®ç­›é€‰æ¡ä»¶
const resetFilter = () => {
  filterForm.value = {
    name: '',
    model: '',
    status: ''
  }
}
// å¤„理分页大小变化
const handleSizeChange = (size) => {
  pageSize.value = size
  currentPage.value = 1
}
// å¤„理当前页变化
const handleCurrentChange = (current) => {
  currentPage.value = current
}
// å¤„理文件变化(导入)
const handleFileChange = (file) => {
  importFile.value = file
}
// å¤„理导入
const handleImport = () => {
  // æ¨¡æ‹Ÿå¯¼å…¥
  if (importFile.value) {
    importDialogVisible.value = false
    ElMessage.success('设备导入成功')
    importFile.value = null
  } else {
    ElMessage.warning('请选择要导入的文件')
  }
}
// å¯¼å‡ºè®¾å¤‡
const exportDevices = () => {
  // æ¨¡æ‹Ÿå¯¼å‡º
  ElMessage.success('设备导出成功')
}
// å¤„理选择变化(用于批量操作)
const handleSelectionChange = (selection) => {
  selectedDevices.value = selection
}
</script>
<style scoped>
.device-management-container {
  padding: 20px;
  background-color: #f5f7fa;
  min-height: 100vh;
}
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.header-buttons {
  display: flex;
  gap: 10px;
}
.device-filter-form {
  margin-bottom: 20px;
  padding: 10px 0;
  border-bottom: 1px solid #ebeef5;
}
.pagination-container {
  display: flex;
  justify-content: flex-end;
  margin-top: 20px;
}
:deep(.el-icon-plus),
:deep(.el-icon-download),
:deep(.el-icon-upload) {
  margin-right: 5px;
}
</style>
src/views/diagnosis/FaultDiagnosis.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,411 @@
<template>
  <div class="fault-diagnosis-container">
    <el-row :gutter="20">
      <!-- å·¦ä¾§ï¼šæ•…障预警列表 -->
      <el-col :span="12">
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>故障预警列表</span>
            </div>
          </template>
          <el-table :data="warningList" stripe style="width: 100%" @row-click="handleWarningClick">
            <el-table-column prop="deviceName" label="设备名称" width="180"></el-table-column>
            <el-table-column prop="warningType" label="预警类型" width="120"></el-table-column>
            <el-table-column prop="riskLevel" label="风险等级" width="100">
              <template #default="scope">
                <el-tag :type="scope.row.riskLevel === 'high' ? 'danger' : scope.row.riskLevel === 'medium' ? 'warning' : 'info'">
                  {{ scope.row.riskLevel === 'high' ? '高' : scope.row.riskLevel === 'medium' ? '中' : '低' }}
                </el-tag>
              </template>
            </el-table-column>
            <el-table-column prop="occurTime" label="发生时间" width="180"></el-table-column>
            <el-table-column prop="status" label="处理状态" width="100">
              <template #default="scope">
                <el-tag :type="scope.row.status === 'pending' ? 'warning' : 'success'">
                  {{ scope.row.status === 'pending' ? '待处理' : '已处理' }}
                </el-tag>
              </template>
            </el-table-column>
          </el-table>
        </el-card>
        <!-- æ•…障历史记录查询 -->
        <el-card shadow="hover" style="margin-top: 20px;">
          <template #header>
            <div class="card-header">
              <span>故障历史记录</span>
            </div>
          </template>
          <el-form :inline="true" :model="historyFilterForm" class="history-filter-form">
            <el-form-item label="设备">
              <el-select v-model="historyFilterForm.deviceId" placeholder="请选择设备" clearable>
                <el-option
                  v-for="device in devices"
                  :key="device.id"
                  :label="device.name"
                  :value="device.id"
                ></el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="时间范围">
              <el-date-picker
                v-model="historyTimeRange"
                type="daterange"
                range-separator="至"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
              ></el-date-picker>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="handleHistorySearch">查询</el-button>
            </el-form-item>
          </el-form>
          <el-table :data="historyList" stripe style="width: 100%" size="small">
            <el-table-column prop="deviceName" label="设备名称" width="150"></el-table-column>
            <el-table-column prop="faultType" label="故障类型" width="120"></el-table-column>
            <el-table-column prop="occurTime" label="发生时间" width="150"></el-table-column>
            <el-table-column prop="dealTime" label="处理时间" width="150"></el-table-column>
            <el-table-column prop="status" label="状态" width="100">
              <template #default="scope">
                <el-tag type="success">{{ scope.row.status }}</el-tag>
              </template>
            </el-table-column>
          </el-table>
          <div class="pagination-container">
            <el-pagination
              background
              layout="total, prev, pager, next"
              :total="historyList.length"
              :page-size="5"
              size="small"
            ></el-pagination>
          </div>
        </el-card>
      </el-col>
      <!-- å³ä¾§ï¼šæ•…障诊断结果 -->
      <el-col :span="12">
        <!-- æ•…障诊断结果 -->
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>故障诊断结果</span>
              <el-button type="primary" size="small" @click="handleDiagnosis">重新诊断</el-button>
            </div>
          </template>
          <div v-if="currentWarning" class="diagnosis-result">
            <h3>{{ currentWarning.deviceName }} - {{ currentWarning.warningType }}</h3>
            <el-descriptions :column="1" border>
              <el-descriptions-item label="风险等级">
                <el-tag :type="currentWarning.riskLevel === 'high' ? 'danger' : currentWarning.riskLevel === 'medium' ? 'warning' : 'info'">
                  {{ currentWarning.riskLevel === 'high' ? '高' : currentWarning.riskLevel === 'medium' ? '中' : '低' }}
                </el-tag>
              </el-descriptions-item>
              <el-descriptions-item label="发生时间">{{ currentWarning.occurTime }}</el-descriptions-item>
              <el-descriptions-item label="原因推测">{{ diagnosisResult.reason }}</el-descriptions-item>
              <el-descriptions-item label="影响范围">{{ diagnosisResult.impact }}</el-descriptions-item>
              <el-descriptions-item label="处理建议">{{ diagnosisResult.suggestion }}</el-descriptions-item>
            </el-descriptions>
          </div>
          <div v-else class="no-selection">
            <el-empty description="请选择一个预警项查看诊断结果"></el-empty>
          </div>
        </el-card>
        <!-- é¢„测性诊断结果 -->
        <el-card shadow="hover" style="margin-top: 20px;">
          <template #header>
            <div class="card-header">
              <span>预测性诊断结果(未来7日故障风险)</span>
            </div>
          </template>
          <div class="prediction-result">
            <el-timeline>
              <el-timeline-item
                v-for="item in predictionList"
                :key="item.date"
                :timestamp="item.date"
                :type="item.riskLevel === 'high' ? 'danger' : item.riskLevel === 'medium' ? 'warning' : 'success'"
              >
                <div class="timeline-content">
                  <h4>{{ item.deviceName }}</h4>
                  <p class="risk-level">
                    é£Žé™©ç­‰çº§ï¼š
                    <el-tag :type="item.riskLevel === 'high' ? 'danger' : item.riskLevel === 'medium' ? 'warning' : 'success'">
                      {{ item.riskLevel === 'high' ? '高' : item.riskLevel === 'medium' ? '中' : '低' }}
                    </el-tag>
                  </p>
                  <p class="fault-type">可能故障类型:{{ item.possibleFault }}</p>
                  <p class="probability">发生概率:{{ item.probability }}%</p>
                </div>
              </el-timeline-item>
            </el-timeline>
          </div>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>
<script setup>
import { ref, reactive } from 'vue'
// è®¾å¤‡åˆ—表
const devices = ref([
  { id: 'D001', name: '空压机A-001' },
  { id: 'D002', name: '冷却塔B-002' },
  { id: 'D003', name: 'æ°´æ³µC-003' },
  { id: 'D004', name: '发电机D-004' },
  { id: 'D005', name: '变压器E-005' }
])
// æ•…障预警列表
const warningList = ref([
  {
    id: 1,
    deviceName: '空压机A-001',
    warningType: '压力异常',
    riskLevel: 'high',
    occurTime: '2024-12-16 14:32:15',
    status: 'pending'
  },
  {
    id: 2,
    deviceName: '冷却塔B-002',
    warningType: '温度过高',
    riskLevel: 'medium',
    occurTime: '2024-12-16 14:30:45',
    status: 'pending'
  },
  {
    id: 3,
    deviceName: 'æ°´æ³µC-003',
    warningType: '振动过大',
    riskLevel: 'medium',
    occurTime: '2024-12-16 14:28:30',
    status: 'pending'
  },
  {
    id: 4,
    deviceName: '发电机D-004',
    warningType: '电流异常',
    riskLevel: 'high',
    occurTime: '2024-12-16 14:25:10',
    status: 'pending'
  },
  {
    id: 5,
    deviceName: '变压器E-005',
    warningType: '电压波动',
    riskLevel: 'low',
    occurTime: '2024-12-16 14:20:05',
    status: 'pending'
  }
])
// å½“前选中的预警项
const currentWarning = ref(warningList.value[0])
// æ•…障诊断结果
const diagnosisResult = reactive({
  reason: '根据设备运行数据推测,故障原因可能是设备内部部件磨损导致的压力异常,需要进一步检查设备的活塞环和气缸套。',
  impact: '如果不及时处理,可能导致设备停机,影响生产线的正常运行,预计停机时间为4-6小时。',
  suggestion: '1. ç«‹å³å®‰æŽ’维修人员进行设备检查;2. æ£€æŸ¥è®¾å¤‡çš„æ´»å¡žçŽ¯å’Œæ°”ç¼¸å¥—ï¼›3. æ›´æ¢ç£¨æŸä¸¥é‡çš„部件;4. æ£€æŸ¥è®¾å¤‡çš„æ¶¦æ»‘系统,确保润滑正常。'
})
// é¢„测性诊断结果
const predictionList = ref([
  {
    date: '2024-12-17',
    deviceName: '空压机A-001',
    riskLevel: 'medium',
    possibleFault: '压力异常',
    probability: 65
  },
  {
    date: '2024-12-18',
    deviceName: '冷却塔B-002',
    riskLevel: 'high',
    possibleFault: '温度过高',
    probability: 85
  },
  {
    date: '2024-12-19',
    deviceName: 'æ°´æ³µC-003',
    riskLevel: 'medium',
    possibleFault: '振动过大',
    probability: 70
  },
  {
    date: '2024-12-20',
    deviceName: '发电机D-004',
    riskLevel: 'high',
    possibleFault: '电流异常',
    probability: 90
  },
  {
    date: '2024-12-21',
    deviceName: '变压器E-005',
    riskLevel: 'low',
    possibleFault: '电压波动',
    probability: 45
  },
  {
    date: '2024-12-22',
    deviceName: '空压机A-001',
    riskLevel: 'high',
    possibleFault: '压力异常',
    probability: 80
  },
  {
    date: '2024-12-23',
    deviceName: '冷却塔B-002',
    riskLevel: 'medium',
    possibleFault: '温度过高',
    probability: 60
  }
])
// æ•…障历史记录查询表单
const historyFilterForm = ref({
  deviceId: ''
})
// åŽ†å²è®°å½•æ—¶é—´èŒƒå›´
const historyTimeRange = ref([])
// æ•…障历史记录
const historyList = ref([
  {
    id: 1,
    deviceName: '空压机A-001',
    faultType: '压力异常',
    occurTime: '2024-12-15 08:30:00',
    dealTime: '2024-12-15 10:45:00',
    status: '已处理'
  },
  {
    id: 2,
    deviceName: '冷却塔B-002',
    faultType: '温度过高',
    occurTime: '2024-12-14 14:20:00',
    dealTime: '2024-12-14 16:15:00',
    status: '已处理'
  },
  {
    id: 3,
    deviceName: 'æ°´æ³µC-003',
    faultType: '振动过大',
    occurTime: '2024-12-13 09:15:00',
    dealTime: '2024-12-13 11:30:00',
    status: '已处理'
  },
  {
    id: 4,
    deviceName: '发电机D-004',
    faultType: '电流异常',
    occurTime: '2024-12-12 16:45:00',
    dealTime: '2024-12-12 18:30:00',
    status: '已处理'
  },
  {
    id: 5,
    deviceName: '变压器E-005',
    faultType: '电压波动',
    occurTime: '2024-12-11 11:20:00',
    dealTime: '2024-12-11 13:15:00',
    status: '已处理'
  }
])
// å¤„理预警项点击
const handleWarningClick = (row) => {
  currentWarning.value = row
}
// é‡æ–°è¯Šæ–­
const handleDiagnosis = () => {
  // æ¨¡æ‹Ÿé‡æ–°è¯Šæ–­
  ElMessage.success('重新诊断完成')
}
// å¤„理历史记录查询
const handleHistorySearch = () => {
  // æ¨¡æ‹ŸæŸ¥è¯¢åŽ†å²è®°å½•
  ElMessage.success('历史记录查询成功')
}
</script>
<style scoped>
.fault-diagnosis-container {
  padding: 20px;
  background-color: #f5f7fa;
  min-height: 100vh;
}
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.diagnosis-result h3 {
  margin-bottom: 20px;
  color: #303133;
}
.no-selection {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 200px;
}
.prediction-result {
  padding: 10px 0;
}
.timeline-content {
  padding: 10px;
  background-color: #fafafa;
  border-radius: 4px;
}
.timeline-content h4 {
  margin-bottom: 10px;
  color: #303133;
}
.timeline-content p {
  margin: 5px 0;
  font-size: 14px;
  color: #606266;
}
.risk-level {
  display: flex;
  align-items: center;
  gap: 5px;
}
.fault-type {
  color: #606266;
}
.probability {
  color: #606266;
}
.history-filter-form {
  margin-bottom: 20px;
  padding: 10px 0;
  border-bottom: 1px solid #ebeef5;
}
.pagination-container {
  display: flex;
  justify-content: flex-end;
  margin-top: 20px;
}
</style>
src/views/energyManagement/dynamicEnergySaving/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/energyArea/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/energyCockpit/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/energyPeriodTime/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/energyPower/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/energyPower/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/energyTrends/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/gasManagement/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/meterCollection/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/waterManagement/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/waterManagement/components/waterBillForm.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/waterManagement/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/waterManagement/waterBill.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/waterManagement/waterTrends.vue
ÎļþÒÑɾ³ý
src/views/environmentAccess/accessManagement/index.vue
ÎļþÒÑɾ³ý
src/views/environmentAccess/intelligentInspectionManagement/index.vue
ÎļþÒÑɾ³ý
src/views/environmentAccess/remoteMonitoringOfEquipment/index.vue
ÎļþÒÑɾ³ý
src/views/environmentAccess/vehicleInformationCollection/index.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/calibration/index.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/gasTank/simple.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/iotMonitor/index.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/iotMonitor/indexWD.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/ledger/Form.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/ledger/Modal.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/ledger/index.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/measurementEquipment/components/calibrationDia.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/measurementEquipment/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/measurementEquipment/filesDia.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/measurementEquipment/index.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/repair/Form/MaintainForm.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/repair/Form/RepairForm.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/repair/Modal/MaintainModal.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/repair/Modal/RepairModal.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/repair/index.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/upkeep/Form/MaintenanceForm.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/upkeep/Form/PlanForm.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/upkeep/Modal/MaintenanceModal.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/upkeep/Modal/PlanModal.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/upkeep/index.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/expenseManagement/Form.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/expenseManagement/Modal.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/expenseManagement/index.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/financialStatements/index.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/revenueManagement/Form.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/revenueManagement/Modal.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/revenueManagement/filesDia.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/revenueManagement/index.vue
ÎļþÒÑɾ³ý
src/views/index.vue
@@ -1,805 +1,392 @@
<template>
    <div class="dashboard">
        <!-- é¡¶éƒ¨æ¨ªå‘两栏 -->
        <div class="dashboard-top">
            <!-- å·¦ï¼šä¼ä¸šä¿¡æ¯+三大数据卡片(上下排列) -->
            <div class="top-left">
                <div class="company-info">
                    <div class="section-title">登陆信息</div>
                    <div style="display: flex;align-items: center;gap: 20px">
                        <img :src="userStore.avatar" class="avatar" alt=""/>
                        <div class="company-card">
                            <div class="company-name">{{userStore.name}}</div>
                            <div class="company-meta">{{userStore.roleName}}</div>
                        </div>
                        <div style="display: flex;align-items: center;gap: 8px">
                            <el-icon color="#5053B5" size="22"><Clock /></el-icon>
                            <span>登陆日期:{{userStore.currentLoginTime}}</span>
                        </div>
                    </div>
                </div>
                <div class="data-cards">
                    <div class="data-card sales">
                        <div class="data-title">销售数据</div>
                        <div class="data-num">
                            <div>
                                <div class="data-desc">本月销售额/元</div>
                                <div class="data-value">{{businessInfo.monthSaleMoney}}</div>
                            </div>
                            <div>
                                <div class="data-desc">未开票金额/元</div>
                                <div class="data-value">{{businessInfo.monthSaleHaveMoney}}</div>
                            </div>
                        </div>
                    </div>
                    <div class="data-card purchase">
                        <div class="data-title">采购数据</div>
                        <div class="data-num">
                            <div>
                                <div class="data-desc">本月采购额/元</div>
                                <div class="data-value">{{businessInfo.monthPurchaseMoney}}</div>
                            </div>
                            <div>
                                <div class="data-desc">待付款金额/元</div>
                                <div class="data-value">{{businessInfo.monthPurchaseHaveMoney}}</div>
                            </div>
                        </div>
                    </div>
                    <div class="data-card inventory">
                        <div class="data-title">库存数据</div>
                        <div class="data-num">
                            <div>
                                <div class="data-desc">当前库存总量/ä»¶</div>
                                <div class="data-value">{{businessInfo.inventoryNum}}</div>
                            </div>
                            <div>
                                <div class="data-desc">今日入库/ä»¶</div>
                                <div class="data-value">{{businessInfo.todayInventoryNum}}</div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <!-- å³ï¼šå¾…办事项 -->
            <div class="todo-panel">
                <div class="section-title">待办事项</div>
                <ul class="todo-list" v-if="todoList.length > 0">
                    <li v-for="item in todoList" :key="item.id">
                        <div style="display: flex;flex-direction: column;justify-content: space-between;width: 100%;gap: 20px">
                            <div style="display: flex;justify-content: space-between;align-items: center;">
                                <div class="todo-title">流程编号:{{item.approveId}}</div>
                                <div class="todo-division">申请部门:{{item.approveDeptName}}</div>
                                <div class="todo-time">{{item.approveTime}}</div>
                            </div>
                            <div class="todo-division">审批事由:{{item.approveReason}}</div>
                        </div>
                    </li>
                </ul>
                <div v-else style="text-align: center">
                    æš‚无数据
                </div>
            </div>
        </div>
        <!-- ä¸­éƒ¨æ¨ªå‘两栏 -->
        <div class="dashboard-row">
            <div class="main-panel">
                <div class="section-title">客户合同金额分析</div>
                <div class="contract-summary">
                    <div class="contract-info">
                        <img src="../assets/images/khtitle.png" alt="" style="width: 42px"/>
                        <div class="contract-card">
                            <div class="contract-name">总合同金额(元)</div>
                            <div class="contract-meta">
                                <div class="main-amount">{{sum}}</div>
                                <div>周同比: <span class="up">{{yny}}% </span> æ—¥çŽ¯æ¯”: <span class="up">{{chain}}% </span></div>
                            </div>
                        </div>
                    </div>
                </div>
                <div style="display: flex;align-items: center;gap: 20px;justify-content: space-evenly;height: 180px;margin-top: 20px">
                    <div>
                        <Echarts ref="chart" :legend="pieLegend" :chartStyle="chartStylePie"
                                         :series="materialPieSeries"
                                         :tooltip="pieTooltip"></Echarts>
                    </div>
                    <ul class="contract-list">
                        <li v-for="item in materialPieSeries[0].data" :key="item.name">
                            <div style="display: flex;align-items: center;justify-content: space-between;width: 100%">
                                <div class="line" :style="{color: item.itemStyle.color}">●{{item.name}}</div>
                                <div style="width: 70px">{{item.rate}}%</div>
                                <div>ï¿¥{{item.value}}</div>
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
            <div class="main-panel">
                <div style="display: flex;justify-content: space-between;">
                    <div class="section-title">应收应付统计</div>
<!--                    <el-radio-group v-model="radio1" size="large" @change="statisticsReceivable">-->
<!--                        <el-radio-button label="按周" :value="1" />-->
<!--                        <el-radio-button label="按月" :value="2" />-->
<!--                        <el-radio-button label="按季度" :value="3" />-->
<!--                    </el-radio-group>-->
                </div>
                <Echarts ref="chart"
                                 :color="barColors2"
                                 :chartStyle="chartStyle"
                                 :grid="grid"
                                 :series="barSeries"
                                 :tooltip="tooltip"
                                 :xAxis="xAxis"
                                 :yAxis="yAxis"
                                 style="height: 260px"></Echarts>
            </div>
        </div>
        <!-- åº•部横向两栏 -->
        <div class="dashboard-row">
<!--            <div class="main-panel">-->
<!--                <div class="section-title">质量统计</div>-->
<!--                <div class="quality-cards">-->
<!--                    <div class="quality-card one">原材料已检测数 <span>{{qualityStatisticsObject.supplierNum}}ä»¶</span></div>-->
<!--                    <div class="quality-card two">过程检验数量 <span>{{qualityStatisticsObject.processNum}}ä»¶</span></div>-->
<!--                    <div class="quality-card three">出厂已检数量 <span>{{qualityStatisticsObject.factoryNum}}ä»¶</span></div>-->
<!--                </div>-->
<!--                <Echarts ref="chart"-->
<!--                                 :chartStyle="chartStyle"-->
<!--                                 :grid="grid"-->
<!--                                 :legend="barLegend"-->
<!--                                 :series="barSeries1"-->
<!--                                 :tooltip="tooltip"-->
<!--                                 :xAxis="xAxis1"-->
<!--                                 :yAxis="yAxis1"-->
<!--                                 style="height: 260px"></Echarts>-->
<!--            </div>-->
            <div class="main-panel">
                <div class="section-title">回款与开票分析</div>
                <Echarts ref="chart" :chartStyle="chartStyle" :grid="grid" :legend="lineLegend" :series="lineSeries"
                                 :tooltip="tooltipLine" :xAxis="xAxis2" :yAxis="yAxis2" style="height: 270px;"></Echarts>
            </div>
        </div>
    </div>
  <div class="dashboard-container">
    <!-- ç»Ÿè®¡å¡ç‰‡ -->
    <el-row :gutter="20">
      <el-col :span="6">
        <el-card class="statistics-card" shadow="hover">
          <div class="card-content">
            <div class="card-title">设备在线率</div>
            <div class="card-value">{{ onlineRate }}%</div>
            <div class="card-desc">
              å½“前在线设备数:{{ onlineCount }} / {{ totalDevices }}
            </div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="statistics-card" shadow="hover">
          <div class="card-content">
            <div class="card-title">故障预警数</div>
            <div class="card-value">{{ warningCount }}</div>
            <div class="card-desc">
              é«˜é£Žé™©ï¼š{{ highRiskCount }} | ä¸­é£Žé™©ï¼š{{ mediumRiskCount }} |
              ä½Žé£Žé™©ï¼š{{ lowRiskCount }}
            </div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="statistics-card" shadow="hover">
          <div class="card-content">
            <div class="card-title">待处理维修单</div>
            <div class="card-value">{{ pendingOrders }}</div>
            <div class="card-desc">
              å¤„理中:{{ processingOrders }} | å·²å®Œæˆï¼š{{ completedOrders }}
            </div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="statistics-card" shadow="hover">
          <div class="card-content">
            <div class="card-title">重点设备运行状态</div>
            <div class="card-value">{{ normalDevices }} æ­£å¸¸</div>
            <div class="card-desc">
              å¼‚常:{{ abnormalDevices }} | æ•…障:{{ faultDevices }}
            </div>
          </div>
        </el-card>
      </el-col>
    </el-row>
    <!-- å›¾è¡¨åŒºåŸŸ -->
    <el-row :gutter="20" style="margin-top: 20px">
      <!-- è®¾å¤‡å¥åº·åº¦è¶‹åŠ¿å›¾ -->
      <el-col :span="12">
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>设备健康度趋势图</span>
            </div>
          </template>
          <div ref="healthChartRef" class="chart-container"></div>
        </el-card>
      </el-col>
      <!-- è¿‘7日故障类型统计 -->
      <el-col :span="12">
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>近7日故障类型统计</span>
            </div>
          </template>
          <div ref="faultChartRef" class="chart-container"></div>
        </el-card>
      </el-col>
    </el-row>
    <!-- é‡ç‚¹è®¾å¤‡è¿è¡ŒçŠ¶æ€å¡ç‰‡ -->
    <el-card shadow="hover" style="margin-top: 20px">
      <template #header>
        <div class="card-header">
          <span>重点设备运行状态</span>
        </div>
      </template>
      <el-table :data="keyDevices" stripe style="width: 100%">
        <el-table-column
          prop="name"
          label="设备名称"
          width="180"
        ></el-table-column>
        <el-table-column
          prop="model"
          label="型号"
          width="120"
        ></el-table-column>
        <el-table-column prop="ip" label="IP地址" width="150"></el-table-column>
        <el-table-column prop="status" label="状态" width="100">
          <template #default="scope">
            <el-tag
              :type="
                scope.row.status === 'online'
                  ? 'success'
                  : scope.row.status === 'warning'
                  ? 'warning'
                  : 'danger'
              "
            >
              {{
                scope.row.status === "online"
                  ? "在线"
                  : scope.row.status === "warning"
                  ? "预警"
                  : "故障"
              }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column
          prop="temperature"
          label="温度(℃)"
          width="100"
        ></el-table-column>
        <el-table-column
          prop="pressure"
          label="压力(MPa)"
          width="100"
        ></el-table-column>
        <el-table-column
          prop="speed"
          label="转速(rpm)"
          width="100"
        ></el-table-column>
        <el-table-column prop="health" label="健康度" width="120">
          <template #default="scope">
            <el-progress
              :percentage="scope.row.health"
              :stroke-width="10"
            ></el-progress>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
  </div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import Echarts from "@/components/Echarts/echarts.vue";
import * as echarts from 'echarts';
import useUserStore from "@/store/modules/user.js";
import {
    analysisCustomerContractAmounts, getAmountHalfYear,
    getBusiness,
    homeTodos,
    qualityStatistics,
    statisticsReceivablePayable
} from "@/api/viewIndex.js";
import { ref, onMounted, onUnmounted } from "vue";
import * as echarts from "echarts";
const userStore = useUserStore()
// ç»Ÿè®¡æ•°æ®
const onlineRate = ref(85);
const onlineCount = ref(170);
const totalDevices = ref(200);
const warningCount = ref(23);
const highRiskCount = ref(5);
const mediumRiskCount = ref(12);
const lowRiskCount = ref(6);
const pendingOrders = ref(15);
const processingOrders = ref(8);
const completedOrders = ref(45);
const normalDevices = ref(162);
const abnormalDevices = ref(18);
const faultDevices = ref(10);
const businessInfo = ref({
    inventoryNum: 0,
    monthPurchaseHaveMoney: 0,
    monthPurchaseMoney: 0,
    monthSaleHaveMoney: 0,
    monthSaleMoney: 0,
    todayInventoryNum: 0,
})
const qualityStatisticsObject = ref({
    supplierNum: 0,
    processNum: 0,
    factoryNum: 0,
})
const sum = ref(0)
const yny = ref(0)
const chain = ref(0)
const pieLegend = reactive({
    show: false,
})
const barSeries = ref([
    {
        type: 'bar',
        data: [],
        label: {
            show: true,
        }
    },
])
const barSeries1 = ref([
    {
        name: '原材料不合格数',
        type: 'bar',
        barGap: 0,
        emphasis: {
            focus: 'series'
        },
        data: []
    },
    {
        name: '过程不合格数',
        type: 'bar',
        emphasis: {
            focus: 'series'
        },
        data: []
    },
    {
        name: '出厂不合格数',
        type: 'bar',
        emphasis: {
            focus: 'series'
        },
        data: []
    },
])
const chartStyle = {
    width: '100%',
    height: '100%' // è®¾ç½®å›¾è¡¨å®¹å™¨çš„高度
}
const chartStylePie = {
    width: '140%',
    height: '140%' // è®¾ç½®å›¾è¡¨å®¹å™¨çš„高度
}
const grid = {
    left: '3%',
        right: '4%',
        bottom: '3%',
        containLabel: true
}
const barLegend = {
    show: true,
    data: ['原材料不合格数', '过程不合格数', '出厂不合格数']
}
const barLegend1 = {
    show: true,
    data: ['预付账款', '应付账款', '预收账款', '应收账款']
}
const lineLegend = {
    show: true,
    data: ['开票', '回款']
}
const tooltip = {
    trigger: 'axis',
    axisPointer: {
        type: 'shadow'
    }
}
const xAxis = [{
    type: 'value',
}]
const xAxis1 = ref([{
    type: 'category',
    axisTick: { show: false },
    data: []
}])
const yAxis = [{
    type: 'category',
    data: [ '应付账款', '应收账款',]
}]
const yAxis1 = [{
    type: 'value'
}]
const pieTooltip = reactive({
    trigger: 'item',
    formatter: function (params) {
        // åŠ¨æ€ç”Ÿæˆæç¤ºä¿¡æ¯ï¼ŒåŸºäºŽæ•°æ®é¡¹çš„ name å±žæ€§
        const description = params.name === '本月回款金额' ? '本月回款金额' : '应收款金额';
        return `${description} ${formatNumber(params.value)}元 ${params.percent}%`;
    },
    position: 'right'
})
const materialPieSeries = ref([
    {
        type: 'pie',
        radius: ['66%', '90%'],
        avoidLabelOverlap: false,
        itemStyle: {
            borderColor: '#fff',
            borderWidth: 2
        },
        label: {
            show: false
        },
        data: []
    }
])
const lineSeries = ref([
    {
        type: 'line',
        data: [],
        label: {
            show: true
        },
    showSymbol: true, // æ˜¾ç¤ºåœ†ç‚¹
    },
])
const tooltipLine = {
    trigger: 'axis',
}
const yAxis2 = ref([
    {
        type: 'value',
    }
])
const xAxis2 = ref([
    {
        type: 'category',
        data: [],
        axisLabel: {
            interval: 0,
            formatter: function(value) {
                return value.replace(/~/g, '\n');
            },
        }
    }
])
// å¾…办事项
const todoList = ref([])
const radio1 = ref(1)
// é‡ç‚¹è®¾å¤‡åˆ—表
const keyDevices = ref([
  {
    name: "空压机A-001",
    model: "KA-200",
    ip: "192.168.1.101",
    status: "online",
    temperature: 42,
    pressure: 0.8,
    speed: 1450,
    health: 92,
  },
  {
    name: "冷却塔B-002",
    model: "CT-300",
    ip: "192.168.1.102",
    status: "warning",
    temperature: 58,
    pressure: 0.6,
    speed: 980,
    health: 75,
  },
  {
    name: "æ°´æ³µC-003",
    model: "WP-150",
    ip: "192.168.1.103",
    status: "online",
    temperature: 38,
    pressure: 1.2,
    speed: 1200,
    health: 88,
  },
  {
    name: "发电机D-004",
    model: "GE-500",
    ip: "192.168.1.104",
    status: "danger",
    temperature: 75,
    pressure: 0.5,
    speed: 1500,
    health: 60,
  },
  {
    name: "变压器E-005",
    model: "TR-1000",
    ip: "192.168.1.105",
    status: "online",
    temperature: 45,
    pressure: 0,
    speed: 0,
    health: 95,
  },
]);
// å›¾è¡¨å¼•用
const barChart = ref(null)
const lineChart = ref(null)
const barColors2 = ['#5181DB', '#D369E0', '#F2CA6D', '#60CCA8']
const healthChartRef = ref(null);
const faultChartRef = ref(null);
let healthChart = null;
let faultChart = null;
// éšæœºé¢œè‰²ç”Ÿæˆå‡½æ•°
const getRandomColor = () => {
  return '#' + Math.floor(Math.random() * 0xffffff).toString(16).padStart(6, '0');
}
// å¥åº·åº¦è¶‹åŠ¿æ•°æ®
const healthTrendData = {
  dates: ["12-10", "12-11", "12-12", "12-13", "12-14", "12-15", "12-16"],
  values: [88, 90, 85, 87, 92, 91, 93],
};
// æ•…障类型统计数据
const faultTypeData = {
  types: ["温度异常", "压力超标", "转速异常", "振动过大", "其他"],
  values: [15, 8, 12, 6, 3],
};
// åˆå§‹åŒ–健康度趋势图
const initHealthChart = () => {
  if (healthChartRef.value) {
    healthChart = echarts.init(healthChartRef.value);
    const option = {
      tooltip: {
        trigger: "axis",
        axisPointer: {
          type: "cross",
          label: {
            backgroundColor: "#6a7985",
          },
        },
      },
      grid: {
        left: "3%",
        right: "4%",
        bottom: "3%",
        containLabel: true,
      },
      xAxis: {
        type: "category",
        boundaryGap: false,
        data: healthTrendData.dates,
      },
      yAxis: {
        type: "value",
        min: 70,
        max: 100,
        name: "健康度(%)",
      },
      series: [
        {
          name: "健康度",
          type: "line",
          stack: "总量",
          areaStyle: {},
          emphasis: {
            focus: "series",
          },
          data: healthTrendData.values,
          itemStyle: {
            color: "#67c23a",
          },
          lineStyle: {
            width: 3,
          },
        },
      ],
    };
    healthChart.setOption(option);
  }
};
// åˆå§‹åŒ–故障类型统计饼图
const initFaultChart = () => {
  if (faultChartRef.value) {
    faultChart = echarts.init(faultChartRef.value);
    const option = {
      tooltip: {
        trigger: "item",
      },
      legend: {
        orient: "vertical",
        left: "left",
      },
      series: [
        {
          name: "故障类型",
          type: "pie",
          radius: "50%",
          data: faultTypeData.types.map((type, index) => ({
            name: type,
            value: faultTypeData.values[index],
          })),
          emphasis: {
            itemStyle: {
              shadowBlur: 10,
              shadowOffsetX: 0,
              shadowColor: "rgba(0, 0, 0, 0.5)",
            },
          },
        },
      ],
    };
    faultChart.setOption(option);
  }
};
// ç›‘听窗口大小变化,调整图表大小
const handleResize = () => {
  healthChart?.resize();
  faultChart?.resize();
};
onMounted(() => {
    getBusinessData()
    analysisCustomer()
    todoInfoS()
    statisticsReceivable()
    qualityStatisticsInfo()
    getAmountHalfYearNum()
})
// æ•°æ®ç»Ÿè®¡
const getBusinessData = () => {
    getBusiness().then((res) => {
        businessInfo.value = {...res.data}
    })
}
// åˆåŒé‡‘额
const analysisCustomer = () => {
    analysisCustomerContractAmounts().then((res) => {
        sum.value = res.data.sum
        yny.value = res.data.yny
        chain.value = res.data.chain
    // ä¸ºæ¯ä¸ªæ•°æ®é¡¹åˆ†é…éšæœºé¢œè‰²
    materialPieSeries.value[0].data = res.data.item.map(item => ({
      ...item,
      itemStyle: { color: getRandomColor() }
    }))
    })
}
// å¾…办事项
const todoInfoS = () => {
    homeTodos().then((res) => {
        todoList.value = res.data
    })
}
// åº”付应收统计
const statisticsReceivable = (type) => {
    console.log(type)
    statisticsReceivablePayable({type: radio1.value}).then((res) => {
        barSeries.value[0].data = [
            // { value: res.data.prepayMoney, itemStyle: { color: barColors2[0] } },
            { value: res.data.payableMoney, itemStyle: { color: barColors2[0] } },
            // { value: res.data.advanceMoney, itemStyle: { color: barColors2[2] } },
            { value: res.data.receivableMoney, itemStyle: { color: barColors2[1] } }
        ]
    })
}
// è´¨æ£€ç»Ÿè®¡
const qualityStatisticsInfo = () => {
    qualityStatistics().then((res) => {
        res.data.item.forEach(item => {
            xAxis1.value[0].data.push(item.date)
            barSeries1.value[0].data.push(item.supplierNum)
            barSeries1.value[1].data.push(item.processNum)
            barSeries1.value[2].data.push(item.factoryNum)
        })
        qualityStatisticsObject.value.supplierNum = res.data.supplierNum
        qualityStatisticsObject.value.processNum = res.data.processNum
        qualityStatisticsObject.value.factoryNum = res.data.factoryNum
    })
}
const getAmountHalfYearNum = async () => {
    const res = await getAmountHalfYear()
    console.log(res)
    const monthName = []
    const receiptAmount = []
    const invoiceAmount = []
    res.data.forEach(item => {
        monthName.push(item.month)
        receiptAmount.push(item.receiptAmount)
        invoiceAmount.push(item.invoiceAmount)
    })
    // æ­£ç¡®å“åº”式赋值:创建新的 xAxis å’Œ series å¯¹è±¡
    xAxis2.value[0].data = monthName
    xAxis2.value[0].data = monthName.map(item => item.replace(/~/g, '\n~'));
    lineSeries.value = [
        {
            name: '开票',
            type: 'line',
            data: receiptAmount,
            stack: 'Total',
            areaStyle: {
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                    {
                        offset: 0,
                        color: 'rgba(131, 207, 255, 1)'
                    },
                    {
                        offset: 1,
                        color: 'rgba(186, 228, 255, 1)'
                    }
                ])
            },
            itemStyle: {
                color: '#2D99FF',
                borderColor: '#2D99FF'
            },
            emphasis: {
                focus: 'series'
            },
            lineStyle: {
                width: 0
            },
            showSymbol: true,
        },
        {
            name: '回款',
            type: 'line',
            data: invoiceAmount,
            stack: 'Total',
            lineStyle: {
                width: 0
            },
            itemStyle: {
                color: '#83CFFF',
                borderColor: '#83CFFF'
            },
            showSymbol: true,
            areaStyle: {
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                    {
                        offset: 0,
                        color: 'rgba(54, 153, 255, 1)'
                    },
                    {
                        offset: 1,
                        color: 'rgba(89, 169, 254, 1)'
                    }
                ])
            },
            emphasis: {
                focus: 'series'
            },
        }
    ]
}
  initHealthChart();
  initFaultChart();
  window.addEventListener("resize", handleResize);
});
onUnmounted(() => {
  window.removeEventListener("resize", handleResize);
  healthChart?.dispose();
  faultChart?.dispose();
});
</script>
<style scoped>
.dashboard {
    background: #f5f7fa;
    min-height: 100vh;
    padding: 20px;
    box-sizing: border-box;
}
.dashboard-top {
    display: flex;
    gap: 20px;
    margin-bottom: 20px;
}
.company-info {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 20px;
    min-width: 0;
    background-color: #EFF2FB; /* ä½¿ç”¨æŒ‡å®šçš„背景颜色 */
    background-image: url("../assets/images/denglu.png");
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    border-radius: 12px;
    height: 138px;
}
.avatar {
    width: 60px;
    height: 60px;
    border-radius: 50%;
    object-fit: contain;
    background: #fff;
    border: 1px solid #eee;
}
.company-card {
    display: flex;
    flex-direction: column;
    gap: 10px;
    position: relative;
    padding-right: 15px;
.dashboard-container {
  padding: 20px;
  background-color: #f5f7fa;
  min-height: 100vh;
}
.company-card::after {
    content: '';
    position: absolute;
    right: 0;
    top: 0;
    bottom: 0;
    width: 1px;
    background-color: #C9C5C5;
    border-radius: 2px;
}
.company-name {
    font-weight: 400;
    font-size: 16px;
    color: #161A9A;
}
.company-meta {
    font-weight: 400;
    font-size: 12px;
    color: #818185;
}
.data-cards {
    display: flex;
    gap: 16px;
    justify-content: flex-start;
    background: #ffffff;
    border-radius: 12px;
    padding: 20px;
}
.data-title {
    font-weight: 700;
    font-size: 26px;
    color: #FFFFFF;
}
.data-num {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 20px;
}
.data-card {
    background: #fff;
    border-radius: 12px;
    padding: 14px 10px 10px 10px;
    min-width: 160px;
    box-shadow: 0 2px 8px #eee;
    display: flex;
    flex-direction: column;
    width: 32%;
    height: 140px;
}
.data-card.sales {
    background-image: url("../assets/images/xioashoushuju.png");
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
}
.data-card.purchase {
    background-image: url("../assets/images/caigou.png");
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
}
.data-card.inventory {
    background-image: url("../assets/images/kucun.png");
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
}
.data-desc {
    font-weight: 500;
    font-size: 13px;
    color: #FFFFFF;
}
.data-value {
    font-size: 18px;
    font-weight: 500;
    margin: 10px 0;
    color: #FFFFFF;
}
.top-left {
    display: flex;
    flex-direction: column;
    gap: 20px;
    width: 50%;
}
.todo-panel {
    background: #fff;
    border-radius: 12px;
    padding: 20px;
    width: 50%;
}
.todo-list {
    list-style: none;
    padding: 0;
    margin: 0;
    font-size: 15px;
    overflow-y: auto;
    height: 260px;
}
.todo-list li {
    border-radius: 8px;
    margin-bottom: 12px;
    padding: 8px 20px;
    height: 74px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    background: rgba(225,227,250,0.62);
}
.todo-title {
    font-weight: 400;
    font-size: 12px;
    color: #000000;
    position: relative;
}
.todo-title::before {
    content: ''; /* å¿…需,表示这里有一个内容 */
    position: absolute;
    left: -10px; /* å®šä½åˆ°å·¦ä¾§ */
    top: 50%; /* åž‚直居中 */
    transform: translateY(-50%); /* å¾®è°ƒåž‚直居中 */
    width: 6px; /* åœ†çš„直径 */
    height: 6px; /* åœ†çš„直径 */
    background: #498CEB;
    border-radius: 50%; /* è®©å…¶å˜æˆåœ†å½¢ */
}
.todo-division {
    font-weight: 400;
    font-size: 12px;
    color: #000000;
}
.todo-time {
    font-weight: 400;
    font-size: 12px;
    color: #000000;
}
.todo-meta {
    color: #888;
    font-size: 13px;
}
.dashboard-row {
    display: flex;
    gap: 20px;
    margin-bottom: 20px;
}
.main-panel {
    background: #fff;
    border-radius: 12px;
    padding: 20px;
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}
.section-title {
    position: relative;
    font-size: 18px;
    color: #333;
    padding-left: 10px;
    margin-bottom: 10px;
    font-weight: 700;
.statistics-card {
  height: 180px;
}
.section-title::before {
    position: absolute;
    left: 0;
    top: 4px;
    content: '';
    width: 4px;
    height: 18px;
    background-color: #002FA7;
    border-radius: 2px;
.card-content {
  display: flex;
  flex-direction: column;
  height: 100%;
  justify-content: center;
  align-items: center;
}
.contract-info {
    display: flex;
    align-items: center;
    gap: 20px;
    height: 90px;
    background: rgba(245,245,245,0.59);
    width: 100%;
    border-radius: 10px;
    padding: 10px 30px;
.card-title {
  font-size: 16px;
  color: #606266;
  margin-bottom: 10px;
}
.contract-summary {
    display: flex;
    align-items: center;
    gap: 30px;
.card-value {
  font-size: 32px;
  font-weight: bold;
  color: #303133;
  margin-bottom: 8px;
}
.contract-card {
    display: flex;
    flex-direction: column;
    gap: 10px;
.card-desc {
  font-size: 14px;
  color: #909399;
}
.contract-name {
    font-weight: 400;
    font-size: 14px;
    color: #050505;
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.contract-meta {
    display: flex;
    align-items: center;
    width: 100%;
    gap: 80px;
.chart-container {
  width: 100%;
  height: 350px;
}
.main-amount {
    font-size: 24px;
    color: rgba(51,50,50,0.85);
}
.up { color: #e57373; }
.contract-list {
    margin-top: 16px;
    font-size: 14px;
    color: #666;
    list-style: none;
    padding: 0;
    height: 190px;
    overflow-y: auto;
    width: 460px;
}
.line {
    position: relative;
    width: 230px;
}
.line::after {
    content: '';
    position: absolute;
    right: 2px;
    top: 0;
    bottom: 0;
    width: 1px;
    background-color: #C9C5C5;
    border-radius: 2px;
}
.contract-list li {
    margin-top: 10px;
}
.quality-cards {
    display: flex;
    gap: 12px;
    margin-bottom: 12px;
}
.quality-card {
    border-radius: 8px;
    padding: 15px 10px 10px 50px;
    font-weight: 400;
    font-size: 12px;
    color: rgba(0,0,0,0.67);
    width: 236px;
    height: 49px;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
}
.quality-card.one {
    background-image: url("../assets/images/yuancailiao.png");
}
.quality-card.two {
    background-image: url("../assets/images/guocheng.png");
}
.quality-card.three {
    background-image: url("../assets/images/chuchang.png");
}
.quality-card span {
    color: #4fc3f7;
    font-weight: bold;
    margin-left: 6px;
}
.chart {
    width: 100%;
    height: 220px;
    margin-top: 10px;
}
</style>
</style>
src/views/inventoryManagement/dispatchLog/index.vue
ÎļþÒÑɾ³ý
src/views/inventoryManagement/issueManagement/index.vue
ÎļþÒÑɾ³ý
src/views/inventoryManagement/receiptManagement/index.vue
ÎļþÒÑɾ³ý
src/views/inventoryManagement/stockManagement/index.vue
ÎļþÒÑɾ³ý
src/views/inventoryManagement/stockWarning/index.vue
ÎļþÒÑɾ³ý
src/views/maintenance/MaintenanceManagement.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,526 @@
<template>
  <div class="maintenance-management-container">
    <!-- é¡¶éƒ¨æ“ä½œæ  -->
    <el-card shadow="hover" style="margin-bottom: 20px;">
      <div class="card-header">
        <span>维修管理</span>
        <div class="header-buttons">
          <el-button type="primary" @click="showCreateWorkOrderDialog">
            <el-icon-plus /> åˆ›å»ºå·¥å•
          </el-button>
        </div>
      </div>
    </el-card>
    <el-row :gutter="20">
      <!-- å·¦ä¾§ï¼šå·¥å•列表 -->
      <el-col :span="16">
        <el-card shadow="hover">
          <!-- å·¥å•状态标签页 -->
          <el-tabs v-model="activeTab" @tab-change="handleTabChange">
            <el-tab-pane label="待处理" name="pending"></el-tab-pane>
            <el-tab-pane label="处理中" name="processing"></el-tab-pane>
            <el-tab-pane label="已完成" name="completed"></el-tab-pane>
          </el-tabs>
          <!-- å·¥å•列表 -->
          <el-table :data="filteredWorkOrders" stripe style="width: 100%" @row-click="handleWorkOrderClick">
            <el-table-column prop="orderNo" label="工单编号" width="180"></el-table-column>
            <el-table-column prop="deviceName" label="设备名称" width="150"></el-table-column>
            <el-table-column prop="faultType" label="故障类型" width="120"></el-table-column>
            <el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
            <el-table-column prop="assignee" label="负责人" width="120"></el-table-column>
            <el-table-column prop="priority" label="优先级" width="100">
              <template #default="scope">
                <el-tag :type="scope.row.priority === 'high' ? 'danger' : scope.row.priority === 'medium' ? 'warning' : 'info'">
                  {{ scope.row.priority === 'high' ? '高' : scope.row.priority === 'medium' ? '中' : '低' }}
                </el-tag>
              </template>
            </el-table-column>
            <el-table-column label="操作" width="150">
              <template #default="scope">
                <el-button size="small" @click="showEditWorkOrderDialog(scope.row)">编辑</el-button>
                <el-button type="danger" size="small" @click="handleDeleteWorkOrder(scope.row.id)">删除</el-button>
              </template>
            </el-table-column>
          </el-table>
          <!-- åˆ†é¡µ -->
          <div class="pagination-container">
            <el-pagination
              background
              layout="total, sizes, prev, pager, next, jumper"
              :total="filteredWorkOrders.length"
              :current-page="currentPage"
              :page-sizes="[10, 20, 50, 100]"
              :page-size="pageSize"
              @size-change="handleSizeChange"
              @current-change="handleCurrentChange"
            ></el-pagination>
          </div>
        </el-card>
      </el-col>
      <!-- å³ä¾§ï¼šç»´ä¿®ç»Ÿè®¡å’Œå¤‡ä»¶æŽ¨è -->
      <el-col :span="8">
        <!-- ç»´ä¿®åŽ†å²ç»Ÿè®¡ -->
        <el-card shadow="hover" style="margin-bottom: 20px;">
          <template #header>
            <div class="card-header">
              <span>维修历史统计</span>
            </div>
          </template>
          <div class="statistics-content">
            <div class="stat-item">
              <div class="stat-label">本月完成工单</div>
              <div class="stat-value">{{ monthlyCompleted }}</div>
            </div>
            <div class="stat-item">
              <div class="stat-label">平均维修时长</div>
              <div class="stat-value">{{ averageRepairTime }}小时</div>
            </div>
            <div class="stat-item">
              <div class="stat-label">设备故障率</div>
              <div class="stat-value">{{ failureRate }}%</div>
            </div>
            <div class="stat-item">
              <div class="stat-label">常用维修设备</div>
              <div class="stat-value">{{ commonDevice }}</div>
            </div>
          </div>
        </el-card>
        <!-- å¸¸ç”¨å¤‡ä»¶å…³è”推荐 -->
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <span>常用备件推荐</span>
            </div>
          </template>
          <div class="spare-parts-content">
            <el-table :data="spareParts" stripe style="width: 100%" size="small">
              <el-table-column prop="name" label="备件名称" width="120"></el-table-column>
              <el-table-column prop="model" label="型号" width="100"></el-table-column>
              <el-table-column prop="stock" label="库存" width="80">
                <template #default="scope">
                  <el-tag :type="scope.row.stock < 10 ? 'danger' : 'success'">
                    {{ scope.row.stock }}
                  </el-tag>
                </template>
              </el-table-column>
              <el-table-column prop="usageCount" label="使用次数" width="80"></el-table-column>
            </el-table>
          </div>
        </el-card>
      </el-col>
    </el-row>
    <!-- åˆ›å»ºå·¥å•对话框 -->
    <el-dialog v-model="createWorkOrderDialogVisible" title="创建维修工单" width="600px">
      <el-form :model="workOrderForm" :rules="workOrderRules" ref="workOrderFormRef" label-width="100px">
        <el-form-item label="设备" prop="deviceId">
          <el-select v-model="workOrderForm.deviceId" placeholder="请选择设备">
            <el-option
              v-for="device in devices"
              :key="device.id"
              :label="device.name"
              :value="device.id"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="故障类型" prop="faultType">
          <el-input v-model="workOrderForm.faultType" placeholder="请输入故障类型"></el-input>
        </el-form-item>
        <el-form-item label="故障描述" prop="faultDescription">
          <el-input v-model="workOrderForm.faultDescription" type="textarea" placeholder="请详细描述故障情况" :rows="3"></el-input>
        </el-form-item>
        <el-form-item label="优先级" prop="priority">
          <el-select v-model="workOrderForm.priority" placeholder="请选择优先级">
            <el-option label="高" value="high"></el-option>
            <el-option label="中" value="medium"></el-option>
            <el-option label="低" value="low"></el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="createWorkOrderDialogVisible = false">取消</el-button>
          <el-button type="primary" @click="handleCreateWorkOrder">确定</el-button>
        </span>
      </template>
    </el-dialog>
    <!-- ç¼–辑工单对话框 -->
    <el-dialog v-model="editWorkOrderDialogVisible" title="编辑维修工单" width="600px">
      <el-form :model="workOrderForm" :rules="workOrderRules" ref="workOrderFormRef" label-width="100px">
        <el-form-item label="工单编号" disabled>
          <el-input v-model="workOrderForm.orderNo"></el-input>
        </el-form-item>
        <el-form-item label="设备" disabled>
          <el-input v-model="workOrderForm.deviceName"></el-input>
        </el-form-item>
        <el-form-item label="故障类型" disabled>
          <el-input v-model="workOrderForm.faultType"></el-input>
        </el-form-item>
        <el-form-item label="负责人" prop="assignee">
          <el-select v-model="workOrderForm.assignee" placeholder="请选择负责人">
            <el-option
              v-for="user in users"
              :key="user.id"
              :label="user.name"
              :value="user.name"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="维修状态" prop="status">
          <el-select v-model="workOrderForm.status" placeholder="请选择状态">
            <el-option label="待处理" value="pending"></el-option>
            <el-option label="处理中" value="processing"></el-option>
            <el-option label="已完成" value="completed"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="维修结果" prop="repairResult">
          <el-input v-model="workOrderForm.repairResult" type="textarea" placeholder="请填写维修结果" :rows="3"></el-input>
        </el-form-item>
        <el-form-item label="备件使用" prop="usedParts">
          <el-input v-model="workOrderForm.usedParts" type="textarea" placeholder="请填写使用的备件" :rows="2"></el-input>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="editWorkOrderDialogVisible = false">取消</el-button>
          <el-button type="primary" @click="handleEditWorkOrder">确定</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { ref, computed } from 'vue'
// è®¾å¤‡åˆ—表
const devices = ref([
  { id: 'D001', name: '空压机A-001' },
  { id: 'D002', name: '冷却塔B-002' },
  { id: 'D003', name: 'æ°´æ³µC-003' },
  { id: 'D004', name: '发电机D-004' },
  { id: 'D005', name: '变压器E-005' }
])
// ç”¨æˆ·åˆ—表(用于分配负责人)
const users = ref([
  { id: 'U001', name: '张三' },
  { id: 'U002', name: '李四' },
  { id: 'U003', name: '王五' },
  { id: 'U004', name: '赵六' }
])
// å·¥å•列表数据
const workOrders = ref([
  {
    id: 1,
    orderNo: 'WO20241216001',
    deviceId: 'D001',
    deviceName: '空压机A-001',
    faultType: '压力异常',
    faultDescription: '设备运行时压力超过设定阈值,伴有异常噪音',
    priority: 'high',
    assignee: '',
    status: 'pending',
    repairResult: '',
    usedParts: '',
    createTime: '2024-12-16 14:32:15',
    startTime: '',
    endTime: ''
  },
  {
    id: 2,
    orderNo: 'WO20241216002',
    deviceId: 'D002',
    deviceName: '冷却塔B-002',
    faultType: '温度过高',
    faultDescription: '冷却塔出水温度超过设定值,冷却效果不佳',
    priority: 'medium',
    assignee: '张三',
    status: 'processing',
    repairResult: '',
    usedParts: '',
    createTime: '2024-12-16 14:30:45',
    startTime: '2024-12-16 15:00:00',
    endTime: ''
  },
  {
    id: 3,
    orderNo: 'WO20241215001',
    deviceId: 'D003',
    deviceName: 'æ°´æ³µC-003',
    faultType: '振动过大',
    faultDescription: '水泵运行时振动值超过标准,可能影响设备寿命',
    priority: 'medium',
    assignee: '李四',
    status: 'completed',
    repairResult: '更换了水泵轴承,调整了联轴器,振动值恢复正常',
    usedParts: '轴承×2,联轴器×1',
    createTime: '2024-12-15 08:30:00',
    startTime: '2024-12-15 09:00:00',
    endTime: '2024-12-15 10:45:00'
  },
  {
    id: 4,
    orderNo: 'WO20241214001',
    deviceId: 'D004',
    deviceName: '发电机D-004',
    faultType: '电流异常',
    faultDescription: '发电机运行时电流波动较大,可能存在短路风险',
    priority: 'high',
    assignee: '王五',
    status: 'completed',
    repairResult: '检查并修复了发电机绕组短路问题,电流恢复正常',
    usedParts: '绝缘材料×1,导线×5ç±³',
    createTime: '2024-12-14 14:20:00',
    startTime: '2024-12-14 14:30:00',
    endTime: '2024-12-14 16:15:00'
  },
  {
    id: 5,
    orderNo: 'WO20241213001',
    deviceId: 'D005',
    deviceName: '变压器E-005',
    faultType: '电压波动',
    faultDescription: '变压器输出电压波动较大,影响下游设备运行',
    priority: 'low',
    assignee: '赵六',
    status: 'completed',
    repairResult: '调整了变压器分接开关,电压稳定在正常范围内',
    usedParts: '',
    createTime: '2024-12-13 09:15:00',
    startTime: '2024-12-13 10:00:00',
    endTime: '2024-12-13 11:30:00'
  }
])
// å½“前激活的标签页(工单状态)
const activeTab = ref('pending')
// åˆ†é¡µæ•°æ®
const currentPage = ref(1)
const pageSize = ref(10)
// å¯¹è¯æ¡†çŠ¶æ€
const createWorkOrderDialogVisible = ref(false)
const editWorkOrderDialogVisible = ref(false)
// å·¥å•表单数据
const workOrderForm = ref({
  id: '',
  orderNo: '',
  deviceId: '',
  deviceName: '',
  faultType: '',
  faultDescription: '',
  priority: 'medium',
  assignee: '',
  status: 'pending',
  repairResult: '',
  usedParts: '',
  createTime: '',
  startTime: '',
  endTime: ''
})
// è¡¨å•验证规则
const workOrderRules = ref({
  deviceId: [{ required: true, message: '请选择设备', trigger: 'change' }],
  faultType: [{ required: true, message: '请输入故障类型', trigger: 'blur' }],
  faultDescription: [{ required: true, message: '请详细描述故障情况', trigger: 'blur' }],
  priority: [{ required: true, message: '请选择优先级', trigger: 'change' }],
  assignee: [{ required: true, message: '请选择负责人', trigger: 'change' }],
  status: [{ required: true, message: '请选择状态', trigger: 'change' }]
})
// è¡¨å•引用
const workOrderFormRef = ref(null)
// ç­›é€‰åŽçš„工单列表
const filteredWorkOrders = computed(() => {
  return workOrders.value.filter(order => order.status === activeTab.value)
})
// ç»´ä¿®ç»Ÿè®¡æ•°æ®
const monthlyCompleted = ref(28)
const averageRepairTime = ref(2.5)
const failureRate = ref(3.2)
const commonDevice = ref('空压机A-001')
// å¸¸ç”¨å¤‡ä»¶æŽ¨è
const spareParts = ref([
  { id: 1, name: '轴承', model: '6308', stock: 15, usageCount: 23 },
  { id: 2, name: '密封件', model: 'MS-25', stock: 8, usageCount: 18 },
  { id: 3, name: '联轴器', model: 'CL-50', stock: 5, usageCount: 12 },
  { id: 4, name: '传感器', model: 'TS-100', stock: 3, usageCount: 15 },
  { id: 5, name: '润滑油', model: 'L-46', stock: 20, usageCount: 30 }
])
// æ˜¾ç¤ºåˆ›å»ºå·¥å•对话框
const showCreateWorkOrderDialog = () => {
  // é‡ç½®è¡¨å•
  workOrderForm.value = {
    id: '',
    orderNo: '',
    deviceId: '',
    deviceName: '',
    faultType: '',
    faultDescription: '',
    priority: 'medium',
    assignee: '',
    status: 'pending',
    repairResult: '',
    usedParts: '',
    createTime: '',
    startTime: '',
    endTime: ''
  }
  createWorkOrderDialogVisible.value = true
}
// æ˜¾ç¤ºç¼–辑工单对话框
const showEditWorkOrderDialog = (order) => {
  workOrderForm.value = { ...order }
  editWorkOrderDialogVisible.value = true
}
// å¤„理工单点击
const handleWorkOrderClick = (row) => {
  // å¯ä»¥åœ¨è¿™é‡Œæ·»åŠ æŸ¥çœ‹å·¥å•è¯¦æƒ…çš„é€»è¾‘
}
// å¤„理标签页切换
const handleTabChange = (tab) => {
  activeTab.value = tab
  currentPage.value = 1 // åˆ‡æ¢æ ‡ç­¾é¡µæ—¶é‡ç½®é¡µç 
}
// å¤„理创建工单
const handleCreateWorkOrder = () => {
  // æ¨¡æ‹Ÿåˆ›å»ºå·¥å•
  const newOrder = {
    ...workOrderForm.value,
    id: workOrders.value.length + 1,
    orderNo: `WO${new Date().getFullYear()}${String(new Date().getMonth() + 1).padStart(2, '0')}${String(new Date().getDate()).padStart(2, '0')}${String(workOrders.value.length + 1).padStart(3, '0')}`,
    deviceName: devices.value.find(d => d.id === workOrderForm.value.deviceId)?.name || '',
    createTime: new Date().toLocaleString(),
    status: 'pending'
  }
  workOrders.value.unshift(newOrder)
  createWorkOrderDialogVisible.value = false
  ElMessage.success('工单创建成功')
}
// å¤„理编辑工单
const handleEditWorkOrder = () => {
  // æ¨¡æ‹Ÿç¼–辑工单
  const index = workOrders.value.findIndex(order => order.id === workOrderForm.value.id)
  if (index !== -1) {
    // å¦‚果状态从待处理变为处理中,设置开始时间
    if (workOrders.value[index].status === 'pending' && workOrderForm.value.status === 'processing') {
      workOrderForm.value.startTime = new Date().toLocaleString()
    }
    // å¦‚果状态从处理中变为已完成,设置结束时间
    if (workOrders.value[index].status === 'processing' && workOrderForm.value.status === 'completed') {
      workOrderForm.value.endTime = new Date().toLocaleString()
    }
    workOrders.value[index] = { ...workOrderForm.value }
    editWorkOrderDialogVisible.value = false
    ElMessage.success('工单编辑成功')
  }
}
// å¤„理删除工单
const handleDeleteWorkOrder = (id) => {
  ElMessageBox.confirm('确定要删除该工单吗?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    // æ¨¡æ‹Ÿåˆ é™¤å·¥å•
    const index = workOrders.value.findIndex(order => order.id === id)
    if (index !== -1) {
      workOrders.value.splice(index, 1)
      ElMessage.success('工单删除成功')
    }
  }).catch(() => {
    // å–消删除
  })
}
// å¤„理分页大小变化
const handleSizeChange = (size) => {
  pageSize.value = size
  currentPage.value = 1
}
// å¤„理当前页变化
const handleCurrentChange = (current) => {
  currentPage.value = current
}
</script>
<style scoped>
.maintenance-management-container {
  padding: 20px;
  background-color: #f5f7fa;
  min-height: 100vh;
}
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.header-buttons {
  display: flex;
  gap: 10px;
}
.pagination-container {
  display: flex;
  justify-content: flex-end;
  margin-top: 20px;
}
.statistics-content {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  padding: 10px 0;
}
.stat-item {
  text-align: center;
  padding: 15px;
  background-color: #fafafa;
  border-radius: 4px;
}
.stat-label {
  font-size: 14px;
  color: #606266;
  margin-bottom: 10px;
}
.stat-value {
  font-size: 24px;
  font-weight: bold;
  color: #303133;
}
.spare-parts-content {
  padding: 10px 0;
}
:deep(.el-icon-plus) {
  margin-right: 5px;
}
</style>
src/views/monitoring/RealTimeMonitoring.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,515 @@
<template>
  <div class="real-time-monitoring-container">
    <!-- è®¾å¤‡é€‰æ‹© -->
    <el-card shadow="hover" style="margin-bottom: 20px;">
      <el-form :inline="true" :model="deviceSelectForm" class="device-select-form">
        <el-form-item label="设备">
          <el-select v-model="deviceSelectForm.deviceId" placeholder="请选择设备" @change="handleDeviceChange">
            <el-option
              v-for="device in devices"
              :key="device.id"
              :label="device.name"
              :value="device.id"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="时间范围">
          <el-date-picker
            v-model="timeRange"
            type="daterange"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            :default-time="['00:00:00', '23:59:59']"
          ></el-date-picker>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleHistoryQuery">查询历史数据</el-button>
        </el-form-item>
      </el-form>
    </el-card>
    <!-- å®žæ—¶å‚数卡片 -->
    <el-row :gutter="20" style="margin-bottom: 20px;">
      <el-col :span="8" v-for="param in realTimeParams" :key="param.name">
        <el-card class="param-card" :shadow="param.isAlarm ? 'always' : 'hover'" :class="{ 'alarm-card': param.isAlarm }">
          <div class="param-content">
            <div class="param-title">
              <span>{{ param.name }}</span>
              <el-tag v-if="param.isAlarm" type="danger">告警</el-tag>
            </div>
            <div class="param-value">{{ param.value }} {{ param.unit }}</div>
            <div class="param-range">
              æ­£å¸¸èŒƒå›´ï¼š{{ param.min }} - {{ param.max }} {{ param.unit }}
            </div>
          </div>
        </el-card>
      </el-col>
    </el-row>
    <!-- å‘Šè­¦æç¤º -->
    <el-card shadow="hover" v-if="alarmList.length > 0" style="margin-bottom: 20px;">
      <template #header>
        <div class="card-header">
          <span>告警提示</span>
        </div>
      </template>
      <el-scrollbar height="200px">
        <div class="alarm-item" v-for="alarm in alarmList" :key="alarm.id">
          <el-alert
            :title="alarm.message"
            :type="alarm.level === 'high' ? 'error' : alarm.level === 'medium' ? 'warning' : 'info'"
            show-icon
            closable
            @close="handleAlarmClose(alarm.id)"
          >
            <template #default>
              <div class="alarm-detail">
                <span>设备:{{ alarm.deviceName }}</span>
                <span>时间:{{ alarm.time }}</span>
              </div>
            </template>
          </el-alert>
        </div>
      </el-scrollbar>
    </el-card>
    <!-- åŽ†å²æ•°æ®è¶‹åŠ¿å›¾ -->
    <el-card shadow="hover">
      <template #header>
        <div class="card-header">
          <span>历史数据趋势</span>
          <div class="param-tabs">
            <el-radio-group v-model="activeParam" size="small" @change="handleParamChange">
              <el-radio-button v-for="param in historyParams" :key="param" :label="param">
                {{ param }}
              </el-radio-button>
            </el-radio-group>
          </div>
        </div>
      </template>
      <div ref="historyChartRef" class="chart-container"></div>
    </el-card>
    <!-- å•设备参数详情页 -->
    <el-dialog v-model="deviceDetailVisible" title="设备参数详情" width="800px">
      <div class="device-detail-content">
        <h3>{{ selectedDevice.name }} - å®žæ—¶å‚æ•°</h3>
        <el-row :gutter="20" style="margin-bottom: 20px;">
          <el-col :span="12" v-for="param in realTimeParams" :key="param.name">
            <div class="detail-param-item">
              <span class="param-label">{{ param.name }}:</span>
              <span class="param-value" :class="{ 'alarm-value': param.isAlarm }">
                {{ param.value }} {{ param.unit }}
              </span>
              <span class="param-range">
                ï¼ˆ{{ param.min }} - {{ param.max }} {{ param.unit }})
              </span>
            </div>
          </el-col>
        </el-row>
        <h3>参数阈值设置</h3>
        <el-form :model="thresholdForm" label-width="100px" style="margin-top: 20px;">
          <el-form-item v-for="param in realTimeParams" :key="param.name" :label="param.name">
            <el-input-number
              v-model="thresholdForm[param.name + 'Min']"
              :min="0"
              :max="1000"
              size="small"
              style="width: 120px; margin-right: 10px;"
              placeholder="最小值"
            ></el-input-number>
            <span style="margin: 0 10px;">-</span>
            <el-input-number
              v-model="thresholdForm[param.name + 'Max']"
              :min="0"
              :max="1000"
              size="small"
              style="width: 120px; margin-right: 10px;"
              placeholder="最大值"
            ></el-input-number>
            <span>{{ param.unit }}</span>
          </el-form-item>
        </el-form>
      </div>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="deviceDetailVisible = false">取消</el-button>
          <el-button type="primary" @click="saveThresholds">保存设置</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, computed } from 'vue'
import * as echarts from 'echarts'
// è®¾å¤‡åˆ—表
const devices = ref([
  { id: 'D001', name: '空压机A-001' },
  { id: 'D002', name: '冷却塔B-002' },
  { id: 'D003', name: 'æ°´æ³µC-003' },
  { id: 'D004', name: '发电机D-004' },
  { id: 'D005', name: '变压器E-005' }
])
// è®¾å¤‡é€‰æ‹©è¡¨å•
const deviceSelectForm = ref({
  deviceId: 'D001' // é»˜è®¤é€‰æ‹©ç¬¬ä¸€ä¸ªè®¾å¤‡
})
// æ—¶é—´èŒƒå›´
const timeRange = ref([])
// å½“前选中的设备
const selectedDevice = ref(devices.value[0])
// å®žæ—¶å‚数数据
const realTimeParams = ref([
  { name: '温度', value: 45, unit: '℃', min: 0, max: 60, isAlarm: false },
  { name: '压力', value: 0.85, unit: 'MPa', min: 0.5, max: 0.8, isAlarm: true },
  { name: '转速', value: 1450, unit: 'rpm', min: 1000, max: 1500, isAlarm: false },
  { name: '振动', value: 3.2, unit: 'mm/s', min: 0, max: 2.5, isAlarm: true },
  { name: '电流', value: 25.6, unit: 'A', min: 0, max: 30, isAlarm: false },
  { name: '电压', value: 380, unit: 'V', min: 360, max: 400, isAlarm: false }
])
// å‘Šè­¦åˆ—表
const alarmList = ref([
  { id: 1, deviceName: '空压机A-001', message: '压力超标', level: 'high', time: '2024-12-16 14:32:15' },
  { id: 2, deviceName: '空压机A-001', message: '振动过大', level: 'medium', time: '2024-12-16 14:30:45' },
  { id: 3, deviceName: '冷却塔B-002', message: '温度异常', level: 'warning', time: '2024-12-16 14:28:30' }
])
// åŽ†å²å‚æ•°é€‰é¡¹
const historyParams = ref(['温度', '压力', '转速', '振动', '电流', '电压'])
const activeParam = ref('温度')
// åŽ†å²æ•°æ®
const historyData = ref({
  dates: [],
  values: []
})
// å›¾è¡¨å¼•用
const historyChartRef = ref(null)
let historyChart = null
// è®¾å¤‡è¯¦æƒ…对话框
const deviceDetailVisible = ref(false)
// é˜ˆå€¼è®¾ç½®è¡¨å•
const thresholdForm = ref({})
// åˆå§‹åŒ–阈值表单
const initThresholdForm = () => {
  const form = {}
  realTimeParams.value.forEach(param => {
    form[param.name + 'Min'] = param.min
    form[param.name + 'Max'] = param.max
  })
  thresholdForm.value = form
}
// å¤„理设备变更
const handleDeviceChange = (deviceId) => {
  selectedDevice.value = devices.value.find(device => device.id === deviceId) || devices.value[0]
  // æ¨¡æ‹Ÿåˆ‡æ¢è®¾å¤‡åŽæ›´æ–°å®žæ—¶å‚æ•°
  updateRealTimeParams()
  // åˆ·æ–°åŽ†å²æ•°æ®å›¾è¡¨
  initHistoryChart()
}
// æ›´æ–°å®žæ—¶å‚数(模拟)
const updateRealTimeParams = () => {
  realTimeParams.value = realTimeParams.value.map(param => {
    // ç”Ÿæˆéšæœºå€¼ï¼Œéƒ¨åˆ†å‚数可能触发告警
    const randomFactor = Math.random() * 0.2 - 0.1 // -0.1 åˆ° 0.1 ä¹‹é—´çš„随机数
    const baseValue = (param.min + param.max) / 2
    const newValue = baseValue + baseValue * randomFactor
    const isAlarm = newValue < param.min || newValue > param.max
    return {
      ...param,
      value: Number(newValue.toFixed(2)),
      isAlarm
    }
  })
}
// å¤„理历史数据查询
const handleHistoryQuery = () => {
  // æ¨¡æ‹ŸæŸ¥è¯¢åŽ†å²æ•°æ®
  generateHistoryData()
  initHistoryChart()
  ElMessage.success('历史数据查询成功')
}
// ç”ŸæˆåŽ†å²æ•°æ®ï¼ˆæ¨¡æ‹Ÿï¼‰
const generateHistoryData = () => {
  const dates = []
  const values = []
  // ç”Ÿæˆè¿‡åŽ»7天的日期和对应数据
  for (let i = 6; i >= 0; i--) {
    const date = new Date()
    date.setDate(date.getDate() - i)
    dates.push(date.toLocaleDateString())
    // ç”Ÿæˆéšæœºå€¼
    const baseValue = (realTimeParams.value.find(p => p.name === activeParam.value).min +
                      realTimeParams.value.find(p => p.name === activeParam.value).max) / 2
    const randomValue = baseValue + (Math.random() - 0.5) * baseValue * 0.4
    values.push(Number(randomValue.toFixed(2)))
  }
  historyData.value = {
    dates,
    values
  }
}
// åˆå§‹åŒ–历史数据趋势图
const initHistoryChart = () => {
  if (historyChartRef.value) {
    historyChart = echarts.init(historyChartRef.value)
    // å¦‚果没有历史数据,生成模拟数据
    if (historyData.value.dates.length === 0) {
      generateHistoryData()
    }
    const paramConfig = realTimeParams.value.find(p => p.name === activeParam.value)
    const option = {
      tooltip: {
        trigger: 'axis',
        axisPointer: {
          type: 'cross',
          label: {
            backgroundColor: '#6a7985'
          }
        }
      },
      grid: {
        left: '3%',
        right: '4%',
        bottom: '3%',
        containLabel: true
      },
      xAxis: {
        type: 'category',
        boundaryGap: false,
        data: historyData.value.dates
      },
      yAxis: {
        type: 'value',
        name: `${activeParam.value}(${paramConfig.unit})`,
        min: paramConfig.min * 0.9,
        max: paramConfig.max * 1.1
      },
      series: [
        {
          name: activeParam.value,
          type: 'line',
          stack: '总量',
          areaStyle: {},
          emphasis: {
            focus: 'series'
          },
          data: historyData.value.values,
          itemStyle: {
            color: '#409eff'
          },
          lineStyle: {
            width: 3
          }
        }
      ]
    }
    historyChart.setOption(option)
  }
}
// å¤„理参数切换
const handleParamChange = () => {
  // ç”Ÿæˆæ–°å‚数的历史数据
  generateHistoryData()
  initHistoryChart()
}
// å¤„理告警关闭
const handleAlarmClose = (alarmId) => {
  const index = alarmList.value.findIndex(alarm => alarm.id === alarmId)
  if (index !== -1) {
    alarmList.value.splice(index, 1)
  }
}
// æ‰“开设备详情页
const openDeviceDetail = () => {
  initThresholdForm()
  deviceDetailVisible.value = true
}
// ä¿å­˜é˜ˆå€¼è®¾ç½®
const saveThresholds = () => {
  // æ¨¡æ‹Ÿä¿å­˜é˜ˆå€¼
  realTimeParams.value = realTimeParams.value.map(param => {
    return {
      ...param,
      min: thresholdForm.value[param.name + 'Min'],
      max: thresholdForm.value[param.name + 'Max']
    }
  })
  deviceDetailVisible.value = false
  ElMessage.success('阈值设置保存成功')
}
// ç›‘听窗口大小变化,调整图表大小
const handleResize = () => {
  historyChart?.resize()
}
// æ¯5秒更新一次实时参数(模拟)
let updateTimer = null
const startRealTimeUpdate = () => {
  updateTimer = setInterval(() => {
    updateRealTimeParams()
  }, 5000)
}
onMounted(() => {
  // åˆå§‹åŒ–图表
  initHistoryChart()
  // åˆå§‹åŒ–阈值表单
  initThresholdForm()
  // å¼€å§‹å®žæ—¶æ›´æ–°
  startRealTimeUpdate()
  // ç›‘听窗口大小变化
  window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
  // æ¸…除定时器
  if (updateTimer) {
    clearInterval(updateTimer)
  }
  // é”€æ¯å›¾è¡¨
  historyChart?.dispose()
  // ç§»é™¤äº‹ä»¶ç›‘听
  window.removeEventListener('resize', handleResize)
})
</script>
<style scoped>
.real-time-monitoring-container {
  padding: 20px;
  background-color: #f5f7fa;
  min-height: 100vh;
}
.device-select-form {
  margin-bottom: 0;
}
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.param-tabs {
  display: flex;
  gap: 10px;
}
.param-card {
  transition: all 0.3s;
}
.alarm-card {
  border-left: 4px solid #f56c6c;
  box-shadow: 0 2px 12px 0 rgba(245, 108, 108, 0.1);
}
.param-content {
  text-align: center;
}
.param-title {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 10px;
  font-size: 16px;
  color: #606266;
  margin-bottom: 10px;
}
.param-value {
  font-size: 32px;
  font-weight: bold;
  color: #303133;
  margin-bottom: 10px;
  display: block;
}
.alarm-value {
  color: #f56c6c;
}
.param-range {
  font-size: 14px;
  color: #909399;
}
.alarm-item {
  margin-bottom: 10px;
}
.alarm-detail {
  display: flex;
  justify-content: space-between;
  margin-top: 5px;
  font-size: 14px;
  color: #606266;
}
.chart-container {
  width: 100%;
  height: 400px;
}
.device-detail-content {
  padding: 10px 0;
}
.device-detail-content h3 {
  margin-bottom: 20px;
  color: #303133;
}
.detail-param-item {
  display: flex;
  align-items: center;
  margin-bottom: 15px;
  padding: 10px;
  background-color: #fafafa;
  border-radius: 4px;
}
.param-label {
  font-size: 14px;
  color: #606266;
  width: 80px;
}
.param-range {
  font-size: 12px;
  color: #909399;
  margin-left: 10px;
}
</style>
src/views/personnelManagement/contractManagement/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/contractManagement/filesDia.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/contractManagement/index.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/dimission/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/dimission/index.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/employeeRecord/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/employeeRecord/index.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/onboarding/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/onboarding/index.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/payrollManagement/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/payrollManagement/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/invoiceEntry/components/ExpandTable.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/invoiceEntry/components/Modal.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/invoiceEntry/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/invoiceEntry/indexOld.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/paymentEntry/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/paymentHistory/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/paymentLedger/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/procurementInvoiceLedger/Form/EditForm.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/procurementInvoiceLedger/Modal/EditModal.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/procurementInvoiceLedger/Modal/UploadModal.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/procurementInvoiceLedger/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/procurementInvoiceLedger/indexOld.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/procurementLedger/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/thePaymentLedger/index.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/operationScheduling/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/operationScheduling/index.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/productionCosting/index.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/productionDispatching/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/productionDispatching/index.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/productionOrder/index.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/productionReporting/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/productionReporting/index.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/safetyMonitoring/index.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/finalInspection/components/filesDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/finalInspection/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/finalInspection/components/inspectionFormDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/finalInspection/index.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/metricMaintenance/index.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/nonconformingManagement/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/nonconformingManagement/components/inspectionFormDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/nonconformingManagement/index.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/processInspection/components/filesDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/processInspection/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/processInspection/components/inspectionFormDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/processInspection/index.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/rawMaterialInspection/components/filesDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/rawMaterialInspection/components/inspectionFormDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/rawMaterialInspection/index.vue
ÎļþÒÑɾ³ý
src/views/reportAnalysis/projectProfit/index.vue
ÎļþÒÑɾ³ý
src/views/reportAnalysis/taxComparison/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/invoiceLedger/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/invoiceRegistration/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/receiptPayment/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/receiptPaymentHistory/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/receiptPaymentLedger/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/salesLedger/fileList.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/salesLedger/index.vue
ÎļþÒÑɾ³ý
vite.config.js
@@ -8,8 +8,8 @@
  const { VITE_APP_ENV } = env;
  const baseUrl =
    VITE_APP_ENV == "development"
      ? "http://192.168.1.147:7003" // å¼€å‘环境后端接口
      : "http://10.136.12.71:7003"; // ç”Ÿäº§çŽ¯å¢ƒåŽç«¯æŽ¥å£
      ? "http://127.0.0.1:8020" // å¼€å‘环境后端接口
      : "http://10.136.12.71:8020"; // ç”Ÿäº§çŽ¯å¢ƒåŽç«¯æŽ¥å£
  return {
    // éƒ¨ç½²ç”Ÿäº§çŽ¯å¢ƒå’Œå¼€å‘çŽ¯å¢ƒä¸‹çš„URL。