vueup/vue-quill 的用法

发布时间 2023-06-19 16:58:46作者: 热心市民~菜先生
<template>
<div class="EmailDialog">
<div
class="EmailDialog-main"
:style="{ borderColor: isShow ? '#474edb' : '#f0f2fc' }"
@click="openDialogHandle"
>
<img :src="EditIcon" alt="" />
<!-- 编辑邮件内容 -->
{{ store.state.languageObj['system_form_flow_action_editemailtext'] }}
</div>
<div class="EmailDialog-dialog" v-if="isShow">
<div class="EmailDialog-dialog-main" @click="stopCloseHandle($event)">
<div class="EmailDialog-dialog-title">
{{ store.state.languageObj['system_form_flow_action_editemailtext'] }}
</div>
<div class="EmailDialog-dialog-scrollbar">
<div class="subject-view">
<input class="subject-title" v-model="subjectVal" placeholder="请输入邮件主题" />
</div>
<div class="subject-view">
<QuillEditor theme="snow" ref="quillRef" contentType="html" v-model:content="textVal" :options="quillOption" />
<input
type="file"
id="uploadImageFile"
@change="uploadImageChangeHandle"
style="opacity: 0"
/>
<!--<Toolbar
style="border-bottom: 1px solid #ccc"
:editor="editorRef"
:defaultConfig="toolbarConfig"
:mode="mode"
/>
<Editor
style="height: 240px; overflow-y: hidden;"
v-model="valueHtml"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="handleCreated"
/>-->
</div>
<div class="ImageEditDialog-main" @click.stop>
<div class="email-label">
<!-- 上传附件 -->
{{ store.state.languageObj['formdata_file_uploadfile'] }}
</div>
<div class="ImageEditDialog-addBtn" @click="uploadHandle">
<span>+</span>
<!-- 点击此处进行上传图片 -->
{{ store.state.languageObj['formdata_file_uploadfile'] }}
<input
type="file"
id="uploadFile"
@change="uploadChangeHandle"
multiple="multiple"
/>
</div>
<div class="ImageEditDialog-img-wrapper scrollbar">
<div
class="FormDataFile-item"
v-for="(item, idx) in fileData"
:key="idx"
:style="{ marginRight: (idx + 1) % 2 === 0 ? '0' : '65px' }"
>
<div class="FormDataFile-item-top">
<div class="FormDataFile-item-top-left">
<div class="FormDataFile-item-top-left-name">
{{ item.created_uname }}
</div>
<div class="FormDataFile-item-top-left-date">
{{ item.created_time ? item.created_time.split(' ')[0] : '' }}
</div>
</div>
<div class="FormDataFile-item-top-right" @click="downloadHandle(item)">
<img :src="downloadIcon" alt="" />
</div>
</div>
<div class="FormDataFile-item-bottom">
<div class="FormDataFile-item-bottom-main">
<img :src="fileIcon[item.file_ext]" alt="" />
<div class="FormDataFile-item-bottom-main-content">
<div class="FormDataFile-item-bottom-main-name">
{{ item.file_name }}
</div>
<div class="FormDataFile-item-bottom-main-size">
{{ item.file_size }}
</div>
</div>
</div>
<div class="FormDataFile-item-bottom-close" @click="delHandle(item)" />
</div>
</div>
</div>
<!--<textarea class="scrollbar" v-model="textVal" placeholder="请输入邮件内容" />-->
</div>
<div class="EmailDialog-dialog-btn">
<div @click="confirmHandle">
{{ store.state.languageObj['global_confirm_btn'] }}
</div>
<div @click="closeDialogHandle">
{{ store.state.languageObj['global_cancel_btn'] }}
</div>
</div>
</div>
</div>
</div>
</div>
</template>

<script>
import { defineComponent, onMounted, reactive, ref, toRefs, watch, nextTick, shallowRef } from 'vue'
import { QuillEditor } from '@vueup/vue-quill'
import '@vueup/vue-quill/dist/vue-quill.snow.css'

import EditIcon from '/@/assets/image/edit-active-icon.png'
import LinkIcon from '/@/assets/image/link-icon.png'
import { createPrompt } from '/@/utils/prompt'
import { _$promise } from '/@/api/index'
import { useStore } from 'vuex'
import downloadIcon from '/@/assets/image/detail-dialog-download.png'
import uploadIcon from '/@/assets/image/detail-dialog-upload.png'
import DocIcon from '/@/assets/image/doc-icon.png'
import PdfIcon from '/@/assets/image/pdf-icon.png'
import PsdIcon from '/@/assets/image/psd-icon.png'
import PptIcon from '/@/assets/image/ppt-icon.png'
import TxtIcon from '/@/assets/image/txt-icon.png'
import OtherIcon from '/@/assets/image/other-icon.png'
import XlsxIcon from '/@/assets/image/xlsx-icon.png'
import XmlIcon from '/@/assets/image/xml-icon.png'
import ZipIcon from '/@/assets/image/zip-icon.png'

export default defineComponent({
name: 'EmailDialog',
components: {
QuillEditor
},
props: {
id: {
type: String,
required: true
},
formId: {
type: String,
required: true
},
flowId: {
type: String,
required: true
},
val: {
type: Object
},
emailTitle: {
type: String
},
attachments: {
type: Array,
default: () => []
}
},
emits: ['EmailDialogHandle'],
setup(props, context) {
const store = useStore()
const quillRef = ref(null)
// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef()
// 内容 HTML
const valueHtml = ref('<p>hello</p>')

const state = reactive({
data: [],
isShowViewImageBool: false,
LinkIcon,
EditIcon,
isShow: false,
textVal: '',
subjectVal: '',
downloadIcon,
uploadIcon,
fileData: [],
fileIcon: {
zip: ZipIcon,
txt: TxtIcon,
xml: XmlIcon,
xlsx: XlsxIcon,
ppt: PptIcon,
psd: PsdIcon,
pdf: PdfIcon,
doc: DocIcon,
docx: DocIcon,
png: OtherIcon,
jpeg: OtherIcon,
jpg: OtherIcon,
xls: XlsxIcon
},
content: '<h2>freddy</h2>',
quillOption: {
contentType: 'html',
theme: 'snow', // 主题
placeholder: '',
modules: {
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'],
['blockquote', 'code-block'],
[{ header: 1 }, { header: 2 }],
[{ list: 'ordered' }, { list: 'bullet' }],
[{ script: 'sub' }],
[{ indent: '-1' }, { indent: '+1' }],
[{ direction: 'rtl' }],
[{ size: ['small', false, 'large', 'huge'] }],
[{ header: [1, 2, 3, 4, 5, 6, false] }],
[{ color: [] }, { background: [] }],
[{ font: [''] }],
[{ align: [] }],
['clean', 'link', 'image']
], // 自定义工具栏选项
handlers: {
'image': function(value) {
if (value) {
const file = document.getElementById('uploadImageFile')
file.click()
}
}
}
}
}
}
})

onMounted(() => {
setTimeout(() => {
valueHtml.value = '<p>模拟 Ajax 异步设置内容</p>'
}, 1500)
})
watch(
() => state.isShow,
() => {
if (state.isShow) {
state.textVal = props.val
state.subjectVal = props.emailTitle
state.fileData = props.attachments || []
nextTick(() => {
// quillRef.value.setHTML(data.content)
valueHtml.value = state.textVal
})
}
}
)

function openDialogHandle() {
state.isShow = true
}
function closeDialogHandle() {
state.isShow = false
state.fileData = []
state.emailTitle = ''
state.textVal = ''
}

function stopCloseHandle(e) {
e.stopPropagation()
}

function confirmHandle() {
state.isShow = false
const obj = {
emailTitle: state.subjectVal,
content: state.textVal,
attachments: state.fileData
}
context.emit('EmailDialogHandle', obj)
}

async function uploadImageChangeHandle(eObj) {
const file = eObj.target.files

if (!file.length) {
return
}

let bool = false
for (const item of file) {
const idx = item.name.lastIndexOf('.')
const str = item.name.substring(idx + 1)
if (str !== 'jpeg' && str !== 'jpg' && str !== 'png') {
bool = true
break
}
}

if (bool) {
createPrompt({
callBack() {},
type: 'error',
btnText: store.state.languageObj['global_know_btn'],
title: store.state.languageObj['global_img_formatdesc']
})
return
}

const res = await _$promise({
url: '/newadmin/FormData/uploadImages',
type: 'post',
formData: true,
data: {
'files[]': file
}
})
if (res.status !== 1) {
createPrompt({
callBack() {},
type: 'error',
btnText: store.state.languageObj['global_know_btn'],
title: res.info
})
return
}
const quill = quillRef.value.getQuill()
const range = quill.getSelection(true)
quill.insertEmbed(range, 'image', res.data[0].file_path)
}

function uploadHandle() {
const file = document.getElementById('uploadFile')
file.click()
}
async function uploadChangeHandle(eObj) {
const file = eObj.target.files

if (!file.length) {
return
}

const bool = false
/* for (const item of file) {
/* const idx = item.name.lastIndexOf('.')
/* const str = item.name.substring(idx + 1)
if (str !== 'jpeg' && str !== 'jpg' && str !== 'png') {
bool = true
break
}
}*/

if (bool) {
createPrompt({
callBack() {},
type: 'error',
btnText: store.state.languageObj['global_know_btn'],
title: store.state.languageObj['global_img_formatdesc']
})
return
}
// emailTitle:''
// attachmentIds []
let type = 'update'
if (props.formId === '' || props.formId === null || props.formId === undefined || props.formId === '0') {
type = 'addNew'
}
const res = await _$promise({
url: '/newadmin/FormData/uploadAttachment',
type: 'post',
formData: true,
data: {
formId: props.formId,
flowId: props.flowId,
type: type,
'files[]': file
}
})
if (res.status !== 1) {
createPrompt({
callBack() {},
type: 'error',
btnText: store.state.languageObj['global_know_btn'],
title: res.info
})
return
}
state.fileData = state.fileData.concat(res.data)
}

function viewImageHandle(valStr) {
state.currentIdx = valStr
state.isShowViewImageBool = true
}

function downloadHandle(obj) {
window.open(obj.file_path)
}

function delHandle(idxStr) {
state.fileData.splice(idxStr, 1)
}

/* function delHandle(obj) {
createPrompt({
okHandle: async() => {
try {
const res = await _$promise({
url: '/newadmin/FormData/deleteAttachment',
type: 'post',
jsonType: true,
data: {
id: obj.id
}
})
if (res.status !== 1) {
createPrompt({
callBack() {},
type: 'error',
btnText: store.state.languageObj['global_know_btn'],
title: res.info
})
return
}
// context.emit('refreshFileHandle')
} catch (err) {
console.log(err)
}
},
noHandle() {},
type: 'warning',
okText: store.state.languageObj['global_confirm_btn'],
noText: store.state.languageObj['global_cancel_btn'],
title: store.state.languageObj['formdata_file_deletetitle'],
desc: store.state.languageObj['global_delete_record_desc']
})
}*/

return {
store,
quillRef,
...toRefs(state),
openDialogHandle,
closeDialogHandle,
stopCloseHandle,
confirmHandle,
uploadHandle,
uploadChangeHandle,
viewImageHandle,
delHandle,
downloadHandle,
uploadImageChangeHandle,
editorRef,
valueHtml,
mode: 'default' // 或 'simple'
}
}
})
</script>

<style scoped>
.EmailDialog-main {
display: flex;
justify-content: center;
align-items: center;
height: 50px;
width: 100%;
border: 1px solid #474edb;
border-radius: 5px;
color: #474edb;
font-size: 14px;
font-weight: 500;
background-color: #f0f2fc;
cursor: pointer;
box-sizing: border-box;
}
.EmailDialog-main img {
width: 20px;
height: 20px;
margin-right: 15px;
}
.EmailDialog-dialog {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.EmailDialog-dialog-main {
width: 800px;
height: auto;
background-color: #fff;
box-shadow: 0px 10px 30px rgba(84, 84, 84, 0.25);
border-radius: 10px;
box-sizing: border-box;
padding: 35px 30px 60px;
position: relative;
}
.EmailDialog-dialog-scrollbar {
height: calc(100% - 28px);
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.EmailDialog-dialog-title {
font-size: 20px;
font-weight: 500;
color: #14163c;
line-height: 28px;
text-align: center;
background: #fff;
padding-bottom:10px;
}
.EmailDialog-dialog-btn {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
display: flex;
box-sizing: border-box;
border-top: 1px solid #e5e9f5;
height: 60px;
}
.EmailDialog-dialog-btn div {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
font-size: 16px;
font-weight: 600;
cursor: pointer;
box-sizing: border-box;
color: #bbc2d0;
}
.EmailDialog-dialog-btn div:nth-child(1) {
color: #474edb;
border-right: 1px solid #e5e9f5;
}

.EmailDialog-dialog-scrollbar input{
background: #fafafb;
border: 1px solid #e5e9f5;
box-sizing: border-box;
border-radius: 5px;
resize: none;
outline: none;
width: 100%;
height: 40px;
box-sizing: border-box;
overflow: auto;
padding: 15px;
font-size: 14px;
color: #14163b;
margin-bottom: 20px;
}
.EmailDialog-dialog-scrollbar textarea {
background: #fafafb;
border: 1px solid #e5e9f5;
box-sizing: border-box;
border-radius: 5px;
resize: none;
outline: none;
width: 500px;
height: 100px;
box-sizing: border-box;
overflow: auto;
padding: 15px;
font-size: 14px;
color: #14163b;
}

.EmailDialog-dialog-scrollbar .subject-view{
width:100%;
overflow-y: auto;
}

.ImageEditDialog-main{
width:100%;
box-sizing: border-box;
}

.ImageEditDialog-addBtn {
border: 1px dashed #bec8d7;
border-radius: 5px;
display: flex;
justify-content: center;
align-items: center;
color: #bec8d7;
width: 100%;
height: 75px;
margin: 10px auto 0;
font-size: 14px;
cursor: pointer;
position: relative;
}
.ImageEditDialog-addBtn input {
position: absolute;
width: 100%;
height: 100%;
outline: none;
border: none;
background-color: transparent;
z-index: -1;
}
.ImageEditDialog-addBtn span {
font-size: 16px;
margin-right: 5px;
}
.close-image {
width: 15px;
height: 15px;
background-color: #fd7979;
border-radius: 50%;
position: absolute;
top: -7px;
right: -7px;
cursor: pointer;
}
.close-image::before {
position: absolute;
width: 8px;
height: 1px;
background-color: #fff;
content: '';
top: 50%;
left: 50%;
margin-left: -4px;
transform: rotate(45deg);
}
.close-image::after {
position: absolute;
width: 8px;
height: 1px;
background-color: #fff;
content: '';
top: 50%;
left: 50%;
margin-left: -4px;
transform: rotate(-45deg);
}
.ImageEditDialog-img-wrapper {
padding: 20px 55px 0;
box-sizing: border-box;
height: calc(100% - 29px - 105px);
overflow: auto;
display: flex;
align-content: flex-start;
flex-wrap: wrap;
}
.ImageEditDialog-img-item {
position: relative;
margin-right: 25px;
margin-bottom: 20px;
width: 90px;
height: 80px;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
}
.ImageEditDialog-img-item img {
max-width: 100%;
width:150px;
max-height: 100%;
cursor: pointer;
}
.email-label {
color: #14163c;
font-size: 15px;
font-weight: 500;
margin-top:20px;
}
.ql-editor img{
max-width:100%!important;
}

.scrollbar::-webkit-scrollbar {
width: 5px;
}
.scrollbar::-webkit-scrollbar-thumb {
border-radius: 10px;
background-color: rgba(106, 117, 202, 0.5) !important;
}
.scrollbar::-webkit-scrollbar-track {
background-color: #fff;
}

.ql-container::-webkit-scrollbar {
width: 5px;
}
.ql-container::-webkit-scrollbar-thumb {
border-radius: 10px;
background-color: rgba(106, 117, 202, 0.5) !important;
}
.ql-container::-webkit-scrollbar-track {
background-color: #fff;
}

.FormDataFile-item {
width: 280px;
box-sizing: border-box;
margin-right: 74px;
margin-bottom: 30px;
}
.FormDataFile-item-top {
display: flex;
justify-content: space-between;
}
.FormDataFile-item-top-left-name {
font-weight: 600;
font-size: 18px;
color: #4d5472;
line-height: 25px;
}
.FormDataFile-item-top-left-date {
font-size: 12px;
color: #9ba5b9;
}
.FormDataFile-item-top-right {
width: 32px;
height: 32px;
cursor: pointer;
}
.FormDataFile-item-top-right img {
width: 100%;
}
.FormDataFile-item-bottom {
padding: 15px 25px 15px 20px;
box-sizing: border-box;
position: relative;
background: #ffffff;
border: 1px solid #bbc2d0;
border-radius: 5px;
margin-top: 10px;
}
.FormDataFile-item-bottom-close {
width: 20px;
height: 20px;
position: absolute;
right: -10px;
top: -10px;
background-color: #fd7979;
border-radius: 50%;
z-index: 10;
cursor: pointer;
}
.FormDataFile-item-bottom-close::before {
width: 10px;
height: 1px;
background-color: #fff;
position: absolute;
top: 50%;
left: 50%;
margin-left: -5px;
content: '';
transform: rotate(45deg);
}
.FormDataFile-item-bottom-close::after {
width: 10px;
height: 1px;
background-color: #fff;
position: absolute;
top: 50%;
left: 50%;
margin-left: -5px;
content: '';
transform: rotate(-45deg);
}
.FormDataFile-item-bottom-main {
display: flex;
}
.FormDataFile-item-bottom-main img {
width: 38px;
height: 44px;
margin-right: 10px;
}
.FormDataFile-item-bottom-main-content {
width: calc(100% - 38px);
}
.FormDataFile-item-bottom-main-name {
font-size: 18px;
font-weight: 600;
color: #4d5472;
line-height: 25px;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.FormDataFile-item-bottom-main-size {
font-size: 14px;
color: #6a7288;
}
</style>