工作台笔记之前是个纯 textarea,内容原样显示,所以 Markdown 一直不解析。现在在笔记面板右上角加了「编辑 / 预览」切换:
编辑:还是原来的 textarea,防抖自动保存不变,占位提示换成了 Markdown 语法提示(和待办/工单编辑器一致)。 预览:用项目里已有的 MarkdownView 渲染,支持标题、列表、任务勾选框、代码块、链接、图片(本地图和外链都会经后端转成 dataURL 显示),点链接走系统浏览器。 几个细节:切到预览前会先把防抖窗口内没落盘的改动存一次,避免丢内容;切换状态记在 localStorage,下次进工作台保持上次选的模式;空笔记在预览下显示「(暂无内容)」占位。按钮复用了 md 编辑器已有的 mdEdit/mdPreviewTab 文案,所以中英文都已经有了,不需要新增词条。
This commit is contained in:
@@ -2,9 +2,10 @@
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { Star, Folder, Code2, GitCommitHorizontal, ListTodo, TicketCheck, StickyNote, ArrowRight, Circle, CircleDot, CircleCheck, Play, Check, CalendarDays, Plus, Bell, Save } from 'lucide-vue-next'
|
||||
import { Star, Folder, Code2, GitCommitHorizontal, ListTodo, TicketCheck, StickyNote, ArrowRight, Circle, CircleDot, CircleCheck, Play, Check, CalendarDays, Plus, Bell, Save, Pencil, Eye } from 'lucide-vue-next'
|
||||
import StatCard from '../components/StatCard.vue'
|
||||
import AIDayPanel from '../components/AIDayPanel.vue'
|
||||
import MarkdownView from '../components/MarkdownView.vue'
|
||||
import { call } from '../api'
|
||||
import { useAppStore } from '../store'
|
||||
|
||||
@@ -19,6 +20,8 @@ const noteText = ref('')
|
||||
const noteSavedAt = ref('')
|
||||
const noteDirty = ref(false)
|
||||
const noteSaving = ref(false)
|
||||
// 编辑/预览切换(预览走 Markdown 渲染),选择记忆在本地
|
||||
const notePreview = ref(localStorage.getItem('cc-wb-note-preview') === '1')
|
||||
const messages = ref([])
|
||||
let noteTimer
|
||||
|
||||
@@ -76,6 +79,13 @@ function editNote() {
|
||||
clearTimeout(noteTimer)
|
||||
noteTimer = setTimeout(() => { saveNote(false) }, 800)
|
||||
}
|
||||
// 切到预览前先落盘,避免防抖窗口内的改动丢失
|
||||
async function setNotePreview(on) {
|
||||
if (notePreview.value === on) return
|
||||
if (on && noteDirty.value) await saveNote(false)
|
||||
notePreview.value = on
|
||||
localStorage.setItem('cc-wb-note-preview', on ? '1' : '0')
|
||||
}
|
||||
async function saveNote(manual = true) {
|
||||
if (noteSaving.value) return
|
||||
noteSaving.value = true
|
||||
@@ -201,6 +211,10 @@ onUnmounted(() => clearTimeout(noteTimer))
|
||||
<div class="wb-note-acts">
|
||||
<small v-if="noteDirty" class="wb-note-dirty">{{ t('noteUnsaved') }}</small>
|
||||
<small v-else-if="noteSavedAt" class="wb-note-saved">{{ t('autoSaved') }} {{ noteSavedAt }}</small>
|
||||
<div class="tabs compact wb-note-tabs">
|
||||
<button type="button" :class="{ active: !notePreview }" @click="setNotePreview(false)"><Pencil />{{ t('mdEdit') }}</button>
|
||||
<button type="button" :class="{ active: notePreview }" @click="setNotePreview(true)"><Eye />{{ t('mdPreviewTab') }}</button>
|
||||
</div>
|
||||
<button type="button" class="btn secondary" :title="t('noteNew')" @click="newNote"><Plus /></button>
|
||||
<button type="button" class="btn primary" :disabled="noteSaving || !noteDirty" :title="t('save')" @click="saveNote(true)"><Save />{{ t('save') }}</button>
|
||||
<button type="button" class="btn secondary" @click="router.push('/notes')">{{ t('viewAll') }}<ArrowRight /></button>
|
||||
@@ -221,7 +235,8 @@ onUnmounted(() => clearTimeout(noteTimer))
|
||||
</button>
|
||||
<div v-if="!notes.length" class="wb-note-list-empty">{{ t('noteEmpty') }}</div>
|
||||
</aside>
|
||||
<textarea v-model="noteText" class="wb-note" :placeholder="t('notepadPlaceholder')" @input="editNote" />
|
||||
<textarea v-show="!notePreview" v-model="noteText" class="wb-note" :placeholder="t('mdPlaceholder')" @input="editNote" />
|
||||
<MarkdownView v-if="notePreview" class="wb-note-preview md-preview-box" :source="noteText || t('mdEmpty')" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user