|
@@ -55,36 +55,63 @@ async function fetchHeatmapData() {
|
|
|
return;
|
|
|
}
|
|
|
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').slice(0, 10); // x轴数据
|
|
|
+ const days = [...new Set(responseData.data.map(item => item.Reporting_Date))]; // x轴数据
|
|
|
+ const keywords = [...new Set(responseData.data.flatMap(item =>
|
|
|
+ Object.keys(item).filter(key => key !== 'Reporting_Date')
|
|
|
+ ))]; // y轴数据
|
|
|
const data = [];
|
|
|
|
|
|
// 找出所有数值的最大值,用于设置 visualMap 的 max 值
|
|
|
const maxValue = Math.max(
|
|
|
- ...responseData.data.flatMap((item) =>
|
|
|
- Object.entries(item)
|
|
|
- .filter(([key]) => key !== 'Reporting_Date')
|
|
|
- .map(([, value]) => value as number)
|
|
|
- )
|
|
|
+ ...responseData.data.flatMap(item =>
|
|
|
+ Object.values(item).filter(value => typeof value === 'number') as number[]
|
|
|
+ )
|
|
|
);
|
|
|
|
|
|
- responseData.data.forEach((item, yIndex) => {
|
|
|
- keywords.forEach((keyword, xIndex) => {
|
|
|
+ responseData.data.forEach(item => {
|
|
|
+ const dayIndex = days.indexOf(item.Reporting_Date);
|
|
|
+ keywords.forEach((keyword: any, keywordIndex) => {
|
|
|
if (item[keyword] !== undefined && item[keyword] !== null) {
|
|
|
- data.push([xIndex, yIndex, item[keyword]]); // 只添加非空值
|
|
|
+ data.push([dayIndex, keywordIndex, item[keyword]]); // [x, y, value]
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
|
|
|
const option = {
|
|
|
+ title: {
|
|
|
+ text: '搜索词时间段对比热力图',
|
|
|
+ },
|
|
|
+ position: 'top',
|
|
|
tooltip: {
|
|
|
position: 'top',
|
|
|
+ formatter: function(params) {
|
|
|
+ const keyword = keywords[params.value[1]]; // 获取当前悬浮的关键词
|
|
|
+ return `${keyword}<br>${params.seriesName}: ${params.value[2]}`;
|
|
|
+ }
|
|
|
},
|
|
|
grid: {
|
|
|
- height: '65%',
|
|
|
- top: '15%',
|
|
|
+ // height: '65%',
|
|
|
+ top: '10%',
|
|
|
+ bottom: '15%',
|
|
|
+ left: '15%',
|
|
|
+ right: '5%',
|
|
|
},
|
|
|
- position: 'top',
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: keywords,
|
|
|
+ type: 'heatmap',
|
|
|
+ data: data,
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ },
|
|
|
+ emphasis: {
|
|
|
+ itemStyle: {
|
|
|
+ shadowBlur: 10,
|
|
|
+ shadowColor: 'rgba(0, 0, 0, 0.5)',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
xAxis: {
|
|
|
type: 'category',
|
|
|
name: '日期',
|
|
@@ -103,7 +130,7 @@ async function fetchHeatmapData() {
|
|
|
return value;
|
|
|
},
|
|
|
},
|
|
|
- data: keywords,
|
|
|
+ data: days,
|
|
|
splitArea: {
|
|
|
show: true,
|
|
|
},
|
|
@@ -117,39 +144,45 @@ async function fetchHeatmapData() {
|
|
|
fontSize: 14,
|
|
|
color: '#333',
|
|
|
},
|
|
|
- // nameTruncate: {
|
|
|
- // maxWidth: 20,
|
|
|
- // ellipsis: '...'
|
|
|
- // },
|
|
|
- data: days,
|
|
|
+ data: keywords,
|
|
|
splitArea: {
|
|
|
show: true,
|
|
|
},
|
|
|
+ axisLabel: {
|
|
|
+ interval: 0, // 显示所有标签
|
|
|
+ width: 280, // 增加标签区域的宽度以适应文本
|
|
|
+ rotate: 15, // 标签旋转角度
|
|
|
+ },
|
|
|
},
|
|
|
+ dataZoom: [
|
|
|
+ {
|
|
|
+ type: 'slider', // 纵向滚动条类型
|
|
|
+ yAxisIndex: 0, // 指定作用于 Y 轴
|
|
|
+ // start: 100, // 初始位置,百分比形式,数值越小,滚动条越靠下
|
|
|
+ // end: 30,
|
|
|
+ startValue: 0, // 初始位置,数值形式,数值越小,滚动条越靠上
|
|
|
+ endValue: 20,
|
|
|
+ zoomLock: true, // 锁定缩放,避免同时缩放两个滚动条
|
|
|
+ showDetail: false, // 显示缩放的细节
|
|
|
+ brushSelect: false,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'inside', // 内置型数据区域缩放组件(使用鼠标滚轮和拖拽)
|
|
|
+ yAxisIndex: 0,
|
|
|
+ zoomOnMouseWheel: false,
|
|
|
+ moveOnMouseMove: true,
|
|
|
+ moveOnMouseWheel: true,
|
|
|
+ }
|
|
|
+ ],
|
|
|
visualMap: {
|
|
|
min: 0,
|
|
|
max: maxValue, // 使用计算出的最大值
|
|
|
+ itemHeight: 500,
|
|
|
calculable: true,
|
|
|
orient: 'horizontal',
|
|
|
left: 'center',
|
|
|
bottom: '2%',
|
|
|
},
|
|
|
- series: [
|
|
|
- {
|
|
|
- name: 'Punch Card',
|
|
|
- type: 'heatmap',
|
|
|
- data: data,
|
|
|
- label: {
|
|
|
- show: true,
|
|
|
- },
|
|
|
- emphasis: {
|
|
|
- itemStyle: {
|
|
|
- shadowBlur: 10,
|
|
|
- shadowColor: 'rgba(0, 0, 0, 0.5)',
|
|
|
- },
|
|
|
- },
|
|
|
- },
|
|
|
- ],
|
|
|
};
|
|
|
|
|
|
if (!chart) {
|
|
@@ -175,25 +208,46 @@ async function fetchHeatmapData() {
|
|
|
|
|
|
<template>
|
|
|
<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 class="text-center flex justify-center items-center">
|
|
|
+ <span class="font-medium mr-1.5">指标 </span>
|
|
|
+ <el-select v-model="filter.metric" @change="fetchHeatmapData" style="width: 200px">
|
|
|
+ <el-option label="搜索查询分数" value="Search_Query_Score"></el-option>
|
|
|
+ <el-option label="搜索查询数量" value="Search_Query_Volume"></el-option>
|
|
|
+
|
|
|
+ <el-option label="展示量-总数" value="Impressions_Total_Count"></el-option>
|
|
|
+ <el-option v-if="filter.layerType === 'asin_view'" label="展示量-ASIN数量" value="Impressions_A_B_Count"></el-option>
|
|
|
+ <el-option v-if="filter.layerType === 'brand_view'" label="展示量-品牌数量" value="Impressions_A_B_Count"></el-option>
|
|
|
+
|
|
|
+ <el-option label="点击量-总数" value="Clicks_Total_Count"></el-option>
|
|
|
+ <el-option v-if="filter.layerType === 'asin_view'" label="点击量-ASIN数量" value="Clicks_A_B_Count"></el-option>
|
|
|
+ <el-option v-if="filter.layerType === 'brand_view'" label="点击量-品牌数量" value="Clicks_A_B_Count"></el-option>
|
|
|
+ <el-option label="点击量-价格中位数" value="Clicks_Price_Median"></el-option>
|
|
|
+ <el-option v-if="filter.layerType === 'asin_view'" label="点击量-ASIN价格中位数" value="Clicks_A_B_Price_Median"></el-option>
|
|
|
+ <el-option v-if="filter.layerType === 'brand_view'" label="点击量-品牌价格中位数" value="Clicks_A_B_Price_Median"></el-option>
|
|
|
+
|
|
|
+ <el-option label="加购-总数" value="Cart_Adds_Total_Count"></el-option>
|
|
|
+ <el-option v-if="filter.layerType === 'asin_view'" label="加购-ASIN数量" value="Cart_Adds_A_B_Count"></el-option>
|
|
|
+ <el-option v-if="filter.layerType === 'brand_view'" label="加购-品牌数量" value="Cart_Adds_A_B_Count"></el-option>
|
|
|
+ <el-option label="加购-价格中位数" value="Cart_Adds_Price_Median"></el-option>
|
|
|
+ <el-option v-if="filter.layerType === 'asin_view'" label="加购-ASIN价格中位数" value="Cart_Adds_A_B_Price_Median"></el-option>
|
|
|
+ <el-option v-if="filter.layerType === 'brand_view'" label="加购-品牌价格中位数" value="Cart_Adds_A_B_Price_Median"></el-option>
|
|
|
+
|
|
|
+
|
|
|
+ <el-option label="购买-总数" value="Purchases_Total_Count"></el-option>
|
|
|
+ <el-option v-if="filter.layerType === 'asin_view'" label="购买-ASIN数量" value="Purchases_A_B_Count"></el-option>
|
|
|
+ <el-option v-if="filter.layerType === 'brand_view'" label="购买-品牌数量" value="Purchases_A_B_Count"></el-option>
|
|
|
+ <el-option label="购买-价格中位数" value="Purchases_Price_Median"></el-option>
|
|
|
+ <el-option v-if="filter.layerType === 'asin_view'" label="购买-ASIN价格中位数" value="Purchases_A_B_Price_Median"></el-option>
|
|
|
+ <el-option v-if="filter.layerType === 'brand_view'" label="购买-品牌价格中位数" value="Purchases_A_B_Price_Median"></el-option>
|
|
|
+ </el-select>
|
|
|
</div>
|
|
|
|
|
|
<div class="w-full">
|
|
|
- <div v-show="!heatmapLoading && !hasData" style="min-height: 500px">
|
|
|
- <el-empty :image-size="300" />
|
|
|
+ <div v-if="!heatmapLoading && !hasData" style="min-height: 800px" class="flex justify-center items-center">
|
|
|
+ <el-empty :image-size="300" />
|
|
|
</div>
|
|
|
- <div v-show="hasData" ref="chartRef" style="width: 100%; height: 500px"></div>
|
|
|
+ <div v-show="hasData" ref="chartRef" style="width: 100%; height: 800px"></div>
|
|
|
</div>
|
|
|
</el-card>
|
|
|
</template>
|