数通智联化工云平台
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

<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>