Tinymce文件夹
dynamicLoadScript.js
let callbacks = []
function loadedTinymce() {
return window.tinymce
}
const dynamicLoadScript = (src, callback) => {
const existingScript = document.getElementById(src)
const cb = callback || function() {}
if (!existingScript) {
const script = document.createElement('script')
script.src = src
script.id = src
document.body.appendChild(script)
callbacks.push(cb)
const onEnd = 'onload' in script ? stdOnEnd : ieOnEnd
onEnd(script)
}
if (existingScript && cb) {
if (loadedTinymce()) {
cb(null, existingScript)
} else {
callbacks.push(cb)
}
}
function stdOnEnd(script) {
script.onload = function() {
this.onerror = this.onload = null
for (const cb of callbacks) {
cb(null, script)
}
callbacks = null
}
script.onerror = function() {
this.onerror = this.onload = null
cb(new Error('Failed to load ' + src), script)
}
}
function ieOnEnd(script) {
script.onreadystatechange = function() {
if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
this.onreadystatechange = null
for (const cb of callbacks) {
cb(null, script)
}
callbacks = null
}
}
}
export default dynamicLoadScript
index.vue
<template>
<div
:class="{ fullscreen: fullscreen }"
class="tinymce-container"
:style="{ width: containerWidth }"
>
<textarea :id="tinymceId" class="tinymce-textarea" />
</div>
</template>
<script>
import load from './dynamicLoadScript'
const tinymceCDN = 'https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js'
const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']
const toolbar = ['bold italic underline strikethrough alignleft aligncenter alignright outdent indent undo redo removeformat subscript superscript code hr bullist numlist link charmap insertdatetime table emoticons forecolor backcolor fullscreen']
export default {
name: 'Tinymce',
props: {
id: {
type: String,
default: function() {
return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
},
},
value: {
type: String,
default: '',
},
toolbar: {
type: Array,
required: false,
default() {
return []
},
},
height: {
type: [Number, String],
required: false,
default: 360,
},
width: {
type: [Number, String],
required: false,
default: 'auto',
},
},
data() {
return {
hasChange: false,
hasInit: false,
tinymceId: this.id,
fullscreen: false,
languageTypeList: {
en: 'en',
zh: 'zh_CN',
es: 'es_MX',
ja: 'ja',
},
}
},
computed: {
containerWidth() {
const width = this.width
if (/^[\d]+(\.[\d]+)?$/.test(width)) {
return `${width}px`
}
return width
},
},
watch: {
value(val) {
if (!this.hasChange && this.hasInit) {
this.$nextTick(() => window.tinymce.get(this.tinymceId).setContent(val || ''))
}
},
},
mounted() {
this.init()
},
activated() {
if (window.tinymce) {
this.initTinymce()
}
},
deactivated() {
this.destroyTinymce()
},
destroyed() {
this.destroyTinymce()
},
methods: {
init() {
load(tinymceCDN, err => {
if (err) {
this.$message.error(err.message)
return
}
this.initTinymce()
})
},
initTinymce() {
const _this = this
window.tinymce.init({
selector: `#${this.tinymceId}`,
language: this.languageTypeList['zh_CN'],
height: this.height,
body_class: 'panel-body ',
object_resizing: false,
toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
menubar: this.menubar || false,
plugins: plugins,
end_container_on_empty_block: true,
powerpaste_word_import: 'clean',
code_dialog_height: 450,
code_dialog_width: 1000,
advlist_bullet_styles: 'square',
advlist_number_styles: 'default',
imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
default_link_target: '_blank',
link_title: false,
nonbreaking_force_tab: true,
init_instance_callback: editor => {
if (_this.value) {
editor.setContent(_this.value)
}
_this.hasInit = true
editor.on('NodeChange Change KeyUp SetContent', () => {
this.hasChange = true
this.$emit('input', editor.getContent())
})
},
setup(editor) {
editor.on('FullscreenStateChanged', e => {
_this.fullscreen = e.state
})
},
convert_urls: false,
})
},
destroyTinymce() {
const tinymce = window.tinymce.get(this.tinymceId)
if (this.fullscreen) {
tinymce.execCommand('mceFullScreen')
}
if (tinymce) {
tinymce.destroy()
}
},
setContent(value) {
window.tinymce.get(this.tinymceId).setContent(value)
},
getContent() {
window.tinymce.get(this.tinymceId).getContent()
},
imageSuccessCBK(arr) {
arr.forEach(v =>
window.tinymce
.get(this.tinymceId)
.insertContent(`<img class="wscnph" src="${v.url}" >`)
)
},
},
}
</script>
<style lang="scss" scoped>
.tinymce-container {
position: relative;
line-height: normal;
}
.tinymce-container {
::v-deep {
.mce-fullscreen {
z-index: 10000;
}
}
}
.tinymce-textarea {
visibility: hidden;
z-index: -1;
}
.editor-custom-btn-container {
position: absolute;
right: 4px;
top: 4px;
/*z-index: 2005;*/
}
.fullscreen .editor-custom-btn-container {
z-index: 10000;
position: fixed;
}
.editor-upload-btn {
display: inline-block;
}
</style>
使用
EmailSend.vue
<template>
<div class="content">
<el-form :model="form" ref="form" :inline="true" class="content-form" label-position="right" label-width="8%">
<el-form-item label="Date" prop="dailyDate" class="emailDate" v-if="templateName == 'mlMonthlyCostRate'">
<el-date-picker
@change="getEmailSubject"
v-model="date"
type="month"
value-format="yyyy-MM"
placeholder="Date" />
</el-form-item>
<el-form-item prop="title" label="邮件主题" class="email" >
<el-select v-model="form.id" placeholder="邮件主题" class="email-input" filterable @change="getEamilData">
<el-option
v-for="item in emailTemplateList"
:key="item.id"
:label="item.subject"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item prop="name" label=" 收 件 人" class="email">
<el-tooltip effect="dark" placement="top" :disabled="!mailRecipientTooltip">
<div slot="content" v-html="mailRecipientTooltip"></div>
<el-input v-model="mailRecipient" clearable class="input-with-select" placeholder="收 件 人" @clear="clearMailRecipient">
<el-select v-model="emailGroup" slot="prepend" multiple collapse-tags placeholder="邮件组" class="eamil-group" @change="changeEmailGroup" value-key="id">
<el-option
v-for="item in emailGroupList"
:key="item.id"
:label="item.mailGroupName"
:value="item">
</el-option>
</el-select>
</el-input>
</el-tooltip>
</el-form-item>
<el-form-item prop="name" label=" 抄 送 人" class="email">
<el-tooltip effect="dark" placement="top" :disabled="!mailCarbonCopyRecipientTooltip">
<div slot="content" v-html="mailCarbonCopyRecipientTooltip"></div>
<el-input v-model="form.mailCarbonCopyRecipient" class="email-input" placeholder="抄 送 人" disabled></el-input>
</el-tooltip>
</el-form-item>
<el-form-item prop="name" label=" 附 件 " class="email">
<el-link type="primary" :underline="false" @click="dowloadFile">{{ attachmentName }}</el-link>
</el-form-item>
<div style="width:99%;height: 300px;">
<tinymce v-model="content" :height="260" ref="tinymce"/>
</div>
</el-form>
</div>
</template>
<script>
import Tinymce from '@/components/Tinymce'
import { Base64 } from 'js-base64'
import {
emailPreview,
mailAddrGroup,
getSubjects,
downLoadMailAttachments,
saveAndSend
} from '../baseApi'
export default {
components: { Tinymce },
props: ['dailyDate','templateName'],
data() {
return {
form: {},
content: '',
emailUserList: [],
emailGroupList: [],
emailGroup: [],
emailTemplateList: [],
mailRecipient: '',
attachmentName: '',
attachmenId: '',
mailRecipientTooltip: '',
mailCarbonCopyRecipientTooltip: '',
date: this.getMonth()
}
},
watch: {
emailTemplateList(val) {
if(val.length > 0) {
this.$set(this.form,'id',this.emailTemplateList[0]?.id)
this.getEamilData()
}
},
mailRecipient() {
this.$set(this.form,'mailRecipient', this.mailRecipient)
}
},
mounted() {
this.getEmailSubject()
},
methods: {
getMonth() {
const y = new Date().getFullYear()
let m = new Date().getMonth()
m = m < 10 ? '0' + m : m
return [y, m].join('-')
},
getEmailSubject() {
const param = {
dailyDate: this.dailyDate || this.date,
templateName: this.templateName
}
getSubjects(param).then(({data})=> {
this.emailTemplateList = data
})
.finally(()=> this.emailLoading = false)
.catch(err => err)
},
getEamilData() {
const param = {
templateId: this.form.id,
dailyDate: this.dailyDate || this.date
}
if(!param.templateId) {
this.$message.warning('请选择邮件主题')
return
}
emailPreview(param).then(({data}) => {
this.form = {...data}
this.mailRecipient = data.mailRecipient
const mailContent = Base64.decode (data.mailContent)
this.attachmentName = data.attachments[0]?.name
this.attachmenId = data.attachments[0]?.id
this.content = mailContent
this.$refs.tinymce.setContent(this.content)
this.getEmailGroup()
})
},
getEmailGroup() {
const param = {
page: 1,
pageSize: 999,
templateId: this.form.id
}
mailAddrGroup(param).then(({data})=> {
this.emailGroupList = data.rows
})
},
changeEmailGroup() {
const mailRecipient = this.emailGroup.map(item =>item.mailRecipient).join(';')
const mailCarbonCopyRecipient = this.emailGroup.map(item =>item.mailCarbonCopyRecipient).join(';')
this.mailRecipient = mailRecipient
this.$set(this.form,'mailCarbonCopyRecipient', mailCarbonCopyRecipient)
if(this.mailRecipient.length > 120) this.mailRecipient = this.mailRecipient.substring(0,120) + '...'
this.mailRecipientTooltip = mailRecipient.split(';').join('</br>')
this.mailCarbonCopyRecipientTooltip = mailCarbonCopyRecipient.split(';').join('</br>')
},
clearMailRecipient() {
this.emailGroup = []
this.form.mailCarbonCopyRecipient = ''
},
dowloadFile() {
downLoadMailAttachments({id:this.attachmenId}).then(res => {
const type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
let blob = new Blob([res], {type: type})
let downloadElement = document.createElement('a')
let href = window.URL.createObjectURL(blob)
downloadElement.href = href
downloadElement.download = res.fileName
document.body.appendChild(downloadElement)
downloadElement.click()
document.body.removeChild(downloadElement)
window.URL.revokeObjectURL(href)
})
},
sendEmail() {
const param = {
...this.form,
mailContent: Base64.encode(this.content)
}
if(!this.form.id || !this.mailRecipient) {
this.$message.warning('请选择邮件主题或者收件人')
return
}
saveAndSend(param).then(({err_code,msg})=> {
if(err_code == 20000) {
this.$message.success(msg)
}else {
this.$message.error(msg)
}
})
.catch(err => err)
},
},
}
</script>
<style scoped lang="scss">
.content {
display: flex;
.content-form {
flex:1;
}
}
.editor-content {
margin-top: 20px;
}
.emailDate {
width: 100%;
.el-form-item__content {
width: 50%;
}
}
::v-deep .email {
width: 100%;
.el-form-item__content {
width: 90%;
}
}
::v-deep .el-dialog__header {
text-align: left;
}
::v-deep .el-input-group__prepend {
width: 20%;
padding-right: 0;
padding-left: 10px;
}
::v-deep .eamil-group > .el-input--suffix{
right: -15px !important;
}
</style>