feat(analytics): 扩展页面访问统计接口并新增站点隔离文档

- 在 `/admin/analytics/pages` 接口响应中添加 `itemsByPv` 和 `itemsByLatest` 字段,分别返回按访问量和最新访问排序的前20条数据,优化前端数据展示逻辑
- 前端管理后台适配新的接口响应结构,提升页面访问统计页面的性能和用户体验
- 新增站点隔离配置文档 (`/docs/config/site-isolation.md`),说明如何通过 `siteId` 配置实现数据隔离
- 在前端配置指南中补充 `siteId` 配置示例
- 新增常见问题文档 (`/docs/common-problems.md`),解答设置 `siteId` 后评论数据不显示的问题及数据迁移方案
- 在导航栏和侧边栏添加“常见问题”和“配置”相关入口,完善文档结构
- 修复前端组件 API 调用中 `postSlug` 参数可能为 `postUrl` 的兼容性问题
This commit is contained in:
anghunk
2026-02-09 14:47:28 +08:00
parent 2453929455
commit 2085a4733c
11 changed files with 149 additions and 51 deletions

View File

@@ -263,22 +263,15 @@ export const getVisitPages = async (c: Context<{ Bindings: Bindings }>) => {
const rawDomain = c.req.query('domain') || '';
const domainFilter = rawDomain.trim().toLowerCase();
const rawOrder = c.req.query('order') || '';
const order = rawOrder.trim().toLowerCase();
const isLatest = order === 'latest';
const order = rawOrder.trim().toLowerCase() === 'latest' ? 'latest' : 'pv';
await c.env.CWD_DB.prepare(
'CREATE TABLE IF NOT EXISTS page_stats (id INTEGER PRIMARY KEY AUTOINCREMENT, post_slug TEXT UNIQUE NOT NULL, post_title TEXT, post_url TEXT, pv INTEGER NOT NULL DEFAULT 0, last_visit_at INTEGER, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)'
).run();
let sql =
'SELECT post_slug, post_title, post_url, pv, last_visit_at FROM page_stats ORDER BY pv DESC, last_visit_at DESC';
if (isLatest) {
sql =
'SELECT post_slug, post_title, post_url, pv, last_visit_at FROM page_stats ORDER BY last_visit_at DESC, pv DESC';
}
const { results } = await c.env.CWD_DB.prepare(sql).all<{
const { results } = await c.env.CWD_DB.prepare(
'SELECT post_slug, post_title, post_url, pv, last_visit_at FROM page_stats'
).all<{
post_slug: string;
post_title: string | null;
post_url: string | null;
@@ -307,9 +300,44 @@ export const getVisitPages = async (c: Context<{ Bindings: Bindings }>) => {
});
}
items = items.slice(0, 20);
const itemsByPv = items
.slice()
.sort((a, b) => {
if (b.pv !== a.pv) {
return b.pv - a.pv;
}
const aLast = a.lastVisitAt ?? 0;
const bLast = b.lastVisitAt ?? 0;
return bLast - aLast;
})
.slice(0, 20);
return c.json({ items });
const itemsByLatest = items
.slice()
.sort((a, b) => {
const aLast = a.lastVisitAt ?? 0;
const bLast = b.lastVisitAt ?? 0;
if (bLast !== aLast) {
return bLast - aLast;
}
return b.pv - a.pv;
})
.slice(0, 20);
const response =
order === 'latest'
? {
items: itemsByLatest,
itemsByPv,
itemsByLatest
}
: {
items: itemsByPv,
itemsByPv,
itemsByLatest
};
return c.json(response);
} catch (e: any) {
return c.json(
{ message: e.message || '获取页面访问统计失败' },