diff --git a/src/components/AiChat.vue b/src/components/AiChat.vue index 1954d4c..2276277 100644 --- a/src/components/AiChat.vue +++ b/src/components/AiChat.vue @@ -196,6 +196,7 @@ v-if="msg.content || (isLastAi(msg) && store.state.currentText)" class="ai-msg-bubble ai-msg-bubble--ai ai-md" :class="{ 'ai-msg-bubble--error': msg.isError }" + :key="'md-' + msg.id + '-' + (isLastAi(msg) ? _mdRenderKey : 0)" >
@@ -803,6 +804,14 @@ onMounted(async () => { console.debug(`[启动] AiChat IPC 完成: ${(performance.now() - t0).toFixed(0)}ms`) }) +// CR-260615-06: mdReady 就绪后主动触发首屏 Markdown 重渲染 +// (marked 加载慢 + 无新 delta 时末段停留纯文本,不触发模板重算) +const _mdRenderKey = ref(0) +function forceUpdate() { _mdRenderKey.value++ } +watch(mdReady, (ready) => { + if (ready) nextTick(() => { forceUpdate() }) +}) + // ── 置顶功能 ── const alwaysOnTop = ref(false) async function toggleAlwaysOnTop() { @@ -1208,78 +1217,6 @@ async function toggleAlwaysOnTop() { 50% { opacity: 0; } } -/* ═══ Markdown 渲染 ═══ */ -.ai-md :deep(p) { margin: 0 0 6px; } -.ai-md :deep(p:last-child) { margin-bottom: 0; } -.ai-md :deep(ul), .ai-md :deep(ol) { margin: 4px 0; padding-left: 20px; } -.ai-md :deep(li) { margin: 2px 0; line-height: 1.5; } -.ai-md :deep(code) { - font-family: var(--df-font-mono); - font-size: 12px; - padding: 1px 5px; - background: rgba(255,255,255,0.06); - border-radius: var(--df-radius-sm); - color: var(--df-accent); -} -.ai-md :deep(pre) { - margin: 8px 0; - padding: 10px 12px; - background: var(--df-bg); - border: 0.5px solid var(--df-border); - border-radius: var(--df-radius); - overflow-x: auto; -} -.ai-md :deep(pre code) { - padding: 0; - background: transparent; - border-radius: 0; - color: var(--df-text-secondary); - font-size: 12px; - line-height: 1.5; -} -.ai-md :deep(blockquote) { - margin: 6px 0; - padding: 4px 12px; - border-left: 2px solid var(--df-accent); - color: var(--df-text-secondary); -} -.ai-md :deep(h1), .ai-md :deep(h2), .ai-md :deep(h3) { - font-weight: 500; - color: var(--df-text); - margin: 8px 0 4px; -} -.ai-md :deep(h1) { font-size: 16px; } -.ai-md :deep(h2) { font-size: 14px; } -.ai-md :deep(h3) { font-size: 13px; } -.ai-md :deep(a) { - color: var(--df-accent); - text-decoration: none; -} -.ai-md :deep(a:hover) { text-decoration: underline; } -.ai-md :deep(strong) { font-weight: 500; color: var(--df-text); } -.ai-md :deep(hr) { - border: none; - border-top: 0.5px solid var(--df-border); - margin: 8px 0; -} -.ai-md :deep(table) { - width: 100%; - border-collapse: collapse; - margin: 6px 0; - font-size: 12px; - overflow-x: auto; - display: block; -} -.ai-md :deep(th), .ai-md :deep(td) { - padding: 4px 8px; - border: 0.5px solid var(--df-border); - text-align: left; -} -.ai-md :deep(th) { - font-weight: 500; - background: var(--df-bg); -} - /* ── token 用量条(克制:右对齐 / 最小字号 / dim / 分隔线,不抢正文焦点) ── */ .ai-token-usage { display: flex; diff --git a/src/main.ts b/src/main.ts index 2a37f21..e2a1e84 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,6 +3,7 @@ import App from "./App.vue"; import router from "./router"; import i18n from "./i18n"; import "./styles/global.css"; +import "./styles/ai-md.css"; createApp(App).use(router).use(i18n).mount("#app"); diff --git a/src/styles/ai-md.css b/src/styles/ai-md.css new file mode 100644 index 0000000..5ac6ca1 --- /dev/null +++ b/src/styles/ai-md.css @@ -0,0 +1,75 @@ +/* ═══ Markdown 渲染(全局,从 AiChat.vue