Some checks failed
Deploy Website on push / Deploy Push Element Ftp (push) Waiting to run
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
217 lines
5.6 KiB
Vue
217 lines
5.6 KiB
Vue
<script lang="ts" setup>
|
|
import type { EchartsUIType } from '@vben/plugins/echarts';
|
|
|
|
import { onMounted, ref } from 'vue';
|
|
|
|
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
|
|
|
|
import { statsHistory, statsTotal } from '#/api/promotion/analytics';
|
|
|
|
const chartRef = ref<EchartsUIType>();
|
|
const { renderEcharts } = useEcharts(chartRef);
|
|
|
|
// 获取30天前的日期
|
|
const getDateString = (daysAgo: number) => {
|
|
const date = new Date();
|
|
date.setDate(date.getDate() - daysAgo);
|
|
return date.toISOString().split('T')[0];
|
|
};
|
|
|
|
onMounted(async () => {
|
|
try {
|
|
// 获取趋势数据
|
|
const endDate = getDateString(0); // 今天
|
|
const startDate = getDateString(29); // 29天前
|
|
const trendData = await statsHistory({ start_date: startDate, end_date: endDate });
|
|
|
|
// 获取统计数据
|
|
const statsData = await statsTotal();
|
|
|
|
// 准备图表数据
|
|
const dates = Array.from({ length: 30 }).map((_, index) => {
|
|
const date = new Date();
|
|
date.setDate(date.getDate() - 29 + index);
|
|
return date.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' });
|
|
});
|
|
|
|
// 如果有历史数据,使用历史数据;否则使用模拟数据
|
|
let clickData = Array(30).fill(0);
|
|
if (trendData && trendData.length > 0) {
|
|
// 将历史数据按日期排序并映射到数组
|
|
const sortedData = trendData.sort((a, b) =>
|
|
new Date(a.stats_date).getTime() - new Date(b.stats_date).getTime()
|
|
);
|
|
|
|
sortedData.forEach((item) => {
|
|
const itemDate = new Date(item.stats_date);
|
|
const today = new Date();
|
|
const daysDiff = Math.floor((today.getTime() - itemDate.getTime()) / (1000 * 60 * 60 * 24));
|
|
|
|
if (daysDiff >= 0 && daysDiff < 30) {
|
|
// 使用实际日期索引
|
|
clickData[29 - daysDiff] = item.click_count || 0;
|
|
}
|
|
});
|
|
} else {
|
|
// 没有历史数据时,使用统计数据生成模拟数据
|
|
const todayClickCount = statsData?.today_click_count || 0;
|
|
const totalClickCount = statsData?.total_click_count || 0;
|
|
|
|
// 简单的线性分布模拟数据
|
|
for (let i = 0; i < 30; i++) {
|
|
// 最后一天使用今日数据,其他天按比例分布
|
|
if (i === 29) {
|
|
clickData[i] = todayClickCount;
|
|
} else {
|
|
// 按指数衰减模拟历史数据
|
|
clickData[i] = Math.max(0, Math.floor(todayClickCount * Math.exp(-0.05 * (29 - i))));
|
|
}
|
|
}
|
|
|
|
// 确保总和不超过总计数
|
|
const sum = clickData.reduce((a, b) => a + b, 0);
|
|
if (sum > totalClickCount && totalClickCount > 0) {
|
|
const ratio = totalClickCount / sum;
|
|
clickData = clickData.map(val => Math.floor(val * ratio));
|
|
}
|
|
}
|
|
|
|
// 计算Y轴最大值
|
|
const maxValue = Math.max(...clickData) || 10;
|
|
|
|
renderEcharts({
|
|
grid: {
|
|
bottom: 0,
|
|
containLabel: true,
|
|
left: '1%',
|
|
right: '1%',
|
|
top: '2%',
|
|
},
|
|
series: [
|
|
{
|
|
areaStyle: {},
|
|
data: clickData,
|
|
itemStyle: {
|
|
color: '#5ab1ef',
|
|
},
|
|
smooth: true,
|
|
type: 'line',
|
|
name: '推广访问量',
|
|
},
|
|
],
|
|
tooltip: {
|
|
axisPointer: {
|
|
lineStyle: {
|
|
color: '#5ab1ef',
|
|
width: 1,
|
|
},
|
|
},
|
|
trigger: 'axis',
|
|
formatter: (params: any) => {
|
|
const param = params[0];
|
|
return `${param.axisValue}<br/>${param.seriesName}: ${param.value}`;
|
|
},
|
|
},
|
|
xAxis: {
|
|
axisTick: {
|
|
show: false,
|
|
},
|
|
boundaryGap: false,
|
|
data: dates,
|
|
splitLine: {
|
|
lineStyle: {
|
|
type: 'solid',
|
|
width: 1,
|
|
},
|
|
show: true,
|
|
},
|
|
type: 'category',
|
|
},
|
|
yAxis: [
|
|
{
|
|
axisTick: {
|
|
show: false,
|
|
},
|
|
max: Math.ceil(maxValue * 1.2), // 比最大值大20%作为Y轴上限
|
|
splitArea: {
|
|
show: true,
|
|
},
|
|
splitNumber: 4,
|
|
type: 'value',
|
|
},
|
|
],
|
|
});
|
|
} catch (error) {
|
|
console.error('获取推广趋势数据失败:', error);
|
|
|
|
// 发生错误时显示默认图表
|
|
renderEcharts({
|
|
grid: {
|
|
bottom: 0,
|
|
containLabel: true,
|
|
left: '1%',
|
|
right: '1%',
|
|
top: '2%',
|
|
},
|
|
series: [
|
|
{
|
|
areaStyle: {},
|
|
data: Array(30).fill(0),
|
|
itemStyle: {
|
|
color: '#5ab1ef',
|
|
},
|
|
smooth: true,
|
|
type: 'line',
|
|
name: '推广访问量',
|
|
},
|
|
],
|
|
tooltip: {
|
|
axisPointer: {
|
|
lineStyle: {
|
|
color: '#5ab1ef',
|
|
width: 1,
|
|
},
|
|
},
|
|
trigger: 'axis',
|
|
},
|
|
xAxis: {
|
|
axisTick: {
|
|
show: false,
|
|
},
|
|
boundaryGap: false,
|
|
data: Array.from({ length: 30 }).map((_, index) => {
|
|
const date = new Date();
|
|
date.setDate(date.getDate() - 29 + index);
|
|
return date.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' });
|
|
}),
|
|
splitLine: {
|
|
lineStyle: {
|
|
type: 'solid',
|
|
width: 1,
|
|
},
|
|
show: true,
|
|
},
|
|
type: 'category',
|
|
},
|
|
yAxis: [
|
|
{
|
|
axisTick: {
|
|
show: false,
|
|
},
|
|
max: 10,
|
|
splitArea: {
|
|
show: true,
|
|
},
|
|
splitNumber: 4,
|
|
type: 'value',
|
|
},
|
|
],
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<EchartsUI ref="chartRef" />
|
|
</template>
|