Parcourir la source

商户端小程序首页重构

skyline il y a 1 mois
Parent
commit
a97d615eb1

+ 7 - 0
haha-admin-mp/src/api/dashboard.ts

@@ -32,3 +32,10 @@ export async function getDeviceStatusDistribution(): Promise<any> {
 export async function getQuickLinks(): Promise<any> {
   return get('/dashboard/quick-links');
 }
+
+/**
+ * 获取待办事项数据
+ */
+export async function getTodoList(): Promise<any> {
+  return get('/dashboard/quick-links'); // 待办数据从quick-links接口获取
+}

+ 233 - 50
haha-admin-mp/src/components/CustomTabBar.vue

@@ -2,15 +2,19 @@
   <view class="custom-tabbar">
     <!-- 左侧两个菜单 -->
     <view class="tab-item" :class="{ active: currentIndex === 0 }" @click="switchTab(0)">
-      <view class="tab-icon">
-        <image :src="currentIndex === 0 ? '/static/tabbar/work-active.png' : '/static/tabbar/work.png'" mode="aspectFit" />
+      <view class="tab-icon-wrapper">
+        <view class="tab-icon">
+          <view class="icon-home"></view>
+        </view>
       </view>
       <text class="tab-text">工作台</text>
     </view>
     
     <view class="tab-item" :class="{ active: currentIndex === 1 }" @click="switchTab(1)">
-      <view class="tab-icon">
-        <image :src="currentIndex === 1 ? '/static/tabbar/order-active.png' : '/static/tabbar/order.png'" mode="aspectFit" />
+      <view class="tab-icon-wrapper">
+        <view class="tab-icon">
+          <view class="icon-order"></view>
+        </view>
       </view>
       <text class="tab-text">订单</text>
     </view>
@@ -18,25 +22,28 @@
     <!-- 中间扫码按钮 -->
     <view class="scan-btn-wrapper">
       <view class="scan-btn" @click="handleScan">
-        <view class="scan-icon">
-          <view class="scan-line"></view>
-          <view class="scan-line vertical"></view>
+        <view class="scan-icon-circle">
+          <view class="scan-qr-icon"></view>
         </view>
-        <text class="scan-text">扫码上货</text>
+        <text class="scan-text">扫码</text>
       </view>
     </view>
     
     <!-- 右侧两个菜单 -->
     <view class="tab-item" :class="{ active: currentIndex === 2 }" @click="switchTab(2)">
-      <view class="tab-icon">
-        <image :src="currentIndex === 2 ? '/static/tabbar/device-active.png' : '/static/tabbar/device.png'" mode="aspectFit" />
+      <view class="tab-icon-wrapper">
+        <view class="tab-icon">
+          <view class="icon-device"></view>
+        </view>
       </view>
       <text class="tab-text">设备</text>
     </view>
     
     <view class="tab-item" :class="{ active: currentIndex === 3 }" @click="switchTab(3)">
-      <view class="tab-icon">
-        <image :src="currentIndex === 3 ? '/static/tabbar/my-active.png' : '/static/tabbar/my.png'" mode="aspectFit" />
+      <view class="tab-icon-wrapper">
+        <view class="tab-icon">
+          <view class="icon-my"></view>
+        </view>
       </view>
       <text class="tab-text">我的</text>
     </view>
@@ -127,15 +134,16 @@ const handleScan = () => {
   bottom: 0;
   left: 0;
   right: 0;
-  height: 100rpx;
+  height: 120rpx;
   background: #ffffff;
-  border-top: 1rpx solid #e2e8f0;
+  border-top: 1rpx solid #e5e7eb;
   display: flex;
   align-items: center;
   justify-content: space-around;
   padding-bottom: constant(safe-area-inset-bottom);
   padding-bottom: env(safe-area-inset-bottom);
   z-index: 999;
+  box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.05);
 }
 
 .tab-item {
@@ -145,88 +153,263 @@ const handleScan = () => {
   justify-content: center;
   flex: 1;
   height: 100%;
+  padding-top: 8rpx;
+  transition: all 0.2s;
 }
 
-.tab-icon {
-  width: 44rpx;
-  height: 44rpx;
+.tab-icon-wrapper {
+  width: 48rpx;
+  height: 48rpx;
   display: flex;
   align-items: center;
   justify-content: center;
+  margin-bottom: 4rpx;
 }
 
-.tab-icon image {
+.tab-icon {
   width: 44rpx;
   height: 44rpx;
+  position: relative;
+}
+
+/* 首页图标 - 房子 */
+.icon-home {
+  width: 32rpx;
+  height: 28rpx;
+  position: relative;
+  margin: 0 auto;
+  
+  &::before {
+    content: '';
+    position: absolute;
+    top: 0;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 0;
+    height: 0;
+    border-left: 16rpx solid transparent;
+    border-right: 16rpx solid transparent;
+    border-bottom: 14rpx solid #94a3b8;
+  }
+  
+  &::after {
+    content: '';
+    position: absolute;
+    bottom: 0;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 24rpx;
+    height: 14rpx;
+    background: #94a3b8;
+    border-radius: 2rpx;
+  }
+}
+
+/* 订单图标 - 文档 */
+.icon-order {
+  width: 28rpx;
+  height: 32rpx;
+  background: #94a3b8;
+  border-radius: 4rpx;
+  position: relative;
+  margin: 0 auto;
+  
+  &::before {
+    content: '';
+    position: absolute;
+    top: 8rpx;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 18rpx;
+    height: 2rpx;
+    background: #ffffff;
+    border-radius: 1rpx;
+  }
+  
+  &::after {
+    content: '';
+    position: absolute;
+    top: 14rpx;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 18rpx;
+    height: 2rpx;
+    background: #ffffff;
+    border-radius: 1rpx;
+  }
+}
+
+/* 设备图标 - 设备 */
+.icon-device {
+  width: 28rpx;
+  height: 32rpx;
+  background: #94a3b8;
+  border-radius: 4rpx;
+  position: relative;
+  margin: 0 auto;
+  
+  &::before {
+    content: '';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    width: 12rpx;
+    height: 12rpx;
+    border: 2rpx solid #ffffff;
+    border-radius: 50%;
+  }
+  
+  &::after {
+    content: '';
+    position: absolute;
+    bottom: 2rpx;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 8rpx;
+    height: 4rpx;
+    background: #ffffff;
+    border-radius: 2rpx;
+  }
+}
+
+/* 我的图标 - 用户 */
+.icon-my {
+  width: 28rpx;
+  height: 32rpx;
+  position: relative;
+  margin: 0 auto;
+  
+  &::before {
+    content: '';
+    position: absolute;
+    top: 0;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 14rpx;
+    height: 14rpx;
+    background: #94a3b8;
+    border-radius: 50%;
+  }
+  
+  &::after {
+    content: '';
+    position: absolute;
+    bottom: 0;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 24rpx;
+    height: 12rpx;
+    background: #94a3b8;
+    border-radius: 12rpx 12rpx 0 0;
+  }
 }
 
 .tab-text {
   font-size: 20rpx;
-  color: #94a3b8;
-  margin-top: 4rpx;
+  color: #333333;
+  transition: all 0.2s;
 }
 
 .tab-item.active .tab-text {
-  color: #10b981;
-  font-weight: 500;
+  color: #fdd835;
+  font-weight: 600;
+}
+
+/* 激活状态图标颜色 */
+.tab-item.active .icon-home::before {
+  border-bottom-color: #fdd835;
+}
+
+.tab-item.active .icon-home::after {
+  background: #fdd835;
+}
+
+.tab-item.active .icon-order {
+  background: #fdd835;
+}
+
+.tab-item.active .icon-device {
+  background: #fdd835;
+}
+
+.tab-item.active .icon-my::before,
+.tab-item.active .icon-my::after {
+  background: #fdd835;
 }
 
 /* 扫码按钮 */
 .scan-btn-wrapper {
   position: relative;
-  width: 100rpx;
-  height: 100%;
+  width: 120rpx;
+  height: 120rpx;
   display: flex;
   align-items: center;
   justify-content: center;
 }
 
 .scan-btn {
-  position: absolute;
-  bottom: 16rpx;
+  position: relative;
   width: 100rpx;
   height: 100rpx;
-  background: #10b981;
-  border-radius: 50%;
   display: flex;
   flex-direction: column;
   align-items: center;
   justify-content: center;
-  box-shadow: 0 4rpx 16rpx rgba(16, 185, 129, 0.4);
-}
-
-.scan-btn:active {
-  transform: scale(0.95);
-  background: #059669;
 }
 
-.scan-icon {
-  width: 36rpx;
-  height: 36rpx;
-  position: relative;
+.scan-icon-circle {
+  width: 80rpx;
+  height: 80rpx;
+  min-width: 80rpx;
+  min-height: 80rpx;
+  background: linear-gradient(135deg, #fdd835 0%, #fbc02d 100%);
+  border-radius: 50%;
   display: flex;
   align-items: center;
   justify-content: center;
+  box-shadow: 0 6rpx 20rpx rgba(253, 216, 53, 0.4);
+  margin-bottom: 4rpx;
+  transition: all 0.2s;
+  flex-shrink: 0;
 }
 
-.scan-line {
-  position: absolute;
-  width: 24rpx;
-  height: 4rpx;
-  background: #ffffff;
-  border-radius: 2rpx;
+.scan-btn:active .scan-icon-circle {
+  transform: scale(0.92);
+  box-shadow: 0 4rpx 12rpx rgba(253, 216, 53, 0.3);
 }
 
-.scan-line.vertical {
-  width: 4rpx;
-  height: 24rpx;
+.scan-qr-icon {
+  width: 36rpx;
+  height: 36rpx;
+  position: relative;
+  
+  &::before {
+    content: '';
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 14rpx;
+    height: 14rpx;
+    border: 3rpx solid #ffffff;
+    border-radius: 3rpx;
+  }
+  
+  &::after {
+    content: '';
+    position: absolute;
+    bottom: 0;
+    right: 0;
+    width: 14rpx;
+    height: 14rpx;
+    border: 3rpx solid #ffffff;
+    border-radius: 3rpx;
+  }
 }
 
 .scan-text {
   font-size: 18rpx;
-  color: #ffffff;
+  color: #333333;
   font-weight: 500;
-  margin-top: 4rpx;
-  white-space: nowrap;
 }
 </style>

+ 855 - 657
haha-admin-mp/src/pages/index/index.vue

@@ -1,202 +1,232 @@
 <template>
   <view class="page">
-    <!-- 顶部导航 - 与内容融合 -->
-    <view class="header">
-      <view class="header-bg"></view>
-      <view class="status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
-      <view class="header-content">
-        <view class="greeting">
-          <text class="greeting-time">{{ getTimeGreeting() }}</text>
-          <text class="greeting-name">运营管理员</text>
-        </view>
-        <view class="avatar" @click="navigateTo('/pages/my/my')">
-          <view class="avatar-icon"></view>
+    <!-- 顶部品牌栏 -->
+    <view class="header" :style="{ paddingTop: (statusBarHeight + 8) + 'px' }">
+      <view class="header-inner">
+        <view class="merchant">
+          <view class="avatar">富</view>
+          <text class="name-text">富玉餐饮</text>
         </view>
+
       </view>
     </view>
 
-    <!-- 统计卡片 -->
-    <view class="stats-section">
-      <view class="stats-card main">
-        <view class="stats-item" @click="navigateTo('/pages/orders/list')">
-          <text class="stats-value">{{ overview.todayOrders || 0 }}</text>
-          <text class="stats-label">今日订单</text>
-        </view>
-        <view class="stats-divider"></view>
-        <view class="stats-item">
-          <text class="stats-value accent">¥{{ formatMoney(overview.todaySales || 0) }}</text>
-          <text class="stats-label">今日销售额</text>
+    <!-- 悬浮主体区:上浮覆盖到头部 -->
+    <view class="content">
+      <!-- 通知栏 -->
+      <view class="notice-bar" v-if="noticeList.length > 0" @click="handleNoticeClick">
+        <view class="notice-tag">公告</view>
+        <view class="notice-content">
+          <swiper class="notice-swiper" vertical autoplay circular interval="3000" duration="500">
+            <swiper-item v-for="(notice, index) in noticeList" :key="index">
+              <text class="notice-text">{{ notice.content }}</text>
+            </swiper-item>
+          </swiper>
         </view>
+        <text class="notice-arrow">›</text>
       </view>
 
-      <view class="stats-row">
-        <view class="stats-card mini success" @click="navigateTo('/pages/device/list')">
-          <view class="stats-dot green"></view>
-          <view class="stats-info">
-            <text class="stats-value">{{ overview.onlineDevices || 0 }}</text>
-            <text class="stats-label">在线设备</text>
+      <!-- 核心销售卡片 -->
+      <view class="sales-card">
+        <view class="sales-main">
+          <view class="sales-primary">
+            <text class="label">今日销售额(元)</text>
+            <text class="primary-value">{{ formatMoney(overview.todaySales || 0) }}</text>
+            <view class="compare" v-if="overview.todayCompare !== undefined">
+              <text class="compare-text">较昨日</text>
+              <text class="compare-value">{{ overview.todayCompare >= 0 ? '+' : '' }}{{ overview.todayCompare || 0 }}%</text>
+            </view>
           </view>
-        </view>
-        <view class="stats-card mini warning">
-          <view class="stats-dot amber"></view>
-          <view class="stats-info">
-            <text class="stats-value">{{ overview.offlineDevices || 0 }}</text>
-            <text class="stats-label">离线设备</text>
+          <view class="sales-secondary">
+            <text class="label">今日订单</text>
+            <text class="secondary-value">{{ overview.todayOrders || 0 }}</text>
+            <text class="unit">单</text>
           </view>
         </view>
-      </view>
-    </view>
-
-    <!-- 快捷功能 -->
-    <view class="section">
-      <view class="section-header">
-        <text class="section-title">快捷功能</text>
-      </view>
-      <view class="quick-grid">
-        <view class="quick-item" @click="navigateTo('/pages/orders/list')">
-          <view class="quick-icon green">
-            <view class="icon-order"></view>
+        <view class="sales-footer">
+          <view class="footer-item">
+            <text class="footer-label">本月销售额</text>
+            <text class="footer-value">¥{{ formatMoney(overview.monthSales || 0) }}</text>
           </view>
-          <text class="quick-name">订单管理</text>
-        </view>
-        <view class="quick-item" @click="navigateTo('/pages/device/list')">
-          <view class="quick-icon cyan">
-            <view class="icon-device"></view>
+          <view class="footer-divider"></view>
+          <view class="footer-item">
+            <text class="footer-label">本月订单</text>
+            <text class="footer-value">{{ overview.monthOrders || 0 }}</text>
           </view>
-          <text class="quick-name">设备管理</text>
         </view>
-        <view class="quick-item" @click="navigateTo('/pages/shop/list')">
-          <view class="quick-icon amber">
-            <view class="icon-shop"></view>
-          </view>
-          <text class="quick-name">门店管理</text>
+      </view>
+
+      <!-- 设备状态 + 数据入口 -->
+      <view class="device-card">
+        <view class="card-title">
+          <text>设备概况</text>
+          <text class="card-more" @click="navigateTo('/pages/device/list')">查看全部 ›</text>
         </view>
-        <view class="quick-item" @click="navigateTo('/pages/products/list')">
-          <view class="quick-icon purple">
-            <view class="icon-product"></view>
+        <view class="device-row">
+          <view class="device-box online">
+            <view class="device-top">
+              <view class="device-dot online-dot"></view>
+              <text class="device-label">在线设备</text>
+            </view>
+            <text class="device-num">{{ overview.onlineDevices || 0 }}</text>
           </view>
-          <text class="quick-name">商品管理</text>
-        </view>
-        <view class="quick-item" @click="navigateTo('/pages/inventory/query')">
-          <view class="quick-icon blue">
-            <view class="icon-chart"></view>
+          <view class="device-box offline">
+            <view class="device-top">
+              <view class="device-dot offline-dot"></view>
+              <text class="device-label">离线设备</text>
+            </view>
+            <text class="device-num">{{ overview.offlineDevices || 0 }}</text>
           </view>
-          <text class="quick-name">库存查询</text>
         </view>
-        <view class="quick-item" @click="navigateTo('/pages/customer/list')">
-          <view class="quick-icon green">
-            <view class="icon-user"></view>
+        <view class="data-entry-row">
+          <view class="data-entry" @click="navigateTo('/pages/statistics/overview')">
+            <view class="data-entry-icon chart">
+              <view class="icon-chart"></view>
+            </view>
+            <view class="data-entry-info">
+              <text class="data-entry-title">数据统计</text>
+              <text class="data-entry-sub">销售 · 订单分析</text>
+            </view>
+            <text class="data-entry-arrow">›</text>
           </view>
-          <text class="quick-name">客户管理</text>
-        </view>
-        <view class="quick-item" @click="navigateTo('/pages/statistics/overview')">
-          <view class="quick-icon blue">
-            <view class="icon-stats"></view>
+          <view class="data-entry" @click="navigateTo('/pages/statistics/overview')">
+            <view class="data-entry-icon analytics">
+              <view class="icon-analytics"></view>
+            </view>
+            <view class="data-entry-info">
+              <text class="data-entry-title">生意参谋</text>
+              <text class="data-entry-sub">经营决策助手</text>
+            </view>
+            <text class="data-entry-arrow">›</text>
           </view>
-          <text class="quick-name">数据统计</text>
         </view>
-        <view class="quick-item" @click="navigateTo('/pages/inventory/warning')">
-          <view class="quick-icon rose">
-            <view class="icon-warning"></view>
-          </view>
-          <text class="quick-name">库存预警</text>
+      </view>
+
+      <!-- 待办事项 -->
+      <view class="todo-card">
+        <view class="card-title">
+          <text>待办事项</text>
+          <text class="card-sub" v-if="totalTodo > 0">共 {{ totalTodo }} 项待处理</text>
+          <text class="card-sub" v-else>暂无待办</text>
         </view>
-        <view class="quick-item" @click="navigateTo('/pages/checkin/index')">
-          <view class="quick-icon amber">
-            <view class="icon-checkin"></view>
+        <view class="todo-grid">
+          <view class="todo-item" v-for="item in todoItems" :key="item.key" @click="navigateTo(item.url)">
+            <view :class="['todo-icon', item.color, { disabled: !item.count }]">
+              <view :class="item.iconClass"></view>
+            </view>
+            <view class="todo-info">
+              <text :class="['todo-value', { active: item.count > 0 }]">{{ item.count }}</text>
+              <text class="todo-label">{{ item.label }}</text>
+            </view>
           </view>
-          <text class="quick-name">签到打卡</text>
         </view>
       </view>
-    </view>
 
-    <!-- 订单趋势 -->
-    <view class="section">
-      <view class="section-header">
-        <text class="section-title">订单趋势</text>
-        <text class="section-tag">近7天</text>
-      </view>
-      <view class="chart-card">
-        <view class="chart-container">
-          <view
-            class="chart-bar-wrapper"
-            v-for="(item, index) in orderTrend"
-            :key="index"
-          >
-            <text class="chart-value">{{ item.count }}</text>
-            <view class="chart-bar-bg">
-              <view
-                class="chart-bar"
-                :style="{ height: getBarHeight(item.count) + '%' }"
-              ></view>
+      <!-- 商户运营 -->
+      <view class="quick-card">
+        <view class="card-title">
+          <text>商户运营</text>
+        </view>
+        <view class="quick-grid">
+          <view class="quick-item" @click="navigateTo('/pages/products/apply')">
+            <view class="quick-icon primary">
+              <view class="icon-apply"></view>
+            </view>
+            <text class="quick-name">新品申请</text>
+          </view>
+          <view class="quick-item" @click="navigateTo('/pages/marketing/list')">
+            <view class="quick-icon orange">
+              <view class="icon-marketing"></view>
+            </view>
+            <text class="quick-name">营销管理</text>
+          </view>
+          <view class="quick-item" @click="navigateTo('/pages/staff/list')">
+            <view class="quick-icon green">
+              <view class="icon-staff"></view>
+            </view>
+            <text class="quick-name">人员管理</text>
+          </view>
+          <view class="quick-item" @click="navigateTo('/pages/shop/list')">
+            <view class="quick-icon blue">
+              <view class="icon-shop-quick"></view>
             </view>
-            <text class="chart-label">{{ item.date }}</text>
+            <text class="quick-name">门店管理</text>
           </view>
         </view>
       </view>
     </view>
-    
+
     <!-- 自定义TabBar -->
     <CustomTabBar />
   </view>
 </template>
 
 <script setup lang="ts">
-import { ref, onMounted } from 'vue';
-import { getDashboardOverview, getDashboardStatistics } from '@/api/dashboard';
+import { ref, computed, onMounted } from 'vue';
+import { getDashboardOverview, getTodoList } from '@/api/dashboard';
 import { formatMoney as formatMoneyUtil } from '@/utils/common';
 import CustomTabBar from '@/components/CustomTabBar.vue';
 
-// 获取系统信息用于计算状态栏高度
-const systemInfo = uni.getSystemInfoSync();
-const statusBarHeight = ref(systemInfo.statusBarHeight || 20);
-
+const statusBarHeight = ref(20); // 状态栏高度,默认20px
 const overview = ref<any>({});
-const statistics = ref<any>({});
-const orderTrend = ref<any[]>([]);
-const maxCount = ref(0);
+const todo = ref<any>({
+  pendingRefunds: 0,
+  pendingAlerts: 0,
+  unpaidOrders: 0,
+  lowStockItems: 0,
+  pendingInvoices: 0,
+  expiringProducts: 0
+});
+
+// 系统通知列表
+const noticeList = ref<any[]>([
+  { id: 1, content: '服务费账单功能升级通知', type: 'system' },
+  { id: 2, content: '应政府监管要求,请尽快完成资质备案信息填写', type: 'important' }
+]);
+
+// 待办项结构化配置
+const todoItems = computed(() => [
+  { key: 'pendingRefunds', label: '待处理退款', count: todo.value.pendingRefunds || 0, color: 'red', iconClass: 'icon-refund', url: '/pages/orders/list?tab=refund' },
+  { key: 'pendingAlerts', label: '待处理异常', count: todo.value.pendingAlerts || 0, color: 'orange', iconClass: 'icon-alert', url: '/pages/device/list?tab=alert' },
+  { key: 'unpaidOrders', label: '未支付订单', count: todo.value.unpaidOrders || 0, color: 'yellow', iconClass: 'icon-unpaid', url: '/pages/orders/list?tab=unpaid' },
+  { key: 'lowStockItems', label: '待补货', count: todo.value.lowStockItems || 0, color: 'blue', iconClass: 'icon-restock', url: '/pages/inventory/list' },
+  { key: 'pendingInvoices', label: '待开发票', count: todo.value.pendingInvoices || 0, color: 'purple', iconClass: 'icon-invoice', url: '/pages/invoice/list' },
+  { key: 'expiringProducts', label: '临期商品', count: todo.value.expiringProducts || 0, color: 'cyan', iconClass: 'icon-expire', url: '/pages/products/expire' }
+]);
+
+const totalTodo = computed(() =>
+  todoItems.value.reduce((sum, item) => sum + (item.count || 0), 0)
+);
 
 const formatMoney = (amount: number | string) => {
   const num = typeof amount === 'string' ? parseFloat(amount) : amount;
   return formatMoneyUtil(num || 0);
 };
 
-const getTimeGreeting = () => {
-  const hour = new Date().getHours();
-  if (hour < 6) return '凌晨好';
-  if (hour < 12) return '上午好';
-  if (hour < 18) return '下午好';
-  return '晚上好';
-};
-
-const getBarHeight = (count: number) => {
-  if (maxCount.value === 0) return 0;
-  return Math.max(15, (count / maxCount.value) * 100);
-};
-
 const navigateTo = (url: string) => {
   uni.navigateTo({ url });
 };
 
+const handleNoticeClick = () => {
+  uni.showToast({ title: '通知中心开发中', icon: 'none' });
+};
+
 const loadData = async () => {
   try {
-    const [overviewRes, statisticsRes] = await Promise.all([
+    const [overviewRes, todoRes] = await Promise.all([
       getDashboardOverview(),
-      getDashboardStatistics('week')
+      getTodoList()
     ]);
     overview.value = overviewRes || {};
-    statistics.value = statisticsRes || {};
-
-    // 构建订单趋势数据
-    const dates = statisticsRes?.dates || [];
-    const ordersData = statisticsRes?.ordersData || [];
-    orderTrend.value = dates.map((date: string, index: number) => ({
-      date: date.slice(5), // MM-dd
-      count: ordersData[index] || 0
-    }));
-
-    if (orderTrend.value.length > 0) {
-      maxCount.value = Math.max(...orderTrend.value.map((item: any) => item.count));
+    if (todoRes) {
+      todo.value = {
+        pendingRefunds: todoRes.pendingRefunds || 0,
+        pendingAlerts: todoRes.pendingAlerts || 0,
+        unpaidOrders: todoRes.unpaidOrders || 0,
+        lowStockItems: todoRes.lowStockItems || 0,
+        pendingInvoices: todoRes.pendingInvoices || 0,
+        expiringProducts: todoRes.expiringProducts || 0
+      };
     }
   } catch (error) {
     console.error('获取仪表盘数据失败', error);
@@ -204,6 +234,12 @@ const loadData = async () => {
 };
 
 onMounted(() => {
+  try {
+    const systemInfo = uni.getSystemInfoSync();
+    statusBarHeight.value = systemInfo.statusBarHeight || 44;
+  } catch (e) {
+    statusBarHeight.value = 44;
+  }
   loadData();
 });
 </script>
@@ -211,604 +247,766 @@ onMounted(() => {
 <style lang="scss" scoped>
 .page {
   min-height: 100vh;
-  background: #f8fafc;
-  padding-bottom: 200rpx;
+  background: #f4f5f7;
+  padding-bottom: 180rpx;
 }
 
-/* 顶部导航 */
+/* ========== 顶部品牌栏 ========== */
 .header {
+  background: #fdd835;
+  padding: 0 32rpx 120rpx;
   position: relative;
+}
+
+.header-inner {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+.merchant {
+  display: flex;
+  align-items: center;
+  flex: 1;
+}
+
+.avatar {
+  width: 88rpx;
+  height: 88rpx;
+  border-radius: 20rpx;
   background: #ffffff;
+  color: #333333;
+  font-size: 40rpx;
+  font-weight: 700;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 20rpx;
+  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
 }
 
-.header-bg {
-  position: absolute;
-  top: 0;
-  left: 0;
-  right: 0;
-  height: 280rpx;
-  background: #ecfdf5;
-  border-radius: 0 0 40rpx 40rpx;
+.name-text {
+  font-size: 34rpx;
+  font-weight: 700;
+  color: #1a1a1a;
 }
 
-.status-bar {
-  width: 100%;
+/* ========== 内容区域(上浮) ========== */
+.content {
+  margin-top: -100rpx;
+  padding: 0 24rpx;
   position: relative;
-  z-index: 1;
+  z-index: 2;
 }
 
-.header-content {
-  position: relative;
+/* 通用卡片标题 */
+.card-title {
   display: flex;
   justify-content: space-between;
   align-items: center;
-  padding: 16rpx 24rpx 24rpx;
-}
+  margin-bottom: 24rpx;
 
-.greeting {
-  .greeting-time {
-    display: block;
-    font-size: 26rpx;
-    color: #64748b;
-    margin-bottom: 4rpx;
-  }
-  
-  .greeting-name {
-    font-size: 40rpx;
-    font-weight: 700;
-    color: #1e293b;
+  > text:first-child {
+    font-size: 30rpx;
+    font-weight: 600;
+    color: #1a1a1a;
   }
 }
 
-.avatar {
-  width: 80rpx;
-  height: 80rpx;
-  border-radius: 50%;
-  background: #ecfdf5;
+.card-more {
+  font-size: 24rpx;
+  color: #999999;
+
+  &:active { opacity: 0.6; }
+}
+
+.card-sub {
+  font-size: 24rpx;
+  color: #999999;
+}
+
+/* ========== 通知栏 ========== */
+.notice-bar {
+  background: #ffffff;
+  padding: 18rpx 20rpx;
+  border-radius: 16rpx;
   display: flex;
   align-items: center;
-  justify-content: center;
-  border: 2rpx solid #10b981;
-  position: relative;
-  
-  .avatar-icon {
-    width: 36rpx;
-    height: 36rpx;
-    background: #10b981;
-    border-radius: 50%;
-    position: relative;
-    
-    &::before {
-      content: '';
-      position: absolute;
-      top: -16rpx;
-      left: 50%;
-      transform: translateX(-50%);
-      width: 22rpx;
-      height: 18rpx;
-      background: #10b981;
-      border-radius: 18rpx 18rpx 0 0;
-    }
-  }
+  margin-bottom: 20rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
+
+  &:active { opacity: 0.85; }
+}
+
+.notice-tag {
+  padding: 4rpx 14rpx;
+  background: #fff7ed;
+  color: #f97316;
+  font-size: 22rpx;
+  font-weight: 600;
+  border-radius: 8rpx;
+  margin-right: 16rpx;
+  flex-shrink: 0;
 }
 
-/* 统计卡片 */
-.stats-section {
-  padding: 16rpx 24rpx;
+.notice-content { flex: 1; overflow: hidden; }
+.notice-swiper { height: 40rpx; }
+.notice-text {
+  font-size: 26rpx;
+  color: #333333;
+  line-height: 40rpx;
+  display: block;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
 }
 
-.stats-card {
+.notice-arrow {
+  font-size: 36rpx;
+  color: #cccccc;
+  margin-left: 12rpx;
+}
+
+/* ========== 核心销售卡片 ========== */
+.sales-card {
   background: #ffffff;
-  border: 1rpx solid #e2e8f0;
   border-radius: 20rpx;
-  
-  &.main {
-    display: flex;
-    padding: 32rpx 0;
-    margin-bottom: 16rpx;
-    
-    .stats-item {
-      flex: 1;
-      display: flex;
-      flex-direction: column;
-      align-items: center;
-      justify-content: center;
-    }
-    
-    .stats-value {
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      font-size: 48rpx;
-      font-weight: 700;
-      color: #1e293b;
-      margin-bottom: 8rpx;
-      
-      &.accent {
-        color: #f97316;
-      }
-    }
-    
-    .stats-label {
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      font-size: 24rpx;
-      color: #64748b;
-    }
-    
-    .stats-divider {
-      width: 1rpx;
-      background: #e2e8f0;
-    }
-  }
-  
-  &.mini {
-    flex: 1;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    padding: 24rpx;
-    
-    &:not(:last-child) {
-      margin-right: 12rpx;
-    }
-    
-    .stats-dot {
-      width: 12rpx;
-      height: 12rpx;
-      border-radius: 50%;
-      margin-right: 16rpx;
-      flex-shrink: 0;
-      
-      &.green { background: #10b981; }
-      &.amber { background: #f97316; }
-    }
-    
-    .stats-info {
-      display: flex;
-      flex-direction: column;
-      align-items: center;
-      justify-content: center;
-      
-      .stats-value {
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        font-size: 32rpx;
-        font-weight: 700;
-        color: #1e293b;
-      }
-      
-      .stats-label {
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        font-size: 22rpx;
-        color: #64748b;
-      }
-    }
-  }
+  padding: 32rpx;
+  margin-bottom: 20rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
 }
 
-.stats-row {
+.sales-main {
   display: flex;
+  justify-content: space-between;
+  align-items: stretch;
+  padding-bottom: 24rpx;
+  border-bottom: 1rpx solid #f0f0f0;
 }
 
-/* 区块 */
-.section {
-  margin: 16rpx 24rpx;
+.sales-primary {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  flex: 1;
 }
-
-.section-header {
+.sales-primary .label {
+  font-size: 24rpx;
+  color: #888888;
+  margin-bottom: 12rpx;
+}
+.primary-value {
+  font-size: 64rpx;
+  font-weight: 700;
+  color: #10b981;
+  line-height: 1;
+  margin-bottom: 10rpx;
+}
+.compare {
   display: flex;
-  justify-content: space-between;
   align-items: center;
-  margin-bottom: 16rpx;
+  font-size: 22rpx;
 }
+.compare-text { color: #999999; margin-right: 8rpx; }
+.compare-value { color: #10b981; font-weight: 600; }
 
-.section-title {
-  font-size: 32rpx;
-  font-weight: 600;
-  color: #1e293b;
+.sales-secondary {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: flex-start;
+  flex: 1;
 }
 
-.section-tag {
+.sales-secondary .label {
+  font-size: 24rpx;
+  color: #888888;
+  margin-bottom: 12rpx;
+}
+.secondary-value {
+  font-size: 44rpx;
+  font-weight: 700;
+  color: #1a1a1a;
+  line-height: 1;
+}
+.unit {
   font-size: 22rpx;
-  color: #10b981;
-  background: #ecfdf5;
-  padding: 8rpx 16rpx;
-  border-radius: 8rpx;
-  
-  &.hot {
-    color: #f97316;
-    background: #fff7ed;
-  }
+  color: #999999;
+  margin-top: 6rpx;
 }
 
-/* 快捷功能 */
-.quick-grid {
+.sales-footer {
   display: flex;
   justify-content: space-between;
+  align-items: center;
+  margin-top: 24rpx;
+  gap: 0;
+}
+.footer-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  flex: 1;
+}
+.footer-label {
+  font-size: 24rpx;
+  color: #888888;
+  margin-bottom: 8rpx;
+}
+.footer-value {
+  font-size: 30rpx;
+  font-weight: 600;
+  color: #1a1a1a;
+}
+.footer-divider {
+  width: 1rpx;
+  height: 40rpx;
+  background: #e5e7eb;
+}
+
+/* ========== 设备卡片 ========== */
+.device-card {
   background: #ffffff;
-  border: 1rpx solid #e2e8f0;
   border-radius: 20rpx;
-  padding: 24rpx 16rpx;
+  padding: 28rpx;
+  margin-bottom: 20rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
 }
 
-.quick-item {
+.device-row {
+  display: flex;
+  gap: 20rpx;
+  margin-bottom: 24rpx;
+}
+
+.device-box {
+  flex: 1;
+  padding: 24rpx;
+  border-radius: 16rpx;
   display: flex;
   flex-direction: column;
   align-items: center;
-  
-  .quick-icon {
-    width: 88rpx;
-    height: 88rpx;
-    border-radius: 20rpx;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    margin-bottom: 12rpx;
-    transition: transform 0.15s;
-    
-    &:active {
-      transform: scale(0.92);
-    }
-    
-    &.green { background: #ecfdf5; }
-    &.cyan { background: #ecfeff; }
-    &.amber { background: #fff7ed; }
-    &.purple { background: #faf5ff; }
-    &.blue { background: #f0f9ff; }
-    &.rose { background: #fff1f2; }
-    
-    /* 图标 - 纯CSS几何图形 */
-    .icon-order {
-      width: 32rpx;
-      height: 40rpx;
-      border: 3rpx solid #10b981;
-      border-radius: 4rpx;
-      position: relative;
-      
-      &::before, &::after {
-        content: '';
-        position: absolute;
-        left: 6rpx;
-        width: 14rpx;
-        height: 3rpx;
-        background: #10b981;
-        border-radius: 2rpx;
-      }
-      &::before { top: 12rpx; }
-      &::after { top: 20rpx; width: 10rpx; }
-    }
-    
-    .icon-device {
-      width: 24rpx;
-      height: 40rpx;
-      border: 3rpx solid #0ea5e9;
-      border-radius: 6rpx;
-      position: relative;
-      
-      &::after {
-        content: '';
-        position: absolute;
-        bottom: 6rpx;
-        left: 50%;
-        transform: translateX(-50%);
-        width: 8rpx;
-        height: 4rpx;
-        background: #0ea5e9;
-        border-radius: 2rpx;
-      }
-    }
-    
-    .icon-shop {
-      position: relative;
-      width: 36rpx;
-      height: 36rpx;
-      
-      &::before {
-        content: '';
-        position: absolute;
-        top: 0;
-        left: 50%;
-        transform: translateX(-50%);
-        width: 0;
-        height: 0;
-        border-left: 20rpx solid transparent;
-        border-right: 20rpx solid transparent;
-        border-bottom: 14rpx solid #f97316;
-      }
-      
-      &::after {
-        content: '';
-        position: absolute;
-        bottom: 0;
-        left: 50%;
-        transform: translateX(-50%);
-        width: 32rpx;
-        height: 18rpx;
-        background: #f97316;
-        border-radius: 0 0 4rpx 4rpx;
-      }
-    }
-    
-    .icon-product {
-      width: 32rpx;
-      height: 32rpx;
-      position: relative;
-      
-      &::before {
-        content: '';
-        position: absolute;
-        top: 0;
-        left: 50%;
-        transform: translateX(-50%);
-        width: 0;
-        height: 0;
-        border-left: 10rpx solid transparent;
-        border-right: 10rpx solid transparent;
-        border-bottom: 12rpx solid #a855f7;
-      }
-      
-      &::after {
-        content: '';
-        position: absolute;
-        bottom: 0;
-        left: 50%;
-        transform: translateX(-50%);
-        width: 28rpx;
-        height: 16rpx;
-        background: #a855f7;
-        border-radius: 4rpx;
-      }
-    }
-    
-    .icon-chart {
-      display: flex;
-      align-items: flex-end;
-      justify-content: space-between;
-      width: 32rpx;
-      height: 28rpx;
-      
-      &::before, &::after, & {
-        content: '';
-        width: 8rpx;
-        background: #0ea5e9;
-        border-radius: 4rpx;
-      }
-      &::before { height: 12rpx; }
-      & { height: 24rpx; }
-      &::after { height: 16rpx; }
-    }
-    
-    .icon-checkin {
-      width: 28rpx;
-      height: 28rpx;
-      border: 3rpx solid #f97316;
-      border-radius: 50%;
-      position: relative;
-
-      &::before {
-        content: '';
-        position: absolute;
-        top: 50%;
-        left: 50%;
-        transform: translate(-50%, -50%);
-        width: 8rpx;
-        height: 8rpx;
-        background: #f97316;
-        border-radius: 50%;
-      }
-
-      &::after {
-        content: '';
-        position: absolute;
-        top: -6rpx;
-        right: -6rpx;
-        width: 12rpx;
-        height: 12rpx;
-        background: #f97316;
-        border-radius: 50%;
-      }
-    }
 
-    .icon-user {
-      width: 24rpx;
-      height: 24rpx;
-      border: 3rpx solid #10b981;
-      border-radius: 50%;
-      position: relative;
-
-      &::before {
-        content: '';
-        position: absolute;
-        top: -10rpx;
-        left: 50%;
-        transform: translateX(-50%);
-        width: 12rpx;
-        height: 12rpx;
-        border: 3rpx solid #10b981;
-        border-radius: 50%;
-      }
-    }
+  &.online { background: #ecfdf5; }
+  &.offline { background: #fff7ed; }
 
-    .icon-stats {
-      display: flex;
-      align-items: flex-end;
-      width: 28rpx;
-      height: 24rpx;
-
-      &::before, &::after, & {
-        content: '';
-        width: 8rpx;
-        background: #0ea5e9;
-        border-radius: 4rpx;
-      }
-
-      &::before { height: 10rpx; margin-right: 2rpx; }
-      & { height: 22rpx; margin-right: 2rpx; }
-      &::after { height: 16rpx; }
-    }
+  &:active { opacity: 0.85; }
+}
 
-    .icon-warning {
-      width: 28rpx;
-      height: 28rpx;
-      border: 3rpx solid #f43f5e;
-      border-radius: 50%;
-      position: relative;
-
-      &::before {
-        content: '';
-        position: absolute;
-        top: 50%;
-        left: 50%;
-        transform: translate(-50%, -50%);
-        width: 3rpx;
-        height: 12rpx;
-        background: #f43f5e;
-      }
-
-      &::after {
-        content: '';
-        position: absolute;
-        bottom: 4rpx;
-        left: 50%;
-        transform: translateX(-50%);
-        width: 3rpx;
-        height: 3rpx;
-        background: #f43f5e;
-        border-radius: 50%;
-      }
-    }
+.device-top {
+  display: flex;
+  align-items: center;
+  margin-bottom: 12rpx;
+}
+
+.device-dot {
+  width: 14rpx;
+  height: 14rpx;
+  border-radius: 50%;
+  margin-right: 10rpx;
+
+  &.online-dot { background: #10b981; }
+  &.offline-dot { background: #f97316; }
+}
+
+.device-label {
+  font-size: 24rpx;
+  color: #666666;
+}
+
+.device-num {
+  font-size: 48rpx;
+  font-weight: 700;
+  color: #1a1a1a;
+  line-height: 1;
+}
+
+.data-entry-row {
+  display: flex;
+  gap: 20rpx;
+}
+
+.data-entry {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  padding: 20rpx;
+  background: #f9fafb;
+  border-radius: 16rpx;
+
+  &:active { opacity: 0.8; }
+}
+
+.data-entry-icon {
+  width: 60rpx;
+  height: 60rpx;
+  border-radius: 14rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 14rpx;
+  flex-shrink: 0;
+
+  &.chart { background: #ecfdf5; }
+  &.analytics { background: #fff7ed; }
+}
+
+.data-entry-info {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  min-width: 0;
+}
+
+.data-entry-title {
+  font-size: 26rpx;
+  font-weight: 600;
+  color: #1a1a1a;
+  margin-bottom: 4rpx;
+}
+
+.data-entry-sub {
+  font-size: 20rpx;
+  color: #999999;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.data-entry-arrow {
+  font-size: 32rpx;
+  color: #cccccc;
+  margin-left: 8rpx;
+}
+
+.icon-chart {
+  display: flex;
+  align-items: flex-end;
+  width: 30rpx;
+  height: 28rpx;
+
+  &::before, &::after {
+    content: '';
+    width: 7rpx;
+    background: #10b981;
+    border-radius: 2rpx;
+    margin-right: 3rpx;
   }
+  &::before { height: 14rpx; }
+  &::after { height: 24rpx; margin-right: 0; }
+}
 
-  .quick-name {
-    font-size: 24rpx;
-    color: #475569;
+.icon-analytics {
+  width: 28rpx;
+  height: 28rpx;
+  position: relative;
+
+  &::before {
+    content: '';
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    border: 3rpx solid #f97316;
+    border-radius: 50%;
+  }
+  &::after {
+    content: '';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    width: 3rpx;
+    height: 14rpx;
+    background: #f97316;
+    transform-origin: bottom center;
+    transform: translate(-50%, -100%) rotate(35deg);
   }
 }
 
-/* 图表卡片 */
-.chart-card {
+/* ========== 待办事项 ========== */
+.todo-card {
   background: #ffffff;
-  border: 1rpx solid #e2e8f0;
   border-radius: 20rpx;
-  padding: 24rpx;
+  padding: 28rpx;
+  margin-bottom: 20rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
 }
 
-.chart-container {
+.todo-grid {
   display: flex;
-  justify-content: space-between;
-  align-items: flex-end;
-  height: 240rpx;
-  padding-top: 32rpx;
+  flex-wrap: wrap;
 }
 
-.chart-bar-wrapper {
-  flex: 1;
+.todo-item {
+  width: 33.333%;
+  display: flex;
+  align-items: center;
+  padding: 14rpx 6rpx;
+  box-sizing: border-box;
+
+  &:active { opacity: 0.7; }
+}
+
+.todo-icon {
+  width: 64rpx;
+  height: 64rpx;
+  border-radius: 16rpx;
   display: flex;
-  flex-direction: column;
   align-items: center;
-  height: 100%;
-  
-  .chart-value {
+  justify-content: center;
+  margin-right: 14rpx;
+  flex-shrink: 0;
+
+  &.red { background: #fef2f2; }
+  &.orange { background: #fff7ed; }
+  &.yellow { background: #fefce8; }
+  &.blue { background: #eff6ff; }
+  &.purple { background: #f5f3ff; }
+  &.cyan { background: #ecfeff; }
+
+  &.disabled { opacity: 0.6; }
+}
+
+.todo-info {
+  display: flex;
+  flex-direction: column;
+  min-width: 0;
+}
+
+.todo-value {
+  font-size: 32rpx;
+  font-weight: 700;
+  color: #cccccc;
+  line-height: 1.2;
+
+  &.active { color: #1a1a1a; }
+}
+
+.todo-label {
+  font-size: 22rpx;
+  color: #666666;
+  margin-top: 2rpx;
+  white-space: nowrap;
+}
+
+/* 待办图标 */
+.icon-refund {
+  width: 30rpx;
+  height: 30rpx;
+  border: 3rpx solid #ef4444;
+  border-radius: 50%;
+  position: relative;
+
+  &::before {
+    content: '';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    width: 14rpx;
+    height: 3rpx;
+    background: #ef4444;
+  }
+}
+
+.icon-alert {
+  width: 0;
+  height: 0;
+  border-left: 16rpx solid transparent;
+  border-right: 16rpx solid transparent;
+  border-bottom: 28rpx solid #f97316;
+  position: relative;
+
+  &::before {
+    content: '';
+    position: absolute;
+    bottom: -20rpx;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 3rpx;
+    height: 10rpx;
+    background: #ffffff;
+  }
+  &::after {
+    content: '';
+    position: absolute;
+    bottom: -26rpx;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 3rpx;
+    height: 3rpx;
+    background: #ffffff;
+    border-radius: 50%;
+  }
+}
+
+.icon-unpaid {
+  width: 30rpx;
+  height: 30rpx;
+  border: 3rpx solid #eab308;
+  border-radius: 50%;
+  position: relative;
+
+  &::before {
+    content: '¥';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
     font-size: 22rpx;
-    font-weight: 600;
-    color: #475569;
-    margin-bottom: 8rpx;
+    font-weight: 700;
+    color: #eab308;
+    line-height: 1;
   }
-  
-  .chart-bar-bg {
-    flex: 1;
-    width: 28rpx;
-    display: flex;
-    align-items: flex-end;
-    background: #f1f5f9;
-    border-radius: 6rpx;
-    
-    .chart-bar {
-      width: 100%;
-      background: #10b981;
-      border-radius: 6rpx;
-      min-height: 20rpx;
-    }
+}
+
+.icon-restock {
+  width: 30rpx;
+  height: 28rpx;
+  background: #3b82f6;
+  border-radius: 3rpx;
+  position: relative;
+
+  &::before {
+    content: '';
+    position: absolute;
+    top: 0;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 14rpx;
+    height: 6rpx;
+    background: #3b82f6;
+    border-radius: 3rpx 3rpx 0 0;
+    top: -4rpx;
   }
-  
-  .chart-label {
-    font-size: 20rpx;
-    color: #94a3b8;
-    margin-top: 10rpx;
+  &::after {
+    content: '+';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    font-size: 24rpx;
+    color: #ffffff;
+    font-weight: 700;
+    line-height: 1;
   }
 }
 
-/* 热销列表 */
-.hot-list {
+.icon-invoice {
+  width: 28rpx;
+  height: 32rpx;
+  background: #8b5cf6;
+  border-radius: 3rpx;
+  position: relative;
+
+  &::before {
+    content: '';
+    position: absolute;
+    top: 10rpx;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 16rpx;
+    height: 2rpx;
+    background: #ffffff;
+    box-shadow: 0 5rpx 0 #ffffff, 0 10rpx 0 #ffffff;
+  }
+}
+
+.icon-expire {
+  width: 30rpx;
+  height: 30rpx;
+  border: 3rpx solid #06b6d4;
+  border-radius: 50%;
+  position: relative;
+
+  &::before {
+    content: '';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    width: 3rpx;
+    height: 10rpx;
+    background: #06b6d4;
+    transform-origin: bottom center;
+    transform: translate(-50%, -100%);
+  }
+  &::after {
+    content: '';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    width: 3rpx;
+    height: 7rpx;
+    background: #06b6d4;
+    transform-origin: bottom center;
+    transform: translate(-50%, -100%) rotate(90deg);
+  }
+}
+
+/* ========== 商户运营 ========== */
+.quick-card {
   background: #ffffff;
-  border: 1rpx solid #e2e8f0;
   border-radius: 20rpx;
-  padding: 8rpx 20rpx;
+  padding: 28rpx 20rpx 20rpx;
+  margin-bottom: 20rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
+
+  .card-title {
+    padding: 0 8rpx;
+  }
+}
+
+.quick-grid {
+  display: flex;
+  justify-content: space-between;
+}
+
+.quick-item {
+  width: 25%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 8rpx 0;
+
+  &:active .quick-icon { transform: scale(0.92); }
 }
 
-.hot-item {
+.quick-icon {
+  width: 92rpx;
+  height: 92rpx;
+  border-radius: 22rpx;
   display: flex;
   align-items: center;
-  padding: 20rpx 8rpx;
-  border-bottom: 1rpx solid #f1f5f9;
-  
-  &:last-child {
-    border-bottom: none;
+  justify-content: center;
+  margin-bottom: 12rpx;
+  transition: transform 0.15s;
+
+  &.primary { background: #ecfdf5; }
+  &.orange { background: #fff7ed; }
+  &.green { background: #f0fdf4; }
+  &.blue { background: #eff6ff; }
+}
+
+.quick-name {
+  font-size: 24rpx;
+  color: #333333;
+}
+
+.icon-apply {
+  width: 36rpx;
+  height: 36rpx;
+  position: relative;
+
+  &::before {
+    content: '';
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    border: 3rpx solid #10b981;
+    border-radius: 6rpx;
   }
-  
-  .hot-rank {
-    width: 44rpx;
-    height: 44rpx;
-    border-radius: 12rpx;
-    background: #f1f5f9;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    margin-right: 16rpx;
-    font-size: 24rpx;
-    font-weight: 600;
-    color: #94a3b8;
-    
-    &.top {
-      background: #10b981;
-      color: #fff;
-    }
+  &::after {
+    content: '+';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    font-size: 28rpx;
+    color: #10b981;
+    font-weight: 700;
+    line-height: 1;
   }
-  
-  .hot-info {
-    flex: 1;
-    
-    .hot-name {
-      display: block;
-      font-size: 28rpx;
-      color: #1e293b;
-      margin-bottom: 4rpx;
-      font-weight: 500;
-    }
-    
-    .hot-sales {
-      font-size: 24rpx;
-      color: #94a3b8;
-    }
+}
+
+.icon-marketing {
+  width: 36rpx;
+  height: 36rpx;
+  position: relative;
+
+  &::before {
+    content: '';
+    position: absolute;
+    top: 50%;
+    left: 0;
+    transform: translateY(-50%);
+    width: 26rpx;
+    height: 16rpx;
+    background: #f97316;
+    border-radius: 2rpx 0 0 2rpx;
   }
-  
-  .hot-progress {
-    width: 80rpx;
-    height: 8rpx;
-    background: #f1f5f9;
-    border-radius: 4rpx;
-    overflow: hidden;
-    
-    .hot-progress-bar {
-      height: 100%;
-      background: #f97316;
-      border-radius: 4rpx;
-    }
+  &::after {
+    content: '';
+    position: absolute;
+    top: 50%;
+    right: 0;
+    transform: translateY(-50%);
+    width: 0;
+    height: 0;
+    border-top: 14rpx solid transparent;
+    border-bottom: 14rpx solid transparent;
+    border-left: 14rpx solid #f97316;
+  }
+}
+
+.icon-staff {
+  width: 32rpx;
+  height: 36rpx;
+  position: relative;
+
+  &::before {
+    content: '';
+    position: absolute;
+    top: 0;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 18rpx;
+    height: 18rpx;
+    background: #22c55e;
+    border-radius: 50%;
+  }
+  &::after {
+    content: '';
+    position: absolute;
+    bottom: 0;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 30rpx;
+    height: 14rpx;
+    background: #22c55e;
+    border-radius: 14rpx 14rpx 0 0;
+  }
+}
+
+.icon-shop-quick {
+  width: 36rpx;
+  height: 36rpx;
+  position: relative;
+
+  &::before {
+    content: '';
+    position: absolute;
+    top: 0;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 0;
+    height: 0;
+    border-left: 20rpx solid transparent;
+    border-right: 20rpx solid transparent;
+    border-bottom: 14rpx solid #3b82f6;
+  }
+  &::after {
+    content: '';
+    position: absolute;
+    bottom: 0;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 30rpx;
+    height: 20rpx;
+    background: #3b82f6;
+    border-radius: 2rpx;
   }
 }
 </style>

+ 46 - 0
haha-service/src/main/java/com/haha/service/impl/DashboardServiceImpl.java

@@ -153,6 +153,21 @@ public class DashboardServiceImpl implements DashboardService {
         result.put("totalShops", 0);
         result.put("activeShops", 0);
 
+        // 本月销售额和订单量
+        LocalDateTime monthStart = LocalDateTime.of(LocalDate.now().withDayOfMonth(1), LocalTime.MIN);
+        LocalDateTime monthEnd = LocalDateTime.now();
+        
+        LambdaQueryWrapper<Order> monthPaidWrapper = new LambdaQueryWrapper<>();
+        monthPaidWrapper.eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
+                .ge(Order::getPayTime, monthStart)
+                .le(Order::getPayTime, monthEnd);
+        List<Order> monthPaidOrders = orderService.list(monthPaidWrapper);
+        BigDecimal monthSales = monthPaidOrders.stream()
+                .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+        result.put("monthSales", monthSales.setScale(2, RoundingMode.HALF_UP).toString());
+        result.put("monthOrders", monthPaidOrders.size());
+
         return result;
     }
 
@@ -383,6 +398,37 @@ public class DashboardServiceImpl implements DashboardService {
         result.put("pendingAfterSale", 0);  // 售后待审核数
         result.put("abnormalActivities", 0); // 异常待处理数
         result.put("complaints", 0);         // 投诉建议数
+        
+        // 待办事项相关数据
+        // 待处理退款数(售后待审核)
+        result.put("pendingRefunds", 0); // TODO: 后续实现售后模块后从售后表查询
+        
+        // 待处理异常数(设备异常告警)
+        try {
+            long pendingAlerts = deviceService.lambdaQuery()
+                    .eq(Device::getStatus, 3) // 假设3为异常状态
+                    .count();
+            result.put("pendingAlerts", pendingAlerts);
+        } catch (Exception e) {
+            result.put("pendingAlerts", 0);
+        }
+        
+        // 未支付订单数(已经在上面计算过)
+        // result.put("unpaidOrders", unpaidOrders);
+        
+        // 待补货数(低库存SKU数量)
+        try {
+            List<Map<String, Object>> lowStockList = deviceInventoryMapper.selectLowStockInventories();
+            result.put("lowStockItems", lowStockList.size());
+        } catch (Exception e) {
+            result.put("lowStockItems", 0);
+        }
+        
+        // 待开发票数
+        result.put("pendingInvoices", 0); // TODO: 后续实现发票模块后从发票表查询
+        
+        // 临期商品在售数
+        result.put("expiringProducts", 0); // TODO: 后续实现商品效期管理后查询
         result.put("skuSuggestions", 0);     // SKU建议数
 
         return result;