From 6ad717533c395b43306de6b7058aa5b71915a45c Mon Sep 17 00:00:00 2001 From: seaHi Date: Sat, 26 Sep 2026 19:28:27 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=94=B9=E8=BF=9B=20Cloudflare=20?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E6=B8=85=E7=90=86=E4=B8=8E=E7=8B=AC=E7=AB=8B?= =?UTF-8?q?=E5=9F=9F=E5=90=8D=E7=9A=84=E6=B5=81=E9=87=8F=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/analytics.ts | 50 ++ .../components/admin/AnalyticsPanel.svelte | 545 ++++++------------ src/lib/server/cloudflare.test.ts | 151 +++++ src/lib/server/cloudflare.ts | 306 +++++----- src/routes/admin/posts/+page.server.ts | 16 - src/routes/admin/posts/[id]/+page.server.ts | 12 - src/routes/admin/posts/new/+page.server.ts | 12 - src/routes/admin/settings/+page.server.ts | 2 +- src/routes/admin/settings/+page.svelte | 14 + src/routes/api/v1/posts/[slug]/+server.ts | 21 - 10 files changed, 570 insertions(+), 559 deletions(-) create mode 100644 src/lib/analytics.ts create mode 100644 src/lib/server/cloudflare.test.ts diff --git a/src/lib/analytics.ts b/src/lib/analytics.ts new file mode 100644 index 0000000..27a66e5 --- /dev/null +++ b/src/lib/analytics.ts @@ -0,0 +1,50 @@ +export interface TrafficRow { + count: number; + sum: { edgeResponseBytes: number }; + dimensions: { date: string; cacheStatus: string; clientRequestPath: string }; +} + +export interface TrafficScope { + label: string; + hostname: string; + days: number; + rows: TrafficRow[]; + error?: string; +} + +export interface AnalyticsData { + scopes: TrafficScope[]; + d1: { sum: { rowsRead: number; rowsWritten: number } }[]; + r2: { max: { payloadSize: number } }[]; + missingEnvVars: boolean; + errorMsg?: string; +} + +export function summarizeTraffic(rows: TrafficRow[]) { + let requests = 0; + let bytes = 0; + let hits = 0; + let privateRequests = 0; + const statuses: Record = {}; + const daily = new Map(); + for (const row of rows) { + requests += row.count; + bytes += row.sum.edgeResponseBytes; + const status = row.dimensions.cacheStatus.toUpperCase(); + statuses[status] = (statuses[status] || 0) + row.count; + if (status === 'HIT') hits += row.count; + if (/^\/(admin|api)(\/|$)/.test(row.dimensions.clientRequestPath)) { + privateRequests += row.count; + } + daily.set(row.dimensions.date, (daily.get(row.dimensions.date) || 0) + row.count); + } + return { + requests, + bytes, + hits, + privateRequests, + hitRate: requests ? (hits / requests) * 100 : null, + statuses, + daily: [...daily].sort(([a], [b]) => a.localeCompare(b)) + }; +} diff --git a/src/lib/components/admin/AnalyticsPanel.svelte b/src/lib/components/admin/AnalyticsPanel.svelte index 55bb9ba..586bc58 100644 --- a/src/lib/components/admin/AnalyticsPanel.svelte +++ b/src/lib/components/admin/AnalyticsPanel.svelte @@ -1,180 +1,102 @@ @@ -182,129 +104,64 @@ {#if loading}
-

正在从 Cloudflare 获取最近 30 天流量数据...

-
- {:else if error} -
- {error} -
- {:else if !trafficData || trafficData.length === 0} -
- 没有获取到有效的流量数据,请确保 CF_API_TOKEN 和 CF_ZONE_ID 配置正确,且网站已有访问。 +

正在获取博客与 R2 附件统计...

{:else} -
30天访问流量
- -
+ {#if error || data?.errorMsg}
{error || data?.errorMsg}
{/if} +
项目访问流量
+

+ 仅统计配置的博客域名和 R2 附件域名,不包含文章中的外链资源。CDN 命中率为 HIT + 请求占比,不代表页面内部缓存命中率或数据库查询比例。数据可能由 Cloudflare 抽样估算。 +

+ {#each scopes as scope (scope.label)} +
+

{scope.label} {scope.hostname || '未配置域名'}

+ {#if scope.error} +
统计不可用:{scope.error}
+ {:else} +

+ 最近 {scope.days} 天 · UTC{scope.days < 30 + ? ' · 受查询范围或数据量限制,已缩短统计时段' + : ''} +

+
+
+
总请求数
+
{formatNumber(scope.summary.requests)}
+
+
+
消耗带宽
+
{formatBytes(scope.summary.bytes)}
+
+
+
CDN 请求命中率
+
+ {scope.summary.hitRate === null + ? '暂无请求' + : `${scope.summary.hitRate.toFixed(1)}%`} +
+
+
+ {#if scope.label === '博客'}

+ 后台及 API 请求:{formatNumber( + scope.summary.privateRequests + )};其他请求:{formatNumber( + scope.summary.requests - scope.summary.privateRequests + )}。均包含在总请求数中。 +

{/if} +
+ {#each Object.entries(scope.summary.statuses) as [status, count] (status)}{status}:{formatNumber(count)}{/each} +
+ {/if} +
+ {/each} + {#if scopes.some((scope) => !scope.error && scope.rows.length)}
-
- -
+
-
-
-
- - - - 页面浏览 (PV) -
-
{totalPV.toLocaleString()}
-
近 30 天累计访问量
-
-
-
- - - - 独立访客 (UV) -
-
{totalUV.toLocaleString()}
-
近 30 天去重访客数
-
-
-
- - - - 消耗总带宽 -
-
{formatBytes(totalBytes)}
-
包含网页及所有静态资源
-
-
-
- - - - 缓存命中率 -
-
{hitRate.toFixed(1)}%
-
由 Cloudflare CDN 成功拦截
-
-
-
- + {/if}
Cloudflare 资源配额
{#if missingEnvVars}
@@ -336,7 +193,7 @@ >
@@ -401,6 +258,46 @@