Преглед на файлове

Merge branch 'master' of https://gogs.dev.dazesoft.cn/dtm_organization/dtm_vue

# Conflicts:
#	src/views/order/channel/index.vue
#	src/views/order/efficiency/index.vue
#	src/views/order/ordervalue/index.vue
#	src/views/order/related/index.vue
#	src/views/order/shopvalue/index.vue
Zhu Jiaqi преди 2 месеца
родител
ревизия
72b4f434ec

+ 153 - 0
src/api/order.js

@@ -0,0 +1,153 @@
+import request from '@/utils/request'
+
+export function uploadOrderValueFiles(data) {
+  return request({
+    url: '/api/import/import-data/upload',
+    method: 'post',
+    data,
+    headers: {
+      'Content-Type': 'multipart/form-data',
+      repeatSubmit: false
+    },
+    timeout: 300000
+  })
+}
+
+export function getOrderMaxDate() {
+  return request({
+    url: '/api/analysis/max-date',
+    method: 'get'
+  })
+}
+
+export function getOrderGmv(params) {
+  return request({
+    url: '/api/analysis/gmv',
+    method: 'get',
+    params
+  })
+}
+
+export function getOrderRBig(params) {
+  return request({
+    url: '/api/analysis/r-big',
+    method: 'get',
+    params
+  })
+}
+
+export function getOrderTop5Percentage(params) {
+  return request({
+    url: '/api/analysis/top5-percentage',
+    method: 'get',
+    params
+  })
+}
+
+export function getOrderAveragePaymentTime(params) {
+  return request({
+    url: '/api/analysis/average-payment-time',
+    method: 'get',
+    params
+  })
+}
+
+export function getOrderTop5Products(params) {
+  return request({
+    url: '/api/analysis/top5-products',
+    method: 'get',
+    params
+  })
+}
+
+export function getOrderLeakageRate(params) {
+  return request({
+    url: '/api/analysis/leakage-rate',
+    method: 'get',
+    params
+  })
+}
+
+export function getOrderPaymentDecisionFunnel(params) {
+  return request({
+    url: '/api/analysis/payment-decision-funnel',
+    method: 'get',
+    params
+  })
+}
+
+export function getOrderCoPurchase() {
+  return request({
+    url: '/api/analysis/co-purchase',
+    method: 'get'
+  })
+}
+
+export function uploadShopValueFiles(data) {
+  return request({
+    url: '/api/shop/import/import-sales-data/upload',
+    method: 'post',
+    data,
+    headers: {
+      'Content-Type': 'multipart/form-data',
+      repeatSubmit: false
+    },
+    timeout: 300000
+  })
+}
+
+export function getShopTopProductContribution() {
+  return request({
+    url: '/api/shop/import/top-product-contribution',
+    method: 'get'
+  })
+}
+
+export function getShopUnitContribution() {
+  return request({
+    url: '/api/shop/import/unit-contribution',
+    method: 'get'
+  })
+}
+
+export function getShopChannelTotalContribution() {
+  return request({
+    url: '/api/shop/import/channel-total-contribution',
+    method: 'get'
+  })
+}
+
+export function getShopChannelContribution() {
+  return request({
+    url: '/api/shop/import/channel-contribution',
+    method: 'get'
+  })
+}
+
+export function getShopChannelRoiValue() {
+  return request({
+    url: '/api/shop/import/channel-roi-value',
+    method: 'get'
+  })
+}
+
+export function getShopCrossSellingProducts() {
+  return request({
+    url: '/api/shop/import/cross-selling-products',
+    method: 'get'
+  })
+}
+
+export function getShopDepartmentEfficiency() {
+  return request({
+    url: '/api/shop/import/department-efficiency',
+    method: 'get'
+  })
+}
+
+export function getShopChannelDiversity() {
+  return request({
+    url: '/api/shop/import/channel-diversity',
+    method: 'get'
+  })
+}

+ 4 - 4
src/views/order/channel/index.vue

@@ -43,7 +43,7 @@
 
 <script>
 import * as echarts from 'echarts';
-import axios from 'axios';
+import { getShopCrossSellingProducts } from '@/api/order';
 
 export default {
   name: 'OrderChannel',
@@ -108,9 +108,9 @@ export default {
     },
     async fetchData() {
       try {
-        const response = await axios.get('/prod-api/api/shop/import/cross-selling-products');
-        if (response.data.success) {
-          this.allProducts = response.data.data || [];
+        const response = await getShopCrossSellingProducts();
+        if (response.success) {
+          this.allProducts = response.data || [];
           this.initLineChart();
         }
       } catch (error) {

+ 5 - 5
src/views/order/efficiency/index.vue

@@ -33,8 +33,8 @@
 </template>
 
 <script>
-import axios from 'axios';
 import * as echarts from 'echarts';
+import { getShopChannelDiversity, getShopDepartmentEfficiency } from '@/api/order';
 
 export default {
   name: 'OrderEfficiency',
@@ -60,11 +60,11 @@ export default {
     async initBarChart() {
       this.barChart.loading = true;
       try {
-        const response = await axios.get('/prod-api/api/shop/import/department-efficiency');
+        const response = await axios.get('/api/shop/import/department-efficiency');
         if (!response.data || !response.data.success) {
           throw new Error(response.data.message || 'REPLACED__');
         }
-        const rawData = response.data.data;
+        const rawData = response.data;
         const chartData = Object.entries(rawData).map(([name, value]) => ({
           name,
           value: parseFloat(value).toFixed(2)
@@ -105,11 +105,11 @@ export default {
     async initPieChart() {
       this.pieChart.loading = true;
       try {
-        const response = await axios.get('/prod-api/api/shop/import/channel-diversity');
+        const response = await axios.get('/api/shop/import/channel-diversity');
         if (!response.data || !response.data.success) {
           throw new Error(response.data.message || '渠道多样性数据获取失败');
         }
-        const rawData = response.data.data;
+        const rawData = response.data;
         const chartData = Object.entries(rawData).map(([name, value]) => ({ name, value }));
 
         await this.$nextTick();

+ 7 - 14
src/views/order/ordervalue/FunnelChart/index.vue

@@ -13,10 +13,8 @@
 
 
 <script>
-
-import axios from 'axios';
-
 import * as echarts from 'echarts';
+import { getOrderPaymentDecisionFunnel } from '@/api/order';
 
 
 
@@ -93,18 +91,13 @@ export default {
     async fetchFunnelData(dateRange = null) {
 
       try {
+        const params = dateRange && dateRange.start && dateRange.end
+          ? { startDate: dateRange.start, endDate: dateRange.end }
+          : undefined;
 
-        let apiUrl = '/api/analysis/payment-decision-funnel';
-
-        if (dateRange && dateRange.start && dateRange.end) {
-
-          apiUrl += `?startDate=${dateRange.start}&endDate=${dateRange.end}`;
-
-        }
-
-        const response = await axios.get(apiUrl);
+        const response = await getOrderPaymentDecisionFunnel(params);
 
-        const data = response.data.data;
+        const data = response.data;
 
         this.rawData = data;
 
@@ -254,4 +247,4 @@ export default {
 
 }
 
-</style>
+</style>

+ 10 - 16
src/views/order/ordervalue/LeakageCard/index.vue

@@ -45,8 +45,7 @@
 
 
 <script>
-
-import axios from 'axios';
+import { getOrderLeakageRate } from '@/api/order';
 
 
 
@@ -113,24 +112,19 @@ export default {
     async fetchLeakageData(dateRange = null) {
 
       try {
+        const params = dateRange && dateRange.start && dateRange.end
+          ? { startDate: dateRange.start, endDate: dateRange.end }
+          : undefined;
 
-        let apiUrl = '/api/analysis/leakage-rate';
-
-        if (dateRange && dateRange.start && dateRange.end) {
-
-          apiUrl += `?startDate=${dateRange.start}&endDate=${dateRange.end}`;
-
-        }
-
-        const response = await axios.get(apiUrl);
+        const response = await getOrderLeakageRate(params);
 
-        if (response.data) {
+        if (response) {
 
-          this.leakageData.totalRefundAmount = this.currencyFormatter.format(response.data.totalRefundAmount || 0);
+          this.leakageData.totalRefundAmount = this.currencyFormatter.format(response.totalRefundAmount || 0);
 
-          this.leakageData.leakageRatePercent = (response.data.leakageRatePercent || 0).toFixed(1);
+          this.leakageData.leakageRatePercent = (response.leakageRatePercent || 0).toFixed(1);
 
-          this.leakageData.totalSuccessAmount = this.currencyFormatter.format(response.data.totalSuccessAmount || 0);
+          this.leakageData.totalSuccessAmount = this.currencyFormatter.format(response.totalSuccessAmount || 0);
 
         }
 
@@ -270,4 +264,4 @@ export default {
 
 .detail-value.success { color: #67C23A; }
 
-</style>
+</style>

+ 9 - 26
src/views/order/ordervalue/Top5PieChart/index.vue

@@ -27,10 +27,8 @@
 
 
 <script>
-
-import axios from 'axios';
-
 import * as echarts from 'echarts';
+import { getOrderTop5Percentage, getOrderTop5Products } from '@/api/order';
 
 
 
@@ -93,26 +91,11 @@ export default {
     async fetchPieData(dateRange = null) {
 
       try {
+        const params = dateRange && dateRange.start && dateRange.end
+          ? { startDate: dateRange.start, endDate: dateRange.end }
+          : undefined;
 
-        let productsUrl = '/api/analysis/top5-products';
-
-        let percentageUrl = '/api/analysis/top5-percentage';
-
-        if (dateRange && dateRange.start && dateRange.end) {
-
-          const params = `?startDate=${dateRange.start}&endDate=${dateRange.end}`;
-
-          productsUrl += params;
-
-          percentageUrl += params;
-
-        }
-
-
-
-        const productsResponse = await axios.get(productsUrl);
-
-        const rawProducts = productsResponse.data || [];
+        const rawProducts = await getOrderTop5Products(params) || [];
 
 
 
@@ -130,11 +113,11 @@ export default {
 
 
 
-        const percentageResponse = await axios.get(percentageUrl);
+        const percentageResponse = await getOrderTop5Percentage(params);
 
-        if (percentageResponse.data.success) {
+        if (percentageResponse.success) {
 
-          this.top5Percent = Math.round(percentageResponse.data.data.top5Percentage);
+          this.top5Percent = Math.round(percentageResponse.data.top5Percentage);
 
         }
 
@@ -342,4 +325,4 @@ export default {
 
 }
 
-</style>
+</style>

+ 43 - 45
src/views/order/ordervalue/index.vue

@@ -47,7 +47,7 @@
 
     </section>
 
-
+    
 
     <!-- 图表区域 -->
 
@@ -57,23 +57,23 @@
 
       <div class="chart-wrapper funnel-chart-wrapper">
 
-        <FunnelChart :date-range="currentDateRange" />
+        <FunnelChart :date-range="currentDateRange" /> 
 
       </div>
 
-
+      
 
       <!-- 明星商品价值环图 (Top 5) -->
 
       <div class="chart-wrapper">
 
-        <Top5PieChart :date-range="currentDateRange" />
+        <Top5PieChart :date-range="currentDateRange" /> 
 
       </div>
 
     </section>
 
-
+    
 
     <!-- 订单价值漏损分析 (退款) - 铺满整排 -->
 
@@ -94,16 +94,18 @@
 
 
 <script>
-
-import axios from 'axios';
-
 import KpiCard from './KpiCard/index.vue';
-
 import FunnelChart from './FunnelChart/index.vue';
-
 import Top5PieChart from './Top5PieChart/index.vue';
-
 import LeakageCard from './LeakageCard/index.vue';
+import {
+  getOrderAveragePaymentTime,
+  getOrderGmv,
+  getOrderMaxDate,
+  getOrderRBig,
+  getOrderTop5Percentage,
+  uploadOrderValueFiles
+} from '@/api/order';
 
 
 
@@ -247,11 +249,7 @@ export default {
 
         files.forEach(file => formData.append('files', file));
 
-        const { data } = await axios.post('/prod-api/api/import/import-data/upload', formData, {
-
-          headers: { 'Content-Type': 'multipart/form-data' }
-
-        });
+        const data = await uploadOrderValueFiles(formData);
 
         if (data && data.success) {
 
@@ -369,37 +367,37 @@ export default {
 
         const [gmvRes, p80Res, top5Res, avgTimeRes] = await Promise.all([
 
-          axios.get(`/prod-api/api/analysis/gmv?startDate=${startDate}&endDate=${endDate}`),
+          getOrderGmv({ startDate, endDate }),
 
-          axios.get(`/prod-api/api/analysis/r-big?startDate=${startDate}&endDate=${endDate}`),
+          getOrderRBig({ startDate, endDate }),
 
-          axios.get(`/prod-api/api/analysis/top5-percentage?startDate=${startDate}&endDate=${endDate}`),
+          getOrderTop5Percentage({ startDate, endDate }),
 
-          axios.get(`/prod-api/api/analysis/average-payment-time?startDate=${startDate}&endDate=${endDate}`)
+          getOrderAveragePaymentTime({ startDate, endDate })
 
         ]);
 
 
 
-        const gmvValue = gmvRes.data || 0;
+        const gmvValue = gmvRes || 0;
 
         this.kpiData.gmv = new Intl.NumberFormat('zh-CN', { style: 'currency', currency: 'CNY' }).format(gmvValue);
 
 
 
-        const p80Value = p80Res.data?.rBigRatio || 0;
+        const p80Value = p80Res?.rBigRatio || 0;
 
         this.kpiData.p80Contribution = `${Math.round(p80Value)}%`;
 
 
 
-        const top5Value = top5Res.data?.data?.top5Percentage || 0;
+        const top5Value = top5Res?.data?.top5Percentage || 0;
 
         this.kpiData.top5Contribution = `${Math.round(top5Value)}%`;
 
 
 
-        const avgSeconds = avgTimeRes.data?.averagePaymentSeconds || 0;
+        const avgSeconds = avgTimeRes?.averagePaymentSeconds || 0;
 
         const minutes = Math.floor(avgSeconds / 60);
 
@@ -487,13 +485,13 @@ export default {
 
         const [gmvRes, p80Res, top5Res, avgTimeRes] = await Promise.all([
 
-          axios.get(`/prod-api/api/analysis/gmv?startDate=${previousMonthStart}&endDate=${previousMonthEnd}`),
+          getOrderGmv({ startDate: previousMonthStart, endDate: previousMonthEnd }),
 
-          axios.get(`/prod-api/api/analysis/r-big?startDate=${previousMonthStart}&endDate=${previousMonthEnd}`),
+          getOrderRBig({ startDate: previousMonthStart, endDate: previousMonthEnd }),
 
-          axios.get(`/prod-api/api/analysis/top5-percentage?startDate=${previousMonthStart}&endDate=${previousMonthEnd}`),
+          getOrderTop5Percentage({ startDate: previousMonthStart, endDate: previousMonthEnd }),
 
-          axios.get(`/prod-api/api/analysis/average-payment-time?startDate=${previousMonthStart}&endDate=${previousMonthEnd}`)
+          getOrderAveragePaymentTime({ startDate: previousMonthStart, endDate: previousMonthEnd })
 
         ]);
 
@@ -501,13 +499,13 @@ export default {
 
         return {
 
-          gmv: gmvRes.data || 0,
+          gmv: gmvRes || 0,
 
-          p80: p80Res.data?.rBigRatio || 0,
+          p80: p80Res?.rBigRatio || 0,
 
-          top5: top5Res.data?.data?.top5Percentage || 0,
+          top5: top5Res?.data?.top5Percentage || 0,
 
-          avgTime: avgTimeRes.data?.averagePaymentSeconds || 0
+          avgTime: avgTimeRes?.averagePaymentSeconds || 0
 
         };
 
@@ -525,17 +523,17 @@ export default {
 
       try {
 
-        const res = await axios.get('/prod-api/api/analysis/max-date');
+        const res = await getOrderMaxDate();
 
-        this.maxDate = res.data;
+        this.maxDate = res;
 
-        this.selectedDate = res.data;
+        this.selectedDate = res;
 
 
 
-        const startDate = this.formatYmd(this.addDays(res.data, -6));
+        const startDate = this.formatYmd(this.addDays(res, -6));
 
-        this.currentDateRange = { start: startDate, end: res.data };
+        this.currentDateRange = { start: startDate, end: res };
 
         await this.fetchAllApiData();
 
@@ -663,31 +661,31 @@ export default {
 
         const [gmvRes, p80Res, top5Res, avgTimeRes] = await Promise.all([
 
-          axios.get('/prod-api/api/analysis/gmv'),
+          getOrderGmv(),
 
-          axios.get('/prod-api/api/analysis/r-big'),
+          getOrderRBig(),
 
-          axios.get('/prod-api/api/analysis/top5-percentage'),
+          getOrderTop5Percentage(),
 
-          axios.get('/prod-api/api/analysis/average-payment-time')
+          getOrderAveragePaymentTime()
 
         ]);
 
 
 
-        const gmvValue = gmvRes.data || 0;
+        const gmvValue = gmvRes || 0;
 
         this.kpiData.gmv = new Intl.NumberFormat('zh-CN', { style: 'currency', currency: 'CNY' }).format(gmvValue);
 
-        const p80Value = p80Res.data?.rBigRatio || 0;
+        const p80Value = p80Res?.rBigRatio || 0;
 
         this.kpiData.p80Contribution = `${Math.round(p80Value)}%`;
 
-        const top5Value = top5Res.data?.data?.top5Percentage || 0;
+        const top5Value = top5Res?.data?.top5Percentage || 0;
 
         this.kpiData.top5Contribution = `${Math.round(top5Value)}%`;
 
-        const avgSeconds = avgTimeRes.data?.averagePaymentSeconds || 0;
+        const avgSeconds = avgTimeRes?.averagePaymentSeconds || 0;
 
         const minutes = Math.floor(avgSeconds / 60);
 

+ 29 - 29
src/views/order/related/index.vue

@@ -36,11 +36,11 @@
           </tr>
         </tbody>
       </table>
-
+      
       <!-- 分页控件 -->
       <div class="pagination">
-        <button
-          :disabled="currentPage === 1"
+        <button 
+          :disabled="currentPage === 1" 
           @click="prevPage"
           class="page-button"
         >
@@ -49,8 +49,8 @@
         <span class="page-info">
           第 {{ currentPage }} 页,共 {{ totalPages }} 页
         </span>
-        <button
-          :disabled="currentPage === totalPages"
+        <button 
+          :disabled="currentPage === totalPages" 
           @click="nextPage"
           class="page-button"
         >
@@ -68,8 +68,8 @@
 </template>
 
 <script>
-import axios from 'axios';
 import * as echarts from 'echarts';
+import { getOrderCoPurchase } from '@/api/order';
 
 export default {
   name: 'OrderRelated',
@@ -107,8 +107,8 @@ export default {
     },
     async fetchData() {
       try {
-        const response = await axios.get('/prod-api/api/analysis/co-purchase');
-        this.coPurchaseData = response.data || [];
+        const response = await getOrderCoPurchase();
+        this.coPurchaseData = response || [];
         this.renderNetworkChart(this.coPurchaseData);
       } catch (error) {
         console.error("获取共现购买数据失败:", error);
@@ -120,27 +120,27 @@ export default {
       const chartEl = this.$refs.networkChart;
       if (!chartEl || !data) return;
       const myChart = echarts.init(chartEl);
-
+  
   // 统计每个节点的出现次数(核心度)
   const nodeCount = {};
   // 统计每条连线的权重
   const linkWeights = {};
-
+  
   data.forEach(item => {
     // 统计节点出现次数
     nodeCount[item.productAId] = (nodeCount[item.productAId] || 0) + 1;
     nodeCount[item.productBId] = (nodeCount[item.productBId] || 0) + 1;
-
+    
     // 统计连线权重
     const linkKey = `${item.productAId}-${item.productBId}`;
     linkWeights[linkKey] = (linkWeights[linkKey] || 0) + item.coPurchaseCount;
   });
-
+  
   // 创建节点和连线
   const nodes = [];
   const links = [];
   const nodeSet = new Set();
-
+  
   // 用于自动聚类的颜色分类
   const categories = [
     { name: '社群1', itemStyle: { color: '#FF6B6B' } },
@@ -150,11 +150,11 @@ export default {
     { name: '社群5', itemStyle: { color: '#FFEAA7' } },
     { name: '社群6', itemStyle: { color: '#DDA0DD' } }
   ];
-
+  
   // 用于社群聚类的简单算法
   const nodeCategories = {};
   let categoryIndex = 0;
-
+  
   data.forEach(item => {
     // 添加节点A
     if (!nodeSet.has(item.productAId)) {
@@ -163,22 +163,22 @@ export default {
       const count = nodeCount[item.productAId];
       // 节点大小范围:15-50
       const symbolSize = Math.min(15 + count * 5, 50);
-
+      
       // 简单的社群聚类:根据第一个关联商品确定社群
       if (!nodeCategories[item.productAId]) {
         nodeCategories[item.productAId] = categoryIndex % categories.length;
         categoryIndex++;
       }
-
-      nodes.push({
-        id: item.productAId,
-        name: item.productAId,
-        symbolSize: symbolSize,
+      
+      nodes.push({ 
+        id: item.productAId, 
+        name: item.productAId, 
+        symbolSize: symbolSize, 
         category: nodeCategories[item.productAId],
         value: count // 用于tooltip显示
       });
     }
-
+    
     // 添加节点B
     if (!nodeSet.has(item.productBId)) {
       nodeSet.add(item.productBId);
@@ -186,22 +186,22 @@ export default {
       const count = nodeCount[item.productBId];
       // 节点大小范围:15-50
       const symbolSize = Math.min(15 + count * 5, 50);
-
+      
       // 简单的社群聚类:根据第一个关联商品确定社群
       if (!nodeCategories[item.productBId]) {
         nodeCategories[item.productBId] = categoryIndex % categories.length;
         categoryIndex++;
       }
-
-      nodes.push({
-        id: item.productBId,
-        name: item.productBId,
-        symbolSize: symbolSize,
+      
+      nodes.push({ 
+        id: item.productBId, 
+        name: item.productBId, 
+        symbolSize: symbolSize, 
         category: nodeCategories[item.productBId],
         value: count // 用于tooltip显示
       });
     }
-
+    
     // 添加连线
     const linkKey = `${item.productAId}-${item.productBId}`;
     const weight = linkWeights[linkKey];

+ 27 - 22
src/views/order/shopvalue/index.vue

@@ -32,7 +32,7 @@
             <span class="kpi-value">{{ (topProductData.contributionRatio * 100).toFixed(2) }}%</span>
           </div>
         </div>
-
+        
         <!-- 下方的环形图 -->
         <div class="chart-card">
           <h3 class="chart-title">Top 5 商品销售分布</h3>
@@ -77,8 +77,15 @@
 </template>
 
 <script>
-import axios from 'axios';
 import * as echarts from 'echarts';
+import {
+  getShopChannelContribution,
+  getShopChannelRoiValue,
+  getShopChannelTotalContribution,
+  getShopTopProductContribution,
+  getShopUnitContribution,
+  uploadShopValueFiles
+} from '@/api/order';
 
 export default {
   name: 'ShopValue',
@@ -126,9 +133,7 @@ export default {
       try {
         const formData = new FormData();
         files.forEach(file => formData.append('files', file));
-        const { data } = await axios.post('/prod-api/api/shop/import/import-sales-data/upload', formData, {
-          headers: { 'Content-Type': 'multipart/form-data' }
-        });
+        const data = await uploadShopValueFiles(formData);
         if (data && data.success) {
           this.$modal.msgSuccess(data.message || '上传并导入成功');
           await this.fetchData();
@@ -207,9 +212,9 @@ export default {
     },
     async fetchTopProductData() {
       try {
-        const response = await axios.get('/prod-api/api/shop/import/top-product-contribution');
-        if (response.data.success) {
-          const data = response.data.data;
+        const response = await getShopTopProductContribution();
+        if (response.success) {
+          const data = response.data;
           this.topProductData.totalSales = data.totalSales;
           this.topProductData.top5TotalSales = data.top5TotalSales;
           this.topProductData.contributionRatio = data.contributionRatio;
@@ -354,14 +359,14 @@ export default {
           channelContributionRes,
           channelRoiValueRes
         ] = await Promise.all([
-          axios.get('/prod-api/api/shop/import/unit-contribution'),
-          axios.get('/prod-api/api/shop/import/channel-total-contribution'),
-          axios.get('/prod-api/api/shop/import/channel-contribution'),
-          axios.get('/prod-api/api/shop/import/channel-roi-value')
+          getShopUnitContribution(),
+          getShopChannelTotalContribution(),
+          getShopChannelContribution(),
+          getShopChannelRoiValue()
         ]);
 
-        if (unitRes.data.success && unitRes.data.data) {
-          const sortedData = [...unitRes.data.data].sort((a, b) => b.totalAmount - a.totalAmount);
+        if (unitRes.success && unitRes.data) {
+          const sortedData = [...unitRes.data].sort((a, b) => b.totalAmount - a.totalAmount);
           this.initDualIndicatorBarChart(
             this.$refs.unitContributionChart,
             sortedData,
@@ -378,8 +383,8 @@ export default {
           );
         }
 
-        if (channelTotalRes.data.success && channelTotalRes.data.data) {
-          const sortedData = [...channelTotalRes.data.data].sort((a, b) => b.totalAmount - a.totalAmount);
+        if (channelTotalRes.success && channelTotalRes.data) {
+          const sortedData = [...channelTotalRes.data].sort((a, b) => b.totalAmount - a.totalAmount);
           this.initDualIndicatorBarChart(
             this.$refs.channelTotalChart,
             sortedData,
@@ -397,17 +402,17 @@ export default {
         }
 
         if (
-          channelContributionRes.data.success &&
-          channelRoiValueRes.data.success &&
-          channelContributionRes.data.data &&
-          channelRoiValueRes.data.data
+          channelContributionRes.success &&
+          channelRoiValueRes.success &&
+          channelContributionRes.data &&
+          channelRoiValueRes.data
         ) {
-          const platformSales = Object.entries(channelContributionRes.data.data).map(([name, value]) => ({
+          const platformSales = Object.entries(channelContributionRes.data).map(([name, value]) => ({
             name,
             totalVolume: Number(value)
           }));
 
-          const platformAvgOrder = Object.entries(channelRoiValueRes.data.data).map(([name, value]) => ({
+          const platformAvgOrder = Object.entries(channelRoiValueRes.data).map(([name, value]) => ({
             name,
             avgOrderValue: Number(value)
           }));