117 lines
3.1 KiB
Vue
117 lines
3.1 KiB
Vue
<script setup lang="ts">
|
|
import { onMounted, onUnmounted, ref, watch } from 'vue';
|
|
import Vditor from 'vditor';
|
|
import 'vditor/dist/index.css';
|
|
import { useThemeStore } from '@/store/modules/theme';
|
|
import { localStg } from '@/utils/storage';
|
|
import { getServiceBaseURL } from '@/utils/service';
|
|
import { isExternal } from '@/utils/ruoyi';
|
|
|
|
defineOptions({
|
|
// eslint-disable-next-line vue/multi-word-component-names
|
|
name: 'Markdown'
|
|
});
|
|
|
|
const { placeholder, height } = defineProps<{
|
|
placeholder?: string;
|
|
height?: number;
|
|
}>();
|
|
|
|
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
|
|
const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);
|
|
|
|
const value = defineModel<string>('value', { default: '' });
|
|
|
|
const theme = useThemeStore();
|
|
|
|
const vditor = ref<Vditor>();
|
|
const domRef = ref<HTMLElement>();
|
|
|
|
function renderVditor() {
|
|
if (!domRef.value) return;
|
|
vditor.value = new Vditor(domRef.value, {
|
|
height: height || 300,
|
|
mode: 'wysiwyg',
|
|
width: '100%',
|
|
theme: theme.darkMode ? 'dark' : 'classic',
|
|
placeholder: placeholder || '请输入内容...',
|
|
cache: { enable: false },
|
|
value: value.value, // 初始值
|
|
blur: val => {
|
|
value.value = val;
|
|
},
|
|
upload: {
|
|
// 文件上传的接口地址
|
|
url: `${import.meta.env.VITE_SERVICE_BASE_URL}/${import.meta.env.VITE_SERVICE_UPLOAD}`,
|
|
// 图片链接转图片的接口地址
|
|
linkToImgUrl: `${import.meta.env.VITE_SERVICE_BASE_URL}/${import.meta.env.VITE_SERVICE_UPLOAD}`,
|
|
// 请求头,携带认证信息
|
|
headers: {
|
|
Authorization: `Bearer ${localStg.get('token')}` as string
|
|
},
|
|
// 是否允许多文件上传
|
|
multiple: false,
|
|
// 文件上传后的格式处理函数
|
|
format: (files: File[], responseText: string): string => {
|
|
// 解析服务器返回的响应
|
|
const res = JSON.parse(responseText);
|
|
// 如果上传成功,返回格式化的数据
|
|
if (res.code === 200) {
|
|
let url = res.data.url;
|
|
if (!url.includes(baseURL) && !isExternal(url)) {
|
|
url = `${baseURL}${url}`;
|
|
}
|
|
return JSON.stringify({
|
|
msg: res.msg,
|
|
data: {
|
|
succMap: {
|
|
[url]: url // 成功上传的文件 URL
|
|
},
|
|
errFiles: [] // 失败的文件列表
|
|
}
|
|
});
|
|
}
|
|
// 如果上传失败,返回错误信息
|
|
return JSON.stringify({
|
|
msg: res.msg,
|
|
data: {
|
|
succMap: {},
|
|
errFiles: files.map(file => file.name) // 所有文件标记为失败
|
|
}
|
|
});
|
|
},
|
|
// 文件上传的字段名
|
|
fieldName: 'file',
|
|
// 文件大小限制(单位:字节)
|
|
max: 10 * 1024 * 1024 // 10MB
|
|
}
|
|
});
|
|
}
|
|
|
|
const stopHandle = watch(
|
|
() => theme.darkMode,
|
|
newValue => {
|
|
const themeMode = newValue ? 'dark' : 'classic';
|
|
vditor.value?.setTheme(themeMode);
|
|
}
|
|
);
|
|
|
|
onMounted(() => {
|
|
renderVditor();
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
stopHandle();
|
|
});
|
|
|
|
defineExpose({
|
|
vditor
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div ref="domRef"></div>
|
|
</template>
|
|
|
|
<style scoped></style>
|