From a9a03d64cf190188d3db04d14970fc0908b03491 Mon Sep 17 00:00:00 2001 From: huangyinfeng <1244041895@qq.com> Date: 星期五, 27 九月 2024 09:02:26 +0800 Subject: [PATCH] 部分功能 --- src/components/Tinymce/src/index.vue | 245 +++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 229 insertions(+), 16 deletions(-) diff --git a/src/components/Tinymce/src/index.vue b/src/components/Tinymce/src/index.vue index f8ed625..a2b2246 100644 --- a/src/components/Tinymce/src/index.vue +++ b/src/components/Tinymce/src/index.vue @@ -2,16 +2,72 @@ <div :class="prefixCls" :style="{ width: containerWidth }"> <textarea :id="tinymceId" - ref="elRef" + ref="elPwRef" :style="{ visibility: 'hidden' }" v-if="!initOptions.inline" ></textarea> <slot v-else></slot> + <!-- <div class="p-2 tox-statusbar"> + <a-upload + v-if="isElse" + v-model:file-list="fileListTemp" + action="https://www.mocky.io/v2/5cc8019d300000980a055e76" + list-type="picture" + class="upload-list-inline" + > + <a-button type="text" size="small" style="margin: 0 auto"> + <upload-outlined></upload-outlined> + 闄勪欢 + </a-button> + <template #iconRender><PaperClipOutlined /></template> + <template #itemRender="{ file, fileList, actions }"> + <a-space class="ant-upload-list-picture-card"> + <span style="display: flex; flex-wrap: wrap"> + <PaperClipOutlined style="margin-right: 4px" /> + <span v-if="!file.editor" :style="file.status === 'error' ? 'color: red' : ''">{{ + file.name + }}</span> + <span v-else> + <a-input size="small" v-model:value="file.tempName"></a-input> + </span> + </span> + <span v-if="!file.editor"> + <a href="javascript:;" @click="actions.preview">棰勮</a> + <a href="javascript:;" @click="fnRename(file, fileList)">閲嶅懡鍚�</a> + <a href="javascript:;" @click="actions.remove">鍒犻櫎</a> + </span> + <span v-else> + <a href="javascript:;" @click="fnSaveRename(file, fileList)">淇濆瓨</a> + <a href="javascript:;" @click="fnOffRename(file, fileList)">鍙栨秷</a> + </span> + </a-space> + </template> + </a-upload> + <div :class="fileListTemp.length > 0 ? 'my-upload-list' : ''"> + <div style="display: flex"> + <ImgUpload + :fullscreen="fullscreen" + @uploading="handleImageUploading" + @done="handleDone" + v-if="isImg" + v-show="editorRef" + :title="'鍥剧墖'" + :disabled="disabled" + :accept="'.jpg,.jpeg,.gif,.png,.webp'" + /> + <a-button v-if="isText" type="text" size="small"> + <SnippetsOutlined /> + 蹇�熸枃鏈�</a-button + > + </div> + </div> + </div> --> </div> </template> <script lang="ts" setup> import type { Editor, RawEditorSettings } from 'tinymce'; + import { PaperClipOutlined, UploadOutlined, SnippetsOutlined } from '@ant-design/icons-vue'; import tinymce from 'tinymce/tinymce'; import 'tinymce/themes/silver'; import 'tinymce/icons/default/icons'; @@ -48,7 +104,7 @@ import 'tinymce/plugins/image'; import 'tinymce/plugins/table'; import 'tinymce/plugins/charmap'; - import 'tinymce/plugins/imagetools'; + // import 'tinymce/plugins/imagetools'; import 'tinymce/plugins/help'; import 'tinymce/plugins/emoticons'; import 'tinymce/plugins/emoticons/js/emojis'; @@ -64,7 +120,7 @@ // import 'tinymce/plugins/tinyddrive'; // import 'tinymce/plugins/advcode'; // import 'tinymce/plugins/mediaembed'; - import 'tinymce/plugins/toc'; + // import 'tinymce/plugins/toc'; // import 'tinymce/plugins/checklist'; // import 'tinymce/plugins/tinycespellchecker'; // import 'tinymce/plugins/a11ychecker'; @@ -88,12 +144,14 @@ PropType, useAttrs, } from 'vue'; + import ImgUpload from './ImgUpload.vue'; import { plugins as defaultPlugins, toolbar as defaultToolbar, toolbar_groups as defaultStyleFormats, } from './tinymce'; import { buildShortUUID } from '@/utils/uuid'; + import { bindHandlers } from './helper'; import { onMountedOrActivated } from '@vben/hooks'; import { useDesign } from '@/hooks/web/useDesign'; import { isNumber } from '@/utils/is'; @@ -129,7 +187,7 @@ height: { type: [Number, String] as PropType<string | number>, required: false, - default: 200, + default: 400, }, width: { type: [Number, String] as PropType<string | number>, @@ -143,15 +201,27 @@ fontsize: { type: String, }, + isElse: { + type: Boolean, + default: true, + }, + isText: { + type: Boolean, + default: true, + }, + isImg: { + type: Boolean, + default: true, + }, }); -console.log('Editor', props); const emit = defineEmits(['change', 'update:modelValue', 'inited', 'init-error']); const attrs = useAttrs(); const editorRef = ref<Editor | null>(null); - const tinymceId = ref<string>(buildShortUUID('tiny-vue')); - const elRef = ref<HTMLElement | null>(null); + const fullscreen = ref(false); + const tinymceId = ref<string>(buildShortUUID('tiny-vue-pw')); + const elPwRef = ref<HTMLElement | null>(null); const { prefixCls } = useDesign('tinymce-container'); @@ -187,13 +257,10 @@ fontsize_formats: '10px 11px 12px 14px 16px 18px 24px 36px 48px 48px 56px 72px', image_advtab: true, importcss_append: true, // 鍏佽鏍峰紡鐢熸晥 - toolbar:[], - toolbar_sticky: true, // 绮樻�у伐鍏锋爮锛堟垨鍋滈潬宸ュ叿鏍忥級锛屽湪鍚戜笅婊氬姩缃戦〉鐩村埌涓嶅啀鍙缂栬緫鍣ㄦ椂锛屽皢宸ュ叿鏍忓拰鑿滃崟鍋滈潬鍦ㄥ睆骞曢《閮� - toolbar_mode: 'floating', //榛樿wrap涓嶆敹缂╁伐鍏锋爮锛屽彇鍊间负floating鎴杝liding鏃讹紝灏嗙涓�琛屾斁涓嶄笅鐨勫伐鍏锋爮鎸夐挳缂╄繘鎶藉眽锛�3涓偣鐨勫浘鏍囷級閲岋紝scrolling鍒欓噰鐢ㄧЩ鍔ㄧ鐨勬í绾挎粴鍔ㄦ柟寮忋�� - // style_formats_autohide: true, menubar: false, branding: false, elementpath: false, + toolbar: [], // quickbars_selection_toolbar: 'bold italic | quicklink h2 h3 blockquote quickimage quicktable', plugins, language_url: publicPath + 'resource/tinymce/langs/' + langName.value + '.js', @@ -209,12 +276,22 @@ skin_url: publicPath + 'resource/tinymce/skins/ui/' + skinName.value, content_css: publicPath + 'resource/tinymce/skins/ui/' + skinName.value + '/content.min.css', ...options, + readonly: true, setup: (editor: Editor) => { editorRef.value = editor; + editor.on('init', (e) => initSetup(e)); }, - // 鍙妯″紡 - readonly: true, }; + }); + + const disabled = computed(() => { + const { options } = props; + const getdDisabled = options && Reflect.get(options, 'readonly'); + const editor = unref(editorRef); + if (editor) { + editor.setMode(getdDisabled ? 'readonly' : 'design'); + } + return getdDisabled ?? false; }); watch( @@ -254,7 +331,7 @@ } function initEditor() { - const el = unref(elRef); + const el = unref(elPwRef); if (el) { el.style.visibility = ''; } @@ -268,7 +345,22 @@ }); } - function setValue(editor: Record<string, any>, val?: string, prevVal?: string) { + function initSetup(e) { + const editor = unref(editorRef); + if (!editor) { + return; + } + const value = props.modelValue || ''; + + editor.setContent(value); + bindModelHandlers(editor); + bindHandlers(e, attrs, unref(editorRef)); + } + + function setValue(editor: Record<string, any>, val?: string, prevVal?: string) { + if (!val) { + editor.setContent(''); + } if ( editor && typeof val === 'string' && @@ -277,8 +369,121 @@ ) { editor.setContent(val); } + } - + + function bindModelHandlers(editor: any) { + const modelEvents = attrs.modelEvents ? attrs.modelEvents : null; + const normalizedEvents = Array.isArray(modelEvents) ? modelEvents.join(' ') : modelEvents; + + watch( + () => props.modelValue, + (val, prevVal) => { + if(val){ + setValue(editor, val, prevVal); + } + }, + ); + + watch( + () => props.value, + (val, prevVal) => { + setValue(editor, val, prevVal); + }, + { + immediate: true, + }, + ); + + editor.on(normalizedEvents ? normalizedEvents : 'change keyup undo redo', () => { + const content = editor.getContent({ format: attrs.outputFormat }); + emit('update:modelValue', content); + const data = { + content, + fileUNID: fileListTemp.value, + }; + emit('change', data); + }); + + editor.on('FullscreenStateChanged', (e) => { + fullscreen.value = e.state; + }); + } + + function handleImageUploading(name: string) { + const editor = unref(editorRef); + if (!editor) { + return; + } + editor.execCommand('mceInsertContent', false, getUploadingImgName(name)); + const content = editor?.getContent() ?? ''; + setValue(editor, content); + } + + function handleDone(name: string, url: string) { + const editor = unref(editorRef); + if (!editor) { + return; + } + const content = editor?.getContent() ?? ''; + const val = content?.replace(getUploadingImgName(name), `<img src="${url}"/>`) ?? ''; + setValue(editor, val); + } + + function getUploadingImgName(name: string) { + return `[uploading:${name}]`; + } + + // 闄勪欢 + const fileListTemp = ref<UploadProps['fileList']>([ + // { + // uid: '-1', + // name: 'xxx.png', + // tempName: 'xxx', + // status: 'done', + // url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', + // thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', + // editor: false, + // }, + // { + // uid: '-2', + // name: 'yyy.png', + // tempName: 'yyy', + // status: 'done', + // url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', + // thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', + // editor: false, + // }, + ]); + function fnRename(file, fileList) { + console.log(file, fileList); + fileListTemp.value = fileList.map((item) => { + // item.tempName = item.name.split('.').slice(0,-1) + if (file.uid == item.uid) { + item.editor = true; + } else { + item.editor = false; + } + return item; + }); + } + function fnSaveRename(file, fileList) { + fileListTemp.value = fileList.map((item) => { + if (file.uid == item.uid) { + item.name = item.tempName; + item.editor = false; + } + return item; + }); + } + function fnOffRename(file, fileList) { + fileListTemp.value = fileList.map((item) => { + if (file.uid == item.uid) { + item.editor = false; + } + return item; + }); + } </script> <style lang="less" scope> @prefix-cls: ~'@{namespace}-tinymce-container'; @@ -293,9 +498,17 @@ } } + .my-upload-list { + // 杩囨浮 + position: absolute; + left: 78px; + transition: all 0.3s; + } + .tox-statusbar { display: flex; // position: absolute; + min-height: 40px; border-bottom-right-radius: 8px; border-bottom-left-radius: 8px; background: #f0f2f5; -- Gitblit v1.8.0