Преглед изворни кода

style: 品牌重塑 — 蓝色主色调 + 侧边栏纯文字标题 + Dashboard布局改造

- 主色由品牌红 #C83A35 切换为专业蓝 #409EFF,覆盖全部交互组件
- 侧边栏移除 logo 图标,保留「超级进化车生活」纯文字标题
- Dashboard 按 admin-web 布局重建:6 等大指标卡片 + 走势图/饼图双栏
- 更新 index.html / platform-config 中标题和主题色
- 亮色主题侧边栏激活指示条保留品牌红作为记忆点

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline пре 4 дана
родитељ
комит
109651134b

+ 1 - 1
admin-web-new/index.html

@@ -8,7 +8,7 @@
       name="viewport"
       content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
     />
-    <title>超级进化</title>
+    <title>超级进化车生活</title>
     <link rel="icon" href="/favicon.ico" />
   </head>
 

+ 1 - 1
admin-web-new/package.json

@@ -33,7 +33,7 @@
   ],
   "license": "MIT",
   "author": {
-    "name": "超级进化"
+    "name": "YesWash"
   },
   "dependencies": {
     "@amap/amap-jsapi-loader": "^1.0.1",

+ 16 - 1
admin-web-new/public/logo.svg

@@ -1 +1,16 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" class="icon" viewBox="0 0 1024 1024"><path fill="#386BF3" d="M410.558.109c0 210.974-300.876 361.752-300.876 633.548 0 174.943 134.704 316.787 300.876 316.787s300.877-141.817 300.877-316.787C711.408 361.752 410.558 210.974 410.558.109"/><path fill="#C3D2FB" d="M613.469 73.665c0 211.055-300.877 361.914-300.877 633.547C312.592 882.156 447.296 1024 613.47 1024s300.876-141.817 300.876-316.788C914.29 435.58 613.469 284.72 613.469 73.665"/><path fill="#303F5B" d="M312.592 707.212c0-183.713 137.636-312.171 226.723-441.39 81.702 106.112 172.12 218.74 172.12 367.726A309.755 309.755 0 0 1 420.36 950.064a323.1 323.1 0 0 1-107.769-242.852z"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
+  <defs>
+    <linearGradient id="washGrad" x1="0" y1="0" x2="1" y2="1">
+      <stop offset="0%" stop-color="#409EFF"/>
+      <stop offset="100%" stop-color="#1D7BE5"/>
+    </linearGradient>
+  </defs>
+  <!-- 圆形底盘 -->
+  <circle cx="16" cy="16" r="15" fill="url(#washGrad)" opacity="0.12"/>
+  <!-- 水滴1 - 左 -->
+  <path d="M10.5 19.5c0 2 1.5 3.5 3 3.5s3-1.5 3-3.5c0-2.5-3-5.5-3-5.5s-3 3-3 5.5z" fill="url(#washGrad)" transform="translate(-1,-1) scale(0.9)"/>
+  <!-- 水滴2 - 右 -->
+  <path d="M16.5 19.5c0 2 1.5 3.5 3 3.5s3-1.5 3-3.5c0-2.5-3-5.5-3-5.5s-3 3-3 5.5z" fill="url(#washGrad)" opacity="0.65" transform="translate(4.5,-1) scale(0.85)"/>
+  <!-- 弧线水花 -->
+  <path d="M6 15c2-3 4.5-5 8-5s7 2.5 9 6" fill="none" stroke="url(#washGrad)" stroke-width="2" stroke-linecap="round" opacity="0.6"/>
+</svg>

+ 3 - 3
admin-web-new/public/platform-config.json

@@ -1,6 +1,6 @@
 {
   "Version": "6.3.0",
-  "Title": "超级进化",
+  "Title": "超级进化车生活",
   "FixedHeader": true,
   "HiddenSideBar": false,
   "MultiTagsCache": false,
@@ -16,8 +16,8 @@
   "HideFooter": false,
   "Stretch": false,
   "SidebarStatus": false,
-  "EpThemeColor": "#C83A35",
-  "ShowLogo": true,
+  "EpThemeColor": "#409EFF",
+  "ShowLogo": false,
   "ShowModel": "smart",
   "MenuArrowIconNoTransition": false,
   "CachingAsyncRoutes": false,

+ 1 - 5
admin-web-new/src/layout/components/lay-sidebar/NavHorizontal.vue

@@ -18,11 +18,7 @@ import Setting from "~icons/ri/settings-3-line";
 import Check from "~icons/ep/check";
 
 const menuRef = ref();
-const showLogo = ref(
-  storageLocal().getItem<StorageConfigs>(
-    `${responsiveStorageNameSpace()}configure`
-  )?.showLogo ?? true
-);
+const showLogo = ref(true);
 
 const { t, route, locale, translationCh, translationEn } =
   useTranslationLang(menuRef);

+ 1 - 6
admin-web-new/src/layout/components/lay-sidebar/NavVertical.vue

@@ -11,12 +11,7 @@ import LaySidebarLogo from "../lay-sidebar/components/SidebarLogo.vue";
 import LaySidebarItem from "../lay-sidebar/components/SidebarItem.vue";
 
 const route = useRoute();
-const showLogo = ref(
-  storageLocal().getItem<StorageConfigs>(
-    `${responsiveStorageNameSpace()}configure`
-  )?.showLogo ?? true
-);
-
+const showLogo = ref(true);
 const {
   device,
   pureApp,

+ 2 - 2
admin-web-new/src/layout/components/lay-sidebar/components/SidebarLogo.vue

@@ -19,7 +19,7 @@ const { title, getLogo } = useNav();
         class="sidebar-logo-link"
         :to="getTopMenu()?.path ?? '/'"
       >
-        <img :src="getLogo()" alt="logo" />
+<!-- logo image removed -->
         <span class="sidebar-title">{{ title }}</span>
       </router-link>
       <router-link
@@ -29,7 +29,7 @@ const { title, getLogo } = useNav();
         class="sidebar-logo-link"
         :to="getTopMenu()?.path ?? '/'"
       >
-        <img :src="getLogo()" alt="logo" />
+<!-- logo image removed -->
         <span class="sidebar-title">{{ title }}</span>
       </router-link>
     </transition>

+ 16 - 16
admin-web-new/src/style/index.scss

@@ -25,22 +25,22 @@
   --pure-theme-menu-title-hover: initial;
   --pure-theme-menu-active-before: transparent;
 
-  /* Brand Red — 覆盖 Element Plus 默认蓝色为品牌红 #C83A35 */
-  --el-color-primary: #C83A35;
-  --el-color-primary-light-1: #D1635C;
-  --el-color-primary-light-2: #D57068;
-  --el-color-primary-light-3: #D97B6F;
-  --el-color-primary-light-4: #DF8E81;
-  --el-color-primary-light-5: #E59E94;
-  --el-color-primary-light-6: #EBAFA6;
-  --el-color-primary-light-7: #F1C4BD;
-  --el-color-primary-light-8: #F6D6D1;
-  --el-color-primary-light-9: #FBE9E6;
-  --el-color-primary-dark-1: #B43330;
-  --el-color-primary-dark-2: #A02D29;
-  --el-color-primary-rgb: 200, 58, 53;
-  --el-menu-active-color: #C83A35;
-  --el-menu-hover-bg-color: rgb(200 58 53 / 8%);
+  /* Primary Blue — 主交互色使用专业蓝 */
+  --el-color-primary: #409EFF;
+  --el-color-primary-light-1: #53ACFF;
+  --el-color-primary-light-2: #66B8FF;
+  --el-color-primary-light-3: #79C4FF;
+  --el-color-primary-light-4: #8CD0FF;
+  --el-color-primary-light-5: #9FDBFF;
+  --el-color-primary-light-6: #B2E6FF;
+  --el-color-primary-light-7: #C5EFFF;
+  --el-color-primary-light-8: #D8F4FF;
+  --el-color-primary-light-9: #EBF9FF;
+  --el-color-primary-dark-1: #3A8EE6;
+  --el-color-primary-dark-2: #337ECC;
+  --el-color-primary-rgb: 64, 158, 255;
+  --el-menu-active-color: #409EFF;
+  --el-menu-hover-bg-color: rgb(64 158 255 / 8%);
 }
 
 /* 灰色模式 */

+ 1 - 1
admin-web-new/src/style/theme.scss

@@ -1,4 +1,4 @@
-/* 亮白色 */
+/* 亮白色 — 品牌红仅用于侧边栏激活指示条 */
 html[data-theme="light"] {
   --pure-theme-sub-menu-active-text: #000000d9;
   --pure-theme-menu-bg: #fff;

+ 147 - 317
admin-web-new/src/views/admin/dashboard/index.vue

@@ -1,46 +1,39 @@
 <script setup lang="ts">
-import { markRaw, nextTick, onActivated, onMounted, reactive, ref, watch, computed } from "vue";
+import { markRaw, nextTick, onActivated, onMounted, reactive, ref, watch } from "vue";
 import * as echarts from "echarts/core";
 import { PieChart, BarChart, LineChart } from "echarts/charts";
 import {
   GridComponent,
   TitleComponent,
   LegendComponent,
-  TooltipComponent,
-  DataZoomComponent
+  TooltipComponent
 } from "echarts/components";
 import { CanvasRenderer } from "echarts/renderers";
 
 echarts.use([
-  PieChart,
-  BarChart,
-  LineChart,
-  GridComponent,
-  TitleComponent,
-  LegendComponent,
-  TooltipComponent,
-  DataZoomComponent,
+  PieChart, BarChart, LineChart,
+  GridComponent, TitleComponent, LegendComponent, TooltipComponent,
   CanvasRenderer
 ]);
 import { getDashboard, getTrend, getWashDeviceStatus } from "@/api/stat";
-import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
-import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 
-defineOptions({
-  name: "Dashboard"
-});
+defineOptions({ name: "Dashboard" });
 
 const homeLineRef = ref();
 const homePieRef = ref();
-const { dataTheme } = useDataThemeChange();
 
 const end = new Date();
 const start = new Date();
 start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
 
 const fmtMoney = (value: number) => {
-  if (!value) return "0";
-  return (value / 100).toFixed(2);
+  if (!value) return "¥0.00";
+  return `¥${(value / 100).toFixed(2)}`;
+};
+
+const fmtNumber = (value: any) => {
+  if (value === null || value === undefined) return "0";
+  return String(value);
 };
 
 const formatDate = (date: Date) => {
@@ -51,50 +44,31 @@ const formatDate = (date: Date) => {
 };
 
 const dateDiff = (start: Date, end: Date) => {
-  const diffTime = Math.abs(end.getTime() - start.getTime());
-  return Math.ceil(diffTime / (1000 * 60 * 60 * 24));
+  return Math.ceil(Math.abs(end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
 };
 
 const Session = {
   get: (key: string) => {
     const value = sessionStorage.getItem(key);
     return value ? JSON.parse(value) : null;
-  },
-  set: (key: string, value: any) => {
-    sessionStorage.setItem(key, JSON.stringify(value));
   }
 };
 
-// 品牌衍生图表色板
-const CHART_BAR = "#4DA89D";
-const CHART_LINE = "#C83A35";
-const CHART_GRID = "#EBEBEB";
-
-const PIE_COLORS = [
-  "#C83A35",
-  "#4DA89D",
-  "#E5A350",
-  "#8B7EC8",
-  "#5BA0D9",
-  "#8E8E8E"
-];
-
 const state = reactive({
   currentStationId: null as string | null,
   dateRange: [formatDate(start), formatDate(end)] as [string, string],
   global: {
     homeChartOne: null as any,
-    homeChartTwo: null as any,
-    dispose: [null, "", undefined]
-  },
-  metrics: {
-    registeredMembers: { value: "0", label: "今日注册会员", icon: "ri/user-add-line" },
-    todayIncome: { value: "0", label: "今日收益金额", icon: "ri/money-dollar-circle-line" },
-    consumptionAmount: { value: "0", label: "今日消费总额", icon: "ri/shopping-cart-2-line" },
-    avgOrderPrice: { value: "0", label: "订单均价", icon: "ri/calculator-line" },
-    todayOrders: { value: "0", label: "今日订单数量", icon: "ri/file-list-3-line" },
-    avgDuration: { value: "0", label: "洗车平均时长", icon: "ri/timer-line" }
+    homeChartTwo: null as any
   },
+  metrics: [
+    { key: "registeredMembers", value: "0", label: "今日注册会员数", unit: "人", color: "#5470C6" },
+    { key: "todayIncome", value: "0", label: "今日收益金额", unit: "元", color: "#91CC75" },
+    { key: "consumptionAmount", value: "0", label: "今日消费总额", unit: "元", color: "#FAC858" },
+    { key: "avgOrderPrice", value: "0", label: "订单平均消费", unit: "元", color: "#EE6666" },
+    { key: "todayOrders", value: "0", label: "今日订单数量", unit: "笔", color: "#73C0DE" },
+    { key: "avgDuration", value: "0", label: "洗车平均时长", unit: "分钟", color: "#8B7EC8" }
+  ] as { key: string; value: string; label: string; unit: string; color: string }[],
   myCharts: [] as any[],
   charts: {
     theme: "",
@@ -138,7 +112,7 @@ const shortcuts = [
 ];
 
 const initLineChart = (dataList: Array<any>) => {
-  if (!state.global.dispose.some((b: any) => b === state.global.homeChartOne)) {
+  if (!state.myCharts.includes(state.global.homeChartOne)) {
     state.global.homeChartOne?.dispose();
   }
   state.global.homeChartOne = markRaw(echarts.init(homeLineRef.value, state.charts.theme));
@@ -153,26 +127,26 @@ const initLineChart = (dataList: Array<any>) => {
 
   dataList.sort((a, b) => a.seq - b.seq);
 
-  const xAxis = dataList.map(k => k.startTime);
   const option = {
     backgroundColor: state.charts.bgColor,
     title: {
       text: "洗车数据走势图",
-      x: "left",
-      textStyle: { fontSize: "15", color: state.charts.color }
+      left: 0,
+      textStyle: { fontSize: 15, color: state.charts.color }
     },
-    grid: { top: 70, right: 0, bottom: 30, left: 50 },
+    grid: { top: 50, right: 20, bottom: 30, left: 60 },
     tooltip: { trigger: "axis" },
-    legend: { data: ["洗车量", "总金额"], right: 20 },
+    legend: { data: ["洗车量", "总金额"], right: 0 },
     xAxis: {
-      data: xAxis
+      data: dataList.map(k => k.startTime),
+      axisLine: { lineStyle: { color: state.charts.color } }
     },
     yAxis: [
       {
         type: "value",
         name: "费用/元  洗车量/次",
         position: "left",
-        splitLine: { show: true, lineStyle: { type: "dashed", color: CHART_GRID } }
+        splitLine: { show: true, lineStyle: { type: "dashed", color: "#f0f0f0" } }
       }
     ],
     series: [
@@ -180,12 +154,13 @@ const initLineChart = (dataList: Array<any>) => {
         name: "洗车量",
         type: "bar",
         barWidth: 10,
-        symbolSize: 6,
-        symbol: "circle",
         smooth: true,
         data: dataList.map(k => k.totalOrders),
-        lineStyle: { color: CHART_BAR },
-        itemStyle: { color: CHART_BAR, borderColor: CHART_BAR, barBorderRadius: 5 }
+        itemStyle: {
+          color: "#68a7a0",
+          borderColor: "#68a7a0",
+          barBorderRadius: 5
+        }
       },
       {
         name: "总金额",
@@ -194,8 +169,8 @@ const initLineChart = (dataList: Array<any>) => {
         symbol: "circle",
         smooth: true,
         data: dataList.map(k => fmtMoney(k.totalAmount)),
-        lineStyle: { color: CHART_LINE },
-        itemStyle: { color: CHART_LINE, borderColor: CHART_LINE }
+        lineStyle: { color: "#409EFF" },
+        itemStyle: { color: "#409EFF", borderColor: "#409EFF" }
       }
     ]
   };
@@ -204,7 +179,7 @@ const initLineChart = (dataList: Array<any>) => {
 };
 
 const initPieChart = (dataMap: any) => {
-  if (!state.global.dispose.some((b: any) => b === state.global.homeChartTwo)) {
+  if (!state.myCharts.includes(state.global.homeChartTwo)) {
     state.global.homeChartTwo?.dispose();
   }
   state.global.homeChartTwo = markRaw(echarts.init(homePieRef.value, state.charts.theme));
@@ -217,6 +192,7 @@ const initPieChart = (dataMap: any) => {
   if (!dicts.length) return;
 
   const getname = dicts.map(k => k.name);
+  const colorList = ["#6B6F75", "#36C78B", "#e9ee8e", "#ffa496", "#E790E8", "#363638"];
   const data: any[] = [];
 
   for (let i = 0; i < getname.length; i++) {
@@ -228,15 +204,15 @@ const initPieChart = (dataMap: any) => {
     backgroundColor: state.charts.bgColor,
     title: {
       text: "洗车设备状态",
-      x: "left",
-      textStyle: { fontSize: "15", color: state.charts.color }
+      left: 0,
+      textStyle: { fontSize: 15, color: state.charts.color }
     },
-    tooltip: { trigger: "item", formatter: "{b} <br/> {c}" },
+    tooltip: { trigger: "item", formatter: "{b}<br/>{c}" },
     legend: {
       type: "scroll",
       orient: "vertical",
-      right: "0%",
-      left: "65%",
+      right: 0,
+      left: "62%",
       top: "center",
       itemWidth: 14,
       itemHeight: 14,
@@ -246,14 +222,14 @@ const initPieChart = (dataMap: any) => {
     series: [
       {
         type: "pie",
-        radius: ["82", dataTheme.value ? "50" : "102"],
-        center: ["32%", "50%"],
+        radius: ["82", "102"],
+        center: ["30%", "50%"],
         itemStyle: {
-          color: (params: any) => PIE_COLORS[params.dataIndex % PIE_COLORS.length]
+          color: (params: any) => colorList[params.dataIndex % colorList.length]
         },
         label: { show: false },
         labelLine: { show: false },
-        data: data
+        data
       }
     ]
   };
@@ -261,20 +237,14 @@ const initPieChart = (dataMap: any) => {
   state.myCharts.push(state.global.homeChartTwo);
 };
 
-const initEchartsResizeFun = () => {
+const initEchartsResize = () => {
   nextTick(() => {
     for (let i = 0; i < state.myCharts.length; i++) {
-      setTimeout(() => {
-        state.myCharts[i]?.resize();
-      }, i * 200);
+      state.myCharts[i]?.resize();
     }
   });
 };
 
-const initEchartsResize = () => {
-  window.addEventListener("resize", initEchartsResizeFun);
-};
-
 const loadCurrentEquipmentStatus = () => {
   getWashDeviceStatus(state.currentStationId || undefined).then((res: any) => {
     initPieChart(res?.data || res || {});
@@ -301,152 +271,105 @@ const loadStationStatToday = () => {
   getDashboard(state.currentStationId || undefined).then((res: any) => {
     const data = res?.data || res;
     if (data) {
-      state.metrics.registeredMembers.value = String(data.todayRegisteredMembers || 0);
-      state.metrics.todayIncome.value = fmtMoney(data.todayIncome || 0);
-      state.metrics.consumptionAmount.value = fmtMoney(data.todayConsumptionAmount || 0);
-      state.metrics.avgOrderPrice.value = fmtMoney(data.avgOrderPrice || 0);
-      state.metrics.todayOrders.value = String(data.todayWashOrders || 0);
-      state.metrics.avgDuration.value = ((data.avgOrderDuration || 0) / 60).toFixed(1);
+      state.metrics[0].value = fmtNumber(data.todayRegisteredMembers);
+      state.metrics[1].value = fmtMoney(data.todayIncome);
+      state.metrics[2].value = fmtMoney(data.todayConsumptionAmount);
+      state.metrics[3].value = fmtMoney(data.avgOrderPrice);
+      state.metrics[4].value = fmtNumber(data.todayWashOrders);
+      state.metrics[5].value = ((data.avgOrderDuration || 0) / 60).toFixed(1);
     }
   });
 };
 
+const loadAll = () => {
+  loadStationStat();
+  loadStationStatToday();
+  loadCurrentEquipmentStatus();
+};
+
 onMounted(() => {
   const currentStationId = Session.get("currentStationId");
   if (currentStationId) {
     state.currentStationId = currentStationId;
-    initEchartsResize();
-    loadStationStat();
-    loadStationStatToday();
-    loadCurrentEquipmentStatus();
-  } else {
-    initEchartsResize();
   }
+  window.addEventListener("resize", initEchartsResize);
+  loadAll();
 });
 
 onActivated(() => {
-  initEchartsResizeFun();
+  initEchartsResize();
 });
 
 watch(
-  () => dataTheme.value,
-  (isDark) => {
+  () => state.charts.theme,
+  () => {
     nextTick(() => {
-      state.charts.theme = isDark ? "dark" : "";
-      state.charts.bgColor = isDark ? "transparent" : "";
-      state.charts.color = isDark ? "#C8C8C8" : "#303133";
-      setTimeout(() => loadStationStat(), 500);
-      setTimeout(() => loadCurrentEquipmentStatus(), 700);
+      state.myCharts = [];
+      setTimeout(() => loadStationStat(), 300);
+      setTimeout(() => loadCurrentEquipmentStatus(), 500);
     });
   }
 );
-
-const featuredMetrics = computed(() => [
-  state.metrics.todayIncome,
-  state.metrics.todayOrders
-]);
-
-const secondaryMetrics = computed(() => [
-  state.metrics.consumptionAmount,
-  state.metrics.avgOrderPrice,
-  state.metrics.registeredMembers,
-  state.metrics.avgDuration
-]);
-
-const isMoneyMetric = (label: string) => {
-  return label.includes("金额") || label.includes("收益") || label.includes("均价") || label.includes("消费");
-};
 </script>
 
 <template>
   <div class="dashboard-container">
-    <!-- 未选择站点提醒 -->
+    <!-- 未选择站点  -->
     <el-alert
       v-if="!state.currentStationId"
       title="未选择站点"
       type="warning"
-      description="请通过右上角站点选择器切换到要查看的门店,选择后将自动加载统计数据"
+      description="请通过右上角站点选择器切换到要查看的门店"
       show-icon
       closable
-      class="mb-4"
+      class="mb15"
     />
 
-    <!-- 核心指标 -->
-    <div class="featured-row">
-      <div
-        v-for="(metric, idx) in featuredMetrics"
-        :key="idx"
-        class="featured-card"
-        :class="idx === 0 ? 'featured-primary' : 'featured-secondary'"
-      >
-        <div class="featured-icon">
-          <component :is="useRenderIcon(metric.icon)" />
-        </div>
-        <div class="featured-body">
-          <div class="featured-value">
-            {{ metric.value }}
-            <span v-if="isMoneyMetric(metric.label)" class="featured-unit">元</span>
-            <span v-else class="featured-unit">笔</span>
-          </div>
-          <div class="featured-label">{{ metric.label }}</div>
-        </div>
-      </div>
-    </div>
-
-    <!-- 次要指标 -->
-    <div class="secondary-row">
-      <div
-        v-for="(metric, idx) in secondaryMetrics"
-        :key="idx"
-        class="secondary-card"
+    <!-- 6指标卡片  -->
+    <el-row :gutter="15" class="metrics-row">
+      <el-col
+        v-for="(m, idx) in state.metrics"
+        :key="m.key"
+        :xs="12" :sm="8" :md="4" :lg="4" :xl="4"
       >
-        <div class="secondary-icon">
-          <component :is="useRenderIcon(metric.icon)" />
+        <div class="metric-card">
+          <div class="metric-value" :style="{ color: m.color }">{{ m.value }}</div>
+          <div class="metric-label">{{ m.label }}</div>
         </div>
-        <div class="secondary-body">
-          <div class="secondary-value">
-            {{ metric.value }}
-            <span v-if="isMoneyMetric(metric.label)" class="secondary-unit">元</span>
-            <span v-else-if="metric.label.includes('时长')" class="secondary-unit">分钟</span>
-            <span v-else class="secondary-unit">人</span>
-          </div>
-          <div class="secondary-label">{{ metric.label }}</div>
-        </div>
-      </div>
-    </div>
+      </el-col>
+    </el-row>
 
-    <!-- 图表区域 -->
+    <!-- 走势图 + 饼图 -->
     <el-row :gutter="15">
       <el-col :xs="24" :sm="14" :md="14" :lg="16" :xl="16">
-        <el-card class="chart-card">
-          <template #header>
-            <div class="chart-header">
-              <el-date-picker
-                @change="loadStationStat"
-                value-format="YYYY-MM-DD"
-                v-model="state.dateRange"
-                type="daterange"
-                unlink-panels
-                range-separator="至"
-                start-placeholder="开始时间"
-                end-placeholder="结束时间"
-                :shortcuts="shortcuts"
-              />
-              <div class="chart-summary">
-                总收益:
-                <el-tag type="success" size="small">{{ fmtMoney(state.homeOneExtra.totalIncome) }}元</el-tag>
-                总订单:
-                <el-tag type="danger" size="small">{{ state.homeOneExtra.totalWashOrders }}笔</el-tag>
-              </div>
+        <div class="chart-panel">
+          <div class="chart-toolbar">
+            <el-date-picker
+              @change="loadStationStat"
+              value-format="YYYY-MM-DD"
+              v-model="state.dateRange"
+              type="daterange"
+              unlink-panels
+              range-separator="至"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              :shortcuts="shortcuts"
+              style="width: 280px"
+            />
+            <div class="chart-summary">
+              总收益:
+              <el-tag type="success" effect="plain" size="small">{{ fmtMoney(state.homeOneExtra.totalIncome) }}元</el-tag>
+              总订单:
+              <el-tag type="danger" effect="plain" size="small">{{ state.homeOneExtra.totalWashOrders }}笔</el-tag>
             </div>
-          </template>
-          <div class="chart-wrapper" ref="homeLineRef" />
-        </el-card>
+          </div>
+          <div class="chart-body" ref="homeLineRef" />
+        </div>
       </el-col>
       <el-col :xs="24" :sm="10" :md="10" :lg="8" :xl="8">
-        <el-card class="chart-card">
-          <div class="chart-wrapper" ref="homePieRef" />
-        </el-card>
+        <div class="chart-panel">
+          <div class="chart-body" ref="homePieRef" />
+        </div>
       </el-col>
     </el-row>
   </div>
@@ -454,165 +377,72 @@ const isMoneyMetric = (label: string) => {
 
 <style scoped lang="scss">
 .dashboard-container {
-  padding: 15px;
+  padding: 20px;
 }
 
-// 核心指标行
-.featured-row {
-  display: grid;
-  grid-template-columns: 3fr 2fr;
-  gap: 15px;
+// 指标卡片
+.metrics-row {
   margin-bottom: 15px;
-
-  @media (max-width: 768px) {
-    grid-template-columns: 1fr;
-  }
 }
 
-.featured-card {
-  display: flex;
-  align-items: center;
-  gap: 20px;
-  padding: 24px 28px;
-  border-radius: 4px;
-  background: var(--el-bg-color);
-
-  &.featured-primary {
-    box-shadow: 0 1px 3px rgb(0 0 0 / 6%);
-    border-top: 3px solid var(--el-color-primary);
+.metric-card {
+  height: 120px;
+  border-radius: 6px;
+  padding: 20px;
+  margin-bottom: 0;
+  background: #fff;
+  border: 1px solid var(--el-border-color-lighter);
+  transition: box-shadow 0.3s;
+
+  &:hover {
+    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
   }
 
-  &.featured-secondary {
-    box-shadow: 0 1px 3px rgb(0 0 0 / 6%);
+  .metric-value {
+    font-size: 30px;
+    font-weight: 700;
+    line-height: 1.3;
+    letter-spacing: -0.5px;
   }
 
-  .featured-icon {
-    font-size: 40px;
-    color: var(--el-color-primary);
-    opacity: 0.85;
-    flex-shrink: 0;
-  }
-
-  .featured-body {
-    .featured-value {
-      font-size: 36px;
-      font-weight: 700;
-      line-height: 1.2;
-      color: var(--el-text-color-primary);
-      letter-spacing: -0.5px;
-    }
-
-    .featured-unit {
-      font-size: 16px;
-      font-weight: 500;
-      color: var(--el-text-color-secondary);
-      margin-left: 4px;
-    }
-
-    .featured-label {
-      margin-top: 6px;
-      font-size: 14px;
-      font-weight: 500;
-      color: var(--el-text-color-secondary);
-    }
+  .metric-label {
+    margin-top: 8px;
+    font-size: 14px;
+    color: var(--el-text-color-secondary);
   }
 }
 
-// 次要指标行
-.secondary-row {
-  display: grid;
-  grid-template-columns: repeat(4, 1fr);
-  gap: 15px;
+// 图表面板
+.chart-panel {
+  width: 100%;
+  background: #fff;
+  border: 1px solid var(--el-border-color-lighter);
+  border-radius: 6px;
+  padding: 20px;
   margin-bottom: 15px;
+  transition: box-shadow 0.3s;
 
-  @media (max-width: 992px) {
-    grid-template-columns: repeat(2, 1fr);
+  &:hover {
+    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
   }
 
-  @media (max-width: 640px) {
-    grid-template-columns: 1fr;
-  }
-}
-
-.secondary-card {
-  display: flex;
-  align-items: center;
-  gap: 14px;
-  padding: 18px 20px;
-  border-radius: 4px;
-  background: var(--el-bg-color);
-  box-shadow: 0 1px 2px rgb(0 0 0 / 4%);
-
-  .secondary-icon {
-    font-size: 28px;
-    color: var(--el-text-color-placeholder);
-    flex-shrink: 0;
-  }
-
-  .secondary-body {
-    min-width: 0;
-
-    .secondary-value {
-      font-size: 22px;
-      font-weight: 600;
-      line-height: 1.3;
-      color: var(--el-text-color-primary);
-    }
-
-    .secondary-unit {
-      font-size: 12px;
-      font-weight: 500;
-      color: var(--el-text-color-secondary);
-      margin-left: 2px;
-    }
-
-    .secondary-label {
-      margin-top: 2px;
-      font-size: 13px;
-      color: var(--el-text-color-secondary);
-    }
-  }
-}
-
-// 图表
-.chart-card {
-  margin-bottom: 15px;
-
-  .chart-header {
+  .chart-toolbar {
     display: flex;
     justify-content: space-between;
     align-items: center;
     flex-wrap: wrap;
     gap: 10px;
+    margin-bottom: 10px;
 
     .chart-summary {
       font-size: 14px;
       color: var(--el-text-color-secondary);
-
-      .el-tag {
-        margin: 0 4px;
-      }
     }
   }
 
-  .chart-wrapper {
-    height: 350px;
+  .chart-body {
+    height: 380px;
     width: 100%;
   }
 }
-
-@media (max-width: 768px) {
-  .chart-header {
-    flex-direction: column;
-    align-items: flex-start;
-  }
-
-  .featured-card {
-    padding: 18px 20px;
-
-    .featured-value {
-      font-size: 28px;
-    }
-  }
-}
 </style>