feat(analytics): 在访问统计中增加同比趋势显示
- 在访问概览 API 中新增昨日、上周、上月 PV 字段,用于计算趋势 - 在前端统计卡片中显示今日、本周、本月访问量的同比变化百分比 - 支持 163 邮箱作为邮件通知服务提供商,更新相关文档和设置界面
This commit is contained in:
@@ -25,15 +25,48 @@
|
||||
</div>
|
||||
<div class="stats-item">
|
||||
<div class="stats-label">今日访问量</div>
|
||||
<div class="stats-value">{{ overview.todayPv }}</div>
|
||||
<div class="stats-value">
|
||||
{{ overview.todayPv }}
|
||||
<span
|
||||
v-if="overview.yesterdayPv !== undefined"
|
||||
class="trend"
|
||||
:class="percentageChange >= 0 ? 'up' : 'down'"
|
||||
:title="`对比昨日 ${percentageChange >= 0 ? '增加' : '减少'} ${Math.abs(percentageChange).toFixed(1)}%`"
|
||||
>
|
||||
<span class="trend-arrow">{{ percentageChange >= 0 ? '↑' : '↓' }}</span>
|
||||
{{ Math.abs(percentageChange).toFixed(1) }}%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-item">
|
||||
<div class="stats-label">本周访问量</div>
|
||||
<div class="stats-value">{{ overview.weekPv }}</div>
|
||||
<div class="stats-value">
|
||||
{{ overview.weekPv }}
|
||||
<span
|
||||
v-if="overview.lastWeekPv !== undefined"
|
||||
class="trend"
|
||||
:class="weekPercentageChange >= 0 ? 'up' : 'down'"
|
||||
:title="`对比上周 ${weekPercentageChange >= 0 ? '增加' : '减少'} ${Math.abs(weekPercentageChange).toFixed(1)}%`"
|
||||
>
|
||||
<span class="trend-arrow">{{ weekPercentageChange >= 0 ? '↑' : '↓' }}</span>
|
||||
{{ Math.abs(weekPercentageChange).toFixed(1) }}%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-item">
|
||||
<div class="stats-label">本月访问量</div>
|
||||
<div class="stats-value">{{ overview.monthPv }}</div>
|
||||
<div class="stats-value">
|
||||
{{ overview.monthPv }}
|
||||
<span
|
||||
v-if="overview.lastMonthPv !== undefined"
|
||||
class="trend"
|
||||
:class="monthPercentageChange >= 0 ? 'up' : 'down'"
|
||||
:title="`对比上月 ${monthPercentageChange >= 0 ? '增加' : '减少'} ${Math.abs(monthPercentageChange).toFixed(1)}%`"
|
||||
>
|
||||
<span class="trend-arrow">{{ monthPercentageChange >= 0 ? '↑' : '↓' }}</span>
|
||||
{{ Math.abs(monthPercentageChange).toFixed(1) }}%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-item">
|
||||
<div class="stats-label">有访问记录的页面数</div>
|
||||
@@ -198,11 +231,33 @@ const overview = ref<VisitOverviewResponse>({
|
||||
totalPv: 0,
|
||||
totalPages: 0,
|
||||
todayPv: 0,
|
||||
yesterdayPv: 0,
|
||||
weekPv: 0,
|
||||
lastWeekPv: 0,
|
||||
monthPv: 0,
|
||||
lastMonthPv: 0,
|
||||
last30Days: [],
|
||||
});
|
||||
|
||||
function calculateChange(current: number, previous: number) {
|
||||
if (previous === 0) {
|
||||
return current > 0 ? 100 : 0;
|
||||
}
|
||||
return ((current - previous) / previous) * 100;
|
||||
}
|
||||
|
||||
const percentageChange = computed(() => {
|
||||
return calculateChange(overview.value.todayPv, overview.value.yesterdayPv || 0);
|
||||
});
|
||||
|
||||
const weekPercentageChange = computed(() => {
|
||||
return calculateChange(overview.value.weekPv, overview.value.lastWeekPv || 0);
|
||||
});
|
||||
|
||||
const monthPercentageChange = computed(() => {
|
||||
return calculateChange(overview.value.monthPv, overview.value.lastMonthPv || 0);
|
||||
});
|
||||
|
||||
const rawItems = ref<VisitPageItem[]>([]);
|
||||
const items = computed<VisitPageItem[]>(() => {
|
||||
const list = rawItems.value.slice();
|
||||
@@ -390,8 +445,11 @@ async function loadData() {
|
||||
totalPv: overviewRes.totalPv,
|
||||
totalPages: overviewRes.totalPages,
|
||||
todayPv: overviewRes.todayPv ?? 0,
|
||||
yesterdayPv: overviewRes.yesterdayPv ?? 0,
|
||||
weekPv: overviewRes.weekPv ?? 0,
|
||||
lastWeekPv: overviewRes.lastWeekPv ?? 0,
|
||||
monthPv: overviewRes.monthPv ?? 0,
|
||||
lastMonthPv: overviewRes.lastMonthPv ?? 0,
|
||||
last30Days: Array.isArray(overviewRes.last30Days)
|
||||
? overviewRes.last30Days
|
||||
: [],
|
||||
|
||||
@@ -305,6 +305,7 @@
|
||||
@change="onProviderChange"
|
||||
>
|
||||
<option value="qq">QQ 邮箱</option>
|
||||
<option value="163">163 邮箱</option>
|
||||
<option value="custom">自定义 SMTP</option>
|
||||
</select>
|
||||
</div>
|
||||
@@ -361,6 +362,10 @@
|
||||
请登录 QQ 邮箱网页版,在【设置 - 账户】中开启 POP3/SMTP
|
||||
服务并生成授权码。
|
||||
</div>
|
||||
<div v-else-if="smtpProvider === '163'" class="form-hint">
|
||||
注意:163 邮箱必须使用授权码,而非登录密码。<br />
|
||||
请登录 163 邮箱网页版,在【设置 - POP3/SMTP/IMAP】中开启服务并生成授权码。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
@@ -816,6 +821,10 @@ function onProviderChange() {
|
||||
smtpHost.value = "smtp.qq.com";
|
||||
smtpPort.value = 465;
|
||||
smtpSecure.value = true;
|
||||
} else if (smtpProvider.value === "163") {
|
||||
smtpHost.value = "smtp.163.com";
|
||||
smtpPort.value = 465;
|
||||
smtpSecure.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -893,6 +902,8 @@ async function load() {
|
||||
|
||||
if (emailNotifyRes.smtp.host === "smtp.qq.com") {
|
||||
smtpProvider.value = "qq";
|
||||
} else if (emailNotifyRes.smtp.host === "smtp.163.com") {
|
||||
smtpProvider.value = "163";
|
||||
} else {
|
||||
smtpProvider.value = "custom";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user