feat(widget): 添加页面访问量显示功能

- 新增公开 API GET /api/analytics/pv 获取页面访问量
- 前端组件初始化时自动填充 #cwd-page-pv 容器
- 支持数字格式化(如 1.2k、1.5M)
- 将版本号更新至 0.1.8
This commit is contained in:
anghunk
2026-03-16 13:57:57 +08:00
parent 607d36ead1
commit e2db5daecb
9 changed files with 107 additions and 5 deletions

View File

@@ -155,6 +155,7 @@
<div class="demo-post">
<h2>这是一篇示例文章</h2>
<div id="cwd-page-pv">0</div>
<p>
这是一个演示 CWD Comments Widget 的示例页面。你可以在上方的配置面板中修改 API 地址和主题,
然后点击"应用配置"按钮重新加载评论组件。

View File

@@ -1,6 +1,6 @@
{
"name": "cwd-widget",
"version": "0.1.7",
"version": "0.1.8",
"description": "Server-free, extremely fast and secure, plug-and-play commenting system based on Cloudflare Workers and the Global Edge Network.",
"type": "module",
"author": "anghunk",

View File

@@ -59,6 +59,7 @@ export class CWDComments {
};
this._likeButtonEl = null;
this._likeCountEl = null;
this._pvElement = null;
this._mounted = false;
@@ -256,6 +257,10 @@ export class CWDComments {
this.api.trackVisit();
}
if (this.api && typeof this.api.getPagePv === 'function') {
this._fetchAndFillPv();
}
if (this.api && typeof this.api.getLikeStatus === 'function') {
try {
const likeResult = await this.api.getLikeStatus();
@@ -820,4 +825,52 @@ export class CWDComments {
getConfig() {
return { ...this.config };
}
/**
* 获取并填充页面访问量
* @private
*/
async _fetchAndFillPv() {
try {
// 查找固定 ID 的容器
const container = typeof document !== 'undefined'
? document.querySelector('#cwd-page-pv')
: null;
if (!container) {
return; // 容器不存在则静默跳过
}
this._pvElement = container;
const result = await this.api.getPagePv();
const pv = result && typeof result.pv === 'number' ? result.pv : 0;
this._updatePvDisplay(pv);
} catch (e) {
// 静默失败,不影响主功能
}
}
/**
* 更新 PV 显示
* @private
*/
_updatePvDisplay(pv) {
if (!this._pvElement) return;
this._pvElement.textContent = this._formatPvNumber(pv);
this._pvElement.setAttribute('data-cwd-pv', String(pv));
}
/**
* 格式化 PV 数字
* @private
*/
_formatPvNumber(num) {
if (num >= 1000000) {
return (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
}
if (num >= 1000) {
return (num / 1000).toFixed(1).replace(/\.0$/, '') + 'k';
}
return String(num);
}
}

View File

@@ -209,6 +209,24 @@ export function createApiClient(config) {
} catch (e) {}
throw new Error(msg);
}
return response.json();
}
async function getPagePv() {
const params = new URLSearchParams({
post_slug: config.postUrl || config.postSlug
});
if (config.siteId) {
params.set('siteId', config.siteId);
}
const response = await fetch(`${baseUrl}/api/analytics/pv?${params}`);
if (!response.ok) {
return { pv: 0, postSlug: config.postSlug };
}
return response.json();
}
@@ -219,6 +237,7 @@ export function createApiClient(config) {
trackVisit,
getLikeStatus,
likePage,
likeComment
likeComment,
getPagePv
};
}