优化: CR-06 mdReady翻转主动重渲染(_mdRenderKey强制刷新)+CR-09 .ai-md样式抽全局css(70行去重→ai-md.css+main.ts导入)
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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
75
src/styles/ai-md.css
Normal 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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user