持续开发习题管理模块,新增ckeditor5富文本组件
This commit is contained in:
180
src/components/richText/ckEditor4.vue
Normal file
180
src/components/richText/ckEditor4.vue
Normal file
@@ -0,0 +1,180 @@
|
||||
<template>
|
||||
<div id="app-ckeditor">
|
||||
<ckeditor
|
||||
v-model="editorData2"
|
||||
:config="editorConfig"
|
||||
@ready="logEvent('ready', $event)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<!--<script src="/node_modules/ckeditor4/ckeditor.js"></script>-->
|
||||
<!--<script src="/node_modules/ckeditor4-vue/dist/ckeditor.js"></script>-->
|
||||
<!--<script src="https://cdn.ckeditor.com/4.19.1/standard-all/ckeditor.js"></script>-->
|
||||
<script>
|
||||
// import { MyCustomUploadAdapterPlugin } from "@/components/richText/customUploadAdapter";
|
||||
import { getToken } from '@/utils/auth'
|
||||
export default {
|
||||
name: 'ckEditor4',
|
||||
model: {
|
||||
prop: 'content',
|
||||
event: 'change'
|
||||
},
|
||||
props: ['modelValue', 'content'],
|
||||
emits: ['update:modelValue'],
|
||||
data() {
|
||||
return {
|
||||
img_url:'',
|
||||
events: [],
|
||||
// editorUrl: "https://xxx/ckeditor/ckeditor.js",
|
||||
editorConfig: {
|
||||
extraPlugins: 'uploadimage,image2',
|
||||
uploadUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile?command=QuickUpload&type=Files&responseType=json',
|
||||
filebrowserBrowseUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile',
|
||||
filebrowserImageBrowseUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile?type=Images',
|
||||
filebrowserUploadUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile?command=QuickUpload&type=Files',
|
||||
filebrowserImageUploadUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile',
|
||||
imageUploadUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile',
|
||||
|
||||
fileTools_requestHeaders: {
|
||||
'Authorization': 'Bearer ' + getToken()
|
||||
},
|
||||
image2_alignClasses: ['image-align-left', 'image-align-center', 'image-align-right'],
|
||||
image2_disableResizer: true,
|
||||
removeButtons: 'PasteFromWord'
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
editorData: {
|
||||
get() {
|
||||
return this.modelValue
|
||||
},
|
||||
set(value) {
|
||||
console.log(value)
|
||||
this.$emit('update:modelValue', value)
|
||||
}
|
||||
},
|
||||
editorData2: {
|
||||
get() {
|
||||
return this.content
|
||||
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('change', value)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// editorData(val1) {
|
||||
// console.log(val1)
|
||||
// }
|
||||
},
|
||||
created() {
|
||||
this.getScript()
|
||||
},
|
||||
methods: {
|
||||
getScript() {
|
||||
const script = document.createElement('script')
|
||||
script.type = 'text/javascript'
|
||||
script.src = '/node_modules/ckeditor4/ckeditor.js'
|
||||
document.getElementsByTagName('head')[0].appendChild(script)
|
||||
},
|
||||
logEvent: function(eventName, event) {
|
||||
const _this = this
|
||||
// console.log(event)
|
||||
// 上传请求
|
||||
event.on( 'fileUploadRequest', async evt => {
|
||||
console.log(evt)
|
||||
var fileLoader = evt.data.fileLoader;
|
||||
// let formData = new FormData();
|
||||
// let xhr = fileLoader.xhr;
|
||||
// xhr.setRequestHeader( 'Authorization', 'Bearer ' + getToken() );
|
||||
// xhr.open( 'POST', fileLoader.uploadUrl, true );
|
||||
// formData.append( 'multipartFile', fileLoader.file);
|
||||
// fileLoader.xhr.send( formData );
|
||||
|
||||
|
||||
// 测试
|
||||
const xhr_ = new XMLHttpRequest()
|
||||
xhr_.onreadystatechange=function()
|
||||
{
|
||||
if (xhr_.readyState==4 && xhr_.status==200)
|
||||
{
|
||||
// console.log(xhr_)
|
||||
_this.img_url = xhr_.response.data.full_path
|
||||
// var data = evt.data;
|
||||
// data.url = res_url
|
||||
// 用官方的方法进行访问
|
||||
let xhr = fileLoader.xhr;
|
||||
xhr.open( 'POST', fileLoader.uploadUrl, true );
|
||||
xhr.setRequestHeader('Authorization', 'Bearer ' + getToken())
|
||||
let formData = new FormData();
|
||||
formData.append( 'multipartFile', fileLoader.file);
|
||||
fileLoader.xhr.send( formData );
|
||||
}
|
||||
}
|
||||
xhr_.open('POST', fileLoader.uploadUrl, true)
|
||||
xhr_.setRequestHeader('Authorization', 'Bearer ' + getToken())
|
||||
xhr_.responseType = 'json'
|
||||
|
||||
const data = new FormData();
|
||||
// 上传参数就根据后端的处理而设置了
|
||||
data.append( 'file', fileLoader.file );
|
||||
xhr_.send(data);
|
||||
|
||||
// 测试结束
|
||||
|
||||
// Prevented the default behavior.
|
||||
evt.stop()
|
||||
})
|
||||
// 回调
|
||||
event.on( 'fileUploadResponse', async evt => {
|
||||
console.log(evt)
|
||||
evt.stop();
|
||||
evt.data.url = _this.img_url
|
||||
// var data = evt.data;
|
||||
// let xhr = data.fileLoader.xhr;
|
||||
// let response = xhr.responseText;
|
||||
// let imgUrl = JSON.parse(response).data;
|
||||
// if(!imgUrl){
|
||||
// data.message = imgUrl // 这是失败alert提示信息
|
||||
// evt.cancel();
|
||||
// }else{
|
||||
// data.url = imgUrl // 返回到“图像信息”那里的URL框里面
|
||||
// }
|
||||
})
|
||||
// if (this.events.length > 19) {
|
||||
// this.events.pop()
|
||||
// }
|
||||
//
|
||||
// const eventData = {
|
||||
// name: eventName,
|
||||
// timestamp: this.getCurrentTimestamp()
|
||||
// }
|
||||
//
|
||||
// this.events.unshift(eventData)
|
||||
|
||||
// console.log(eventData.timestamp, eventData.name, event)
|
||||
},
|
||||
|
||||
getCurrentTimestamp: function() {
|
||||
return new Intl.DateTimeFormat('en', {
|
||||
hour12: false,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
}).format(new Date())
|
||||
},
|
||||
|
||||
clearEventsLog: function() {
|
||||
this.events = []
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.ck-editor__main{
|
||||
max-height: 350px;
|
||||
overflow: scroll;
|
||||
}
|
||||
</style>
|
53
src/components/richText/ckEditor5.vue
Normal file
53
src/components/richText/ckEditor5.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<div id="editor-box">
|
||||
<ckeditor :editor="editor" v-model="value" :config="editorConfig" @ready="logEvent('ready', $event)"></ckeditor>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script >
|
||||
// import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
|
||||
import ClassicEditor from 'axl-editor';
|
||||
import { MyCustomUploadAdapterPlugin } from '@/components/richText/customUploadAdapter'
|
||||
// import {ref,onMounted } from 'vue'
|
||||
export default {
|
||||
name: 'editor-box',
|
||||
props: ['modelValue','content'],
|
||||
emits: ['update:modelValue'],
|
||||
data() {
|
||||
return {
|
||||
editor: ClassicEditor,
|
||||
editorData: '<p>Content of the editor.</p>',
|
||||
editorConfig: {
|
||||
// The configuration of the editor.
|
||||
// uploadUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile?command=QuickUpload&type=Files&responseType=json',
|
||||
// simpleUpload:{
|
||||
// uploadUrl: 'https://apiwx.twzxjy.com/api/v1/public/uploadFile?command=QuickUpload&type=Files&responseType=json',
|
||||
// }
|
||||
extraPlugins:[MyCustomUploadAdapterPlugin]
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
value: {
|
||||
get() {
|
||||
return this.modelValue
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('update:modelValue', value)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
logEvent(eventName, event){
|
||||
const _this = this
|
||||
console.log(eventName)
|
||||
// event.on( 'fileUploadRequest', async evt => {
|
||||
// console.log(evt)
|
||||
// })
|
||||
},
|
||||
}
|
||||
}
|
||||
// const name = ref(ClassicEditor)
|
||||
// const editorData = ref('<p>Content of the editor.</p>')
|
||||
// const editorConfig = ref({})
|
||||
</script>
|
146
src/components/richText/customUploadAdapter.js
Normal file
146
src/components/richText/customUploadAdapter.js
Normal file
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* 图片压缩处理,转换为等比的高800px的图像
|
||||
* @params file File类型的图片文件
|
||||
* @return Promise<file> 返回一个promise,值为一个压缩后的图片文件
|
||||
*/
|
||||
import { getToken } from '@/utils/auth'
|
||||
function imgCutdown(file) {
|
||||
return new Promise((resolve) => {
|
||||
const render = new FileReader();
|
||||
render.onload = function(progress) {
|
||||
const target = progress.target;
|
||||
if (!target) return;
|
||||
|
||||
const reuslt = target.result;
|
||||
if (typeof reuslt === "string") {
|
||||
const image = new Image();
|
||||
image.src = reuslt;
|
||||
image.onload = function() {
|
||||
const h = 800;
|
||||
const rate = h / image.height;
|
||||
const canvas = document.createElement("canvas");
|
||||
const context = canvas.getContext("2d");
|
||||
if (!context) return;
|
||||
canvas.width = image.width * rate;
|
||||
canvas.height = h;
|
||||
context.drawImage(
|
||||
image,
|
||||
0,
|
||||
0,
|
||||
image.width,
|
||||
image.height,
|
||||
0,
|
||||
0,
|
||||
canvas.width,
|
||||
canvas.height
|
||||
);
|
||||
canvas.toBlob(
|
||||
function(b) {
|
||||
const file = new File([b], "pic", {
|
||||
type: "image/jpeg",
|
||||
});
|
||||
resolve(file);
|
||||
},
|
||||
"image/jpeg",
|
||||
0.5
|
||||
);
|
||||
};
|
||||
}
|
||||
};
|
||||
render.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
// 上传图片的地址,我这里使用的是vue的环境变量,也可以直接写死
|
||||
// const uploadUrl = `${process.env.VUE_APP_HOST}image/upload.do`;
|
||||
// const uploadUrl = `https://192.168.1.23:8000/api/v1/public/uploadFile`
|
||||
const uploadUrl = `https://apiwx.twzxjy.com/api/v1/public/uploadFile`
|
||||
|
||||
// 自定义适配器类
|
||||
class MyUploadAdapter {
|
||||
constructor(loader) {
|
||||
this.loader = loader
|
||||
}
|
||||
|
||||
upload() {
|
||||
return this.loader.file.then(
|
||||
(file) =>
|
||||
new Promise((resolve, reject) => {
|
||||
this._initRequest();
|
||||
this._initListeners(resolve, reject, file);
|
||||
this._sendRequest(file);
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
abort() {
|
||||
if (this.xhr) {
|
||||
this.xhr.abort();
|
||||
}
|
||||
}
|
||||
|
||||
_initRequest() {
|
||||
const xhr = (this.xhr = new XMLHttpRequest())
|
||||
|
||||
xhr.open('POST', uploadUrl, true)
|
||||
xhr.setRequestHeader('Authorization', 'Bearer ' + getToken())
|
||||
xhr.responseType = 'json'
|
||||
}
|
||||
|
||||
_initListeners(resolve, reject, file) {
|
||||
const xhr = this.xhr
|
||||
const loader = this.loader
|
||||
const genericErrorText = `Couldn't upload file: ${file.name}.`
|
||||
|
||||
xhr.addEventListener('error', () => reject(genericErrorText))
|
||||
xhr.addEventListener('abort', () => reject())
|
||||
xhr.addEventListener('load', () => {
|
||||
const response = xhr.response
|
||||
|
||||
if (!response || response.error) {
|
||||
return reject(
|
||||
response && response.error ? response.error.message : genericErrorText
|
||||
)
|
||||
}
|
||||
console.log(response)
|
||||
|
||||
resolve({
|
||||
default: response.data.path,
|
||||
})
|
||||
})
|
||||
|
||||
if (xhr.upload) {
|
||||
xhr.upload.addEventListener('progress', (evt) => {
|
||||
if (evt.lengthComputable) {
|
||||
loader.uploadTotal = evt.total
|
||||
loader.uploaded = evt.loaded
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async _sendRequest(file) {
|
||||
const data = new FormData();
|
||||
// 判断如果上传图片大于1M,则进行压缩处理
|
||||
// if (file.size > 1000 * 1024) {
|
||||
// file = await imgCutdown(file);
|
||||
// }
|
||||
|
||||
// 上传参数就根据后端的处理而设置了
|
||||
// data.append("file", file);
|
||||
// data.append("name", file.name);
|
||||
// data.append("group", "pic");
|
||||
data.append( 'file', file );
|
||||
this.xhr.send(data);
|
||||
}
|
||||
}
|
||||
|
||||
function MyCustomUploadAdapterPlugin(editor) {
|
||||
editor.plugins.get("FileRepository").createUploadAdapter = (loader) => {
|
||||
return new MyUploadAdapter(loader);
|
||||
};
|
||||
}
|
||||
export {
|
||||
MyUploadAdapter,
|
||||
MyCustomUploadAdapterPlugin
|
||||
}
|
Reference in New Issue
Block a user