瀏覽代碼

增加 取消分析页面

ylong 8 月之前
父節點
當前提交
fa8cbd5bc9

+ 31 - 8
src/views/optimization/orderAnalysis/components/pie-chart.vue

@@ -12,6 +12,8 @@
     LegendComponent,
     ToolboxComponent
   } from 'echarts/components';
+  import { ref, reactive, defineExpose } from 'vue';
+  import request from '@/utils/request';
 
   // 按需加载echarts
   use([
@@ -28,7 +30,7 @@
     },
     series: [
       {
-        name: 'Nightingale Chart',
+        name: '取消原因分布',
         type: 'pie',
         radius: [50, 150],
         center: ['50%', '50%'],
@@ -36,16 +38,37 @@
         itemStyle: {
           borderRadius: 8
         },
+        label: {
+          formatter: '{b}: {c} ({d}%)'
+        },
         data: [
-          { value: 40, name: '快递不取件' },
-          { value: 38, name: '快递不上门' },
-          { value: 32, name: '时间不合适' },
-          { value: 30, name: '发现更贵的平台' },
-          { value: 28, name: '不想卖了' },
-          { value: 26, name: '信息填写错误' },
-          { value: 22, name: '以上都不是' }
+          { value: 0, name: '快递不取件' },
+          { value: 0, name: '快递不上门' },
+          { value: 0, name: '时间不合适' },
+          { value: 0, name: '发现更贵的平台' },
+          { value: 0, name: '不想卖了' },
+          { value: 0, name: '信息填写错误' },
+          { value: 0, name: '以上都不是' }
         ]
       }
     ]
   });
+
+  // 更新图表数据
+  const updateChartData = (data) => {
+    if (!data || !data.reasonList) return;
+    
+    // 假设API返回的数据格式是reasonList数组,每项包含reason和count
+    const chartData = data.reasonList.map(item => ({
+      value: item.count,
+      name: item.reason
+    }));
+    
+    options.series[0].data = chartData;
+  };
+
+  // 暴露更新方法给父组件使用
+  defineExpose({
+    updateChartData
+  });
 </script>

+ 32 - 11
src/views/optimization/orderAnalysis/components/rank-list.vue

@@ -9,23 +9,44 @@
 </template>
 
 <script setup>
-  import SimpleTable from '@/components/CommonPage/SimpleTable.vue';
+  import { reactive, defineExpose } from 'vue';
   import request from '@/utils/request';
 
   const columns = reactive([
     { label: '排行榜', prop: 'rank', align: 'center' },
-    { label: '取消地区', prop: 'area', align: 'center' },
-    { label: '取消数量', prop: 'number', align: 'center' }
+    { label: '取消地区', prop: 'cityName', align: 'center' },
+    { label: '取消数量', prop: 'count', align: 'center' }
   ]);
 
   const dataList = reactive([
-    { rank: 1, area: '北京', number: 10 },
-    { rank: 2, area: '上海', number: 9 },
-    { rank: 3, area: '广州', number: 8 },
-    { rank: 4, area: '深圳', number: 7 },
-    { rank: 5, area: '成都', number: 6 },
-    { rank: 6, area: '杭州', number: 5 },
-    { rank: 7, area: '武汉', number: 4 },
-    { rank: 8, area: '西安', number: 3 },
+    { rank: 1, cityName: '北京', count: 10 },
+    { rank: 2, cityName: '上海', count: 9 },
+    { rank: 3, cityName: '广州', count: 8 },
+    { rank: 4, cityName: '深圳', count: 7 },
+    { rank: 5, cityName: '成都', count: 6 },
+    { rank: 6, cityName: '杭州', count: 5 },
+    { rank: 7, cityName: '武汉', count: 4 },
+    { rank: 8, cityName: '西安', count: 3 },
   ]);
+
+  // 更新排行榜数据
+  const updateRankData = (data) => {
+    if (!data || !data.rankList) return;
+    
+    // 清空现有数据
+    dataList.length = 0;
+    
+    // 添加新数据,同时设置排名
+    data.rankList.forEach((item, index) => {
+      dataList.push({
+        ...item,
+        rank: index + 1
+      });
+    });
+  };
+
+  // 暴露更新方法给父组件使用
+  defineExpose({
+    updateRankData
+  });
 </script>

+ 203 - 9
src/views/optimization/orderAnalysis/index.vue

@@ -7,9 +7,48 @@
       :tools="false"
     >
       <template #toolbar>
+        <!-- 添加日期选择器 -->
+        <div class="date-selector-container">
+          <div class="date-period-selector">
+            <el-button
+              :class="{ active: activePeriod === 'yesterday' }"
+              @click="changePeriod('yesterday')"
+            >昨日</el-button>
+            <el-button
+              :class="{ active: activePeriod === '7d' }"
+              @click="changePeriod('7d')"
+            >7日</el-button>
+            <el-button
+              :class="{ active: activePeriod === '15d' }"
+              @click="changePeriod('15d')"
+            >15日</el-button>
+            <el-button
+              :class="{ active: activePeriod === '30d' }"
+              @click="changePeriod('30d')"
+            >30日</el-button>
+
+            <el-date-picker
+              v-model="dateRange"
+              type="datetimerange"
+              range-separator="至"
+              start-placeholder="开始日期时间"
+              end-placeholder="结束日期时间"
+              format="YYYY-MM-DD HH:mm:ss"
+              value-format="YYYY-MM-DD HH:mm:ss"
+              :clearable="false"
+              :disabled-date="(date) => false"
+              @change="handleDateRangeChange"
+            />
+            <div class="date-action-buttons">
+              <el-button type="primary" @click="fetchData">搜索</el-button>
+              <el-button @click="resetFilters">重置</el-button>
+            </div>
+          </div>
+        </div>
+        
         <div class="flex mb-6">
-          <pieChart class="flex-1"></pieChart>
-          <rank-list></rank-list>
+          <pieChart ref="pieChartRef" class="flex-1"></pieChart>
+          <rank-list ref="rankListRef"></rank-list>
         </div>
       </template>
     </common-table>
@@ -17,34 +56,189 @@
 </template>
 
 <script setup>
-  import { ref, reactive } from 'vue';
+  import { ref, reactive, onMounted, computed } from 'vue';
   import CommonTable from '@/components/CommonPage/CommonTable.vue';
   import pieChart from '@/views/optimization/orderAnalysis/components/pie-chart.vue';
   import rankList from '@/views/optimization/orderAnalysis/components/rank-list.vue';
   import { useDictData } from '@/utils/use-dict-data';
+  import dayjs from 'dayjs';
+  import request from '@/utils/request';
+  import { ElMessage } from 'element-plus';
 
   defineOptions({ name: 'orderCancelAnalysis' });
 
+  // 状态变量
+  const activePeriod = ref('');
+  const isCustomDateRange = ref(false);
+  const dateRange = ref([
+    dayjs().startOf('day').format('YYYY-MM-DD HH:mm:ss'),
+    dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss')
+  ]);
+
+  // 图表组件实例
+  const pieChartRef = ref(null);
+  const rankListRef = ref(null);
+
   /** 表格列配置 */
   const columns = ref([
-    { label: '订单编号', prop: 'orderCode', align: 'center' },
-    { label: '用户UID', prop: 'uid', align: 'center' },
-    { label: '取消原因', prop: 'cancelReason', align: 'center', minWidth: 200 },
-    { label: '取消时间', prop: 'createTime', align: 'center' }
+    { label: '订单编号', prop: 'orderId', align: 'center' },
+    { label: '用户UID', prop: 'userId', align: 'center' },
+    { label: '用户昵称', prop: 'nickName', align: 'center' },
+    { label: '取消原因', prop: 'reason', align: 'center', minWidth: 200 },
+    { label: '取消时间', prop: 'cancelTime', align: 'center' }
   ]);
 
   /** 页面组件实例 */
   const pageRef = ref(null);
 
   const pageConfig = reactive({
-    pageUrl: '/baseinfo/godown/pagelist',
-    exportUrl: '/baseinfo/godown/export',
+    pageUrl: '/order/recycleOrderStatistic/cancel/list',
     fileName: '订单取消分析',
     cacheKey: 'orderCancelAnalysisTable'
   });
 
+  // 根据时间段更新日期范围的方法
+  const updateDateRangeByPeriod = (period) => {
+    isCustomDateRange.value = false;
+
+    switch (period) {
+      case 'yesterday':
+        dateRange.value = [
+          dayjs().subtract(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
+          dayjs().subtract(1, 'day').endOf('day').format('YYYY-MM-DD 23:59:59')
+        ];
+        break;
+      case '7d':
+        dateRange.value = [
+          dayjs().subtract(7, 'day').startOf('day').format('YYYY-MM-DD 00:00:00'),
+          dayjs().endOf('day').format('YYYY-MM-DD 23:59:59')
+        ];
+        break;
+      case '15d':
+        dateRange.value = [
+          dayjs().subtract(15, 'day').startOf('day').format('YYYY-MM-DD 00:00:00'),
+          dayjs().endOf('day').format('YYYY-MM-DD 23:59:59')
+        ];
+        break;
+      case '30d':
+        dateRange.value = [
+          dayjs().subtract(30, 'day').startOf('day').format('YYYY-MM-DD 00:00:00'),
+          dayjs().endOf('day').format('YYYY-MM-DD 23:59:59')
+        ];
+        break;
+      default:
+        dateRange.value = [
+          dayjs().startOf('day').format('YYYY-MM-DD 00:00:00'),
+          dayjs().endOf('day').format('YYYY-MM-DD 23:59:59')
+        ];
+    }
+  };
+
+  // 处理时间段变更按钮点击的方法
+  const changePeriod = (period) => {
+    activePeriod.value = period;
+    updateDateRangeByPeriod(period);
+    fetchData();
+  };
+
+  // 处理日期选择器变更
+  const handleDateRangeChange = () => {
+    isCustomDateRange.value = true;
+    activePeriod.value = '';
+  };
+
+  const getDateRangeForAPI = () => {
+    let startDate, endDate;
+
+    if (Array.isArray(dateRange.value) && dateRange.value.length === 2) {
+      startDate = dateRange.value[0];
+      endDate = dateRange.value[1];
+    } else {
+      // 如果dateRange不是数组,使用当天作为默认值
+      startDate = dayjs().startOf('day').format('YYYY-MM-DD 00:00:00');
+      endDate = dayjs().endOf('day').format('YYYY-MM-DD 23:59:59');
+    }
+
+    return { startDate, endDate };
+  };
+
+  const fetchData = async () => {
+    const { startDate, endDate } = getDateRangeForAPI();
+    
+    try {
+      // 统计数据
+      const { data } = await request.get('/order/recycleOrderStatistic/cancel/sum', {
+        params: {
+          startDate,
+          endDate
+        }
+      });
+      
+      // 更新饼图和排行榜数据
+      if (data && data.data) {
+        pieChartRef.value?.updateChartData(data.data);
+        rankListRef.value?.updateRankData(data.data);
+      }
+      
+      // 刷新表格
+      reload({
+        startDate,
+        endDate
+      });
+    } catch (error) {
+      ElMessage.error('获取数据失败');
+      console.error('Failed to fetch statistic data:', error);
+    }
+  };
+
+  const resetFilters = () => {
+    isCustomDateRange.value = false;
+    activePeriod.value = '';
+    // 重置为今日
+    dateRange.value = [
+      dayjs().startOf('day').format('YYYY-MM-DD 00:00:00'),
+      dayjs().endOf('day').format('YYYY-MM-DD 23:59:59')
+    ];
+    fetchData();
+  };
+
   //刷新表格
   function reload(where) {
     pageRef.value?.reload(where);
   }
+
+  onMounted(() => {
+    // 默认加载今日数据
+    fetchData();
+  });
 </script>
+
+<style lang="scss" scoped>
+  .date-selector-container {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-bottom: 20px;
+    border-bottom: 1px solid #ebeef5;
+    padding-bottom: 16px;
+  }
+
+  .date-period-selector {
+    display: flex;
+    gap: 10px;
+
+    .el-button {
+      border-radius: 4px;
+    }
+
+    .active {
+      color: #409eff;
+      border-color: #409eff;
+    }
+  }
+
+  .date-action-buttons {
+    display: flex;
+    gap: 8px;
+  }
+</style>