From d5e65bf5925c8cd1fe0f0bf0b8b857006d64ad94 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期五, 30 一月 2026 15:26:34 +0800
Subject: [PATCH] 进销存升级 1.部分输入框(有效日期、检定周期)输入做下限制(大于0的整数数字)

---
 src/views/financialManagement/accounting/index.vue |  666 +++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 430 insertions(+), 236 deletions(-)

diff --git a/src/views/financialManagement/accounting/index.vue b/src/views/financialManagement/accounting/index.vue
index 91588fd..830fe1a 100644
--- a/src/views/financialManagement/accounting/index.vue
+++ b/src/views/financialManagement/accounting/index.vue
@@ -1,120 +1,179 @@
 <template>
   <div style="padding: 20px;">
     <!-- 椤甸潰鏍囬鍜岀瓫閫夋潯浠� -->
-    <div class="w-full md:w-auto flex items-center gap-3" style="margin-bottom: 20px;">
-      <el-button
-        type="primary"
-        icon="Refresh"
-        @click="resetFilters"
-        size="default"
-      >
-        鏌ヨ
-      </el-button>
+    <div class="w-full md:w-auto flex items-center gap-3">
+      <el-form :inline="true">
+        <el-form-item label="骞翠唤">
+          <el-date-picker
+            v-model="selectedYear"
+            type="year"
+            placeholder="璇烽�夋嫨骞翠唤"
+            format="YYYY"
+            value-format="YYYY"
+            clearable
+            @change="fetchData()"
+            style="width: 200px"
+            :disabled-date="(date) => date.getFullYear() > new Date().getFullYear()"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button
+            type="primary"
+            icon="Refresh"
+            @click="resetFilters"
+            size="default"
+          >
+            閲嶇疆
+          </el-button>
+        </el-form-item>
+      </el-form>
     </div>
 
     <main class="container mx-auto px-4 pb-10">
       <!-- 鍥哄畾璧勪骇鎸囨爣鍗$墖 -->
-      <div class="grid-container">
+      <div class="kpi-grid">
         <!-- 璁惧鎬绘暟 -->
-        <el-card class="bg2">
-          <p>璁惧鎬绘暟</p>
-          <h3>
-            {{ assetInfo.totalEquipment }}
-          </h3>
-        </el-card>
+        <div class="kpi-card">
+          <div class="kpi-left">
+            <span class="kpi-dot kpi-dot-blue"></span>
+            <span class="kpi-title">璁惧鎬绘暟</span>
+            <div class="kpi-value">{{ assetInfo.totalEquipment }}涓�</div>
+          </div>
+          <div class="kpi-icon-wrap kpi-icon-blue">
+            <img :src="iconBlue" alt="" class="kpi-icon" />
+          </div>
+        </div>
 
         <!-- 璧勪骇鍘熷�� -->
-        <el-card class="bg3">
-          <p>璧勪骇鍘熷��</p>
-          <h3>
-            楼{{ assetInfo.totalOriginalValue }}
-          </h3>
-        </el-card>
+        <div class="kpi-card">
+          <div class="kpi-left">
+            <span class="kpi-dot kpi-dot-orange"></span>
+            <span class="kpi-title">璧勪骇鍘熷��</span>
+            <div class="kpi-value">楼{{ formatCurrency(assetInfo.totalOriginalValue) }}</div>
+          </div>
+          <div class="kpi-icon-wrap kpi-icon-orange">
+            <img :src="iconWalletOrange" alt="" class="kpi-icon" />
+          </div>
+        </div>
 
         <!-- 绱鎶樻棫 -->
-        <el-card class="bg4">
-          <p>绱鎶樻棫</p>
-          <h3>
-            楼{{ assetInfo.totalDepreciation }}
-          </h3>
-        </el-card>
+        <div class="kpi-card">
+          <div class="kpi-left">
+            <span class="kpi-dot kpi-dot-green"></span>
+            <span class="kpi-title">绱鎶樻棫</span>
+            <div class="kpi-value">楼{{ formatCurrency(assetInfo.totalDepreciation) }}</div>
+          </div>
+          <div class="kpi-icon-wrap kpi-icon-green">
+            <img :src="iconGreen" alt="" class="kpi-icon" />
+          </div>
+        </div>
+
+        <!-- 搴撳瓨璧勪骇 -->
+        <div class="kpi-card">
+          <div class="kpi-left">
+            <span class="kpi-dot kpi-dot-pink"></span>
+            <span class="kpi-title">搴撳瓨璧勪骇</span>
+            <div class="kpi-value">楼{{ formatCurrency(assetInfo.inventoryValue) }}</div>
+          </div>
+          <div class="kpi-icon-wrap kpi-icon-pink">
+            <img :src="iconPink" alt="" class="kpi-icon" />
+          </div>
+        </div>
 
         <!-- 鍑�鍊� -->
-        <el-card class="bg5">
-          <p>鍑�鍊�</p>
-          <h3>
-            楼{{ assetInfo.totalNetValue }}
-          </h3>
-        </el-card>
+        <div class="kpi-card">
+          <div class="kpi-left">
+            <span class="kpi-dot kpi-dot-yellow"></span>
+            <span class="kpi-title">鍑�鍊�</span>
+            <div class="kpi-value">楼{{ formatCurrency(assetInfo.totalNetValue) }}</div>
+          </div>
+          <div class="kpi-icon-wrap kpi-icon-yellow">
+            <img :src="iconYellow" alt="" class="kpi-icon" />
+          </div>
+        </div>
+
+        <!-- 璐熷�� -->
+        <div class="kpi-card">
+          <div class="kpi-left">
+            <span class="kpi-dot kpi-dot-red"></span>
+            <span class="kpi-title">璐熷��</span>
+            <div class="kpi-value">楼{{ formatCurrency(assetInfo.debt) }}</div>
+          </div>
+          <div class="kpi-icon-wrap kpi-icon-red">
+            <img :src="iconWalletRed" alt="" class="kpi-icon" />
+          </div>
+        </div>
       </div>
 
       <!-- 鍥哄畾璧勪骇缁熻鍥捐〃 -->
-      <div class="grid-layout">
-        <!-- 鎸夎澶囩被鍨嬬粺璁� -->
-        <el-card style="margin-bottom: 20px;">
+      <div class="chart-row">
+        <!-- 璁惧绫诲瀷鍒嗗竷 -->
+        <el-card class="chart-card">
           <h2 class="section-title">璁惧绫诲瀷鍒嗗竷</h2>
-          <div class="echarts">
-            <Echarts
+          <div class="chart-content">
+            <div class="pie-wrap">
+              <Echarts
                 :legend="typeDistributionLegend"
                 :chartStyle="chartStylePie"
                 :series="typeDistributionSeries"
                 :tooltip="pieTooltip"
-                style="height: 260px; width: 35%;">
-              <div class="chart-num">
-                <span style="font-size: 22px;">璁惧绫诲瀷</span>
-                <span style="font-size: 36px; font-weight: 500; font-family: 'MyCustomFont', sans-serif;">{{ assetInfo.totalEquipment }}</span>
+                style="height: 260px; width: 100%;"
+              />
+            </div>
+            <div class="type-cards">
+              <div class="type-card" v-for="(item, index) in typeDistributionData" :key="index">
+                <span class="type-name">{{ item.name }}</span>
+                <span class="type-count">{{ item.count }}</span>
               </div>
-            </Echarts>
+            </div>
+          </div>
+        </el-card>
+        <!-- 璁惧閲戦鍒嗘瀽 -->
+        <el-card class="chart-card">
+          <h2 class="section-title">璁惧閲戦鍒嗘瀽</h2>
+          <div class="bar-chart-wrap">
             <Echarts
-                ref="chart"
-                :chartStyle="chartStyle"
-                :grid="grid"
-                :legend="lineLegend"
-                :series="typeDistributionLineSeries"
-                :tooltip="tooltip"
-                :xAxis="xAxis"
-                :yAxis="yAxis"
-                style="height: 260px; width: 64%;"></Echarts>
+              ref="barChart"
+              :chartStyle="chartStyle"
+              :grid="grid"
+              :legend="lineLegend"
+              :series="typeDistributionBarSeries"
+              :tooltip="tooltip"
+              :xAxis="xAxis"
+              :yAxis="yAxisBar"
+              style="height: 260px; width: 100%;"
+            />
           </div>
         </el-card>
       </div>
-      <!-- 璁惧鍙拌处琛ㄦ牸 -->
-      <el-card style="margin-bottom: 20px;">
+      <!-- 璁惧鏁版嵁琛� -->
+      <el-card class="table-card">
+        <h2 class="section-title">璁惧鏁版嵁琛�</h2>
         <el-table
           :data="equipmentList"
           stripe
           style="width: 100%"
           :header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
         >
-          <el-table-column prop="id" label="璧勪骇缂栧彿" width="120" />
+          <el-table-column type="index" label="搴忓彿" width="60" :index="(index) => (pagination.currentPage - 1) * pagination.pageSize + index + 1" />
           <el-table-column prop="deviceName" label="璁惧鍚嶇О" width="250" />
-          <el-table-column prop="deviceModel" label="鍨嬪彿瑙勬牸" min-width="150" />
+          <el-table-column prop="deviceModel" label="瑙勬牸鍨嬪彿" min-width="150" />
           <el-table-column prop="supplierName" label="渚涘簲鍟�" min-width="120" />
           <el-table-column prop="unit" label="鍗曚綅" width="120" />
           <el-table-column prop="number" label="鏁伴噺" width="120" />
           <el-table-column prop="originalValue" label="鍘熷��(鍏�)" width="120">
             <template #default="{ row }">
-              楼{{ formatCurrency(row.taxIncludingPriceTotal) }}
+              {{ formatCurrency(row.taxIncludingPriceTotal) }}
             </template>
           </el-table-column>
           <el-table-column prop="depreciation" label="绱鎶樻棫(鍏�)" width="140">
             <template #default="{ row }">
-              楼{{ formatCurrency(row.taxIncludingPriceTotal-row.unTaxIncludingPriceTotal) }}
+              {{ formatCurrency(row.deprAmount) }}
             </template>
           </el-table-column>
           <el-table-column prop="netValue" label="鍑�鍊�(鍏�)" width="120">
             <template #default="{ row }">
-              楼{{ formatCurrency(row.unTaxIncludingPriceTotal) }}
-            </template>
-          </el-table-column>
-          <el-table-column prop="status" label="鐘舵��" width="100">
-            <template #default="{ row }">
-              <el-tag
-                :type="getStatusTagType(row.status)"
-                size="small"
-              >
-                {{ row.status }}
-              </el-tag>
+              {{ formatCurrency(row.netValue) }}
             </template>
           </el-table-column>
         </el-table>
@@ -141,21 +200,33 @@
 import { ref, computed, onMounted, reactive } from 'vue';
 import 'element-plus/dist/index.css';
 import Echarts from "@/components/Echarts/echarts.vue";
-import { getLedgerPage } from "@/api/equipmentManagement/ledger";
+import { getAccountingTotal, getDeviceTypeDistribution, getCalculateDepreciation } from "@/api/financialManagement/accounting";
 import dayjs from "dayjs";
+import iconBlue from '@/assets/icons/png/blue@2x.png';
+import iconWalletOrange from '@/assets/icons/png/walletOrange@2x.png';
+import iconGreen from '@/assets/icons/png/green@2x.png';
+import iconPink from '@/assets/icons/png/pink@2x.png';
+import iconYellow from '@/assets/icons/png/yellow@2x.png';
+import iconWalletRed from '@/assets/icons/png/walletRed@2x.png';
 
 // 绛涢�夋潯浠�
 const dateRange = ref(null);
 const equipmentType = ref('');
+const selectedYear = ref(dayjs().format('YYYY')); // 榛樿褰撳墠骞翠唤
 
 
 // 鍥哄畾璧勪骇淇℃伅
 const assetInfo = ref({
-  totalEquipment: 0,
-  totalOriginalValue: 0,
-  totalDepreciation: 0,
-  totalNetValue: 0
+  totalEquipment: 0, // deviceTotal
+  totalOriginalValue: 0, // deviceAmount
+  totalDepreciation: 0, // deprAmount
+  totalNetValue: 0, // netValue
+  debt: 0, // 璐熷��
+  inventoryValue: 0 // 搴撳瓨璧勪骇
 });
+
+// 璁惧绫诲瀷鎬绘暟锛堢敤浜庡浘琛ㄦ樉绀猴級
+const deviceTypeTotalCount = ref(0);
 
 // 璁惧鍒楄〃
 const equipmentList = ref([]);
@@ -231,30 +302,16 @@
   height: '100%' // 璁剧疆鍥捐〃瀹瑰櫒鐨勯珮搴�
 };
 
-const pieColors = ['#F04864', '#FACC14', '#8543E0', '#1890FF', '#13C2C2', '#2FC25B']; // 鍙牴鎹疄闄呰皟鏁�
+const pieColors = ['#165DFF', '#14C9C9', '#8543E0', '#1890FF', '#13C2C2', '#2FC25B']; // 鍙牴鎹疄闄呰皟鏁�
 
 // 楗煎浘鏁版嵁
 const typeDistributionData = ref([]);
 const departmentDistributionData = ref([]);
 
-// 楗煎浘鍥句緥
+// 楗煎浘鍥句緥锛堟偓鍋滄樉绀哄悕绉�+鍗犳瘮锛屽浘渚嬫斁涓嬫柟鍗$墖灞曠ず锛�
 const typeDistributionLegend = computed(() => ({
-  show: true,
-  top: 'center',
-  left: '60%',
-  orient: 'vertical',
-  icon: 'circle',
-  data: typeDistributionData.value.map(item => item.name),
-  formatter: function(name) {
-    const item = typeDistributionData.value.find(i => i.name === name);
-    if (!item) return name;
-    return `${name} | ${item.count} 鍙� | ${item.amount}`;
-  },
-  textStyle: {
-    color: '#333',
-    fontSize: 14,
-    lineHeight: 26,
-  }
+  show: false,
+  data: typeDistributionData.value.map(item => item.name)
 }));
 
 
@@ -262,16 +319,14 @@
 const typeDistributionSeries = computed(() => [
   {
     type: 'pie',
-    radius: ['50%', '65%'],
-    center: ['25%', '50%'],
+    radius: ['0%', '65%'],
+    center: ['50%', '45%'],
     avoidLabelOverlap: false,
     itemStyle: {
       borderColor: '#fff',
       borderWidth: 2
     },
-    label: {
-      show: false
-    },
+    label: { show: false },
     data: typeDistributionData.value,
     color: pieColors
   }
@@ -279,23 +334,35 @@
 
 // 鎶樼嚎鍥炬暟鎹�
 const typeDistributionLineSeries = ref([]);
+// 鏌辩姸鍥炬暟鎹紙璁惧閲戦鍒嗘瀽锛�
+const typeDistributionBarSeries = computed(() => [
+  {
+    name: '閿�鍞',
+    type: 'bar',
+    data: typeDistributionData.value.map(item => (item.amountNum != null ? item.amountNum : 0)),
+    itemStyle: { color: '#13C2C2' }
+  }
+]);
+// 鏌辩姸鍥� Y 杞�
+const yAxisBar = [
+  {
+    type: 'value',
+    name: '閿�鍞(涓囧厓)',
+    position: 'left',
+    min: 0,
+    nameTextStyle: { color: '#000', fontSize: 14 },
+    splitLine: { lineStyle: { color: '#f0f0f0' } }
+  }
+];
 
 
-// 楗煎浘鎻愮ず妗�
+// 楗煎浘鎻愮ず妗嗭紙鍥惧唴鏍峰紡锛氬悕绉� + 鍗犳瘮锛�
 const pieTooltip = reactive({
   trigger: 'item',
   formatter: function(params) {
-    // 妫�鏌ユ暟鎹槸鍚﹀瓨鍦�
     if (!params.data) return params.name;
-    // 鎷兼帴瀹屾暣鍐呭
-    return `
-      <div>
-        <div style="color:${params.color};font-size:16px;">鈼�</div>
-        <div>${params.name}</div>
-        <div>鏁伴噺锛�${params.data.count} 鍙�</div>
-        <div>閲戦锛�${params.data.amount}</div>
-      </div>
-    `;
+    const pct = params.percent != null ? params.percent.toFixed(0) : 0;
+    return `${params.name} ${pct}%`;
   }
 });
 
@@ -306,63 +373,98 @@
 const fetchData = async () => {
   try {
     // 鑾峰彇鍥哄畾璧勪骇姹囨�讳俊鎭�
-    const assetInfoRes = await getAssetInfo({
+    const assetInfoRes = await getAccountingTotal({
       startDate: dateRange.value ? dateRange.value[0] : null,
       endDate: dateRange.value ? dateRange.value[1] : null,
-      equipmentType: equipmentType.value
+      equipmentType: equipmentType.value,
+      year: selectedYear.value
     });
 
     if (assetInfoRes.code === 200) {
-      assetInfo.value = assetInfoRes.data;
+      // 鏄犲皠鍚庣瀛楁鍒板墠绔瓧娈�
+      const data = assetInfoRes.data;
+      assetInfo.value = {
+        totalEquipment: data.deviceTotal || 0, // 璁惧鎬绘暟
+        totalOriginalValue: data.deviceAmount || 0, // 璧勪骇鍘熷��
+        totalDepreciation: data.deprAmount || 0, // 绱鎶樻棫
+        totalNetValue: data.netValue || 0, // 鍑�鍊�
+        debt: data.debt || 0, // 璐熷��
+        inventoryValue: data.inventoryValue || 0 // 搴撳瓨璧勪骇
+      };
     }
 
-    // 鑾峰彇璁惧鍒楄〃
-    const equipmentListRes = await getLedgerPage({
-      current: pagination.value.currentPage,
-      size: pagination.value.pageSize,
+    // 鑾峰彇璁惧绫诲瀷鍒嗗竷鏁版嵁锛堥ゼ鍥惧拰鎶樼嚎鍥撅級
+    const distributionRes = await getDeviceTypeDistribution({
       startDate: dateRange.value ? dateRange.value[0] : null,
       endDate: dateRange.value ? dateRange.value[1] : null,
-      equipmentType: equipmentType.value
+      equipmentType: equipmentType.value,
+      year: selectedYear.value
     });
 
-    if (equipmentListRes.code === 200) {
-      equipmentList.value = equipmentListRes.data.records;
-      pagination.value.total = equipmentListRes.data.total;
-
-      // 鏍规嵁 equipmentList 鎸� deviceName 杩涜鍒嗙被缁熻
-      const deviceNameMap = {};
-      equipmentList.value.forEach(item => {
-        const deviceName = item.deviceName;
-        if (!deviceNameMap[deviceName]) {
-          deviceNameMap[deviceName] = {
-            name: deviceName,
-            count: 0,
-            totalValue: 0
-          };
-        }
-        deviceNameMap[deviceName].count += item.number || 1; // 鍋囪 number 涓鸿澶囨暟閲�
-        deviceNameMap[deviceName].totalValue += item.taxIncludingPriceTotal || 0; // 绱姞鍚◣鎬讳环
-      });
-
-      // 杞崲涓� typeDistributionData 鏍煎紡
-      typeDistributionData.value = Object.values(deviceNameMap).map(item => ({
-        name: item.name,
-        value: item.count,
-        count: item.count,
-        amount: `楼${formatCurrency(item.totalValue)}`
-      }));
+    if (distributionRes.code === 200) {
+      const data = distributionRes.data;
+      
+      // 鏇存柊璁惧绫诲瀷鎬绘暟
+      deviceTypeTotalCount.value = data.totalCount || 0;
+      
+      // 杞崲楗煎浘鏁版嵁鏍煎紡
+      if (data.details && data.details.length > 0) {
+        typeDistributionData.value = data.details.map(item => ({
+          name: item.type || '',
+          value: Number(item.count || 0),
+          count: Number(item.count || 0),
+          amount: `楼${formatCurrency(item.amount || 0)}`,
+          amountNum: Number(item.amount || 0)
+        }));
+      } else if (data.categories && data.categories.length > 0) {
+        // 濡傛灉娌℃湁 details锛屼娇鐢� categories銆乧ountData 鍜� amountData 鏋勫缓
+        typeDistributionData.value = data.categories.map((category, index) => ({
+          name: category,
+          value: Number(data.countData[index] || 0),
+          count: Number(data.countData[index] || 0),
+          amount: `楼${formatCurrency(data.amountData[index] || 0)}`,
+          amountNum: Number(data.amountData[index] || 0)
+        }));
+      } else {
+        typeDistributionData.value = [];
+      }
 
       // 鏇存柊x杞存暟鎹�
-      xAxis.value[0].data = typeDistributionData.value.map(item => item.name);
+      xAxis.value[0].data = data.categories || typeDistributionData.value.map(item => item.name);
 
       // 鏋勫缓鎶樼嚎鍥炬暟鎹�
       typeDistributionLineSeries.value = [
         {
           name: '璁惧鏁伴噺',
           type: 'line',
-          data: typeDistributionData.value.map(item => item.count)
+          data: data.countData || typeDistributionData.value.map(item => item.count)
         }
       ];
+    }
+
+    // 鑾峰彇璁惧鍒楄〃锛堟姌鏃ц绠楁暟鎹級
+    const equipmentListRes = await getCalculateDepreciation({
+      current: pagination.value.currentPage,
+      size: pagination.value.pageSize,
+      startDate: dateRange.value ? dateRange.value[0] : null,
+      endDate: dateRange.value ? dateRange.value[1] : null,
+      equipmentType: equipmentType.value,
+      year: selectedYear.value
+    });
+
+    if (equipmentListRes.code === 200) {
+      // 濡傛灉杩斿洖鐨勬槸鍒嗛〉鏁版嵁
+      if (equipmentListRes.data.records) {
+        equipmentList.value = equipmentListRes.data.records;
+        pagination.value.total = equipmentListRes.data.total;
+      } else if (Array.isArray(equipmentListRes.data)) {
+        // 濡傛灉杩斿洖鐨勬槸鏁扮粍
+        equipmentList.value = equipmentListRes.data;
+        pagination.value.total = equipmentListRes.data.length;
+      } else {
+        equipmentList.value = [];
+        pagination.value.total = 0;
+      }
     }
   } catch (error) {
     console.error('鑾峰彇鍥哄畾璧勪骇鏁版嵁澶辫触锛�', error);
@@ -401,6 +503,7 @@
 const resetFilters = () => {
   dateRange.value = null;
   equipmentType.value = '';
+  selectedYear.value = dayjs().format('YYYY'); // 閲嶇疆涓哄綋鍓嶅勾浠�
   fetchData();
 };
 
@@ -417,131 +520,222 @@
 </script>
 
 <style scoped lang="scss">
-/* 鍩虹鏍峰紡琛ュ厖 */
 :root {
-  --el-color-primary: #4f46e5;
+  --el-color-primary: #1890ff;
 }
 
-.el-card {
-  position: relative;
-  border-radius: 12px;
-  padding: 14px 10px 10px 10px;
-  box-shadow: 0 2px 8px #eee;
+/* 椤甸潰鑳屾櫙 */
+main {
+  background: #f5f5f5;
+  padding: 0;
+  margin: 0 -20px;
+  padding: 0 20px 20px;
+}
+
+/* KPI 鍗$墖缃戞牸 */
+.kpi-grid {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  gap: 16px;
+  margin-bottom: 20px;
+}
+
+@media (max-width: 1024px) {
+  .kpi-grid {
+    grid-template-columns: repeat(2, 1fr);
+  }
+}
+
+@media (max-width: 640px) {
+  .kpi-grid {
+    grid-template-columns: 1fr;
+  }
+}
+
+/* KPI 鍗$墖 - 鐧藉簳銆佸渾瑙掋�侀槾褰� */
+.kpi-card {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  background: #fff;
+  border-radius: 8px;
+  padding: 16px 20px;
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
+  min-height: 100px;
+}
+
+.kpi-left {
+  flex: 1;
+  min-width: 0;
+}
+
+.kpi-dot {
+  display: inline-block;
+  width: 8px;
+  height: 8px;
+  border-radius: 50%;
+  margin-right: 6px;
+  vertical-align: middle;
+}
+
+.kpi-dot-blue { background: #1890ff; }
+.kpi-dot-orange { background: #fa8c16; }
+.kpi-dot-green { background: #52c41a; }
+.kpi-dot-pink { background: #eb2f96; }
+.kpi-dot-yellow { background: #facc14; }
+.kpi-dot-red { background: #f5222d; }
+
+.kpi-title {
+  font-size: 14px;
+  color: #333;
+  vertical-align: middle;
+}
+
+.kpi-value {
+  font-size: 24px;
+  font-weight: 600;
+  color: #333;
+  margin-top: 8px;
+  line-height: 1.2;
+}
+
+/* 鍙充晶鍥炬爣鏂瑰潡 */
+.kpi-icon-wrap {
+  width: 48px;
+  height: 48px;
+  border-radius: 8px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+}
+
+.kpi-icon-blue { background: #e6f7ff; }
+.kpi-icon-orange { background: #fff7e6; }
+.kpi-icon-green { background: #f6ffed; }
+.kpi-icon-pink { background: #fff0f6; }
+.kpi-icon-yellow { background: #fffbe6; }
+.kpi-icon-red { background: #fff1f0; }
+
+.kpi-icon {
+  width: 28px;
+  height: 28px;
+  object-fit: contain;
+}
+
+/* 鍥捐〃鍖哄煙涓ゅ垪 */
+.chart-row {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 20px;
+  margin-bottom: 20px;
+}
+
+@media (max-width: 1024px) {
+  .chart-row {
+    grid-template-columns: 1fr;
+  }
+}
+
+.chart-card {
+  border-radius: 8px;
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
 
   :deep(.el-card__body) {
-    padding: 10px 20px !important;
-  }
-
-  &.bg1 {
-    background: url(@/assets/icons/png/1.png) no-repeat 100% 100% !important;
-  }
-
-  &.bg2 {
-    background: url(@/assets/icons/png/2.png) no-repeat 100% 100% !important;
-  }
-
-  &.bg3 {
-    background: url(@/assets/icons/png/3.png) no-repeat 100% 100% !important;
-  }
-
-  &.bg4 {
-    background: url(@/assets/icons/png/4.png) no-repeat 100% 100% !important;
-  }
-
-  &.bg5 {
-    background: url(@/assets/icons/png/5.png) no-repeat 100% 100% !important;
+    padding: 16px 20px;
   }
 }
 
-.grid-container {
-  /* grid 瀹瑰櫒鍩虹鏍峰紡 */
-  display: grid;
-  gap: 1rem; /* gap-4 瀵瑰簲 1rem (16px) */
-  margin-bottom: 2rem; /* mb-8 瀵瑰簲 2rem (32px) */
-
-  p {
-    font-size: 22px;
-    margin-top: 0px;
-    color: #fff;
-  }
-
-  h3 {
-    font-size: 36px;
-    font-weight: 500;
-    font-family: 'MyCustomFont', sans-serif;
-    margin: 10px 0;
-    color: #fff;
-  }
-}
-
-/* 绉诲姩绔粯璁ゆ牱寮� (grid-cols-1) */
-.grid-container {
-  grid-template-columns: repeat(1, minmax(0, 1fr));
-}
-
-/* 灏忓睆骞曞強浠ヤ笂 (sm:grid-cols-2) */
-@media (min-width: 640px) {
-  .grid-container {
-    grid-template-columns: repeat(2, minmax(0, 1fr));
-  }
-}
-
-/* 澶у睆骞曞強浠ヤ笂 (lg:grid-cols-5) */
-@media (min-width: 1024px) {
-  .grid-container {
-    grid-template-columns: repeat(5, minmax(0, 1fr));
-  }
-}
-
-/* 鍗$墖鎮仠鏁堟灉澧炲己 */
-.el-card:hover {
-  transform: translateY(-2px);
-}
-
-.echarts {
+.chart-content {
   display: flex;
-  justify-content: space-between;
+  flex-direction: column;
+  align-items: center;
 }
 
-/* 鍥捐〃瀹瑰櫒鏍峰紡 */
-.el-chart {
+.pie-wrap {
+  position: relative;
   width: 100%;
-  height: 100%;
+  height: 260px;
 }
 
+.type-cards {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 12px;
+  justify-content: center;
+  margin-top: 12px;
+}
+
+.type-card {
+  background: #fafafa;
+  border-radius: 6px;
+  padding: 8px 16px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  min-width: 80px;
+}
+
+.type-name {
+  font-size: 12px;
+  color: #666;
+}
+
+.type-count {
+  font-size: 16px;
+  font-weight: 600;
+  color: #333;
+  margin-top: 4px;
+}
+
+.bar-chart-wrap {
+  width: 100%;
+  height: 260px;
+}
+
+/* 鍖哄潡鏍囬 - 宸︿晶钃濊壊绔栫嚎 */
 .section-title {
   position: relative;
   font-size: 18px;
   color: #333;
-  padding-left: 10px;
-  margin-bottom: 10px;
+  padding-left: 12px;
+  margin-bottom: 16px;
   font-weight: 700;
 }
 
 .section-title::before {
   position: absolute;
   left: 0;
-  top: 0px;
+  top: 2px;
   content: '';
   width: 4px;
   height: 18px;
-  background-color: #002FA7;
+  background: #1890ff;
   border-radius: 2px;
 }
 
-.chart-num {
-  position: absolute;
-  z-index: 3;
-  top: 92px;
-  left: 92px;
-  display: flex;
-  flex-direction: column;
-  justify-content: center;
+/* 琛ㄦ牸鍗$墖 */
+.table-card {
+  border-radius: 8px;
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
+
+  :deep(.el-card__body) {
+    padding: 16px 20px;
+  }
 }
 
 .pagination-container {
   margin-top: 20px;
   display: flex;
-  justify-content: center;
+  justify-content: flex-end;
+  align-items: center;
+}
+
+:deep(.el-pagination) {
+  --el-pagination-button-bg-color: #fff;
+}
+
+:deep(.el-pager li.is-active) {
+  background: #1890ff;
 }
 </style>

--
Gitblit v1.9.3