优化: CR-06 mdReady翻转主动重渲染(_mdRenderKey强制刷新)+CR-09 .ai-md样式抽全局css(70行去重→ai-md.css+main.ts导入)

This commit is contained in:
2026-06-15 12:23:19 +08:00
parent be38a44b0c
commit 8382730bbd
3 changed files with 85 additions and 72 deletions

View File

@@ -196,6 +196,7 @@
v-if="msg.content || (isLastAi(msg) && store.state.currentText)" v-if="msg.content || (isLastAi(msg) && store.state.currentText)"
class="ai-msg-bubble ai-msg-bubble--ai ai-md" class="ai-msg-bubble ai-msg-bubble--ai ai-md"
:class="{ 'ai-msg-bubble--error': msg.isError }" :class="{ 'ai-msg-bubble--error': msg.isError }"
:key="'md-' + msg.id + '-' + (isLastAi(msg) ? _mdRenderKey : 0)"
> >
<div v-html="renderContent(msg)"></div> <div v-html="renderContent(msg)"></div>
<span v-if="isLastAi(msg) && isViewingGenerating" class="ai-cursor"></span> <span v-if="isLastAi(msg) && isViewingGenerating" class="ai-cursor"></span>
@@ -803,6 +804,14 @@ onMounted(async () => {
console.debug(`[启动] AiChat IPC 完成: ${(performance.now() - t0).toFixed(0)}ms`) 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) const alwaysOnTop = ref(false)
async function toggleAlwaysOnTop() { async function toggleAlwaysOnTop() {
@@ -1208,78 +1217,6 @@ async function toggleAlwaysOnTop() {
50% { opacity: 0; } 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 / 分隔线,不抢正文焦点) ── */ /* ── token 用量条(克制:右对齐 / 最小字号 / dim / 分隔线,不抢正文焦点) ── */
.ai-token-usage { .ai-token-usage {
display: flex; display: flex;

View File

@@ -3,6 +3,7 @@ import App from "./App.vue";
import router from "./router"; import router from "./router";
import i18n from "./i18n"; import i18n from "./i18n";
import "./styles/global.css"; import "./styles/global.css";
import "./styles/ai-md.css";
createApp(App).use(router).use(i18n).mount("#app"); createApp(App).use(router).use(i18n).mount("#app");

75
src/styles/ai-md.css Normal file
View File

@@ -0,0 +1,75 @@
/* ═══ Markdown 渲染(全局,从 AiChat.vue <style scoped> 抽出) ═══ */
/* CR-260615-09: 原 5 文件重复 ~350 行 → 仅 AiChat.vue 有实际内容,
其余 4 文件(ProjectDetail/Ideas/Knowledge/TaskDetail)零 .ai-md 引用。
提为全局 CSS 消除唯一重复源。 */
.ai-md p { margin: 0 0 6px; }
.ai-md p:last-child { margin-bottom: 0; }
.ai-md ul, .ai-md ol { margin: 4px 0; padding-left: 20px; }
.ai-md li { margin: 2px 0; line-height: 1.5; }
.ai-md 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 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 pre code {
padding: 0;
background: transparent;
border-radius: 0;
color: var(--df-text-secondary);
font-size: 12px;
line-height: 1.5;
}
.ai-md blockquote {
margin: 6px 0;
padding: 4px 12px;
border-left: 2px solid var(--df-accent);
color: var(--df-text-secondary);
}
.ai-md h1, .ai-md h2, .ai-md h3 {
font-weight: 500;
color: var(--df-text);
margin: 8px 0 4px;
}
.ai-md h1 { font-size: 16px; }
.ai-md h2 { font-size: 14px; }
.ai-md h3 { font-size: 13px; }
.a-md a {
color: var(--df-accent);
text-decoration: none;
}
.ai-md a:hover { text-decoration: underline; }
.ai-md strong { font-weight: 500; color: var(--df-text); }
.ai-md hr {
border: none;
border-top: 0.5px solid var(--df-border);
margin: 8px 0;
}
.ai-md table {
width: 100%;
border-collapse: collapse;
margin: 6px 0;
font-size: 12px;
overflow-x: auto;
display: block;
}
.ai-md th, .ai-md td {
padding: 4px 8px;
border: 0.5px solid var(--df-border);
text-align: left;
}
.ai-md th {
font-weight: 500;
background: var(--df-bg);
}