From 1b736033f6d01b774d58b4c2d7cd2ce8607a44fa Mon Sep 17 00:00:00 2001
From: WXL <wl_5969728@163.com>
Date: 星期日, 28 十二月 2025 20:28:46 +0800
Subject: [PATCH] 页面完善

---
 src/views/OfficeRelated/checkingIn/components/PersonalAttendanceReport.vue |  680 +++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 522 insertions(+), 158 deletions(-)

diff --git a/src/views/OfficeRelated/checkingIn/components/PersonalAttendanceReport.vue b/src/views/OfficeRelated/checkingIn/components/PersonalAttendanceReport.vue
index 8c5d0bd..0771f71 100644
--- a/src/views/OfficeRelated/checkingIn/components/PersonalAttendanceReport.vue
+++ b/src/views/OfficeRelated/checkingIn/components/PersonalAttendanceReport.vue
@@ -12,6 +12,7 @@
           size="small"
           @click="exportReport"
           icon="el-icon-download"
+          type="primary"
         >
           瀵煎嚭鎶ヨ〃
         </el-button>
@@ -20,7 +21,7 @@
 
     <!-- 缁熻姒傝 -->
     <el-row :gutter="20" class="stats-overview">
-      <el-col :span="6">
+      <el-col :xs="12" :sm="6" class="stat-col">
         <el-card shadow="hover" class="stat-card">
           <div class="stat-content">
             <div class="stat-icon attendance-icon">
@@ -33,7 +34,7 @@
           </div>
         </el-card>
       </el-col>
-      <el-col :span="6">
+      <el-col :xs="12" :sm="6" class="stat-col">
         <el-card shadow="hover" class="stat-card">
           <div class="stat-content">
             <div class="stat-icon present-icon">
@@ -46,7 +47,7 @@
           </div>
         </el-card>
       </el-col>
-      <el-col :span="6">
+      <el-col :xs="12" :sm="6" class="stat-col">
         <el-card shadow="hover" class="stat-card">
           <div class="stat-content">
             <div class="stat-icon abnormal-icon">
@@ -59,7 +60,7 @@
           </div>
         </el-card>
       </el-col>
-      <el-col :span="6">
+      <el-col :xs="12" :sm="6" class="stat-col">
         <el-card shadow="hover" class="stat-card">
           <div class="stat-content">
             <div class="stat-icon rate-icon">
@@ -74,98 +75,150 @@
       </el-col>
     </el-row>
 
-    <!-- 鍥捐〃鍖哄煙 -->
+    <!-- 鍥捐〃鍖哄煙 - 浼樺寲甯冨眬 -->
     <el-row :gutter="20" class="charts-section">
-      <el-col :span="12">
-        <el-card header="鍑哄嫟瓒嬪娍" shadow="never">
+      <el-col :xs="24" :lg="12" class="chart-col">
+        <el-card class="chart-card" shadow="never">
+          <template #header>
+            <div class="chart-header">
+              <span class="chart-title">鍑哄嫟瓒嬪娍鍒嗘瀽</span>
+              <div class="chart-legend">
+                <span class="legend-item">
+                  <span class="legend-color bar-color"></span>
+                  鍑哄嫟澶╂暟
+                </span>
+                <span class="legend-item">
+                  <span class="legend-color line-color"></span>
+                  鍑哄嫟鐜�
+                </span>
+              </div>
+            </div>
+          </template>
           <div id="attendanceTrendChart" class="chart-container"></div>
         </el-card>
       </el-col>
-      <el-col :span="12">
-        <el-card header="鑰冨嫟鍒嗗竷" shadow="never">
+      <el-col :xs="24" :lg="12" class="chart-col">
+        <el-card class="chart-card" shadow="never">
+          <template #header>
+            <div class="chart-header">
+              <span class="chart-title">鑰冨嫟鍒嗗竷</span>
+            </div>
+          </template>
           <div id="attendanceDistributionChart" class="chart-container"></div>
         </el-card>
       </el-col>
     </el-row>
 
     <!-- 璇︾粏缁熻琛ㄦ牸 -->
-    <el-card header="璇︾粏缁熻" class="detail-table-card" shadow="never">
-      <el-table :data="detailedStats" border style="width: 100%">
-        <el-table-column prop="month" label="鏈堜唤"  />
-        <el-table-column prop="workDays" label="搴斿嚭鍕ゅぉ鏁�"  />
-        <el-table-column prop="actualDays" label="瀹為檯鍑哄嫟"  />
-        <el-table-column prop="lateTimes" label="杩熷埌娆℃暟" >
-          <template #default="scope">
-            <el-tag v-if="scope.row.lateTimes > 0" type="warning" size="small">
-              {{ scope.row.lateTimes }}
-            </el-tag>
-            <span v-else>{{ scope.row.lateTimes }}</span>
-          </template>
-        </el-table-column>
-        <el-table-column prop="leaveEarlyTimes" label="鏃╅��娆℃暟" >
-          <template #default="scope">
-            <el-tag v-if="scope.row.leaveEarlyTimes > 0" type="warning" size="small">
-              {{ scope.row.leaveEarlyTimes }}
-            </el-tag>
-            <span v-else>{{ scope.row.leaveEarlyTimes }}</span>
-          </template>
-        </el-table-column>
-        <el-table-column prop="absenceDays" label="缂哄嫟澶╂暟" >
-          <template #default="scope">
-            <el-tag v-if="scope.row.absenceDays > 0" type="danger" size="small">
-              {{ scope.row.absenceDays }}
-            </el-tag>
-            <span v-else>{{ scope.row.absenceDays }}</span>
-          </template>
-        </el-table-column>
-        <el-table-column prop="businessTripDays" label="鍑哄樊澶╂暟" >
-          <template #default="scope">
-            <el-tag v-if="scope.row.businessTripDays > 0" type="primary" size="small">
-              {{ scope.row.businessTripDays }}
-            </el-tag>
-            <span v-else>{{ scope.row.businessTripDays }}</span>
-          </template>
-        </el-table-column>
-        <el-table-column prop="attendanceRate" label="鍑哄嫟鐜�" >
-          <template #default="scope">
-            <el-progress
-              :percentage="scope.row.attendanceRate"
-              :show-text="false"
-              :color="getProgressColor(scope.row.attendanceRate)"
-            />
-            <span>{{ scope.row.attendanceRate }}%</span>
-          </template>
-        </el-table-column>
-      </el-table>
+    <el-card class="detail-card" shadow="never">
+      <template #header>
+        <div class="card-header">
+          <span class="card-title">鏈堝害璇︾粏缁熻</span>
+          <el-button size="mini" type="text" @click="toggleTableExpand">
+            {{ tableExpanded ? '鏀惰捣' : '灞曞紑' }}
+            <i :class="tableExpanded ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i>
+          </el-button>
+        </div>
+      </template>
+      <el-collapse-transition>
+        <div v-show="tableExpanded">
+          <el-table
+            :data="detailedStats"
+            border
+            style="width: 100%"
+            class="stats-table"
+            :row-class-name="getRowClassName"
+          >
+            <!-- 琛ㄦ牸鍒楀畾涔変繚鎸佷笉鍙� -->
+            <el-table-column prop="month" label="鏈堜唤" align="center" />
+            <el-table-column prop="workDays" label="搴斿嚭鍕ゅぉ鏁�" align="center" />
+            <el-table-column prop="actualDays" label="瀹為檯鍑哄嫟" align="center" />
+            <el-table-column prop="lateTimes" label="杩熷埌娆℃暟" align="center">
+              <template #default="scope">
+                <el-tag v-if="scope.row.lateTimes > 0" type="warning" size="small">
+                  {{ scope.row.lateTimes }}
+                </el-tag>
+                <span v-else>{{ scope.row.lateTimes }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="leaveEarlyTimes" label="鏃╅��娆℃暟" align="center">
+              <template #default="scope">
+                <el-tag v-if="scope.row.leaveEarlyTimes > 0" type="warning" size="small">
+                  {{ scope.row.leaveEarlyTimes }}
+                </el-tag>
+                <span v-else>{{ scope.row.leaveEarlyTimes }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="absenceDays" label="缂哄嫟澶╂暟" align="center">
+              <template #default="scope">
+                <el-tag v-if="scope.row.absenceDays > 0" type="danger" size="small">
+                  {{ scope.row.absenceDays }}
+                </el-tag>
+                <span v-else>{{ scope.row.absenceDays }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="businessTripDays" label="鍑哄樊澶╂暟" align="center">
+              <template #default="scope">
+                <el-tag v-if="scope.row.businessTripDays > 0" type="primary" size="small">
+                  {{ scope.row.businessTripDays }}
+                </el-tag>
+                <span v-else>{{ scope.row.businessTripDays }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="attendanceRate" label="鍑哄嫟鐜�" align="center" min-width="100">
+              <template #default="scope">
+                <div class="progress-cell">
+                  <el-progress
+                    :percentage="scope.row.attendanceRate"
+                    :show-text="false"
+                    :color="getProgressColor(scope.row.attendanceRate)"
+                    class="rate-progress"
+                  />
+                  <span class="rate-text" :class="getRateTextClass(scope.row.attendanceRate)">
+                    {{ scope.row.attendanceRate }}%
+                  </span>
+                </div>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+      </el-collapse-transition>
     </el-card>
 
     <!-- 寮傚父璁板綍 -->
-    <el-card header="寮傚父璁板綍" class="abnormal-records-card" shadow="never">
-      <el-table :data="abnormalRecords" border style="width: 100%">
-        <el-table-column prop="date" label="鏃ユ湡"  />
-        <el-table-column prop="type" label="寮傚父绫诲瀷" >
+    <el-card class="abnormal-card" shadow="never">
+      <template #header>
+        <div class="card-header">
+          <span class="card-title">寮傚父璁板綍鏄庣粏</span>
+        </div>
+      </template>
+      <el-table :data="abnormalRecords" border class="abnormal-table">
+        <!-- 寮傚父璁板綍琛ㄦ牸鍒楀畾涔変繚鎸佷笉鍙� -->
+        <el-table-column prop="date" label="鏃ユ湡" align="center" />
+        <el-table-column prop="type" label="寮傚父绫诲瀷" align="center">
           <template #default="scope">
-            <el-tag :type="getAbnormalType(scope.row.type)" size="small">
+            <el-tag :type="getAbnormalType(scope.row.type)" size="small" effect="light">
               {{ scope.row.type }}
             </el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="description" label="鎻忚堪" min-width="200" />
-        <el-table-column prop="duration" label="鏃堕暱"  />
-        <el-table-column prop="status" label="鐘舵��" >
+        <el-table-column prop="description" label="鎻忚堪" align="center" min-width="200" />
+        <el-table-column prop="duration" label="鏃堕暱" align="center" />
+        <el-table-column prop="status" label="鐘舵��" align="center">
           <template #default="scope">
             <el-tag
               :type="scope.row.status === '宸插鐞�' ? 'success' : 'warning'"
               size="small"
+              effect="light"
             >
               {{ scope.row.status }}
             </el-tag>
           </template>
         </el-table-column>
-        <el-table-column label="鎿嶄綔" >
+        <el-table-column label="鎿嶄綔" align="center" width="80">
           <template #default="scope">
             <el-button type="text" size="mini" @click="viewAbnormalDetail(scope.row)">
-              鏌ョ湅
+              璇︽儏
             </el-button>
           </template>
         </el-table-column>
@@ -201,7 +254,8 @@
       detailedStats: [],
       abnormalRecords: [],
       trendChart: null,
-      distributionChart: null
+      distributionChart: null,
+      tableExpanded: true
     }
   },
   mounted() {
@@ -211,7 +265,7 @@
     })
   },
   beforeDestroy() {
-    // 閿�姣佸浘琛ㄥ疄渚�
+    // 閿�姣佸浘琛ㄥ疄渚媅3](@ref)
     if (this.trendChart) {
       this.trendChart.dispose()
     }
@@ -221,7 +275,7 @@
   },
   methods: {
     initData() {
-      // 鍒濆鍖栨瑙堟暟鎹�
+      // 鍒濆鍖栨暟鎹�昏緫淇濇寔涓嶅彉
       this.overview = {
         totalDays: this.stats.totalDays || 22,
         presentDays: this.stats.presentDays || 20,
@@ -229,7 +283,6 @@
         attendanceRate: this.stats.attendanceRate || 90.9
       }
 
-      // 鍒濆鍖栬缁嗙粺璁�
       this.detailedStats = [
         { month: '2024-12', workDays: 22, actualDays: 20, lateTimes: 2,
           leaveEarlyTimes: 1, absenceDays: 0, businessTripDays: 3, attendanceRate: 90.9 },
@@ -239,7 +292,6 @@
           leaveEarlyTimes: 0, absenceDays: 0, businessTripDays: 1, attendanceRate: 95.7 }
       ]
 
-      // 鍒濆鍖栧紓甯歌褰�
       this.abnormalRecords = [
         { date: '2024-12-15', type: '杩熷埌', description: '鏃╀笂杩熷埌30鍒嗛挓', duration: '30鍒嗛挓', status: '宸插鐞�' },
         { date: '2024-12-08', type: '鏃╅��', description: '涓嬪崍鎻愬墠1灏忔椂绂诲紑', duration: '1灏忔椂', status: '宸插鐞�' },
@@ -261,43 +313,89 @@
       const option = {
         tooltip: {
           trigger: 'axis',
+          backgroundColor: 'rgba(255, 255, 255, 0.95)',
+          borderColor: '#ebeef5',
+          borderWidth: 1,
+          textStyle: {
+            color: '#606266'
+          },
           formatter: function(params) {
-            let result = params[0].axisValue + '<br/>'
+            let result = `<div style="font-weight: 600; margin-bottom: 8px;">${params[0].axisValue}</div>`
             params.forEach(param => {
-              result += `${param.seriesName}: ${param.value}<br/>`
+              const icon = param.seriesType === 'bar' ? '鈼�' : '鈼�'
+              result += `<div>${icon} ${param.seriesName}: <span style="font-weight: 600; color: ${param.color}">${param.value}${param.seriesName === '鍑哄嫟鐜�' ? '%' : ''}</span></div>`
             })
             return result
           }
         },
         legend: {
           data: ['鍑哄嫟澶╂暟', '寮傚父澶╂暟', '鍑哄嫟鐜�'],
-          bottom: 10
+          bottom: 10,
+          textStyle: {
+            color: '#606266'
+          },
+          itemWidth: 12,
+          itemHeight: 12
         },
         grid: {
           left: '3%',
-          right: '4%',
+          right: '3%',
           bottom: '15%',
-          top: '10%',
+          top: '15%',
           containLabel: true
         },
         xAxis: {
           type: 'category',
-          data: ['10鏈�', '11鏈�', '12鏈�']
+          data: ['10鏈�', '11鏈�', '12鏈�'],
+          axisLine: {
+            lineStyle: {
+              color: '#dcdfe6'
+            }
+          },
+          axisLabel: {
+            color: '#606266'
+          }
         },
         yAxis: [
           {
             type: 'value',
             name: '澶╂暟',
             min: 0,
-            max: 30
+            max: 30,
+            axisLine: {
+              show: true,
+              lineStyle: {
+                color: '#dcdfe6'
+              }
+            },
+            axisLabel: {
+              color: '#606266',
+              formatter: '{value}'
+            },
+            splitLine: {
+              lineStyle: {
+                color: '#f0f2f5',
+                type: 'dashed'
+              }
+            }
           },
           {
             type: 'value',
             name: '鍑哄嫟鐜�(%)',
             min: 0,
             max: 100,
+            axisLine: {
+              show: true,
+              lineStyle: {
+                color: '#dcdfe6'
+              }
+            },
             axisLabel: {
+              color: '#606266',
               formatter: '{value}%'
+            },
+            splitLine: {
+              show: false
             }
           }
         ],
@@ -305,19 +403,39 @@
           {
             name: '鍑哄嫟澶╂暟',
             type: 'bar',
-            barWidth: '30%',
+            barWidth: '25%',
             data: [22, 19, 20],
             itemStyle: {
-              color: '#409EFF'
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                { offset: 0, color: '#409EFF' },
+                { offset: 1, color: '#66b1ff' }
+              ]),
+              borderRadius: [2, 2, 0, 0]
+            },
+            emphasis: {
+              itemStyle: {
+                shadowBlur: 10,
+                shadowColor: 'rgba(64, 158, 255, 0.5)'
+              }
             }
           },
           {
             name: '寮傚父澶╂暟',
             type: 'bar',
-            barWidth: '30%',
+            barWidth: '25%',
             data: [1, 2, 2],
             itemStyle: {
-              color: '#F56C6C'
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                { offset: 0, color: '#F56C6C' },
+                { offset: 1, color: '#f78989' }
+              ]),
+              borderRadius: [2, 2, 0, 0]
+            },
+            emphasis: {
+              itemStyle: {
+                shadowBlur: 10,
+                shadowColor: 'rgba(245, 108, 108, 0.5)'
+              }
             }
           },
           {
@@ -325,14 +443,28 @@
             type: 'line',
             yAxisIndex: 1,
             data: [95.7, 90.5, 90.9],
+            symbol: 'circle',
+            symbolSize: 8,
             itemStyle: {
-              color: '#67C23A'
+              color: '#67C23A',
+              borderColor: '#fff',
+              borderWidth: 2
             },
             lineStyle: {
-              width: 3
-            }
+              width: 3,
+              shadowColor: 'rgba(103, 194, 58, 0.3)',
+              shadowBlur: 8,
+              shadowOffsetY: 2
+            },
+            emphasis: {
+              scale: true
+            },
+            animationEasing: 'cubicInOut',
+            animationDuration: 2000
           }
-        ]
+        ],
+        animation: true,
+        animationDuration: 1500
       }
       this.trendChart.setOption(option)
     },
@@ -345,13 +477,27 @@
       const option = {
         tooltip: {
           trigger: 'item',
-          formatter: '{a} <br/>{b}: {c} ({d}%)'
+          backgroundColor: 'rgba(255, 255, 255, 0.95)',
+          borderColor: '#ebeef5',
+          borderWidth: 1,
+          textStyle: {
+            color: '#606266'
+          },
+          formatter: '{a} <br/>{b}: {c}澶� ({d}%)'
         },
         legend: {
           orient: 'vertical',
           right: 10,
           top: 'center',
-          data: ['姝e父鍑哄嫟', '杩熷埌', '鏃╅��', '缂哄嫟', '鍑哄樊']
+          textStyle: {
+            color: '#606266',
+            fontSize: 12
+          },
+          itemWidth: 12,
+          itemHeight: 12,
+          formatter: function(name) {
+            return `${name}`
+          }
         },
         series: [
           {
@@ -359,24 +505,38 @@
             type: 'pie',
             radius: ['40%', '70%'],
             center: ['40%', '50%'],
-            avoidLabelOverlap: false,
+            avoidLabelOverlap: true,
             itemStyle: {
               borderColor: '#fff',
-              borderWidth: 2
+              borderWidth: 2,
+              borderRadius: 3,
+              shadowBlur: 5,
+              shadowColor: 'rgba(0, 0, 0, 0.1)'
             },
             label: {
-              show: false,
-              position: 'center'
+              show: true,
+              formatter: '{b}\n{d}%',
+              textStyle: {
+                fontSize: 12,
+                fontWeight: 'normal'
+              }
             },
             emphasis: {
               label: {
                 show: true,
-                fontSize: 18,
+                fontSize: 14,
                 fontWeight: 'bold'
+              },
+              itemStyle: {
+                shadowBlur: 10,
+                shadowOffsetX: 0,
+                shadowColor: 'rgba(0, 0, 0, 0.2)'
               }
             },
             labelLine: {
-              show: false
+              length: 15,
+              length2: 10,
+              smooth: true
             },
             data: [
               { value: 20, name: '姝e父鍑哄嫟', itemStyle: { color: '#67C23A' } },
@@ -384,23 +544,30 @@
               { value: 1, name: '鏃╅��', itemStyle: { color: '#F56C6C' } },
               { value: 0, name: '缂哄嫟', itemStyle: { color: '#909399' } },
               { value: 3, name: '鍑哄樊', itemStyle: { color: '#409EFF' } }
-            ]
+            ],
+            animationType: 'scale',
+            animationEasing: 'elasticOut',
+            animationDelay: function(idx) {
+              return Math.random() * 200
+            }
           }
-        ]
+        ],
+        animation: true,
+        animationDuration: 1000
       }
       this.distributionChart.setOption(option)
     },
 
     setupChartResize() {
-      // 鐩戝惉绐楀彛鍙樺寲锛岄噸鏂版覆鏌撳浘琛�
-      const handleResize = () => {
+      // 浣跨敤鑺傛祦鍑芥暟浼樺寲鎬ц兘[3](@ref)
+      const handleResize = this.throttle(() => {
         if (this.trendChart) {
           this.trendChart.resize()
         }
         if (this.distributionChart) {
           this.distributionChart.resize()
         }
-      }
+      }, 300)
 
       window.addEventListener('resize', handleResize)
       this.$once('hook:beforeDestroy', () => {
@@ -408,13 +575,42 @@
       })
     },
 
+    throttle(func, wait) {
+      let timeout = null
+      return function() {
+        const context = this
+        const args = arguments
+        if (!timeout) {
+          timeout = setTimeout(() => {
+            timeout = null
+            func.apply(context, args)
+          }, wait)
+        }
+      }
+    },
+
+    toggleTableExpand() {
+      this.tableExpanded = !this.tableExpanded
+    },
+
+    getRowClassName({ rowIndex }) {
+      return rowIndex % 2 === 1 ? 'even-row' : 'odd-row'
+    },
+
+    getRateTextClass(rate) {
+      if (rate >= 95) return 'rate-excellent'
+      if (rate >= 90) return 'rate-good'
+      if (rate >= 80) return 'rate-average'
+      return 'rate-poor'
+    },
+
+    // 鍏朵粬鏂规硶淇濇寔涓嶅彉
     handlePeriodChange(period) {
       this.reportPeriod = period
       this.updateChartData()
     },
 
     updateChartData() {
-      // 鏍规嵁閫夋嫨鐨勫懆鏈熸洿鏂板浘琛ㄦ暟鎹�
       let data
       switch (this.reportPeriod) {
         case 'month':
@@ -429,12 +625,10 @@
         default:
           data = this.getMonthlyData()
       }
-
       this.updateCharts(data)
     },
 
     getMonthlyData() {
-      // 妯℃嫙鏈堝害鏁版嵁
       return {
         xAxis: ['10鏈�', '11鏈�', '12鏈�'],
         attendance: [22, 19, 20],
@@ -444,7 +638,6 @@
     },
 
     getQuarterlyData() {
-      // 妯℃嫙瀛e害鏁版嵁
       return {
         xAxis: ['Q1', 'Q2', 'Q3', 'Q4'],
         attendance: [65, 62, 58, 61],
@@ -454,7 +647,6 @@
     },
 
     getYearlyData() {
-      // 妯℃嫙骞村害鏁版嵁
       return {
         xAxis: ['2022', '2023', '2024'],
         attendance: [240, 248, 252],
@@ -470,7 +662,7 @@
         option.series[0].data = data.attendance
         option.series[1].data = data.abnormal
         option.series[2].data = data.rate
-        this.trendChart.setOption(option)
+        this.trendChart.setOption(option, { notMerge: false })
       }
     },
 
@@ -493,12 +685,10 @@
 
     viewAbnormalDetail(record) {
       this.$message.info(`鏌ョ湅寮傚父璁板綍: ${record.date} - ${record.type}`)
-      // 杩欓噷鍙互鎵撳紑璇︽儏瀵硅瘽妗�
     },
 
     exportReport() {
       this.$message.success('鎶ヨ〃瀵煎嚭鍔熻兘寮�鍙戜腑')
-      // 杩欓噷鍙互瀹炵幇瀵煎嚭PDF鎴朎xcel鍔熻兘
     }
   }
 }
@@ -506,9 +696,9 @@
 
 <style scoped>
 .personal-attendance-report {
-  padding: 20px;
-  background: #fff;
-  border-radius: 8px;
+  padding: 24px;
+  background: #f8f9fa;
+  min-height: 100vh;
 }
 
 .report-header {
@@ -516,15 +706,17 @@
   justify-content: space-between;
   align-items: center;
   margin-bottom: 24px;
-  padding-bottom: 16px;
-  border-bottom: 1px solid #ebeef5;
+  padding: 0;
 }
 
 .report-header h4 {
   margin: 0;
   color: #303133;
-  font-size: 20px;
+  font-size: 24px;
   font-weight: 600;
+  background: linear-gradient(135deg, #409EFF, #67C23A);
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
 }
 
 .header-actions {
@@ -534,51 +726,78 @@
 }
 
 .stats-overview {
-  margin-bottom: 24px;
+  margin-bottom: 32px;
+}
+
+.stat-col {
+  margin-bottom: 20px;
 }
 
 .stat-card {
-  border-radius: 8px;
-  transition: all 0.3s ease;
+  border-radius: 12px;
+  border: none;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  background: #fff;
+  position: relative;
+  overflow: hidden;
+}
+
+.stat-card::before {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 3px;
+  background: linear-gradient(90deg, var(--gradient-start), var(--gradient-end));
 }
 
 .stat-card:hover {
-  transform: translateY(-2px);
-  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+  transform: translateY(-4px);
+  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.15);
 }
 
 .stat-content {
   display: flex;
   align-items: center;
-  padding: 16px;
+  padding: 20px;
 }
 
 .stat-icon {
-  width: 60px;
-  height: 60px;
-  border-radius: 50%;
+  width: 64px;
+  height: 64px;
+  border-radius: 16px;
   display: flex;
   align-items: center;
   justify-content: center;
   margin-right: 16px;
-  font-size: 24px;
+  font-size: 28px;
   color: white;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
 }
 
 .attendance-icon {
-  background: linear-gradient(135deg, #409EFF, #79BBFF);
+  --gradient-start: #409EFF;
+  --gradient-end: #66b1ff;
+  background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end));
 }
 
 .present-icon {
-  background: linear-gradient(135deg, #67C23A, #95D475);
+  --gradient-start: #67C23A;
+  --gradient-end: #85ce61;
+  background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end));
 }
 
 .abnormal-icon {
-  background: linear-gradient(135deg, #E6A23C, #EEBD6D);
+  --gradient-start: #E6A23C;
+  --gradient-end: #ebb563;
+  background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end));
 }
 
 .rate-icon {
-  background: linear-gradient(135deg, #F56C6C, #F89898);
+  --gradient-start: #F56C6C;
+  --gradient-end: #f78989;
+  background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end));
 }
 
 .stat-info {
@@ -586,47 +805,162 @@
 }
 
 .stat-value {
-  font-size: 28px;
-  font-weight: bold;
+  font-size: 32px;
+  font-weight: 700;
   color: #303133;
   margin-bottom: 4px;
+  line-height: 1;
 }
 
 .stat-label {
   color: #909399;
   font-size: 14px;
+  font-weight: 500;
 }
 
 .charts-section {
+  margin-bottom: 32px;
+}
+
+.chart-col {
   margin-bottom: 24px;
 }
 
-.chart-container {
-  width: 100%;
-  height: 300px;
+.chart-card {
+  border-radius: 12px;
+  border: none;
+  background: #fff;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
 }
 
-.detail-table-card,
-.abnormal-records-card {
-  margin-bottom: 20px;
+.chart-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 0;
+}
+
+.chart-title {
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+}
+
+.chart-legend {
+  display: flex;
+  gap: 16px;
+  align-items: center;
+}
+
+.legend-item {
+  display: flex;
+  align-items: center;
+  gap: 6px;
+  font-size: 12px;
+  color: #606266;
+}
+
+.legend-color {
+  width: 12px;
+  height: 12px;
+  border-radius: 2px;
+}
+
+.bar-color {
+  background: linear-gradient(135deg, #409EFF, #66b1ff);
+}
+
+.line-color {
+  background: linear-gradient(135deg, #67C23A, #85ce61);
+}
+
+.chart-container {
+  width: 40vw;
+  height: 320px;
+  position: relative;
+}
+
+.detail-card,
+.abnormal-card {
+  border-radius: 12px;
+  border: none;
+  background: #fff;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+  margin-bottom: 24px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 0;
+}
+
+.card-title {
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+}
+
+.stats-table {
+  border-radius: 8px;
+  overflow: hidden;
+}
+
+.stats-table :deep(.el-table__row) {
+  transition: background-color 0.3s;
+}
+
+.stats-table :deep(.el-table__row:hover) {
+  background-color: #f5f7fa;
+}
+
+.stats-table :deep(.even-row) {
+  background-color: #fafbfc;
+}
+
+.progress-cell {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.rate-progress {
+  flex: 1;
+}
+
+.rate-text {
+  font-size: 12px;
+  font-weight: 600;
+  min-width: 40px;
+}
+
+.rate-excellent { color: #67C23A; }
+.rate-good { color: #E6A23C; }
+.rate-average { color: #F56C6C; }
+.rate-poor { color: #909399; }
+
+.abnormal-table {
+  border-radius: 8px;
+  overflow: hidden;
 }
 
 /* 鍝嶅簲寮忚璁� */
 @media (max-width: 1200px) {
-  .stats-overview .el-col {
-    margin-bottom: 16px;
+  .chart-container {
+    height: 280px;
   }
 }
 
 @media (max-width: 768px) {
   .personal-attendance-report {
-    padding: 12px;
+    padding: 16px;
   }
 
   .report-header {
     flex-direction: column;
     align-items: flex-start;
-    gap: 12px;
+    gap: 16px;
   }
 
   .header-actions {
@@ -635,14 +969,42 @@
   }
 
   .stat-content {
-    padding: 12px;
+    padding: 16px;
+    flex-direction: column;
+    text-align: center;
   }
 
   .stat-icon {
-    width: 50px;
-    height: 50px;
-    font-size: 20px;
-    margin-right: 12px;
+    margin-right: 0;
+    margin-bottom: 12px;
+    width: 56px;
+    height: 56px;
+    font-size: 24px;
+  }
+
+  .stat-value {
+    font-size: 28px;
+  }
+
+  .chart-container {
+    height: 240px;
+  }
+
+  .chart-header {
+    flex-direction: column;
+    gap: 12px;
+    align-items: flex-start;
+  }
+
+  .chart-legend {
+    align-self: stretch;
+    justify-content: space-around;
+  }
+}
+
+@media (max-width: 480px) {
+  .stat-col {
+    margin-bottom: 16px;
   }
 
   .stat-value {
@@ -650,7 +1012,7 @@
   }
 
   .chart-container {
-    height: 250px;
+    height: 200px;
   }
 }
 
@@ -662,21 +1024,23 @@
   opacity: 0;
 }
 
-/* 琛ㄦ牸鏍峰紡浼樺寲 */
-.el-table {
-  border-radius: 4px;
-  overflow: hidden;
+/* 婊氬姩鏉℃牱寮忎紭鍖� */
+:deep(::-webkit-scrollbar) {
+  width: 6px;
+  height: 6px;
 }
 
-.el-table::before {
-  display: none;
+:deep(::-webkit-scrollbar-track) {
+  background: #f1f1f1;
+  border-radius: 3px;
 }
 
-/* 鍗$墖鏍囬鏍峰紡 */
-.el-card__header {
-  background: #f8f9fa;
-  border-bottom: 1px solid #ebeef5;
-  font-weight: 600;
-  color: #303133;
+:deep(::-webkit-scrollbar-thumb) {
+  background: #c1c1c1;
+  border-radius: 3px;
+}
+
+:deep(::-webkit-scrollbar-thumb:hover) {
+  background: #a8a8a8;
 }
 </style>

--
Gitblit v1.9.3