feat(analytics): 为访问和评论趋势图表添加7天/30天切换功能

- 在访问趋势和评论数趋势卡片标题栏添加切换按钮
- 重构图表数据源处理逻辑,支持按时间范围筛选
- 添加对应的CSS样式实现标签式切换器
- 保持默认显示最近30天数据,点击切换时重新渲染图表
This commit is contained in:
anghunk
2026-01-27 10:46:11 +08:00
parent 8ed5fb86a9
commit 61f2223825
2 changed files with 103 additions and 6 deletions

View File

@@ -42,7 +42,27 @@
</div>
<div class="card">
<h3 class="card-title">最近 30 天访问趋势</h3>
<div class="card-title-row">
<h3 class="card-title">访问趋势</h3>
<div class="visit-tabs">
<button
class="visit-tab"
:class="{ 'visit-tab-active': chartRange === '7' }"
type="button"
@click="changeChartRange('7')"
>
最近 7
</button>
<button
class="visit-tab"
:class="{ 'visit-tab-active': chartRange === '30' }"
type="button"
@click="changeChartRange('30')"
>
最近 30
</button>
</div>
</div>
<div v-if="loading" class="page-hint">加载中...</div>
<div v-else-if="error" class="page-error">{{ error }}</div>
<div class="chart-wrapper">
@@ -187,6 +207,7 @@ const injectedDomainFilter = inject<Ref<string> | null>("domainFilter", null);
const domainFilter = injectedDomainFilter ?? ref("");
const last30Days = ref<{ date: string; total: number }[]>([]);
const likeStatsItems = ref<LikeStatsItem[]>([]);
const chartRange = ref<"7" | "30">("30");
const toastMessage = ref("");
const toastType = ref<"success" | "error">("success");
@@ -375,8 +396,11 @@ function renderChart() {
if (!chartInstance) {
chartInstance = echarts.init(el);
}
const dates = last30Days.value.map((item) => item.date.slice(5));
const values = last30Days.value.map((item) => item.total);
const source = last30Days.value;
const seriesData =
chartRange.value === "7" ? source.slice(-7) : source;
const dates = seriesData.map((item) => item.date.slice(5));
const values = seriesData.map((item) => item.total);
const option: echarts.EChartsOption = {
tooltip: {
trigger: "axis",
@@ -422,6 +446,14 @@ function renderChart() {
chartInstance.setOption(option);
}
function changeChartRange(range: "7" | "30") {
if (chartRange.value === range) {
return;
}
chartRange.value = range;
renderChart();
}
function handleResize() {
if (chartInstance) {
chartInstance.resize();

View File

@@ -42,7 +42,27 @@
</div>
<div class="card">
<h3 class="card-title">最近 30 天评论数趋势</h3>
<div class="card-title-row">
<h3 class="card-title">评论数趋势</h3>
<div class="chart-tabs">
<button
class="chart-tab"
:class="{ 'chart-tab-active': chartRange === '7' }"
type="button"
@click="changeChartRange('7')"
>
最近 7
</button>
<button
class="chart-tab"
:class="{ 'chart-tab-active': chartRange === '30' }"
type="button"
@click="changeChartRange('30')"
>
最近 30
</button>
</div>
</div>
<div v-if="statsLoading" class="page-hint">加载中...</div>
<div v-else-if="statsError" class="page-error">{{ statsError }}</div>
<div class="chart-wrapper">
@@ -105,6 +125,7 @@ const statsSummary = ref({
});
const domainStats = ref<DomainStat[]>([]);
const last7Days = ref<{ date: string; total: number }[]>([]);
const chartRange = ref<"7" | "30">("30");
const injectedDomainFilter = inject<Ref<string> | null>("domainFilter", null);
const domainFilter = injectedDomainFilter ?? ref("");
@@ -159,8 +180,11 @@ function renderChart() {
if (!chartInstance) {
chartInstance = echarts.init(el);
}
const dates = last7Days.value.map((item) => item.date.slice(5));
const values = last7Days.value.map((item) => item.total);
const source = last7Days.value;
const seriesData =
chartRange.value === "7" ? source.slice(-7) : source;
const dates = seriesData.map((item) => item.date.slice(5));
const values = seriesData.map((item) => item.total);
const option: echarts.EChartsOption = {
tooltip: {
trigger: "axis",
@@ -206,6 +230,14 @@ function renderChart() {
chartInstance.setOption(option);
}
function changeChartRange(range: "7" | "30") {
if (chartRange.value === range) {
return;
}
chartRange.value = range;
renderChart();
}
function handleResize() {
if (chartInstance) {
chartInstance.resize();
@@ -277,6 +309,14 @@ onBeforeUnmount(() => {
font-size: 16px;
}
.card-title-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 12px;
}
.page-hint {
font-size: 14px;
color: #57606a;
@@ -287,6 +327,31 @@ onBeforeUnmount(() => {
color: #d1242f;
}
.chart-tabs {
display: inline-flex;
border-radius: 999px;
border: 1px solid #d0d7de;
overflow: hidden;
}
.chart-tab {
padding: 4px 10px;
font-size: 12px;
border: none;
background-color: #ffffff;
color: #57606a;
cursor: pointer;
}
.chart-tab + .chart-tab {
border-left: 1px solid #d0d7de;
}
.chart-tab-active {
background-color: #0969da;
color: #ffffff;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));