feat(analytics): 为访问和评论趋势图表添加7天/30天切换功能
- 在访问趋势和评论数趋势卡片标题栏添加切换按钮 - 重构图表数据源处理逻辑,支持按时间范围筛选 - 添加对应的CSS样式实现标签式切换器 - 保持默认显示最近30天数据,点击切换时重新渲染图表
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user