chenhj
2026-04-25 0a717445a99739530497e5140a8bd4e594b61690
feat(editor): 添加富文本编辑器及图片上传功能

- 新增基于vue-quill的富文本编辑器组件
- 实现图片粘贴自动上传并插入功能
- 支持通过url方式上传图片,限制文件格式与大小
- 提供通用的上传接口api,支持批量文件FormData上传
- 添加会议看板页面,展示会议统计与列表信息
- 使用Element Plus组件丰富UI界面,优化用户体验
已修改3个文件
68 ■■■■■ 文件已修改
src/api/basicData/common.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Editor/index.vue 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/meetingBoard/index.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/basicData/common.js
@@ -11,3 +11,15 @@
    },
  })
}
// 通用上传接口,支持 FormData 批量传文件,永不过期,慎用
export function uploadPublicFile(data) {
  return request({
    url: '/common/public/upload',
    method: 'post',
    data,
    headers: {
      'Content-Type': 'multipart/form-data',
    },
  })
}
src/components/Editor/index.vue
@@ -5,11 +5,11 @@
      :before-upload="handleBeforeUpload"
      :on-success="handleUploadSuccess"
      :on-error="handleUploadError"
      name="file"
      name="files"
      :show-file-list="false"
      :headers="headers"
      class="editor-img-uploader"
      v-if="type == 'url'"
      v-if="type === 'url'"
    >
      <i ref="uploadRef" class="editor-img-uploader"></i>
    </el-upload>
@@ -27,15 +27,15 @@
</template>
<script setup>
import axios from "axios";
import { QuillEditor } from "@vueup/vue-quill";
import "@vueup/vue-quill/dist/vue-quill.snow.css";
import { getToken } from "@/utils/auth";
import {uploadPublicFile} from "@/api/basicData/common.js";
const { proxy } = getCurrentInstance();
const quillEditorRef = ref();
const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传的图片服务器地址
const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/public/upload"); // 上传的图片服务器地址
const headers = ref({
  Authorization: "Bearer " + getToken(),
});
@@ -157,21 +157,40 @@
function handleUploadSuccess(res, file) {
  // 如果上传成功
  if (res.code == 200) {
    const imageUrl = resolveImageUrl(res);
    if (!imageUrl) {
      proxy.$modal.msgError("未获取到图片地址");
      return;
    }
    // 获取富文本实例
    let quill = toRaw(quillEditorRef.value).getQuill();
    // 获取光标位置
    let length = quill.selection.savedRange.index;
    const selection = quill.getSelection(true);
    const length = selection ? selection.index : quill.getLength();
    // 插入图片,res.url为服务器返回的图片链接地址
    quill.insertEmbed(
      length,
      "image",
      import.meta.env.VITE_APP_BASE_API + res.fileName
    );
    quill.insertEmbed(length, "image", imageUrl);
    // 调整光标到最后
    quill.setSelection(length + 1);
  } else {
    proxy.$modal.msgError("图片插入失败");
  }
}
function resolveImageUrl(res) {
  if (!res) return "";
  // 兼容新接口: data[0].previewURL
  const previewURL = res?.data?.[0]?.previewURL;
  if (previewURL) {
    return previewURL;
  }
  // 兼容旧接口
  if (res.url) {
    return res.url;
  }
  if (res.fileName) {
    return `${import.meta.env.VITE_APP_BASE_API}${res.fileName}`;
  }
  return "";
}
// 上传失败处理
@@ -196,17 +215,10 @@
function insertImage(file) {
  const formData = new FormData();
  formData.append("file", file);
  axios
    .post(uploadUrl.value, formData, {
      headers: {
        "Content-Type": "multipart/form-data",
        Authorization: headers.value.Authorization,
      },
    })
    .then((res) => {
      handleUploadSuccess(res.data);
    });
  formData.append("files", file);
  uploadPublicFile(formData).then((res) => {
    handleUploadSuccess(res)
  })
}
</script>
src/views/collaborativeApproval/meetingBoard/index.vue
@@ -83,9 +83,7 @@
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { Clock, Location, User, UserFilled } from '@element-plus/icons-vue'
import Editor from "@/components/Editor/index.vue";
import {getMeetSummaryItems,getMeetSummary} from '@/api/collaborativeApproval/meeting.js'
import dayjs from "dayjs";