You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
7.0 KiB
231 lines
7.0 KiB
|
|
<script lang='ts' setup>
|
|
import { ref, onMounted } from "vue";
|
|
import tinymce from "tinymce/tinymce";
|
|
import "tinymce/models/dom"; // 特别注意 tinymce 6.0.0 版本之后必须引入,否则不显示
|
|
import "tinymce/themes/silver/theme";
|
|
import Editor from "@tinymce/tinymce-vue"; // 引入组件
|
|
import { v4 as uuidv4 } from "uuid";
|
|
import { ElMessage } from 'element-plus'
|
|
|
|
let onlyNumber = uuidv4().replaceAll('-','').toString(); //获取唯一编码
|
|
|
|
/**
|
|
* 初始富文本组件
|
|
*/
|
|
const tinymceInit = {
|
|
selector: "#"+onlyNumber,
|
|
language_url: "/tinymce/langs/zh-Hans.js", // 引入语言包(该语言包在public下,注意文件名称)
|
|
language: "zh-Hans", // 这里名称根据 zh-Hans.js 里面写的名称而定
|
|
skin_url: "/tinymce/skins/ui/oxide", // 这里引入的样式
|
|
height: 260, // 限制高度
|
|
statusbar:false,
|
|
toolbar:false,
|
|
branding: false, //是否禁用“Powered by TinyMCE”
|
|
menubar: false, //顶部菜单栏显示
|
|
forced_root_block:'',
|
|
newline_behavior:"",
|
|
content_css: "/tinymce/skins/content/default/content.css", //以css文件方式自定义可编辑区域的css样式,css文件需自己创建并引入
|
|
auto_focus : true,
|
|
}
|
|
const props = defineProps({
|
|
aftText:{
|
|
type: String,
|
|
default(){
|
|
return {}
|
|
}
|
|
},
|
|
aftTextCopy:{
|
|
type: String,
|
|
default(){
|
|
return {}
|
|
}
|
|
},
|
|
})
|
|
|
|
let $emit = defineEmits(["textChange","gongshiChange"]);
|
|
|
|
const tinymceHtml = ref("")
|
|
tinymceHtml.value = props.aftText
|
|
const tinymceBox = ref(null)
|
|
|
|
|
|
onMounted(() => {
|
|
tinymce.init({}); // 初始化富文本
|
|
});
|
|
watch(()=>tinymceHtml.value, (val:any) => {
|
|
$emit('textChange',val);
|
|
nextTick(()=>{
|
|
let formulaOne = [];
|
|
let formulaTwo = [];
|
|
tinymceBox.value.childNodes.forEach(element => {
|
|
|
|
element.childNodes.forEach(child => {
|
|
formulaOne.push(child.innerText?child.innerText:child.data)
|
|
if(child.dataset&&child.dataset.keyid){
|
|
formulaTwo.push(child.dataset.keyid)
|
|
}else{
|
|
formulaTwo.push(child.innerText?child.innerText:child.data)
|
|
}
|
|
})
|
|
});
|
|
let suanShitwo = formulaTwo.join('').replace(/\s+/g, "");
|
|
let gongShi ={
|
|
formulaHtml:tinymceBox.value.innerHTML,
|
|
mathsString:tinymceBox.value.innerText,
|
|
mathsFormula:suanShitwo,
|
|
}
|
|
$emit('gongshiChange',gongShi);
|
|
|
|
if(containsNewline(gongShi.mathsString)){
|
|
errorCondition("条件不允许换行")
|
|
}else if(!gongShi.formulaHtml.startsWith("<p><span")){
|
|
errorCondition("条件需以蓝色块开头")
|
|
}else if(gongShi.formulaHtml.endsWith("</span></p>")){
|
|
errorCondition("条件不能以蓝色块结尾")
|
|
}else if(countSpanTags(gongShi.formulaHtml)>1){
|
|
errorCondition("不允许出现多个蓝色块")
|
|
}else if(!containsSingleComparator(gongShi.mathsFormula)){
|
|
errorCondition("不存在有效符号")
|
|
}else if(checkEnding(gongShi.mathsFormula)){
|
|
errorCondition("不能以符号为结尾")
|
|
}else{
|
|
succCondition()
|
|
}
|
|
})
|
|
|
|
},
|
|
{ deep: true }
|
|
)
|
|
function checkEnding(str: string) {
|
|
const symbols = ['==', '>=', '>', '<=', '<', '!=', '='];
|
|
const trimmedStr = str.trim();
|
|
for (let symbol of symbols) {
|
|
if (trimmedStr.endsWith(symbol)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function containsSingleComparator(str: string) {
|
|
// 定义需要检查的运算符
|
|
const comparators = ['==', '>=', '>', '<=', '<', '!='];
|
|
let found = false; // 用于标记是否找到运算符
|
|
let i = 0; // 字符串索引
|
|
|
|
while (i < str.length - 1) { // 至少需要两个字符来形成运算符
|
|
// 遍历每个可能的运算符
|
|
for (const comparator of comparators) {
|
|
if (str.substr(i, comparator.length) === comparator) {
|
|
// 如果找到了一个运算符
|
|
if (found) {
|
|
// 如果已经找到了一个运算符,则返回false
|
|
return false;
|
|
}
|
|
found = true; // 标记为已找到
|
|
// 跳过当前找到的运算符的剩余部分,避免重复检查
|
|
i += comparator.length - 1;
|
|
break; // 跳出内层循环
|
|
}
|
|
}
|
|
i++; // 继续检查下一个字符
|
|
}
|
|
|
|
// 检查是否只找到了一个运算符
|
|
return found;
|
|
}
|
|
|
|
function containsComparator(str: string) {
|
|
if(str.includes("==")||str.includes("!=")||str.includes(">")||str.includes(">=")||str.includes("<")||str.includes("<=")){
|
|
return true
|
|
}else{
|
|
return false
|
|
}
|
|
}
|
|
const containsNewline = (str: string) => {
|
|
//console.log("Testing string:", str); // 查看传递给函数的实际字符串
|
|
return /\n/.test(str);
|
|
};
|
|
const countSpanTags = (str: string) => {
|
|
// 使用正则表达式匹配所有出现的<span>(不考虑闭合标签或属性)
|
|
const matches = str.match(/<span\b[^>]*>/gi);
|
|
// 如果matches是null,表示没有找到匹配项,返回0
|
|
// 否则,返回匹配项数组的长度
|
|
return matches ? matches.length : 0;
|
|
};
|
|
function succCondition(){
|
|
ElMessage.closeAll()
|
|
ElMessage({
|
|
showClose: true,
|
|
message: '条件格式校验通过',
|
|
type: 'success',
|
|
duration:3500,
|
|
})
|
|
}
|
|
|
|
function errorCondition(str:string){
|
|
ElMessage.closeAll()
|
|
ElMessage({
|
|
showClose: true,
|
|
message: '条件格式错误 : '+str+' , 正确条件格式如 : 年龄==10',
|
|
type: 'error',
|
|
duration:3500,
|
|
})
|
|
}
|
|
|
|
|
|
const addIcon = (currentObject:any) =>{
|
|
tinymce.activeEditor?.execCommand('mceInsertContent', false, `<span style="margin:3px;background-color: #4189EF;border-radius: 5px; padding:3px" contenteditable="false" data-keyid= "${currentObject.id}" >${currentObject.label}</span>`);
|
|
}
|
|
const addIcon_field = (currentObject:any) =>{
|
|
tinymce.activeEditor?.execCommand('mceInsertContent', false, `<span style="margin:3px;background-color: #4189EF;border-radius: 5px; padding:3px" contenteditable="false" data-keyid= "${currentObject.id}" >${currentObject.treeAttrs.show}</span>`);
|
|
}
|
|
const addIcon_org = (currentObject:any) =>{
|
|
let id = "orgOrPerson:"+currentObject.id
|
|
tinymce.activeEditor?.execCommand('mceInsertContent', false, `<span style="margin:3px;background-color: #4189EF;border-radius: 5px; padding:3px" contenteditable="false" data-keyid= "${id}" >${currentObject.label}</span>`);
|
|
}
|
|
//取消
|
|
const handelCancel = (associatedFormsHideDialogTextCopy:any) =>{
|
|
tinymceHtml.value = associatedFormsHideDialogTextCopy
|
|
}
|
|
const tinymceReInit = ()=>{
|
|
|
|
|
|
let str:string = props.aftTextCopy
|
|
}
|
|
const focusEditor = ()=>{
|
|
tinymce.EditorManager.get(onlyNumber)?.focus(true)
|
|
}
|
|
|
|
|
|
|
|
defineExpose({
|
|
tinymceHtml,
|
|
addIcon,
|
|
addIcon_org,
|
|
addIcon_field,
|
|
handelCancel,
|
|
tinymceReInit,
|
|
focusEditor,
|
|
})
|
|
|
|
</script>
|
|
<template >
|
|
<div >
|
|
<editor :id="onlyNumber" v-model="tinymceHtml" :init="tinymceInit" ></editor>
|
|
</div>
|
|
<div class="isHidde">
|
|
<div ref="tinymceBox" v-html="tinymceHtml"> </div>
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
<style lang='scss' scoped>
|
|
.isHidde{
|
|
display:none;
|
|
position: fixed;
|
|
z-index: 1;
|
|
margin-top: -10px
|
|
}
|
|
</style>
|
|
|