diff --git a/app/assets/scss/common.scss b/app/assets/scss/common.scss index d5e9838..e4c9473 100644 --- a/app/assets/scss/common.scss +++ b/app/assets/scss/common.scss @@ -1,2 +1,45 @@ @use "./markdown/reset.scss"; -@use "./markdown/green.scss"; \ No newline at end of file +@use "./markdown/green.scss"; + +// .code-block-wrapper { +// position: relative; +// margin: 16px 0; +// border-radius: 8px; +// background: #1e1e1e; +// overflow: hidden; +// } +// .code-header { +// display: flex; +// justify-content: space-between; +// align-items: center; +// padding: 8px 12px; +// background: #2d2d2d; +// color: #ccc; +// font-size: 14px; +// } +// .code-lang { +// font-weight: 600; +// text-transform: uppercase; +// } +// .copy-btn { +// padding: 4px 8px; +// border: none; +// border-radius: 4px; +// background: #444; +// color: #fff; +// cursor: pointer; +// font-size: 12px; +// transition: all 0.2s; +// } +// .copy-btn:hover { +// background: #555; +// } +// pre { +// margin: 0; +// padding: 12px; +// overflow-x: auto; +// } +// code { +// color: #d4d4d4; +// font-family: 'Consolas', 'Monaco', monospace; +// } \ No newline at end of file diff --git a/app/components/PostBodyMarkdownEditor.vue b/app/components/PostBodyMarkdownEditor.vue index e99df00..683a0a0 100644 --- a/app/components/PostBodyMarkdownEditor.vue +++ b/app/components/PostBodyMarkdownEditor.vue @@ -28,6 +28,9 @@ function ensureMdEditorStripFrontMatter() { mdEditorGlobalConfig({ markdownItConfig(md) { attachMarkdownItStripFrontMatter(md, 'person_panel_strip_fm') + md.set({ + html: false + }) }, }) } diff --git a/app/utils/render-markdown.ts b/app/utils/render-markdown.ts index 52399c9..cab9db2 100644 --- a/app/utils/render-markdown.ts +++ b/app/utils/render-markdown.ts @@ -7,8 +7,50 @@ const md = new MarkdownIt({ linkify: true, typographer: false, breaks: true, + // // 开启代码块语言识别 + // highlight: function (str: string, lang: string) { + // // 处理语言标签(如果没有指定语言,默认 text) + // const language = lang || 'text' + // // 生成带语言标识 + 复制按钮的代码块外壳 + // return ` + //
+ //
+ // ${language} + // + //
+ //
${md.utils.escapeHtml(str)}
+ //
+ // ` + // }, }) +// /** 全局复制代码函数(挂载到 window,确保页面可调用) */ +// declare global { +// interface Window { +// copyCode: (btn: HTMLButtonElement) => void +// } +// } + +// // 只在客户端环境注册复制函数 +// if (typeof window !== 'undefined') { +// window.copyCode = function (btn: HTMLButtonElement) { +// const codeBlock = btn.closest('.code-block-wrapper')!.querySelector('code')! +// const text = codeBlock.textContent || '' + +// navigator.clipboard.writeText(text).then(() => { +// const originalText = btn.textContent +// btn.textContent = '已复制' +// btn.style.backgroundColor = '#10b981' + +// // 2秒后恢复按钮文字 +// setTimeout(() => { +// btn.textContent = originalText +// btn.style.backgroundColor = '' +// }, 2000) +// }) +// } +// } + /** 将 Markdown 转为可安全用于 `v-html` 的 HTML(禁用源码中的原始 HTML)。 */ export function renderSafeMarkdown(src: string): string { if (!src.trim()) { diff --git a/packages/drizzle-pkg/db.sqlite b/packages/drizzle-pkg/db.sqlite index d3823f1..84ff945 100644 Binary files a/packages/drizzle-pkg/db.sqlite and b/packages/drizzle-pkg/db.sqlite differ diff --git a/server/plugins/03.error-logger.ts b/server/plugins/03.error-logger.ts index c0385fe..1b56fa2 100644 --- a/server/plugins/03.error-logger.ts +++ b/server/plugins/03.error-logger.ts @@ -2,6 +2,23 @@ import log4js from "logger"; const logger = log4js.getLogger("ERROR"); +/** 路径/路由类「找不到」:只打控制台,不落盘(避免扫描、错 URL 等刷爆 running.log) */ +function isPathNotFoundLikeError(error: unknown): boolean { + if (!error || typeof error !== "object") return false; + const e = error as NodeJS.ErrnoException & { statusCode?: number; statusMessage?: string }; + const code = typeof e.code === "string" ? e.code : ""; + if (code === "ENOENT" || code === "ENOTDIR") return true; + + if (e.statusCode !== 404) return false; + const sm = (e.statusMessage ?? "").trim(); + if (!sm) return true; + if (/^not found$/i.test(sm)) return true; + if (/page not found/i.test(sm)) return true; + if (/^cannot (get|post|put|delete|patch|head)\b/i.test(sm)) return true; + if (/no route found|cannot find.*route|static asset.*not found/i.test(sm)) return true; + return false; +} + const processHandlersKey = "__personPanelErrorLoggerProcessHandlers"; function installProcessErrorLogging() { @@ -32,12 +49,19 @@ export default defineNitroPlugin((nitroApp) => { nitroApp.hooks.hook("error", (error, context) => { const event = context.event; const tags = Array.isArray(context.tags) ? (context.tags as string[]).join(",") : ""; - logger.error( + const prefix = [ event?.method ?? "", event?.path ?? "(no request)", tags ? `[${tags}]` : "", - "\n", - error - ); + ] + .filter(Boolean) + .join(" "); + + if (isPathNotFoundLikeError(error)) { + console.error(prefix || "(error)", "\n", error); + return; + } + + logger.error(prefix, "\n", error); }); });