Browse Source

tinymce优化

JEECG 7 months ago
parent
commit
39ca47d2ef

+ 28 - 2
jeecgboot-vue3/src/components/Tinymce/src/Editor.vue

@@ -5,6 +5,7 @@
       <ImgUpload
         :fullscreen="fullscreen"
         @uploading="handleImageUploading"
+        @loading="handleLoading"
         @done="handleDone"
         v-show="editorRef"
         :disabled="disabled"
@@ -13,6 +14,7 @@
     <!-- update-end--author:liaozhiyang---date:20240517---for:【TV360X-35】富文本,图片上传遮挡其他按钮 -->
     <Editor :id="tinymceId" ref="elRef" :disabled="disabled" :init="initOptions" :style="{ visibility: 'hidden' }" v-if="!initOptions.inline"></Editor>
     <slot v-else></slot>
+    <ProcessMask ref="processMaskRef" :show="showUploadMask"/>
   </div>
 </template>
 
@@ -33,6 +35,7 @@
   import 'tinymce/plugins/image';
   import { defineComponent, computed, nextTick, ref, unref, watch, onDeactivated, onBeforeUnmount, onMounted } from 'vue';
   import ImgUpload from './ImgUpload.vue';
+  import ProcessMask from './ProcessMask.vue';
   import {simpleToolbar, menubar, simplePlugins} from './tinymce';
   import { buildShortUUID } from '/@/utils/uuid';
   import { bindHandlers } from './helper';
@@ -82,6 +85,10 @@
       type: Boolean,
       default: true,
     },
+    showUploadMask: {
+      type: Boolean,
+      default: false,
+    },
     //是否聚焦
     autoFocus:{
       type: Boolean,
@@ -91,9 +98,9 @@
 
   export default defineComponent({
     name: 'Tinymce',
-    components: { ImgUpload,Editor },
+    components: { ImgUpload,Editor,ProcessMask },
     inheritAttrs: false,
-    props: tinymceProps,
+    props: tinymceProps as any,
     emits: ['change', 'update:modelValue', 'inited', 'init-error'],
     setup(props, { emit, attrs }) {
       console.log("---Tinymce---初始化---")
@@ -103,6 +110,7 @@
       const tinymceId = ref<string>(buildShortUUID('tiny-vue'));
       const elRef = ref<Nullable<HTMLElement>>(null);
       const editorRootRef = ref<Nullable<HTMLElement>>(null);
+      const processMaskRef = ref<any>(null);
       const imgUploadShow = ref(false);
       const targetElem = ref<null | HTMLDivElement>(null);
 
@@ -325,6 +333,20 @@
         setValue(editor, val);
       }
 
+      /**
+       * 上传进度计算
+       * @param file
+       * @param fileList
+       */
+      function handleLoading(fileLength,showMask){
+        if(fileLength && fileLength > 0){
+          setTimeout(() => {
+              props?.showUploadMask && processMaskRef.value.calcProcess(fileLength)
+          },100)
+        }else{
+           props?.showUploadMask && (processMaskRef.value.showMask = showMask);
+        }
+      }
       function getUploadingImgName(name: string) {
         return `[uploading:${name}]`;
       }
@@ -397,6 +419,9 @@
         editorRootRef,
         imgUploadShow,
         targetElem,
+
+        handleLoading,
+        processMaskRef
       };
     },
   });
@@ -428,6 +453,7 @@
     }
     // update-end--author:liaozhiyang---date:20240527---for:【TV360X-329】富文本禁用状态下工具栏划过边框丢失
   }
+
   html[data-theme='dark'] {
     .@{prefix-cls} {
       .tox .tox-edit-area__iframe {background-color: #141414;}

+ 26 - 22
jeecgboot-vue3/src/components/Tinymce/src/ImgUpload.vue

@@ -8,6 +8,7 @@
       :showUploadList="false"
       :data="getBizData()"
       :headers="getheader()"
+      :before-upload="beforeUpload"
       accept=".jpg,.jpeg,.gif,.png,.webp"
     >
       <a-button type="primary" v-bind="{ ...getButtonProps }">
@@ -37,10 +38,8 @@
         default: false,
       },
     },
-    emits: ['uploading', 'done', 'error'],
+    emits: ['uploading', 'done', 'error', 'loading'],
     setup(props, { emit }) {
-      let uploading = false;
-
       //update-begin-author:taoyan date:2022-5-13 for: 富文本上传图片不支持
       function getheader() {
         return getHeaders();
@@ -67,33 +66,37 @@
         };
       });
 
+      let uploadLength = 0;
       function handleChange({ file, fileList }) {
-        if (file.status === 'error') {
-          emit('error');
-          uploading = false;
+        // 过滤掉已经存在的文件
+        fileList = fileList.filter((file) => {
+          const existFile = uploadFileList.value.find(({ uid }) => uid === file.uid);
+          return existFile ? false : true;
+        });
+        uploadLength == 0 && (uploadLength = fileList.length);
+        if (file.status != 'uploading') {
+          emit('loading', uploadLength, true);
         }
-        let files = [] as any;
-        let noUploadingFileCount = 0;
+        // 处理上传好的文件
         if (file.status != 'uploading') {
           fileList.forEach((file) => {
             if (file.status === 'done' && file.response.success) {
-              files.push(file);
-            }
-            if (file.status != 'uploading') {
-              noUploadingFileCount++;
+              const name = file?.name;
+              let realUrl = getFileAccessHttpUrl(file.response.message);
+              uploadFileList.value.push(file);
+              emit('done', name, realUrl);
             }
           });
         }
-
-        if (noUploadingFileCount == fileList.length) {
-          fileList.forEach((file) => {
-            const name = file?.name;
-            let realUrl = getFileAccessHttpUrl(file.response.message);
-            emit('done', name, realUrl);
-          });
-        }
       }
-
+      //上传之前
+      function beforeUpload() {
+        uploadLength = 0;
+        emit('loading', null, true);
+        setTimeout(() => {
+          emit('loading', null, false);
+        }, 10000);
+      }
       return {
         prefixCls,
         handleChange,
@@ -102,7 +105,8 @@
         getBizData,
         t,
         getButtonProps,
-        uploadFileList
+        uploadFileList,
+        beforeUpload,
       };
     },
   });

+ 99 - 0
jeecgboot-vue3/src/components/Tinymce/src/ProcessMask.vue

@@ -0,0 +1,99 @@
+<template>
+  <div class="mask" v-if="showMask && show">
+    <div class="progress-bar-rear">
+      <div class="progress-bar-front" :style="{ width: progressBarWidth }"></div>
+    </div>
+    <div class="value">{{ percentage }}</div>
+  </div>
+</template>
+<script lang="ts" setup>
+  import { computed, ref } from 'vue';
+
+  const props = defineProps({
+    backColor: {
+      type: [String],
+      default: 'white',
+    },
+    processColor: {
+      type: String,
+      default: '#018FFB',
+    },
+    show: {
+      type: Boolean,
+      default: false,
+    },
+  });
+  //显示遮罩
+  const showMask = ref(false);
+  //进度值占比
+  const progressValue = ref<any>(0);
+  //当前数量
+  const currentNum = ref(0);
+  // 计算进度条宽度的计算属性
+  const progressBarWidth = computed(() => {
+    return progressValue.value > 0 ? `${progressValue.value}px` : '0px';
+  });
+  // 计算进度条百分比
+  const percentage = computed(() => {
+    return `${progressValue.value}%`;
+  });
+  // 进度色
+  const frontColor = computed(() => {
+    return props.processColor;
+  });
+  // 后置背景色
+  const rearColor = computed(() => {
+    return props.backColor;
+  });
+  function calcProcess(totalNum) {
+    !showMask.value && (showMask.value = true);
+    currentNum.value += 1;
+    progressValue.value = ((currentNum.value / totalNum) * 100).toFixed(2);
+    console.log('currentNum.value', currentNum.value);
+    console.log('totalNum.value', totalNum);
+    if (currentNum.value == totalNum) {
+      showMask.value = false;
+      currentNum.value = 0;
+      progressValue.value = 0;
+    }
+  }
+  defineExpose({
+    calcProcess,
+    showMask,
+  });
+</script>
+
+<style lang="less">
+  .mask {
+    position: absolute; /* 或者使用固定定位等其他方式 */
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background-color: rgba(0, 0, 0, 0.5); /* 半透明遮罩 */
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    overflow: hidden;
+    z-index: 99;
+  }
+
+  .progress-bar-rear {
+    width: 100px; /* 进度条宽度 */
+    height: 10px; /* 进度条高度 */
+    background-color: v-bind(rearColor); /* 进度条颜色 */
+    border-radius: 4px;
+  }
+
+  .progress-bar-front {
+    height: 10px; /* 进度条高度 */
+    background-color: v-bind(frontColor); /* 进度条颜色 */
+    border-radius: 4px;
+  }
+  .value {
+    color: #fff;
+    margin-left: 5px;
+    font-size: 16px;
+    font-weight: 600;
+  }
+</style>