Tinymce

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>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zero0985

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值