Pārlūkot izejas kodu

编辑器增加上传附件功能

编辑器增加上传附件功能
dangyunlong 1 nedēļu atpakaļ
vecāks
revīzija
0a23d2ae64
2 mainītis faili ar 295 papildinājumiem un 129 dzēšanām
  1. 293 127
      src/components/edit/myEditor.vue
  2. 2 2
      src/utils/baseUrl.js

+ 293 - 127
src/components/edit/myEditor.vue

@@ -1,149 +1,315 @@
 <template>
     <tiny-editor v-model="content" :init="init" :key="componentKey" id="textarea"></tiny-editor>
-  </template>
-  
-  <script>
-  import editor from '@tinymce/tinymce-vue';
-  import url from '@/utils/baseUrl';
-  
-  export default {
+</template>
+
+<script>
+import editor from '@tinymce/tinymce-vue';
+import url from '@/utils/baseUrl';
+
+export default {
     name: 'myEditor',
     props: {
-      value: {
-        type: String,
-        default: ''
-      }
+        value: {
+            type: String,
+            default: ''
+        }
     },
     data() {
-      return {
-        componentKey: 0,
-        content: '',
-        init: {
-          selector: '#textarea',
-          height: 550,
-          language_url: 'js/tinymce/langs/zh_CN.js',
-          language: 'zh_CN',
-          plugins: 'paste image axupimgs code lists advlist table anchor autosave charmap fullscreen hr insertdatetime link preview print searchreplace wordcount indent2em',
-          toolbar: [
-            "undo redo |  styleselect | fontselect | fontsizeselect | bold italic underline strikethrough subscript superscript charmap | indent2em | alignleft aligncenter alignright alignjustify | lineheight | outdent indent",
-            "forecolor backcolor | link | removeformat | image axupimgs | table | searchreplace cut copy paste | hr blockquote anchor | bullist numlist | insertdatetime |  restoredraft | code | fullscreen preview print wordcount"
-          ],
-          font_formats: '微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;宋体=simsun,serif',
-          fontsize_formats: '12px 14px 16px 18px 20px 22px 24px 28px 32px 36px 42px 48px',
-          branding: false,
-          paste_data_images: true,
-          paste_postprocess: (editor, args) => {
-            const images = args.node.querySelectorAll('img[src^="data:image/"]');
-            if (images.length > 0) {
-              Array.from(images).forEach((img) => {
-                const blob = this.dataURLtoBlob(img.src);
-                this.uploadImageFromBlob(blob, 
-                  (imageUrl) => {
-                    editor.dom.setAttrib(img, 'src', imageUrl);
-                    editor.dom.setAttrib(img, 'alt', '粘贴的图片');
-                  },
-                  (error) => {
-                    console.error('图片上传失败:', error);
-                    editor.dom.remove(img);
-                  }
-                );
-              });
+        return {
+            componentKey: 0,
+            content: '',
+            init: {
+                selector: '#textarea',
+                height: 550,
+                language_url: 'js/tinymce/langs/zh_CN.js',
+                language: 'zh_CN',
+                plugins: 'paste link image axupimgs code lists advlist table anchor autosave charmap fullscreen hr insertdatetime link preview print searchreplace wordcount indent2em',
+                toolbar: [
+                    "undo redo |  styleselect | fontselect | fontsizeselect | bold italic underline strikethrough subscript superscript charmap | indent2em | alignleft aligncenter alignright alignjustify | lineheight | outdent indent",
+                    "forecolor backcolor | link | removeformat | image axupimgs | table | searchreplace cut copy paste | hr blockquote anchor | bullist numlist | insertdatetime |  restoredraft | code | fullscreen preview print wordcount"
+                ],
+                font_formats: '微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;宋体=simsun,serif',
+                fontsize_formats: '12px 14px 16px 18px 20px 22px 24px 28px 32px 36px 42px 48px',
+                branding: false,
+                paste_data_images: true,
+                paste_postprocess: (editor, args) => {
+                    const images = args.node.querySelectorAll('img[src^="data:image/"]');
+                    if (images.length > 0) {
+                        Array.from(images).forEach((img) => {
+                            const blob = this.dataURLtoBlob(img.src);
+                            this.uploadImageFromBlob(blob,
+                                (imageUrl) => {
+                                    editor.dom.setAttrib(img, 'src', imageUrl);
+                                    editor.dom.setAttrib(img, 'alt', '粘贴的图片');
+                                },
+                                (error) => {
+                                    console.error('图片上传失败:', error);
+                                    editor.dom.remove(img);
+                                }
+                            );
+                        });
+                    }
+                },
+                images_upload_handler: (blobInfo, success, failure) => {
+                    const xhr = new XMLHttpRequest();
+                    xhr.withCredentials = false;
+                    xhr.open('POST', url.baseUrl + '/public/uploadFile');
+                    xhr.onload = () => {
+                        if (xhr.status < 200 || xhr.status >= 300) {
+                            failure('HTTP Error: ' + xhr.status);
+                            return;
+                        }
+                        const json = JSON.parse(xhr.responseText);
+                        if (json.code != 200) {
+                            failure('图片上传失败! ' + json.message);
+                            return;
+                        }
+                        success(json.data.imgUrl);
+
+                        const editor = tinymce.activeEditor;
+                        const nodeChangeHandler = (e) => {
+                            const imgElm = e.element;
+                            if (imgElm.nodeName === 'IMG' && imgElm.src === json.data.imgUrl) {
+                                editor.dom.setAttrib(imgElm, 'alt', json.data.oldName || '全国政务信息一体化应用平台');
+                                editor.off('NodeChange', nodeChangeHandler);
+                            }
+                        };
+                        editor.on('NodeChange', nodeChangeHandler);
+                    };
+                    const formData = new FormData();
+                    formData.append('file', blobInfo.blob());
+                    xhr.send(formData);
+                },
+                //上传文件
+                file_picker_callback: (cb, value, meta) => {
+                    console.log(this);
+                    const input = document.createElement('input');
+                    input.setAttribute('type', 'file');
+                    // 设置允许的文件格式
+                    input.setAttribute('accept', '.pdf,.doc,.docx,.jpg,.jpeg,.png,.gif,.zip,.rar,.mp3,.mp4,.ppt,.xls');
+                    
+                    input.addEventListener('change', (e) => {
+                        const file = e.target.files[0];
+                        if (!file) return;
+                        // 检查文件格式
+                        const allowedExtensions = ['.pdf', '.doc', '.docx','.png', '.jpg', '.jpeg', '.gif', '.mp3','.mp4', '.zip', '.rar', '.ppt','.xls'];
+                        const fileName = file.name.toLowerCase();
+                        const fileExtension = fileName.substring(fileName.lastIndexOf('.')).toLowerCase();
+                        const isValidFile = allowedExtensions.includes(fileExtension);
+                        
+                        if (!isValidFile) {
+                            this.$message({
+                                type: 'error',
+                                message: '只允许上传PDF、Word、Excel、PPT、图片、音频、视频和压缩格式的文件!'
+                            });
+                            return;
+                        }
+                        
+                        // 显示上传中提示
+                        const loadingMessage = this.$message({
+                            type: 'info',
+                            message: '文件上传中...',
+                            duration: 0
+                        });
+                        
+                        // 创建FormData并上传
+                        const formData = new FormData();
+                        formData.append('file', file);
+                        
+                        // 调用您的上传方法
+                        this.$store.dispatch('pool/uploadFile', formData).then(res => {
+                            console.log('上传结果:', res);
+                            if (res.code === 200 && res.data && res.data.imgUrl) {
+                                const fileUrl = res.data.imgUrl;
+                                const originalFileName = file.name;
+                                
+                                // 关闭上传中提示
+                                loadingMessage.close();
+                                
+                                this.$message({
+                                    type: 'success',
+                                    message: '文件上传成功!请在链接对话框中设置标题',
+                                    duration: 3000
+                                });
+                                
+                                // 定义文件类型对应的图标
+                                const iconMap = {
+                                    '.doc': 'http://192.168.1.234:19000/pre/image/png/20260113/1768285836397142.png',
+                                    '.docx': 'http://192.168.1.234:19000/pre/image/png/20260113/1768290036895691.png',
+                                    '.jpg': 'http://192.168.1.234:19000/pre/image/png/20260113/1768285943518814.png',
+                                    '.jpeg': 'http://192.168.1.234:19000/pre/image/png/20260113/1768285943518814.png',
+                                    '.mp3': 'http://192.168.1.234:19000/pre/image/png/20260113/1768285970917457.png',
+                                    '.mp4': 'http://192.168.1.234:19000/pre/image/png/20260113/1768285980356293.png',
+                                    '.pdf': 'http://192.168.1.234:19000/pre/image/png/20260113/1768285992141969.png',
+                                    '.png': 'http://192.168.1.234:19000/pre/image/png/20260113/1768286002939847.png',
+                                    '.gif': 'http://192.168.1.234:19000/pre/image/png/20260113/1768286002939847.png',
+                                    '.ppt': 'http://192.168.1.234:19000/pre/image/png/20260113/1768286013209864.png',
+                                    '.xls': 'http://192.168.1.234:19000/pre/image/png/20260113/1768286021736124.png',
+                                    '.zip': 'http://192.168.1.234:19000/pre/image/png/20260113/1768286028878150.png',
+                                    '.rar': 'http://192.168.1.234:19000/pre/image/png/20260113/1768287422984578.png'
+                                };
+                                
+                                // 获取对应图标
+                                const iconUrl = iconMap[fileExtension] || 'http://192.168.1.234:19000/pre/image/png/20260113/1768285943518814.png';
+                                
+                                // 使用原文件名作为默认标题
+                                const defaultTitle = originalFileName;
+                                
+                                // 调用回调函数,将文件URL传递给链接对话框
+                                // 用户可以在对话框中编辑链接文本后再插入
+                                cb(fileUrl, {
+                                    title: defaultTitle,
+                                    text: defaultTitle, // 默认显示原文件名
+                                    href: fileUrl,
+                                    // 可以传递一些额外数据用于后续处理
+                                    metadata: {
+                                        fileUrl: fileUrl,
+                                        iconUrl: iconUrl,
+                                        fileName: originalFileName,
+                                        fileExtension: fileExtension
+                                    }
+                                });
+                                
+                            } else {
+                                loadingMessage.close();
+                                console.error('上传失败:', res);
+                                this.$message({
+                                    type: 'error',
+                                    message: '文件上传失败:' + (res.message || '未知错误')
+                                });
+                            }
+                        })
+                        .catch(error => {
+                            loadingMessage.close();
+                            console.error('上传错误:', error);
+                            this.$message({
+                                type: 'error',
+                                message: '网络错误,请重试!'
+                            });
+                        });
+                    });
+                    input.click();
+                },
+                setup: (editor) => {
+                    this.editorInstance = editor;
+                    editor.setContent(this.value);
+                    editor.on('change', () => {
+                        this.$emit('input', editor.getContent());
+                    });
+                    // 添加自定义文件上传按钮
+                    editor.ui.registry.addButton('attachment', {
+                        icon: 'attachment',
+                        tooltip: '插入文件链接',
+                        onAction: () => {
+                            // 打开链接对话框,但填充文件上传功能
+                            editor.execCommand('mceLink');
+
+                            // 或者直接打开文件上传
+                            editor.execCommand('mceLink', false, {
+                                title: '上传文件',
+                                filetype: 'file'
+                            });
+                        }
+                    });
+                    // 监听链接插入事件
+                    editor.on('SetContent', (e) => {
+                        // 延迟执行,确保链接已插入
+                        setTimeout(() => {
+                            // 查找新插入的链接(可能需要更精确的检测逻辑)
+                            const links = editor.getBody().querySelectorAll('a[href]');
+                            links.forEach(link => {
+                                // 检查是否是需要添加图标的文件链接
+                                const href = link.getAttribute('href');
+                                if (href && !link.querySelector('img')) {
+                                    // 这里可以根据href判断是否是文件链接
+                                    // 例如检查URL是否包含特定路径或文件扩展名
+                                    const fileExtensions = ['.pdf', '.doc', '.docx', '.jpg', '.jpeg', '.png', '.gif', '.mp3', '.mp4', '.zip', '.rar', '.ppt', '.xls'];
+                                    const isFileLink = fileExtensions.some(ext => href.toLowerCase().endsWith(ext));
+                                    
+                                    if (isFileLink) {
+                                        const fileName = link.textContent || '文件';
+                                        const fileExtension = href.substring(href.lastIndexOf('.')).toLowerCase();
+                                        
+                                        // 定义文件类型对应的图标
+                                        const iconMap = {
+                                            '.doc': 'http://192.168.1.234:19000/pre/image/png/20260113/1768285836397142.png',
+                                            '.docx': 'http://192.168.1.234:19000/pre/image/png/20260113/1768290036895691.png',
+                                            '.jpg': 'http://192.168.1.234:19000/pre/image/png/20260113/1768285943518814.png',
+                                            '.jpeg': 'http://192.168.1.234:19000/pre/image/png/20260113/1768285943518814.png',
+                                            '.mp3': 'http://192.168.1.234:19000/pre/image/png/20260113/1768285970917457.png',
+                                            '.mp4': 'http://192.168.1.234:19000/pre/image/png/20260113/1768285980356293.png',
+                                            '.pdf': 'http://192.168.1.234:19000/pre/image/png/20260113/1768285992141969.png',
+                                            '.png': 'http://192.168.1.234:19000/pre/image/png/20260113/1768286002939847.png',
+                                            '.gif': 'http://192.168.1.234:19000/pre/image/png/20260113/1768286002939847.png',
+                                            '.ppt': 'http://192.168.1.234:19000/pre/image/png/20260113/1768286013209864.png',
+                                            '.xls': 'http://192.168.1.234:19000/pre/image/png/20260113/1768286021736124.png',
+                                            '.zip': 'http://192.168.1.234:19000/pre/image/png/20260113/1768286028878150.png',
+                                            '.rar': 'http://192.168.1.234:19000/pre/image/png/20260113/1768287422984578.png'
+                                        };
+                                        
+                                        const iconUrl = iconMap[fileExtension] || iconMap['.jpg'];
+                                        
+                                        // 创建带图标的链接
+                                        const iconHtml = `<img src="${iconUrl}" style="height: 30px; vertical-align: middle; margin-right: 5px;" alt="${fileExtension}图标"/>`;
+                                        link.innerHTML = iconHtml + fileName;
+                                    }
+                                }
+                            });
+                        }, 100);
+                    });
+                }
             }
-          },
-          images_upload_handler: (blobInfo, success, failure) => {
+        };
+    },
+    methods: {
+        dataURLtoBlob(dataURL) {
+            const arr = dataURL.split(',');
+            const mime = arr[0].match(/:(.*?);/)[1];
+            const bstr = atob(arr[1]);
+            let n = bstr.length;
+            const u8arr = new Uint8Array(n);
+            while (n--) {
+                u8arr[n] = bstr.charCodeAt(n);
+            }
+            return new Blob([u8arr], { type: mime });
+        },
+        //上传图片
+        uploadImageFromBlob(blob, success, failure) {
             const xhr = new XMLHttpRequest();
             xhr.withCredentials = false;
             xhr.open('POST', url.baseUrl + '/public/uploadFile');
             xhr.onload = () => {
-              if (xhr.status < 200 || xhr.status >= 300) {
-                failure('HTTP Error: ' + xhr.status);
-                return;
-              }
-              const json = JSON.parse(xhr.responseText);
-              if (json.code != 200) {
-                failure('图片上传失败! ' + json.message);
-                return;
-              }
-              success(json.data.imgUrl);
-              
-              const editor = tinymce.activeEditor;
-              const nodeChangeHandler = (e) => {
-                const imgElm = e.element;
-                if (imgElm.nodeName === 'IMG' && imgElm.src === json.data.imgUrl) {
-                  editor.dom.setAttrib(imgElm, 'alt', json.data.oldName || '全国政务信息一体化应用平台');
-                  editor.off('NodeChange', nodeChangeHandler);
+                if (xhr.status < 200 || xhr.status >= 300) {
+                    failure('HTTP Error: ' + xhr.status);
+                    return;
+                }
+                const json = JSON.parse(xhr.responseText);
+                if (json.code != 200) {
+                    failure('图片上传失败! ' + json.message);
+                    return;
                 }
-              };
-              editor.on('NodeChange', nodeChangeHandler);
+                success(json.data.imgUrl);
             };
             const formData = new FormData();
-            formData.append('file', blobInfo.blob());
+            formData.append('file', blob);
             xhr.send(formData);
-          },
-          setup: (editor) => {
-            this.editorInstance = editor;
-            editor.setContent(this.value);
-            editor.on('change', () => {
-              this.$emit('input', editor.getContent());
-            });
-          }
-        }
-      };
-    },
-    methods: {
-      dataURLtoBlob(dataURL) {
-        const arr = dataURL.split(',');
-        const mime = arr[0].match(/:(.*?);/)[1];
-        const bstr = atob(arr[1]);
-        let n = bstr.length;
-        const u8arr = new Uint8Array(n);
-        while(n--) {
-          u8arr[n] = bstr.charCodeAt(n);
-        }
-        return new Blob([u8arr], {type: mime});
-      },
-      
-      uploadImageFromBlob(blob, success, failure) {
-        const xhr = new XMLHttpRequest();
-        xhr.withCredentials = false;
-        xhr.open('POST', url.baseUrl + '/public/uploadFile');
-        
-        xhr.onload = () => {
-          if (xhr.status < 200 || xhr.status >= 300) {
-            failure('HTTP Error: ' + xhr.status);
-            return;
-          }
-          
-          const json = JSON.parse(xhr.responseText);
-          if (json.code != 200) {
-            failure('图片上传失败! ' + json.message);
-            return;
-          }
-          
-          success(json.data.imgUrl);
-        };
-        
-        const formData = new FormData();
-        formData.append('file', blob);
-        xhr.send(formData);
-      },
-      
-      reinitEditor() {
-        this.componentKey += 1;
-      }
+        },
+        reinitEditor() {
+            this.componentKey += 1;
+        },
     },
     watch: {
-      value(newVal) {
-        if (this.editorInstance && newVal !== this.editorInstance.getContent()) {
-          this.content = newVal;
+        value(newVal) {
+            if (this.editorInstance && newVal !== this.editorInstance.getContent()) {
+                this.content = newVal;
+            }
         }
-      }
     },
     components: {
-      'tiny-editor': editor,
+        'tiny-editor': editor,
     },
     mounted() {
-      this.reinitEditor();
-    },
-  }
-  </script>
+        this.reinitEditor();
+    }
+}
+</script>

+ 2 - 2
src/utils/baseUrl.js

@@ -10,7 +10,7 @@ const URL = {
   baseUrl: 'https://apipre1.bjzxtw.org.cn',//pre环境域名2
   aiUrl: 'http://apipre3.bjzxtw.org.cn',//ai环境域名
   //baseUrl: 'http://192.168.1.201:9501',//刘佳伟本地环境
-  // baseUrl:'http://192.168.1.201:9501',//冯蕊的本地环境
+  //baseUrl:'http://192.168.1.201:9101',//冯蕊的本地环境
   //baseUrl: 'http://192.168.1.129:9501',//刘剑的本地环境
   // WebsocketUrl: 'ws://192.168.1.201:9506',//刘佳伟 -- websocket地址
   // WebsocketUrl: 'ws://192.168.1.127:9506'//刘剑 -- websocket地址
@@ -28,4 +28,4 @@ const URL = {
   imUrl: 'https://imp.ncltw.org.cn/message', //im地址
 }
 
-export default URL;
+export default URL;