Browse Source

Merge branch 'master' into cpq-dev

chenlei1231 2 months ago
parent
commit
83dff06438

+ 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);

+ 1 - 1
src/views/adweb/seo/SeoKeywordsRankList.vue

@@ -707,7 +707,7 @@
 
       //表格内的去查询按钮
       gotoSearch(word) {
-        window.open('https://www.google.com/search?q=' + word, '_blank');
+        window.open('http://google-proxy.adwebcloud.com/search?q=' + word, '_blank');
       },
 
       handleExportXlsLU(fileName, keywordType) {

+ 5 - 5
src/views/adweb/site/components/GoogleAdsModal.vue

@@ -29,8 +29,8 @@ const formSchema = [
     required: true,
   },
   {
-    field: 'apiAccessToken',
-    label: 'API Access Token',
+    field: 'apiRefreshToken',
+    label: 'API Refresh Token',
     component: 'Input',
   },
   {
@@ -57,8 +57,8 @@ async function handleSubmit() {
       customerId: values.googleAdsAccount,
       siteCode: values.siteCode,
     };
-    if (values.apiAccessToken) {
-      params.refreshToken = values.apiAccessToken;
+    if (values.apiRefreshToken) {
+      params.refreshToken = values.apiRefreshToken;
     }
     await bindGoogleAdsAccount(params);
     createMessage.success('Google Ads账号绑定成功');
@@ -84,7 +84,7 @@ const init = async (data: { record: Recordable }) => {
     if (res) {
       setFieldsValue({
         googleAdsAccount: res.customerId,
-        apiAccessToken: res.refreshToken,
+        apiRefreshToken: res.refreshToken,
         siteCode: data.record.code,
       });
     }