yanghao 1 周之前
父节点
当前提交
c12d5c9394
共有 1 个文件被更改,包括 149 次插入53 次删除
  1. 149 53
      src/views/pms/qhse/safety/index.vue

+ 149 - 53
src/views/pms/qhse/safety/index.vue

@@ -58,23 +58,15 @@
       <!-- 列表 -->
       <ContentWrap class="flex-1 overflow-hidden mt-15px" style="border: none">
         <div class="stats-cards">
-          <div class="stats-card">
-            <div
-              class="stats-card__decor stats-card__decor--left"
-              :style="{
-                background:
-                  'radial-gradient(circle, rgba(61, 124, 255, 0.2) 0%, rgba(61, 124, 255, 0) 72%)'
-              }"></div>
-            <div class="stats-card__decor stats-card__decor--right"></div>
+          <div
+            class="stats-card"
+            style="background: linear-gradient(180deg, #fff 0%, #e8f2ff 100%)">
             <div class="stats-card__header">
-              <div class="stats-card__icon-wrap">
-                <div class="stats-card__icon">
-                  <Icon icon="eos-icons:counting" color="#2563eb" />
-                </div>
-              </div>
+              <Icon icon="eos-icons:counting" color="#2563eb" />
+
               <div class="stats-card__title">隐患总数</div>
             </div>
-            <div class="stats-card__body">
+            <div class="stats-card__body py-8">
               <CountTo
                 :duration="2600"
                 :end-val="hiddenCount"
@@ -83,23 +75,14 @@
             </div>
           </div>
 
-          <div class="stats-card">
-            <div
-              class="stats-card__decor stats-card__decor--left"
-              :style="{
-                background:
-                  'radial-gradient(circle, rgba(255, 91, 97, 0.22) 0%, rgba(255, 91, 97, 0) 72%)'
-              }"></div>
-            <div class="stats-card__decor stats-card__decor--right"></div>
+          <div
+            class="stats-card"
+            style="background: linear-gradient(180deg, #fff4f4 0%, #ffe8e8 100%)">
             <div class="stats-card__header">
-              <div class="stats-card__icon-wrap">
-                <div class="stats-card__icon" :style="{ color: '#ff5b61' }">
-                  <Icon icon="ep:info-filled" color="#de3b3b" />
-                </div>
-              </div>
+              <Icon icon="ep:info-filled" color="#de3b3b" />
               <div class="stats-card__title">未整改数</div>
             </div>
-            <div class="stats-card__body">
+            <div class="stats-card__body py-8">
               <CountTo
                 :duration="2600"
                 :end-val="todo"
@@ -108,26 +91,31 @@
             </div>
           </div>
 
-          <div class="stats-card">
-            <div class="stats-card__decor stats-card__decor--left"></div>
-            <div class="stats-card__decor stats-card__decor--right"></div>
+          <div
+            class="stats-card"
+            style="background: linear-gradient(180deg, #fff 0%, #e8f2ff 100%)">
             <div class="stats-card__header">
-              <div class="stats-card__icon-wrap">
-                <div class="stats-card__icon">
-                  <Icon icon="ep:info-filled" color="#de3b3b" />
-                </div>
-              </div>
+              <Icon icon="material-symbols:android-cell-4-bar" color="#2563eb" />
+
               <div class="stats-card__title">整改率</div>
             </div>
-            <div class="stats-card__body">
+            <div class="stats-card__body py-8">
               <CountTo
                 :duration="2600"
-                :end-val="((hiddenCount - todo) / hiddenCount) * 100"
+                :end-val="((hiddenCount - todo) / hiddenCount) * 100 || 0"
                 :start-val="0"
                 class="stats-card__count text-2xl text-center! text-[#2563eb]!" />
               <span class="text-[#2563eb]!">%</span>
             </div>
           </div>
+
+          <!-- 饼图 -->
+          <div
+            class="stats-card pie-chart-card"
+            style="background: linear-gradient(180deg, #fff 0%, #e8f2ff 100%)">
+            <div class="pie-chart-title">隐患来源分布</div>
+            <div ref="pieChartRef" class="pie-chart-container"></div>
+          </div>
         </div>
         <zm-table
           :loading="loading"
@@ -371,6 +359,7 @@
 </template>
 
 <script setup lang="ts">
+import { ref, reactive, watch, nextTick } from 'vue'
 import { IotHiddenApi, IotHiddenTypeApi } from '@/api/pms/qhse/index'
 import DeptTree from '@/views/system/user/DeptTree2.vue'
 
@@ -390,6 +379,13 @@ const userStore = useUserStore()
 import { useTableComponents } from '@/components/ZmTable/useTableComponents'
 const { ZmTable, ZmTableColumn } = useTableComponents()
 
+import * as echarts from 'echarts/core'
+import { PieChart } from 'echarts/charts'
+import { TooltipComponent, LegendComponent } from 'echarts/components'
+import { CanvasRenderer } from 'echarts/renderers'
+
+echarts.use([TooltipComponent, LegendComponent, PieChart, CanvasRenderer])
+
 defineOptions({ name: 'IotQHSECertificate' })
 
 const loading = ref(true) // 列表的加载中
@@ -704,6 +700,8 @@ const getTree = async () => {
 let hiddenCount = ref(0)
 let todo = ref(0)
 let source = ref('')
+const pieChartRef = ref<HTMLDivElement>()
+let pieChart: echarts.ECharts | null = null
 async function getStatic() {
   if (queryParams.deptId) {
     const res = await IotHiddenApi.getHiddenStatistics(queryParams.deptId)
@@ -716,6 +714,71 @@ async function getStatic() {
     todo.value = res.todo
     source.value = res.source
   }
+
+  nextTick(() => {
+    initPieChart()
+  })
+}
+
+const initPieChart = () => {
+  if (!pieChartRef.value) return
+
+  if (pieChart) {
+    pieChart.dispose()
+  }
+
+  pieChart = echarts.init(pieChartRef.value)
+
+  const chartData = Array.isArray(source.value)
+    ? source.value.map((item: any) => ({
+        name: item.classify || '未知',
+        value: item.count || 0
+      }))
+    : []
+
+  const option = {
+    tooltip: {
+      trigger: 'item',
+      formatter: '{b}: {c} ({d}%)'
+    },
+    legend: {
+      orient: 'vertical',
+      left: 'left',
+      top: 'middle',
+      textStyle: {
+        fontSize: 11
+      },
+      itemWidth: 10,
+      itemHeight: 10
+    },
+    series: [
+      {
+        name: '隐患来源',
+        type: 'pie',
+        radius: ['35%', '60%'],
+        center: ['58%', '50%'],
+        avoidLabelOverlap: false,
+        itemStyle: {
+          borderRadius: 6,
+          borderColor: '#fff',
+          borderWidth: 2
+        },
+        label: {
+          show: false
+        },
+        emphasis: {
+          label: {
+            show: true,
+            fontSize: 12,
+            fontWeight: 'bold'
+          }
+        },
+        data: chartData
+      }
+    ]
+  }
+
+  pieChart.setOption(option)
 }
 onMounted(async () => {
   getList()
@@ -723,6 +786,23 @@ onMounted(async () => {
 
   getStatic()
 })
+
+onUnmounted(() => {
+  if (pieChart) {
+    pieChart.dispose()
+    pieChart = null
+  }
+})
+
+watch(
+  () => source.value,
+  () => {
+    nextTick(() => {
+      initPieChart()
+    })
+  },
+  { deep: true }
+)
 </script>
 
 <style scoped>
@@ -748,20 +828,12 @@ onMounted(async () => {
 .stats-card {
   position: relative;
   overflow: hidden;
-  min-height: 132px;
-  padding: 18px 18px 16px;
-  border-radius: 22px;
-  background: radial-gradient(
-      circle at 18% 22%,
-      rgb(255 255 255 / 92%) 0%,
-      rgb(255 255 255 / 0%) 20%
-    ),
-    radial-gradient(circle at 88% 80%, rgb(255 215 158 / 22%) 0%, rgb(255 215 158 / 0%) 16%),
-    linear-gradient(135deg, rgb(239 245 255 / 96%) 0%, rgb(217 230 248 / 88%) 100%);
-  border: 1px solid rgb(255 255 255 / 62%);
-  box-shadow:
-    inset 0 1px 0 rgb(255 255 255 / 86%),
-    0 14px 30px rgb(116 146 191 / 12%);
+  min-height: 100px;
+  padding: 18px 18px 0px;
+
+  border: 1px solid #e4ecf7;
+  border-radius: 10px;
+  box-shadow: 0 4px 12px rgb(31 91 184 / 8%);
 }
 
 .stats-card__decor {
@@ -834,7 +906,7 @@ onMounted(async () => {
   font-weight: 800;
   line-height: 0.92;
   letter-spacing: 1px;
-  font-style: italic;
+  /* font-style: italic; */
   text-shadow: 0 8px 18px rgb(68 110 183 / 10%);
 }
 
@@ -845,6 +917,26 @@ onMounted(async () => {
   line-height: 1;
 }
 
+.pie-chart-card {
+  display: flex;
+  flex-direction: column;
+  min-height: 180px;
+}
+
+.pie-chart-title {
+  font-size: 13px;
+  font-weight: 600;
+  color: #324b72;
+  margin-bottom: 6px;
+  text-align: center;
+}
+
+.pie-chart-container {
+  flex: 1;
+  min-height: 50px;
+  width: 100%;
+}
+
 @media (max-width: 768px) {
   .stats-cards {
     grid-template-columns: 1fr;
@@ -888,5 +980,9 @@ onMounted(async () => {
     font-size: 18px;
     padding-bottom: 6px;
   }
+
+  .pie-chart-container {
+    min-height: 220px;
+  }
 }
 </style>