This commit is contained in:
liuye
2021-12-24 14:48:46 +08:00
4 changed files with 270 additions and 4 deletions

View File

@@ -40,7 +40,8 @@
"vue": "^2.6.11",
"vuedraggable": "^2.24.3",
"vuex": "^3.2.0",
"vuex-persistedstate": "^4.0.0-beta.3"
"vuex-persistedstate": "^4.0.0-beta.3",
"wangeditor": "^4.7.10"
},
"devDependencies": {
"@babel/runtime": "~7.12.0",

View File

@@ -5,7 +5,7 @@
<u-input v-model="form.title" placeholder="请输入最多30字" maxlength="30"/>
</u-form-item>
<u-form-item label="详情描述" prop="content">
<AiTextarea v-model="form.content" placeholder="请输入最多500字" :maxlength="500"/>
<AiEditor v-model="form.content" placeholder="请输入最多500字" :maxlength="500"/>
</u-form-item>
<u-form-item label="图片最多9张" class="files">
<AiUploader multiple :limit="9" :def.sync="form.fileList" action="/admin/file/add2"/>

View File

@@ -60,7 +60,7 @@ export default {
},
data() {
return {
fullArea: [{name: '全', id: 0}],
fullArea: [{name: '全', id: 0}],
index: '',
list: [],
}
@@ -86,7 +86,7 @@ export default {
} else {
this.fullArea = res.data
}
this.fullArea.unshift({name: '全', id: 0})
this.fullArea.unshift({name: '全', id: 0})
}
})
},

265
src/components/AiEditor.vue Normal file
View File

@@ -0,0 +1,265 @@
<template>
<div class="AiEditor" @click="editing=true">
<div ref="AiEditorInstance"/>
<div class="bottomPanel" :class="{fixed:isFullScreen}">
<slot v-if="$slots.bottom" name="bottom"/>
<div v-else-if="maxlength" class="fontCount">{{ [editorText.length, maxlength].join(" / ") }}</div>
</div>
</div>
</template>
<script>
/**
* 原组件wangeditor封装
* 修改者:Kubbo
*/
import E from 'wangeditor'
export default {
name: "AiEditor",
inject: {
elFormItem: {default: ""},
elForm: {default: ''},
},
model: {
prop: "value",
event: "change"
},
props: {
value: {type: String, required: true, default: ""},
placeholder: {default: '请输入正文'},
conf: Object,
instance: {type: Function},
maxlength: Number,
valid: {type: Boolean, default: true}
},
data() {
return {
ins: null,
isFullScreen: false,
isPasteStyle: true,//粘贴是否携带格式
origin: "",
editorText: "",
editing: false//自动赋值问题,
}
},
computed: {
validateState() {
return ['', 'success'].includes(this.elFormItem?.validateState)
},
extra() {
return {
fullscreen(editor) {
if (editor?.ins.$toolbarElem) {
let btn = E.$(`<div class="w-e-menu" data-title="全屏"><i class="w-e-icon-fullscreen"/></div>`)
btn.on("click", () => {
editor.isFullScreen = !editor.isFullScreen
editor.isFullScreen ? editor.ins.fullScreen() : editor.ins.unFullScreen()
})
editor.ins.$toolbarElem.append(btn)
}
},
preview(editor) {
if (editor?.ins.$toolbarElem) {
let btn = E.$(`<div class="w-e-menu" data-title="预览"><i class="el-icon-monitor"/></div>`)
btn.on("click", () => {
editor.$refs.preview.dialog = true
})
editor.ins.$toolbarElem.append(btn)
}
},
pasteWithStyle(editor) {
if (editor?.ins.$toolbarElem) {
let btn = E.$(`<div class="w-e-menu w-e-active" data-title="粘贴格式"><i class="iconfont iconCopy"/></div>`)
editor.origin = JSON.parse(JSON.stringify(editor.value))
btn.on("click", () => {
editor.isPasteStyle = !editor.isPasteStyle
if (editor.isPasteStyle) {
editor.setContent(editor.origin)
btn.addClass("w-e-active")
} else {
editor.origin = JSON.parse(JSON.stringify(editor.value))
editor.setContent(editor.editorText)
btn.removeClass("w-e-active")
}
})
editor.ins.$toolbarElem.append(btn)
}
}
}
},
customConfig() {
let init = ["fullscreen", "preview", "pasteWithStyle"]
if (this.maxlength > 0) init = init.slice(0, 2)
return {
debug: true,
pasteFilterStyle: !this.isPasteStyle,
showFullScreen: false,
zIndexFullScreen: 1000,
zIndex: 98,
focus: false,
menus: [],
init,
customUploadImg: (files, insert) => {
this.uploadFile(files, insert)
},
customUploadVideo: (files, insert) => {
this.uploadFile(files, insert)
},
onfocus: () => {
this.editing = true
},
onblur: () => {
this.editing = false
},
onchange: html => {
if (this.maxlength > 0) {
this.editorText = html?.replace(/<\/?.+?\/?>/g, '')
if (this.editorText.length > this.maxlength) {
this.ins.history.revoke()
// this.editorText = this.editorText.substring(0, this.maxlength)
// this.setContent(this.editorText)
}
} else {
this.editorText = html
}
this.$emit("change", this.editorText)
},
pasteTextHandle: str => this.isPasteStyle ? str : str?.replace(/<\/?.+?\/?>/g, ''),
...this.conf
}
}
},
methods: {
initEditor() {
let {placeholder, customConfig} = this
this.ins = new E(this.$refs.AiEditorInstance)
this.ins.config = {...this.ins.config, ...customConfig, placeholder}
this.ins.create()
customConfig.init.map(e => this.extra?.[e]?.(this))
},
setContent(data) {
if (this.ins) {
this.ins.txt.html(data)
this.editing = false
}
},
uploadFile(files, insert) {
files && files.map(e => {
let formData = new FormData()
formData.append('file', e)
this?.instance?.post(`/admin/file/add`, formData).then(res => {
if (res && res.data) {
res.data.map(m => {
let item = m.split(";")
insert(item[0])
})
}
})
})
},
/**
* 表单验证
* @param componentName
* @param eventName
* @param params
*/
dispatch(componentName, eventName, params) {
let parent = this.$parent || this.$root;
let name = parent.$options.componentName;
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.componentName;
}
}
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params));
}
},
},
watch: {
value(v) {
this.dispatch('ElFormItem', 'el.form.change', [v]);
if (v && !this.editing) {
this.setContent(v)
}
},
placeholder(v) {
if (this.ins) {
document.querySelector('.AiEditor .placeholder').innerHTML = v
}
},
editing(v) {
}
},
mounted() {
!this.ins && this.initEditor()
}
}
</script>
<style lang="scss" scoped>
::v-deep.AiEditor {
width: 100%;
position: relative;
/* 菜单区 */
.w-e-toolbar {
align-items: center;
flex-wrap: wrap;
-webkit-box-lines: multiple;
.w-e-menu {
line-height: 24px;
a {
text-decoration: none;
}
&:hover {
z-index: 10002 !important;
}
}
}
/* 编辑区 */
.w-e-text {
overflow: auto;
padding: 10px;
p {
margin: 0;
}
}
.fontCount {
pointer-events: none;
color: #999;
}
.bottomPanel {
position: absolute;
bottom: 8px;
right: 24px;
z-index: 1999;
&.fixed {
position: fixed;
}
}
&.invalid {
.w-e-text-container, .w-e-toolbar {
border-color: red !important;
}
.fontCount {
color: red
}
}
}
</style>