From fa281e483a5fef9de01d8e08f258ebd8a7fca8eb Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期一, 23 三月 2026 13:47:28 +0800
Subject: [PATCH] 优化标准/实际成本对比分析页面的样式和功能,增加背景元素,改进KPI展示,支持自定义排序功能

---
 src/views/costAccounting/stdVsActCostAnalysis/index.vue |  684 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 603 insertions(+), 81 deletions(-)

diff --git a/src/views/costAccounting/stdVsActCostAnalysis/index.vue b/src/views/costAccounting/stdVsActCostAnalysis/index.vue
index 45b0e25..e0da789 100644
--- a/src/views/costAccounting/stdVsActCostAnalysis/index.vue
+++ b/src/views/costAccounting/stdVsActCostAnalysis/index.vue
@@ -1,12 +1,28 @@
 <template>
   <div class="std-cost-page">
-    <el-card class="filter-card" shadow="never">
+    <div class="page-bg" aria-hidden="true">
+      <div class="bg-mesh" />
+      <div class="bg-orb bg-orb--a" />
+      <div class="bg-orb bg-orb--b" />
+      <div class="bg-orb bg-orb--c" />
+      <div class="bg-grid" />
+    </div>
+
+    <div class="page-inner">
+    <el-card class="filter-card glass-card" shadow="never">
       <template #header>
         <div class="card-head">
           <div class="card-head-left">
-            <el-icon class="card-icon ui-icon"><DataLine /></el-icon>
-            <span class="card-title">鏍囧噯/瀹為檯鎴愭湰瀵规瘮鍒嗘瀽</span>
-            <span class="subtle">宸紓 = 瀹為檯鎴愭湰 - 鏍囧噯鎴愭湰</span>
+            <div class="title-badge">
+              <el-icon class="card-icon ui-icon"><DataLine /></el-icon>
+            </div>
+            <div class="title-block">
+              <div class="title-row">
+                <span class="card-title shimmer-text">鏍囧噯/瀹為檯鎴愭湰瀵规瘮鍒嗘瀽</span>
+                <span class="live-pill">瀹炴椂鍒嗘瀽</span>
+              </div>
+              <span class="subtle">宸紓 = 瀹為檯鎴愭湰 鈭� 鏍囧噯鎴愭湰</span>
+            </div>
           </div>
         </div>
       </template>
@@ -87,40 +103,68 @@
       </div>
     </el-card>
 
-    <el-card class="panel-card" shadow="never">
+    <el-card class="panel-card glass-card kpi-card" shadow="never">
       <div class="kpi-strip">
         <div class="kpi-item kpi-std">
-          <div class="kpi-label">鏍囧噯鎴愭湰鍚堣</div>
+          <div class="kpi-top">
+            <el-icon class="kpi-ico"><Histogram /></el-icon>
+            <div class="kpi-label">鏍囧噯鎴愭湰鍚堣</div>
+          </div>
           <div class="kpi-value">楼{{ formatMoney(overview.standardCost) }}</div>
+          <div class="kpi-glow" />
         </div>
         <div class="kpi-item kpi-act">
-          <div class="kpi-label">瀹為檯鎴愭湰鍚堣</div>
+          <div class="kpi-top">
+            <el-icon class="kpi-ico"><TrendCharts /></el-icon>
+            <div class="kpi-label">瀹為檯鎴愭湰鍚堣</div>
+          </div>
           <div class="kpi-value">楼{{ formatMoney(overview.actualCost) }}</div>
+          <div class="kpi-glow" />
         </div>
         <div class="kpi-item kpi-diff">
-          <div class="kpi-label">宸紓鍚堣</div>
+          <div class="kpi-top">
+            <el-icon class="kpi-ico"><Switch /></el-icon>
+            <div class="kpi-label">宸紓鍚堣</div>
+          </div>
           <div class="kpi-value" :class="overview.diff >= 0 ? 'cost-value' : 'ok-value'">
             楼{{ formatMoney(overview.diff) }}
           </div>
+          <div class="kpi-glow" />
         </div>
         <div class="kpi-item kpi-rate">
-          <div class="kpi-label">宸紓鐜�</div>
+          <div class="kpi-top">
+            <el-icon class="kpi-ico"><PieChart /></el-icon>
+            <div class="kpi-label">宸紓鐜�</div>
+          </div>
           <div class="kpi-value">{{ formatPercent(overview.diffRate) }}</div>
+          <div class="kpi-glow" />
         </div>
       </div>
     </el-card>
 
-    <el-card class="table-card" shadow="never">
+    <el-card class="table-card glass-card chart-section" shadow="never">
       <template #header>
         <div class="panel-head">
-          <span class="card-title">鏍囧噯/瀹為檯鎴愭湰鍙鍖栵紙鏌辩姸 + 鎶樼嚎锛�</span>
+          <div class="panel-head-main">
+            <span class="panel-accent" />
+            <div>
+              <span class="card-title">鏍囧噯/瀹為檯鎴愭湰鍙鍖�</span>
+              <span class="chart-tag">鏌辩姸 路 鎶樼嚎</span>
+            </div>
+          </div>
           <span class="subtle">鏀寔鎸夋湀浠姐�佷骇鍝佺被鍒�佹垚鏈被鍨嬬瓫閫�</span>
         </div>
       </template>
       <div class="chart-wrap">
         <div class="chart-tools chart-tools-inline" @click.stop>
-          <button class="chart-tool" type="button" @click="openLargeChart">鏌ョ湅澶у浘</button>
-          <button class="chart-tool" type="button" @click="downloadChartImage">涓嬭浇鍥捐〃</button>
+          <button class="chart-tool chart-tool--primary" type="button" @click="openLargeChart">
+            <el-icon><ZoomIn /></el-icon>
+            鏌ョ湅澶у浘
+          </button>
+          <button class="chart-tool" type="button" @click="downloadChartImage">
+            <el-icon><Download /></el-icon>
+            涓嬭浇鍥捐〃
+          </button>
         </div>
         <div ref="chartRef" class="chart-content"></div>
       </div>
@@ -131,6 +175,7 @@
       title="鏍囧噯/瀹為檯鎴愭湰瀵规瘮澶у浘"
       width="88%"
       top="6vh"
+      append-to-body
       destroy-on-close
       @opened="initLargeChart"
       @closed="disposeLargeChart"
@@ -138,31 +183,34 @@
       <div ref="largeChartRef" class="large-chart-content"></div>
     </el-dialog>
 
-    <el-card class="table-card" shadow="never">
+    <el-card class="table-card glass-card" shadow="never">
       <template #header>
         <div class="panel-head">
-          <span class="card-title">瀵规瘮鏄庣粏</span>
-          <span class="subtle">鍏� {{ tableData.length }} 鏉�</span>
+          <div class="panel-head-main">
+            <span class="panel-accent panel-accent--emerald" />
+            <span class="card-title">瀵规瘮鏄庣粏</span>
+          </div>
+          <span class="count-chip">鍏� {{ tableData.length }} 鏉�</span>
         </div>
       </template>
-      <el-table :data="pagedTableData" stripe class="lux-table">
+      <el-table :data="pagedTableData" stripe class="lux-table" @sort-change="handleSortChange">
         <el-table-column prop="month" label="鏈堜唤" width="110" />
         <el-table-column prop="category" label="浜у搧绫诲埆" min-width="140" />
         <el-table-column prop="costType" label="鎴愭湰绫诲瀷" min-width="120" />
-        <el-table-column prop="standardCost" label="鏍囧噯鎴愭湰(鍏�)" align="right">
+        <el-table-column prop="standardCost" label="鏍囧噯鎴愭湰(鍏�)" sortable="custom" align="right">
           <template #default="scope">楼{{ formatMoney(scope.row.standardCost) }}</template>
         </el-table-column>
-        <el-table-column prop="actualCost" label="瀹為檯鎴愭湰(鍏�)" align="right">
+        <el-table-column prop="actualCost" label="瀹為檯鎴愭湰(鍏�)" sortable="custom" align="right">
           <template #default="scope">楼{{ formatMoney(scope.row.actualCost) }}</template>
         </el-table-column>
-        <el-table-column prop="diff" label="宸紓(鍏�)" align="right">
+        <el-table-column prop="diff" label="宸紓(鍏�)" sortable="custom" align="right">
           <template #default="scope">
             <span :class="scope.row.diff >= 0 ? 'cost-value' : 'ok-value'">
               {{ formatSignedMoney(scope.row.diff) }}
             </span>
           </template>
         </el-table-column>
-        <el-table-column prop="diffRate" label="宸紓鐜�" align="right">
+        <el-table-column prop="diffRate" label="宸紓鐜�" sortable="custom" align="right">
           <template #default="scope">
             <span :class="scope.row.diffRate >= 0 ? 'cost-value' : 'ok-value'">
               {{ formatPercent(scope.row.diffRate) }}
@@ -182,12 +230,22 @@
         />
       </div>
     </el-card>
+    </div>
   </div>
 </template>
 
 <script setup>
 import { computed, nextTick, onMounted, onUnmounted, reactive, ref, watch } from "vue";
-import { ArrowDown, DataLine } from "@element-plus/icons-vue";
+import {
+  ArrowDown,
+  DataLine,
+  Download,
+  Histogram,
+  PieChart,
+  Switch,
+  TrendCharts,
+  ZoomIn,
+} from "@element-plus/icons-vue";
 import { ElMessage } from "element-plus";
 import * as echarts from "echarts";
 import * as XLSX from "xlsx";
@@ -295,9 +353,37 @@
   size: 10,
 });
 
+/** sortable="custom" 闇�鍦� sort-change 閲岃嚜琛屾帓搴忥紝鍐嶅垎椤� */
+const tableSort = reactive({
+  prop: "",
+  order: "",
+});
+
+const handleSortChange = ({ prop, order }) => {
+  tableSort.prop = prop || "";
+  tableSort.order = order || "";
+  page.current = 1;
+};
+
+const sortedTableData = computed(() => {
+  const rows = [...tableData.value];
+  if (!tableSort.prop || !tableSort.order) return rows;
+  const dir = tableSort.order === "ascending" ? 1 : -1;
+  const key = tableSort.prop;
+  rows.sort((a, b) => {
+    const na = Number(a[key]);
+    const nb = Number(b[key]);
+    const va = Number.isFinite(na) ? na : 0;
+    const vb = Number.isFinite(nb) ? nb : 0;
+    if (va === vb) return 0;
+    return va < vb ? -dir : dir;
+  });
+  return rows;
+});
+
 const pagedTableData = computed(() => {
   const start = (page.current - 1) * page.size;
-  return tableData.value.slice(start, start + page.size);
+  return sortedTableData.value.slice(start, start + page.size);
 });
 
 const overview = computed(() => {
@@ -321,9 +407,23 @@
 const buildChartOption = () => {
   const { xAxis, standard, actual, diffRate } = getChartData();
   return {
+    animation: true,
+    animationDuration: 920,
+    animationEasing: "cubicOut",
+    textStyle: { fontFamily: "inherit" },
     tooltip: {
       trigger: "axis",
-      axisPointer: { type: "shadow" },
+      axisPointer: {
+        type: "cross",
+        crossStyle: { color: "rgba(47, 111, 237, 0.35)" },
+        lineStyle: { type: "dashed" },
+      },
+      backgroundColor: "rgba(255, 255, 255, 0.94)",
+      borderColor: "rgba(47, 111, 237, 0.22)",
+      borderWidth: 1,
+      padding: [12, 14],
+      textStyle: { color: "rgba(15, 23, 42, 0.88)" },
+      extraCssText: "box-shadow: 0 12px 40px rgba(15, 23, 42, 0.12); border-radius: 12px;",
       formatter: (params) => {
         const row = tableData.value[params[0]?.dataIndex] || {};
         return [
@@ -335,25 +435,33 @@
         ].join("<br/>");
       },
     },
-    legend: { data: ["鏍囧噯鎴愭湰", "瀹為檯鎴愭湰", "宸紓鐜�"] },
-    grid: { left: "4%", right: "4%", top: "16%", bottom: "16%", containLabel: true },
+    legend: {
+      data: ["鏍囧噯鎴愭湰", "瀹為檯鎴愭湰", "宸紓鐜�"],
+      top: 6,
+      itemGap: 18,
+      textStyle: { color: "rgba(15, 23, 42, 0.72)" },
+    },
+    grid: { left: "3%", right: "3%", top: "18%", bottom: "14%", containLabel: true },
     xAxis: {
       type: "category",
       data: xAxis,
-      axisLabel: { color: "rgba(15, 23, 42, 0.62)" },
-      axisLine: { lineStyle: { color: "rgba(15, 23, 42, 0.08)" } },
+      axisLabel: { color: "rgba(15, 23, 42, 0.62)", fontSize: 11 },
+      axisLine: { lineStyle: { color: "rgba(15, 23, 42, 0.1)" } },
+      axisTick: { show: false },
     },
     yAxis: [
       {
         type: "value",
         name: "鎴愭湰(鍏�)",
-        axisLabel: { color: "rgba(15, 23, 42, 0.58)" },
-        splitLine: { lineStyle: { color: "rgba(15, 23, 42, 0.06)" } },
+        nameTextStyle: { color: "rgba(15, 23, 42, 0.5)", fontSize: 11 },
+        axisLabel: { color: "rgba(15, 23, 42, 0.55)" },
+        splitLine: { lineStyle: { color: "rgba(15, 23, 42, 0.06)", type: "dashed" } },
       },
       {
         type: "value",
         name: "宸紓鐜�(%)",
-        axisLabel: { color: "rgba(15, 23, 42, 0.58)" },
+        nameTextStyle: { color: "rgba(15, 23, 42, 0.5)", fontSize: 11 },
+        axisLabel: { color: "rgba(15, 23, 42, 0.55)" },
         splitLine: { show: false },
       },
     ],
@@ -361,25 +469,62 @@
       {
         name: "鏍囧噯鎴愭湰",
         type: "bar",
-        barMaxWidth: 24,
+        barMaxWidth: 26,
         data: standard,
-        itemStyle: { color: "#5b8cff", borderRadius: [4, 4, 0, 0] },
+        itemStyle: {
+          borderRadius: [6, 6, 0, 0],
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: "#8eb4ff" },
+            { offset: 1, color: "#3d74f5" },
+          ]),
+        },
+        emphasis: {
+          itemStyle: {
+            shadowBlur: 12,
+            shadowColor: "rgba(61, 116, 245, 0.45)",
+          },
+        },
       },
       {
         name: "瀹為檯鎴愭湰",
         type: "bar",
-        barMaxWidth: 24,
+        barMaxWidth: 26,
         data: actual,
-        itemStyle: { color: "#f59e0b", borderRadius: [4, 4, 0, 0] },
+        itemStyle: {
+          borderRadius: [6, 6, 0, 0],
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: "#fcd34d" },
+            { offset: 1, color: "#ea580c" },
+          ]),
+        },
+        emphasis: {
+          itemStyle: {
+            shadowBlur: 12,
+            shadowColor: "rgba(234, 88, 12, 0.4)",
+          },
+        },
       },
       {
         name: "宸紓鐜�",
         type: "line",
         yAxisIndex: 1,
         smooth: true,
+        symbol: "circle",
+        symbolSize: 7,
+        showSymbol: true,
         data: diffRate,
-        itemStyle: { color: "#ef4444" },
-        lineStyle: { width: 2 },
+        lineStyle: { width: 3, shadowBlur: 8, shadowColor: "rgba(239, 68, 68, 0.35)" },
+        itemStyle: {
+          color: "#ef4444",
+          borderColor: "#fff",
+          borderWidth: 2,
+        },
+        areaStyle: {
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: "rgba(239, 68, 68, 0.28)" },
+            { offset: 1, color: "rgba(239, 68, 68, 0.02)" },
+          ]),
+        },
       },
     ],
   };
@@ -489,6 +634,8 @@
   searchForm.monthRange = getDefaultMonthRange();
   searchForm.category = "";
   searchForm.costType = "";
+  tableSort.prop = "";
+  tableSort.order = "";
   page.current = 1;
   handleQuery();
 };
@@ -549,6 +696,8 @@
     } else {
       updateChart();
     }
+    // 寮圭獥鍑虹幇鍚庡鍣ㄥ昂瀵镐細鍙樺寲锛屽己鍒� resize 闃叉 canvas 婧㈠嚭閬尅琛ㄥご/鍏抽棴鎸夐挳
+    largeChartInstance?.resize?.();
   });
 };
 
@@ -602,26 +751,138 @@
 </script>
 
 <style scoped lang="scss">
+@keyframes mesh-shift {
+  0%,
+  100% {
+    opacity: 1;
+    transform: scale(1) translate(0, 0);
+  }
+  50% {
+    opacity: 0.85;
+    transform: scale(1.02) translate(-1%, 1%);
+  }
+}
+
+@keyframes orb-float {
+  0%,
+  100% {
+    transform: translate(0, 0) scale(1);
+  }
+  33% {
+    transform: translate(12px, -18px) scale(1.05);
+  }
+  66% {
+    transform: translate(-8px, 10px) scale(0.98);
+  }
+}
+
+@keyframes shimmer {
+  0% {
+    background-position: 200% center;
+  }
+  100% {
+    background-position: -200% center;
+  }
+}
+
 .std-cost-page {
-  --lux-bg: #f6f7fb;
-  --lux-card: rgba(255, 255, 255, 0.86);
-  --lux-border: rgba(15, 23, 42, 0.08);
+  --lux-bg: #eef1f8;
+  --lux-card: rgba(255, 255, 255, 0.72);
+  --lux-border: rgba(15, 23, 42, 0.1);
   --lux-text: rgba(15, 23, 42, 0.92);
   --lux-subtle: rgba(15, 23, 42, 0.58);
   --lux-primary: #2f6fed;
   --lux-success: #16a34a;
   --lux-warning: #f59e0b;
   --lux-danger: #ef4444;
-  --lux-shadow-soft: 0 10px 28px rgba(15, 23, 42, 0.06);
-  --lux-radius: 14px;
+  --lux-shadow-soft: 0 12px 40px rgba(15, 23, 42, 0.08);
+  --lux-shadow-lift: 0 20px 50px rgba(47, 111, 237, 0.12);
+  --lux-radius: 16px;
 
-  padding: 18px 22px 24px;
-  background: radial-gradient(
-      1200px 420px at 20% 0%,
-      rgba(47, 111, 237, 0.1),
-      transparent 55%
-    ),
-    linear-gradient(180deg, var(--lux-bg) 0%, #ffffff 58%);
+  position: relative;
+  min-height: 100%;
+  padding: 20px 22px 28px;
+  overflow: hidden;
+  background: linear-gradient(165deg, #e8ecf7 0%, #f4f6fb 42%, #fafbfd 100%);
+}
+
+.page-bg {
+  pointer-events: none;
+  position: absolute;
+  inset: 0;
+  z-index: 0;
+}
+
+.bg-mesh {
+  position: absolute;
+  inset: -20%;
+  background:
+    radial-gradient(ellipse 80% 50% at 15% 0%, rgba(47, 111, 237, 0.18), transparent 50%),
+    radial-gradient(ellipse 60% 45% at 85% 15%, rgba(245, 158, 11, 0.12), transparent 45%),
+    radial-gradient(ellipse 50% 40% at 50% 100%, rgba(22, 163, 74, 0.08), transparent 50%);
+  animation: mesh-shift 14s ease-in-out infinite;
+}
+
+.bg-orb {
+  position: absolute;
+  border-radius: 50%;
+  filter: blur(60px);
+  opacity: 0.55;
+  animation: orb-float 18s ease-in-out infinite;
+}
+
+.bg-orb--a {
+  width: 320px;
+  height: 320px;
+  top: -80px;
+  right: 5%;
+  background: rgba(47, 111, 237, 0.35);
+}
+
+.bg-orb--b {
+  width: 260px;
+  height: 260px;
+  bottom: 10%;
+  left: -40px;
+  background: rgba(99, 102, 241, 0.28);
+  animation-delay: -6s;
+}
+
+.bg-orb--c {
+  width: 200px;
+  height: 200px;
+  top: 40%;
+  right: 25%;
+  background: rgba(245, 158, 11, 0.22);
+  animation-delay: -12s;
+}
+
+.bg-grid {
+  position: absolute;
+  inset: 0;
+  opacity: 0.35;
+  background-image:
+    linear-gradient(rgba(15, 23, 42, 0.04) 1px, transparent 1px),
+    linear-gradient(90deg, rgba(15, 23, 42, 0.04) 1px, transparent 1px);
+  background-size: 48px 48px;
+  mask-image: radial-gradient(ellipse 90% 70% at 50% 30%, black 20%, transparent 75%);
+}
+
+.page-inner {
+  position: relative;
+  z-index: 1;
+}
+
+.glass-card {
+  backdrop-filter: blur(14px);
+  -webkit-backdrop-filter: blur(14px);
+  border: 1px solid rgba(255, 255, 255, 0.65);
+  box-shadow: var(--lux-shadow-soft), inset 0 1px 0 rgba(255, 255, 255, 0.85);
+  transition: box-shadow 0.35s ease, transform 0.35s ease;
+}
+
+.glass-card:hover {
+  box-shadow: var(--lux-shadow-lift), inset 0 1px 0 rgba(255, 255, 255, 0.9);
 }
 
 .filter-card,
@@ -630,13 +891,69 @@
   border-radius: var(--lux-radius);
   border-color: var(--lux-border);
   background: var(--lux-card);
-  box-shadow: var(--lux-shadow-soft);
 }
 
 .filter-card,
 .panel-card,
 .table-card {
-  margin-bottom: 14px;
+  margin-bottom: 16px;
+}
+
+.title-badge {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 44px;
+  height: 44px;
+  border-radius: 14px;
+  background: linear-gradient(145deg, rgba(47, 111, 237, 0.2), rgba(47, 111, 237, 0.06));
+  box-shadow: 0 8px 24px rgba(47, 111, 237, 0.15);
+}
+
+.card-icon {
+  font-size: 22px;
+  color: var(--lux-primary);
+}
+
+.title-block {
+  display: flex;
+  flex-direction: column;
+  gap: 4px;
+}
+
+.title-row {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+
+.shimmer-text {
+  background: linear-gradient(
+    90deg,
+    var(--lux-text) 0%,
+    var(--lux-text) 40%,
+    rgba(47, 111, 237, 0.95) 50%,
+    var(--lux-text) 60%,
+    var(--lux-text) 100%
+  );
+  background-size: 200% auto;
+  -webkit-background-clip: text;
+  background-clip: text;
+  color: transparent;
+  animation: shimmer 5s linear infinite;
+}
+
+.live-pill {
+  font-size: 11px;
+  font-weight: 650;
+  letter-spacing: 0.04em;
+  padding: 4px 10px;
+  border-radius: 999px;
+  color: #0d47a1;
+  background: linear-gradient(135deg, rgba(47, 111, 237, 0.18), rgba(47, 111, 237, 0.06));
+  border: 1px solid rgba(47, 111, 237, 0.22);
+  box-shadow: 0 2px 10px rgba(47, 111, 237, 0.12);
 }
 
 .filter-layout {
@@ -656,14 +973,40 @@
   margin: 0;
 }
 
+.filter-form :deep(.el-input__wrapper),
+.filter-form :deep(.el-select .el-input__wrapper) {
+  border-radius: 10px;
+  box-shadow: 0 2px 8px rgba(15, 23, 42, 0.04);
+  transition: box-shadow 0.2s ease;
+}
+
+.filter-form :deep(.el-input__wrapper:hover) {
+  box-shadow: 0 4px 14px rgba(47, 111, 237, 0.1);
+}
+
 .filter-actions {
   display: flex;
   justify-content: flex-end;
   align-items: center;
   flex-wrap: wrap;
   gap: 10px 14px;
-  padding-top: 10px;
-  border-top: 1px dashed rgba(15, 23, 42, 0.1);
+  padding-top: 12px;
+  border-top: 1px dashed rgba(15, 23, 42, 0.12);
+}
+
+.filter-actions :deep(.lux-btn) {
+  border-radius: 10px;
+  font-weight: 600;
+  transition: transform 0.2s ease, box-shadow 0.2s ease;
+}
+
+.filter-actions :deep(.lux-btn:hover) {
+  transform: translateY(-1px);
+  box-shadow: 0 8px 20px rgba(47, 111, 237, 0.18);
+}
+
+.filter-actions :deep(.el-button--success.is-plain) {
+  border-color: rgba(22, 163, 74, 0.35);
 }
 
 .action-group {
@@ -688,22 +1031,59 @@
   display: flex;
   align-items: center;
   justify-content: space-between;
-  gap: 10px;
+  gap: 12px;
+  flex-wrap: wrap;
 }
 
 .card-head-left {
   display: flex;
   align-items: center;
-  gap: 8px;
+  gap: 14px;
 }
 
-.card-icon {
+.panel-head-main {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.panel-accent {
+  width: 4px;
+  height: 22px;
+  border-radius: 4px;
+  background: linear-gradient(180deg, #5b8cff, #2f6fed);
+  box-shadow: 0 2px 8px rgba(47, 111, 237, 0.35);
+}
+
+.panel-accent--emerald {
+  background: linear-gradient(180deg, #34d399, #059669);
+  box-shadow: 0 2px 8px rgba(5, 150, 105, 0.35);
+}
+
+.chart-tag {
+  margin-left: 10px;
+  font-size: 11px;
+  font-weight: 650;
+  color: rgba(15, 23, 42, 0.55);
+  padding: 2px 8px;
+  border-radius: 6px;
+  background: rgba(15, 23, 42, 0.05);
+}
+
+.count-chip {
+  font-size: 12px;
+  font-weight: 650;
   color: var(--lux-primary);
+  padding: 6px 12px;
+  border-radius: 999px;
+  background: rgba(47, 111, 237, 0.1);
+  border: 1px solid rgba(47, 111, 237, 0.15);
 }
 
 .card-title {
   font-weight: 760;
   color: var(--lux-text);
+  letter-spacing: -0.02em;
 }
 
 .subtle {
@@ -711,44 +1091,115 @@
   font-size: 12px;
 }
 
+.kpi-card {
+  padding: 2px;
+}
+
 .kpi-strip {
   display: grid;
   grid-template-columns: repeat(4, minmax(0, 1fr));
-  gap: 12px;
+  gap: 14px;
 }
 
 .kpi-item {
-  padding: 12px 14px;
-  border-radius: 12px;
-  border: 1px solid rgba(15, 23, 42, 0.08);
+  position: relative;
+  padding: 16px 16px 14px;
+  border-radius: 14px;
+  border: 1px solid rgba(255, 255, 255, 0.7);
+  overflow: hidden;
+  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.3s ease;
+}
+
+.kpi-item:hover {
+  transform: translateY(-4px);
+  box-shadow: 0 16px 36px rgba(15, 23, 42, 0.1);
+}
+
+.kpi-glow {
+  position: absolute;
+  right: -20%;
+  bottom: -40%;
+  width: 120px;
+  height: 120px;
+  border-radius: 50%;
+  filter: blur(40px);
+  opacity: 0.45;
+  pointer-events: none;
+}
+
+.kpi-std .kpi-glow {
+  background: rgba(47, 111, 237, 0.55);
+}
+
+.kpi-act .kpi-glow {
+  background: rgba(245, 158, 11, 0.5);
+}
+
+.kpi-diff .kpi-glow {
+  background: rgba(239, 68, 68, 0.45);
+}
+
+.kpi-rate .kpi-glow {
+  background: rgba(22, 163, 74, 0.5);
+}
+
+.kpi-top {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  margin-bottom: 8px;
+}
+
+.kpi-ico {
+  font-size: 18px;
+  opacity: 0.88;
 }
 
 .kpi-std {
-  background: linear-gradient(135deg, rgba(47, 111, 237, 0.1), rgba(255, 255, 255, 0.86));
+  background: linear-gradient(145deg, rgba(47, 111, 237, 0.14), rgba(255, 255, 255, 0.92));
+}
+
+.kpi-std .kpi-ico {
+  color: #2563eb;
 }
 
 .kpi-act {
-  background: linear-gradient(135deg, rgba(245, 158, 11, 0.1), rgba(255, 255, 255, 0.86));
+  background: linear-gradient(145deg, rgba(245, 158, 11, 0.16), rgba(255, 255, 255, 0.92));
+}
+
+.kpi-act .kpi-ico {
+  color: #d97706;
 }
 
 .kpi-diff {
-  background: linear-gradient(135deg, rgba(239, 68, 68, 0.08), rgba(255, 255, 255, 0.86));
+  background: linear-gradient(145deg, rgba(239, 68, 68, 0.12), rgba(255, 255, 255, 0.92));
+}
+
+.kpi-diff .kpi-ico {
+  color: #dc2626;
 }
 
 .kpi-rate {
-  background: linear-gradient(135deg, rgba(22, 163, 74, 0.1), rgba(255, 255, 255, 0.86));
+  background: linear-gradient(145deg, rgba(22, 163, 74, 0.12), rgba(255, 255, 255, 0.92));
+}
+
+.kpi-rate .kpi-ico {
+  color: #059669;
 }
 
 .kpi-label {
   font-size: 12px;
   color: var(--lux-subtle);
+  font-weight: 600;
 }
 
 .kpi-value {
-  margin-top: 6px;
+  position: relative;
+  z-index: 1;
   font-size: 22px;
   font-weight: 780;
   color: var(--lux-text);
+  font-variant-numeric: tabular-nums;
 }
 
 .cost-value {
@@ -761,15 +1212,21 @@
   font-weight: 700;
 }
 
+.chart-section :deep(.el-card__header) {
+  border-bottom: 1px solid rgba(15, 23, 42, 0.06);
+}
+
 .chart-wrap {
   position: relative;
-  padding-top: 34px;
-  border-radius: 12px;
+  padding-top: 40px;
+  border-radius: 14px;
   overflow: hidden;
+  background: linear-gradient(180deg, rgba(255, 255, 255, 0.5) 0%, rgba(248, 250, 252, 0.95) 100%);
+  border: 1px solid rgba(15, 23, 42, 0.06);
 }
 
 .chart-content {
-  height: 360px;
+  height: 380px;
 }
 
 .chart-tools {
@@ -780,39 +1237,70 @@
 
 .chart-tools-inline {
   position: absolute;
-  top: 4px;
-  right: 6px;
+  top: 6px;
+  right: 8px;
   z-index: 2;
 }
 
 .chart-tool {
-  font-size: 11px;
+  display: inline-flex;
+  align-items: center;
+  gap: 4px;
+  font-size: 12px;
   font-weight: 650;
   line-height: 1;
-  padding: 6px 10px;
+  padding: 8px 12px;
   border-radius: 10px;
   border: 1px solid rgba(15, 23, 42, 0.1);
-  background: rgba(255, 255, 255, 0.78);
-  color: rgba(15, 23, 42, 0.72);
+  background: rgba(255, 255, 255, 0.88);
+  color: rgba(15, 23, 42, 0.75);
   cursor: pointer;
-  transition: background-color 0.16s ease, border-color 0.16s ease, transform 0.16s ease;
+  transition:
+    background-color 0.2s ease,
+    border-color 0.2s ease,
+    transform 0.2s ease,
+    box-shadow 0.2s ease;
+}
+
+.chart-tool--primary {
+  border-color: rgba(47, 111, 237, 0.28);
+  background: linear-gradient(135deg, rgba(47, 111, 237, 0.12), rgba(255, 255, 255, 0.95));
+  color: #1e40af;
 }
 
 .chart-tool:hover {
-  background: rgba(47, 111, 237, 0.08);
-  border-color: rgba(47, 111, 237, 0.22);
-  transform: translateY(-1px);
+  background: rgba(47, 111, 237, 0.1);
+  border-color: rgba(47, 111, 237, 0.28);
+  transform: translateY(-2px);
+  box-shadow: 0 6px 16px rgba(47, 111, 237, 0.12);
 }
 
 .large-chart-content {
   height: 70vh;
   min-height: 520px;
+  width: 100%;
+  overflow: hidden; // 闃叉 ECharts 鐢诲竷婧㈠嚭閬尅寮圭獥鏍囬鏍�
+}
+
+.std-cost-page :deep(.el-dialog__header) {
+  position: relative;
+  z-index: 3;
+}
+
+.std-cost-page :deep(.el-dialog__headerbtn) {
+  position: relative;
+  z-index: 4;
+}
+
+.std-cost-page :deep(.el-dialog__body) {
+  position: relative;
+  z-index: 1;
 }
 
 .pagination-container {
   display: flex;
   justify-content: flex-end;
-  padding-top: 12px;
+  padding-top: 14px;
 }
 
 .w-260 {
@@ -826,14 +1314,21 @@
 ::deep(.lux-table) {
   border-radius: 12px;
   overflow: hidden;
+  --el-table-border-color: rgba(15, 23, 42, 0.06);
 }
 
 ::deep(.lux-table th.el-table__cell) {
-  background: rgba(15, 23, 42, 0.03);
+  background: linear-gradient(180deg, rgba(15, 23, 42, 0.04), rgba(15, 23, 42, 0.02));
+  font-weight: 700;
+  color: rgba(15, 23, 42, 0.75);
+}
+
+::deep(.lux-table .el-table__row) {
+  transition: background-color 0.2s ease;
 }
 
 ::deep(.lux-table .el-table__row:hover > td.el-table__cell) {
-  background-color: rgba(47, 111, 237, 0.06) !important;
+  background-color: rgba(47, 111, 237, 0.07) !important;
 }
 
 @media (max-width: 1100px) {
@@ -845,5 +1340,32 @@
     justify-content: flex-start;
     padding-top: 8px;
   }
+
+  .shimmer-text {
+    animation: none;
+    color: var(--lux-text);
+    background: none;
+    -webkit-background-clip: unset;
+    background-clip: unset;
+  }
+}
+
+@media (prefers-reduced-motion: reduce) {
+  .bg-mesh,
+  .bg-orb,
+  .shimmer-text {
+    animation: none;
+  }
+
+  .shimmer-text {
+    color: var(--lux-text);
+    background: none;
+    -webkit-background-clip: unset;
+    background-clip: unset;
+  }
+
+  .kpi-item:hover {
+    transform: none;
+  }
 }
 </style>
\ No newline at end of file

--
Gitblit v1.9.3