1 changed files with 80 additions and 0 deletions
@ -0,0 +1,80 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import { MdEditor } from 'md-editor-v3' |
||||
|
import 'md-editor-v3/lib/style.css' |
||||
|
import { request, unwrapApiBody, type ApiResponse } from '~/utils/http/factory' |
||||
|
|
||||
|
const props = defineProps<{ |
||||
|
modelValue: string |
||||
|
}>() |
||||
|
|
||||
|
const emit = defineEmits<{ |
||||
|
'update:modelValue': [string] |
||||
|
}>() |
||||
|
|
||||
|
const toast = useToast() |
||||
|
const editorId = `post-body-md-${useId()}` |
||||
|
|
||||
|
const local = computed({ |
||||
|
get: () => props.modelValue, |
||||
|
set: (v: string) => emit('update:modelValue', v), |
||||
|
}) |
||||
|
|
||||
|
function extractUploadError(e: unknown): string { |
||||
|
if (e && typeof e === 'object') { |
||||
|
const fe = e as { |
||||
|
statusMessage?: string |
||||
|
message?: string |
||||
|
data?: { message?: string } |
||||
|
} |
||||
|
if (typeof fe.statusMessage === 'string' && fe.statusMessage.length) { |
||||
|
return fe.statusMessage |
||||
|
} |
||||
|
if (typeof fe.data?.message === 'string' && fe.data.message.length) { |
||||
|
return fe.data.message |
||||
|
} |
||||
|
if (typeof fe.message === 'string' && fe.message.length) { |
||||
|
return fe.message |
||||
|
} |
||||
|
} |
||||
|
return '图片上传失败' |
||||
|
} |
||||
|
|
||||
|
async function onUploadImg(files: File[], callback: (urls: string[]) => void) { |
||||
|
const form = new FormData() |
||||
|
for (const f of files) { |
||||
|
form.append('file', f) |
||||
|
} |
||||
|
try { |
||||
|
const res = await request<ApiResponse<{ files: { url: string }[] }>>('/api/file/upload', { |
||||
|
method: 'POST', |
||||
|
body: form, |
||||
|
}) |
||||
|
const { files: uploaded } = unwrapApiBody(res) |
||||
|
callback(uploaded.map((x) => x.url)) |
||||
|
} catch (e: unknown) { |
||||
|
toast.add({ title: extractUploadError(e), color: 'error' }) |
||||
|
callback([]) |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<ClientOnly> |
||||
|
<MdEditor |
||||
|
:id="editorId" |
||||
|
v-model="local" |
||||
|
language="zh-CN" |
||||
|
:preview="true" |
||||
|
preview-theme="github" |
||||
|
theme="light" |
||||
|
:on-upload-img="onUploadImg" |
||||
|
:style="{ height: 'min(72vh, 720px)' }" |
||||
|
class="w-full rounded-lg overflow-hidden ring ring-default" |
||||
|
/> |
||||
|
<template #fallback> |
||||
|
<div class="text-muted text-sm py-12 text-center border border-default rounded-lg"> |
||||
|
编辑器加载中… |
||||
|
</div> |
||||
|
</template> |
||||
|
</ClientOnly> |
||||
|
</template> |
||||
Loading…
Reference in new issue