From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/components/Editor/src/Editor.vue | 294 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 294 insertions(+), 0 deletions(-)
diff --git a/src/components/Editor/src/Editor.vue b/src/components/Editor/src/Editor.vue
new file mode 100644
index 0000000..30146be
--- /dev/null
+++ b/src/components/Editor/src/Editor.vue
@@ -0,0 +1,294 @@
+<script lang="ts" setup>
+import { PropType } from 'vue'
+import { Editor, Toolbar } from '@wangeditor-next/editor-for-vue'
+import { i18nChangeLanguage, IDomEditor, IEditorConfig } from '@wangeditor-next/editor'
+import { propTypes } from '@/utils/propTypes'
+import { isNumber } from '@/utils/is'
+import { ElMessage } from 'element-plus'
+import { useLocaleStore } from '@/store/modules/locale'
+import { getRefreshToken, getTenantId } from '@/utils/auth'
+import { getUploadUrl } from '@/components/UploadFile/src/useUpload'
+import merge from 'lodash-es/merge'
+
+defineOptions({ name: 'Editor' })
+
+type InsertFnType = (url: string, alt: string, href: string) => void
+
+const localeStore = useLocaleStore()
+
+const currentLocale = computed(() => localeStore.getCurrentLocale)
+
+i18nChangeLanguage(unref(currentLocale).lang)
+
+const props = defineProps({
+ editorId: propTypes.string.def('wangEditor-1'),
+ height: propTypes.oneOfType([Number, String]).def('500px'),
+ editorConfig: {
+ type: Object as PropType<Partial<IEditorConfig>>,
+ default: () => undefined
+ },
+ readonly: propTypes.bool.def(false),
+ modelValue: propTypes.string.def(''),
+ directory: propTypes.string.def('editor-default')
+})
+
+const emit = defineEmits(['change', 'update:modelValue'])
+
+// 缂栬緫鍣ㄥ疄渚嬶紝蹇呴』鐢� shallowRef
+const editorRef = shallowRef<IDomEditor>()
+
+const valueHtml = ref('')
+
+watch(
+ () => props.modelValue,
+ (val: string) => {
+ if (!val) {
+ val = ''
+ }
+ if (val === unref(valueHtml)) return
+ valueHtml.value = val
+ },
+ {
+ immediate: true
+ }
+)
+
+// 鐩戝惉
+watch(
+ () => valueHtml.value,
+ (val: string) => {
+ emit('update:modelValue', val)
+ }
+)
+watch(
+ () => props.readonly,
+ async (val) => {
+ // 鐗规畩锛氱瓑寰� editorRef 娓叉煋瀹屾垚
+ if (!editorRef.value) {
+ await nextTick()
+ }
+ if (val) {
+ editorRef.value?.disable()
+ } else {
+ editorRef.value?.enable()
+ }
+ }
+)
+
+const handleCreated = (editor: IDomEditor) => {
+ editorRef.value = editor
+}
+
+// 缂栬緫鍣ㄩ厤缃�
+const editorConfig = computed((): IEditorConfig => {
+ return merge(
+ {
+ placeholder: '璇疯緭鍏ュ唴瀹�...',
+ readOnly: props.readonly,
+ customAlert: (s: string, t: string) => {
+ switch (t) {
+ case 'success':
+ ElMessage.success(s)
+ break
+ case 'info':
+ ElMessage.info(s)
+ break
+ case 'warning':
+ ElMessage.warning(s)
+ break
+ case 'error':
+ ElMessage.error(s)
+ break
+ default:
+ ElMessage.info(s)
+ break
+ }
+ },
+ autoFocus: false,
+ scroll: true,
+ EXTEND_CONF: {
+ mentionConfig: {
+ showModal: () => {},
+ hideModal: () => {}
+ }
+ },
+ MENU_CONF: {
+ ['uploadImage']: {
+ server: getUploadUrl(),
+ // 鍗曚釜鏂囦欢鐨勬渶澶т綋绉檺鍒讹紝榛樿涓� 2M
+ maxFileSize: 10 * 1024 * 1024,
+ // 鏈�澶氬彲涓婁紶鍑犱釜鏂囦欢锛岄粯璁や负 100
+ maxNumberOfFiles: 100,
+ // 閫夋嫨鏂囦欢鏃剁殑绫诲瀷闄愬埗锛岄粯璁や负 ['image/*'] 銆傚涓嶆兂闄愬埗锛屽垯璁剧疆涓� []
+ allowedFileTypes: ['image/*'],
+
+ // 鑷畾涔夊鍔� http header
+ headers: {
+ Accept: '*',
+ Authorization: 'Bearer ' + getRefreshToken(), // 浣跨敤 getRefreshToken() 鏂规硶锛岃�屼笉浣跨敤 getAccessToken() 鏂规硶鐨勫師鍥狅細Editor 鏃犳硶鏂逛究鐨勫埛鏂拌闂护鐗�
+ 'tenant-id': getTenantId()
+ },
+
+ // 瓒呮椂鏃堕棿锛岄粯璁や负 10 绉�
+ timeout: 15 * 1000, // 15 绉�
+
+ // form-data fieldName锛屽悗绔帴鍙e弬鏁板悕绉帮紝榛樿鍊紈angeditor-uploaded-image
+ fieldName: 'file',
+ // 闄勫姞鍙傛暟
+ meta: {
+ directory: `${props.directory}-image`
+ },
+ metaWithUrl: false,
+
+ // uppy 閰嶇疆椤�
+ uppyConfig: {
+ onBeforeFileAdded: (newFile: any) => {
+ newFile.id = `${newFile.id}-${Date.now()}`
+ return newFile
+ }
+ },
+
+ // 涓婁紶涔嬪墠瑙﹀彂
+ onBeforeUpload(file: File) {
+ // console.log(file)
+ return file
+ },
+ // 涓婁紶杩涘害鐨勫洖璋冨嚱鏁�
+ onProgress(progress: number) {
+ // progress 鏄� 0-100 鐨勬暟瀛�
+ console.log('progress', progress)
+ },
+ onSuccess(file: File, res: any) {
+ console.log('onSuccess', file, res)
+ },
+ onFailed(file: File, res: any) {
+ alert(res.message)
+ console.log('onFailed', file, res)
+ },
+ onError(file: File, err: any, res: any) {
+ alert(err.message)
+ console.error('onError', file, err, res)
+ },
+ // 鑷畾涔夋彃鍏ュ浘鐗�
+ customInsert(res: any, insertFn: InsertFnType) {
+ insertFn(res.data, 'image', res.data)
+ }
+ },
+ ['uploadVideo']: {
+ server: getUploadUrl(),
+ // 鍗曚釜鏂囦欢鐨勬渶澶т綋绉檺鍒讹紝榛樿涓� 10M
+ maxFileSize: 1024 * 1024 * 1024,
+ // 鏈�澶氬彲涓婁紶鍑犱釜鏂囦欢锛岄粯璁や负 100
+ maxNumberOfFiles: 10,
+ // 閫夋嫨鏂囦欢鏃剁殑绫诲瀷闄愬埗锛岄粯璁や负 ['video/*'] 銆傚涓嶆兂闄愬埗锛屽垯璁剧疆涓� []
+ allowedFileTypes: ['video/*'],
+
+ // 鑷畾涔夊鍔� http header
+ headers: {
+ Accept: '*',
+ Authorization: 'Bearer ' + getRefreshToken(), // 浣跨敤 getRefreshToken() 鏂规硶锛岃�屼笉浣跨敤 getAccessToken() 鏂规硶鐨勫師鍥狅細Editor 鏃犳硶鏂逛究鐨勫埛鏂拌闂护鐗�
+ 'tenant-id': getTenantId()
+ },
+
+ // 瓒呮椂鏃堕棿锛岄粯璁や负 30 绉�
+ timeout: 15 * 1000, // 15 绉�
+
+ // form-data fieldName锛屽悗绔帴鍙e弬鏁板悕绉帮紝榛樿鍊紈angeditor-uploaded-image
+ fieldName: 'file',
+ // 闄勫姞鍙傛暟
+ meta: {
+ directory: `${props.directory}-video`
+ },
+ metaWithUrl: false,
+
+ // uppy 閰嶇疆椤�
+ uppyConfig: {
+ onBeforeFileAdded: (newFile: any) => {
+ newFile.id = `${newFile.id}-${Date.now()}`
+ return newFile
+ }
+ },
+
+ // 涓婁紶涔嬪墠瑙﹀彂
+ onBeforeUpload(file: File) {
+ // console.log(file)
+ return file
+ },
+ // 涓婁紶杩涘害鐨勫洖璋冨嚱鏁�
+ onProgress(progress: number) {
+ // progress 鏄� 0-100 鐨勬暟瀛�
+ console.log('progress', progress)
+ },
+ onSuccess(file: File, res: any) {
+ console.log('onSuccess', file, res)
+ },
+ onFailed(file: File, res: any) {
+ alert(res.message)
+ console.log('onFailed', file, res)
+ },
+ onError(file: File, err: any, res: any) {
+ alert(err.message)
+ console.error('onError', file, err, res)
+ },
+ // 鑷畾涔夋彃鍏ュ浘鐗�
+ customInsert(res: any, insertFn: InsertFnType) {
+ insertFn(res.data, 'mp4', res.data)
+ }
+ }
+ },
+ uploadImgShowBase64: true
+ },
+ props.editorConfig || {}
+ )
+})
+
+const editorStyle = computed(() => {
+ return {
+ height: isNumber(props.height) ? `${props.height}px` : props.height
+ }
+})
+
+// 鍥炶皟鍑芥暟
+const handleChange = (editor: IDomEditor) => {
+ emit('change', editor)
+}
+
+// 缁勪欢閿�姣佹椂锛屽強鏃堕攢姣佺紪杈戝櫒
+onBeforeUnmount(() => {
+ const editor = unref(editorRef.value)
+
+ // 閿�姣侊紝骞剁Щ闄� editor
+ editor?.destroy()
+})
+
+const getEditorRef = async (): Promise<IDomEditor> => {
+ await nextTick()
+ return unref(editorRef.value) as IDomEditor
+}
+
+defineExpose({
+ getEditorRef
+})
+</script>
+
+<template>
+ <div class="border-1 border-solid border-[var(--tags-view-border-color)] z-10">
+ <!-- 宸ュ叿鏍� -->
+ <Toolbar
+ :editor="editorRef"
+ :editorId="editorId"
+ class="border-0 b-b-1 border-solid border-[var(--tags-view-border-color)]"
+ />
+ <!-- 缂栬緫鍣� -->
+ <Editor
+ v-model="valueHtml"
+ :defaultConfig="editorConfig"
+ :editorId="editorId"
+ :style="editorStyle"
+ @on-change="handleChange"
+ @on-created="handleCreated"
+ />
+ </div>
+</template>
+
+<style src="@wangeditor-next/editor/dist/css/style.css"></style>
--
Gitblit v1.8.0