Sfoglia il codice sorgente

feat: 重新设计所有报表页面,增加多样化图表和布局(仪表盘、漏斗图、雷达图、玫瑰图、排名卡片等)

docker 2 mesi fa
parent
commit
16cbcb29b5

+ 113 - 165
src/views/report/ChannelPerformanceView.vue

@@ -6,84 +6,64 @@
         <h1>渠道绩效报表</h1>
         <p>分析各渠道GMV占比、增长率、库存周转和盈利能力,优化渠道资源配置。</p>
       </div>
-      <div class="chip-list">
-        <span class="chip">渠道对比</span>
-        <span class="chip">绩效排名</span>
-      </div>
-    </section>
-
-    <section class="glass-card section-card">
-      <el-form inline class="filter-form">
-        <el-form-item label="时间范围">
-          <el-date-picker v-model="filters.dateRange" type="daterange" range-separator="至" start-placeholder="开始" end-placeholder="结束" style="width:240px" />
-        </el-form-item>
-        <el-form-item label="渠道">
-          <el-select v-model="filters.channel" placeholder="全部渠道" clearable style="width:140px">
-            <el-option label="Shopify" value="Shopify" />
-            <el-option label="TikTok Shop" value="TikTok Shop" />
-            <el-option label="Amazon" value="Amazon" />
-          </el-select>
-        </el-form-item>
-        <el-form-item>
-          <el-button type="primary" @click="loadData">查询</el-button>
-          <el-button @click="resetFilters">重置</el-button>
-        </el-form-item>
-      </el-form>
     </section>
 
-    <section class="stat-grid" style="grid-template-columns:repeat(4, 1fr)">
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">总GMV</div>
-        <div class="stat-card__value" style="font-size:22px;color:var(--cb-primary)">$328,560</div>
-        <div class="stat-card__trend trend-up">+12.5% ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">活跃渠道</div>
-        <div class="stat-card__value" style="font-size:22px">3</div>
-        <div class="stat-card__trend">个</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">平均毛利率</div>
-        <div class="stat-card__value" style="font-size:22px;color:var(--cb-success)">38.2%</div>
-        <div class="stat-card__trend trend-up">+2.1pp ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">库存周转</div>
-        <div class="stat-card__value" style="font-size:22px">28.5天</div>
-        <div class="stat-card__trend trend-down">-3.2天 ↓</div>
-      </article>
+    <section class="glass-card section-card" style="padding:20px">
+      <el-row :gutter="24">
+        <el-col :span="6" v-for="ch in channels" :key="ch.name">
+          <div class="channel-card" :style="{ borderLeftColor: ch.color }">
+            <div class="channel-card__header">
+              <div class="channel-card__dot" :style="{ backgroundColor: ch.color }"></div>
+              <div class="channel-card__name">{{ ch.name }}</div>
+            </div>
+            <div class="channel-card__gmv">${{ ch.gmv.toLocaleString() }}</div>
+            <div class="channel-card__growth" :class="ch.growth >= 0 ? 'trend-up' : 'trend-down'">
+              {{ ch.growth >= 0 ? '↑' : '↓' }} {{ Math.abs(ch.growth) }}%
+            </div>
+            <div class="channel-card__footer">
+              <span>客单价: ${{ ch.avgOrder }}</span>
+              <span>订单: {{ ch.orders }}</span>
+            </div>
+          </div>
+        </el-col>
+      </el-row>
     </section>
 
     <section class="page-grid page-grid--two">
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">渠道GMV占比</h3>
-        <v-chart :option="gmvShareOption" autoresize style="height:280px" />
+        <h3 style="margin:0 0 16px">渠道占比与增长</h3>
+        <v-chart :option="channelCompareOption" autoresize style="height:300px" />
       </article>
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">各渠道增长率对比</h3>
-        <v-chart :option="growthCompareOption" autoresize style="height:280px" />
+        <h3 style="margin:0 0 16px">盈利能力雷达图</h3>
+        <v-chart :option="radarOption" autoresize style="height:300px" />
       </article>
     </section>
 
     <section class="glass-card section-card">
       <h3 style="margin:0 0 16px">渠道绩效明细</h3>
-      <el-table :data="channelPerformance" stripe v-loading="loading">
-        <el-table-column prop="channel" label="渠道" width="130">
+      <el-table :data="channelData" stripe>
+        <el-table-column prop="channel" label="渠道" width="140">
           <template #default="{ row }">
             <div style="display:flex;align-items:center;gap:8px">
-              <span class="channel-dot" :style="{ backgroundColor: row.color }"></span>
+              <div class="channel-dot" :style="{ backgroundColor: row.color }"></div>
               {{ row.channel }}
             </div>
           </template>
         </el-table-column>
-        <el-table-column prop="shopCount" label="店铺数" width="80" />
         <el-table-column prop="gmv" label="GMV" width="130">
           <template #default="{ row }">
-            <span style="font-weight:600">${{ row.gmv.toLocaleString() }}</span>
+            <span style="font-weight:600;color:var(--cb-primary)">${{ row.gmv.toLocaleString() }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="orders" label="订单数" width="90" />
+        <el-table-column prop="avgOrder" label="客单价" width="100" />
+        <el-table-column prop="profitRate" label="毛利率" width="100">
+          <template #default="{ row }">
+            <el-progress :percentage="row.profitRate" :stroke-width="10" :show-text="false" :color="row.profitRate >= 35 ? '#67C23A' : row.profitRate >= 25 ? '#E6A23C' : '#F56C6C'" />
+            <span style="font-size:12px">{{ row.profitRate }}%</span>
           </template>
         </el-table-column>
-        <el-table-column prop="orderCount" label="订单数" width="100" />
-        <el-table-column prop="avgOrderValue" label="客单价" width="100" />
         <el-table-column prop="growth" label="增长率" width="100">
           <template #default="{ row }">
             <span :class="row.growth >= 0 ? 'trend-up' : 'trend-down'">
@@ -91,172 +71,140 @@
             </span>
           </template>
         </el-table-column>
-        <el-table-column prop="profitRate" label="毛利率" width="90">
-          <template #default="{ row }">
-            <el-tag :type="row.profitRate >= 35 ? 'success' : row.profitRate >= 25 ? 'warning' : 'danger'" size="small">
-              {{ row.profitRate }}%
-            </el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column prop="inventoryTurnover" label="库存周转" width="100">
+        <el-table-column prop="inventoryDays" label="库存周转" width="100">
           <template #default="{ row }">
-            {{ row.inventoryTurnover }}天
+            {{ row.inventoryDays }}天
           </template>
         </el-table-column>
-        <el-table-column prop="rating" label="店铺评分" width="100">
+        <el-table-column prop="rating" label="评分" width="120">
           <template #default="{ row }">
             <el-rate v-model="row.rating" disabled text-color="#ff9900" />
           </template>
         </el-table-column>
-        <el-table-column label="操作" width="100" fixed="right">
-          <template #default="{ row }">
-            <el-button link type="primary" @click="viewDetail(row)">详情</el-button>
-          </template>
-        </el-table-column>
       </el-table>
     </section>
 
-    <section class="page-grid page-grid--two">
+    <section class="page-grid" style="grid-template-columns: 2fr 1fr;">
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">各渠道月度GMV趋势</h3>
-        <v-chart :option="monthlyTrendOption" autoresize style="height:280px" />
+        <h3 style="margin:0 0 16px">月度GMV趋势</h3>
+        <v-chart :option="monthlyTrendOption" autoresize style="height:260px" />
       </article>
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">各渠道盈利能力对比</h3>
-        <v-chart :option="profitCompareOption" autoresize style="height:280px" />
+        <h3 style="margin:0 0 16px">利润率对比</h3>
+        <v-chart :option="profitRateCompare" autoresize style="height:260px" />
       </article>
     </section>
   </div>
 </template>
 
 <script setup lang="ts">
-import { onMounted, ref, computed } from 'vue';
+import { ref, computed, onMounted } from 'vue';
 import VChart from 'vue-echarts';
 import { use } from 'echarts/core';
 import { CanvasRenderer } from 'echarts/renderers';
-import { LineChart, BarChart, PieChart } from 'echarts/charts';
+import { LineChart, BarChart, PieChart, RadarChart } from 'echarts/charts';
 import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/components';
 
-use([CanvasRenderer, LineChart, BarChart, PieChart, GridComponent, TooltipComponent, LegendComponent]);
+use([CanvasRenderer, LineChart, BarChart, PieChart, RadarChart, GridComponent, TooltipComponent, LegendComponent]);
 
 const loading = ref(false);
 
-const filters = ref({
-  dateRange: null as [Date, Date] | null,
-  channel: ''
-});
+const channels = ref([
+  { name: 'Shopify', gmv: 158200, orders: 856, avgOrder: 184.8, growth: 15.2, color: '#409EFF' },
+  { name: 'TikTok Shop', gmv: 89200, orders: 428, avgOrder: 208.4, growth: 28.5, color: '#67C23A' },
+  { name: 'Amazon', gmv: 81200, orders: 385, avgOrder: 211.0, growth: 8.6, color: '#E6A23C' }
+]);
 
-const channelPerformance = ref([
-  { channel: 'Shopify', shopCount: 2, gmv: 158200, orderCount: 856, avgOrderValue: 184.8, growth: 15.2, profitRate: 42.5, inventoryTurnover: 25.2, rating: 4.8, color: '#409EFF' },
-  { channel: 'TikTok Shop', shopCount: 3, gmv: 89200, orderCount: 428, avgOrderValue: 208.4, growth: 28.5, profitRate: 35.8, inventoryTurnover: 30.5, rating: 4.5, color: '#67C23A' },
-  { channel: 'Amazon', shopCount: 2, gmv: 81200, orderCount: 385, avgOrderValue: 211.0, growth: 8.6, profitRate: 32.1, inventoryTurnover: 28.8, rating: 4.3, color: '#E6A23C' }
+const channelData = ref([
+  { channel: 'Shopify', gmv: 158200, orders: 856, avgOrder: 184.8, profitRate: 42, growth: 15.2, inventoryDays: 25, rating: 4.8, color: '#409EFF' },
+  { channel: 'TikTok Shop', gmv: 89200, orders: 428, avgOrder: 208.4, profitRate: 36, growth: 28.5, inventoryDays: 30, rating: 4.5, color: '#67C23A' },
+  { channel: 'Amazon', gmv: 81200, orders: 385, avgOrder: 211.0, profitRate: 32, growth: 8.6, inventoryDays: 28, rating: 4.3, color: '#E6A23C' }
 ]);
 
 const months = ['1月', '2月', '3月', '4月'];
 
-const gmvShareOption = computed(() => ({
-  tooltip: { trigger: 'item', formatter: '{b}: ${c} ({d}%)' },
-  legend: { orient: 'vertical', right: 20, top: 'center' },
-  series: [{
-    type: 'pie',
-    radius: ['40%', '70%'],
-    center: ['35%', '50%'],
-    data: [
-      { value: 158200, name: 'Shopify', itemStyle: { color: '#409EFF' } },
-      { value: 89200, name: 'TikTok Shop', itemStyle: { color: '#67C23A' } },
-      { value: 81200, name: 'Amazon', itemStyle: { color: '#E6A23C' } }
-    ]
-  }]
+const channelCompareOption = computed(() => ({
+  tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
+  legend: { data: ['Shopify', 'TikTok Shop', 'Amazon'], bottom: 0 },
+  grid: { left: 60, right: 20, top: 20, bottom: 50 },
+  xAxis: { type: 'category', data: months },
+  yAxis: { type: 'value', axisLabel: { formatter: '${value}' } },
+  series: [
+    { name: 'Shopify', type: 'bar', data: [125600, 138200, 152800, 158200], itemStyle: { color: '#409EFF', borderRadius: [4, 4, 0, 0] } },
+    { name: 'TikTok Shop', type: 'bar', data: [65800, 72500, 82800, 89200], itemStyle: { color: '#67C23A', borderRadius: [4, 4, 0, 0] } },
+    { name: 'Amazon', type: 'bar', data: [72000, 75800, 79200, 81200], itemStyle: { color: '#E6A23C', borderRadius: [4, 4, 0, 0] } }
+  ]
 }));
 
-const growthCompareOption = computed(() => ({
-  tooltip: { trigger: 'axis' },
-  grid: { left: 60, right: 20, top: 20, bottom: 30 },
-  xAxis: { type: 'category', data: ['Shopify', 'TikTok Shop', 'Amazon'] },
-  yAxis: { type: 'value', axisLabel: { formatter: '{value}%' } },
+const radarOption = computed(() => ({
+  tooltip: {},
+  radar: {
+    indicator: [
+      { name: 'GMV', max: 200000 },
+      { name: '增长率', max: 35 },
+      { name: '利润率', max: 50 },
+      { name: '客单价', max: 250 },
+      { name: '周转率', max: 35 }
+    ],
+    center: ['50%', '55%'],
+    radius: '65%'
+  },
   series: [{
-    name: '增长率',
-    type: 'bar',
-    data: [15.2, 28.5, 8.6],
-    itemStyle: { color: '#409EFF', borderRadius: [4, 4, 0, 0] }
+    type: 'radar',
+    data: [
+      { value: [158200, 15.2, 42, 184.8, 25], name: 'Shopify', areaStyle: { color: 'rgba(64, 158, 255, 0.3)' }, lineStyle: { color: '#409EFF' }, itemStyle: { color: '#409EFF' } },
+      { value: [89200, 28.5, 36, 208.4, 30], name: 'TikTok Shop', areaStyle: { color: 'rgba(103, 194, 58, 0.3)' }, lineStyle: { color: '#67C23A' }, itemStyle: { color: '#67C23A' } },
+      { value: [81200, 8.6, 32, 211.0, 28], name: 'Amazon', areaStyle: { color: 'rgba(230, 162, 60, 0.3)' }, lineStyle: { color: '#E6A23C' }, itemStyle: { color: '#E6A23C' } }
+    ]
   }]
 }));
 
 const monthlyTrendOption = computed(() => ({
   tooltip: { trigger: 'axis' },
-  grid: { left: 60, right: 20, top: 20, bottom: 30 },
-  xAxis: { type: 'category', data: months },
+  legend: { data: ['Shopify', 'TikTok Shop', 'Amazon'], bottom: 0 },
+  grid: { left: 60, right: 20, top: 20, bottom: 50 },
+  xAxis: { type: 'category', data: months, boundaryGap: false },
   yAxis: { type: 'value', axisLabel: { formatter: '${value}' } },
   series: [
-    {
-      name: 'Shopify',
-      type: 'line',
-      smooth: true,
-      data: [125600, 138200, 152800, 158200],
-      itemStyle: { color: '#409EFF' }
-    },
-    {
-      name: 'TikTok Shop',
-      type: 'line',
-      smooth: true,
-      data: [65800, 72500, 82800, 89200],
-      itemStyle: { color: '#67C23A' }
-    },
-    {
-      name: 'Amazon',
-      type: 'line',
-      smooth: true,
-      data: [72000, 75800, 79200, 81200],
-      itemStyle: { color: '#E6A23C' }
-    }
+    { name: 'Shopify', type: 'line', smooth: true, data: [125600, 138200, 152800, 158200], areaStyle: { opacity: 0.1 }, itemStyle: { color: '#409EFF' } },
+    { name: 'TikTok Shop', type: 'line', smooth: true, data: [65800, 72500, 82800, 89200], areaStyle: { opacity: 0.1 }, itemStyle: { color: '#67C23A' } },
+    { name: 'Amazon', type: 'line', smooth: true, data: [72000, 75800, 79200, 81200], areaStyle: { opacity: 0.1 }, itemStyle: { color: '#E6A23C' } }
   ]
 }));
 
-const profitCompareOption = computed(() => ({
+const profitRateCompare = computed(() => ({
   tooltip: { trigger: 'axis' },
   grid: { left: 60, right: 20, top: 20, bottom: 30 },
   xAxis: { type: 'category', data: ['Shopify', 'TikTok Shop', 'Amazon'] },
-  yAxis: { type: 'value', axisLabel: { formatter: '${value}' } },
-  series: [
-    {
-      name: '销售额',
-      type: 'bar',
-      data: [158200, 89200, 81200],
-      itemStyle: { color: '#409EFF', borderRadius: [4, 4, 0, 0] }
+  yAxis: { type: 'value', axisLabel: { formatter: '{value}%' }, max: 50 },
+  series: [{
+    type: 'bar',
+    data: [42, 36, 32],
+    itemStyle: {
+      color: (params: any) => {
+        const colors = ['#409EFF', '#67C23A', '#E6A23C'];
+        return colors[params.dataIndex];
+      },
+      borderRadius: [4, 4, 0, 0]
     },
-    {
-      name: '毛利',
-      type: 'bar',
-      data: [67235, 31936, 26065],
-      itemStyle: { color: '#67C23A', borderRadius: [4, 4, 0, 0] }
-    }
-  ]
+    label: { show: true, position: 'top', formatter: '{c}%' }
+  }]
 }));
 
-const loadData = () => {
-  loading.value = true;
-  setTimeout(() => { loading.value = false; }, 300);
-};
-
-const resetFilters = () => {
-  filters.value = { dateRange: null, channel: '' };
-};
-
-const viewDetail = (row: any) => {
-  console.log('View channel detail:', row);
-};
+const loadData = () => { loading.value = true; setTimeout(() => { loading.value = false; }, 300); };
 
 onMounted(loadData);
 </script>
 
 <style scoped>
-.filter-form :deep(.el-form-item) { margin-bottom: 0; }
-.channel-dot {
-  width: 10px;
-  height: 10px;
-  border-radius: 50%;
-  display: inline-block;
-}
+.channel-card { background: linear-gradient(135deg, rgba(255,255,255,1), rgba(248,249,250,1)); border-left: 4px solid; border-radius: 8px; padding: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.04); }
+.channel-card__header { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
+.channel-card__dot { width: 10px; height: 10px; border-radius: 50%; }
+.channel-card__name { font-weight: 600; color: var(--cb-text-primary); }
+.channel-card__gmv { font-size: 24px; font-weight: 700; color: var(--cb-text-primary); margin-bottom: 4px; }
+.channel-card__growth { font-size: 13px; margin-bottom: 8px; }
+.channel-card__footer { display: flex; justify-content: space-between; font-size: 12px; color: var(--cb-text-soft); padding-top: 8px; border-top: 1px solid #f0f0f0; }
+.channel-dot { width: 10px; height: 10px; border-radius: 50%; }
 .trend-up { color: var(--el-color-success); }
 .trend-down { color: var(--el-color-danger); }
 </style>

+ 202 - 165
src/views/report/CustomerAnalysisView.vue

@@ -6,227 +6,264 @@
         <h1>客户分析报表</h1>
         <p>分析新客/老客占比、复购率、客单价分布和地域分布,支持客户画像和精准营销。</p>
       </div>
-      <div class="chip-list">
-        <span class="chip">客户画像</span>
-        <span class="chip">复购分析</span>
-      </div>
-    </section>
-
-    <section class="glass-card section-card">
-      <el-form inline class="filter-form">
-        <el-form-item label="时间范围">
-          <el-date-picker v-model="filters.dateRange" type="daterange" range-separator="至" start-placeholder="开始" end-placeholder="结束" style="width:240px" />
-        </el-form-item>
-        <el-form-item label="客户类型">
-          <el-select v-model="filters.customerType" placeholder="全部" clearable style="width:120px">
-            <el-option label="新客" value="new" />
-            <el-option label="老客" value="returning" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="渠道">
-          <el-select v-model="filters.channel" placeholder="全部渠道" clearable style="width:140px">
-            <el-option label="Shopify" value="Shopify" />
-            <el-option label="TikTok Shop" value="TikTok Shop" />
-            <el-option label="Amazon" value="Amazon" />
-          </el-select>
-        </el-form-item>
-        <el-form-item>
-          <el-button type="primary" @click="loadData">查询</el-button>
-          <el-button @click="resetFilters">重置</el-button>
-        </el-form-item>
-      </el-form>
     </section>
 
-    <section class="stat-grid" style="grid-template-columns:repeat(5, 1fr)">
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">客户总数</div>
-        <div class="stat-card__value" style="font-size:22px;color:var(--cb-primary)">12,586</div>
-        <div class="stat-card__trend trend-up">+8.5% ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">新客数</div>
-        <div class="stat-card__value" style="font-size:22px">4,852</div>
-        <div class="stat-card__trend">占比38.5%</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">老客数</div>
-        <div class="stat-card__value" style="font-size:22px">7,734</div>
-        <div class="stat-card__trend">占比61.5%</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">复购率</div>
-        <div class="stat-card__value" style="font-size:22px;color:var(--cb-success)">18.5%</div>
-        <div class="stat-card__trend trend-up">+2.1% ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">平均客单价</div>
-        <div class="stat-card__value" style="font-size:22px">¥1,852</div>
-        <div class="stat-card__trend trend-up">+5.2% ↑</div>
-      </article>
+    <section class="glass-card section-card" style="padding:20px">
+      <el-row :gutter="24">
+        <el-col :span="8">
+          <div class="funnel-card">
+            <div class="funnel-card__title">客户漏斗</div>
+            <v-chart :option="customerFunnel" autoresize style="height:280px" />
+          </div>
+        </el-col>
+        <el-col :span="16">
+          <div class="stats-row">
+            <div class="stat-box">
+              <div class="stat-box__icon" style="background:linear-gradient(135deg,#409EFF,#67C23A)">
+                <el-icon><User /></el-icon>
+              </div>
+              <div class="stat-box__content">
+                <div class="stat-box__value">12,586</div>
+                <div class="stat-box__label">客户总数</div>
+                <div class="stat-box__trend trend-up">+8.5% ↑</div>
+              </div>
+            </div>
+            <div class="stat-box">
+              <div class="stat-box__icon" style="background:linear-gradient(135deg,#67C23A,#E6A23C)">
+                <el-icon><UserPlus /></el-icon>
+              </div>
+              <div class="stat-box__content">
+                <div class="stat-box__value">4,852</div>
+                <div class="stat-box__label">新客户</div>
+                <div class="stat-box__trend">占比38.5%</div>
+              </div>
+            </div>
+            <div class="stat-box">
+              <div class="stat-box__icon" style="background:linear-gradient(135deg,#E6A23C,#F56C6C)">
+                <el-icon><Refresh /></el-icon>
+              </div>
+              <div class="stat-box__content">
+                <div class="stat-box__value">18.5%</div>
+                <div class="stat-box__label">复购率</div>
+                <div class="stat-box__trend trend-up">+2.1% ↑</div>
+              </div>
+            </div>
+            <div class="stat-box">
+              <div class="stat-box__icon" style="background:linear-gradient(135deg,#F56C6C,#909399)">
+                <el-icon><Wallet /></el-icon>
+              </div>
+              <div class="stat-box__content">
+                <div class="stat-box__value">¥1,852</div>
+                <div class="stat-box__label">平均客单价</div>
+                <div class="stat-box__trend trend-up">+5.2% ↑</div>
+              </div>
+            </div>
+          </div>
+        </el-col>
+      </el-row>
     </section>
 
     <section class="page-grid page-grid--two">
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">新客/老客占比</h3>
-        <v-chart :option="customerTypeOption" autoresize style="height:280px" />
+        <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
+          <h3 style="margin:0">客户类型分布</h3>
+          <el-radio-group v-model="customerView" size="small">
+            <el-radio-button label="pie">占比</el-radio-button>
+            <el-radio-button label="bar">趋势</el-radio-button>
+          </el-radio-group>
+        </div>
+        <v-chart :option="customerTypeChart" autoresize style="height:280px" />
       </article>
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">客单价分布</h3>
-        <v-chart :option="orderValueDistOption" autoresize style="height:280px" />
-      </article>
-    </section>
-
-    <section class="page-grid page-grid--two">
-      <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">地域分布 TOP 10</h3>
-        <el-table :data="regionDistribution" stripe size="small">
-          <el-table-column prop="rank" label="排名" width="60" />
-          <el-table-column prop="region" label="国家/地区" width="120" />
-          <el-table-column prop="customerCount" label="客户数" width="90" />
-          <el-table-column prop="orderCount" label="订单数" width="90" />
-          <el-table-column prop="gmv" label="GMV" width="110">
+        <h3 style="margin:0 0 16px">TOP 10 高价值客户</h3>
+        <el-table :data="vipCustomers" stripe size="small">
+          <el-table-column prop="rank" label="排名" width="50">
+            <template #default="{ row }">
+              <span :class="row.rank <= 3 ? 'vip-rank vip-rank--top' : 'vip-rank'">{{ row.rank }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="name" label="客户" width="120" />
+          <el-table-column prop="totalAmount" label="累计消费" width="100">
             <template #default="{ row }">
-              <span style="font-weight:600">${{ row.gmv.toLocaleString() }}</span>
+              <span class="amount-text">¥{{ row.totalAmount.toLocaleString() }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="orderCount" label="订单数" width="70" />
+          <el-table-column prop="vipLevel" label="等级" width="70">
+            <template #default="{ row }">
+              <el-tag :type="row.vipLevel === '钻石' ? 'danger' : row.vipLevel === '金牌' ? 'warning' : 'info'" size="small">
+                {{ row.vipLevel }}
+              </el-tag>
             </template>
           </el-table-column>
-          <el-table-column prop="avgOrderValue" label="客单价" width="100" />
         </el-table>
       </article>
-      <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">复购周期分析</h3>
-        <v-chart :option="repurchaseCycleOption" autoresize style="height:260px" />
-      </article>
     </section>
 
-    <section class="glass-card section-card">
-      <h3 style="margin:0 0 16px">客户明细</h3>
-      <el-table :data="customerDetail" stripe v-loading="loading">
-        <el-table-column prop="customerId" label="客户ID" width="120" />
-        <el-table-column prop="name" label="客户名称" width="120" />
-        <el-table-column prop="channel" label="渠道" width="100" />
-        <el-table-column prop="totalOrders" label="累计订单" width="90" />
-        <el-table-column prop="totalAmount" label="累计消费" width="120">
-          <template #default="{ row }">
-            <span style="font-weight:600">${{ row.totalAmount.toLocaleString() }}</span>
-          </template>
-        </el-table-column>
-        <el-table-column prop="avgOrderValue" label="平均客单价" width="120" />
-        <el-table-column prop="lastOrderDate" label="最近下单" width="110" />
-        <el-table-column prop="customerType" label="客户类型" width="90">
-          <template #default="{ row }">
-            <el-tag :type="row.customerType === '新客' ? 'primary' : 'success'" size="small">
-              {{ row.customerType }}
-            </el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column prop="vipLevel" label="VIP等级" width="90">
-          <template #default="{ row }">
-            <el-tag :type="row.vipLevel === '钻石' ? 'danger' : row.vipLevel === '金牌' ? 'warning' : 'info'" size="small">
-              {{ row.vipLevel }}
-            </el-tag>
-          </template>
-        </el-table-column>
-      </el-table>
+    <section class="page-grid" style="grid-template-columns: 1fr 1fr 1fr;">
+      <article class="glass-card section-card">
+        <h3 style="margin:0 0 16px">地域分布</h3>
+        <v-chart :option="regionChart" autoresize style="height:240px" />
+      </article>
+      <article class="glass-card section-card">
+        <h3 style="margin:0 0 16px">复购周期</h3>
+        <v-chart :option="repurchaseChart" autoresize style="height:240px" />
+      </article>
+      <article class="glass-card section-card">
+        <h3 style="margin:0 0 16px">客单价分布</h3>
+        <v-chart :option="orderValueChart" autoresize style="height:240px" />
+      </article>
     </section>
   </div>
 </template>
 
 <script setup lang="ts">
-import { onMounted, ref, computed } from 'vue';
+import { ref, computed, onMounted } from 'vue';
+import { User, UserPlus, Refresh, Wallet } from '@element-plus/icons-vue';
 import VChart from 'vue-echarts';
 import { use } from 'echarts/core';
 import { CanvasRenderer } from 'echarts/renderers';
-import { LineChart, BarChart, PieChart } from 'echarts/charts';
+import { LineChart, BarChart, PieChart, FunnelChart } from 'echarts/charts';
 import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/components';
 
-use([CanvasRenderer, LineChart, BarChart, PieChart, GridComponent, TooltipComponent, LegendComponent]);
+use([CanvasRenderer, LineChart, BarChart, PieChart, FunnelChart, GridComponent, TooltipComponent, LegendComponent]);
 
 const loading = ref(false);
+const customerView = ref('pie');
 
-const filters = ref({
-  dateRange: null as [Date, Date] | null,
-  customerType: '',
-  channel: ''
-});
-
-const regionDistribution = ref([
-  { rank: 1, region: '美国', customerCount: 4250, orderCount: 8560, gmv: 128600, avgOrderValue: 150.2 },
-  { rank: 2, region: '英国', customerCount: 2860, orderCount: 5280, gmv: 89200, avgOrderValue: 169.0 },
-  { rank: 3, region: '日本', customerCount: 1950, orderCount: 3680, gmv: 65800, avgOrderValue: 178.8 },
-  { rank: 4, region: '德国', customerCount: 1280, orderCount: 2350, gmv: 42800, avgOrderValue: 182.1 },
-  { rank: 5, region: '法国', customerCount: 960, orderCount: 1820, gmv: 32600, avgOrderValue: 179.1 },
-  { rank: 6, region: '加拿大', customerCount: 820, orderCount: 1580, gmv: 28500, avgOrderValue: 180.4 },
-  { rank: 7, region: '澳大利亚', customerCount: 680, orderCount: 1290, gmv: 23800, avgOrderValue: 184.5 },
-  { rank: 8, region: '意大利', customerCount: 520, orderCount: 980, gmv: 17200, avgOrderValue: 175.5 },
-  { rank: 9, region: '西班牙', customerCount: 420, orderCount: 820, gmv: 14800, avgOrderValue: 180.5 },
-  { rank: 10, region: '荷兰', customerCount: 380, orderCount: 720, gmv: 13200, avgOrderValue: 183.3 }
-]);
-
-const customerDetail = ref([
-  { customerId: 'CUS001', name: 'John Smith', channel: 'Shopify', totalOrders: 12, totalAmount: 4856, avgOrderValue: 404.7, lastOrderDate: '2026-04-18', customerType: '老客', vipLevel: '钻石' },
-  { customerId: 'CUS002', name: 'Emma Johnson', channel: 'TikTok Shop', totalOrders: 8, totalAmount: 3280, avgOrderValue: 410.0, lastOrderDate: '2026-04-19', customerType: '老客', vipLevel: '金牌' },
-  { customerId: 'CUS003', name: 'Michael Brown', channel: 'Amazon', totalOrders: 1, totalAmount: 1280, avgOrderValue: 1280.0, lastOrderDate: '2026-04-20', customerType: '新客', vipLevel: '普通' },
-  { customerId: 'CUS004', name: 'Sarah Davis', channel: 'Shopify', totalOrders: 5, totalAmount: 2890, avgOrderValue: 578.0, lastOrderDate: '2026-04-17', customerType: '老客', vipLevel: '金牌' },
-  { customerId: 'CUS005', name: 'James Wilson', channel: 'Shopify', totalOrders: 15, totalAmount: 6850, avgOrderValue: 456.7, lastOrderDate: '2026-04-20', customerType: '老客', vipLevel: '钻石' },
-  { customerId: 'CUS006', name: 'Lisa Anderson', channel: 'TikTok Shop', totalOrders: 1, totalAmount: 890, avgOrderValue: 890.0, lastOrderDate: '2026-04-19', customerType: '新客', vipLevel: '普通' }
+const vipCustomers = ref([
+  { rank: 1, name: 'John Smith', totalAmount: 48560, orderCount: 12, vipLevel: '钻石' },
+  { rank: 2, name: 'Emma Johnson', totalAmount: 32800, orderCount: 8, vipLevel: '金牌' },
+  { rank: 3, name: 'James Wilson', totalAmount: 68500, orderCount: 15, vipLevel: '钻石' },
+  { rank: 4, name: 'Sarah Davis', totalAmount: 28900, orderCount: 5, vipLevel: '金牌' },
+  { rank: 5, name: 'Michael Brown', totalAmount: 12800, orderCount: 1, vipLevel: '普通' },
+  { rank: 6, name: 'Lisa Anderson', totalAmount: 8900, orderCount: 1, vipLevel: '普通' },
+  { rank: 7, name: 'David Lee', totalAmount: 15600, orderCount: 3, vipLevel: '银牌' },
+  { rank: 8, name: 'Jennifer Wang', totalAmount: 22800, orderCount: 6, vipLevel: '金牌' }
 ]);
 
-const customerTypeOption = computed(() => ({
-  tooltip: { trigger: 'item', formatter: '{b}: {c}人 ({d}%)' },
-  legend: { orient: 'vertical', right: 20, top: 'center' },
+const customerFunnel = computed(() => ({
+  tooltip: { trigger: 'item' },
   series: [{
-    type: 'pie',
-    radius: ['40%', '70%'],
-    center: ['35%', '50%'],
+    type: 'funnel',
+    left: '10%',
+    top: 30,
+    bottom: 30,
+    width: '80%',
+    min: 0,
+    max: 100,
+    minSize: '0%',
+    maxSize: '100%',
+    sort: 'descending',
+    gap: 4,
+    label: { show: true, position: 'inside', formatter: '{b}: {c}%' },
+    itemStyle: { borderColor: '#fff', borderWidth: 2 },
     data: [
-      { value: 4852, name: '新客', itemStyle: { color: '#409EFF' } },
-      { value: 7734, name: '老客', itemStyle: { color: '#67C23A' } }
+      { value: 100, name: '访问', itemStyle: { color: '#409EFF' } },
+      { value: 60, name: '加购', itemStyle: { color: '#67C23A' } },
+      { value: 40, name: '下单', itemStyle: { color: '#E6A23C' } },
+      { value: 25, name: '支付', itemStyle: { color: '#F56C6C' } },
+      { value: 15, name: '复购', itemStyle: { color: '#909399' } }
     ]
   }]
 }));
 
-const orderValueDistOption = computed(() => ({
+const customerTypeChart = computed(() => {
+  if (customerView.value === 'pie') {
+    return {
+      tooltip: { trigger: 'item', formatter: '{b}: {c}人 ({d}%)' },
+      series: [{
+        type: 'pie',
+        radius: ['40%', '70%'],
+        center: ['50%', '50%'],
+        roseType: 'radius',
+        itemStyle: { borderRadius: 8 },
+        data: [
+          { value: 4852, name: '新客户', itemStyle: { color: '#409EFF' } },
+          { value: 7734, name: '老客户', itemStyle: { color: '#67C23A' } }
+        ],
+        label: { color: '#666' }
+      }]
+    };
+  }
+  const weeks = ['第1周', '第2周', '第3周', '第4周'];
+  return {
+    tooltip: { trigger: 'axis' },
+    legend: { data: ['新客', '老客'], bottom: 0 },
+    grid: { left: 50, right: 20, top: 10, bottom: 40 },
+    xAxis: { type: 'category', data: weeks },
+    yAxis: { type: 'value' },
+    series: [
+      { name: '新客', type: 'bar', data: [1250, 1380, 1120, 1102], itemStyle: { color: '#409EFF', borderRadius: [4, 4, 0, 0] } },
+      { name: '老客', type: 'bar', data: [2150, 2280, 1890, 1414], itemStyle: { color: '#67C23A', borderRadius: [4, 4, 0, 0] } }
+    ]
+  };
+});
+
+const regionChart = computed(() => ({
   tooltip: { trigger: 'axis' },
-  grid: { left: 60, right: 20, top: 20, bottom: 30 },
-  xAxis: { type: 'category', data: ['0-100', '100-300', '300-500', '500-1000', '1000+'] },
+  grid: { left: 60, right: 20, top: 10, bottom: 30 },
+  xAxis: { type: 'category', data: ['美国', '英国', '日本', '德国', '法国'] },
   yAxis: { type: 'value' },
   series: [{
-    name: '客户数',
     type: 'bar',
-    data: [3250, 5280, 2850, 980, 226],
-    itemStyle: { color: '#409EFF', borderRadius: [4, 4, 0, 0] }
+    data: [4250, 2860, 1950, 1280, 960],
+    itemStyle: {
+      color: (params: any) => {
+        const colors = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399'];
+        return colors[params.dataIndex];
+      },
+      borderRadius: [0, 4, 4, 0]
+    }
   }]
 }));
 
-const repurchaseCycleOption = computed(() => ({
+const repurchaseChart = computed(() => ({
   tooltip: { trigger: 'axis' },
-  grid: { left: 60, right: 20, top: 20, bottom: 30 },
-  xAxis: { type: 'category', data: ['7天内', '7-15天', '15-30天', '30-60天', '60-90天', '90天以上'] },
+  grid: { left: 60, right: 20, top: 10, bottom: 30 },
+  xAxis: { type: 'category', data: ['7天内', '7-15天', '15-30天', '30-60天', '60天以上'] },
   yAxis: { type: 'value' },
   series: [{
-    name: '复购客户数',
     type: 'line',
     smooth: true,
-    data: [1250, 2180, 1850, 1280, 680, 320],
-    areaStyle: { opacity: 0.15 },
-    itemStyle: { color: '#67C23A' }
+    data: [1250, 2180, 1850, 1280, 680],
+    areaStyle: { opacity: 0.3 },
+    lineStyle: { width: 3 },
+    itemStyle: { color: '#67C23A' },
+    symbol: 'circle',
+    symbolSize: 8
   }]
 }));
 
-const loadData = () => {
-  loading.value = true;
-  setTimeout(() => { loading.value = false; }, 300);
-};
+const orderValueChart = computed(() => ({
+  tooltip: { trigger: 'axis' },
+  grid: { left: 60, right: 20, top: 10, bottom: 30 },
+  xAxis: { type: 'category', data: ['0-100', '100-300', '300-500', '500-1000', '1000+'] },
+  yAxis: { type: 'value' },
+  series: [{
+    type: 'bar',
+    data: [3250, 5280, 2850, 980, 226],
+    itemStyle: { color: '#E6A23C', borderRadius: [4, 4, 0, 0] },
+    barWidth: '50%'
+  }]
+}));
 
-const resetFilters = () => {
-  filters.value = { dateRange: null, customerType: '', channel: '' };
-};
+const loadData = () => { loading.value = true; setTimeout(() => { loading.value = false; }, 300); };
 
 onMounted(loadData);
 </script>
 
 <style scoped>
-.filter-form :deep(.el-form-item) { margin-bottom: 0; }
+.funnel-card { text-align: center; }
+.funnel-card__title { font-size: 14px; color: var(--cb-text-soft); margin-bottom: 12px; font-weight: 500; }
+.stats-row { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; }
+.stat-box { display: flex; align-items: center; gap: 12px; padding: 16px; background: linear-gradient(135deg, rgba(64, 158, 255, 0.08), rgba(103, 194, 58, 0.08)); border-radius: 12px; }
+.stat-box__icon { width: 44px; height: 44px; border-radius: 10px; display: flex; align-items: center; justify-content: center; color: white; font-size: 18px; }
+.stat-box__value { font-size: 20px; font-weight: 600; color: var(--cb-text-primary); }
+.stat-box__label { font-size: 12px; color: var(--cb-text-soft); }
+.stat-box__trend { font-size: 11px; margin-top: 2px; }
+.vip-rank { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; border-radius: 50%; background: #f0f0f0; font-size: 12px; font-weight: 600; }
+.vip-rank--top { background: linear-gradient(135deg, #FFD700, #FFA500); color: white; }
+.amount-text { color: var(--cb-primary); font-weight: 600; }
 .trend-up { color: var(--el-color-success); }
-.trend-down { color: var(--el-color-danger); }
 </style>

+ 142 - 179
src/views/report/MarketingReportView.vue

@@ -6,118 +6,92 @@
         <h1>营销报表</h1>
         <p>追踪促销ROI、优惠券核销率和活动效果,分析营销效率并优化投放策略。</p>
       </div>
-      <div class="chip-list">
-        <span class="chip">活动效果</span>
-        <span class="chip">ROI分析</span>
-      </div>
     </section>
 
-    <section class="glass-card section-card">
-      <el-form inline class="filter-form">
-        <el-form-item label="时间范围">
-          <el-date-picker v-model="filters.dateRange" type="daterange" range-separator="至" start-placeholder="开始" end-placeholder="结束" style="width:240px" />
-        </el-form-item>
-        <el-form-item label="活动类型">
-          <el-select v-model="filters.activityType" placeholder="全部" clearable style="width:130px">
-            <el-option label="折扣活动" value="discount" />
-            <el-option label="满减活动" value="off" />
-            <el-option label="买赠活动" value="gift" />
-            <el-option label="优惠券" value="coupon" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="状态">
-          <el-select v-model="filters.status" placeholder="全部" clearable style="width:120px">
-            <el-option label="进行中" value="进行中" />
-            <el-option label="已结束" value="已结束" />
-            <el-option label="未开始" value="未开始" />
-          </el-select>
-        </el-form-item>
-        <el-form-item>
-          <el-button type="primary" @click="loadData">查询</el-button>
-          <el-button @click="resetFilters">重置</el-button>
-        </el-form-item>
-      </el-form>
-    </section>
-
-    <section class="stat-grid" style="grid-template-columns:repeat(5, 1fr)">
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">活动数量</div>
-        <div class="stat-card__value" style="font-size:22px;color:var(--cb-primary)">28</div>
-        <div class="stat-card__trend">进行中: 8</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">优惠券核销</div>
-        <div class="stat-card__value" style="font-size:22px">12,580</div>
-        <div class="stat-card__trend">张</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">核销金额</div>
-        <div class="stat-card__value" style="font-size:22px;color:var(--cb-success)">¥458,200</div>
-        <div class="stat-card__trend trend-up">+18.5% ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">活动GMV</div>
-        <div class="stat-card__value" style="font-size:22px">¥1,856,000</div>
-        <div class="stat-card__trend trend-up">+25.3% ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">平均ROI</div>
-        <div class="stat-card__value" style="font-size:22px;color:var(--cb-success)">3.8x</div>
-        <div class="stat-card__trend trend-up">+0.5x ↑</div>
-      </article>
+    <section class="glass-card section-card" style="padding:20px">
+      <el-row :gutter="24">
+        <el-col :span="8">
+          <div class="chart-card">
+            <div class="chart-card__title">活动效果概览</div>
+            <v-chart :option="activityOverview" autoresize style="height:200px" />
+          </div>
+        </el-col>
+        <el-col :span="16">
+          <div style="display:grid;grid-template-columns:repeat(4,1fr);gap:16px">
+            <div class="metric-card">
+              <div class="metric-card__value" style="color:var(--cb-primary)">28</div>
+              <div class="metric-card__label">活动数量</div>
+              <div class="metric-card__sub">进行中: 8</div>
+            </div>
+            <div class="metric-card">
+              <div class="metric-card__value" style="color:var(--cb-success)">¥458,200</div>
+              <div class="metric-card__label">核销金额</div>
+              <div class="metric-card__sub">+18.5% ↑</div>
+            </div>
+            <div class="metric-card">
+              <div class="metric-card__value">¥1,856,000</div>
+              <div class="metric-card__label">活动GMV</div>
+              <div class="metric-card__sub">+25.3% ↑</div>
+            </div>
+            <div class="metric-card">
+              <div class="metric-card__value" style="color:var(--cb-success)">3.8x</div>
+              <div class="metric-card__label">平均ROI</div>
+              <div class="metric-card__sub">+0.5x ↑</div>
+            </div>
+          </div>
+        </el-col>
+      </el-row>
     </section>
 
-    <section class="page-grid page-grid--two">
+    <section class="page-grid" style="grid-template-columns: 1fr 1fr;">
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">活动效果趋势</h3>
-        <v-chart :option="activityTrendOption" autoresize style="height:280px" />
+        <h3 style="margin:0 0 16px">营销漏斗</h3>
+        <v-chart :option="marketingFunnel" autoresize style="height:280px" />
       </article>
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">各渠道活动效果</h3>
-        <v-chart :option="channelEffectOption" autoresize style="height:280px" />
+        <h3 style="margin:0 0 16px">活动效果对比</h3>
+        <v-chart :option="activityCompare" autoresize style="height:280px" />
       </article>
     </section>
 
-    <section class="page-grid page-grid--two">
-      <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">优惠券核销TOP</h3>
-        <el-table :data="couponTop" stripe size="small">
-          <el-table-column prop="rank" label="排名" width="60" />
-          <el-table-column prop="name" label="优惠券名称" min-width="160" show-overflow-tooltip />
-          <el-table-column prop="usedCount" label="核销数" width="90" />
-          <el-table-column prop="amount" label="核销金额" width="110">
-            <template #default="{ row }">
-              <span style="font-weight:600">¥{{ row.amount.toLocaleString() }}</span>
-            </template>
-          </el-table-column>
-          <el-table-column prop="roi" label="ROI" width="80">
-            <template #default="{ row }">
-              <span style="color:var(--cb-success)">{{ row.roi }}x</span>
-            </template>
-          </el-table-column>
-        </el-table>
-      </article>
-      <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">活动ROI对比</h3>
-        <v-chart :option="roiCompareOption" autoresize style="height:260px" />
-      </article>
+    <section class="glass-card section-card">
+      <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
+        <h3 style="margin:0">优惠券核销 TOP</h3>
+        <el-button type="primary" size="small">查看全部</el-button>
+      </div>
+      <div class="coupon-list">
+        <div v-for="(c, idx) in couponTop" :key="idx" class="coupon-item">
+          <div class="coupon-item__rank" :class="{ 'coupon-item__rank--top': idx < 3 }">{{ idx + 1 }}</div>
+          <div class="coupon-item__info">
+            <div class="coupon-item__name">{{ c.name }}</div>
+            <div class="coupon-item__meta">
+              <span>已核销: {{ c.usedCount }}张</span>
+              <span>核销率: {{ c.usedRate }}%</span>
+            </div>
+          </div>
+          <div class="coupon-item__amount">
+            <div class="coupon-item__value">¥{{ c.amount.toLocaleString() }}</div>
+            <el-tag :type="c.roi >= 4 ? 'success' : c.roi >= 3 ? 'warning' : 'info'" size="small">
+              ROI {{ c.roi }}x
+            </el-tag>
+          </div>
+        </div>
+      </div>
     </section>
 
     <section class="glass-card section-card">
       <h3 style="margin:0 0 16px">营销活动明细</h3>
-      <el-table :data="marketingDetail" stripe v-loading="loading">
-        <el-table-column prop="activityName" label="活动名称" min-width="180" show-overflow-tooltip />
-        <el-table-column prop="type" label="活动类型" width="100">
+      <el-table :data="marketingDetail" stripe>
+        <el-table-column prop="name" label="活动名称" min-width="160" />
+        <el-table-column prop="type" label="类型" width="100">
           <template #default="{ row }">
             <el-tag size="small">{{ row.type }}</el-tag>
           </template>
         </el-table-column>
         <el-table-column prop="channel" label="渠道" width="100" />
-        <el-table-column prop="startTime" label="开始时间" width="110" />
-        <el-table-column prop="endTime" label="结束时间" width="110" />
         <el-table-column prop="gmv" label="活动GMV" width="120">
           <template #default="{ row }">
-            <span style="font-weight:600">¥{{ row.gmv.toLocaleString() }}</span>
+            <span style="font-weight:600;color:var(--cb-primary)">¥{{ row.gmv.toLocaleString() }}</span>
           </template>
         </el-table-column>
         <el-table-column prop="cost" label="活动成本" width="110">
@@ -127,15 +101,14 @@
         </el-table-column>
         <el-table-column prop="roi" label="ROI" width="80">
           <template #default="{ row }">
-            <el-tag :type="row.roi >= 3 ? 'success' : row.roi >= 2 ? 'warning' : 'danger'" size="small">
-              {{ row.roi }}x
-            </el-tag>
+            <el-progress :percentage="(row.roi / 5) * 100" :stroke-width="6" :show-text="false" :color="row.roi >= 3 ? '#67C23A' : '#E6A23C'" />
+            <span style="font-size:12px">{{ row.roi }}x</span>
           </template>
         </el-table-column>
-        <el-table-column prop="participation" label="参与数" width="90" />
+        <el-table-column prop="participation" label="参与数" width="80" />
         <el-table-column prop="status" label="状态" width="90">
           <template #default="{ row }">
-            <el-tag :type="row.status === '进行中' ? 'success' : row.status === '已结束' ? 'info' : 'warning'" size="small">
+            <el-tag :type="row.status === '进行中' ? 'success' : 'info'" size="small">
               {{ row.status }}
             </el-tag>
           </template>
@@ -146,114 +119,104 @@
 </template>
 
 <script setup lang="ts">
-import { onMounted, ref, computed } from 'vue';
+import { ref, computed, onMounted } from 'vue';
 import VChart from 'vue-echarts';
 import { use } from 'echarts/core';
 import { CanvasRenderer } from 'echarts/renderers';
-import { LineChart, BarChart, PieChart } from 'echarts/charts';
+import { LineChart, BarChart, PieChart, FunnelChart } from 'echarts/charts';
 import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/components';
 
-use([CanvasRenderer, LineChart, BarChart, PieChart, GridComponent, TooltipComponent, LegendComponent]);
+use([CanvasRenderer, LineChart, BarChart, PieChart, FunnelChart, GridComponent, TooltipComponent, LegendComponent]);
 
 const loading = ref(false);
 
-const filters = ref({
-  dateRange: null as [Date, Date] | null,
-  activityType: '',
-  status: ''
-});
-
 const couponTop = ref([
-  { rank: 1, name: '新人专享满99减20', usedCount: 3280, amount: 65600, roi: 4.2 },
-  { rank: 2, name: '会员专享8折券', usedCount: 2850, amount: 45600, roi: 3.8 },
-  { rank: 3, name: '老客回归满149减30', usedCount: 1890, amount: 56700, roi: 4.5 },
-  { rank: 4, name: '限时9折券', usedCount: 1200, amount: 19200, roi: 3.2 },
-  { rank: 5, name: '新品兑换券', usedCount: 156, amount: 0, roi: 2.8 }
+  { name: '新人专享满99减20', usedCount: 3280, usedRate: 65.6, amount: 65600, roi: 4.2 },
+  { name: '会员专享8折券', usedCount: 2850, usedRate: 72.5, amount: 45600, roi: 3.8 },
+  { name: '老客回归满149减30', usedCount: 1890, usedRate: 63.0, amount: 56700, roi: 4.5 },
+  { name: '限时9折券', usedCount: 1200, usedRate: 60.0, amount: 19200, roi: 3.2 },
+  { name: '新品兑换券', usedCount: 156, usedRate: 31.2, amount: 0, roi: 2.8 }
 ]);
 
 const marketingDetail = ref([
-  { activityName: '4月大促活动', type: '折扣活动', channel: 'Shopify', startTime: '2026-04-01', endTime: '2026-04-30', gmv: 856000, cost: 198000, roi: 4.3, participation: 5280, status: '进行中' },
-  { activityName: '会员月活动', type: '优惠券', channel: 'Shopify', startTime: '2026-04-01', endTime: '2026-04-30', gmv: 428000, cost: 112000, roi: 3.8, participation: 2850, status: '进行中' },
-  { activityName: '新品首发活动', type: '买赠活动', channel: 'TikTok Shop', startTime: '2026-04-18', endTime: '2026-05-18', gmv: 285000, cost: 85000, roi: 3.4, participation: 1280, status: '进行中' },
-  { activityName: '春季促销', type: '满减活动', channel: 'Amazon', startTime: '2026-03-15', endTime: '2026-04-15', gmv: 528000, cost: 156000, roi: 3.4, participation: 3560, status: '已结束' },
-  { activityName: '复活节特惠', type: '折扣活动', channel: 'TikTok Shop', startTime: '2026-04-01', endTime: '2026-04-12', gmv: 186000, cost: 52000, roi: 3.6, participation: 1680, status: '已结束' }
+  { name: '4月大促活动', type: '折扣活动', channel: 'Shopify', gmv: 856000, cost: 198000, roi: 4.3, participation: 5280, status: '进行中' },
+  { name: '会员月活动', type: '优惠券', channel: 'Shopify', gmv: 428000, cost: 112000, roi: 3.8, participation: 2850, status: '进行中' },
+  { name: '新品首发活动', type: '买赠活动', channel: 'TikTok Shop', gmv: 285000, cost: 85000, roi: 3.4, participation: 1280, status: '进行中' },
+  { name: '春季促销', type: '满减活动', channel: 'Amazon', gmv: 528000, cost: 156000, roi: 3.4, participation: 3560, status: '已结束' }
 ]);
 
-const days = ['4/14', '4/15', '4/16', '4/17', '4/18', '4/19', '4/20'];
+const activityOverview = computed(() => ({
+  series: [{
+    type: 'pie',
+    radius: ['45%', '70%'],
+    center: ['50%', '50%'],
+    data: [
+      { value: 856000, name: '折扣活动', itemStyle: { color: '#409EFF' } },
+      { value: 428000, name: '优惠券', itemStyle: { color: '#67C23A' } },
+      { value: 285000, name: '买赠活动', itemStyle: { color: '#E6A23C' } },
+      { value: 528000, name: '满减活动', itemStyle: { color: '#F56C6C' } }
+    ],
+    label: { show: true, formatter: '{b}\n{d}%', color: '#666' },
+    itemStyle: { borderRadius: 8 }
+  }]
+}));
 
-const activityTrendOption = computed(() => ({
-  tooltip: { trigger: 'axis' },
-  grid: { left: 60, right: 20, top: 20, bottom: 30 },
-  xAxis: { type: 'category', data: days },
-  yAxis: { type: 'value', axisLabel: { formatter: '¥{value}' } },
-  series: [
-    {
-      name: '活动GMV',
-      type: 'bar',
-      data: [268000, 312000, 285000, 325000, 298000, 358000, 312000],
-      itemStyle: { color: '#409EFF', borderRadius: [4, 4, 0, 0] }
-    },
-    {
-      name: '活动成本',
-      type: 'line',
-      smooth: true,
-      yAxisIndex: 0,
-      data: [68000, 78000, 72000, 82000, 75000, 89000, 78000],
-      itemStyle: { color: '#E6A23C' }
-    }
-  ]
+const marketingFunnel = computed(() => ({
+  tooltip: { trigger: 'item' },
+  series: [{
+    type: 'funnel',
+    left: '10%',
+    width: '80%',
+    top: 30,
+    bottom: 30,
+    sort: 'descending',
+    gap: 3,
+    label: { show: true, position: 'inside', formatter: '{b}: {c}%' },
+    itemStyle: { borderColor: '#fff', borderWidth: 2 },
+    data: [
+      { value: 100, name: '曝光', itemStyle: { color: '#909399' } },
+      { value: 65, name: '点击', itemStyle: { color: '#409EFF' } },
+      { value: 40, name: '参与', itemStyle: { color: '#67C23A' } },
+      { value: 25, name: '下单', itemStyle: { color: '#E6A23C' } },
+      { value: 15, name: '核销', itemStyle: { color: '#F56C6C' } }
+    ]
+  }]
 }));
 
-const channelEffectOption = computed(() => ({
+const activityCompare = computed(() => ({
   tooltip: { trigger: 'axis' },
-  grid: { left: 60, right: 20, top: 20, bottom: 30 },
-  xAxis: { type: 'category', data: ['Shopify', 'TikTok Shop', 'Amazon'] },
-  yAxis: { type: 'value' },
+  legend: { data: ['GMV', 'ROI'], bottom: 0 },
+  grid: { left: 60, right: 20, top: 20, bottom: 50 },
+  xAxis: { type: 'category', data: ['折扣活动', '优惠券', '买赠活动', '满减活动'] },
+  yAxis: [
+    { type: 'value', name: 'GMV', axisLabel: { formatter: '¥{value}' } },
+    { type: 'value', name: 'ROI', splitLine: { show: false } }
+  ],
   series: [
-    {
-      name: 'GMV',
-      type: 'bar',
-      data: [856000, 428000, 528000],
-      itemStyle: { color: '#409EFF', borderRadius: [4, 4, 0, 0] }
-    },
-    {
-      name: 'ROI',
-      type: 'line',
-      smooth: true,
-      yAxisIndex: 0,
-      data: [4.3, 3.8, 3.4],
-      itemStyle: { color: '#67C23A' }
-    }
+    { name: 'GMV', type: 'bar', data: [856000, 428000, 285000, 528000], itemStyle: { color: '#409EFF', borderRadius: [4, 4, 0, 0] } },
+    { name: 'ROI', type: 'line', yAxisIndex: 1, smooth: true, data: [4.3, 3.8, 3.4, 3.4], lineStyle: { width: 3 }, itemStyle: { color: '#F56C6C' }, symbol: 'circle', symbolSize: 8 }
   ]
 }));
 
-const roiCompareOption = computed(() => ({
-  tooltip: { trigger: 'axis' },
-  grid: { left: 60, right: 20, top: 20, bottom: 30 },
-  xAxis: { type: 'category', data: ['折扣活动', '满减活动', '买赠活动', '优惠券'] },
-  yAxis: { type: 'value' },
-  series: [{
-    name: 'ROI',
-    type: 'bar',
-    data: [4.2, 3.8, 3.5, 3.2],
-    itemStyle: { color: '#409EFF', borderRadius: [4, 4, 0, 0] }
-  }]
-}));
-
-const loadData = () => {
-  loading.value = true;
-  setTimeout(() => { loading.value = false; }, 300);
-};
-
-const resetFilters = () => {
-  filters.value = { dateRange: null, activityType: '', status: '' };
-};
+const loadData = () => { loading.value = true; setTimeout(() => { loading.value = false; }, 300); };
 
 onMounted(loadData);
 </script>
 
 <style scoped>
-.filter-form :deep(.el-form-item) { margin-bottom: 0; }
-.trend-up { color: var(--el-color-success); }
-.trend-down { color: var(--el-color-danger); }
+.chart-card { background: rgba(248,249,250,1); border-radius: 12px; padding: 16px; }
+.chart-card__title { font-size: 14px; color: var(--cb-text-soft); margin-bottom: 12px; font-weight: 500; }
+.metric-card { background: rgba(248,249,250,1); border-radius: 12px; padding: 16px; text-align: center; }
+.metric-card__value { font-size: 24px; font-weight: 700; color: var(--cb-text-primary); }
+.metric-card__label { font-size: 13px; color: var(--cb-text-soft); margin: 4px 0; }
+.metric-card__sub { font-size: 12px; color: var(--el-color-success); }
+.coupon-list { display: flex; flex-direction: column; gap: 12px; }
+.coupon-item { display: flex; align-items: center; gap: 16px; padding: 16px; background: rgba(248,249,250,1); border-radius: 10px; }
+.coupon-item__rank { width: 32px; height: 32px; border-radius: 50%; background: #f0f0f0; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 14px; }
+.coupon-item__rank--top { background: linear-gradient(135deg, #409EFF, #67C23A); color: white; }
+.coupon-item__info { flex: 1; }
+.coupon-item__name { font-weight: 600; margin-bottom: 4px; }
+.coupon-item__meta { display: flex; gap: 16px; font-size: 12px; color: var(--cb-text-soft); }
+.coupon-item__amount { text-align: right; }
+.coupon-item__value { font-weight: 700; font-size: 18px; color: var(--cb-primary); margin-bottom: 4px; }
 </style>

+ 128 - 147
src/views/report/ProcurementReportView.vue

@@ -6,146 +6,120 @@
         <h1>采购报表</h1>
         <p>追踪采购额、到货及时率、质量合格率和供应商排名,优化采购策略。</p>
       </div>
-      <div class="chip-list">
-        <span class="chip">供应商排名</span>
-        <span class="chip">质量分析</span>
-      </div>
     </section>
 
-    <section class="glass-card section-card">
-      <el-form inline class="filter-form">
-        <el-form-item label="时间范围">
-          <el-date-picker v-model="filters.dateRange" type="daterange" range-separator="至" start-placeholder="开始" end-placeholder="结束" style="width:240px" />
-        </el-form-item>
-        <el-form-item label="供应商">
-          <el-select v-model="filters.supplier" placeholder="全部供应商" clearable style="width:150px">
-            <el-option label="深圳华通" value="深圳华通" />
-            <el-option label="广州鼎盛" value="广州鼎盛" />
-            <el-option label="东莞鑫达" value="东莞鑫达" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="状态">
-          <el-select v-model="filters.status" placeholder="全部" clearable style="width:120px">
-            <el-option label="已完成" value="已完成" />
-            <el-option label="进行中" value="进行中" />
-            <el-option label="已取消" value="已取消" />
-          </el-select>
-        </el-form-item>
-        <el-form-item>
-          <el-button type="primary" @click="loadData">查询</el-button>
-          <el-button @click="resetFilters">重置</el-button>
-        </el-form-item>
-      </el-form>
-    </section>
-
-    <section class="stat-grid" style="grid-template-columns:repeat(5, 1fr)">
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">本月采购额</div>
-        <div class="stat-card__value" style="font-size:22px;color:var(--cb-primary)">¥1,258,600</div>
-        <div class="stat-card__trend trend-up">+15.2% ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">采购单数</div>
-        <div class="stat-card__value" style="font-size:22px">86</div>
-        <div class="stat-card__trend">单</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">到货及时率</div>
-        <div class="stat-card__value" style="font-size:22px;color:var(--cb-success)">94.2%</div>
-        <div class="stat-card__trend trend-up">+2.1% ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">质量合格率</div>
-        <div class="stat-card__value" style="font-size:22px;color:var(--cb-success)">97.8%</div>
-        <div class="stat-card__trend trend-up">+0.8% ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">平均交期</div>
-        <div class="stat-card__value" style="font-size:22px">12.5天</div>
-        <div class="stat-card__trend trend-down">-1.2天 ↓</div>
-      </article>
+    <section class="glass-card section-card" style="padding:20px">
+      <div style="display:flex;gap:16px;flex-wrap:wrap">
+        <div class="procure-card">
+          <div class="procure-card__icon" style="background:linear-gradient(135deg,#409EFF,#67C23A)">
+            <el-icon><ShoppingCart /></el-icon>
+          </div>
+          <div class="procure-card__info">
+            <div class="procure-card__value">¥1,258,600</div>
+            <div class="procure-card__label">本月采购额</div>
+            <div class="procure-card__trend trend-up">+15.2% ↑</div>
+          </div>
+        </div>
+        <div class="procure-card">
+          <div class="procure-card__icon" style="background:linear-gradient(135deg,#67C23A,#E6A23C)">
+            <el-icon><Timer /></el-icon>
+          </div>
+          <div class="procure-card__info">
+            <div class="procure-card__value">94.2%</div>
+            <div class="procure-card__label">到货及时率</div>
+            <div class="procure-card__trend trend-up">+2.1% ↑</div>
+          </div>
+        </div>
+        <div class="procure-card">
+          <div class="procure-card__icon" style="background:linear-gradient(135deg,#E6A23C,#F56C6C)">
+            <el-icon><CircleCheck /></el-icon>
+          </div>
+          <div class="procure-card__info">
+            <div class="procure-card__value">97.8%</div>
+            <div class="procure-card__label">质量合格率</div>
+            <div class="procure-card__trend trend-up">+0.8% ↑</div>
+          </div>
+        </div>
+        <div class="procure-card">
+          <div class="procure-card__icon" style="background:linear-gradient(135deg,#F56C6C,#909399)">
+            <el-icon><Clock /></el-icon>
+          </div>
+          <div class="procure-card__info">
+            <div class="procure-card__value">12.5天</div>
+            <div class="procure-card__label">平均交期</div>
+            <div class="procure-card__trend trend-down">-1.2天 ↓</div>
+          </div>
+        </div>
+      </div>
     </section>
 
-    <section class="page-grid page-grid--two">
+    <section class="page-grid" style="grid-template-columns: 1fr 1fr;">
       <article class="glass-card section-card">
         <h3 style="margin:0 0 16px">采购额趋势</h3>
         <v-chart :option="purchaseTrendOption" autoresize style="height:280px" />
       </article>
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">供应商采购占比</h3>
-        <v-chart :option="supplierShareOption" autoresize style="height:280px" />
+        <h3 style="margin:0 0 16px">供应商采购分布</h3>
+        <v-chart :option="supplierDistOption" autoresize style="height:280px" />
       </article>
     </section>
 
     <section class="glass-card section-card">
-      <h3 style="margin:0 0 16px">供应商排名</h3>
-      <el-table :data="supplierRanking" stripe v-loading="loading">
-        <el-table-column prop="rank" label="排名" width="70" />
-        <el-table-column prop="supplierName" label="供应商" min-width="180" />
-        <el-table-column prop="purchaseAmount" label="采购额" width="130">
-          <template #default="{ row }">
-            <span style="font-weight:600">¥{{ row.purchaseAmount.toLocaleString() }}</span>
-          </template>
-        </el-table-column>
-        <el-table-column prop="orderCount" label="订单数" width="90" />
-        <el-table-column prop="deliveryRate" label="交期达成率" width="110">
-          <template #default="{ row }">
-            <span :style="{ color: row.deliveryRate >= 95 ? 'var(--cb-success)' : 'var(--cb-danger)' }">
-              {{ row.deliveryRate }}%
-            </span>
-          </template>
-        </el-table-column>
-        <el-table-column prop="qualityRate" label="合格率" width="90">
-          <template #default="{ row }">
-            <span :style="{ color: row.qualityRate >= 98 ? 'var(--cb-success)' : 'var(--cb-danger)' }">
-              {{ row.qualityRate }}%
-            </span>
-          </template>
-        </el-table-column>
-        <el-table-column prop="avgLeadTime" label="平均交期" width="100">
-          <template #default="{ row }">
-            {{ row.avgLeadTime }}天
-          </template>
-        </el-table-column>
-        <el-table-column prop="ratingLevel" label="等级" width="80">
-          <template #default="{ row }">
-            <el-tag :type="row.ratingLevel === 'A' ? 'success' : row.ratingLevel === 'B' ? '' : 'warning'" size="small">
-              {{ row.ratingLevel }}
-            </el-tag>
-          </template>
-        </el-table-column>
-      </el-table>
+      <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
+        <h3 style="margin:0">供应商排名</h3>
+        <el-radio-group v-model="rankingType" size="small">
+          <el-radio-button label="amount">采购额</el-radio-button>
+          <el-radio-button label="quality">质量</el-radio-button>
+          <el-radio-button label="delivery">交期</el-radio-button>
+        </el-radio-group>
+      </div>
+      <div class="supplier-ranking">
+        <div v-for="(s, idx) in supplierRanking" :key="idx" class="supplier-item">
+          <div class="supplier-item__rank" :class="{ 'supplier-item__rank--top': idx < 3 }">
+            {{ idx + 1 }}
+          </div>
+          <div class="supplier-item__info">
+            <div class="supplier-item__name">{{ s.name }}</div>
+            <el-progress :percentage="s.score" :stroke-width="6" :show-text="false" :color="idx < 3 ? '#409EFF' : '#909399'" />
+          </div>
+          <div class="supplier-item__meta">
+            <div class="supplier-item__value">¥{{ s.amount.toLocaleString() }}</div>
+            <div class="supplier-item__rate">{{ s.rate }}%</div>
+          </div>
+          <el-tag :type="s.level === 'A' ? 'success' : s.level === 'B' ? 'warning' : 'info'" size="small">
+            {{ s.level }}级
+          </el-tag>
+        </div>
+      </div>
     </section>
 
     <section class="glass-card section-card">
       <h3 style="margin:0 0 16px">采购明细</h3>
-      <el-table :data="purchaseDetail" stripe v-loading="loading">
-        <el-table-column prop="poNo" label="采购单号" width="160" />
-        <el-table-column prop="supplier" label="供应商" width="150" />
-        <el-table-column prop="sku" label="SKU" width="120" />
-        <el-table-column prop="qty" label="数量" width="80" />
-        <el-table-column prop="unitPrice" label="单价" width="100">
+      <el-table :data="purchaseDetail" stripe>
+        <el-table-column prop="poNo" label="采购单号" width="150" />
+        <el-table-column prop="supplier" label="供应商" width="130" />
+        <el-table-column prop="sku" label="SKU" width="110" />
+        <el-table-column label="数量/单价" width="120">
           <template #default="{ row }">
-            ¥{{ row.unitPrice }}
+            <span>{{ row.qty }} / ¥{{ row.price }}</span>
           </template>
         </el-table-column>
         <el-table-column prop="amount" label="金额" width="120">
           <template #default="{ row }">
-            <span style="font-weight:600">¥{{ row.amount.toLocaleString() }}</span>
+            <span style="font-weight:600;color:var(--cb-primary)">¥{{ row.amount.toLocaleString() }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="expectedDate" label="预计交期" width="110" />
-        <el-table-column prop="actualDate" label="实际交期" width="110" />
-        <el-table-column prop="status" label="状态" width="100">
+        <el-table-column label="交期" width="140">
           <template #default="{ row }">
-            <el-tag :type="row.status === '已完成' ? 'success' : row.status === '进行中' ? 'primary' : 'info'" size="small">
-              {{ row.status }}
-            </el-tag>
+            <span :class="row.onTime ? 'trend-up' : 'trend-down'">
+              {{ row.onTime ? '✓ 准时' : '✗ 延迟' }}
+            </span>
+            {{ row.expectedDate }}
           </template>
         </el-table-column>
-        <el-table-column prop="qualityStatus" label="质检状态" width="100">
+        <el-table-column prop="qualityStatus" label="质检" width="90">
           <template #default="{ row }">
-            <el-tag :type="row.qualityStatus === '合格' ? 'success' : row.qualityStatus === '待检' ? 'warning' : 'danger'" size="small">
+            <el-tag :type="row.qualityStatus === '合格' ? 'success' : 'warning'" size="small">
               {{ row.qualityStatus }}
             </el-tag>
           </template>
@@ -156,7 +130,8 @@
 </template>
 
 <script setup lang="ts">
-import { onMounted, ref, computed } from 'vue';
+import { ref, computed, onMounted } from 'vue';
+import { ShoppingCart, Timer, CircleCheck, Clock } from '@element-plus/icons-vue';
 import VChart from 'vue-echarts';
 import { use } from 'echarts/core';
 import { CanvasRenderer } from 'echarts/renderers';
@@ -166,27 +141,21 @@ import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/compon
 use([CanvasRenderer, LineChart, BarChart, PieChart, GridComponent, TooltipComponent, LegendComponent]);
 
 const loading = ref(false);
-
-const filters = ref({
-  dateRange: null as [Date, Date] | null,
-  supplier: '',
-  status: ''
-});
+const rankingType = ref('amount');
 
 const supplierRanking = ref([
-  { rank: 1, supplierName: '深圳华通供应链有限公司', purchaseAmount: 428600, orderCount: 28, deliveryRate: 98.5, qualityRate: 99.2, avgLeadTime: 10, ratingLevel: 'A' },
-  { rank: 2, supplierName: '广州鼎盛纺织制衣厂', purchaseAmount: 325800, orderCount: 22, deliveryRate: 95.0, qualityRate: 97.5, avgLeadTime: 12, ratingLevel: 'A' },
-  { rank: 3, supplierName: '东莞鑫达皮革制品厂', purchaseAmount: 258200, orderCount: 18, deliveryRate: 88.0, qualityRate: 94.0, avgLeadTime: 15, ratingLevel: 'B' },
-  { rank: 4, supplierName: '宁波海天塑业有限公司', purchaseAmount: 185600, orderCount: 12, deliveryRate: 92.0, qualityRate: 96.0, avgLeadTime: 14, ratingLevel: 'B' },
-  { rank: 5, supplierName: '苏州金诚纺织集团', purchaseAmount: 125400, orderCount: 8, deliveryRate: 82.0, qualityRate: 91.0, avgLeadTime: 18, ratingLevel: 'C' }
+  { name: '深圳华通供应链有限公司', amount: 428600, score: 100, rate: 98.5, level: 'A' },
+  { name: '广州鼎盛纺织制衣厂', amount: 325800, score: 76, rate: 95.0, level: 'A' },
+  { name: '东莞鑫达皮革制品厂', amount: 258200, score: 60, rate: 88.0, level: 'B' },
+  { name: '宁波海天塑业有限公司', amount: 185600, score: 43, rate: 92.0, level: 'B' },
+  { name: '苏州金诚纺织集团', amount: 125400, score: 29, rate: 82.0, level: 'C' }
 ]);
 
 const purchaseDetail = ref([
-  { poNo: 'PO-20260420-001', supplier: '深圳华通', sku: 'SKU-NM-BK-M', qty: 500, unitPrice: 85, amount: 42500, expectedDate: '2026-04-25', actualDate: '2026-04-23', status: '已完成', qualityStatus: '合格' },
-  { poNo: 'PO-20260419-002', supplier: '广州鼎盛', sku: 'SKU-AE-GR-L', qty: 800, unitPrice: 42, amount: 33600, expectedDate: '2026-04-28', actualDate: '-', status: '进行中', qualityStatus: '待检' },
-  { poNo: 'PO-20260418-003', supplier: '东莞鑫达', sku: 'SKU-UT-WH-XL', qty: 200, unitPrice: 156, amount: 31200, expectedDate: '2026-04-22', actualDate: '2026-04-25', status: '已完成', qualityStatus: '合格' },
-  { poNo: 'PO-20260417-004', supplier: '宁波海天', sku: 'SKU-UT-BK-42', qty: 150, unitPrice: 185, amount: 27750, expectedDate: '2026-04-30', actualDate: '-', status: '进行中', qualityStatus: '待检' },
-  { poNo: 'PO-20260416-005', supplier: '深圳华通', sku: 'SKU-NM-BK-S', qty: 400, unitPrice: 68, amount: 27200, expectedDate: '2026-04-20', actualDate: '2026-04-19', status: '已完成', qualityStatus: '合格' }
+  { poNo: 'PO-20260420-001', supplier: '深圳华通', sku: 'SKU-NM-BK-M', qty: 500, price: 85, amount: 42500, expectedDate: '2026-04-25', onTime: true, qualityStatus: '合格' },
+  { poNo: 'PO-20260419-002', supplier: '广州鼎盛', sku: 'SKU-AE-GR-L', qty: 800, price: 42, amount: 33600, expectedDate: '2026-04-28', onTime: false, qualityStatus: '待检' },
+  { poNo: 'PO-20260418-003', supplier: '东莞鑫达', sku: 'SKU-UT-WH-XL', qty: 200, price: 156, amount: 31200, expectedDate: '2026-04-22', onTime: false, qualityStatus: '合格' },
+  { poNo: 'PO-20260417-004', supplier: '宁波海天', sku: 'SKU-UT-BK-42', qty: 150, price: 185, amount: 27750, expectedDate: '2026-04-30', onTime: true, qualityStatus: '待检' }
 ]);
 
 const days = ['4/14', '4/15', '4/16', '4/17', '4/18', '4/19', '4/20'];
@@ -194,47 +163,59 @@ const days = ['4/14', '4/15', '4/16', '4/17', '4/18', '4/19', '4/20'];
 const purchaseTrendOption = computed(() => ({
   tooltip: { trigger: 'axis' },
   grid: { left: 60, right: 20, top: 20, bottom: 30 },
-  xAxis: { type: 'category', data: days },
+  xAxis: { type: 'category', data: days, boundaryGap: false },
   yAxis: { type: 'value', axisLabel: { formatter: '¥{value}' } },
   series: [{
-    name: '采购额',
-    type: 'bar',
+    type: 'line',
+    smooth: true,
     data: [168000, 185000, 172000, 198000, 182000, 215000, 186000],
-    itemStyle: { color: '#409EFF', borderRadius: [4, 4, 0, 0] }
+    areaStyle: { opacity: 0.3, color: { type: 'linear', x: 0, y: 0, x2: 0, y2: 1, colorStops: [{ offset: 0, color: 'rgba(64,158,255,0.5)' }, { offset: 1, color: 'rgba(64,158,255,0.05)' } } },
+    lineStyle: { width: 3, color: '#409EFF' },
+    itemStyle: { color: '#409EFF' },
+    symbol: 'circle',
+    symbolSize: 6
   }]
 }));
 
-const supplierShareOption = computed(() => ({
+const supplierDistOption = computed(() => ({
   tooltip: { trigger: 'item', formatter: '{b}: ¥{c} ({d}%)' },
-  legend: { orient: 'vertical', right: 20, top: 'center' },
   series: [{
     type: 'pie',
-    radius: ['40%', '70%'],
-    center: ['35%', '50%'],
+    radius: ['45%', '75%'],
+    center: ['50%', '50%'],
+    roseType: 'area',
+    itemStyle: { borderRadius: 8 },
     data: [
       { value: 428600, name: '深圳华通', itemStyle: { color: '#409EFF' } },
       { value: 325800, name: '广州鼎盛', itemStyle: { color: '#67C23A' } },
       { value: 258200, name: '东莞鑫达', itemStyle: { color: '#E6A23C' } },
       { value: 185600, name: '宁波海天', itemStyle: { color: '#F56C6C' } },
       { value: 125400, name: '苏州金诚', itemStyle: { color: '#909399' } }
-    ]
+    ],
+    label: { color: '#666' }
   }]
 }));
 
-const loadData = () => {
-  loading.value = true;
-  setTimeout(() => { loading.value = false; }, 300);
-};
-
-const resetFilters = () => {
-  filters.value = { dateRange: null, supplier: '', status: '' };
-};
+const loadData = () => { loading.value = true; setTimeout(() => { loading.value = false; }, 300); };
 
 onMounted(loadData);
 </script>
 
 <style scoped>
-.filter-form :deep(.el-form-item) { margin-bottom: 0; }
+.procure-card { display: flex; align-items: center; gap: 16px; padding: 20px 24px; background: linear-gradient(135deg, rgba(255,255,255,1), rgba(248,249,250,1)); border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.04); min-width: 200px; }
+.procure-card__icon { width: 48px; height: 48px; border-radius: 12px; display: flex; align-items: center; justify-content: center; color: white; font-size: 20px; }
+.procure-card__value { font-size: 22px; font-weight: 700; color: var(--cb-text-primary); }
+.procure-card__label { font-size: 13px; color: var(--cb-text-soft); margin: 2px 0; }
+.procure-card__trend { font-size: 12px; }
+.supplier-ranking { display: flex; flex-direction: column; gap: 12px; }
+.supplier-item { display: flex; align-items: center; gap: 12px; padding: 12px 16px; background: rgba(248,249,250,1); border-radius: 8px; }
+.supplier-item__rank { width: 28px; height: 28px; border-radius: 50%; background: #f0f0f0; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 14px; }
+.supplier-item__rank--top { background: linear-gradient(135deg, #409EFF, #67C23A); color: white; }
+.supplier-item__info { flex: 1; min-width: 0; }
+.supplier-item__name { font-weight: 500; margin-bottom: 6px; font-size: 14px; }
+.supplier-item__value { font-weight: 600; color: var(--cb-primary); font-size: 14px; }
+.supplier-item__rate { font-size: 12px; color: var(--cb-text-soft); }
+.supplier-item__meta { text-align: right; margin-right: 12px; }
 .trend-up { color: var(--el-color-success); }
 .trend-down { color: var(--el-color-danger); }
 </style>

+ 168 - 167
src/views/report/ProfitAnalysisView.vue

@@ -6,85 +6,94 @@
         <h1>利润分析报表</h1>
         <p>追踪SKU/渠道/供应商维度的成本、毛利和利润率,支持自定义成本分摊规则。</p>
       </div>
-      <div class="chip-list">
-        <span class="chip">成本自动分摊</span>
-        <span class="chip">利润预警</span>
-      </div>
     </section>
 
-    <section class="glass-card section-card">
-      <el-form inline class="filter-form">
-        <el-form-item label="时间范围">
-          <el-date-picker v-model="filters.dateRange" type="daterange" range-separator="至" start-placeholder="开始" end-placeholder="结束" style="width:240px" />
-        </el-form-item>
-        <el-form-item label="分析维度">
-          <el-select v-model="filters.dimension" placeholder="选择维度" clearable style="width:130px">
-            <el-option label="按SKU" value="sku" />
-            <el-option label="按渠道" value="channel" />
-            <el-option label="按供应商" value="supplier" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="利润预警">
-          <el-select v-model="filters.alertStatus" placeholder="全部" clearable style="width:120px">
-            <el-option label="正常" value="normal" />
-            <el-option label="预警" value="warning" />
-            <el-option label="亏损" value="loss" />
-          </el-select>
-        </el-form-item>
-        <el-form-item>
-          <el-button type="primary" @click="loadData">查询</el-button>
-          <el-button @click="resetFilters">重置</el-button>
-        </el-form-item>
-      </el-form>
+    <section class="glass-card section-card" style="padding:20px">
+      <el-row :gutter="24">
+        <el-col :span="6">
+          <div class="gauge-card">
+            <div class="gauge-card__title">整体毛利率</div>
+            <v-chart :option="grossProfitGauge" autoresize style="height:160px" />
+            <div class="gauge-card__compare">
+              <span class="trend-up">↑ 2.1pp</span> vs 上期
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="6">
+          <div class="gauge-card">
+            <div class="gauge-card__title">净利润率</div>
+            <v-chart :option="netProfitGauge" autoresize style="height:160px" />
+            <div class="gauge-card__compare">
+              <span class="trend-up">↑ 1.5pp</span> vs 上期
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="6">
+          <div class="gauge-card">
+            <div class="gauge-card__title">毛利率预警</div>
+            <div class="gauge-card__alert">
+              <div class="alert-stat">
+                <div class="alert-stat__num" style="color:var(--el-color-danger)">12</div>
+                <div class="alert-stat__label">亏损SKU</div>
+              </div>
+              <div class="alert-stat">
+                <div class="alert-stat__num" style="color:var(--el-color-warning)">28</div>
+                <div class="alert-stat__label">低利润SKU</div>
+              </div>
+            </div>
+          </div>
+        </el-col>
+        <el-col :span="6">
+          <div class="gauge-card">
+            <div class="gauge-card__title">成本构成</div>
+            <v-chart :option="costPie" autoresize style="height:160px" />
+          </div>
+        </el-col>
+      </el-row>
     </section>
 
-    <section class="stat-grid" style="grid-template-columns:repeat(4, 1fr)">
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">销售额</div>
-        <div class="stat-card__value" style="font-size:22px;color:var(--cb-primary)">$328,560</div>
-        <div class="stat-card__trend trend-up">+12.5% ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">总成本</div>
-        <div class="stat-card__value" style="font-size:22px">$198,420</div>
-        <div class="stat-card__trend trend-down">+8.2% ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">毛利</div>
-        <div class="stat-card__value" style="font-size:22px;color:var(--cb-success)">$130,140</div>
-        <div class="stat-card__trend trend-up">+18.3% ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">毛利率</div>
-        <div class="stat-card__value" style="font-size:22px">39.6%</div>
-        <div class="stat-card__trend trend-up">+2.1pp ↑</div>
-      </article>
-    </section>
-
-    <section class="page-grid page-grid--two">
+    <section class="page-grid" style="grid-template-columns: 1fr 1fr;">
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">成本结构分析</h3>
-        <v-chart :option="costStructureOption" autoresize style="height:280px" />
+        <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
+          <h3 style="margin:0">利润趋势</h3>
+          <el-radio-group v-model="profitView" size="small">
+            <el-radio-button label="gross">毛利</el-radio-button>
+            <el-radio-button label="net">净利</el-radio-button>
+            <el-radio-button label="cost">成本</el-radio-button>
+          </el-radio-group>
+        </div>
+        <v-chart :option="profitTrendChart" autoresize style="height:280px" />
       </article>
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">毛利趋势</h3>
-        <v-chart :option="profitTrendOption" autoresize style="height:280px" />
+        <h3 style="margin:0 0 16px">成本结构堆叠图</h3>
+        <v-chart :option="costStackChart" autoresize style="height:280px" />
       </article>
     </section>
 
     <section class="glass-card section-card">
-      <h3 style="margin:0 0 16px">利润明细</h3>
-      <el-table :data="profitDetail" stripe v-loading="loading">
+      <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
+        <h3 style="margin:0">SKU 利润明细</h3>
+        <div class="chip-list">
+          <el-tag type="success" size="small">正常: 86</el-tag>
+          <el-tag type="warning" size="small">预警: 28</el-tag>
+          <el-tag type="danger" size="small">亏损: 12</el-tag>
+        </div>
+      </div>
+      <el-table :data="profitDetail" stripe>
         <el-table-column prop="sku" label="SKU" width="130" />
         <el-table-column prop="productTitle" label="商品名称" min-width="180" show-overflow-tooltip />
-        <el-table-column prop="salesAmount" label="销售额" width="110">
+        <el-table-column prop="salesAmount" label="销售额" width="120">
           <template #default="{ row }">
             <span style="font-weight:600">${{ row.salesAmount.toLocaleString() }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="cost" label="成本" width="100">
+        <el-table-column label="成本构成" width="200">
           <template #default="{ row }">
-            ${{ row.cost.toLocaleString() }}
+            <div class="cost-bar">
+              <div class="cost-bar__product" :style="{ width: row.productCostPct + '%' }"></div>
+              <div class="cost-bar__freight" :style="{ width: row.freightCostPct + '%' }"></div>
+              <div class="cost-bar__platform" :style="{ width: row.platformFeePct + '%' }"></div>
+            </div>
           </template>
         </el-table-column>
         <el-table-column prop="grossProfit" label="毛利" width="100">
@@ -92,7 +101,7 @@
             <span style="color:var(--cb-success);font-weight:600">${{ row.grossProfit.toLocaleString() }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="profitRate" label="毛利率" width="80">
+        <el-table-column prop="profitRate" label="毛利率" width="90">
           <template #default="{ row }">
             <el-tag :type="row.profitRate >= 30 ? 'success' : row.profitRate >= 15 ? 'warning' : 'danger'" size="small">
               {{ row.profitRate }}%
@@ -100,152 +109,144 @@
           </template>
         </el-table-column>
         <el-table-column prop="channel" label="渠道" width="100" />
-        <el-table-column prop="supplier" label="供应商" width="120" show-overflow-tooltip />
-        <el-table-column label="操作" width="100" fixed="right">
-          <template #default="{ row }">
-            <el-button link type="primary" @click="viewCostDetail(row)">成本明细</el-button>
-          </template>
-        </el-table-column>
       </el-table>
     </section>
-
-    <el-dialog v-model="costDetailVisible" title="成本明细" width="600px">
-      <el-descriptions :column="2" border v-if="selectedItem">
-        <el-descriptions-item label="SKU">{{ selectedItem.sku }}</el-descriptions-item>
-        <el-descriptions-item label="商品名称" :span="2">{{ selectedItem.productTitle }}</el-descriptions-item>
-        <el-descriptions-item label="商品成本">${{ selectedItem.productCost }}</el-descriptions-item>
-        <el-descriptions-item label="头程运费">${{ selectedItem.freightCost }}</el-descriptions-item>
-        <el-descriptions-item label="平台佣金">${{ selectedItem.platformFee }}</el-descriptions-item>
-        <el-descriptions-item label="关税">${{ selectedItem.customDuty }}</el-descriptions-item>
-        <el-descriptions-item label="其他费用">${{ selectedItem.otherFee }}</el-descriptions-item>
-        <el-descriptions-item label="总成本">${{ selectedItem.cost }}</el-descriptions-item>
-        <el-descriptions-item label="毛利率">
-          <el-tag :type="selectedItem.profitRate >= 30 ? 'success' : selectedItem.profitRate >= 15 ? 'warning' : 'danger'">
-            {{ selectedItem.profitRate }}%
-          </el-tag>
-        </el-descriptions-item>
-      </el-descriptions>
-      <template #footer>
-        <el-button @click="costDetailVisible = false">关闭</el-button>
-      </template>
-    </el-dialog>
   </div>
 </template>
 
 <script setup lang="ts">
-import { onMounted, ref, computed } from 'vue';
+import { ref, computed, onMounted } from 'vue';
 import VChart from 'vue-echarts';
 import { use } from 'echarts/core';
 import { CanvasRenderer } from 'echarts/renderers';
-import { LineChart, BarChart, PieChart } from 'echarts/charts';
+import { LineChart, BarChart, PieChart, GaugeChart } from 'echarts/charts';
 import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/components';
 
-use([CanvasRenderer, LineChart, BarChart, PieChart, GridComponent, TooltipComponent, LegendComponent]);
-
-interface ProfitItem {
-  sku: string;
-  productTitle: string;
-  salesAmount: number;
-  cost: number;
-  grossProfit: number;
-  profitRate: number;
-  channel: string;
-  supplier: string;
-  productCost: number;
-  freightCost: number;
-  platformFee: number;
-  customDuty: number;
-  otherFee: number;
-}
+use([CanvasRenderer, LineChart, BarChart, PieChart, GaugeChart, GridComponent, TooltipComponent, LegendComponent]);
 
 const loading = ref(false);
-const costDetailVisible = ref(false);
-const selectedItem = ref<ProfitItem | null>(null);
-
-const filters = ref({
-  dateRange: null as [Date, Date] | null,
-  dimension: 'sku',
-  alertStatus: ''
-});
-
-const profitDetail = ref<ProfitItem[]>([
-  { sku: 'SKU-NM-BK-M', productTitle: 'Nomad 防水背包 黑色 中号', salesAmount: 45800, cost: 26800, grossProfit: 19000, profitRate: 41.5, channel: 'Shopify', supplier: '深圳华通', productCost: 18500, freightCost: 3200, platformFee: 2750, customDuty: 1800, otherFee: 550 },
-  { sku: 'SKU-AE-GR-L', productTitle: 'AeroDry 速干T恤 绿色 L码', salesAmount: 28500, cost: 18200, grossProfit: 10300, profitRate: 36.1, channel: 'TikTok Shop', supplier: '广州鼎盛', productCost: 12800, freightCost: 2100, platformFee: 1710, customDuty: 1200, otherFee: 390 },
-  { sku: 'SKU-UT-WH-XL', productTitle: 'UrbanTrail 徒步鞋 白色 XL', salesAmount: 38600, cost: 26500, grossProfit: 12100, profitRate: 31.3, channel: 'Amazon', supplier: '东莞鑫达', productCost: 18500, freightCost: 3500, platformFee: 2700, customDuty: 1400, otherFee: 400 },
-  { sku: 'SKU-NM-BK-S', productTitle: 'Nomad 防水背包 黑色 小号', salesAmount: 32600, cost: 21800, grossProfit: 10800, profitRate: 33.1, channel: 'Shopify', supplier: '深圳华通', productCost: 15200, freightCost: 2600, platformFee: 1956, customDuty: 1600, otherFee: 444 },
-  { sku: 'SKU-AE-BL-M', productTitle: 'AeroDry 运动短裤 蓝色 M码', salesAmount: 19800, cost: 14200, grossProfit: 5600, profitRate: 28.3, channel: 'TikTok Shop', supplier: '广州鼎盛', productCost: 9800, freightCost: 1800, platformFee: 1188, customDuty: 1000, otherFee: 412 },
-  { sku: 'SKU-UT-BK-42', productTitle: 'UrbanTrail 登山靴 黑色 42码', salesAmount: 42800, cost: 35200, grossProfit: 7600, profitRate: 17.8, channel: 'Amazon', supplier: '宁波海天', productCost: 25800, freightCost: 4200, platformFee: 3200, customDuty: 1600, otherFee: 400 }
+const profitView = ref('gross');
+
+const profitDetail = ref([
+  { sku: 'SKU-NM-BK-M', productTitle: 'Nomad 防水背包 黑色 中号', salesAmount: 45800, cost: 26800, grossProfit: 19000, profitRate: 41.5, channel: 'Shopify', productCostPct: 69, freightCostPct: 12, platformFeePct: 10 },
+  { sku: 'SKU-AE-GR-L', productTitle: 'AeroDry 速干T恤 绿色 L码', salesAmount: 28500, cost: 18200, grossProfit: 10300, profitRate: 36.1, channel: 'TikTok Shop', productCostPct: 70, freightCostPct: 12, platformFeePct: 9 },
+  { sku: 'SKU-UT-WH-XL', productTitle: 'UrbanTrail 徒步鞋 白色 XL', salesAmount: 38600, cost: 26500, grossProfit: 12100, profitRate: 31.3, channel: 'Amazon', productCostPct: 70, freightCostPct: 13, platformFeePct: 10 },
+  { sku: 'SKU-NM-BK-S', productTitle: 'Nomad 防水背包 黑色 小号', salesAmount: 32600, cost: 21800, grossProfit: 10800, profitRate: 33.1, channel: 'Shopify', productCostPct: 70, freightCostPct: 12, platformFeePct: 9 }
 ]);
 
 const days = ['4/14', '4/15', '4/16', '4/17', '4/18', '4/19', '4/20'];
 
-const costStructureOption = computed(() => ({
-  tooltip: { trigger: 'item', formatter: '{b}: ${c} ({d}%)' },
-  legend: { orient: 'vertical', right: 20, top: 'center' },
+const grossProfitGauge = computed(() => ({
+  series: [{
+    type: 'gauge',
+    startAngle: 200,
+    endAngle: -20,
+    min: 0,
+    max: 60,
+    splitNumber: 6,
+    radius: '90%',
+    center: ['50%', '60%'],
+    pointer: { width: 4 },
+    axisLine: { lineStyle: { width: 12, color: [[0.5, '#67C23A'], [0.8, '#E6A23C'], [1, '#F56C6C']] } },
+    progress: { show: true, width: 12 },
+    detail: { valueAnimation: true, formatter: '{value}%', fontSize: 24, offsetCenter: [0, '40%'] },
+    data: [{ value: 39.6 }]
+  }]
+}));
+
+const netProfitGauge = computed(() => ({
+  series: [{
+    type: 'gauge',
+    startAngle: 200,
+    endAngle: -20,
+    min: 0,
+    max: 30,
+    splitNumber: 6,
+    radius: '90%',
+    center: ['50%', '60%'],
+    pointer: { width: 4 },
+    axisLine: { lineStyle: { width: 12, color: [[0.5, '#67C23A'], [0.8, '#E6A23C'], [1, '#F56C6C']] } },
+    progress: { show: true, width: 12 },
+    detail: { valueAnimation: true, formatter: '{value}%', fontSize: 24, offsetCenter: [0, '40%'] },
+    data: [{ value: 18.2 }]
+  }]
+}));
+
+const costPie = computed(() => ({
+  tooltip: { trigger: 'item', formatter: '{b}: {d}%' },
   series: [{
     type: 'pie',
-    radius: ['40%', '70%'],
-    center: ['35%', '50%'],
+    radius: ['50%', '70%'],
+    avoidLabelOverlap: false,
+    padAngle: 3,
+    itemStyle: { borderRadius: 6 },
     data: [
-      { value: 120600, name: '商品成本', itemStyle: { color: '#409EFF' } },
-      { value: 21600, name: '头程运费', itemStyle: { color: '#67C23A' } },
-      { value: 13500, name: '平台佣金', itemStyle: { color: '#E6A23C' } },
-      { value: 8600, name: '关税', itemStyle: { color: '#F56C6C' } },
-      { value: 2600, name: '其他费用', itemStyle: { color: '#909399' } }
-    ]
+      { value: 60, name: '商品成本', itemStyle: { color: '#409EFF' } },
+      { value: 15, name: '头程运费', itemStyle: { color: '#67C23A' } },
+      { value: 12, name: '平台佣金', itemStyle: { color: '#E6A23C' } },
+      { value: 8, name: '关税', itemStyle: { color: '#F56C6C' } },
+      { value: 5, name: '其他', itemStyle: { color: '#909399' } }
+    ],
+    label: { show: false }
   }]
 }));
 
-const profitTrendOption = computed(() => ({
+const profitTrendChart = computed(() => ({
   tooltip: { trigger: 'axis' },
-  grid: { left: 60, right: 20, top: 20, bottom: 30 },
-  xAxis: { type: 'category', data: days },
+  legend: { data: ['毛利', '成本'], bottom: 0 },
+  grid: { left: 60, right: 20, top: 20, bottom: 50 },
+  xAxis: { type: 'category', data: days, boundaryGap: false },
   yAxis: { type: 'value', axisLabel: { formatter: '${value}' } },
   series: [
-    {
-      name: '销售额',
-      type: 'bar',
-      stack: 'total',
-      data: [42800, 51200, 48600, 55200, 49800, 57500, 52300],
-      itemStyle: { color: '#409EFF' }
-    },
-    {
-      name: '成本',
-      type: 'bar',
-      stack: 'total',
-      data: [25800, 30800, 29200, 33200, 29800, 34600, 31600],
-      itemStyle: { color: '#E6A23C' }
-    },
     {
       name: '毛利',
       type: 'line',
       smooth: true,
-      yAxisIndex: 0,
       data: [17000, 20400, 19400, 22000, 20000, 22900, 20700],
+      areaStyle: { opacity: 0.3 },
+      lineStyle: { width: 3 },
       itemStyle: { color: '#67C23A' }
+    },
+    {
+      name: '成本',
+      type: 'line',
+      smooth: true,
+      data: [25800, 30800, 29200, 33200, 29800, 34600, 31600],
+      lineStyle: { width: 2, type: 'dashed' },
+      itemStyle: { color: '#E6A23C' }
     }
   ]
 }));
 
-const loadData = () => {
-  loading.value = true;
-  setTimeout(() => { loading.value = false; }, 300);
-};
-
-const resetFilters = () => {
-  filters.value = { dateRange: null, dimension: 'sku', alertStatus: '' };
-};
+const costStackChart = computed(() => ({
+  tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
+  legend: { data: ['商品成本', '头程运费', '平台佣金', '关税'], bottom: 0 },
+  grid: { left: 60, right: 20, top: 20, bottom: 50 },
+  xAxis: { type: 'category', data: days },
+  yAxis: { type: 'value', axisLabel: { formatter: '${value}' } },
+  series: [
+    { name: '商品成本', type: 'bar', stack: 'total', data: [18000, 21500, 20400, 23200, 20800, 24200, 22100], itemStyle: { color: '#409EFF' } },
+    { name: '头程运费', type: 'bar', stack: 'total', data: [3200, 3800, 3600, 4200, 3800, 4400, 4000], itemStyle: { color: '#67C23A' } },
+    { name: '平台佣金', type: 'bar', stack: 'total', data: [2700, 3200, 3000, 3500, 3200, 3800, 3400], itemStyle: { color: '#E6A23C' } },
+    { name: '关税', type: 'bar', stack: 'total', data: [1800, 2200, 2000, 2300, 2000, 2500, 2100], itemStyle: { color: '#F56C6C' } }
+  ]
+}));
 
-const viewCostDetail = (row: ProfitItem) => {
-  selectedItem.value = row;
-  costDetailVisible.value = true;
-};
+const loadData = () => { loading.value = true; setTimeout(() => { loading.value = false; }, 300); };
 
 onMounted(loadData);
 </script>
 
 <style scoped>
-.filter-form :deep(.el-form-item) { margin-bottom: 0; }
+.gauge-card { text-align: center; }
+.gauge-card__title { font-size: 14px; color: var(--cb-text-soft); margin-bottom: 8px; }
+.gauge-card__compare { font-size: 12px; color: var(--cb-text-soft); margin-top: 8px; }
+.gauge-card__alert { display: flex; justify-content: center; gap: 32px; padding: 16px 0; }
+.alert-stat__num { font-size: 32px; font-weight: 600; }
+.alert-stat__label { font-size: 12px; color: var(--cb-text-soft); }
+.cost-bar { display: flex; height: 8px; border-radius: 4px; overflow: hidden; background: #f0f0f0; }
+.cost-bar__product { background: #409EFF; }
+.cost-bar__freight { background: #67C23A; }
+.cost-bar__platform { background: #E6A23C; }
 .trend-up { color: var(--el-color-success); }
-.trend-down { color: var(--el-color-danger); }
 </style>

+ 234 - 153
src/views/report/SalesAnalysisView.vue

@@ -6,10 +6,6 @@
         <h1>销售分析报表</h1>
         <p>多维度分析销售数据,洞察GMV、订单量、客单价趋势,支持按渠道/国家/商品维度下钻。</p>
       </div>
-      <div class="chip-list">
-        <span class="chip">实时数据</span>
-        <span class="chip">支持导出</span>
-      </div>
     </section>
 
     <section class="glass-card section-card">
@@ -24,20 +20,6 @@
             <el-option label="Amazon" value="Amazon" />
           </el-select>
         </el-form-item>
-        <el-form-item label="国家">
-          <el-select v-model="filters.country" placeholder="全部国家" clearable style="width:120px">
-            <el-option label="美国" value="US" />
-            <el-option label="英国" value="UK" />
-            <el-option label="日本" value="JP" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="对比周期">
-          <el-select v-model="filters.comparePeriod" placeholder="选择对比周期" clearable style="width:130px">
-            <el-option label="上周同期" value="lastWeek" />
-            <el-option label="上月同期" value="lastMonth" />
-            <el-option label="去年同期" value="lastYear" />
-          </el-select>
-        </el-form-item>
         <el-form-item>
           <el-button type="primary" @click="loadData">查询</el-button>
           <el-button @click="resetFilters">重置</el-button>
@@ -45,95 +27,141 @@
       </el-form>
     </section>
 
-    <section class="stat-grid" style="grid-template-columns:repeat(5, 1fr)">
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">GMV</div>
-        <div class="stat-card__value" style="font-size:22px;color:var(--cb-primary)">$328,560</div>
-        <div class="stat-card__trend trend-up">+12.5% ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">订单量</div>
-        <div class="stat-card__value" style="font-size:22px">1,258</div>
-        <div class="stat-card__trend trend-up">+8.3% ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">客单价</div>
-        <div class="stat-card__value" style="font-size:22px">$261.2</div>
-        <div class="stat-card__trend trend-up">+3.8% ↑</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">转化率</div>
-        <div class="stat-card__value" style="font-size:22px">3.8%</div>
-        <div class="stat-card__trend trend-down">-0.2% ↓</div>
-      </article>
-      <article class="glass-card stat-card">
-        <div class="stat-card__label">复购率</div>
-        <div class="stat-card__value" style="font-size:22px">18.5%</div>
-        <div class="stat-card__trend trend-up">+1.2% ↑</div>
-      </article>
+    <section class="glass-card section-card" style="padding:20px">
+      <div style="display:flex;align-items:center;gap:24px;flex-wrap:wrap">
+        <div class="kpi-box">
+          <div class="kpi-box__icon" style="background:linear-gradient(135deg,#409EFF,#67C23A)">
+            <el-icon><TrendCharts /></el-icon>
+          </div>
+          <div class="kpi-box__content">
+            <div class="kpi-box__label">本月GMV</div>
+            <div class="kpi-box__value">$328,560</div>
+            <div class="kpi-box__trend trend-up">
+              <el-icon><Top /></el-icon> +12.5%
+            </div>
+          </div>
+        </div>
+        <div class="kpi-box">
+          <div class="kpi-box__icon" style="background:linear-gradient(135deg,#E6A23C,#F56C6C)">
+            <el-icon><ShoppingCart /></el-icon>
+          </div>
+          <div class="kpi-box__content">
+            <div class="kpi-box__label">订单量</div>
+            <div class="kpi-box__value">1,258</div>
+            <div class="kpi-box__trend trend-up">
+              <el-icon><Top /></el-icon> +8.3%
+            </div>
+          </div>
+        </div>
+        <div class="kpi-box">
+          <div class="kpi-box__icon" style="background:linear-gradient(135deg,#909399,#409EFF)">
+            <el-icon><Wallet /></el-icon>
+          </div>
+          <div class="kpi-box__content">
+            <div class="kpi-box__label">客单价</div>
+            <div class="kpi-box__value">$261.2</div>
+            <div class="kpi-box__trend trend-up">
+              <el-icon><Top /></el-icon> +3.8%
+            </div>
+          </div>
+        </div>
+        <div class="kpi-box">
+          <div class="kpi-box__icon" style="background:linear-gradient(135deg,#67C23A,#E6A23C)">
+            <el-icon><Refresh /></el-icon>
+          </div>
+          <div class="kpi-box__content">
+            <div class="kpi-box__label">复购率</div>
+            <div class="kpi-box__value">18.5%</div>
+            <div class="kpi-box__trend trend-up">
+              <el-icon><Top /></el-icon> +1.2%
+            </div>
+          </div>
+        </div>
+      </div>
     </section>
 
-    <section class="page-grid page-grid--two">
+    <section class="page-grid" style="grid-template-columns: 2fr 1fr;">
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">GMV 趋势</h3>
-        <v-chart :option="gmvTrendOption" autoresize style="height:300px" />
+        <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
+          <h3 style="margin:0">销售趋势</h3>
+          <el-radio-group v-model="trendType" size="small">
+            <el-radio-button label="gmv">GMV</el-radio-button>
+            <el-radio-button label="orders">订单</el-radio-button>
+            <el-radio-button label="both">对比</el-radio-button>
+          </el-radio-group>
+        </div>
+        <v-chart :option="salesTrendOption" autoresize style="height:320px" />
       </article>
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">订单量趋势</h3>
-        <v-chart :option="orderTrendOption" autoresize style="height:300px" />
+        <h3 style="margin:0 0 16px">渠道占比</h3>
+        <v-chart :option="channelRoseOption" autoresize style="height:300px" />
       </article>
     </section>
 
     <section class="page-grid page-grid--two">
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">渠道销售占比</h3>
-        <v-chart :option="channelPieOption" autoresize style="height:280px" />
+        <h3 style="margin:0 0 16px">TOP 10 销售商品</h3>
+        <div class="rank-list">
+          <div v-for="(item, idx) in topProducts" :key="idx" class="rank-item">
+            <div class="rank-item__rank" :class="{ 'rank-item__rank--top3': idx < 3 }">{{ idx + 1 }}</div>
+            <div class="rank-item__info">
+              <div class="rank-item__name">{{ item.title }}</div>
+              <el-progress :percentage="item.percent" :stroke-width="6" :show-text="false" :color="idx < 3 ? '#409EFF' : '#909399'" />
+            </div>
+            <div class="rank-item__value">
+              <div class="rank-item__sales">¥{{ item.amount }}</div>
+              <div class="rank-item__qty">{{ item.qty }}件</div>
+            </div>
+          </div>
+        </div>
       </article>
       <article class="glass-card section-card">
-        <h3 style="margin:0 0 16px">TOP 10 销售商品</h3>
-        <el-table :data="topProducts" stripe size="small">
-          <el-table-column prop="rank" label="排名" width="60" />
-          <el-table-column prop="title" label="商品名称" min-width="180" show-overflow-tooltip />
-          <el-table-column prop="salesQty" label="销量" width="80" />
-          <el-table-column prop="salesAmount" label="销售额" width="100" />
-        </el-table>
+        <h3 style="margin:0 0 16px">地域分布</h3>
+        <v-chart :option="regionBarOption" autoresize style="height:280px" />
       </article>
     </section>
 
     <section class="glass-card section-card">
-      <h3 style="margin:0 0 16px">销售明细</h3>
-      <el-table :data="salesDetail" stripe v-loading="loading">
+      <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
+        <h3 style="margin:0">销售明细</h3>
+        <div class="chip-list">
+          <el-button type="primary" size="small">导出Excel</el-button>
+          <el-button size="small">导出CSV</el-button>
+        </div>
+      </div>
+      <el-table :data="salesDetail" stripe>
         <el-table-column prop="date" label="日期" width="110" />
         <el-table-column prop="channel" label="渠道" width="100" />
         <el-table-column prop="country" label="国家" width="80" />
-        <el-table-column prop="orderCount" label="订单数" width="80" />
-        <el-table-column prop="gmv" label="GMV" width="120">
+        <el-table-column prop="gmv" label="GMV" width="130">
           <template #default="{ row }">
-            <span style="font-weight:600">${{ row.gmv.toLocaleString() }}</span>
+            <span style="font-weight:600;color:var(--cb-primary)">${{ row.gmv.toLocaleString() }}</span>
           </template>
         </el-table-column>
+        <el-table-column prop="orderCount" label="订单数" width="90" />
         <el-table-column prop="avgOrderValue" label="客单价" width="100" />
-        <el-table-column prop="conversionRate" label="转化率" width="80" />
-        <el-table-column prop="mom" label="环比" width="80">
+        <el-table-column label="环比" width="90">
           <template #default="{ row }">
-            <span :class="row.mom >= 0 ? 'trend-up' : 'trend-down'">{{ row.mom >= 0 ? '+' : '' }}{{ row.mom }}%</span>
+            <span :class="row.mom >= 0 ? 'trend-up' : 'trend-down'">
+              {{ row.mom >= 0 ? '+' : '' }}{{ row.mom }}%
+            </span>
           </template>
         </el-table-column>
-        <el-table-column prop="yoy" label="同比" width="80">
+        <el-table-column label="同比" width="90">
           <template #default="{ row }">
-            <span :class="row.yoy >= 0 ? 'trend-up' : 'trend-down'">{{ row.yoy >= 0 ? '+' : '' }}{{ row.yoy }}%</span>
+            <span :class="row.yoy >= 0 ? 'trend-up' : 'trend-down'">
+              {{ row.yoy >= 0 ? '+' : '' }}{{ row.yoy }}%
+            </span>
           </template>
         </el-table-column>
       </el-table>
-      <div style="display:flex;justify-content:flex-end;margin-top:16px">
-        <el-pagination v-model:current-page="page" v-model:page-size="pageSize" :total="total" :page-sizes="[10, 20, 50]" layout="total, sizes, prev, pager, next" />
-      </div>
     </section>
   </div>
 </template>
 
 <script setup lang="ts">
-import { onMounted, ref, computed } from 'vue';
+import { ref, computed, onMounted } from 'vue';
+import { TrendCharts, ShoppingCart, Wallet, Refresh, Top } from '@element-plus/icons-vue';
 import VChart from 'vue-echarts';
 import { use } from 'echarts/core';
 import { CanvasRenderer } from 'echarts/renderers';
@@ -143,115 +171,168 @@ import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/compon
 use([CanvasRenderer, LineChart, BarChart, PieChart, GridComponent, TooltipComponent, LegendComponent]);
 
 const loading = ref(false);
-const page = ref(1);
-const pageSize = ref(10);
-const total = ref(0);
-
+const trendType = ref('both');
 const filters = ref({
   dateRange: null as [Date, Date] | null,
-  channel: '',
-  country: '',
-  comparePeriod: 'lastWeek'
+  channel: ''
 });
 
-const salesDetail = ref([
-  { date: '2026-04-20', channel: 'Shopify', country: 'US', orderCount: 128, gmv: 35680, avgOrderValue: 278.75, conversionRate: 4.2, mom: 5.8, yoy: 12.3 },
-  { date: '2026-04-20', channel: 'TikTok Shop', country: 'UK', orderCount: 86, gmv: 18920, avgOrderValue: 220.00, conversionRate: 3.5, mom: 8.2, yoy: 25.6 },
-  { date: '2026-04-19', channel: 'Shopify', country: 'JP', orderCount: 95, gmv: 28450, avgOrderValue: 299.47, conversionRate: 3.8, mom: -2.1, yoy: 8.9 },
-  { date: '2026-04-19', channel: 'Amazon', country: 'US', orderCount: 156, gmv: 42180, avgOrderValue: 270.38, conversionRate: 4.5, mom: 12.4, yoy: 15.2 },
-  { date: '2026-04-18', channel: 'TikTok Shop', country: 'US', orderCount: 68, gmv: 15200, avgOrderValue: 223.53, conversionRate: 3.2, mom: -5.6, yoy: 32.1 }
+const topProducts = ref([
+  { title: 'Nomad 防水背包 黑色 中号', amount: '186,240', qty: 258, percent: 100 },
+  { title: 'AeroDry 速干T恤 绿色 L码', amount: '89,250', qty: 425, percent: 48 },
+  { title: 'UrbanTrail 徒步鞋 白色 XL', amount: '128,340', qty: 186, percent: 69 },
+  { title: 'Nomad 防水背包 黑色 小号', amount: '100,632', qty: 168, percent: 54 },
+  { title: 'AeroDry 运动短裤 蓝色 M码', amount: '54,600', qty: 312, percent: 29 },
+  { title: 'UrbanTrail 登山靴 黑色 42码', amount: '86,450', qty: 95, percent: 46 },
+  { title: 'Nomad 防水背包 灰色 大号', amount: '109,340', qty: 142, percent: 59 },
+  { title: 'AeroDry 速干帽 黑色', amount: '41,600', qty: 520, percent: 22 },
+  { title: 'UrbanTrail 徒步袜 专业款', amount: '27,200', qty: 680, percent: 15 },
+  { title: 'Nomad 收纳袋 套装', amount: '34,650', qty: 385, percent: 19 }
 ]);
 
-const topProducts = ref([
-  { rank: 1, title: 'Nomad 防水背包 黑色 中号', salesQty: 258, salesAmount: '¥186,240' },
-  { rank: 2, title: 'AeroDry 速干T恤 绿色 L码', salesQty: 425, salesAmount: '¥89,250' },
-  { rank: 3, title: 'UrbanTrail 徒步鞋 白色 XL', salesQty: 186, salesAmount: '¥128,340' },
-  { rank: 4, title: 'Nomad 防水背包 黑色 小号', salesQty: 168, salesAmount: '¥100,632' },
-  { rank: 5, title: 'AeroDry 运动短裤 蓝色 M码', salesQty: 312, salesAmount: '¥54,600' },
-  { rank: 6, title: 'UrbanTrail 登山靴 黑色 42码', salesQty: 95, salesAmount: '¥86,450' },
-  { rank: 7, title: 'Nomad 防水背包 灰色 大号', salesQty: 142, salesAmount: '¥109,340' },
-  { rank: 8, title: 'AeroDry 速干帽 黑色', salesQty: 520, salesAmount: '¥41,600' },
-  { rank: 9, title: 'UrbanTrail 徒步袜 专业款', salesQty: 680, salesAmount: '¥27,200' },
-  { rank: 10, title: 'Nomad 收纳袋 套装', salesQty: 385, salesAmount: '¥34,650' }
+const salesDetail = ref([
+  { date: '2026-04-20', channel: 'Shopify', country: 'US', gmv: 35680, orderCount: 128, avgOrderValue: 278.75, mom: 5.8, yoy: 12.3 },
+  { date: '2026-04-20', channel: 'TikTok Shop', country: 'UK', gmv: 18920, orderCount: 86, avgOrderValue: 220.00, mom: 8.2, yoy: 25.6 },
+  { date: '2026-04-19', channel: 'Shopify', country: 'JP', gmv: 28450, orderCount: 95, avgOrderValue: 299.47, mom: -2.1, yoy: 8.9 }
 ]);
 
 const days = ['4/14', '4/15', '4/16', '4/17', '4/18', '4/19', '4/20'];
 
-const gmvTrendOption = computed(() => ({
-  tooltip: { trigger: 'axis' },
-  grid: { left: 60, right: 20, top: 20, bottom: 30 },
-  xAxis: { type: 'category', data: days },
-  yAxis: { type: 'value', axisLabel: { formatter: '${value}' } },
-  series: [
-    {
-      name: '本期GMV',
-      type: 'line',
-      smooth: true,
-      data: [32800, 41200, 38600, 45200, 39800, 47500, 42300],
-      areaStyle: { opacity: 0.15 },
-      itemStyle: { color: '#409EFF' }
-    },
-    {
-      name: '上期GMV',
-      type: 'line',
-      smooth: true,
-      data: [29000, 35500, 34200, 38800, 36500, 41200, 37600],
-      itemStyle: { color: '#909399' },
-      lineStyle: { type: 'dashed' }
-    }
-  ]
-}));
-
-const orderTrendOption = computed(() => ({
-  tooltip: { trigger: 'axis' },
-  grid: { left: 50, right: 20, top: 20, bottom: 30 },
-  xAxis: { type: 'category', data: days },
-  yAxis: { type: 'value' },
-  series: [
-    {
-      name: '本期订单',
-      type: 'bar',
-      data: [128, 156, 142, 168, 152, 178, 156],
-      itemStyle: { color: '#409EFF', borderRadius: [4, 4, 0, 0] }
-    },
-    {
-      name: '上期订单',
-      type: 'bar',
-      data: [112, 138, 128, 148, 138, 162, 142],
-      itemStyle: { color: '#E6A23C', borderRadius: [4, 4, 0, 0] }
-    }
-  ]
-}));
+const salesTrendOption = computed(() => {
+  if (trendType.value === 'gmv') {
+    return {
+      tooltip: { trigger: 'axis' },
+      grid: { left: 60, right: 20, top: 20, bottom: 40 },
+      xAxis: { type: 'category', data: days, boundaryGap: false },
+      yAxis: { type: 'value', axisLabel: { formatter: '${value}' } },
+      series: [{
+        name: 'GMV',
+        type: 'line',
+        smooth: true,
+        data: [32800, 41200, 38600, 45200, 39800, 47500, 42300],
+        areaStyle: { opacity: 0.3 },
+        lineStyle: { width: 3 },
+        itemStyle: { color: '#409EFF' },
+        emphasis: { focus: 'series' }
+      }]
+    };
+  } else if (trendType.value === 'orders') {
+    return {
+      tooltip: { trigger: 'axis' },
+      grid: { left: 50, right: 20, top: 20, bottom: 40 },
+      xAxis: { type: 'category', data: days },
+      yAxis: { type: 'value' },
+      series: [{
+        name: '订单量',
+        type: 'bar',
+        data: [128, 156, 142, 168, 152, 178, 156],
+        itemStyle: { color: '#67C23A', borderRadius: [4, 4, 0, 0] },
+        emphasis: { focus: 'series' }
+      }]
+    };
+  }
+  return {
+    tooltip: { trigger: 'axis' },
+    grid: { left: 60, right: 20, top: 20, bottom: 40 },
+    xAxis: { type: 'category', data: days },
+    yAxis: [
+      { type: 'value', name: 'GMV', axisLabel: { formatter: '${value}' } },
+      { type: 'value', name: '订单', splitLine: { show: false } }
+    ],
+    series: [
+      {
+        name: 'GMV',
+        type: 'bar',
+        data: [32800, 41200, 38600, 45200, 39800, 47500, 42300],
+        itemStyle: { color: 'rgba(64, 158, 255, 0.5)', borderRadius: [4, 4, 0, 0] }
+      },
+      {
+        name: '订单量',
+        type: 'line',
+        yAxisIndex: 1,
+        smooth: true,
+        data: [128, 156, 142, 168, 152, 178, 156],
+        lineStyle: { width: 2 },
+        itemStyle: { color: '#67C23A' }
+      }
+    ]
+  };
+});
 
-const channelPieOption = computed(() => ({
+const channelRoseOption = computed(() => ({
   tooltip: { trigger: 'item', formatter: '{b}: ${c} ({d}%)' },
-  legend: { orient: 'vertical', right: 20, top: 'center' },
   series: [{
     type: 'pie',
-    radius: ['40%', '70%'],
-    center: ['35%', '50%'],
+    radius: ['20%', '70%'],
+    center: ['50%', '50%'],
+    roseType: 'area',
+    itemStyle: { borderRadius: 5 },
     data: [
       { value: 158200, name: 'Shopify', itemStyle: { color: '#409EFF' } },
       { value: 89200, name: 'TikTok Shop', itemStyle: { color: '#67C23A' } },
       { value: 81200, name: 'Amazon', itemStyle: { color: '#E6A23C' } }
     ],
-    label: { show: false }
+    label: { color: '#666' }
   }]
 }));
 
-const loadData = () => {
-  loading.value = true;
-  setTimeout(() => { loading.value = false; }, 300);
-};
+const regionBarOption = computed(() => ({
+  tooltip: { trigger: 'axis' },
+  grid: { left: 60, right: 20, top: 10, bottom: 30 },
+  xAxis: { type: 'value' },
+  yAxis: { type: 'category', data: ['美国', '英国', '日本', '德国', '法国', '加拿大'] },
+  series: [{
+    type: 'bar',
+    data: [158200, 89200, 65800, 42800, 32600, 28500],
+    itemStyle: {
+      color: (params: any) => {
+        const colors = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399', '#B37FEB'];
+        return colors[params.dataIndex];
+      },
+      borderRadius: [0, 4, 4, 0]
+    },
+    barWidth: '60%'
+  }]
+}));
 
-const resetFilters = () => {
-  filters.value = { dateRange: null, channel: '', country: '', comparePeriod: 'lastWeek' };
-};
+const loadData = () => { loading.value = true; setTimeout(() => { loading.value = false; }, 300); };
+const resetFilters = () => { filters.value = { dateRange: null, channel: '' }; };
 
 onMounted(loadData);
 </script>
 
 <style scoped>
+.kpi-box {
+  display: flex;
+  align-items: center;
+  gap: 16px;
+  padding: 16px 20px;
+  background: linear-gradient(135deg, rgba(64, 158, 255, 0.1), rgba(103, 194, 58, 0.1));
+  border-radius: 12px;
+  min-width: 200px;
+}
+.kpi-box__icon {
+  width: 48px;
+  height: 48px;
+  border-radius: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: white;
+  font-size: 20px;
+}
+.kpi-box__label { font-size: 13px; color: var(--cb-text-soft); margin-bottom: 4px; }
+.kpi-box__value { font-size: 22px; font-weight: 600; color: var(--cb-text-primary); }
+.kpi-box__trend { font-size: 12px; display: flex; align-items: center; gap: 2px; margin-top: 4px; }
+.rank-list { display: flex; flex-direction: column; gap: 12px; }
+.rank-item { display: flex; align-items: center; gap: 12px; }
+.rank-item__rank { width: 24px; height: 24px; border-radius: 50%; background: #f0f0f0; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; }
+.rank-item__rank--top3 { background: linear-gradient(135deg, #409EFF, #67C23A); color: white; }
+.rank-item__info { flex: 1; min-width: 0; }
+.rank-item__name { font-size: 13px; margin-bottom: 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
+.rank-item__value { text-align: right; }
+.rank-item__sales { font-weight: 600; color: var(--cb-primary); }
+.rank-item__qty { font-size: 12px; color: var(--cb-text-soft); }
 .filter-form :deep(.el-form-item) { margin-bottom: 0; }
 .trend-up { color: var(--el-color-success); }
 .trend-down { color: var(--el-color-danger); }