Explorar el Código

feat:Quill富文本编辑器替换onlyOffice

白白 hace 1 año
padre
commit
3b93abd9ab

+ 157 - 0
src/components/QuillEditor/Editor.vue

@@ -0,0 +1,157 @@
+<template>
+  <div class="main-container">
+    <QuillEditor ref="myQuillEditorRef"
+                 theme="snow"
+                 v-model:content="data.content"
+                 :options="data.editorOption"
+                 contentType="delta"
+                 @update:content="setValue()"
+    />
+  </div>
+</template>
+
+<script setup>
+  import { QuillEditor, Quill } from '@vueup/vue-quill'
+  import { reactive, onMounted, ref, toRaw, watch, defineProps } from 'vue'
+  import '@vueup/vue-quill/dist/vue-quill.snow.css'
+  import emitter from '@/utils/emitter'
+  import dayjs from 'dayjs'
+
+  const props = defineProps(['value', 'onTextChangeRef', 'onSelectionChangeRef', 'onGetHTML', 'onGetText', 'onGetQuill'])
+  const emit = defineEmits(['updateValue'])
+
+  const content = ref('')
+  const myQuillEditorRef = ref()
+  const fileBtn = ref()
+
+  const data = reactive({
+    content: ``,
+    editorOption: {
+      modules: {
+        toolbar: [
+          ['bold', 'italic', 'underline', 'strike'],
+          [{ 'size': ['small', false, 'large', 'huge'] }],
+          [{ 'font': [] }],
+          [{ 'align': [] }],
+          [{ 'list': 'ordered' }, { 'list': 'bullet' }],
+          [{ 'indent': '-1' }, { 'indent': '+1' }],
+          [{ 'header': 1 }, { 'header': 2 }],
+          ['image'],
+          [{ 'direction': 'rtl' }],
+          [{ 'color': [] }, { 'background': [] }]
+        ]
+      },
+      placeholder: '请输入内容...'
+    }
+  })
+
+  // 抛出更改内容
+  const setValue = () => {
+    const html = toRaw(myQuillEditorRef.value).getHTML()
+    emitter.emit('get-html', html)
+    const text = toRaw(myQuillEditorRef.value).getText()
+    emitter.emit('get-text', text)
+    const content1 = toRaw(myQuillEditorRef.value).getContents()
+    emitter.emit('get-quill-content', content1)
+  }
+
+
+  //初始化Quill及行为监控
+  const initQuill = () => {
+    const quill = toRaw(myQuillEditorRef.value).getQuill()
+    if (myQuillEditorRef.value) {
+      quill.getModule('toolbar')
+    }
+
+    // 文本变化监控
+    quill.on(Quill.events.TEXT_CHANGE, (...args) => {
+      console.log("文本变化监控")
+      console.log(args)
+      Object.assign(props.onTextChangeRef, {...args})
+      emitter.emit('change-record', {type: "TEXT_CHANGE", ...args["0"], time: dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss.SSS")})
+    })
+
+    // 光标变化监控
+    quill.on(Quill.events.SELECTION_CHANGE, (...args) => {
+      console.log("光标变化监控")
+      console.log(args)
+      Object.assign(props.onSelectionChangeRef, {...args})
+      emitter.emit('change-record', {type: "SELECTION_CHANGE", ...args["0"], time: dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss.SSS")})
+    });
+
+    // 粘贴行为监控
+    quill.root.addEventListener('paste', function (event) {
+      console.log("粘贴行为监控")
+      var clipboardData = event.clipboardData;
+      if (clipboardData && clipboardData.types && clipboardData.types.includes('text/plain')) {
+        var pastedText = clipboardData.getData('text/plain');
+        console.log('粘贴的纯文本内容:', pastedText);
+        emitter.emit('change-record', {type: "COPY", ops: pastedText, time: dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss.SSS")})
+      }
+    })
+  }
+
+// 初始化编辑器
+  onMounted(() => {
+    initQuill()
+  });
+
+  /**
+   * 暂不启用
+   * 用于处理图片
+   * @param state
+   */
+  const imgHandler = (state) => {
+    if (state) {
+      fileBtn.value.click()
+    }
+  }
+
+  /**
+   * 暂不启用
+   * 用于文件上传
+   * @param e
+   */
+  const handleUpload = (e) => {
+    const files = Array.prototype.slice.call(e.target.files)
+    if (!files) {
+      return
+    }
+    const formdata = new FormData()
+    formdata.append('file', files[0])
+    backsite.uploadFile(formdata)  // 此处使用服务端提供上传接口
+        .then(res => {
+          if (res.data.url) {
+            const quill = toRaw(myQuillEditor.value).getQuill()
+            const length = quill.getSelection().index
+            quill.insertEmbed(length, 'image', res.data.url)
+            quill.setSelection(length + 1)
+          }
+        })
+  }
+
+</script>
+
+<style scoped lang="scss">
+// 调整样式
+.main-container {
+  height: 85vh;
+  border: solid 2px rgba(199, 199, 199, 0.3);
+}
+
+.main-container :deep(.ql-container) {
+  height: 95%;
+  max-height: 95%;
+  background: #fff;
+}
+
+.main-container :deep(.ql-toolbar) {
+  height: 5%;
+  background: #fff;
+}
+
+.main-container :deep(.ql-formats) {
+  height: 21px;
+  line-height: 21px;
+}
+</style>

+ 4 - 0
src/components/QuillEditor/QuillEditor.scss

@@ -0,0 +1,4 @@
+.editor-container {
+  height: 100%;
+  //background-color:#fff;
+}

+ 71 - 0
src/components/QuillEditor/QuillEditor.vue

@@ -0,0 +1,71 @@
+<!--
+  Description: Quill富文本编辑区
+  Author: BaiQi
+  Created Date: 2025-1-8
+-->
+<template>
+  <div class="editor-container">
+    <Editor :onTextChangeRef="lastChange" :onSelectionChangeRef="range" :onGetHTML="getHTML" :onGetText="getText" @updateValue="getMsg"/>
+  </div>
+</template>
+
+<script setup lang="ts">
+import "./QuillEditor.scss"
+import Editor from './Editor.vue';
+import { onUnmounted, reactive, ref, watch } from 'vue';
+import emitter from '@/utils/emitter';
+// import * as XLSX from 'xlsx'
+
+let range = reactive({})
+let lastChange = reactive({})
+let getHTML = ref("")
+let getText = ref("")
+let getQuillContent = reactive({})
+// 行为记录
+let changeRecordList = reactive([])
+
+
+const emailForm = reactive({
+  test_msg: '1'
+})
+
+const getMsg = (val) => {
+  emailForm.test_msg = val
+}
+
+emitter.on('get-html', (value: string) => {
+  console.log(value)
+  getHTML.value = value
+})
+
+emitter.on('get-text', (value: string) => {
+  console.log(value)
+  getText.value = value
+})
+
+emitter.on('get-quill-content', (value: Object) => {
+  console.log(value)
+  Object.assign(getQuillContent, value)
+})
+
+// 接收行为数据
+emitter.on('change-record', (value) => {
+  console.log(value)
+  changeRecordList.push(value)
+})
+
+onUnmounted(() => {
+  emitter.off('get-html')
+  emitter.off('get-text')
+  emitter.off('change-record')
+  emitter.off('get-quill-content')
+})
+
+</script>
+
+<script lang="ts">
+export default {
+  name: "QuillEditor"
+}
+</script>
+

+ 0 - 30
src/views/EditPage/EditPage.vue

@@ -33,7 +33,6 @@
   import "./index.scss"
   import "./index.scss"
   import {useRoute} from 'vue-router'
   import {useRoute} from 'vue-router'
   import {ElMessage, ElMessageBox} from "element-plus";
   import {ElMessage, ElMessageBox} from "element-plus";
-  import emitter from "@/utils/emitter";
   import IndexedDB from "@/utils/indexedDBUtil";
   import IndexedDB from "@/utils/indexedDBUtil";
   import {isModified, registerAllEventListeners, removeAllEventListeners} from "@/views/EditPage/userWritingRecord";
   import {isModified, registerAllEventListeners, removeAllEventListeners} from "@/views/EditPage/userWritingRecord";
 
 
@@ -44,7 +43,6 @@
   const apis = useApis()
   const apis = useApis()
   const store = useStore()
   const store = useStore()
   const indexedDB = new IndexedDB()
   const indexedDB = new IndexedDB()
-  // let isModified = ref(false)
 
 
   const dataForm = reactive<{
   const dataForm = reactive<{
     messages: IDialogue[],
     messages: IDialogue[],
@@ -57,7 +55,6 @@
   })
   })
 
 
   const handleBack = () => {
   const handleBack = () => {
-    // console.log(isModified.value)
     if(isModified.value){
     if(isModified.value){
       ElMessageBox.confirm(
       ElMessageBox.confirm(
           '您编辑的信息尚未保存,您确定要离开吗?',
           '您编辑的信息尚未保存,您确定要离开吗?',
@@ -107,29 +104,6 @@
         })
         })
   }
   }
 
 
-  const handleMouseMove = (event: MouseEvent) => {
-    // console.log(`鼠标位置:x = ${event.clientX}, y = ${event.clientY}`);
-    // indexedDB.addData({
-    //   date: Date.now(),
-    //   userId: store.user.id,
-    //   info: `x = ${event.clientX}, y = ${event.clientY}`,
-    //   eventId: `${store.user.id}_${Date.now()}`,
-    //   type: "MouseMove"
-    // })
-  };
-
-  // // 接收word是否修改后未保存,用于决定是否提醒用户
-  // emitter.on("is-modified", () => {
-  //   isModified.value = true
-  // })
-  //
-  // // 接收AI对话点击发送按钮的行为信息
-  // emitter.on("click-ai-send-button", (event:any) => {
-  //   indexedDB.addData(event)
-  //   console.log(event)
-  // })
-
-
   onMounted( () => {
   onMounted( () => {
     fetchData()
     fetchData()
     indexedDB.initDB("eventId")
     indexedDB.initDB("eventId")
@@ -150,7 +124,3 @@ export default {
   name: "EditPage"
   name: "EditPage"
 }
 }
 </script>
 </script>
-
-<!--<style module>-->
-<!--//@import "CoursePage.scss";-->
-<!--</style>-->

+ 2 - 1
src/views/Home/component/Edit/index.scss

@@ -33,7 +33,8 @@
 }
 }
 
 
 .edit-root {
 .edit-root {
-  border: solid 1px rgba(199, 199, 199, 0.3);
+  //background-color: red;
+  //border: solid 10px rgba(199, 199, 199, 0.3);
   height: 100%;
   height: 100%;
 }
 }
 
 

+ 2 - 10
src/views/Home/component/Edit/index.vue

@@ -5,18 +5,10 @@
 -->
 -->
 <template>
 <template>
   <div class="edit">
   <div class="edit">
-<!--    <el-message :message="messageApi"></el-message>-->
     <div class="edit-box">
     <div class="edit-box">
       <div>编辑区</div>
       <div>编辑区</div>
       <div class="edit-root">
       <div class="edit-root">
-        <WordEditor
-            @value-change="handleValueChange"
-            :document-key="engagement?.fileKey"
-            :document-title="data.fileTitle"
-            :document-url="engagement?.fileUrl"
-            :user-id="store.user.id"
-            :username="store.user.name"
-        ></WordEditor>
+        <QuillEditor/>
       </div>
       </div>
       <div class="button-right">
       <div class="button-right">
         <el-button type="primary" @click="handleSubmit">提交</el-button>
         <el-button type="primary" @click="handleSubmit">提交</el-button>
@@ -34,8 +26,8 @@
   import useApis from "@/apis";
   import useApis from "@/apis";
   import {useStore} from "@/store";
   import {useStore} from "@/store";
   import {ElMessage} from "element-plus";
   import {ElMessage} from "element-plus";
-  import WordEditor from "@/components/WordEditor/WordEditor.vue";
   import emitter from "@/utils/emitter";
   import emitter from "@/utils/emitter";
+  import QuillEditor from "@/components/QuillEditor/QuillEditor.vue";
 
 
   interface IEditProps {
   interface IEditProps {
     engagement: engagementVO
     engagement: engagementVO