feat: add MarkdownEditor component and integrate it into news add/edit forms

This commit is contained in:
2026-01-09 00:05:41 +07:00
parent be085db45b
commit 28d93217a3
7 changed files with 727 additions and 17 deletions

View File

@@ -0,0 +1,48 @@
<script lang="ts" setup>
import type { ComponentInstance } from 'vue';
import { getCurrentInstance } from 'vue';
import { storeToRefs } from 'pinia';
import type { ToolbarNames } from 'md-editor-v3';
import { MdEditor } from 'md-editor-v3';
import { useThemeStore } from '@/store/modules/theme';
import 'md-editor-v3/lib/style.css';
const modelValue = defineModel('value', { type: String, default: '' });
const themeStore = useThemeStore();
const { darkMode } = storeToRefs(themeStore);
const toolbarsExclude: ToolbarNames[] = [
'github',
'catalog',
'previewOnly',
'fullscreen',
'image',
'code',
'codeRow',
'save',
'htmlPreview',
'next',
'revoke',
'mermaid'
];
const vm = getCurrentInstance()!;
function changeRef(expose: any) {
vm.exposed = expose;
}
defineExpose({} as ComponentInstance<typeof MdEditor>);
</script>
<template>
<MdEditor
:ref="changeRef"
v-model="modelValue"
v-bind="{ ...$attrs }"
:toolbars-exclude="toolbarsExclude"
:theme="darkMode ? 'dark' : 'light'"
/>
</template>
<style lang="css" scoped></style>

View File

@@ -25,8 +25,10 @@ declare module 'vue' {
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
IconIcRoundDelete: typeof import('~icons/ic/round-delete')['default']
IconIcRoundEdit: typeof import('~icons/ic/round-edit')['default']
IconIcRoundPlus: typeof import('~icons/ic/round-plus')['default']
IconIcRoundUpload: typeof import('~icons/ic/round-upload')['default']
IconIcRoundVisibility: typeof import('~icons/ic/round-visibility')['default']
IconLocalBanner: typeof import('~icons/local/banner')['default']
IconLocalLogo: typeof import('~icons/local/logo')['default']
IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default']
@@ -40,6 +42,7 @@ declare module 'vue' {
IconUilSearch: typeof import('~icons/uil/search')['default']
LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
LookForward: typeof import('./../components/custom/look-forward.vue')['default']
MarkdownEditor: typeof import('./../components/markdown-editor/index.vue')['default']
MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']
NAlert: typeof import('naive-ui')['NAlert']
NBadge: typeof import('naive-ui')['NBadge']
@@ -82,6 +85,7 @@ declare module 'vue' {
NSwitch: typeof import('naive-ui')['NSwitch']
NTab: typeof import('naive-ui')['NTab']
NTabs: typeof import('naive-ui')['NTabs']
NText: typeof import('naive-ui')['NText']
NThing: typeof import('naive-ui')['NThing']
NTooltip: typeof import('naive-ui')['NTooltip']
NUpload: typeof import('naive-ui')['NUpload']
@@ -118,8 +122,10 @@ declare global {
const IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
const IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
const IconIcRoundDelete: typeof import('~icons/ic/round-delete')['default']
const IconIcRoundEdit: typeof import('~icons/ic/round-edit')['default']
const IconIcRoundPlus: typeof import('~icons/ic/round-plus')['default']
const IconIcRoundUpload: typeof import('~icons/ic/round-upload')['default']
const IconIcRoundVisibility: typeof import('~icons/ic/round-visibility')['default']
const IconLocalBanner: typeof import('~icons/local/banner')['default']
const IconLocalLogo: typeof import('~icons/local/logo')['default']
const IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default']
@@ -133,6 +139,7 @@ declare global {
const IconUilSearch: typeof import('~icons/uil/search')['default']
const LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
const LookForward: typeof import('./../components/custom/look-forward.vue')['default']
const MarkdownEditor: typeof import('./../components/markdown-editor/index.vue')['default']
const MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']
const NAlert: typeof import('naive-ui')['NAlert']
const NBadge: typeof import('naive-ui')['NBadge']
@@ -175,6 +182,7 @@ declare global {
const NSwitch: typeof import('naive-ui')['NSwitch']
const NTab: typeof import('naive-ui')['NTab']
const NTabs: typeof import('naive-ui')['NTabs']
const NText: typeof import('naive-ui')['NText']
const NThing: typeof import('naive-ui')['NThing']
const NTooltip: typeof import('naive-ui')['NTooltip']
const NUpload: typeof import('naive-ui')['NUpload']

View File

@@ -163,14 +163,7 @@ async function handleSubmit() {
</NFormItem>
<NFormItem label="新闻内容" path="content">
<NInput
v-model:value="form.content"
type="textarea"
placeholder="请输入新闻内容"
:rows="10"
maxlength="10000"
show-count
/>
<MarkdownEditor v-model:value="form.content" placeholder="请输入新闻内容" :preview="false" />
</NFormItem>
<NFormItem label="附件上传" path="attachmentIds">

View File

@@ -165,14 +165,7 @@ async function handleSubmit() {
</NFormItem>
<NFormItem label="新闻内容" path="content">
<NInput
v-model:value="form.content"
type="textarea"
placeholder="请输入新闻内容"
:rows="10"
maxlength="10000"
show-count
/>
<MarkdownEditor v-model:value="form.content" placeholder="请输入新闻内容" :preview="false" />
</NFormItem>
<NFormItem label="附件上传" path="attachmentIds">

View File

@@ -134,7 +134,7 @@ function handleAdd() {
tableInst.value?.reload();
}
}),
style: { width: '600px' },
style: { width: '1200px' },
showIcon: false
});
}