yanghao 4 gün önce
ebeveyn
işleme
1c99beb5a4
2 değiştirilmiş dosya ile 117 ekleme ve 2 silme
  1. 8 0
      src/api/pms/qhse/index.ts
  2. 109 2
      src/views/pms/qhse/certificate.vue

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

@@ -46,6 +46,10 @@ export const IotMeasureCertApi = {
   // 导出计量器具-证书管理 Excel
   exportIotMeasureCert: async (params) => {
     return await request.download({ url: `/rq/iot-measure-cert/export-excel`, params })
+  },
+  // 统计
+  getIotMeasureCertStatistics: async (id) => {
+    return await request.get({ url: `/rq/iot-measure-cert/stat?deptId=${id}` })
   }
 }
 
@@ -289,6 +293,10 @@ export const IotHiddenApi = {
   // 整改
   rectifyHidden: async (data) => {
     return await request.put({ url: `/rq/iot-hazard/rectify`, data })
+  },
+  // 统计
+  getHiddenStatistics: async (id) => {
+    return await request.get({ url: `/rq/iot-hazard-type?deptId=${id}` })
   }
 }
 

+ 109 - 2
src/views/pms/qhse/certificate.vue

@@ -68,10 +68,32 @@
 
       <!-- 列表 -->
       <ContentWrap class="flex-1 overflow-hidden mt-15px" style="border: none">
+        <div class="stats-cards">
+          <div class="stats-card stats-card--expired">
+            <div class="stats-card__label">已过期</div>
+            <div class="stats-card__value">{{ expired }}</div>
+          </div>
+          <div class="stats-card stats-card--warn">
+            <div class="stats-card__label">60天预警</div>
+            <div class="stats-card__value">{{ warn }}</div>
+          </div>
+          <div class="stats-card stats-card--total">
+            <div class="stats-card__label">证书总数</div>
+            <div class="stats-card__value">{{ totalCert }}</div>
+          </div>
+          <div class="stats-card stats-card--personal">
+            <div class="stats-card__label">个人证书</div>
+            <div class="stats-card__value">{{ personal }}</div>
+          </div>
+          <div class="stats-card stats-card--organization">
+            <div class="stats-card__label">组织证书</div>
+            <div class="stats-card__value">{{ organization }}</div>
+          </div>
+        </div>
         <zm-table
           :loading="loading"
           :data="list"
-          height="calc(74.5vh - 220px)"
+          height="calc(62.5vh - 220px)"
           :show-overflow-tooltip="true"
           :row-style="tableRowStyle"
           :row-class-name="tableRowClassName">
@@ -322,6 +344,8 @@ import UploadImage from '@/components/UploadFile/src/QHSEUploadImgs.vue'
 import { DICT_TYPE, getStrDictOptions, getBoolDictOptions } from '@/utils/dict'
 import { defaultProps } from '@/utils/tree'
 import { selectedDeptsEmployee } from '@/api/system/user'
+import { useUserStore } from '@/store/modules/user'
+const userStore = useUserStore()
 
 defineOptions({ name: 'IotQHSECertificate' })
 
@@ -454,6 +478,7 @@ const handleExport = async () => {
 const handleDeptNodeClick = async (row) => {
   queryParams.deptId = row.id
   await getList()
+  await getStatic()
 }
 
 /** 搜索按钮操作 */
@@ -649,9 +674,31 @@ const handleDeptChange = async (value) => {
   console.log('value>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>', userList.value)
 }
 
+let totalCert = ref(0)
+let expired = ref(0)
+let warn = ref(0)
+let personal = ref(0)
+let organization = ref(0)
+async function getStatic() {
+  if (queryParams.deptId) {
+    const res = await IotMeasureCertApi.getIotMeasureCertStatistics(queryParams.deptId)
+    totalCert.value = res.total
+    expired.value = res.expired
+    warn.value = res.warn
+    personal.value = res.personal
+    organization.value = res.organization
+  } else {
+    const res = await IotMeasureCertApi.getIotMeasureCertStatistics(userStore.user.deptId)
+    totalCert.value = res.total
+    expired.value = res.expired
+    warn.value = res.warn
+    personal.value = res.personal
+    organization.value = res.organization
+  }
+}
 onMounted(async () => {
   getList()
-
+  getStatic()
   deptList.value = handleTree(await DeptApi.getSimpleDeptList())
   deptList2.value = handleTree(await DeptApi.getSimpleDeptList())
 })
@@ -665,6 +712,66 @@ onMounted(async () => {
   height: 700px !important;
 }
 
+.stats-cards {
+  display: grid;
+  grid-template-columns: repeat(5, minmax(0, 1fr));
+  gap: 12px;
+  margin-bottom: 16px;
+}
+
+.stats-card {
+  padding: 14px 16px;
+  background: linear-gradient(180deg, #ffffff 0%, #f7faff 100%);
+  border: 1px solid #e4ecf7;
+  border-radius: 10px;
+  box-shadow: 0 4px 12px rgb(31 91 184 / 8%);
+}
+
+.stats-card__label {
+  font-size: 14px;
+  font-weight: 600;
+  color: #6b7280;
+  line-height: 1.4;
+}
+
+.stats-card__value {
+  margin-top: 8px;
+  font-size: 28px;
+  font-weight: 700;
+  line-height: 1;
+  color: #1f5bb8;
+}
+
+.stats-card--expired {
+  background: linear-gradient(180deg, #fff4f4 0%, #ffe8e8 100%);
+  border-color: #ffcfcf;
+}
+
+.stats-card--expired .stats-card__value {
+  color: #de3b3b;
+}
+
+.stats-card--warn {
+  background: linear-gradient(180deg, #fff8ef 0%, #ffeed9 100%);
+  border-color: #ffd7a1;
+}
+
+.stats-card--warn .stats-card__value {
+  color: #d97706;
+}
+
+.stats-card--total .stats-card__value {
+  color: #2563eb;
+}
+
+.stats-card--personal .stats-card__value {
+  color: #16a34a;
+}
+
+.stats-card--organization .stats-card__value {
+  color: #7c3aed;
+}
+
 /* 过期行的红色背景 - 基础状态 */
 :deep(.el-table__body tr.expired-row > td.el-table__cell) {
   background-color: #ffe6e6 !important;