Browse Source

升级富文本编辑器版本

asd123a20 2 years ago
parent
commit
dce2824965

File diff suppressed because it is too large
+ 825 - 10
admin-content/package-lock.json


+ 1 - 0
admin-content/package.json

@@ -8,6 +8,7 @@
     "lint": "vue-cli-service lint"
   },
   "dependencies": {
+    "@wangeditor/editor": "^5.1.14",
     "core-js": "^3.6.5",
     "element-ui": "^2.15.6",
     "sass": "^1.48.0",

+ 6 - 0
admin-content/src/store/index.js

@@ -68,6 +68,12 @@ const mutations = {
   menusQuery(state, payload) {
     state.menusList = payload.data;
     state.dict.menus = payload.data.filter(e => e.type == 1);
+    // state.dict.menus = payload.data.filter(e => {
+    //   if (e.type == 1) {
+    //     const data = payload.data.filter(j => j.parentCode !== e.code);
+    //     if (data.length <= 0) return e;
+    //   }
+    // });
   },
   sourceQuery(state, payload) {
     state.dict.source = payload.data;

+ 3 - 2
admin-content/src/views/home.vue

@@ -63,7 +63,7 @@
 import filterList from '@components/filterList/index.vue';
 import dialogAndDrawer from '@components/dialogAndDrawer.vue';
 import formData from '@components/formData/index.vue';
-import editoritem from '@components/editoritem.vue';
+import editoritem from '@components/editoritem2.vue';
 import deepTree from '@components/deepTree.vue';
 import { mapState, mapActions } from 'vuex';
 const token = sessionStorage.getItem('token');
@@ -99,7 +99,7 @@ export default {
         { name: 'title', label: '标题' },
         { name: 'curtTitle', label: '副标题' },
         { name: 'source', label: '来源', formater: 'dict:source' },
-        // { name: 'describe', label: '描述' },
+        { name: 'author', label: '作者' },
         { name: 'bind', label: '绑定菜单', formater: 'dict:menus' },
         { name: 'date', label: '时间', formater: 'date:datetime' },
         { name: 'istop', label: '置顶', formater: 'slot' },
@@ -181,6 +181,7 @@ export default {
     },
     // 查询
     async filterQuery ({ filter = {}, paging = { page: 0, size: 10 } } = {}) {
+      this.page = paging.page;
       if (this.types !== null) filter.bind = this.types;
       await this.contentsQuery({ filter, paging });
     },

+ 116 - 0
admin-frame/lib/editorButtom2.js

@@ -0,0 +1,116 @@
+
+import { DomEditor } from '@wangeditor/editor';
+let targetDom = null;
+let editors = null;
+export default class MyMenu {
+  constructor() {
+    // super(editor);
+    this.title = '格式刷';
+    this.iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 384 512"><path d="M352 0H32C14.33 0 0 14.33 0 32v224h384V32c0-17.67-14.33-32-32-32zM0 320c0 35.35 28.66 64 64 64h64v64c0 35.35 28.66 64 64 64s64-28.65 64-64v-64h64c35.34 0 64-28.65 64-64v-32H0v32zm192 104c13.25 0 24 10.74 24 24c0 13.25-10.75 24-24 24s-24-10.75-24-24c0-13.26 10.75-24 24-24z" fill="currentColor"></path></svg>';
+    this.tag = 'button';
+    this._active = false;
+    const dom = document.getElementById('editor-container');
+    const _this = this;
+    dom.onclick = function () {
+      if (!_this._active) return;
+      // 深拷贝所有的json
+      let html = JSON.stringify(editors.children);
+      html = JSON.parse(html);
+      console.log(html);
+      // 当前获取的的值
+      const doms = DomEditor.getSelectedElems(editors);
+      if (doms[0]?.type == 'image' || doms[1]?.type == 'image') return false;
+      if (!targetDom) {
+        _this._active = false;
+        return;
+      }
+      // 循环赋值
+      for (let l = 0; l < html.length; l++) {
+        for (let i = 0; i < html[l].children.length; i++) {
+          let children = doms[0].children[0].text.replace(/\s+/g, '');
+          if (children == '') children = doms[0].children[1];
+          if (html[l].children[i].text == children.text) {
+            for (const key in targetDom) {
+              html[l].children[i][key] = targetDom[key];
+            }
+          }
+        }
+      }
+      const paste = pasteDom(html);
+      console.log(paste, 'paste');
+      console.log(editors.getHtml());
+      editors.setHtml(paste);
+    };
+  }
+
+  tryChangeActive() {}
+
+  getValue(editor) {
+    return editor;
+  }
+
+  isActive(editor) {
+    return false;
+  }
+
+  isDisabled(editor) {
+    return false; // or true
+  }
+
+  exec(editor, value) {
+    editors = editor;
+    this._active = !this._active;
+    if (!this._active) {
+      editor.copyStyleList = null;
+    } else {
+      // 获取格式刷样式
+      const node = DomEditor.getSelectedElems(editor);
+      // if (!node) return;
+      const containerEle = node[0];
+      const copyStyleList = parseDom(containerEle);
+      // // 保存格式刷样式
+      editor.copyStyleList = copyStyleList;
+    }
+  }
+}
+
+// 复制选中dom的样式
+function parseDom(dom) {
+  if (dom.children[0]?.type == 'image' || dom.children[1]?.type == 'image') return false;
+  getTargetDom(dom);
+  function getTargetDom(dom) {
+    let children = dom.children[0];
+    const item = children.text.replace(/\s+/g, '');
+    if (item == '') children = dom.children[1];
+    const childrens = { ...children };
+    delete childrens.text;
+    targetDom = childrens;
+  }
+}
+
+// 循环制造标签
+function pasteDom(dom) {
+  let list = '';
+  for (let l = 0; l < dom.length; l++) {
+    for (let i = 0; i < dom[l].children.length; i++) {
+      let style = '';
+      let text = '';
+      if (dom[l].children[i].type == 'image') {
+        for (const keyl in dom[l].children[i].style) {
+          style += `${keyl}:${dom[l].children[i].style[keyl]};`;
+        }
+      } else {
+        text = dom[l].children[i].text;
+        delete dom[l].children[i].text;
+        for (const key in dom[l].children[i]) {
+          let keys = key;
+          if (keys == 'fontSize') keys = 'font-size';
+          style += `${keys}:${dom[l].children[i][key]};`;
+        }
+      }
+      const labels = dom[l].children[i].type !== 'image' ? `<p><span style="${style}">${text}</span></p>` : `<p><img style="${style}" src="${dom[l].children[i]?.src}"></img></p>`;
+      list += labels;
+    }
+  }
+  return list;
+}

File diff suppressed because it is too large
+ 823 - 4
admin-frame/package-lock.json


+ 1 - 0
admin-frame/package.json

@@ -8,6 +8,7 @@
     "lint": "vue-cli-service lint"
   },
   "dependencies": {
+    "@wangeditor/editor": "^5.1.14",
     "axios": "^0.24.0",
     "core-js": "^3.6.5",
     "element-ui": "^2.15.6",

+ 6 - 0
admin-frame/src/components/editoritem.vue

@@ -95,4 +95,10 @@ button {
   background: none;
   border: none;
 }
+.editor {
+  p {
+    line-height: 2em;
+    font-size: 16px;
+  }
+}
 </style>

+ 67 - 86
admin-frame/src/components/editoritem2.vue

@@ -1,126 +1,107 @@
 <template lang="html">
   <div class="editor">
-    <div ref="toolbar" class="toolbar">
+    <div ref="toolbar" class="toolbar" id="toolbar-container">
     </div>
-    <div ref="editor" class="text">
+    <div ref="editor" class="text" id="editor-container">
     </div>
   </div>
 </template>
 
 <script>
-import E from 'wangeditor';
+// import E from 'wangeditor';
+import '@wangeditor/editor/dist/css/style.css';
+import { createEditor, createToolbar } from '@wangeditor/editor';
+import MyMenu from '@lib/editorButtom2.js';
 import $axios from '@lib/axios.js';
+// toolbar
+let editor;
 export default {
   name: 'editoritem',
   data () {
     return {
-      editor: null,
-      info_: null
+      info_: null,
+      myMenuConf: {
+        key: 'menu1',
+        factory() {
+          return new MyMenu();
+        }
+      },
+      editorConfig: {
+        MENU_CONF: {}
+      }
     };
   },
-  model: {
-    prop: 'value',
-    event: 'change'
-  },
   props: {
     value: {
       type: String,
       default: ''
-    },
-    isClear: {
-      type: Boolean,
-      default: false
-    }
-  },
-  watch: {
-    isClear (val) {
-      // 触发清除文本域内容
-      if (val) {
-        this.editor.txt.clear();
-        this.info_ = null;
-      }
-    },
-    value: function (value) {
-      if (value !== this.editor.txt.html()) {
-        this.editor.txt.html(this.value);
-      }
     }
-    // value为编辑框输入的内容,这里我监听了一下值,当父组件调用得时候,如果给value赋值了,子组件将会显示父组件赋给的值
   },
   mounted () {
     this.seteditor();
-    this.editor.txt.html(this.value);
   },
   methods: {
     seteditor () {
-      this.editor = new E(this.$refs.toolbar, this.$refs.editor);
-      this.editor.config.uploadImgShowBase64 = false; // base 64 存储图片
-      this.editor.config.uploadImgMaxSize = 50 * 1024 * 1024; // 将图片大小限制为 2M
-      this.editor.config.uploadImgMaxLength = 1; // 限制一次最多上传 3 张图片
-      this.editor.config.uploadImgTimeout = 3 * 60 * 1000; // 设置超时时间
-      this.editor.config.showLinkImg = false;
-      // 配置菜单
-      this.editor.config.menus = [
-        'head', // 标题
-        'bold', // 粗体
-        'fontSize', // 字号
-        'fontName', // 字体
-        'italic', // 斜体
-        'underline', // 下划线
-        'strikeThrough', // 删除线
-        'foreColor', // 文字颜色
-        'backColor', // 背景颜色
-        'link', // 插入链接
-        'list', // 列表
-        'justify', // 对齐方式
-        'quote', // 引用
-        'emoticon', // 表情
-        'image', // 插入图片
-        'table', // 表格
-        'video', // 插入视频
-        'code', // 插入代码
-        'undo', // 撤销
-        'redo', // 重复
-        'fullscreen' // 全屏
-      ];
-      // 自定义文件上传
-      this.editor.config.customUploadImg = async function (resultFiles, insertImgFn) {
-        // resultFiles 是 input 中选中的文件列表
-        var data = new FormData();
-        const filesUpload = '/api/files/filestore/upload';
-        data.append('file', resultFiles[0]);
-        const headers = {
-          'Content-Type': 'multipart/form-data'
-        };
-        const res = await $axios.post(filesUpload, data, null, headers);
-        // insertImgFn 是获取图片 url 后,插入到编辑器的方法
-        // const url = `http://127.0.0.1:9002${res.data.filePath}`;
-        const url = res.data.filePath;
-        // 上传图片,返回结果,将图片插入到编辑器中
-        insertImgFn(url);
-      };
-      // this.editor.config.onlineVideoCheck = (src) => {
-      //   const videoMod = `<iframe src="${src}"> </iframe>`;
-      //   // this.editor.txt.append(videoMod);
-      //   this.editor.cmd.do('insertHTML', videoMod);
+      // 解决重复key问题
+      // if (!editor) Boot.registerMenu(this.myMenuConf);
+      // 创建编辑器
+      editor = createEditor({
+        selector: '#editor-container',
+        config: {
+          onChange: (editor) => {
+            this.info_ = editor.getHtml(); // 绑定当前逐渐地值
+            this.$emit('change', this.info_); // 将内容同步到父组件中
+          },
+          MENU_CONF: {
+            uploadImage: {
+              async customUpload(file, insertFn) {
+                var data = new FormData();
+                const filesUpload = '/api/files/filestore/upload';
+                data.append('file', file);
+                const headers = {
+                  'Content-Type': 'multipart/form-data'
+                };
+                const res = await $axios.post(filesUpload, data, null, headers);
+                const url = res.data.filePath;
+                const alt = res.data.name;
+                const href = res.data.filePath;
+                // 上传图片,返回结果,将图片插入到编辑器中
+                insertFn(url, alt, href);
+              }
+            }
+          }
+        }
+      });
+      // 创建工具栏
+      createToolbar({
+        editor,
+        selector: '#toolbar-container'
+      });
+      // toolbar.config.insertKeys = {
+      //   index: 0,
+      //   keys: ['menu1']
       // };
-      this.editor.config.onchange = (html) => {
-        this.info_ = html; // 绑定当前逐渐地值
-        this.$emit('change', this.info_); // 将内容同步到父组件中
-      };
-      // 创建富文本编辑器
-      this.editor.create();
+      editor.setHtml((this.value));
     }
+  },
+  beforeDestroy() {
+    if (editor == null) return;
+    editor.destroy(); // 组件销毁时,及时销毁编辑器
   }
 };
 </script>
 
-<style lang="css">
+<style lang="scss">
   .editor {
     width: 100%;
     margin: 0 auto;
     position: relative;
     z-index: 0;
+    p {
+      line-height: 2em;
+      font-size: 16px;
+      text-align: justify;
+    }
   }
   .toolbar {
     border: 1px solid #ccc;

+ 3 - 0
admin-frame/src/components/filterList/index.vue

@@ -106,6 +106,9 @@ export default {
     resetPage(e) {
       this.$refs.pagination.resetPage(e);
     },
+    handleCurrentChange(e) {
+      this.$refs.pagination.handleCurrentChange(e);
+    },
     // 分页函数
     paginationsQuery(e) {
       this.paging = e;

+ 1 - 1
admin-page/src/views/home.vue

@@ -24,7 +24,7 @@
 import filterList from '@components/filterList/index.vue';
 import dialogAndDrawer from '@components/dialogAndDrawer.vue';
 import formData from '@components/formData/index.vue';
-import editoritem from '@components/editoritem.vue';
+import editoritem from '@components/editoritem2.vue';
 import { mapState, mapActions } from 'vuex';
 export default {
   components: {