Jelajahi Sumber

Merge branch 'qhse_person' of shuzhihua/pms-iot-vue into master

yanghao 8 jam lalu
induk
melakukan
009d253e55

+ 28 - 0
src/api/pms/qhse/index.ts

@@ -534,3 +534,31 @@ export const QhseMonthReportApi = {
     return await request.download({ url: `/rq/qhse-month-report/export-excel`, params })
     return await request.download({ url: `/rq/qhse-month-report/export-excel`, params })
   }
   }
 }
 }
+
+// 应检设备证书
+export const InspectDeviceCertApi = {
+  // 获得设备证书分页
+  getInspectDeviceCertList: async (params) => {
+    return await request.get({ url: `/rq/qhse-inspect-device-cert/page`, params })
+  },
+  // 删除设备证书
+  deleteInspectDeviceCert: async (id) => {
+    return await request.delete({ url: `/rq/qhse-inspect-device-cert/delete?id=` + id })
+  },
+  // 添加设备证书
+  createInspectDeviceCert: async (data) => {
+    return await request.post({ url: `/rq/qhse-inspect-device-cert/create`, data })
+  },
+  // 获取详情
+  getInspectDeviceCert: async (id) => {
+    return await request.get({ url: `/rq/qhse-inspect-device-cert/get?id=` + id })
+  },
+  // 修改设备证书
+  updateInspectDeviceCert: async (data) => {
+    return await request.put({ url: `/rq/qhse-inspect-device-cert/update`, data })
+  },
+  // 导出设备证书 Excel
+  exportInspectDeviceCert: async (params) => {
+    return await request.download({ url: `/rq/qhse-inspect-device-cert/export-excel`, params })
+  }
+}

+ 1 - 0
src/layout/components/Menu/src/components/useRenderMenuItem.tsx

@@ -149,6 +149,7 @@ export const useRenderMenuItem = () =>
                 '职业健康体检',
                 '职业健康体检',
                 '健康培训',
                 '健康培训',
                 '突发事件处置',
                 '突发事件处置',
+                'QHSE月报管理',
                 'QHSE资料库',
                 'QHSE资料库',
                 'QHSE资质证书',
                 'QHSE资质证书',
                 'QHSE体系文件',
                 'QHSE体系文件',

+ 12 - 24
src/views/pms/device/DeviceInfo.vue

@@ -7,8 +7,7 @@
           :src="defaultPicUrl"
           :src="defaultPicUrl"
           style="width: 35em; height: 12em"
           style="width: 35em; height: 12em"
           @click="imagePreview(defaultPicUrl)"
           @click="imagePreview(defaultPicUrl)"
-          fit="contain"
-        />
+          fit="contain" />
       </div>
       </div>
       <div style="flex: 2; height: 12em; margin-top: 23px">
       <div style="flex: 2; height: 12em; margin-top: 23px">
         <el-form ref="formRef" :disabled="false" :model="formData" label-width="120px">
         <el-form ref="formRef" :disabled="false" :model="formData" label-width="120px">
@@ -169,8 +168,7 @@
           ref="fileRef"
           ref="fileRef"
           :deviceId="id"
           :deviceId="id"
           :deviceName="formData.deviceName"
           :deviceName="formData.deviceName"
-          v-if="loadedTabs.includes('1')"
-        />
+          v-if="loadedTabs.includes('1')" />
       </el-tab-pane>
       </el-tab-pane>
       <el-tab-pane :label="t('deviceInfo.deviceBOM')" name="bom">
       <el-tab-pane :label="t('deviceInfo.deviceBOM')" name="bom">
         <BomList
         <BomList
@@ -178,72 +176,63 @@
           v-model:activeName="activeName"
           v-model:activeName="activeName"
           :deviceId="id"
           :deviceId="id"
           :deviceCategoryName="formData.assetClassName"
           :deviceCategoryName="formData.assetClassName"
-          v-if="loadedTabs.includes('2')"
-        />
+          v-if="loadedTabs.includes('2')" />
       </el-tab-pane>
       </el-tab-pane>
       <el-tab-pane :label="t('deviceInfo.operationRecords')" name="record">
       <el-tab-pane :label="t('deviceInfo.operationRecords')" name="record">
         <RecordList
         <RecordList
           ref="recordRef"
           ref="recordRef"
           v-model:activeName="activeName"
           v-model:activeName="activeName"
           :deviceId="id"
           :deviceId="id"
-          v-if="loadedTabs.includes('3')"
-        />
+          v-if="loadedTabs.includes('3')" />
       </el-tab-pane>
       </el-tab-pane>
       <el-tab-pane :label="t('deviceInfo.faultRecords')" name="failure">
       <el-tab-pane :label="t('deviceInfo.faultRecords')" name="failure">
         <FailureList
         <FailureList
           ref="failureRef"
           ref="failureRef"
           v-model:activeName="activeName"
           v-model:activeName="activeName"
           :deviceId="id"
           :deviceId="id"
-          v-if="loadedTabs.includes('4')"
-        />
+          v-if="loadedTabs.includes('4')" />
       </el-tab-pane>
       </el-tab-pane>
       <el-tab-pane :label="t('deviceInfo.repairRecords')" name="maintain">
       <el-tab-pane :label="t('deviceInfo.repairRecords')" name="maintain">
         <MaintainList
         <MaintainList
           ref="maintainRef"
           ref="maintainRef"
           v-model:activeName="activeName"
           v-model:activeName="activeName"
           :deviceId="id"
           :deviceId="id"
-          v-if="loadedTabs.includes('5')"
-        />
+          v-if="loadedTabs.includes('5')" />
       </el-tab-pane>
       </el-tab-pane>
       <el-tab-pane :label="t('deviceInfo.maintenanceRecords')" name="maintenance">
       <el-tab-pane :label="t('deviceInfo.maintenanceRecords')" name="maintenance">
         <MaintenanceList
         <MaintenanceList
           ref="maintenanceRef"
           ref="maintenanceRef"
           v-model:activeName="activeName"
           v-model:activeName="activeName"
           :deviceId="id"
           :deviceId="id"
-          v-if="loadedTabs.includes('6')"
-        />
+          v-if="loadedTabs.includes('6')" />
       </el-tab-pane>
       </el-tab-pane>
       <el-tab-pane :label="t('deviceInfo.inspectionRecords')" name="inspect">
       <el-tab-pane :label="t('deviceInfo.inspectionRecords')" name="inspect">
         <InspectList
         <InspectList
           ref="inspectRef"
           ref="inspectRef"
           v-model:activeName="activeName"
           v-model:activeName="activeName"
           :deviceId="id"
           :deviceId="id"
-          v-if="loadedTabs.includes('7')"
-        />
+          v-if="loadedTabs.includes('7')" />
       </el-tab-pane>
       </el-tab-pane>
       <el-tab-pane :label="t('deviceInfo.transferRecords')" name="allot">
       <el-tab-pane :label="t('deviceInfo.transferRecords')" name="allot">
         <AllotLogList
         <AllotLogList
           ref="allotRef"
           ref="allotRef"
           v-model:activeName="activeName"
           v-model:activeName="activeName"
           :deviceId="id"
           :deviceId="id"
-          v-if="loadedTabs.includes('8')"
-        />
+          v-if="loadedTabs.includes('8')" />
       </el-tab-pane>
       </el-tab-pane>
       <el-tab-pane :label="t('deviceInfo.statusChangeRecords')" name="status">
       <el-tab-pane :label="t('deviceInfo.statusChangeRecords')" name="status">
         <DeviceStatusLogList
         <DeviceStatusLogList
           ref="statusRef"
           ref="statusRef"
           v-model:activeName="activeName"
           v-model:activeName="activeName"
           :deviceId="id"
           :deviceId="id"
-          v-if="loadedTabs.includes('9')"
-        />
+          v-if="loadedTabs.includes('9')" />
       </el-tab-pane>
       </el-tab-pane>
       <el-tab-pane :label="t('deviceInfo.RPAdjustmentRecords')" name="person">
       <el-tab-pane :label="t('deviceInfo.RPAdjustmentRecords')" name="person">
         <PersonList
         <PersonList
           ref="personRef"
           ref="personRef"
           v-model:activeName="activeName"
           v-model:activeName="activeName"
           :deviceId="id"
           :deviceId="id"
-          v-if="loadedTabs.includes('10')"
-        />
+          v-if="loadedTabs.includes('10')" />
       </el-tab-pane>
       </el-tab-pane>
 
 
       <!-- 关联设备 -->
       <!-- 关联设备 -->
@@ -252,8 +241,7 @@
           ref="personRef"
           ref="personRef"
           v-model:activeName="activeName"
           v-model:activeName="activeName"
           :deviceId="id"
           :deviceId="id"
-          v-if="loadedTabs.includes('11')"
-        />
+          v-if="loadedTabs.includes('11')" />
       </el-tab-pane>
       </el-tab-pane>
     </el-tabs>
     </el-tabs>
   </ContentWrap>
   </ContentWrap>

+ 25 - 17
src/views/pms/qhse/index.vue

@@ -14,24 +14,32 @@
     <el-form
     <el-form
       ref="queryFormRef"
       ref="queryFormRef"
       :model="queryParams"
       :model="queryParams"
-      size="default"
+      size="small"
       label-width="auto"
       label-width="auto"
-      class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 py-2 flex items-center flex-wrap min-w-0">
-      <div class="flex items-center gap-4 flex-wrap">
+      class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 pt-4 flex items-center flex-wrap min-w-0">
+      <div class="flex items-center gap-1 flex-wrap">
         <el-form-item label="计量器具名称" prop="measureName">
         <el-form-item label="计量器具名称" prop="measureName">
           <el-input
           <el-input
             v-model="queryParams.measureName"
             v-model="queryParams.measureName"
             placeholder="请输入计量器具名称"
             placeholder="请输入计量器具名称"
             clearable
             clearable
             @keyup.enter="handleQuery"
             @keyup.enter="handleQuery"
-            class="!w-200px" />
+            class="!w-120px" />
+        </el-form-item>
+        <el-form-item label="编码" prop="measureCode">
+          <el-input
+            v-model="queryParams.measureCode"
+            placeholder="请输入计量器具编码"
+            clearable
+            @keyup.enter="handleQuery"
+            class="!w-120px" />
         </el-form-item>
         </el-form-item>
         <el-form-item label="是否过期" prop="expired">
         <el-form-item label="是否过期" prop="expired">
           <el-select
           <el-select
             v-model="queryParams.expired"
             v-model="queryParams.expired"
             placeholder="请选择是否过期"
             placeholder="请选择是否过期"
             clearable
             clearable
-            class="!w-200px">
+            class="!w-120px">
             <el-option
             <el-option
               v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
               v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
               :key="dict.value"
               :key="dict.value"
@@ -44,7 +52,7 @@
             v-model="queryParams.alertWarn"
             v-model="queryParams.alertWarn"
             placeholder="请选择是否预警"
             placeholder="请选择是否预警"
             clearable
             clearable
-            class="!w-200px">
+            class="!w-120px">
             <el-option
             <el-option
               v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
               v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
               :key="dict.value"
               :key="dict.value"
@@ -200,14 +208,13 @@
   </div>
   </div>
 
 
   <!-- 新增/编辑台账对话框 -->
   <!-- 新增/编辑台账对话框 -->
-  <el-dialog
-    :title="dialogTitle"
-    v-model="dialogVisible"
-    width="800px"
-    destroy-on-close
-    label-width="120px"
-    @close="closeDialog">
-    <el-form ref="formRef" :model="formData" :rules="formRules" v-loading="formLoading">
+  <Dialog :title="dialogTitle" v-model="dialogVisible" destroy-on-close @close="closeDialog">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      v-loading="formLoading"
+      label-width="120px">
       <el-row :gutter="20">
       <el-row :gutter="20">
         <el-col :span="12">
         <el-col :span="12">
           <el-form-item label="计量器具名称" prop="measureName">
           <el-form-item label="计量器具名称" prop="measureName">
@@ -333,7 +340,7 @@
       <el-button @click="closeDialog">取 消</el-button>
       <el-button @click="closeDialog">取 消</el-button>
       <el-button type="primary" @click="submitForm" :loading="submitLoading">确 定</el-button>
       <el-button type="primary" @click="submitForm" :loading="submitLoading">确 定</el-button>
     </template>
     </template>
-  </el-dialog>
+  </Dialog>
 
 
   <el-drawer
   <el-drawer
     v-model="drawerVisible"
     v-model="drawerVisible"
@@ -411,7 +418,7 @@
     </div>
     </div>
   </el-drawer>
   </el-drawer>
 
 
-  <el-dialog v-model="dialogFileView" title="附件" width="500">
+  <Dialog v-model="dialogFileView" title="附件" width="500">
     <div
     <div
       v-for="(file, index) in fileList"
       v-for="(file, index) in fileList"
       :key="index"
       :key="index"
@@ -432,7 +439,7 @@
         <el-button type="primary" @click="dialogFileView = false"> 确认 </el-button>
         <el-button type="primary" @click="dialogFileView = false"> 确认 </el-button>
       </div>
       </div>
     </template>
     </template>
-  </el-dialog>
+  </Dialog>
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
@@ -474,6 +481,7 @@ const queryParams = reactive({
   pageNo: 1,
   pageNo: 1,
   pageSize: 10,
   pageSize: 10,
   measureName: undefined,
   measureName: undefined,
+  measureCertNo: undefined,
   deptId: undefined,
   deptId: undefined,
   expired: undefined,
   expired: undefined,
   alertWarn: undefined
   alertWarn: undefined

+ 108 - 94
src/views/pms/qhse/iotmeasuredetect/index.vue

@@ -1,11 +1,22 @@
 <template>
 <template>
-  <el-row :gutter="20">
-    <DeptTree @node-click="handleDeptNodeClick" v-model:collapsed="isLeftContentCollapsed" />
-
-    <el-col :span="isLeftContentCollapsed ? 24 : 20" :xs="24">
-      <ContentWrap style="border: none">
-        <!-- 搜索工作栏 -->
-        <el-form :model="queryParams" ref="queryFormRef" :inline="true">
+  <div
+    class="grid grid-cols-[auto_1fr] grid-rows-[auto_auto_minmax(0,1fr)] gap-0 gap-x-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]">
+    <DeptTreeSelect
+      class="row-span-4"
+      :top-id="rootDeptId"
+      :deptId="deptId"
+      v-model="queryParams.deptId"
+      :init-select="false"
+      :show-title="false"
+      request-api="getSimpleDeptList"
+      @node-click="handleDeptNodeClick" />
+
+    <div class="mb-1">
+      <el-form
+        :model="queryParams"
+        ref="queryFormRef"
+        class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 py-2 pt-4 flex items-center flex-wrap min-w-0">
+        <div class="flex items-center gap-4 flex-wrap">
           <el-form-item label="计量器具编码" prop="measureCode">
           <el-form-item label="计量器具编码" prop="measureCode">
             <el-input
             <el-input
               v-model="queryParams.measureCode"
               v-model="queryParams.measureCode"
@@ -32,14 +43,6 @@
               class="!w-150px" />
               class="!w-150px" />
           </el-form-item>
           </el-form-item>
           <el-form-item label="检测/校准有效期" prop="validityPeriod">
           <el-form-item label="检测/校准有效期" prop="validityPeriod">
-            <!-- <el-date-picker
-              v-model="queryParams.validityPeriod"
-              value-format="YYYY-MM-DD"
-              type="daterange"
-              placeholder="选择检测/校准有效期"
-              clearable
-              class="!w-150px" /> -->
-
             <el-date-picker
             <el-date-picker
               v-model="queryParams.validityPeriod"
               v-model="queryParams.validityPeriod"
               value-format="YYYY-MM-DD HH:mm:ss"
               value-format="YYYY-MM-DD HH:mm:ss"
@@ -64,76 +67,91 @@
               <Icon icon="ep:download" class="mr-5px" /> 导出
               <Icon icon="ep:download" class="mr-5px" /> 导出
             </el-button>
             </el-button>
           </el-form-item>
           </el-form-item>
-        </el-form>
-      </ContentWrap>
-
-      <!-- 列表 -->
-      <ContentWrap class="flex-1 overflow-hidden mt-15px" style="border: none">
-        <zm-table
-          :loading="loading"
-          :data="list"
-          :stripe="true"
-          height="calc(85vh - 195px)"
-          :show-overflow-tooltip="true">
-          <zm-table-column :label="t('monitor.serial')" width="70" align="center">
-            <template #default="scope">
-              {{ scope.$index + 1 }}
-            </template>
-          </zm-table-column>
-          <zm-table-column label="计量器具编码" align="center" prop="measureCode" />
-          <zm-table-column label="计量器具名称" align="center" prop="measureName" />
-          <zm-table-column label="证书编码" align="center" prop="measureCertNo" />
-          <zm-table-column label="检测/校准日期" align="center" prop="detectDate" width="140">
-            <template #default="scope">
-              <span class="iot-md-date">{{ formatDateCorrectly(scope.row.detectDate) }}</span>
-            </template>
-          </zm-table-column>
-          <zm-table-column label="检测/校准机构" align="center" prop="detectOrg" />
-          <zm-table-column label="检测/校准标准" align="center" prop="detectStandard" />
-          <zm-table-column label="检测/校准内容" align="center" prop="detectContent">
-            <template #default="scope">
-              <div class="detect-content" v-html="scope.row.detectContent"></div>
-            </template>
-          </zm-table-column>
-          <zm-table-column label="检测/校准有效期" align="center" prop="validityPeriod" width="140">
-            <template #default="scope">
-              <span class="iot-md-date">{{ formatDateCorrectly(scope.row.validityPeriod) }}</span>
-            </template>
-          </zm-table-column>
-          <zm-table-column label="校准金额" align="center" prop="detectAmount" />
-          <zm-table-column label="部门名称" align="center" prop="deptName" />
-          <zm-table-column label="附件" align="center" prop="file" min-width="90">
-            <template #default="scope">
-              <el-button
-                v-if="scope.row.file"
-                link
-                type="primary"
-                @click="viewFile(scope.row.file)">
-                查看
-              </el-button>
-            </template>
-          </zm-table-column>
-          <zm-table-column label="操作" align="center" width="140" fixed="right" action>
-            <template #default="scope">
-              <el-button link type="primary" @click="openForm('update', scope.row.id)">
-                编辑
-              </el-button>
-              <el-button link type="danger" @click="handleDelete(scope.row.id)"> 删除 </el-button>
-            </template>
-          </zm-table-column>
-        </zm-table>
-        <div class="iot-md-pagination">
-          <Pagination
-            :total="total"
-            v-model:page="queryParams.pageNo"
-            v-model:limit="queryParams.pageSize"
-            @pagination="getList" />
         </div>
         </div>
-      </ContentWrap>
-    </el-col>
-  </el-row>
+      </el-form>
+    </div>
 
 
-  <el-dialog v-model="dialogFileView" title="附件" width="500">
+    <div class="min-w-0"></div>
+
+    <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg flex flex-col p-2 pt-4 min-w-0">
+      <div class="flex-1 relative min-h-0">
+        <el-auto-resizer class="absolute">
+          <template #default="{ width, height }">
+            <zm-table
+              :loading="loading"
+              :data="list"
+              :width="width"
+              :height="height"
+              :max-height="height">
+              <zm-table-column :label="t('monitor.serial')" width="70" align="center">
+                <template #default="scope">
+                  {{ scope.$index + 1 }}
+                </template>
+              </zm-table-column>
+              <zm-table-column label="计量器具编码" align="center" prop="measureCode" />
+              <zm-table-column label="计量器具名称" align="center" prop="measureName" />
+              <zm-table-column label="证书编码" align="center" prop="measureCertNo" />
+              <zm-table-column label="检测/校准日期" align="center" prop="detectDate" width="140">
+                <template #default="scope">
+                  <span class="iot-md-date">{{ formatDateCorrectly(scope.row.detectDate) }}</span>
+                </template>
+              </zm-table-column>
+              <zm-table-column label="检测/校准机构" align="center" prop="detectOrg" />
+              <zm-table-column label="检测/校准标准" align="center" prop="detectStandard" />
+              <zm-table-column label="检测/校准内容" align="center" prop="detectContent">
+                <template #default="scope">
+                  <div class="detect-content" v-html="scope.row.detectContent"></div>
+                </template>
+              </zm-table-column>
+              <zm-table-column
+                label="检测/校准有效期"
+                align="center"
+                prop="validityPeriod"
+                width="140">
+                <template #default="scope">
+                  <span class="iot-md-date">{{
+                    formatDateCorrectly(scope.row.validityPeriod)
+                  }}</span>
+                </template>
+              </zm-table-column>
+              <zm-table-column label="校准金额" align="center" prop="detectAmount" />
+              <zm-table-column label="部门名称" align="center" prop="deptName" />
+              <zm-table-column label="附件" align="center" prop="file" min-width="90">
+                <template #default="scope">
+                  <el-button
+                    v-if="scope.row.file"
+                    link
+                    type="primary"
+                    @click="viewFile(scope.row.file)">
+                    查看
+                  </el-button>
+                </template>
+              </zm-table-column>
+              <zm-table-column label="操作" align="center" width="140" fixed="right" action>
+                <template #default="scope">
+                  <el-button link type="primary" @click="openForm('update', scope.row.id)">
+                    编辑
+                  </el-button>
+                  <el-button link type="danger" @click="handleDelete(scope.row.id)">
+                    删除
+                  </el-button>
+                </template>
+              </zm-table-column>
+            </zm-table>
+          </template>
+        </el-auto-resizer>
+      </div>
+      <div class="h-8 mt-2 flex items-center justify-end">
+        <Pagination
+          :total="total"
+          v-model:page="queryParams.pageNo"
+          v-model:limit="queryParams.pageSize"
+          @pagination="getList" />
+      </div>
+    </div>
+  </div>
+
+  <Dialog v-model="dialogFileView" title="附件" width="500">
     <div
     <div
       v-for="(file, index) in fileList"
       v-for="(file, index) in fileList"
       :key="index"
       :key="index"
@@ -154,7 +172,7 @@
         <el-button type="primary" @click="dialogFileView = false"> 确认 </el-button>
         <el-button type="primary" @click="dialogFileView = false"> 确认 </el-button>
       </div>
       </div>
     </template>
     </template>
-  </el-dialog>
+  </Dialog>
 
 
   <!-- 表单弹窗:添加/修改 -->
   <!-- 表单弹窗:添加/修改 -->
   <IotMeasureDetectForm ref="formRef" @success="getList" />
   <IotMeasureDetectForm ref="formRef" @success="getList" />
@@ -165,16 +183,19 @@ import download from '@/utils/download'
 import { IotMeasureDetectApi, IotMeasureDetectVO } from '@/api/pms/qhse/index'
 import { IotMeasureDetectApi, IotMeasureDetectVO } from '@/api/pms/qhse/index'
 import IotMeasureDetectForm from './IotMeasureDetectForm.vue'
 import IotMeasureDetectForm from './IotMeasureDetectForm.vue'
 import { formatDate } from '@/utils/formatTime'
 import { formatDate } from '@/utils/formatTime'
-import DeptTree from '@/views/system/user/DeptTree2.vue'
+import DeptTreeSelect from '@/components/DeptTreeSelect/index.vue'
 import { useTableComponents } from '@/components/ZmTable/useTableComponents'
 import { useTableComponents } from '@/components/ZmTable/useTableComponents'
 const { ZmTable, ZmTableColumn } = useTableComponents()
 const { ZmTable, ZmTableColumn } = useTableComponents()
+import { useUserStore } from '@/store/modules/user'
 
 
 /** 计量器具-检测校准明细 列表 */
 /** 计量器具-检测校准明细 列表 */
 defineOptions({ name: 'IotMeasureDetect' })
 defineOptions({ name: 'IotMeasureDetect' })
+// const userStore = useUserStore()
+const rootDeptId = 156
+const deptId = useUserStore().getUser.deptId || rootDeptId
 
 
 const message = useMessage() // 消息弹窗
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 const { t } = useI18n() // 国际化
-const isLeftContentCollapsed = ref(false)
 
 
 const loading = ref(true) // 列表的加载中
 const loading = ref(true) // 列表的加载中
 const list = ref<IotMeasureDetectVO[]>([]) // 列表的数据
 const list = ref<IotMeasureDetectVO[]>([]) // 列表的数据
@@ -338,14 +359,7 @@ onMounted(() => {
 })
 })
 </script>
 </script>
 
 
-<style scoped>
-::deep(.el-tree--highlight-current) {
-  height: 200px !important;
-}
-::deep(.el-transfer-panel__body) {
-  height: 700px !important;
-}
-
+<style scoped lang="scss">
 .file-name-text {
 .file-name-text {
   flex: 1;
   flex: 1;
   overflow: hidden;
   overflow: hidden;

+ 89 - 33
src/views/pms/stat/maintain.vue

@@ -700,9 +700,11 @@ const initChart = async () => {
         barGap: 0,
         barGap: 0,
         itemStyle: {
         itemStyle: {
           color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
           color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-            { offset: 0, color: '#188df0' },
+            { offset: 0, color: '#83bff6' },
+            { offset: 0.5, color: '#188df0' },
             { offset: 1, color: '#188df0' }
             { offset: 1, color: '#188df0' }
-          ])
+          ]),
+          borderRadius: [5, 5, 0, 0]
         },
         },
         emphasis: {
         emphasis: {
           focus: 'series'
           focus: 'series'
@@ -714,10 +716,11 @@ const initChart = async () => {
         type: 'bar',
         type: 'bar',
         itemStyle: {
         itemStyle: {
           color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
           color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-            { offset: 0, color: '#d3a137' },
-
+            { offset: 0, color: '#ffb600' },
+            { offset: 0.5, color: '#d3a137' },
             { offset: 1, color: '#d3a137' }
             { offset: 1, color: '#d3a137' }
-          ])
+          ]),
+          borderRadius: [5, 5, 0, 0]
         },
         },
         emphasis: {
         emphasis: {
           focus: 'series'
           focus: 'series'
@@ -755,14 +758,22 @@ onUnmounted(() => {
 // 统计卡片基础样式
 // 统计卡片基础样式
 .stat-card {
 .stat-card {
   border-radius: 12px;
   border-radius: 12px;
-  border: none;
+  border: 1px solid rgba(207, 220, 237, 0.9);
   transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
   transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
   overflow: hidden;
   overflow: hidden;
   position: relative;
   position: relative;
+  background: linear-gradient(180deg, #ffffff 0%, #f4f8ff 100%);
+  box-shadow:
+    inset 0 1px 0 rgba(255, 255, 255, 0.95),
+    inset 0 -10px 24px rgba(210, 225, 244, 0.26),
+    0 10px 24px rgba(32, 66, 120, 0.08);
 
 
   &:hover {
   &:hover {
     transform: translateY(-4px);
     transform: translateY(-4px);
-    box-shadow: 0 12px 24px -8px rgba(0, 0, 0, 0.15);
+    box-shadow:
+      inset 0 1px 0 rgba(255, 255, 255, 0.98),
+      inset 0 -12px 26px rgba(204, 220, 243, 0.32),
+      0 16px 32px rgba(32, 66, 120, 0.12);
   }
   }
 
 
   :deep(.el-card__body) {
   :deep(.el-card__body) {
@@ -772,25 +783,29 @@ onUnmounted(() => {
 
 
 // 渐变色背景
 // 渐变色背景
 .stat-card-gradient-1 {
 .stat-card-gradient-1 {
-  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  background: radial-gradient(circle at top left, rgba(121, 164, 255, 0.16), transparent 42%),
+    linear-gradient(180deg, #ffffff 0%, #f4f8ff 100%);
 }
 }
 
 
 .stat-card-gradient-2 {
 .stat-card-gradient-2 {
-  background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
+  background: radial-gradient(circle at top left, rgba(118, 186, 255, 0.14), transparent 42%),
+    linear-gradient(180deg, #ffffff 0%, #f3f8ff 100%);
 }
 }
 
 
 .stat-card-gradient-3 {
 .stat-card-gradient-3 {
-  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
+  background: radial-gradient(circle at top left, rgba(96, 154, 241, 0.14), transparent 42%),
+    linear-gradient(180deg, #ffffff 0%, #f5f9ff 100%);
 }
 }
 
 
 .stat-card-gradient-4 {
 .stat-card-gradient-4 {
-  background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
+  background: radial-gradient(circle at top left, rgba(137, 176, 242, 0.14), transparent 42%),
+    linear-gradient(180deg, #ffffff 0%, #f4f8fe 100%);
 }
 }
 
 
 // 统计内容区域
 // 统计内容区域
 .stat-content {
 .stat-content {
   padding: 20px;
   padding: 20px;
-  color: white;
+  color: #1f2a44;
 }
 }
 
 
 .stat-header {
 .stat-header {
@@ -803,27 +818,31 @@ onUnmounted(() => {
 .stat-icon-wrapper {
 .stat-icon-wrapper {
   width: 48px;
   width: 48px;
   height: 48px;
   height: 48px;
-  background: rgba(255, 255, 255, 0.2);
+  background: linear-gradient(180deg, rgba(255, 255, 255, 0.96) 0%, rgba(232, 240, 252, 0.92) 100%);
+  border: 1px solid rgba(205, 219, 239, 0.9);
   border-radius: 12px;
   border-radius: 12px;
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
   justify-content: center;
   justify-content: center;
-  backdrop-filter: blur(10px);
+  box-shadow:
+    inset 0 1px 0 rgba(255, 255, 255, 0.95),
+    inset 0 -6px 12px rgba(205, 220, 242, 0.34),
+    0 6px 14px rgba(66, 104, 168, 0.08);
 }
 }
 
 
 .stat-icon {
 .stat-icon {
   font-size: 24px;
   font-size: 24px;
-  color: white;
+  color: #5d79b7;
 }
 }
 
 
 .stat-title {
 .stat-title {
   font-size: 16px;
   font-size: 16px;
   font-weight: 600;
   font-weight: 600;
-  color: rgba(255, 255, 255, 0.95);
+  color: #000;
 }
 }
 
 
 .stat-divider {
 .stat-divider {
-  border-color: rgba(255, 255, 255, 0.2);
+  border-color: rgba(201, 214, 234, 0.85);
   margin: 12px 0;
   margin: 12px 0;
 }
 }
 
 
@@ -835,14 +854,14 @@ onUnmounted(() => {
 
 
 .stat-label {
 .stat-label {
   font-size: 13px;
   font-size: 13px;
-  color: rgba(255, 255, 255, 0.8);
+  color: #7182a1;
   margin-bottom: 4px;
   margin-bottom: 4px;
 }
 }
 
 
 .stat-value {
 .stat-value {
   font-size: 36px;
   font-size: 36px;
   font-weight: 700;
   font-weight: 700;
-  color: white;
+  color: #1f2f54;
   line-height: 1;
   line-height: 1;
 }
 }
 
 
@@ -854,30 +873,44 @@ onUnmounted(() => {
 
 
 .stat-sub-label {
 .stat-sub-label {
   font-size: 13px;
   font-size: 13px;
-  color: rgba(255, 255, 255, 0.85);
+  color: #7182a1;
 }
 }
 
 
 .stat-sub-value {
 .stat-sub-value {
   font-size: 28px;
   font-size: 28px;
   font-weight: 700;
   font-weight: 700;
   line-height: 1;
   line-height: 1;
+  color: #1f2f54;
 }
 }
 
 
 // 图表卡片增强样式
 // 图表卡片增强样式
 .chart-card-enhanced {
 .chart-card-enhanced {
   border-radius: 12px;
   border-radius: 12px;
-  border: 1px solid #e5e7eb;
+  border: 1px solid rgba(207, 220, 237, 0.9);
   transition: all 0.3s ease;
   transition: all 0.3s ease;
+  background: linear-gradient(180deg, #ffffff 0%, #f5f9ff 100%);
+  box-shadow:
+    inset 0 1px 0 rgba(255, 255, 255, 0.96),
+    inset 0 -12px 26px rgba(212, 226, 244, 0.2),
+    0 10px 24px rgba(32, 66, 120, 0.07);
 
 
   &:hover {
   &:hover {
-    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
-    border-color: #d1d5db;
+    box-shadow:
+      inset 0 1px 0 rgba(255, 255, 255, 0.98),
+      inset 0 -14px 30px rgba(208, 223, 244, 0.24),
+      0 16px 30px rgba(32, 66, 120, 0.1);
+    border-color: rgba(193, 209, 231, 0.95);
   }
   }
 
 
   :deep(.el-card__header) {
   :deep(.el-card__header) {
     padding: 16px 20px;
     padding: 16px 20px;
-    border-bottom: 1px solid #f3f4f6;
-    background: linear-gradient(to right, #fafafa, #ffffff);
+    border-bottom: 1px solid rgba(223, 232, 245, 0.95);
+    background: linear-gradient(
+      90deg,
+      rgba(244, 248, 255, 0.96) 0%,
+      rgba(255, 255, 255, 0.98) 100%
+    );
+    box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.78);
   }
   }
 
 
   :deep(.el-card__body) {
   :deep(.el-card__body) {
@@ -901,14 +934,16 @@ onUnmounted(() => {
   width: 8px;
   width: 8px;
   height: 8px;
   height: 8px;
   border-radius: 50%;
   border-radius: 50%;
-  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-  box-shadow: 0 2px 4px rgba(102, 126, 234, 0.3);
+  background: linear-gradient(135deg, #84aef7 0%, #5e87d8 100%);
+  box-shadow:
+    0 0 0 4px rgba(122, 162, 235, 0.12),
+    0 2px 6px rgba(86, 124, 189, 0.24);
 }
 }
 
 
 .chart-title {
 .chart-title {
   font-size: 16px;
   font-size: 16px;
   font-weight: 600;
   font-weight: 600;
-  color: #1f2937;
+  color: #233554;
   letter-spacing: 0.3px;
   letter-spacing: 0.3px;
 }
 }
 
 
@@ -922,10 +957,17 @@ onUnmounted(() => {
   align-items: center;
   align-items: center;
   padding: 12px;
   padding: 12px;
   transition: all 0.2s ease;
   transition: all 0.2s ease;
+  border-radius: 12px;
 
 
   &:hover {
   &:hover {
-    background: rgba(102, 126, 234, 0.03);
-    border-radius: 8px;
+    background: linear-gradient(
+      180deg,
+      rgba(244, 248, 255, 0.9) 0%,
+      rgba(237, 244, 255, 0.95) 100%
+    );
+    box-shadow:
+      inset 0 1px 0 rgba(255, 255, 255, 0.86),
+      inset 0 -8px 16px rgba(212, 225, 243, 0.22);
   }
   }
 }
 }
 
 
@@ -940,12 +982,21 @@ onUnmounted(() => {
   gap: 6px;
   gap: 6px;
   margin-top: 8px;
   margin-top: 8px;
   padding: 6px 12px;
   padding: 6px 12px;
-  background: #f9fafb;
+  background: linear-gradient(180deg, rgba(255, 255, 255, 0.96) 0%, rgba(242, 247, 255, 0.96) 100%);
+  border: 1px solid rgba(216, 228, 244, 0.95);
   border-radius: 20px;
   border-radius: 20px;
   transition: all 0.2s ease;
   transition: all 0.2s ease;
+  box-shadow:
+    inset 0 1px 0 rgba(255, 255, 255, 0.9),
+    0 4px 10px rgba(58, 90, 145, 0.06);
 
 
   .chart-item:hover & {
   .chart-item:hover & {
-    background: #f3f4f6;
+    background: linear-gradient(
+      180deg,
+      rgba(255, 255, 255, 0.98) 0%,
+      rgba(238, 244, 255, 0.98) 100%
+    );
+    border-color: rgba(201, 217, 239, 0.98);
   }
   }
 }
 }
 
 
@@ -988,13 +1039,18 @@ onUnmounted(() => {
 
 
 .label-text {
 .label-text {
   font-size: 13px;
   font-size: 13px;
-  color: #6b7280;
+  color: #64748f;
   font-weight: 500;
   font-weight: 500;
 }
 }
 
 
 .bar-chart-container {
 .bar-chart-container {
   height: 350px;
   height: 350px;
   width: 100%;
   width: 100%;
+  border-radius: 12px;
+  background: linear-gradient(180deg, rgba(252, 254, 255, 0.9) 0%, rgba(244, 249, 255, 0.92) 100%);
+  box-shadow:
+    inset 0 1px 0 rgba(255, 255, 255, 0.92),
+    inset 0 -10px 20px rgba(217, 230, 245, 0.16);
 }
 }
 
 
 // 响应式优化
 // 响应式优化