Explorar o código

Refactor customs data components to enhance sorting and data fetching. Updated HsCodeAnalysis, OriginCountryAnalysis, and OrigPortAnalysis to utilize query parameters for data retrieval, improving performance. Simplified sorting options and pagination in DestinationCountryAnalysis and OrigPortAnalysis. Removed unused data fetching methods for cleaner code and better maintainability.

zq940222 hai 3 meses
pai
achega
c806e13f2b

+ 2 - 2
src/views/adweb/data/components/DestinationCountryAnalysis.vue

@@ -5,8 +5,8 @@
             <span>排序:</span>
             <a-radio-group v-model:value="sortMode" button-style="solid" style="margin-left: 16px;" @change="handleSortChange">
             <a-radio-button value="count">交易次数</a-radio-button>
-            <a-radio-button value="sum_weight">交易重量</a-radio-button>
-            <a-radio-button value="sum_amount">交易金额</a-radio-button>
+            <a-radio-button value="weight">交易重量</a-radio-button>
+            <a-radio-button value="amount">交易金额</a-radio-button>
         </a-radio-group>
         </template>
         <!-- 添加切换按钮组 -->

+ 79 - 15
src/views/adweb/data/components/HsCodeAnalysis.vue

@@ -3,8 +3,7 @@
   <a-card title="产品">
     <template #extra>
       <span>排序:</span>
-      <a-radio-group v-model:value="sortMode" button-style="solid" style="margin-left: 16px;"
-        @change="handleSortChange">
+      <a-radio-group v-model:value="sortMode" button-style="solid" style="margin-left: 16px;">
         <a-radio-button value="count">交易次数</a-radio-button>
         <a-radio-button value="weight">交易重量</a-radio-button>
         <a-radio-button value="amount">交易金额</a-radio-button>
@@ -23,7 +22,15 @@
 
       <!-- 列表视图 -->
       <div v-show="viewType === 'table'">
-        <a-table :columns="columns" :data-source="tableData" :pagination="false">
+        <a-table :columns="columns" :data-source="tableData" :loading="loading" row-key="fk" :pagination="{
+          current: pagination.current,
+          pageSize: pagination.pageSize,
+          total: pagination.total,
+          showSizeChanger: true,
+          showQuickJumper: true,
+          showTotal: (total) => `共 ${total} 条`,
+          onShowSizeChange: handleTableChange,
+        }" @change="handleTableChange">
           <template #bodyCell="{ column, record }">
             <template v-if="column.dataIndex === 'val'">
               {{ record.val }}
@@ -36,8 +43,9 @@
 </template>
 
 <script lang="ts">
-import { defineComponent, ref, computed, onMounted, watch } from 'vue';
+import { defineComponent, ref, onMounted, watch } from 'vue';
 import { useECharts } from '/@/hooks/web/useECharts';
+import { getHsCodeReport } from '../customsData.api';
 
 export default defineComponent({
   props: {
@@ -49,16 +57,17 @@ export default defineComponent({
       type: String,
       default: '350px',
     },
-    hsCodeData: {
+    queryParam: {
       type: Object,
       default: () => ({}),
     },
   },
-  setup(props, { emit }) {
+  setup(props) {
     const chartRef = ref<HTMLDivElement | null>(null);
     const { setOptions } = useECharts(chartRef);
     const viewType = ref<'chart' | 'table'>('chart');
     const sortMode = ref('count');
+    const loading = ref(false);
 
     // 格式化函数
     const formatNumber = (value: string | number) => {
@@ -99,16 +108,27 @@ export default defineComponent({
     ];
 
     // 计算表格数据
-    const tableData = computed(() => {
-      return props.hsCodeData?.buckets || [];
+    const tableData = ref([]);
+
+    const pagination = ref({
+      current: 1,
+      pageSize: 10,
+      total: 0
     });
 
-    const handleSortChange = (value: string) => {
-      emit('update:sortMode', value.target.value);
-    };
+    const updateChart = async () => {
+      let chartData = [];
+      const params = {
+        sort: sortMode.value,
+        page: 1,
+        page_size: 10,
+        ...props.queryParam,
+      };
 
-    const updateChart = () => {
-      const chartData = tableData.value;
+      const res = await getHsCodeReport(params);
+      if (res.result.data.result && res.result.data.result.buckets) {
+        chartData = res.result.data.result.buckets;
+      }
       if (!chartData.length) return;
 
       // 取前10条数据展示
@@ -188,16 +208,57 @@ export default defineComponent({
       });
     };
 
+    // Replace registerTransactionTable with this new method
+    const handleTableChange = async (pag, filters, sorter) => {
+      loading.value = true;
+      try {
+        const params = {
+          sort: sortMode.value,
+          page: pag.current,
+          page_size: pag.pageSize,
+          ...props.queryParam,
+        };
+
+        const res = await getHsCodeReport(params);
+        if (res.result.data.result && res.result.data.result.buckets) {
+          pagination.value = {
+            current: pag.current,
+            pageSize: pag.pageSize,
+            total: res.result.data.result.numBuckets || 0,
+          };
+          tableData.value = res.result.data.result.buckets;
+        }
+      } catch (error) {
+        console.error('Failed to fetch data:', error);
+      } finally {
+        loading.value = false;
+      }
+    };
+
+
     watch(
-      () => props.hsCodeData,
+      () => props.queryParam,
       () => {
         updateChart();
       },
       { deep: true }
     );
 
+    watch(
+      () => sortMode.value,
+      () => {
+        updateChart();
+        handleTableChange(pagination.value, {}, {});
+      }
+    );
+
     onMounted(() => {
       updateChart();
+
+    });
+    onMounted(async () => {
+      // 这里可以添加获取数据的逻辑
+      await handleTableChange(pagination.value.current, pagination.value.pageSize, sortMode.value);
     });
 
     return {
@@ -207,7 +268,10 @@ export default defineComponent({
       columns,
       tableData,
       formatNumber,
-      handleSortChange,
+      pagination,
+      loading,
+      handleTableChange,
+      getHsCodeReport
     };
   },
 });

+ 187 - 104
src/views/adweb/data/components/OrigPortAnalysis.vue

@@ -3,23 +3,32 @@
     <a-card title="起运港" :loading="loading">
         <!-- 添加切换按钮组 -->
         <template #extra>
+            <span>排序:</span>
+            <a-radio-group v-model:value="sortMode" button-style="solid" style="margin-left: 16px;">
+                <a-radio-button value="count">交易次数</a-radio-button>
+                <a-radio-button value="weight">交易重量</a-radio-button>
+                <a-radio-button value="amount">交易金额</a-radio-button>
+            </a-radio-group>
+        </template>
+        <!-- 添加切换按钮组 -->
+        <div class="switch-view">
             <a-radio-group v-model:value="viewMode" button-style="solid">
                 <a-radio-button value="chart">图表</a-radio-button>
                 <a-radio-button value="table">列表</a-radio-button>
             </a-radio-group>
-        </template>
-
+        </div>
         <!-- 图表视图 -->
-        <div v-show="viewMode === 'chart'" ref="chartRef" style="height: 400px"></div>
-
+        <div v-show="viewMode === 'chart'" ref="chartRef" :style="{ height, width }"></div>
         <!-- 表格视图 -->
-        <a-table
-            v-show="viewMode === 'table'"
-            :columns="columns"
-            :data-source="tableData"
-            :pagination="false"
-            size="middle"
-        >
+        <a-table v-show="viewMode === 'table'" :columns="columns" :data-source="tableData" :pagination="{
+            current: pagination.current,
+            pageSize: pagination.pageSize,
+            total: pagination.total,
+            showSizeChanger: true,
+            showQuickJumper: true,
+            showTotal: (total) => `共 ${total} 条`,
+            onShowSizeChange: handleTableChange,
+        }" @change="handleTableChange" size="middle">
             <template #bodyCell="{ column, record }">
                 <template v-if="column.dataIndex === 'count' || column.dataIndex === 'num_supplier'">
                     {{ formatNumber(record[column.dataIndex]) }}
@@ -33,25 +42,37 @@
 </template>
 
 <script setup lang="ts">
-import { ref, onMounted, watch, computed, nextTick, onUnmounted } from 'vue';
-import * as echarts from 'echarts';
+import { ref, onMounted, watch, Ref, nextTick } from 'vue';
+import { useECharts } from '/@/hooks/web/useECharts';
+import { getOrigPortReport } from '../customsData.api';
+
+const chartRef = ref<HTMLDivElement | null>(null);
+const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
 
 const props = defineProps({
-    origPortData: {  // 修改属性名
+    queryParam: {  // 修改属性名
         type: Object,
         required: true
-    }
+    },
+    width: {
+        type: String as PropType<string>,
+        default: '100%',
+    },
+    height: {
+        type: String as PropType<string>,
+        default: 'calc(50vh - 78px)',
+    },
 });
 
-const chartRef = ref(null);
 const loading = ref(false);
 const viewMode = ref('chart');
-let chart = null;
+const sortMode = ref('count');
+const allBuckets = ref({});
 
 // 定义表格列
 const columns = [
     {
-        title: '起运港',  
+        title: '起运港',
         dataIndex: 'val',
         key: 'val',
     },
@@ -94,124 +115,182 @@ const formatDecimal = (num: string | number) => {
 };
 
 // 计算表格数据
-const tableData = computed(() => {
-    if (!props.origPortData?.buckets) return [];  // 修改属性名
-    
-    return props.origPortData.buckets.map((item, index) => ({
-        key: index,
-        val: item.val,
-        count: item.count,
-        num_supplier: item.num_supplier,
-        sum_weight: item.sum_weight,
-        sum_amount: item.sum_amount
-    }));
+const tableData = ref([]);
+
+const pagination = ref({
+    current: 1,
+    pageSize: 10,
+    total: 0
 });
 
 const initChart = () => {
     if (!chartRef.value) return;
-    
-    chart = echarts.init(chartRef.value);
     updateChart();
 };
 
-const updateChart = () => {
-    if (!chart || !props.origPortData?.buckets) return;  // 修改属性名
-
-    // 获取前10个数据并计算总数
-    const data = props.origPortData.buckets  // 修改属性名
-        .sort((a, b) => Number(b.count) - Number(a.count))
-        .slice(0, 10);
-    
-    const total = data.reduce((sum, item) => sum + Number(item.count), 0);
-
-    const option = {
-        tooltip: {
-            trigger: 'item',
-            formatter: (params) => {
-                const percent = ((params.value / total) * 100).toFixed(2);
-                return `${params.name}<br/>交易次数: ${formatNumber(params.value)}<br/>占比: ${percent}%`;
-            }
-        },
-        legend: {
-            orient: 'vertical',
-            right: 10,
-            top: 'center',
-            type: 'scroll'
-        },
-        series: [
-            {
-                name: '交易次数',
-                type: 'pie',
-                radius: ['40%', '70%'],
-                avoidLabelOverlap: true,
-                itemStyle: {
-                    borderRadius: 10,
-                    borderColor: '#fff',
-                    borderWidth: 2
-                },
-                label: {
-                    show: true,
-                    formatter: (params) => {
-                        const percent = ((params.value / total) * 100).toFixed(2);
-                        return `${params.name}\n${percent}%`;
-                    }
-                },
-                emphasis: {
+const updateChart = async () => {
+    let chartData = [];
+    const params = {
+        sort: sortMode.value,
+        page: 1,
+        page_size: 10,
+        ...props.queryParam,
+    };
+
+    try {
+        const res = await getOrigPortReport(params);
+        if (res.result.data.result && res.result.data.result.buckets) {
+            chartData = res.result.data.result.buckets;
+            allBuckets.value = res.result.data.result.allBuckets;
+        }
+
+        if (chartData.length === 0) {
+            console.warn('No data available for chart');
+            return;
+        }
+
+        const valueKeyMap = {
+            count: 'count',
+            weight: 'sum_weight',
+            amount: 'sum_amount'
+        };
+
+        const totalKeyMap = {
+            count: 'count',
+            weight: 'weight_sum',
+            amount: 'amount_sum'
+        };
+
+        const total = allBuckets.value[totalKeyMap[sortMode.value]] || 0;
+        const data = chartData.sort((a, b) => Number(b[valueKeyMap[sortMode.value]]) - Number(a[valueKeyMap[sortMode.value]]));
+
+        const otherCount = total - data.reduce((sum, item) => sum + Number(item[valueKeyMap[sortMode.value]]), 0);
+
+        const option = {
+            tooltip: {
+                trigger: 'item',
+                formatter: (params) => {
+                    const percent = total > 0 ? ((params.value / total) * 100).toFixed(2) : 0.00;
+                    return `${params.name}<br/>${sortMode.value === 'count' ? '交易次数' : sortMode.value === 'weight' ? '交易重量' : '交易金额'}: ${formatNumber(params.value)}<br/>占比: ${percent}%`;
+                }
+            },
+            legend: {
+                orient: 'vertical',
+                right: 10,
+                top: 'center',
+                type: 'scroll'
+            },
+            series: [
+                {
+                    name: '交易次数',
+                    type: 'pie',
+                    radius: ['40%', '70%'],
+                    avoidLabelOverlap: true,
+                    itemStyle: {
+                        borderRadius: 10,
+                        borderColor: '#fff',
+                        borderWidth: 2
+                    },
                     label: {
                         show: true,
-                        fontSize: 14,
-                        fontWeight: 'bold'
-                    }
-                },
-                data: data.map(item => ({
-                    name: item.val_cn || item.val,
-                    value: Number(item.count)
-                }))
-            }
-        ]
-    };
+                        formatter: (params) => {
+                            const percent = total > 0 ? ((params.value / total) * 100).toFixed(2) : 0.00;
+                            return `${params.name}\n${percent}%`;
+                        }
+                    },
+                    emphasis: {
+                        label: {
+                            show: true,
+                            fontSize: 14,
+                            fontWeight: 'bold'
+                        }
+                    },
+                    data: [
+                        ...data.map(item => ({
+                            name: item.val_cn || item.val,
+                            value: Number(item[valueKeyMap[sortMode.value]])
+                        })),
+                        {
+                            name: '其他',
+                            value: otherCount
+                        }
+                    ]
+                }
+            ]
+        };
 
-    chart.setOption(option);
+        nextTick(() => {
+            console.log('Setting chart options:', option); // Log the options to debug
+            setOptions(option); // Ensure options are set after DOM updates
+        });
+    } catch (error) {
+        console.error('Failed to update chart:', error);
+    }
+};
+
+// Replace registerTransactionTable with this new method
+const handleTableChange = async (pag, filters, sorter) => {
+    loading.value = true;
+    try {
+        const params = {
+            sort: sortMode.value,
+            page: pag.current,
+            page_size: pag.pageSize,
+            ...props.queryParam,
+        };
+
+        const res = await getOrigPortReport(params);
+        if (res.result.data.result && res.result.data.result.buckets) {
+            pagination.value = {
+                current: pag.current,
+                pageSize: pag.pageSize,
+                total: res.result.data.result.numBuckets || 0,
+            };
+            tableData.value = res.result.data.result.buckets;
+
+        }
+    } catch (error) {
+        console.error('Failed to fetch data:', error);
+    } finally {
+        loading.value = false;
+    }
 };
 
-// 监听数据变化
 watch(
-    () => props.origPortData,  // 修改属性名
+    () => sortMode.value,
     () => {
         updateChart();
-    },
-    { deep: true }
+        handleTableChange(pagination.value, {}, {});
+    }
 );
-
 // 监听视图模式变化
 watch(viewMode, (newValue) => {
     if (newValue === 'chart') {
+        // 在下一个 tick 后初始化图表,确保 DOM 已更新
         nextTick(() => {
             initChart();
         });
     }
 });
 
-onMounted(() => {
-    if (viewMode.value === 'chart') {
+watch(sortMode, () => {
+    // 在下一个 tick 后初始化图表,确保 DOM 已更新
+    nextTick(() => {
         initChart();
-    }
+    });
+    handleTableChange(pagination.value, {}, {});
+});
+onMounted(async () => {
+    // 这里可以添加获取数据的逻辑
+    await handleTableChange(pagination.value.current, pagination.value.pageSize, sortMode.value);
 });
 
-// 监听窗口大小变化
-window.addEventListener('resize', () => {
+onMounted(() => {
     if (viewMode.value === 'chart') {
-        chart?.resize();
+        initChart();
     }
 });
 
-// 组件卸载时清理
-onUnmounted(() => {
-    chart?.dispose();
-    window.removeEventListener('resize', () => {
-        chart?.resize();
-    });
-});
 </script>
 
 <style scoped>
@@ -222,4 +301,8 @@ onUnmounted(() => {
 :deep(.ant-table-pagination) {
     margin: 16px 0;
 }
+
+.switch-view {
+    margin-bottom: 16px;
+}
 </style>

+ 191 - 113
src/views/adweb/data/components/OriginCountryAnalysis.vue

@@ -2,14 +2,14 @@
     <a-card title="原产国" :loading="loading">
         <template #extra>
             <span>排序:</span>
-            <a-radio-group v-model:value="sortMode" button-style="solid" style="margin-left: 16px;" @change="handleSortChange">
+            <a-radio-group v-model:value="sortMode" button-style="solid" style="margin-left: 16px;">
                 <a-radio-button value="count">交易次数</a-radio-button>
                 <a-radio-button value="weight">交易重量</a-radio-button>
                 <a-radio-button value="amount">交易金额</a-radio-button>
             </a-radio-group>
         </template>
         <!-- 添加切换按钮组 -->
-        <div>
+        <div class="switch-button">
             <a-radio-group v-model:value="viewMode" button-style="solid">
                 <a-radio-button value="chart">图表</a-radio-button>
                 <a-radio-button value="table">列表</a-radio-button>
@@ -20,8 +20,15 @@
         <div v-show="viewMode === 'chart'" ref="chartRef" style="height: 400px"></div>
 
         <!-- 表格视图 -->
-        <a-table v-show="viewMode === 'table'" :columns="columns" :data-source="tableData" :pagination="false"
-            size="middle">
+        <a-table v-show="viewMode === 'table'" :columns="columns" :data-source="tableData" :pagination="{
+            current: pagination.current,
+            pageSize: pagination.pageSize,
+            total: pagination.total,
+            showSizeChanger: true,
+            showQuickJumper: true,
+            showTotal: (total) => `共 ${total} 条`,
+            onShowSizeChange: handleTableChange,
+        }" @change="handleTableChange" size="middle">
             <template #bodyCell="{ column, record }">
                 <template v-if="column.dataIndex === 'count' || column.dataIndex === 'num_supplier'">
                     {{ formatNumber(record[column.dataIndex]) }}
@@ -35,31 +42,33 @@
 </template>
 
 <script setup lang="ts">
-import { ref, onMounted, watch, computed, nextTick, onUnmounted, defineEmits } from 'vue';
-import * as echarts from 'echarts';
+import { ref, onMounted, watch, nextTick, onUnmounted, Ref } from 'vue';
+import { useECharts } from '/@/hooks/web/useECharts';
+import { getOrigCountryReport } from '../customsData.api';
 
-// Define emits
-const emit = defineEmits();
+const chartRef = ref<HTMLDivElement | null>(null);
+const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
 
 const props = defineProps({
-    originCountryData: {
+    queryParam: {
         type: Object,
         required: true
     }
 });
 
-const chartRef = ref(null);
 const loading = ref(false);
 const viewMode = ref('chart');
 const sortMode = ref('count');
+const allBuckets = ref({});
+
 let chart = null;
 
 // 定义表格列
 const columns = [
     {
         title: '原产国',
-        dataIndex: 'country',
-        key: 'country',
+        dataIndex: 'val_cn',
+        key: 'val_cn',
     },
     {
         title: '交易次数',
@@ -86,10 +95,26 @@ const columns = [
         dataIndex: 'percentage',
         key: 'percentage',
         customRender: ({ record }) => {
-            const total = props.originCountryData.allBuckets.count; // 计算总数
-            const percent = total > 0 && (record.count > 0 || record.sum_weight > 0 || record.sum_amount > 0) 
-                ? ((record.count / total) * 100).toFixed(2) 
-                : 0.00; // 计算百分比
+            const percent = (() => {
+                const valueKeyMap = {
+                    count: 'count',
+                    weight: 'sum_weight',
+                    amount: 'sum_amount'
+                };
+                const totalKeyMap = {
+                    count: 'count',
+                    weight: 'weight_sum',
+                    amount: 'amount_sum'
+                };
+
+                const selectedValue = record[valueKeyMap[sortMode.value]];
+                const total = allBuckets.value[totalKeyMap[sortMode.value]] || 0;
+
+                return total > 0 && selectedValue > 0
+                    ? ((selectedValue / total) * 100).toFixed(2)
+                    : 0.00;
+            })();
+
             return `${percent}%`;
         }
     }
@@ -109,116 +134,158 @@ const formatDecimal = (num: string | number) => {
 };
 
 // 计算表格数据
-const tableData = computed(() => {
-    if (!props.originCountryData?.buckets) return [];
-
-    return props.originCountryData.buckets.map((item, index) => ({
-        key: index,
-        country: item.val_cn || item.val,
-        count: item.count,
-        num_supplier: item.num_supplier,
-        sum_weight: item.sum_weight,
-        sum_amount: item.sum_amount,
-        percentage: 0
-    }));
+const tableData = ref([]);
+const pagination = ref({
+    current: 1,
+    pageSize: 10,
+    total: 0
 });
+const chartData = ref([]);
 
 const initChart = () => {
-    if (!chartRef.value) return;
-
-    chart = echarts.init(chartRef.value);
     updateChart();
 };
 
-const updateChart = () => {
-    if (!chart || !props.originCountryData?.buckets) return;
-
-    const valueKeyMap = {
-        count: 'count',
-        weight: 'sum_weight',
-        amount: 'sum_amount'
-    }
-    // 获取前10个数据并计算总数
-    const data = props.originCountryData.buckets
-        .sort((a, b) => Number(b[valueKeyMap[sortMode.value]]) - Number(a[valueKeyMap[sortMode.value]]))
-        .slice(0, 10);
-
-    // 根据 sortMode 映射到 allBuckets 的对应关系
-    const totalKeyMap = {
-        count: 'count',
-        weight: 'weight_sum',
-        amount: 'amount_sum'
+const updateChart = async () => {
+    console.log('updateChart');
+    const params = {
+        sort: sortMode.value,
+        page: 1,
+        page_size: 10,
+        ...props.queryParam,
     };
 
-    const total = props.originCountryData.allBuckets[totalKeyMap[sortMode.value]]; // 使用映射获取总数
-    const otherCount = total - data.reduce((sum, item) => sum + Number(item[valueKeyMap[sortMode.value]]), 0);
-
-    const option = {
-        tooltip: {
-            trigger: 'item',
-            formatter: (params) => {
-                const percent = ((params.value / total) * 100).toFixed(2);
-                return `${params.name}<br/>${sortMode.value === 'count' ? '交易次数' : sortMode.value === 'weight' ? '交易重量' : '交易金额'}: ${formatNumber(params.value)}<br/>占比: ${percent}%`;
-            }
-        },
-        legend: {
-            orient: 'vertical',
-            right: 10,
-            top: 'center',
-            type: 'scroll'
-        },
-        series: [
-            {
-                name: '交易次数',
-                type: 'pie',
-                radius: ['40%', '70%'],
-                avoidLabelOverlap: true,
-                itemStyle: {
-                    borderRadius: 10,
-                    borderColor: '#fff',
-                    borderWidth: 2
-                },
-                label: {
-                    show: true,
-                    formatter: (params) => {
-                        const percent = total > 0 ? ((params.value / total) * 100).toFixed(2) : 0.00;
-                        return `${params.name}\n${percent}%`;
-                    }
-                },
-                emphasis: {
+    try {
+        const res = await getOrigCountryReport(params);
+
+        if (res && res.result && res.result.data && res.result.data.result && res.result.data.result.buckets) {
+            chartData.value = res.result.data.result.buckets;
+            allBuckets.value = res.result.data.result.allBuckets;
+        } else {
+            console.error('Unexpected API response structure:', res);
+            return; // Exit if the response structure is not as expected
+        }
+
+        const valueKeyMap = {
+            count: 'count',
+            weight: 'sum_weight',
+            amount: 'sum_amount'
+        };
+
+        // 获取前10个数据并计算总数
+        const data = chartData.value
+            .sort((a, b) => Number(b[valueKeyMap[sortMode.value]]) - Number(a[valueKeyMap[sortMode.value]]))
+            .slice(0, 10);
+
+        // 根据 sortMode 映射到 allBuckets 的对应关系
+        const totalKeyMap = {
+            count: 'count',
+            weight: 'weight_sum',
+            amount: 'amount_sum'
+        };
+
+        const total = allBuckets.value[totalKeyMap[sortMode.value]] || 0; // 使用映射获取总数
+        const otherCount = total - data.reduce((sum, item) => sum + Number(item[valueKeyMap[sortMode.value]]), 0);
+
+        const option = {
+            tooltip: {
+                trigger: 'item',
+                formatter: (params) => {
+                    const percent = ((params.value / total) * 100).toFixed(2);
+                    return `${params.name}<br/>${sortMode.value === 'count' ? '交易次数' : sortMode.value === 'weight' ? '交易重量' : '交易金额'}: ${formatNumber(params.value)}<br/>占比: ${percent}%`;
+                }
+            },
+            legend: {
+                orient: 'vertical',
+                right: 10,
+                top: 'center',
+                type: 'scroll'
+            },
+            series: [
+                {
+                    name: '交易次数',
+                    type: 'pie',
+                    radius: ['40%', '70%'],
+                    avoidLabelOverlap: true,
+                    itemStyle: {
+                        borderRadius: 10,
+                        borderColor: '#fff',
+                        borderWidth: 2
+                    },
                     label: {
                         show: true,
-                        fontSize: 14,
-                        fontWeight: 'bold'
-                    }
-                },
-                data: [
-                    ...data.map(item => ({
-                        name: item.val_cn || item.val,
-                        value: Number(item[valueKeyMap[sortMode.value]])
-                    })),
-                    {
-                        name: '其他',
-                        value: otherCount
-                    }
-                ]
-            }
-        ]
-    };
+                        formatter: (params) => {
+                            const percent = total > 0 ? ((params.value / total) * 100).toFixed(2) : 0.00;
+                            return `${params.name}\n${percent}%`;
+                        }
+                    },
+                    emphasis: {
+                        label: {
+                            show: true,
+                            fontSize: 14,
+                            fontWeight: 'bold'
+                        }
+                    },
+                    data: [
+                        ...data.map(item => ({
+                            name: item.val_cn || item.val,
+                            value: Number(item[valueKeyMap[sortMode.value]])
+                        })),
+                        {
+                            name: '其他',
+                            value: otherCount
+                        }
+                    ]
+                }
+            ]
+        };
 
-    chart.setOption(option);
+        nextTick(() => {
+            console.log('setOptions');
+            setOptions(option);
+        });
+    } catch (error) {
+        console.error('Failed to fetch data:', error);
+    }
 };
 
-const handleSortChange = (event) => {
-    sortMode.value = event.target.value; // Update sort mode correctly
-    emit('update:sortMode', sortMode.value); // Emit the updated sort mode
+// Replace registerTransactionTable with this new method
+const handleTableChange = async (pag, filters, sorter) => {
+    loading.value = true;
+    try {
+        const params = {
+            sort: sortMode.value,
+            page: pag.current,
+            page_size: pag.pageSize,
+            ...props.queryParam,
+        };
+
+        const res = await getOrigCountryReport(params);
+        if (res.result.data.result && res.result.data.result.buckets) {
+            pagination.value = {
+                current: pag.current,
+                pageSize: pag.pageSize,
+                total: res.result.data.result.numBuckets || 0,
+            };
+            tableData.value = res.result.data.result.buckets;
+
+        }
+    } catch (error) {
+        console.error('Failed to fetch data:', error);
+    } finally {
+        loading.value = false;
+    }
 };
 
 // 监听数据变化
 watch(
-    () => props.originCountryData,
+    () => props.queryParam,
     () => {
-        updateChart();
+        if (viewMode.value === 'chart') {
+            updateChart();
+        } else {
+            handleTableChange(pagination.value, {}, {});
+        }
     },
     { deep: true }
 );
@@ -226,10 +293,17 @@ watch(
 // 监听视图模式变化
 watch(viewMode, (newValue) => {
     if (newValue === 'chart') {
-        // 在下一个 tick 后初始化图表,确保 DOM 已更新
-        nextTick(() => {
-            initChart();
-        });
+        updateChart();
+    } else {
+        handleTableChange(pagination.value, {}, {});
+    }
+});
+
+watch(sortMode, () => {
+    if (viewMode.value === 'chart') {
+        updateChart();
+    } else {
+        handleTableChange(pagination.value, {}, {});
     }
 });
 
@@ -263,4 +337,8 @@ onUnmounted(() => {
 :deep(.ant-table-pagination) {
     margin: 16px 0;
 }
-</style>
+
+.switch-button {
+    margin-bottom: 16px;
+}
+</style>

+ 4 - 64
src/views/adweb/data/customsData.vue

@@ -315,14 +315,14 @@
             <trade-analysis :monthly-trend-data="monthlyTrendData" />
           </div>
           <div class="analysis-item">
-            <HsCodeAnalysis :hs-code-data="hsCodeData" @update:sortMode="handleSortMode" />
+            <HsCodeAnalysis :queryParam = "queryParam" />
           </div>
           <a-row :gutter="16">
             <!-- 新增行 -->
             <a-col :span="12">
               <!-- 左侧列 -->
               <div class="analysis-item">
-                <OriginCountryAnalysis :origin-country-data="originCountryData" @update:sortMode="handleSortModeOriginCountryData"  />
+                <OriginCountryAnalysis :queryParam = "queryParam" />
               </div>
             </a-col>
             <a-col :span="12">
@@ -344,7 +344,7 @@
       <a-tab-pane key="shippingAnalysis" tab="航运类分析报告">
         <div class="analysis-content">
           <div class="analysis-item">
-            <OrigPortAnalysis :origPortData="origPortData"></OrigPortAnalysis>
+            <OrigPortAnalysis :queryParam = "queryParam"></OrigPortAnalysis>
           </div>
           <div class="analysis-item">
             <DestPortAnalysis :destPortData="destPortData"></DestPortAnalysis>
@@ -365,17 +365,13 @@
 
 <script lang="ts" setup>
 import { reactive, ref, onMounted } from 'vue';
-import dayjs, { Dayjs } from 'dayjs';
+import dayjs from 'dayjs';
 import {
   list,
   listCompanies,
   getTrendReport,
-  getHsCodeReport,
   getOrigCountryReport,
   getDestCountryReport,
-  getSupplierReport,
-  getBuyerReport,
-  getOrigPortReport,
   getDestPortReport,
   getTransTypeReport,
   getIncotermsReport,
@@ -612,15 +608,11 @@ const handleTabChange = async (key: string) => {
     // Load trade analysis data
     await Promise.all([
       loadMonthlyTrendData(),
-      fetchHsCodeData(),
-      fetchOriginCountryData(),
       fetchDestinationCountryData(),
-      fetchBuyerData(),
     ]);
   } else if (key === 'shippingAnalysis') {
     // Load shipping analysis data
     await Promise.all([
-      fetchOrigPortData(),
       fetchDestPortData(),
       fetchTransTypeData(),
       fetchIncotermsData()
@@ -652,30 +644,6 @@ const loadMonthlyTrendData = async () => {
   }
 };
 
-const hsCodeData = ref({});
-
-// 获取HS编码数据
-const fetchHsCodeData = async (sortMode = 'count') => {
-  const params = {
-    ...queryParam,
-    sort: sortMode,
-  };
-  const res = await getHsCodeReport(params);
-  hsCodeData.value = res.result.data.result;
-};
-
-const originCountryData = ref({});
-
-// 获取原产国数据
-const fetchOriginCountryData = async (sortMode = 'count') => {
-  const params = {
-    ...queryParam,
-    sort: sortMode
-  };
-  const res = await getOrigCountryReport(params);
-  originCountryData.value = res.result.data.result;
-};
-
 const destinationCountryData = ref({});
 
 // 获取目的国数据
@@ -688,27 +656,6 @@ const fetchDestinationCountryData = async (sortMode = 'count') => {
   destinationCountryData.value = res.result.data.result;
 };
 
-const buyerData = ref({});
-
-// 获取采购商数据
-const fetchBuyerData = async () => {
-  const params = {
-    ...queryParam,
-  };
-  const res = await getBuyerReport(params);
-  buyerData.value = res.result.data.result;
-};
-
-const origPortData = ref({});
-// 获取起运港数据
-const fetchOrigPortData = async () => {
-  const params = {
-    ...queryParam,
-  };
-  const res = await getOrigPortReport(params);
-  origPortData.value = res.result.data.result;
-}
-
 const destPortData = ref({});
 // 获取起运港数据
 const fetchDestPortData = async () => {
@@ -1055,13 +1002,6 @@ const resetModalData = () => {
   tradePartnersData.value = {}; // 重置贸易伙伴数据
   regionDistributionData.value = {}; // 重置区域分布数据
 };
-const handleSortMode = (value) => {
-  fetchHsCodeData(value);
-};
-
-const handleSortModeOriginCountryData = (value) => {
-  fetchOriginCountryData(value);
-}
 
 const handleSortModeDestinationCountryData = (value) => {
   fetchDestinationCountryData(value);