Bläddra i källkod

Merge branch 'wang' into test

WanGxC 9 månader sedan
förälder
incheckning
141f6d6ee8

+ 3 - 1
src/views/productCenter/productList/components/ProductSelectCard.vue

@@ -147,10 +147,11 @@ onBeforeUnmount(() => {
     <el-scrollbar>
       <div class="scrollbar-flex-content" v-show="cardData">
         <el-card
+          v-if="cardData.length !== 0"
           v-for="(item, index) in cardData"
           :key="item.productlineId"
           shadow="hover"
-          body-style="padding: 0;box-sizing: border-box; position: relative; width: 100%;"
+          body-style="padding: 0; box-sizing: border-box; position: relative; width: 100%;"
           class="scrollbar-demo-item"
           :class="{ selected: selectedCardIndex === index }"
           @click="selectCard(index, item)">
@@ -177,6 +178,7 @@ onBeforeUnmount(() => {
         </el-card>
       </div>
       <el-card
+        v-if="cardData.length === 0"
         shadow="hover"
         body-style="padding: 0;box-sizing: border-box; position: relative; width: 100%;"
         class="scrollbar-demo-item">

+ 10 - 6
src/views/searchTerm/analysisPage/IndicatorChart.vue

@@ -1,18 +1,22 @@
 <script setup lang="ts">
 /**
  * @Name: IndicatorChart.vue
- * @Description:
+ * @Description: 搜索词-分析页-图表卡片
  * @Author: Cheney
  */
-import IndicatorHeatmap from './IndicatorHeatmap.vue'
+import IndicatorHeatmap from './IndicatorHeatmap.vue';
+import IndicatorFunnel from './IndicatorFunnel.vue';
+import IndicatorXBar from './IndicatorXBar.vue';
 </script>
 
 <template>
-  <el-card shadow="hover"  style="border: none; margin-bottom: 10px">
+  <el-card shadow="hover" style="border: none; margin-bottom: 10px">
     <IndicatorHeatmap />
+    <div class="flex gap-5">
+      <IndicatorFunnel class="flex-1" />
+      <IndicatorXBar class="flex-1" />
+    </div>
   </el-card>
 </template>
 
-<style scoped>
-
-</style>
+<style scoped></style>

+ 178 - 0
src/views/searchTerm/analysisPage/IndicatorFunnel.vue

@@ -0,0 +1,178 @@
+<script setup lang="ts">
+/**
+ * @Name: IndicatorFunnel.vue
+ * @Description: 搜索词-分析页-漏斗图
+ * @Author: Cheney
+ */
+import { Search } from '@element-plus/icons-vue';
+import { inject, onBeforeUnmount, reactive, ref, Ref, watch } from 'vue';
+import * as api from './api';
+import * as echarts from 'echarts';
+import emitter from '/@/utils/emitter';
+
+const filter = inject<Ref>('filter');
+const funnelFilter = reactive({
+  layerSelect: 'all_asin',
+  searchTermInp: '',
+});
+
+const funnelLoading = ref(false);
+const chartRef = ref<HTMLElement | null>(null);
+let chart: echarts.ECharts | null = null;
+let resizeObserver: ResizeObserver | null = null;
+const hasData = ref(true);
+
+onBeforeUnmount(() => {
+  emitter.all.clear();
+  // 清理 ResizeObserver
+  if (resizeObserver) {
+    resizeObserver.disconnect();
+  }
+  if (chart) {
+    chart.dispose();
+    chart = null;
+  }
+});
+
+emitter.on('QueryCondition-sendRequest', () => {
+  fetchFunnelData();
+});
+
+watch(filter.value, () => {
+  funnelFilter.layerSelect = filter.value.layerType;
+});
+
+async function fetchFunnelData() {
+  funnelLoading.value = true;
+  const query = {
+    date_start: filter.value.reportDate[0],
+    date_end: filter.value.reportDate[1],
+    report_range: filter.value.reportType,
+    layer_type: funnelFilter.layerSelect,
+  };
+  try {
+    const response = await api.getFunnelData(query);
+    if (!response.data || Object.keys(response.data).length === 0) {
+      hasData.value = false;
+      if (chart) {
+        chart.clear();
+      }
+      return;
+    }
+
+    hasData.value = true;
+
+    // 转换数据
+    const rawData = response.data;
+    const funnelData = Object.entries(rawData)
+      .filter(([key]) => key.endsWith('log2'))
+      .map(([key, value]) => {
+        const name =
+          key.replace('_Total_Countlog2', '').charAt(0).toUpperCase() +
+          key.replace('_Total_Countlog2', '').slice(1).toLowerCase();
+        const originalKey = key.replace('log2', '');
+        return {
+          value: value,
+          name: name,
+          originalValue: rawData[originalKey],
+        };
+      });
+
+    const option = {
+      title: {
+        text: '购买旅程漏斗图',
+      },
+      tooltip: {
+        trigger: 'item',
+        formatter: function (params) {
+          return `${params.name}: ${params.data.originalValue.toLocaleString()}`;
+        },
+      },
+      // toolbox: {
+      //   feature: {
+      //     dataView: { readOnly: false },
+      //   },
+      // },
+      series: [
+        {
+          type: 'funnel',
+          left: '10%',
+          top: 50,
+          bottom: 0,
+          width: '80%',
+          min: 0,
+          max: 100,
+          minSize: '0%',
+          maxSize: '100%',
+          sort: 'descending',
+          gap: 2,
+          labelLine: {
+            length: 10,
+            lineStyle: {
+              width: 1,
+              type: 'solid',
+            },
+          },
+          itemStyle: {
+            borderColor: '#fff',
+            borderWidth: 1,
+          },
+          emphasis: {
+            label: {
+              fontSize: 20,
+            },
+          },
+          data: funnelData,
+        },
+      ],
+    };
+
+    initChart(option);
+  } catch (error) {
+    console.error('==Error==', error);
+  } finally {
+    funnelLoading.value = false;
+  }
+}
+
+function initChart(opt) {
+  if (!chart) {
+    chart = echarts.init(chartRef.value);
+  }
+  chart.setOption(opt);
+
+  // 添加 ResizeObserver 以处理图表大小变化
+  if (!resizeObserver) {
+    resizeObserver = new ResizeObserver(() => {
+      chart?.resize();
+    });
+    resizeObserver.observe(chartRef.value);
+  }
+}
+</script>
+
+<template>
+  <el-card shadow="never" v-loading="funnelLoading" class="mt-5">
+    <div class="flex gap-5 mb-4 justify-center">
+      <div>
+        <span class="font-medium mr-0.5">层级 </span>
+        <el-select v-model="funnelFilter.layerSelect" @change="fetchFunnelData" style="width: 130px">
+          <el-option label="Asin View" value="asin_view" />
+          <el-option label="Brand View" value="brand_view" />
+          <el-option label="All Asin" value="all_asin" />
+          <el-option label="All Brand" value="all_brand" />
+        </el-select>
+      </div>
+      <div>
+        <span class="font-medium mr-0.5">搜索词 </span>
+        <el-input v-model="funnelFilter.searchTermInp" :prefix-icon="Search" @change="fetchFunnelData" style="width: 200px" />
+      </div>
+    </div>
+    <div v-show="!funnelLoading && !hasData" class="no-data-message" style="min-height: 500px">
+      <el-empty />
+    </div>
+    <div v-show="hasData" ref="chartRef" style="width: 100%; height: 500px"></div>
+  </el-card>
+</template>
+
+<style scoped></style>

+ 26 - 28
src/views/searchTerm/analysisPage/IndicatorHeatmap.vue

@@ -1,12 +1,12 @@
 <script setup lang="ts">
 /**
  * @Name: IndicatorHeatmap.vue
- * @Description:
+ * @Description: 搜索词-分析页-热力图
  * @Author: Cheney
  */
 
 import * as echarts from 'echarts';
-import { inject, onBeforeUnmount, onMounted, Ref, ref } from 'vue';
+import { inject, onBeforeUnmount, Ref, ref } from 'vue';
 import * as api from './api';
 import emitter from '/@/utils/emitter';
 
@@ -17,11 +17,6 @@ const chartRef = ref<HTMLElement | null>(null);
 let chart: echarts.ECharts | null = null;
 let resizeObserver: ResizeObserver | null = null;
 
-onMounted(() => {
-  initChart();
-  fetchHeatmapData();
-});
-
 onBeforeUnmount(() => {
   emitter.all.clear();
   // 清理 ResizeObserver
@@ -34,17 +29,10 @@ onBeforeUnmount(() => {
   }
 });
 
-emitter.on('QueryCondition-sendHeatmapRequest', () => {
+emitter.on('QueryCondition-sendRequest', () => {
   fetchHeatmapData();
 });
 
-function initChart() {
-  if (chartRef.value) {
-    // chart = echarts.init(chartRef.value);
-    // chart.setOption(option);
-  }
-}
-
 async function fetchHeatmapData() {
   heatmapLoading.value = true;
   const query = {
@@ -68,7 +56,7 @@ async function fetchHeatmapData() {
     }
     hasData.value = true;
     const days = responseData.data.map((item) => item.Reporting_Date); // y轴数据
-    const keywords = Object.keys(responseData.data[0]).filter((key) => key !== 'Reporting_Date'); // x轴数据
+    const keywords = Object.keys(responseData.data[0]).filter((key) => key !== 'Reporting_Date').slice(0, 10); // x轴数据
     const data = [];
 
     // 找出所有数值的最大值,用于设置 visualMap 的 max 值
@@ -93,8 +81,8 @@ async function fetchHeatmapData() {
         position: 'top',
       },
       grid: {
-        height: '50%',
-        top: '10%',
+        height: '65%',
+        top: '15%',
       },
       position: 'top',
       xAxis: {
@@ -144,7 +132,7 @@ async function fetchHeatmapData() {
         calculable: true,
         orient: 'horizontal',
         left: 'center',
-        bottom: '15%',
+        bottom: '2%',
       },
       series: [
         {
@@ -186,18 +174,28 @@ async function fetchHeatmapData() {
 </script>
 
 <template>
-  <div v-loading="heatmapLoading">
-    <el-radio-group v-model="filter.metric" @change="fetchHeatmapData">
-      <el-radio-button label="Search_Query_Score" value="Search_Query_Score" />
-      <el-radio-button label="Search_Query_Volume" value="Search_Query_Volume" />
-    </el-radio-group>
-    <div>
-      <div v-show="!heatmapLoading && !hasData" class="no-data-message">
+  <el-card shadow="never" v-loading="heatmapLoading" class="flex flex-col" body-class="w-full">
+    <div class="font-bold text-xl mb-4 text-center" style="color: #464646">搜索词时间段对比热力图</div>
+    <div class="text-center">
+      <el-radio-group v-model="filter.metric" @change="fetchHeatmapData">
+        <el-radio-button label="Search_Query_Score" value="Search_Query_Score" />
+        <el-radio-button label="Search_Query_Volume" value="Search_Query_Volume" />
+        <el-radio-button label="Impressions_Total_Count" value="Impressions_Total_Count" />
+        <el-radio-button label="Impressions_A_B_Count" value="Impressions_A_B_Count" />
+        <el-radio-button label="Clicks_Total_Count" value="Clicks_Total_Count" />
+        <el-radio-button label="Clicks_Price_Median" value="Clicks_Price_Median" />
+        <el-radio-button label="Cart_Adds_Total_Count" value="Cart_Adds_Total_Count" />
+        <el-radio-button label="Purchases_Total_Count" value="Purchases_Total_Count" />
+      </el-radio-group>
+    </div>
+
+    <div class="w-full">
+      <div v-show="!heatmapLoading && !hasData" class="no-data-message" style="min-height: 500px">
         <el-empty />
       </div>
-      <div v-show="hasData" ref="chartRef" style="width: 100%; height: 400px"></div>
+      <div v-show="hasData" ref="chartRef" style="width: 100%; height: 500px"></div>
     </div>
-  </div>
+  </el-card>
 </template>
 
 <style scoped></style>

+ 40 - 5
src/views/searchTerm/analysisPage/IndicatorOverview.vue

@@ -4,10 +4,14 @@
  * @Description: 分析页-指标总览
  * @Author: Cheney
  */
-import { reactive, inject, watch, Ref } from 'vue';
+import { inject, onBeforeUnmount, reactive, ref, Ref, watch } from 'vue';
 import { Bottom, Top } from '@element-plus/icons-vue';
+import * as api from '/@/views/searchTerm/analysisPage/api';
+import emitter from '/@/utils/emitter';
 
-const queryConditionData = inject<Ref>('queryConditionData');
+const filter = inject<Ref>('filter');
+const metricLoading = ref(false);
+const responseData = ref(null);
 const indicator = reactive([
   {
     title: '',
@@ -34,7 +38,6 @@ const indicator = reactive([
     color: '#f0f0fe',
   },
 ]);
-
 // 指标与返回数据字段的映射关系
 const mapping = {
   imp: {
@@ -59,7 +62,15 @@ const mapping = {
   },
 };
 
-watch(queryConditionData, (newData) => {
+onBeforeUnmount(() => {
+  emitter.all.clear();
+});
+
+emitter.on('QueryCondition-sendRequest', () => {
+  fetchIndicatorData();
+});
+
+watch(responseData, (newData) => {
   if (newData) {
     for (const key in mapping) {
       if (newData[key]) {
@@ -77,10 +88,34 @@ watch(queryConditionData, (newData) => {
     });
   }
 });
+
+async function fetchIndicatorData() {
+  metricLoading.value = true;
+  const query = {
+    date_start: filter.value.reportDate[0],
+    date_end: filter.value.reportDate[1],
+    layer_type: filter.value.layerType,
+    search_term: filter.value.searchTerm,
+    report_range: filter.value.reportType,
+    [filter.value.layerType.split('_')[0]]: filter.value.variable,
+  };
+  try {
+    const response = await api.getAsinMetrics(query);
+    responseData.value = response.data;
+  } catch (error) {
+    console.error('==Error==', error);
+  } finally {
+    metricLoading.value = false;
+  }
+}
 </script>
 
 <template>
-  <el-card shadow="hover" body-class="flex justify-between w-full" style="border: none; margin-bottom: 10px">
+  <el-card
+    v-loading="metricLoading"
+    shadow="hover"
+    body-class="flex justify-between w-full"
+    style="border: none; margin-bottom: 10px">
     <el-card
       v-for="(item, index) in indicator"
       :key="index"

+ 191 - 0
src/views/searchTerm/analysisPage/IndicatorXBar.vue

@@ -0,0 +1,191 @@
+<script setup lang="ts">
+/**
+ * @Name: IndicatorXBar.vue
+ * @Description: 搜索词-分析页-柱状图
+ * @Author: Cheney
+ */
+import { inject, onBeforeUnmount, reactive, Ref, ref, watch } from 'vue';
+import * as api from '/@/views/searchTerm/analysisPage/api';
+import * as echarts from 'echarts';
+import emitter from '/@/utils/emitter';
+
+const filter = inject<Ref>('filter');
+const barLoading = ref(false);
+
+const barFilter = reactive({
+  layerSelect: 'Impressions_A_B_Count',
+  searchTermInp: '',
+});
+
+let responseData = null;
+const chartRef = ref<HTMLElement | null>(null);
+let chart: echarts.ECharts | null = null;
+let resizeObserver: ResizeObserver | null = null;
+const hasData = ref(true);
+
+onBeforeUnmount(() => {
+  emitter.all.clear();
+  // 清理 ResizeObserver
+  if (resizeObserver) {
+    resizeObserver.disconnect();
+  }
+  if (chart) {
+    chart.dispose();
+    chart = null;
+  }
+});
+
+emitter.on('QueryCondition-sendRequest', () => {
+  fetchBarData();
+});
+
+// watch(filter.value,() => {
+//   barFilter.layerSelect = filter.value.layerType;
+// })
+
+async function fetchBarData() {
+  barLoading.value = true;
+  const query = {
+    date_start: filter.value.reportDate[0],
+    date_end: filter.value.reportDate[1],
+    report_range: filter.value.reportType,
+    layer_type: filter.value.layerType,
+    search_term: barFilter.searchTermInp,
+    [filter.value.layerType.split('_')[0]]: filter.value.variable,
+    metrics: barFilter.layerSelect
+  };
+  try {
+    responseData = await api.getBarData(query);
+    if (!responseData.data || responseData.data.length === 0) {
+      // 处理空数据的情况
+      hasData.value = false;
+      if (chart) {
+        chart.clear();
+      }
+      return;
+    }
+
+    hasData.value = true;
+
+    const asinList = Object.keys(responseData.data[0]).filter(key => key !== 'Search_Query');
+
+// 准备图表数据
+    const searchQueries = responseData.data.map(item => item.Search_Query);
+    const seriesData = asinList.map(asin => ({
+      name: asin,
+      type: 'bar',
+      stack: 'total',
+      label: {
+        show: true,
+        position: 'inside',
+        formatter: '{c}'
+      },
+      emphasis: {
+        focus: 'series'
+      },
+      data: responseData.data.map(item => item[asin] || 0)
+    }));
+
+    const option = {
+      tooltip: {
+        trigger: 'axis',
+        axisPointer: {
+          type: 'shadow'
+        }
+      },
+      legend: {
+        orient: 'horizontal',
+        top: 'bottom'
+      },
+      grid: {
+        left: '3%',
+        right: '4%',
+        bottom: '15%',
+        containLabel: true
+      },
+      xAxis: {
+        type: 'value'
+      },
+      yAxis: {
+        type: 'category',
+        data: searchQueries,
+        axisLabel: {
+          interval: 0,
+          formatter: function (value) {
+            return value.length > 20 ? value.substring(0, 20) + '...' : value;
+          }
+        }
+      },
+      series: seriesData
+    };
+
+    initChart(option);
+  } catch (error) {
+    console.error('==Error==', error);
+  } finally {
+    barLoading.value = false;
+  }
+}
+
+function initChart(opt: echarts.EChartsCoreOption) {
+  if (!chart) {
+    chart = echarts.init(chartRef.value);
+  }
+  chart.setOption(opt);
+
+  // 添加 ResizeObserver 以处理图表大小变化
+  if (!resizeObserver) {
+    resizeObserver = new ResizeObserver(() => {
+      chart?.resize();
+    });
+    resizeObserver.observe(chartRef.value);
+  }
+}
+
+function changeChart() {
+  const option = {
+    title: {
+      text: 'Asin/Brand 关键词情况',
+    },
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'shadow',
+      },
+    },
+    legend: {},
+    // grid: {
+    //   left: '3%',
+    //   right: '4%',
+    //   bottom: '3%',
+    //   containLabel: true,
+    // },
+    dataset: {
+      dimensions: ['Search_Query', 'Impressions_A_B_Count', 'Clicks_Total_Count', 'Cart_Adds_Total_Count', 'Purchases_Total_Count'],
+      source: responseData.data
+    }
+  }
+}
+</script>
+
+<template>
+  <el-card shadow="never" v-loading="barLoading" class="mt-5">
+    <div class="flex gap-5 mb-4 justify-center">
+      <div>
+        <span class="font-medium mr-0.5">层级 </span>
+        <el-select v-model="barFilter.layerSelect" @change="changeChart" style="width: 130px">
+          <el-option label="曝光次数" value="Impressions_A_B_Count" />
+          <el-option label="点击次数" value="Clicks_Total_Count" />
+          <el-option label="购买次数" value="Purchases_Total_Count" />
+          <el-option label="加购次数" value="Cart_Total_Count" />
+        </el-select>
+      </div>
+    </div>
+    <div v-show="!barLoading && !hasData" class="no-data-message" style="min-height: 500px">
+      <el-empty />
+    </div>
+    <div v-show="hasData" ref="chartRef" style="width: 100%; height: 500px"></div>
+  </el-card>
+</template>
+
+<style scoped></style>

+ 11 - 33
src/views/searchTerm/analysisPage/QueryCondition.vue

@@ -1,18 +1,19 @@
 <script setup lang="ts">
 /**
  * @Name: QueryCondition.vue
- * @Description:
+ * @Description:  搜索词-分析页-条件筛选栏
  * @Author: Cheney
  */
 import { RefreshLeft, Search } from '@element-plus/icons-vue';
-import { ref, watch } from 'vue';
-import * as api from './api';
+import { onMounted, ref, watch, inject, Ref } from 'vue';
 import emitter from '/@/utils/emitter';
 
-const responseData = defineModel('responseData');
-const filter: any = defineModel('filter'); // 在父组件中初始化
-const pageLoading = defineModel('pageLoading', { default: false });
 const defaultLabel = ref('ASIN');
+const filter = inject<Ref>('filter');
+
+onMounted(() => {
+  handleQuery();
+});
 
 watch(
   () => filter.value.layerType,
@@ -29,31 +30,7 @@ watch(
 );
 
 function handleQuery() {
-  pageLoading.value = true;
-  fetchIndicatorData();
-  fetchHeatmapData();
-  pageLoading.value = false;
-}
-
-async function fetchIndicatorData() {
-  const query = {
-    date_start: filter.value.reportDate[0],
-    date_end: filter.value.reportDate[1],
-    layer_type: filter.value.layerType,
-    search_term: filter.value.searchTerm,
-    report_range: filter.value.reportType,
-    [filter.value.layerType.split('_')[0]]: filter.value.variable,
-  };
-  try {
-    const response = await api.getAsinMetrics(query);
-    responseData.value = response.data;
-  } catch (error) {
-    console.error('==Error==', error);
-  }
-}
-
-async function fetchHeatmapData() {
-  emitter.emit('QueryCondition-sendHeatmapRequest');
+  emitter.emit('QueryCondition-sendRequest');
 }
 
 function resetCondition() {
@@ -84,15 +61,16 @@ function resetCondition() {
       </div>
       <div>
         <span class="font-bold mr-2" style="color: #303133">搜索词:</span>
-        <el-input v-model="filter.searchTerm" style="width: 200px"></el-input>
+        <el-input v-model="filter.searchTerm" :prefix-icon="Search" style="width: 180px"></el-input>
       </div>
       <div>
         <span class="font-bold mr-2" style="color: #303133">{{ defaultLabel }}:</span>
-        <el-input v-model="filter.variable" style="width: 200px"></el-input>
+        <el-input v-model="filter.variable" :prefix-icon="Search" style="width: 180px"></el-input>
       </div>
       <div>
         <span class="font-bold mr-2" style="color: #303133">报告日期:</span>
         <el-date-picker
+            style="width: 280px;"
           v-model="filter.reportDate"
           type="daterange"
           range-separator="To"

+ 71 - 0
src/views/searchTerm/analysisPage/QuerySummary.vue

@@ -0,0 +1,71 @@
+<script setup lang="ts">
+/**
+ * @Name: IndicatorHeatmap.vue
+ * @Description: 搜索词-分析页-Query汇总
+ * @Author: Cheney
+ */
+
+import { inject, nextTick, Ref, ref } from 'vue'
+import * as api from './api';
+import { usePagination } from '/@/utils/usePagination';
+
+const { tableData, total, currentPage, pageSize, handlePageChange } = usePagination(fetchTableData);
+const filter = inject<Ref>('filter');
+const loading = ref(false);
+const typeSelect = ref('positive');
+
+async function fetchTableData() {
+  loading.value = true;
+  const query = {
+    date_start: filter.value.reportDate[0],
+    date_end: filter.value.reportDate[1],
+    report_range: filter.value.reportType,
+    layer_type: filter.value.layerType,
+    searchTerm_type: typeSelect.value,
+    page: currentPage.value,
+    limit: pageSize
+  };
+  try {
+    const response = await api.getTableData(query);
+    total.value = response.total;
+    tableData.value = response.data;
+  } catch (error) {
+    console.log('error:', error);
+  } finally {
+    loading.value = false;
+    await nextTick();
+    // 触发窗口 resize 事件
+    window.dispatchEvent(new Event('resize'));
+  }
+}
+
+function changeType() {}
+</script>
+
+<template>
+  <el-card shadow="never" v-loading="loading">
+    <div class="flex gap-5 mb-4 justify-center">
+      <div>
+        <span class="font-medium mr-0.5">类型 </span>
+        <el-select v-model="typeSelect" @change="changeType" style="width: 130px">
+          <el-option label="positive" value="positive" />
+          <el-option label="negative" value="negative" />
+        </el-select>
+      </div>
+    </div>
+    <div style="height: 100%; overflow: auto">
+      <el-table :data="tableData" height="550" stripe style="width: 100%"> </el-table>
+    </div>
+    <div class="mt-3.5 flex justify-end">
+      <el-pagination
+        v-model:current-page="currentPage"
+        v-model:page-size="pageSize"
+        :page-sizes="[10, 20, 30, 50, 100, 200]"
+        layout="sizes, prev, pager, next"
+        :total="total"
+        @change="handlePageChange" />
+    </div>
+  </el-card>
+</template>
+
+<style scoped></style>

+ 23 - 0
src/views/searchTerm/analysisPage/api.ts

@@ -17,3 +17,26 @@ export function getHeatmapData(query: any) {
     params: query,
   });
 }
+
+export function getFunnelData(query: any) {
+  return request({
+    url: apiPrefix + 'funnelchart/',
+    method: 'GET',
+    params: query,
+  });
+}
+
+export function getBarData(query: any) {
+  return request({
+    url: apiPrefix + 'barchart/',
+    method: 'GET',
+    params: query,
+  });
+}
+export function getTableData(query: any) {
+  return request({
+    url: apiPrefix + 'rootmetric/',
+    method: 'GET',
+    params: query,
+  });
+}

+ 12 - 9
src/views/searchTerm/analysisPage/index.vue

@@ -4,31 +4,34 @@
  * @Description: 分析页
  * @Author: Cheney
  */
-import { provide, ref, watch } from 'vue';
+import { provide, ref } from 'vue';
 import QueryCondition from './QueryCondition.vue';
 import IndicatorOverview from './IndicatorOverview.vue';
 import IndicatorChart from './IndicatorChart.vue';
+import QuerySummary from './QuerySummary.vue';
 
-const pageLoading = ref();
-const queryConditionData = ref();
-provide('queryConditionData', queryConditionData);
-
-const filter = ref({  // 初始化 QueryCondition组件的filter
+const filter = ref({
+  // 初始化 QueryCondition组件的filter
   layerType: 'asin_view',
   searchTerm: '',
   reportType: 'MONTHLY',
   reportDate: ['2024-04-01', '2024-06-01'],
   variable: 'B00TEST0001',
-  metric: 'Search_Query_Score'
+  metric: 'Search_Query_Score',
 });
 provide('filter', filter);
 </script>
 
 <template>
-  <div v-loading="pageLoading" class="py-2 px-2.5">
-    <QueryCondition v-model:response-data="queryConditionData" v-model:filter="filter" v-model:pageLoading="pageLoading" />
+  <div class="py-2 px-2.5">
+    <QueryCondition />
     <IndicatorOverview />
     <IndicatorChart />
+    <el-card shadow="hover" body-class="flex gap-5"  style="border: none;">
+      <QuerySummary class="flex-1" />
+      <QuerySummary class="flex-1" />
+    </el-card>
+
   </div>
 </template>