Tinymce富文本编辑器二次开发电子病历时解决的bug

<template> <div :class="prefixCls" :style="{ width: containerWidth }"> <ImgUpload :fullscreen="fullscreen" @uploading="handleImageUploading" @done="handleDone" v-if="showImageUpload && !props.isHide" v-show="editorRef" :disabled="disabled" :uploadParams="props.uploadParams" /> <textarea :id="tinymceId" ref="elRef" :style="{ visibility: 'hidden' }" v-if="!initOptions.inline"></textarea> <slot v-else></slot> <signModal @register="signatureModal" @success="handleSignature" @exportSign="getSign" /> <recordModal @register="recorderModal" @success="handleGetText" /> </div> </template> <script lang="ts"> import sign from '/@/assets/svg/sign.svg'; import recordSvg from '/@/assets/svg/record.svg'; import type { Editor, RawEditorSettings, BodyComponentSpec } from 'tinymce'; import { useMessage } from '/@/hooks/web/useMessage'; import tinymce from 'tinymce/tinymce'; import 'tinymce/themes/silver'; import 'tinymce/icons/default/icons'; import 'tinymce/plugins/advlist'; import 'tinymce/plugins/anchor'; import 'tinymce/plugins/autolink'; import 'tinymce/plugins/autosave'; import 'tinymce/plugins/code'; import 'tinymce/plugins/codesample'; import 'tinymce/plugins/directionality'; import 'tinymce/plugins/fullscreen'; import 'tinymce/plugins/hr'; import 'tinymce/plugins/insertdatetime'; import 'tinymce/plugins/link'; import 'tinymce/plugins/lists'; import 'tinymce/plugins/media'; import 'tinymce/plugins/nonbreaking'; import 'tinymce/plugins/noneditable'; import 'tinymce/plugins/pagebreak'; import 'tinymce/plugins/paste'; import 'tinymce/plugins/preview'; import 'tinymce/plugins/print'; import 'tinymce/plugins/save'; import 'tinymce/plugins/searchreplace'; import 'tinymce/plugins/spellchecker'; import 'tinymce/plugins/tabfocus'; import 'tinymce/plugins/table'; import 'tinymce/plugins/template'; import 'tinymce/plugins/textpattern'; import 'tinymce/plugins/visualblocks'; import 'tinymce/plugins/visualchars'; import 'tinymce/plugins/wordcount'; // import '/@/components/MedicalTinymce/plugins/control/index.js'; import { defineComponent, computed, nextTick, ref, unref, watch, onDeactivated, onBeforeUnmount, toRaw } from 'vue'; import ImgUpload from './ImgUpload.vue'; import { toolbar, plugins } from './tinymce'; import { buildShortUUID } from '/@/utils/uuid'; import { bindHandlers } from './helper'; import { useModal } from '/@/components/Modal'; import { ActionEnum, VALIDATE_API } from '/@/enums/commonEnum'; import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated'; import { useDesign } from '/@/hooks/web/useDesign'; import { isNumber } from '/@/utils/is'; import { useLocale } from '/@/locales/useLocale'; import { useAppStore } from '/@/store/modules/app'; import { asyncFindDefUrlById, asyncFindUrlById } from '/@/api/lamp/file/upload'; import signModal from '/@/components/Signature/components/signModal/index.vue'; import recordModal from '/@/components/CustomRecorder/index.vue'; const tinymceProps = { options: { type: Object as PropType<Partial<RawEditorSettings>>, default: () => ({}), }, value: { type: String, }, toolbar: { type: Array as PropType<string[]>, default: toolbar, }, plugins: { type: Array as PropType<string[]>, default: plugins, }, modelValue: { type: String, }, height: { type: [Number, String] as PropType<string | number>, required: false, default: 400, }, width: { type: [Number, String] as PropType<string | number>, required: false, default: 'auto', }, showImageUpload: { type: Boolean, default: true, }, isDef: { type: Boolean, default: false, }, uploadParams: { type: Object as PropType<any>, default: {}, }, isHide: { type: Boolean, default: false, }, isPrint: { type: Boolean, default: false, }, templatevalue: { type: Array, }, getParams: { type: Boolean, default: false, }, }; export default defineComponent({ name: 'Tinymce', components: { ImgUpload, signModal, recordModal }, inheritAttrs: false, props: tinymceProps, emits: ['change', 'update:modelValue', 'inited', 'init-error', 'templateparams'], setup(props, { emit, attrs }) { const { createMessage } = useMessage(); const editorRef = ref<Nullable<Editor>>(null); const fullscreen = ref(false); const tinymceId = ref<string>(buildShortUUID('tiny-vue')); const elRef = ref<Nullable<HTMLElement>>(null); let dialogConfig = ref(null); const { prefixCls } = useDesign('tinymce-container'); const [signatureModal, { openModal: openSignModal }] = useModal(); const [recorderModal, { openModal: openRecord }] = useModal(); const appStore = useAppStore(); const appEnv = import.meta.env.MODE; let currentBookMark = ref<any>(''); const tinymceContent = computed(() => props.modelValue); const childBtn = { type: 'grid', // component type columns: 1, // number of columns items: [ { type: 'button', name: 'add', text: '添加子项', }, { type: 'button', name: 'del', text: '删除子项', }, { type: 'collection', // component type name: 'collection', // identifier label: '', }, { type: 'collection', // component type name: 'collection1', // identifier label: '', }, ], // array of panel components }; let childItem = { type: 'grid', // component type columns: 1, // number of columns items: [ { type: 'grid', columns: 2, items: [ { type: 'input', name: 'label1', label: '标签1', }, { type: 'input', name: 'value1', label: '值1', }, ], }, ], // array of panel components }; const containerWidth = computed(() => { const width = props.width; if (isNumber(width)) { return `${width}px`; } return width; }); const skinName = computed(() => { return appStore.getDarkMode === 'light' ? 'oxide' : 'oxide-dark'; }); const langName = computed(() => { const lang = useLocale().getLocale.value; return ['zh_CN', 'en'].includes(lang) ? lang : 'zh_CN'; }); const initOptions = computed((): RawEditorSettings => { const { height, options, toolbar, plugins } = props; const publicPath = import.meta.env.VITE_PUBLIC_PATH || '/'; return { selector: `#${unref(tinymceId)}`, height, // toolbar: appEnv === 'development' ? [...toolbar, 'HtmlBtn'] : toolbar, toolbar: !!props.isHide ? false : !!props.isPrint ? false : toolbar, menubar: !!props.isHide ? false : !!props.isPrint ? 'print' : 'file edit insert view format table', menu: { print: { title: '打印', items: 'print', }, }, plugins, fontsize_formats: '8pt 10pt 12pt 14pt 16pt 18pt 20pt 22pt 24pt 36pt', font_formats: `微软雅黑='微软雅黑';宋体='宋体';黑体='黑体';仿宋='仿宋';楷体='楷体';隶书='隶书';幼圆='幼圆'; Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde; Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new, courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma, arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings`, language_url: publicPath + 'resource/tinymce/langs/' + langName.value + '.js', language: langName.value, branding: false, default_link_target: '_blank', link_title: false, object_resizing: false, auto_focus: true, skin: skinName.value, skin_url: publicPath + 'resource/tinymce/skins/ui/' + skinName.value, content_css: publicPath + 'resource/tinymce/skins/ui/' + skinName.value + '/content.min.css', ...options, extended_valid_elements: 'a[class|target|href|onclick],div[class|onclick|id|style],link[rel|href]', setup: (editor: Editor) => { console.log(editor, 'editoreditoreditoreditoreditor'); editorRef.value = editor; editor.on('init', (e) => initSetup(e)); // 注册一个icon editor.ui.registry.addIcon( 'shopping-cart', `<svg viewBox="0 0 1024 1024" data-icon="shopping-cart" width="1.5em" height="1.5em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M922.9 701.9H327.4l29.9-60.9 496.8-.9c16.8 0 31.2-12 34.2-28.6l68.8-385.1c1.8-10.1-.9-20.5-7.5-28.4a34.99 34.99 0 0 0-26.6-12.5l-632-2.1-5.4-25.4c-3.4-16.2-18-28-34.6-28H96.5a35.3 35.3 0 1 0 0 70.6h125.9L246 312.8l58.1 281.3-74.8 122.1a34.96 34.96 0 0 0-3 36.8c6 11.9 18.1 19.4 31.5 19.4h62.8a102.43 102.43 0 0 0-20.6 61.7c0 56.6 46 102.6 102.6 102.6s102.6-46 102.6-102.6c0-22.3-7.4-44-20.6-61.7h161.1a102.43 102.43 0 0 0-20.6 61.7c0 56.6 46 102.6 102.6 102.6s102.6-46 102.6-102.6c0-22.3-7.4-44-20.6-61.7H923c19.4 0 35.3-15.8 35.3-35.3a35.42 35.42 0 0 0-35.4-35.2zM305.7 253l575.8 1.9-56.4 315.8-452.3.8L305.7 253zm96.9 612.7c-17.4 0-31.6-14.2-31.6-31.6 0-17.4 14.2-31.6 31.6-31.6s31.6 14.2 31.6 31.6a31.6 31.6 0 0 1-31.6 31.6zm325.1 0c-17.4 0-31.6-14.2-31.6-31.6 0-17.4 14.2-31.6 31.6-31.6s31.6 14.2 31.6 31.6a31.6 31.6 0 0 1-31.6 31.6z"></path></svg>`, ); // 注册获取html以及数据的按钮 registerSignBtn(editor); }, // 生命周期:挂载后回调 init_instance_callback: (editor: Editor) => { // 修改编辑器默认字体和字号 editor.getBody().style.fontSize = '16pt'; editor.getBody().style.fontFamily = '宋体'; }, }; }); // 注册获取html以及数据的按钮 function registerSignBtn(editor: Editor) { editor.ui.registry.addButton('CardBtn', { type: 'button', // icon: `shopping-cart`, text: '获取并保存html', onAction: function (_) { //按钮事件:组装 html + data数据 getControlValue(); saveTemplate(editor.getContent(), getControlValue()); }, }); } // 获取控件数据值 function getControlValue() { let dom = tinymce.activeEditor.dom; let controls = dom.select('.control'); let data = controls.map((item) => { // console.log('item', item); let dataControl = JSON.parse(item.getAttribute('data-control')); let controlValue = item.getAttribute('data-value'); //文本框 没有data-value console.log(controlValue, item.firstElementChild.innerHTML, 'item.firstElementChild.innerHTML'); if (!controlValue) { if (dataControl.initialData.select == 'input') { if (!!item.firstElementChild.innerHTML) { controlValue = item.firstElementChild.innerHTML; } else { controlValue = ''; } } // controlValue = item.firstElementChild.innerHTML; } return { controlType: dataControl.initialData.select, fieldName: dataControl.initialData.name, fieldKey: dataControl.initialData.fieldKey, controlValue, }; }); console.log(data); return data; } // 保存模板 async function saveTemplate(doc: string, data: any) { try { const params: any = { doc, data }; emit('templateparams', params); } finally { } } const disabled = computed(() => { const { options } = props; const getdDisabled = options && Reflect.get(options, 'readonly'); const editor =
上一篇:Leetcode-894-所有可能的真二叉树-c++


下一篇:HarmonyOS NEXT应用开发之ForEach:循环渲染