需求:
1.通过点击按钮和运算符将按钮和运算符的文字赋值到input框中,input框不能输入,但是可以删除,以及光标插入。
2.删除时,运算符直接删,但是文字按钮需要整体删除。(如,在"社保个人"光标在"人"后点击删除时,直接删除"社保个人"这几个字)
3.保存时需要对input的内容进行校验,判断是否是一个正常的公式。
截图:
<!-- 科目公式配置 -->
<template>
<div>
<el-form ref="elForm" size="medium" label-width="100px">
<el-form-item label="绩效工资=">
<el-input id="inputRef" type="textarea" placeholder="请选择" :value="salary" @input="inputChange"
:autosize="{minRows: 4, maxRows: 4}" :style="{width: '100%'}"></el-input>
</el-form-item>
<div style="text-align: center;">
<el-tag v-for="(item,index) in symbolList" :key="index" style="margin: 5px;" @click="add(item)">{{item}}</el-tag>
</div>
</el-form>
<el-tabs type="border-card" style="margin-top: 30px;">
<el-tab-pane v-for="(item,index) in allData" :key="index" :label="item.title">
<el-tag v-for="(item1,idx) in item.list" :key="idx" style="margin: 5px;"@click="add(item1.name)">{{item1.name}}</el-tag>
</el-tab-pane>
</el-tabs>
<div style=" margin-top: 65px; text-align: right;">
<el-button type="primary" style="margin-left: 10px;" @click.native="submitForm">保 存</el-button>
<el-button @click.native="closeBtn">取 消</el-button>
</div>
</div>
</template>
<script>
import { insertInputTxt } from "@/utils/ruoyi";
export default {
data() {
return {
salary:"",
symbolList:['+','-','*','/','(',')','%'], //符号数组
allData:[],
}
},
methods: {
open(data) {
var allData = [
{title:'薪酬数据',list:[{id:'101',name:'基本工资'},{id:'102',name:'岗位工资'}]},
{title:'考勤数据',list:[{id:'103',name:'应到天数'},{id:'104',name:'实到天数'},{id:'105',name:'请假天数'}]},
{title:'变动项目',list:[{id:'106',name:'社保个人'},{id:'107',name:'公积金个人'},{id:'108',name:'变动项目合计'}]},
{title:'自定义科目',list:[{id:'109',name:'自定义科目1'},{id:'110',name:'绩效比例数'}]},
]
var all = {title:'全部',list:[]}
var li = []
allData.forEach((item,index) =>{
li = li.concat(item.list)
})
this.$set(all,'list',li)
allData.unshift(all) //添加all数据到allData数组的第一位
// console.log(allData)
this.allData = allData
if(data){//修改赋值
this.salary = data
}else{ //新增清空上次的值,
this.salary = ''
}
},
add(text){
this.salary = insertInputTxt('inputRef',text)
},
inputChange(val){
//1.只允许按钮插入,不允许手动输入,允许手动删除
if(this.salary.length > val.length){
this.salary = val
}
//2.删除时获取光标前后的文字
var elInput = document.getElementById('inputRef');
var startPos = elInput.selectionStart;
var endPos = elInput.selectionEnd;
if (startPos === undefined || endPos === undefined) return
var txt = elInput.value;
var q = txt.substring(0, startPos) //光标前面的文字
var h = txt.substring(endPos) //光标后面的文字
// console.log( "光标前面的文字:" + q)
//3.删除的逻辑处理:获取光标前的最后一项文字(不算运算符)
var arr = q.split(/[\+\-\*\/\(\)\%]/).filter(Boolean) //按字符集分割字符串,然后去掉空的元素
var lastStr = arr.pop() //删除数组的最后一项,返回的是数组的最后一项
// console.log("最后一项:" + lastStr)
if(lastStr){
//判断光标前的最后一项文字是否是完整的科目(在全部数据中存在)
var qbData = this.allData[0].list
var isWZ = false //是否完整科目
qbData.forEach(item =>{
if(item.name === lastStr){
isWZ = true //是完整科目
}
})
if(!isWZ){ //如果不是完整科目,就在光标前的文字中删除该不完整的科目
q = q.substr(0, q.length - lastStr.length); //在q中删除lastStr
}
//如果是完整科目,那就意味着光标删除的只是一个运算符,不用做额外处理
this.salary = q + h //拼接光标前后字段即可
setTimeout(() => { //删除文字后,让光标定位到删除的地方,需要加个延时,不然代码会失效
elInput.focus()
elInput.selectionStart = elInput.selectionEnd = q.length
}, 50); //延时尽量小,不然容易误删最后面的文字
}
},
checkFormulaText(){//分割字符串
var resultStr = this.salary
var errorMsg = ""
//拦截1:判断公式中 基本工资岗位工资 中间没有运算符
var arr = resultStr.split(/[\+\-\*\/\(\)\%]/).filter(Boolean) //按字符集分割字符串,然后去掉空的元素
var qbData = this.allData[0].list
var qbList = []
qbData.forEach(item =>{
qbList.push(item.name)
})
var isSuccess = true
arr.forEach(name =>{
if(!qbList.includes(name)){ //数组中没有这条数据
errorMsg = "公式配置错误,请检查:" + name
isSuccess = false
}
})
//拦截2:公式中有以下错误的运算符
var errorList = [
"++","+-","+*","+/","+%",
"-+","--","-*","-/","-%",
"*+","*-","**","*/","*%",
"/+","/-","/*","//","/%",
"%+","%-","%*","%/","%%",
"(+","(-","(*","(/","(%",
"+)","-)","*)","/)","%)",
"()",")("
]
errorList.forEach(item =>{
if(resultStr.indexOf(item) != -1){ //字符串包含
errorMsg = "公式配置错误,请检查:" + item
isSuccess = false
}
});
//拦截3:公式中(的个数与)的个数不相同
var sub1 = (resultStr.match(/\(/g)||[]).length
var sub2 = (resultStr.match(/\)/g)||[]).length
if(sub1 !== sub2){
errorMsg = "公式配置错误,请检查()是否匹配"
isSuccess = false
}
//拦截4:公式中()的位置是否反了 社保个人)+(岗位工资
var sub1F = resultStr.indexOf('\(')
var sub2F = resultStr.indexOf('\)')
var sub1E = resultStr.lastIndexOf('\(')
var sub2E = resultStr.lastIndexOf('\)')
if(sub2F < sub1F || sub2E < sub1E ){ // )首次出现的位置 小于 ( 首次出现的位置; 或者 ) 最后出现的位置 小于 (最后出现的位置
errorMsg = "公式配置错误,请检查()是否匹配"
isSuccess = false
}
//拦截5: 公式中,公积金个人(自定义科目1)实到天数
if(sub1F !== 0){ //如果(不是第一位,获取每个(前面的一个字符,看看是不是符号,不是符号,就报错
var idxList = this.getStrPositions(resultStr,'(')
var isE = false
idxList.forEach(item =>{
var dd = resultStr.substr(item-1,1) //获取(前面一个字符
if(!this.symbolList.includes(dd)){ //不是符号,报错
isE = true
}
})
if(isE){
errorMsg = "公式配置错误,请检查(运算符"
isSuccess = false
}
}
if(sub2E !== resultStr.length-1){ //如果)不是最后一位,获取每一个)后面的一个字符,看看是不是符号,不是符号,就报错
var idxList = this.getStrPositions(resultStr,')')
var isE = false
idxList.forEach(item =>{
var dd = resultStr.substr(item+1,1) //获取)后面的一个字符
if(!this.symbolList.includes(dd)){ //不是符号,报错
isE = true
}
})
if(isE){
errorMsg ="公式配置错误,请检查)运算符"
isSuccess = false
}
}
//拦截6:公式的开头和结尾有非法运算符
if(resultStr.length > 0){
var firstChart = resultStr.substr(0,1) //第一个字符
var firstErrorList = ["+","-","*","/","%",")"]
firstErrorList.forEach(item =>{
if(firstChart === item){
errorMsg = "公式配置错误,开头不能是:" + item
isSuccess = false
}
});
var endChart = resultStr.substr(-1) //最后一个字符
var endErrorList = ["+","-","*","/","%","("]
endErrorList.forEach(item =>{
if(endChart === item){
errorMsg = "公式配置错误,结尾不能是:" + item
isSuccess = false
}
});
}else{
errorMsg ="请配置公式"
isSuccess = false
}
if(!isSuccess){
this.msgError(errorMsg)
}
return isSuccess
},
getStrPositions(str,subStr){
var indexs=[];
var string=str;
while(true){
var index=string.lastIndexOf(subStr);
if(index!=-1){
string=string.substr(0,index)+string.substr(index+subStr.length,string.length);
indexs.push(index);
}else{
break;
}
}
return indexs;
},
submitForm() {
if(this.checkFormulaText()){
this.$emit('closeConfigFormula',{msg:this.salary}); //通知父组件改变
}
},
closeBtn(){
this.$emit('closeConfigFormula',{msg:''}); //通知父组件改变
}
}
}
</script>
/** input在光标前插入文字
* id:input绑定的id
* insertTxt:要插入的文本
* 返回:插入后的所有文本
*/
export function insertInputTxt(id,insertTxt) {
var elInput = document.getElementById(id);
var startPos = elInput.selectionStart;
var endPos = elInput.selectionEnd;
if (startPos === undefined || endPos === undefined) return
var txt = elInput.value;
var result = txt.substring(0, startPos) + insertTxt + txt.substring(endPos)
elInput.value = result;
elInput.focus();
elInput.selectionStart = startPos + insertTxt.length;
elInput.selectionEnd = startPos + insertTxt.length;
return result;
}