|
@@ -1,188 +1,181 @@
|
|
|
<template>
|
|
|
- <div>
|
|
|
- <quill-editor
|
|
|
- ref="quillEditor"
|
|
|
- v-model="content"
|
|
|
- :options="editorOptions"
|
|
|
- @ready="onEditorReady"
|
|
|
+ <div style="border: 1px solid #ccc">
|
|
|
+ <Toolbar
|
|
|
+ style="border-bottom: 1px solid #ccc"
|
|
|
+ :editor="editor"
|
|
|
+ :defaultConfig="toolbarConfig"
|
|
|
+ :mode="mode"
|
|
|
+ />
|
|
|
+ <Editor
|
|
|
+ style="height: 500px; overflow-y: hidden"
|
|
|
+ v-model="html"
|
|
|
+ :defaultConfig="editorConfig"
|
|
|
+ :mode="mode"
|
|
|
+ @onCreated="onCreated"
|
|
|
+ @change="handleEditorChange"
|
|
|
+ />
|
|
|
+ <input
|
|
|
+ type="file"
|
|
|
+ ref="fileInput"
|
|
|
+ style="display: none"
|
|
|
+ @change="handleFileUpload"
|
|
|
/>
|
|
|
- <button @click="submit">确定</button>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { quillEditor } from "vue-quill-editor";
|
|
|
-import "quill/dist/quill.core.css";
|
|
|
-import "quill/dist/quill.snow.css";
|
|
|
-import "quill/dist/quill.bubble.css";
|
|
|
+import Vue from "vue";
|
|
|
+import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
|
|
|
+import { Boot } from "@wangeditor/editor";
|
|
|
+import { uploadFile } from "@/api/performance";
|
|
|
|
|
|
-export default {
|
|
|
- components: {
|
|
|
- quillEditor,
|
|
|
- },
|
|
|
+const customMenuKey = "customUpload";
|
|
|
+let isCustomMenuRegistered = false;
|
|
|
+
|
|
|
+function registerCustomUploadIcon(componentInstance) {
|
|
|
+ if (isCustomMenuRegistered) return;
|
|
|
+
|
|
|
+ const customUploadMenu = {
|
|
|
+ key: customMenuKey,
|
|
|
+ factory() {
|
|
|
+ return {
|
|
|
+ tag: "button",
|
|
|
+ getValue(editor) {
|
|
|
+ return editor.getHtml();
|
|
|
+ },
|
|
|
+ isActive(editor) {
|
|
|
+ return false;
|
|
|
+ },
|
|
|
+ exec: () => {
|
|
|
+ componentInstance.uploadFile();
|
|
|
+ },
|
|
|
+ isDisabled(editor) {
|
|
|
+ return false;
|
|
|
+ },
|
|
|
+ title: "上传文件",
|
|
|
+ iconSvg: `<svg t="1718589544286" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1591" width="200" height="200">
|
|
|
+ <path d="M1024 693.248q0 25.6-8.704 48.128t-24.576 40.448-36.864 30.208-45.568 16.384l1.024 1.024-17.408 0-4.096 0-4.096 0-675.84 0q-5.12 1.024-16.384 1.024-39.936 0-74.752-15.36t-60.928-41.472-40.96-60.928-14.848-74.752 14.848-74.752 40.96-60.928 60.928-41.472 74.752-15.36l1.024 0q-1.024-8.192-1.024-15.36l0-16.384q0-72.704 27.648-137.216t75.776-112.128 112.128-75.264 136.704-27.648 137.216 27.648 112.64 75.264 75.776 112.128 27.648 137.216q0 37.888-8.192 74.24t-22.528 69.12q5.12-1.024 10.752-1.536t10.752-0.512q27.648 0 52.736 10.752t43.52 29.696 29.184 44.032 10.752 53.76zM665.6 571.392q20.48 0 26.624-4.608t-8.192-22.016q-14.336-18.432-31.744-48.128t-36.352-60.416-38.4-57.344-37.888-38.912q-18.432-13.312-27.136-14.336t-25.088 12.288q-18.432 15.36-35.84 38.912t-35.328 50.176-35.84 52.224-36.352 45.056q-18.432 18.432-13.312 32.768t25.6 14.336l16.384 0q9.216 0 19.968 0.512t20.992 0.512l17.408 0q14.336 1.024 18.432 9.728t4.096 24.064q0 17.408-0.512 30.72t-0.512 25.6-0.512 25.6-0.512 30.72q0 7.168 1.536 15.36t5.632 15.36 12.288 11.776 21.504 4.608l23.552 0q9.216 0 27.648 1.024 24.576 0 28.16-12.288t3.584-38.912q0-23.552 0.512-42.496t0.512-51.712q0-23.552 4.608-36.352t19.968-12.8q11.264 0 32.256-0.512t32.256-0.512z" p-id="1592"></path>
|
|
|
+ </svg>`,
|
|
|
+ text: "上传文件",
|
|
|
+ };
|
|
|
+ },
|
|
|
+ };
|
|
|
+
|
|
|
+ Boot.registerMenu({
|
|
|
+ key: customMenuKey,
|
|
|
+ ...customUploadMenu,
|
|
|
+ });
|
|
|
+
|
|
|
+ isCustomMenuRegistered = true;
|
|
|
+}
|
|
|
+
|
|
|
+export default Vue.extend({
|
|
|
+ components: { Editor, Toolbar },
|
|
|
props: {
|
|
|
value: {
|
|
|
type: String,
|
|
|
- defaultValue: "",
|
|
|
+ default: "",
|
|
|
},
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
- content: "",
|
|
|
- editorOptions: {
|
|
|
- theme: "snow",
|
|
|
- modules: {
|
|
|
- toolbar: {
|
|
|
- container: [
|
|
|
- [{ header: "1" }, { header: "2" }, { font: [] }],
|
|
|
- [{ size: [] }],
|
|
|
- ["bold", "italic", "underline", "strike", "blockquote"],
|
|
|
- [
|
|
|
- { list: "ordered" },
|
|
|
- { list: "bullet" },
|
|
|
- { indent: "-1" },
|
|
|
- { indent: "+1" },
|
|
|
- ],
|
|
|
- ["link", "image", "video", "custom-file"], // 添加自定义文件图标
|
|
|
- ["clean"],
|
|
|
- ],
|
|
|
- handlers: {
|
|
|
- // image: this.imageHandler,
|
|
|
- video: this.videoHandler,
|
|
|
- "custom-file": this.fileHandler, // 自定义文件处理函数
|
|
|
+ editor: null,
|
|
|
+ html: "<p>hello</p>",
|
|
|
+ toolbarConfig: {
|
|
|
+ excludeKeys: ["group-video"], // 移除上传视频功能
|
|
|
+ },
|
|
|
+ editorConfig: {
|
|
|
+ placeholder: "请输入内容...",
|
|
|
+ MENU_CONF: {
|
|
|
+ // 上传图片
|
|
|
+ uploadImage: {
|
|
|
+ async customUpload(file, insertFn) {
|
|
|
+ console.log(file, "上传文件");
|
|
|
+ if (!/^(image\/png|image\/jpeg|image\/jpg)$/i.test(file.type)) {
|
|
|
+ alert("只能上传格式为png、jpg、jpeg的图片文件!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const form = new FormData();
|
|
|
+ form.append("file", file);
|
|
|
+ uploadFile(form)
|
|
|
+ .then((res) => {
|
|
|
+ let data = res.data;
|
|
|
+ console.log(data, 7777);
|
|
|
+ insertFn(`${data}`);
|
|
|
+ Vue.prototype.$message({
|
|
|
+ type: "success",
|
|
|
+ message: `${file.name}上传成功`,
|
|
|
+ });
|
|
|
+ })
|
|
|
+ .catch((err) => console.log(err, 888));
|
|
|
},
|
|
|
},
|
|
|
},
|
|
|
},
|
|
|
+ mode: "default",
|
|
|
};
|
|
|
},
|
|
|
created() {
|
|
|
- this.content = this.value;
|
|
|
+ this.html = this.value;
|
|
|
+ registerCustomUploadIcon(this);
|
|
|
},
|
|
|
methods: {
|
|
|
- submit() {
|
|
|
- console.log(this.content, "this.$refs.quillEditor.getContents();");
|
|
|
- },
|
|
|
- onEditorReady(editor) {
|
|
|
- console.log(editor, "editor");
|
|
|
- },
|
|
|
- imageHandler() {
|
|
|
- const input = document.createElement("input");
|
|
|
- input.setAttribute("type", "file");
|
|
|
- input.setAttribute("accept", "image/*");
|
|
|
- input.click();
|
|
|
-
|
|
|
- input.onchange = async () => {
|
|
|
- const file = input.files[0];
|
|
|
- if (file) {
|
|
|
- const formData = new FormData();
|
|
|
- formData.append("file", file);
|
|
|
- const quill = this.$refs.quillEditor.quill;
|
|
|
- const range = quill.getSelection();
|
|
|
- quill.insertEmbed(range.index, "image", formData);
|
|
|
- // try {
|
|
|
- // const response = await this.uploadImage(formData);
|
|
|
- // const url = response.data.url; // 根据你的实际响应数据结构
|
|
|
- // const quill = this.$refs.quillEditor.quill;
|
|
|
- // const range = quill.getSelection();
|
|
|
- // quill.insertEmbed(range.index, "image", url);
|
|
|
- // } catch (error) {
|
|
|
- // console.error("Image upload failed", error);
|
|
|
- // }
|
|
|
- }
|
|
|
+ onCreated(editor) {
|
|
|
+ this.editor = Object.seal(editor);
|
|
|
+ this.toolbarConfig.insertKeys = {
|
|
|
+ index: 22,
|
|
|
+ keys: [customMenuKey],
|
|
|
};
|
|
|
},
|
|
|
- videoHandler() {
|
|
|
- const input = document.createElement("input");
|
|
|
- input.setAttribute("type", "file");
|
|
|
- input.setAttribute("accept", "video/*");
|
|
|
- input.click();
|
|
|
-
|
|
|
- input.onchange = async () => {
|
|
|
- const file = input.files[0];
|
|
|
- if (file) {
|
|
|
- const formData = new FormData();
|
|
|
- formData.append("file", file);
|
|
|
-
|
|
|
- try {
|
|
|
- const response = await this.uploadVideo(formData);
|
|
|
- const url = response.data.url;
|
|
|
- const quill = this.$refs.quillEditor.quill;
|
|
|
- const range = quill.getSelection();
|
|
|
- quill.insertEmbed(range.index, "video", url);
|
|
|
- } catch (error) {
|
|
|
- console.error("Video upload failed", error);
|
|
|
+ handleFileUpload(event) {
|
|
|
+ const file = event.target.files[0];
|
|
|
+ if (!file) return;
|
|
|
+ if (
|
|
|
+ !/^(text\/html|application\/pdf|application\/msword|application\/vnd\.ms-excel|application\/vnd\.ms-office|application\/vnd\.openxmlformats-officedocument\.spreadsheetml\.sheet|application\/vnd\.openxmlformats-officedocument\.wordprocessingml\.document|application\/vnd\.openxmlformats-officedocument\.spreadsheetml\.sheet|text\/csv)$/i.test(
|
|
|
+ file.type
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ alert("只能上传格式为html、pdf、word、excel、csv、docx、xlsx的文件!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const form = new FormData();
|
|
|
+ form.append("file", file);
|
|
|
+ uploadFile(form)
|
|
|
+ .then((res) => {
|
|
|
+ let data = res.data;
|
|
|
+ console.log(data, file.type, 7777, this.editor);
|
|
|
+ if (this.editor) {
|
|
|
+ this.editor.dangerouslyInsertHtml(
|
|
|
+ `<a href="${data}" target="_blank">点击查看 ${file.name}</a>`
|
|
|
+ );
|
|
|
+ this.$message({
|
|
|
+ type: "success",
|
|
|
+ message: `${file.name}上传成功`,
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ console.error("Editor instance is not available.");
|
|
|
}
|
|
|
- }
|
|
|
- };
|
|
|
+ })
|
|
|
+ .catch((err) => console.log(err, 888));
|
|
|
},
|
|
|
- fileHandler() {
|
|
|
- const input = document.createElement("input");
|
|
|
- input.setAttribute("type", "file");
|
|
|
- input.setAttribute("accept", ".doc,.docx,.pdf");
|
|
|
- input.click();
|
|
|
-
|
|
|
- input.onchange = async () => {
|
|
|
- const file = input.files[0];
|
|
|
- if (file) {
|
|
|
- const formData = new FormData();
|
|
|
- formData.append("file", file);
|
|
|
- const quill = this.$refs.quillEditor.quill;
|
|
|
- const range = quill.getSelection();
|
|
|
- quill.insertText(
|
|
|
- range.index,
|
|
|
- `File uploaded: ${file.name} (URL: ${formData})`
|
|
|
- );
|
|
|
- // try {
|
|
|
- // const response = await this.uploadFile(formData);
|
|
|
- // const url = response.data.url;
|
|
|
- // const quill = this.$refs.quillEditor.quill;
|
|
|
- // const range = quill.getSelection();
|
|
|
- // quill.insertText(
|
|
|
- // range.index,
|
|
|
- // `File uploaded: ${file.name} (URL: ${url})`
|
|
|
- // );
|
|
|
- // } catch (error) {
|
|
|
- // console.error("File upload failed", error);
|
|
|
- // }
|
|
|
- }
|
|
|
- };
|
|
|
+ uploadFile() {
|
|
|
+ this.$refs.fileInput.click();
|
|
|
},
|
|
|
- async uploadImage(formData) {
|
|
|
- const response = await axios.post("/api/upload/image", formData, {
|
|
|
- headers: {
|
|
|
- "Content-Type": "multipart/form-data",
|
|
|
- },
|
|
|
- });
|
|
|
- return response;
|
|
|
+ handleEditorChange(newVal) {
|
|
|
+ this.$emit("input", newVal);
|
|
|
},
|
|
|
- async uploadVideo(formData) {
|
|
|
- const response = await axios.post("/api/upload/video", formData, {
|
|
|
- headers: {
|
|
|
- "Content-Type": "multipart/form-data",
|
|
|
- },
|
|
|
- });
|
|
|
- return response;
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ value(newVal) {
|
|
|
+ this.html = newVal;
|
|
|
},
|
|
|
- async uploadFile(formData) {
|
|
|
- const response = await axios.post("/api/upload/file", formData, {
|
|
|
- headers: {
|
|
|
- "Content-Type": "multipart/form-data",
|
|
|
- },
|
|
|
- });
|
|
|
- return response;
|
|
|
+ html(newVal) {
|
|
|
+ this.$emit("input", newVal);
|
|
|
},
|
|
|
},
|
|
|
-};
|
|
|
+});
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-/* 添加你需要的样式 */
|
|
|
-::v-deep .ql-snow.ql-toolbar .ql-custom-file {
|
|
|
- background: url("../assets/upload.png");
|
|
|
- background-size: 16px 16px;
|
|
|
- background-position: center center;
|
|
|
- background-repeat: no-repeat;
|
|
|
- /*background: red;*/
|
|
|
-}
|
|
|
+/* Add your custom styles here */
|
|
|
</style>
|