feat(markdown): 只读内容支持 Markdown 渲染
- 新增 MarkdownRenderer.vue 组件,基于 marked 解析 GFM
- 学习残片/报告历史列表:纯文本 {{ }} 替换为 MarkdownRenderer
- ReviewDetail.vue content-body:p 标签逐行渲染替换为 MarkdownRenderer
- 结束会话总结框:增加「编辑/预览」切换,预览模式实时渲染 markdown
- 学习预期展示也改为 MarkdownRenderer
This commit is contained in:
@@ -13,6 +13,7 @@ import { useStudyFragment } from "@/components/composables/fragment";
|
||||
import { getFragmentsBySession, updateFragments } from "@/api/reportFragments";
|
||||
import { getExpectation, getReportDraft, getTaskFragments, getTaskReports, upsertExpectation } from "@/api/studySessions";
|
||||
import router from "@/router";
|
||||
import MarkdownRenderer from "@/components/MarkdownRenderer.vue";
|
||||
|
||||
const {
|
||||
fragmentsDialogVisible,
|
||||
@@ -24,6 +25,7 @@ const {
|
||||
|
||||
const summaryDialogVisible = ref(false);
|
||||
const summaryContent = ref("");
|
||||
const summaryPreview = ref(false);
|
||||
const summaryLoading = ref(false);
|
||||
const summaryLoadingSeconds = ref(0);
|
||||
let summaryLoadingTimer: ReturnType<typeof setInterval> | null = null;
|
||||
@@ -666,7 +668,7 @@ onUnmounted(() => {
|
||||
<div v-loading="loadingHistory" class="history-list">
|
||||
<div v-for="item in historyFragments" :key="item.id" class="history-item">
|
||||
<span class="session-tag">{{ item.sessionNum }}</span>
|
||||
<span class="history-content">{{ item.content }}</span>
|
||||
<MarkdownRenderer :content="item.content" />
|
||||
</div>
|
||||
<el-empty v-if="!loadingHistory && historyFragments.length === 0" description="暂未找到匹配的残片" :image-size="48"></el-empty>
|
||||
</div>
|
||||
@@ -676,7 +678,7 @@ onUnmounted(() => {
|
||||
<div v-loading="loadingHistory" class="history-list">
|
||||
<div v-for="item in historyReports" :key="item.id" class="history-item report-item">
|
||||
<span class="session-tag">{{ item.sessionNum }}</span>
|
||||
<p class="history-content">{{ item.content }}</p>
|
||||
<MarkdownRenderer :content="item.content" />
|
||||
</div>
|
||||
<el-empty v-if="!loadingHistory && historyReports.length === 0" description="暂未找到匹配的报告" :image-size="48" />
|
||||
</div>
|
||||
@@ -721,21 +723,39 @@ onUnmounted(() => {
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="summaryDialogVisible" title="结束会话总结" width="560px">
|
||||
<el-dialog v-model="summaryDialogVisible" title="结束会话总结" width="640px">
|
||||
<div v-if="expectationSaved" class="summary-expectation">
|
||||
<span class="expectation-label">本次预期</span>
|
||||
<span>{{ expectationSaved }}</span>
|
||||
<MarkdownRenderer :content="expectationSaved" />
|
||||
</div>
|
||||
<p v-if="summaryLoading" class="ai-waiting">
|
||||
AI 正在聚合残片生成草稿,已等待 {{ summaryLoadingSeconds }} 秒…
|
||||
</p>
|
||||
<el-input
|
||||
v-loading="summaryLoading"
|
||||
type="textarea"
|
||||
v-model="summaryContent"
|
||||
placeholder="总结本次学到的内容(已有残片时自动生成草稿,可修改)"
|
||||
:rows="8"
|
||||
/>
|
||||
<div class="summary-editor">
|
||||
<div class="summary-toolbar">
|
||||
<el-button
|
||||
size="small"
|
||||
:type="summaryPreview ? '' : 'primary'"
|
||||
@click="summaryPreview = false"
|
||||
>编辑</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
:type="summaryPreview ? 'primary' : ''"
|
||||
@click="summaryPreview = true"
|
||||
>预览</el-button>
|
||||
</div>
|
||||
<el-input
|
||||
v-if="!summaryPreview"
|
||||
v-loading="summaryLoading"
|
||||
type="textarea"
|
||||
v-model="summaryContent"
|
||||
placeholder="总结本次学到的内容(已有残片时自动生成草稿,可修改)"
|
||||
:rows="8"
|
||||
/>
|
||||
<div v-else class="summary-preview">
|
||||
<MarkdownRenderer :content="summaryContent" />
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="closeSummaryDialog">取消</el-button>
|
||||
<el-button type="success" @click="endTimer(summaryContent)">确认结束</el-button>
|
||||
@@ -819,6 +839,33 @@ onUnmounted(() => {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.summary-editor {
|
||||
border: 1px solid #e0e8e0;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.summary-toolbar {
|
||||
display: flex;
|
||||
gap: 0;
|
||||
border-bottom: 1px solid #e0e8e0;
|
||||
background: #f9fbf9;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.summary-toolbar .el-button {
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.summary-preview {
|
||||
padding: 12px 16px;
|
||||
min-height: 200px;
|
||||
max-height: 360px;
|
||||
overflow-y: auto;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
|
||||
Reference in New Issue
Block a user