瀏覽代碼

公式文本和数组相互转换

gangyj 3 年之前
父節點
當前提交
605c13a88f
共有 4 個文件被更改,包括 258 次插入49 次删除
  1. 27 1
      src/api/formula/formula.js
  2. 70 22
      src/views/formula/edit.vue
  3. 22 5
      src/views/formula/formulaArrayToString.js
  4. 139 21
      src/views/formula/formulaStringToArray.js

+ 27 - 1
src/api/formula/formula.js

@@ -10,7 +10,7 @@ export const getTypeMap = (params) => {
   })
 }
 
-export const saveFormula = ({formula,remark,wbsId,elementId}) => {
+export const saveFormula = ({formula,remark,wbsId,elementId,map}) => {
   return request({
     url: '/api/blade-manager/formula/save',
     method: 'post',
@@ -19,6 +19,32 @@ export const saveFormula = ({formula,remark,wbsId,elementId}) => {
       remark,
       wbsId,
       elementId,
+      map
+    }
+  })
+}
+
+export const updateFormula = ({id,formula,remark,wbsId,elementId,map}) => {
+  return request({
+    url: '/api/blade-manager/formula/update',
+    method: 'post',
+    data: {
+      id,
+      formula,
+      remark,
+      wbsId,
+      elementId,
+      map
+    }
+  })
+}
+
+export const formulaDetail = (params) => {
+  return request({
+    url: '/api/blade-manager/formula/detail',
+    method: 'get',
+    params: {
+      ...params,
     }
   })
 }

+ 70 - 22
src/views/formula/edit.vue

@@ -153,7 +153,7 @@
     </div>
     <div v-if="!operationVisible && showFunDetail">
       <el-tabs v-model="actiFunIndex" closable @tab-remove="removeFun" :before-leave="funLeave">
-        <el-tab-pane v-for="(item,index) in equationSelectEle.children" :key="item.name" :label="item.name" :name="index.toString()">
+        <el-tab-pane v-for="(item,index) in equationSelectEle.children" :key="index" :label="item.name" :name="index.toString()">
           <formula-template :formulainfo="item" :curele="equationSelectEle" @sele-ele-handle="showChooseEle">
             
           </formula-template>
@@ -222,7 +222,7 @@ import { getLazytree,selectByNodeTable,selectFormElements} from "@/api/manager/w
 import { getProjectList } from "@/api/manager/projectinfo";
 import { findContractByProjectId } from "@/api/manager/contractinfo";
 import { getDetail as getEleDeatil } from "@/api/manager/wbsformelement";
-import { getTypeMap,saveFormula } from "@/api/formula/formula";
+import { getTypeMap,saveFormula,formulaDetail,updateFormula } from "@/api/formula/formula";
 import {mapGetters} from "vuex";
 
 import formulaItem from "./component/formulaItem"
@@ -239,10 +239,12 @@ export default {
     return {
       wbsid: "", //从哪个wbs树过来的
       eleid: "", //元素id
+      formulaid:'',
 
       isRetain: false, //是否保留小数
       retainNum: 2, //保留几位小数
       formulaList:{},
+      formulaMap:{},
       activeIndex: "1-1", //当前选择的公式
 
       projectList: [], //项目备选列表
@@ -276,6 +278,8 @@ export default {
       argumenObj:{},
 
       symbolReg:/(\+|-|\*|\/)(.+)/,
+      operatorReg : /^\+|-|\*|%/,//加减乘除
+      startFCRegExp : /^FC\.([a-zA-Z]+)\(/,// 匹配开始的FC.xxx(
     };
   },
   computed: {
@@ -313,10 +317,10 @@ export default {
     this.init();
   },
   methods: {
-    init() {
+    async init() {
       this.getEleDeatil();
       this.getProjectList();
-      this.getTypeMap();
+      await this.getTypeMap();
 
       this.formulaStringToArray();
     },
@@ -526,7 +530,7 @@ export default {
       }
       //console.log(JSON.parse(expression.template));
       let obj = Object.assign({}, expression);
-      obj.template = JSON.parse(obj.template);
+      //obj.template = JSON.parse(obj.template);
       obj.arguments = new Array(obj.template.args.length);
       obj.arguments[0] = {
           id:this.equationSelectEle.id,
@@ -609,24 +613,49 @@ export default {
 
     //保存公式
     saveFormula(){
-      let text = formulaArrayToString(this.processFormula,this.resultFormula);
+      let obj = formulaArrayToString(this.processFormula,this.resultFormula);
       //console.log(text);
-      saveFormula({
-        formula:text,
-        remark:'',
-        wbsId:this.wbsid,
-        elementId:this.eleid
-      }).then(()=>{
-        this.$message({
-          type: "success",
-          message: "保存成功"
-        });
-      })
+      if(this.formulaid){
+        updateFormula({
+          id:this.formulaid,
+          formula:obj.text,
+          remark:'',
+          wbsId:this.wbsid,
+          elementId:this.eleid,
+          map:JSON.stringify(obj.eleMap)
+        }).then(()=>{
+          this.$message({
+            type: "success",
+            message: "修改成功"
+          });
+        })
+      }else{
+        saveFormula({
+          formula:obj.text,
+          remark:'',
+          wbsId:this.wbsid,
+          elementId:this.eleid,
+          map:JSON.stringify(obj.eleMap)
+        }).then(()=>{
+          this.$message({
+            type: "success",
+            message: "保存成功"
+          });
+        })
+      }
+      
     },
 
     //把公式文本还原数组
-    formulaStringToArray(){
-      formulaStringToArray('');
+    async formulaStringToArray(){
+      let detail = (await formulaDetail({elementId:this.eleid})).data.data;
+      //console.log(detail);
+      if(detail.id){
+        this.formulaid = detail.id;
+        let formula = formulaStringToArray(detail.formula,detail.map,this.formulaMap);
+        this.processFormula = formula.processFormula;
+        this.resultFormula[0].children = formula.resultFormulaChildren;
+      }
     },
 
     getNodeDetail(data) {
@@ -660,9 +689,28 @@ export default {
     },
 
     getTypeMap(){
-      getTypeMap().then((res)=>{
-        //console.log(res)
-        this.formulaList = res.data.data;
+      return new Promise((resolve)=>{
+        getTypeMap().then((res)=>{
+          //console.log(res)
+          this.formulaList = res.data.data;
+
+          //生成map,方便查找
+          for (let key in this.formulaList) {
+            if(typeof(this.formulaList[key]) == 'object'){
+              this.formulaList[key].forEach((formula)=>{
+                formula.template =  JSON.parse(formula.template);
+                if(this.operatorReg.test(formula.template.ft)){
+                  this.formulaMap[formula.template.ft] = formula;
+                }else if(this.startFCRegExp.test(formula.template.ft)){
+                  let regRes = formula.template.ft.match(this.startFCRegExp);
+                  this.formulaMap[regRes[0]] = formula;
+                }
+              })
+            }
+          }
+        }).finally(() => {
+          resolve();
+        })
       })
     }
   },

+ 22 - 5
src/views/formula/formulaArrayToString.js

@@ -1,6 +1,6 @@
 
-
-function transformArguments(children,curEle){
+//转换公式的参数
+function transformArguments(children,curEle,eleMap){
   let fcReg = /(FC\.\S+\()(.+)\)/;
   let fcText = '';
   for (let i = (children.length-1); i >= 0; i--) {
@@ -29,6 +29,12 @@ function transformArguments(children,curEle){
             //不是第一个嵌套的公式,且和当前挂载的是同一个元素
             //认为这个参数是之前公式计算的结果,不再写入元素
           }else{
+            eleMap[arg.tableElementKey] = {
+              id: arg.id,
+              name: arg.name,
+              tableElementKey: arg.tableElementKey,
+              type: "Element",
+            };
             fcText += `E[${arg.tableElementKey}]`;
           }
         }else{
@@ -57,14 +63,24 @@ export const formulaArrayToString = (processFormula,resultFormula) => {
   // console.log(processFormula)
   // console.log(resultFormula)
   let text = '';
+  let eleMap = {};//元素字典,为了回显的时候查询信息
 
   processFormula.forEach(item => {
     if(item.type == 'Element'){
+      //console.log(item)
       if(item.children.length <1){
+        eleMap[item.tableElementKey] = {
+          id: item.id,
+          name: item.name,
+          tableElementKey: item.tableElementKey,
+          type: "Element",
+        };
         text += `E[${item.tableElementKey}]`;
       }else{
-        text += transformArguments(item.children,item);
+        text += transformArguments(item.children,item,eleMap);
       }
+    }else if(item.type == 'Element'){
+      text += item.template.ft;
     }else{
       text += item.name;
     }
@@ -72,12 +88,13 @@ export const formulaArrayToString = (processFormula,resultFormula) => {
 
   if(resultFormula[0].children.length){
     //等号左侧部分
-    let resText = transformArguments(resultFormula[0].children,resultFormula[0]);
+    let resText = transformArguments(resultFormula[0].children,resultFormula[0],eleMap);
   
     //等号左侧元素不需要,左侧的公式嵌套右侧所有结果
     text = resText.replace(`E[${resultFormula[0].tableElementKey}]`,text);
   }
 
   //console.log(text);
-  return text;
+  //console.log(eleMap)
+  return {text,eleMap};
 }

+ 139 - 21
src/views/formula/formulaStringToArray.js

@@ -1,9 +1,60 @@
 
+//解析公式的参数
+function parseFormulaArguments(ele,funObj,resArr){
+  let fcReg = /(FC\.\S+\()(.+)\)/;
+  let fun = {
+    example:funObj.example,
+    name:funObj.name,
+    template:funObj.template,
+  };
+  let argTextArr = funObj.children;//放参数文本的数组
+  fun.arguments = [];
+
+  let tmpArr = fcReg.exec(funObj.template.ft);
+  let argList = tmpArr[2].split(",");//括号里面参数部分#1,#2..
+
+  argList.forEach((argText,index)=>{
+    //只用动态的
+    if(argText.indexOf('#')>-1){
+      if(argTextArr[index].type == 'Element'){
+        fun.arguments.push(argTextArr[index])
+      }else if(argTextArr[index].type == 'Function'){
+        fun.arguments.push(ele)
+      }else{
+        fun.arguments.push(argTextArr[index].tag)
+      }
+    }
+  })
+
+  ele.children.push(fun);
+  if(funObj.parent){
+    let isTop = false;
+    for (let i = 0; i < funObj.parent.children.length; i++) {
+      if(funObj.parent.children[i].type == "Operator" ||
+        funObj.parent.children[i].type == "Brackets"
+      ){
+        //有这些认为就最顶层,外面的方法是放到结果那里的
+        isTop = true;
+        break;
+      }
+    }
+    if(!isTop){
+      parseFormulaArguments(ele,funObj.parent,resArr)
+    }
+  }else{
+    //结束之后把parent删掉
+    delete ele.parent;
+    for (let i = 0; i < resArr.length; i++) {
+      if(resArr[i] == funObj){
+        //用元素替换最顶层的方法
+        resArr[i] = ele;
+        break;
+      }
+    }
+  }
+}
 
-
-export const formulaStringToArray = (text) => {
-  
-  text = "FC.pow(FC.pow(E[assa_faf],3),2)+FC.date(E[assa_aff],我的)";
+export const formulaStringToArray = (text,elemap,formulaMap) => {
 
   // 匹配开始的FC.xxx(
   const startFCRegExp = /^FC\.([a-zA-Z]+)\(/;
@@ -11,9 +62,12 @@ export const formulaStringToArray = (text) => {
   const endBracketsReg = /^\)/;//右括号
   const elementReg = /^E\[(.[^\]]+_.[^\]]+)\]/;//元素
   const commaReg = /^,/;//逗号
-  const operatorReg = /^\+|-|\*|÷/;//加减乘除
+  const operatorReg = /^\+|-|\*|%/;//加减乘除
   const wordReg = /^[\u4e00-\u9fa5\w'"-]+/;//文本
 
+  let elementMap = JSON.parse(elemap);//元素字典
+  //console.log(formulaMap)
+
   let resArr = [];//结果数组
   let strIndex = 0;//位置索引
   let nuText = text;//未处理的字符串
@@ -28,13 +82,24 @@ export const formulaStringToArray = (text) => {
       //匹配FC开始部分FC.xxx(
       let regRes = nuText.match(startFCRegExp);
       let startText = regRes[0];//匹配到的文本
-
+      
+      let obj = {};
+      if(formulaMap[startText]){
+        Object.assign(obj,formulaMap[startText]);
+        Object.assign(obj,{
+          type:'Function',
+          children:[],
+          tag:startText
+        });
+      }else{
+        obj = {
+          type:'Function',
+          children:[],
+          tag:startText
+        }
+      }
       //startStack.push(startText);
-      contentStack.push({
-        type:'Function',
-        children:[],
-        tag:startText
-      });
+      contentStack.push(obj);
 
       strIndex += startText.length;//索引移动
     }else if(endBracketsReg.test(nuText)){
@@ -61,6 +126,7 @@ export const formulaStringToArray = (text) => {
       contentStack.push({
         type:'Brackets',
         children:[],
+        selected:false,
         tag:startBrackets
       });
 
@@ -69,12 +135,25 @@ export const formulaStringToArray = (text) => {
       //console.log('匹配元素')
       //匹配元素
       let eleArr = nuText.match(elementReg);
-      let obj = {
-        type:'Element',
-        tableElementKey:eleArr[1],
-        children:[],
-        tag:eleArr[0]
+      let obj = {};
+      if(elementMap[eleArr[1]]){
+        Object.assign(obj,elementMap[eleArr[1]]);
+        Object.assign(obj,{
+          selected:false,
+          children:[],
+          tag:eleArr[0]
+        });
+      }else{
+        obj = {
+          type:'Element',
+          name:eleArr[1].split('_')[1],
+          tableElementKey:eleArr[1],
+          children:[],
+          selected:false,
+          tag:eleArr[0]
+        }
       }
+      
       let content =contentStack[contentStack.length - 1];
       obj.parent = content;
       content.children.push(obj);
@@ -87,10 +166,11 @@ export const formulaStringToArray = (text) => {
       //匹配逗号
       let comma = nuText.match(commaReg)[0];
 
-      contentStack[contentStack.length - 1].children.push({
-        type:'Comma',
-        tag:comma
-      });
+      // 方法体里面的逗号忽略
+      // contentStack[contentStack.length - 1].children.push({
+      //   type:'Comma',
+      //   tag:comma
+      // });
 
       strIndex += comma.length;//索引移动
     }else if(operatorReg.test(nuText)){
@@ -100,8 +180,14 @@ export const formulaStringToArray = (text) => {
       let obj = {
         type:'Operator',
         name:operator,
+        selected:false,
         tag:operator,
+      };
+      if(formulaMap[operator]){
+        obj.example = formulaMap[operator].example;
+        obj.template = formulaMap[operator].template;
       }
+
       if(contentStack.length > 0){
         //不然就在方法体或括号里面
         contentStack[contentStack.length - 1].children.push(obj);
@@ -130,7 +216,39 @@ export const formulaStringToArray = (text) => {
     }
   }
 
+  //数组清理到最后能显示的元素
+  for (let i = elementArr.length-1; i >0; i--) {
+    //判断当前元素是不是最底层
+    let isBottom = true;
+    let childrenEles = [];
+    let chs = elementArr[i].parent.children;
+    for (let j = 0; j < chs.length; j++) {
+      if(chs[j].type == "Function"){
+        isBottom = false;
+      }else if(chs[j].type == "Element"){
+        childrenEles.push(chs[j]);
+      }
+    }
+    if(isBottom){
+      //认为最底层的参数第一个元素就是显示在页面的那个元素
+      if(childrenEles[0] != elementArr[i]){
+        elementArr.splice(i,1);
+      }
+    }else{
+      elementArr.splice(i,1);
+    }
+  }
+
+  elementArr.forEach((ele)=>{
+    parseFormulaArguments(ele,ele.parent,resArr);
+  })
+
   console.log(contentStack)
   console.log(resArr);
-  return resArr;
+  console.log(elementArr);
+
+  return {
+    processFormula:resArr,
+    resultFormulaChildren:[],
+  };
 }