From 09b1661008f9147415a50a6bca96648fdcff9286 Mon Sep 17 00:00:00 2001
From: npmrun <1549469775@qq.com>
Date: Tue, 4 Aug 2026 16:59:02 +0800
Subject: [PATCH] log
---
.env.example | 3 +-
app/components/index/CardFormModal.vue | 2 +-
app/error.vue | 60 +++++++++++++++++++++
app/pages/auth/login.vue | 13 +----
app/plugins/error-reporter.client.ts | 62 ++++++++++++++++++++++
bun.lock | 3 ++
package.json | 1 +
packages/common/config/index.ts | 2 +
packages/drizzle-pkg/db.sqlite | Bin 282624 -> 282624 bytes
packages/env/schema.ts | 3 ++
packages/logger/index.ts | 3 +-
server/api/_error-report.post.ts | 38 +++++++++++++
server/api/auth/login.post.ts | 6 +++
server/api/auth/oauth/[provider]/authorize.get.ts | 5 ++
server/api/auth/oauth/[provider]/callback.get.ts | 12 +++++
server/api/auth/register.post.ts | 8 +++
server/api/file/upload.post.ts | 7 ++-
server/api/llm/chat/index.post.ts | 13 +++++
server/middleware/10.auth-guard.ts | 5 ++
server/plugins/00.req-time.ts | 7 +++
server/plugins/20.error-logger.ts | 2 +
server/scheduler/tasks/cleanup-logs.ts | 40 ++++++++++++--
server/service/auth/context.ts | 4 ++
server/service/auth/index.ts | 2 +
server/service/chat/index.ts | 5 +-
server/service/oauth/oauth-manager.ts | 21 +++++++-
server/utils/admin-guard.ts | 9 ++++
server/utils/handler.ts | 2 +
server/utils/simple-rate-limit.ts | 5 ++
29 files changed, 322 insertions(+), 21 deletions(-)
create mode 100644 app/error.vue
create mode 100644 app/plugins/error-reporter.client.ts
create mode 100644 server/api/_error-report.post.ts
diff --git a/.env.example b/.env.example
index 7e831e4..0c535b9 100644
--- a/.env.example
+++ b/.env.example
@@ -11,4 +11,5 @@ GITEA_CLIENT_ID=your_gitea_client_id
GITEA_CLIENT_SECRET=your_gitea_client_secret
GITEA_URL=https://gitea.com
NITRO_PORT=3399
-APP_URL=http://localhost:3399
\ No newline at end of file
+APP_URL=http://localhost:3399
+LOG_LEVEL=info
\ No newline at end of file
diff --git a/app/components/index/CardFormModal.vue b/app/components/index/CardFormModal.vue
index 158d5d5..b1d9744 100644
--- a/app/components/index/CardFormModal.vue
+++ b/app/components/index/CardFormModal.vue
@@ -181,7 +181,7 @@ async function onFileUpload(e: Event) {
})
imageUrl.value = raw.data[0].url
} catch (e) {
- console.log(e)
+ console.error('[CardFormModal] 图片上传失败:', e)
error.value = '图片上传失败'
}
}
diff --git a/app/error.vue b/app/error.vue
new file mode 100644
index 0000000..c2ee6d4
--- /dev/null
+++ b/app/error.vue
@@ -0,0 +1,60 @@
+
+
diff --git a/app/plugins/error-reporter.client.ts b/app/plugins/error-reporter.client.ts
new file mode 100644
index 0000000..ea9e679
--- /dev/null
+++ b/app/plugins/error-reporter.client.ts
@@ -0,0 +1,62 @@
+interface ClientErrorPayload {
+ message: string;
+ stack?: string;
+ url?: string;
+ line?: number;
+ column?: number;
+ userAgent?: string;
+ tags?: string[];
+}
+
+let reportEndpoint = "/api/_error-report";
+
+function reportError(payload: ClientErrorPayload) {
+ try {
+ $fetch(reportEndpoint, {
+ method: "POST",
+ body: payload,
+ }).catch(() => {});
+ } catch {
+ // 静默失败,避免错误上报本身导致循环
+ }
+}
+
+export default defineNuxtPlugin((nuxtApp) => {
+ // Vue 运行时错误
+ nuxtApp.vueApp.config.errorHandler = (err, _instance, info) => {
+ const error = err instanceof Error ? err : new Error(String(err));
+ reportError({
+ message: error.message,
+ stack: error.stack,
+ url: window.location.href,
+ userAgent: navigator.userAgent,
+ tags: ["vue", info],
+ });
+ };
+
+ // 未捕获的 Promise rejection
+ window.addEventListener("unhandledrejection", (event) => {
+ const reason = event.reason;
+ const error = reason instanceof Error ? reason : new Error(String(reason));
+ reportError({
+ message: error.message,
+ stack: error.stack,
+ url: window.location.href,
+ userAgent: navigator.userAgent,
+ tags: ["unhandledrejection"],
+ });
+ });
+
+ // 未捕获的同步错误
+ window.addEventListener("error", (event) => {
+ if (!event.message) return;
+ reportError({
+ message: event.message,
+ url: event.filename || window.location.href,
+ line: event.lineno,
+ column: event.colno,
+ userAgent: navigator.userAgent,
+ tags: ["window"],
+ });
+ });
+});
diff --git a/bun.lock b/bun.lock
index 5ed2bb7..cd5b52c 100644
--- a/bun.lock
+++ b/bun.lock
@@ -41,6 +41,7 @@
"zod": "4.3.6",
},
"devDependencies": {
+ "@iconify-json/ph": "^1.2.2",
"@nuxt/kit": "4.4.6",
"@tailwindcss/vite": "4.3.0",
"@types/multer": "2.1.0",
@@ -237,6 +238,8 @@
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
+ "@iconify-json/ph": ["@iconify-json/ph@1.2.2", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-PgkEZNtqa8hBGjHXQa4pMwZa93hmfu8FUSjs/nv4oUU6yLsgv+gh9nu28Kqi8Fz9CCVu4hj1MZs9/60J57IzFw=="],
+
"@iconify/collections": ["@iconify/collections@1.0.689", "https://registry.npmmirror.com/@iconify/collections/-/collections-1.0.689.tgz", { "dependencies": { "@iconify/types": "*" } }, "sha512-/XdTbQnsxfvpNvZvPCI2TGZHxem40PjUZ6IXoGA4M5QugVNN+l311l4PWyxECXOt95iFoKA8ZcHzyZVWFW9OFw=="],
"@iconify/types": ["@iconify/types@2.0.0", "https://registry.npmmirror.com/@iconify/types/-/types-2.0.0.tgz", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
diff --git a/package.json b/package.json
index a702640..68f30f5 100644
--- a/package.json
+++ b/package.json
@@ -55,6 +55,7 @@
"zod": "4.3.6"
},
"devDependencies": {
+ "@iconify-json/ph": "^1.2.2",
"@nuxt/kit": "4.4.6",
"@tailwindcss/vite": "4.3.0",
"@types/multer": "2.1.0",
diff --git a/packages/common/config/index.ts b/packages/common/config/index.ts
index 8e3a32c..cab7cd2 100644
--- a/packages/common/config/index.ts
+++ b/packages/common/config/index.ts
@@ -12,6 +12,8 @@ export const API_ALLOWLIST: RouteRule[] = [
{ path: "/api/config/global", methods: ["GET"] },
{ path: "/api/auth/oauth/:provider/callback", methods: ["GET"] },
{ path: "/api/auth/oauth/:provider/authorize", methods: ["GET"] },
+ /** 客户端错误上报 — 公开(无需登录) */
+ { path: "/api/_error-report", methods: ["POST"] },
/** 卡片列表 + 详情 */
{ path: "/api/cards", methods: ["GET"] },
{ path: "/api/cards/:id", methods: ["GET"] },
diff --git a/packages/drizzle-pkg/db.sqlite b/packages/drizzle-pkg/db.sqlite
index 1816764899706222ba0c2b60e38a06e077972c86..832dfa3f8de8953cc63b16059bf87600b7ccb3d4 100644
GIT binary patch
delta 679
zcma)&-%C?r7{}k|oSn_>{CIZK9n@)hNXWu1mASSgk_J{H{kS+$MCjS(B0*Gwpqm;>
z4Jn5u`9@kA6bY#nyEq_(H+4}6deu#d5rlX#B`*>rTJOn!AYOQ09^U8seLmkeJ*B3n
z)Db_d-LHtj+S|^HOQ4R