cldu пре 4 месеци
родитељ
комит
f8576a2ad3

BIN
src/assets/img/sand_new/blue_edit_icon.png


+ 1 - 0
src/lang/modules/ETATables/En.js

@@ -194,6 +194,7 @@ export default {
     no_corresponding_data: "No corresponding data",
     calculation_btn: "calculation",
     only_select_msg: "Only monthly indicators can be selected",
+    only_quarterly_msg:"Only quarterly indicators can be selected",
     no_quarterly_msg: "Unable to select quarterly indicators",
     no_day_msg: "Cannot select daily indicators",
     no_year_msg: "Unable to select annual indicators",

+ 1 - 0
src/lang/modules/ETATables/Zh.js

@@ -206,6 +206,7 @@ export default {
   no_corresponding_data: "无对应的数据",
   calculation_btn: "计算",
   only_select_msg: "只能选择月度指标",
+  only_quarterly_msg:"只能选择季度指标",
   no_quarterly_msg: "不能选择季度指标",
   no_day_msg: "不能选择日度指标",
   no_year_msg: "不能选择年度指标",

+ 16 - 1
src/lang/modules/SandboxManage/SandFlow.js

@@ -50,6 +50,14 @@ export const SandFlowEn = {
     link_type_opt2:'Image library',
     link_type_opt3:'reports',
     msg_leave_page_save:'Before leaving this page, do you want to save current contents?',
+    add_node_data:'Add node data',
+    clear_node_data:'Clear node data',
+    edit_node_data:'Edit node data',
+    successfully_cleared_node_data:'Successfully cleared node data',
+    node_data_saved_successfully:'Node data saved successfully',
+    data_already_exists:'The data already exists, please add it again',
+    select_indicator_criteria:'Please select the indicators that meet the criteria',
+    calculation_configuration_parameters:'Calculation method configuration parameters',
   };
   
   /* 中文 */
@@ -100,7 +108,14 @@ export const SandFlowEn = {
     link_type_opt2:'图库',
     link_type_opt3:'研报',
     msg_leave_page_save:'在离开页面之前,是否保存当前内容?',
-
+    add_node_data:'添加节点数据',
+    clear_node_data:'清除节点数据',
+    edit_node_data:'编辑节点数据',
+    successfully_cleared_node_data:'清除节点数据成功',
+    node_data_saved_successfully:'节点数据保存成功',
+    data_already_exists:'该数据已存在,请重新添加',
+    select_indicator_criteria:'请选择符合条件的指标',
+    calculation_configuration_parameters:'计算方式配置参数',
   };
   
   /**

+ 2 - 3
src/views/chartRelevance_manage/components/selectTarget.vue

@@ -201,7 +201,6 @@ export default {
                 KeyWord: query,
                 CurrentIndex: page,
             }
-
             let res;
             if(this.filter) {
                res = this.targetType=='1'?await dataBaseInterface.targetSearchByPage(params):await preDictEdbInterface.edbSearch(params)
@@ -212,10 +211,10 @@ export default {
                 14: 6
               }
 
-              let FilterSource = (['/addMixedSheet','/editBalanceSheet'].includes(this.$route.path) && this.$parent.isCalculateDia)
+              let FilterSource = (['/addMixedSheet','/editBalanceSheet','/sandflow'].includes(this.$route.path) && this.$parent.isCalculateDia)
                 ? filterMap[this.$parent.formData.source]||1 
                 : 1;
-              let Frequency = (['/addMixedSheet','/editBalanceSheet'].includes(this.$route.path) && this.$parent.isCalculateDia && this.$parent.formData.source===2)
+                let Frequency = (['/addMixedSheet','/editBalanceSheet','/sandflow'].includes(this.$route.path) && this.$parent.isCalculateDia && this.$parent.formData.source===2)
                 ? '季度' 
                 : ''
               res = await sheetInterface.searchTarget({

+ 3 - 0
src/views/dataEntry_manage/databaseComponents/util.js

@@ -17,6 +17,9 @@ export const formRules= {
 	n_num: [
 		{ required: true, message: /* 'N不能为空' */bus.$i18nt.t('Edb.Valids.n_msg'), trigger: 'blur' },
 	],
+	nNum: [
+		{ required: true, message: /* 'N不能为空' */bus.$i18nt.t('Edb.Valids.n_msg'), trigger: 'blur' },
+	],
 	moveVal: [
 		{ required: true, message: /* '移动方式参数不能为空' */bus.$i18nt.t('Edb.Valids.move_msg'),trigger: 'blur' }
 	],

+ 0 - 1
src/views/datasheet_manage/mixins/conditionTableMixin.js

@@ -262,7 +262,6 @@ export default {
             if (getDecimalPlaces(cell.ShowValue) < styleCss.decimal || styleCss.nt == 'percent') {
                 Value = transDecimalPlace(cell.ShowValue + '', { ...styleCss, pn: styleCss.decimal - getDecimalPlaces(cell.ShowValue) + (styleCss.nt == 'percent'&&getDecimalPlaces(cell.ShowValue)!=0 ? 2 : 0) })
             }
-            // console.log(cell)
             this.$set(this.config.data[cell.rIndex][cell.cIndex],'ShowFormatValue',Value)
             return Value
         },

+ 312 - 0
src/views/sandbox_manage/common/customize.js

@@ -0,0 +1,312 @@
+import { Graph, Cell, Node, Path } from "@antv/x6";
+import { getTextSize, getTextWidth } from "./measure.js";
+export default {
+  data() {
+    return {
+      styleConfig: {},
+      childsNodeSize: [], //数据节点内部内容宽度数组
+    };
+  },
+  created() {
+    this.styleConfig = this.$store.state.sand.styleConfig;
+  },
+  methods: {
+    handleCustomDataNodeWidth(list) {
+      let arr = [[], [], []]; //按列分组,获取当前列的内容的最大长度作为该列的最大长度
+      list.map((item, index) => {
+        arr[index % 3].push(item);
+      });
+      let widthArr = [];
+      arr.map((arrs, arrsIndex) => {
+        let widths = [];
+        arrs.map((item) => {
+          widths.push(
+            getTextWidth(
+              item.label,
+              "Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif",
+              14
+            ) || 0
+          );
+          widths.push(
+            getTextWidth(
+              item.value,
+              "Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif",
+              14
+            ) || 0
+          );
+        });
+        let max = widths.length > 0 ? Math.max.apply(null, widths) : 0;
+        if (max) widthArr[arrsIndex] = max > 106 ? max : 106;
+      });
+
+      let sum = widthArr.reduce((accumulator, current) => {
+        return accumulator + current;
+      }, 0);
+      sum +=
+        list.filter((_) => _).length >= 3 ? 40 : 20 + 10 * (list.length - 1);
+      return {
+        sum,
+        widthArr,
+      };
+    },
+    getCustomDataNodeSize(data) {
+      const list = data.calculationMethod;
+      let height = Math.ceil(list.length / 3) * 66;
+      let o = this.handleCustomDataNodeWidth(list);
+      return {
+        height: height || 66,
+        width: o.sum || 50,
+        innerWidthArr: o.widthArr,
+      };
+    },
+    handleNodesSize(list) {
+      let sizes = list.map((item, index) => {
+        let h = { height: 30, width: 200 };
+        if (!item.calculationMethod || !item.calculationMethod.length) {
+          h = getTextSize(
+            item.Name,
+            200,
+            14,
+            "Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif"
+          );
+          h.height = h.height < 30 ? 30 : h.height;
+        } else {
+          let nodeSize = this.getCustomDataNodeSize(item);
+
+          let nameWidth =
+            getTextWidth(
+              item.Name,
+              "Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif",
+              14
+            ) + 10;
+          let titleWidth =
+            nameWidth < nodeSize.width ? nameWidth : nodeSize.width;
+          titleWidth = titleWidth < 126 ? 126 : titleWidth;
+          let x = getTextSize(
+            item.Name,
+            titleWidth,
+            14,
+            "Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif"
+          );
+          h = {
+            width: nodeSize.width,
+            height: nodeSize.height,
+            innerWidthArr: nodeSize.innerWidthArr,
+            titleWidth: x.width,
+            titleHeight: h.height < 30 ? 30 : h.height,
+          };
+        }
+        return h;
+      });
+      this.childsNodeSize = sizes || [];
+      let sumHeight = this.childsNodeSize.reduce((a, b) => {
+        return a + b.height + (b.titleHeight || 0);
+      }, 0);
+      sumHeight = sumHeight + (sizes.length - 1) * 30;
+      return {
+        sumHeight,
+      };
+    },
+    addCustomDataNodes(select_cell, list) {
+      this.graph.startBatch("renderMindmap");
+      this.childsNodeSize = [];
+      let { sumHeight } = this.handleNodesSize(list);
+      let startY =
+        select_cell.position().y +
+        Math.floor(select_cell.size().height / 2) -
+        Math.floor(sumHeight / 2);
+      const getY = (index) => {
+        if (index == 0) {
+          if (this.childsNodeSize[index].titleHeight)
+            return this.childsNodeSize[index].titleHeight;
+          return 0;
+        }
+        let hs = this.childsNodeSize.slice(0, index);
+        let h = hs.reduce((a, b) => {
+          return a + b.height + (b.titleHeight || 0);
+        }, 0);
+        if (this.childsNodeSize[index].titleHeight)
+          h += this.childsNodeSize[index].titleHeight;
+        h += index *30;
+        return h;
+      };
+      let cells = [];
+      let childNodeCells = [];
+      list.map((linkItem, linkIndex) => {
+        //外层框节点/外层标题节点
+        const currentNode = this.graph.createNode({
+          id: `${select_cell.id}-${linkIndex + 1}`,
+          shape:
+            !linkItem.calculationMethod || !linkItem.calculationMethod.length
+              ? "mindmap-child-datanode-title"
+              : "mindmap-child-datanode",
+          x: select_cell.position().x + select_cell.size().width + 119,
+          y: startY + getY(linkIndex),
+          width: this.childsNodeSize[linkIndex].width,
+          height: this.childsNodeSize[linkIndex].height,
+          label:
+            !linkItem.calculationMethod || !linkItem.calculationMethod.length
+              ? linkItem.Name
+              : "",
+          type:
+            !linkItem.calculationMethod || !linkItem.calculationMethod.length
+              ? "datanode-title"
+              : "datanode-child",
+          attrs: {
+            body: {
+              stroke:
+                !linkItem.calculationMethod ||
+                !linkItem.calculationMethod.length
+                  ? this.$store.state.sand.styleConfig.titleBorderColor
+                  : this.$store.state.sand.styleConfig.dataBorderColor,
+              fill:
+                !linkItem.calculationMethod ||
+                !linkItem.calculationMethod.length
+                  ? this.$store.state.sand.styleConfig.titleBackgoundColor
+                  : this.$store.state.sand.styleConfig.dataBackgroundColor,
+            },
+            text: {
+              fill:
+                !linkItem.calculationMethod ||
+                !linkItem.calculationMethod.length
+                  ? this.$store.state.sand.styleConfig.titleTextColor 
+                  : this.$store.state.sand.styleConfig.dataTextColor,
+            },
+          },
+          zIndex:0,
+          data: linkItem,
+        });
+        childNodeCells.push(currentNode)
+        cells.push(currentNode);
+        //连接线
+        cells.push(
+            this.graph.createEdge({
+              shape: 'mindmap-edge',
+              attrs:{
+                line:{
+                  stroke:this.$store.state.sand.styleConfig.lineColor
+                }
+              },
+              zIndex:0,
+              source: {
+                cell: select_cell.id,
+                anchor: {
+                  name: select_cell.data && select_cell.data.key == 'text' ?  'right' : 'center',
+                  args: {
+                    dx: select_cell.data && select_cell.data.key == 'text' ? 0 : '25%',
+                  },
+                },
+              },
+              target: {
+                cell: `${select_cell.id}-${linkIndex + 1}`,
+                anchor: {
+                  name: 'left',
+                },
+              },
+            }),
+        )
+
+        let titleNode = null;
+        if (
+          linkItem.detailParams &&
+          linkItem.detailParams.id &&
+          linkItem.calculationMethod &&
+          linkItem.calculationMethod.length > 0
+        ) {
+          //内部标题节点
+          titleNode = this.graph.createNode({
+            id: `${select_cell.id}-${linkIndex + 1}-0`,
+            shape: "mindmap-child-datanode-title",
+            x: select_cell.position().x + select_cell.size().width + 119,
+            y:
+              startY +
+              getY(linkIndex) -
+              this.childsNodeSize[linkIndex].titleHeight,
+            width: this.childsNodeSize[linkIndex].titleWidth,
+            height: this.childsNodeSize[linkIndex].titleHeight,
+            label: linkItem.Name,
+            type: "datanode-title",
+            attrs: {
+              body: {
+                stroke: this.$store.state.sand.styleConfig.titleBorderColor,
+                fill: this.$store.state.sand.styleConfig.titleBackgoundColor,
+              },
+              text: {
+                fill: this.$store.state.sand.styleConfig.titleTextColor ,
+              },
+            },
+            zIndex:0,
+            data: linkItem,
+          });
+          cells.push(titleNode);
+        }
+
+        if (
+          linkItem.calculationMethod &&
+          linkItem.calculationMethod.length > 0
+        ) {
+            //内部数据节点
+          let inners = linkItem.calculationMethod.map((item, index) => {
+            let widthArr = this.childsNodeSize[linkIndex] ? this.childsNodeSize[linkIndex].innerWidthArr : [];
+            let m = index % 3;
+            let w =
+              m == 0
+                ? 0
+                : m == 1
+                ? widthArr[0]
+                : widthArr[0] + widthArr[1];
+            let innerNode = this.graph.createNode({
+              id: `${select_cell.id}-${linkIndex + 1}-${index + 1}`,
+              shape: "mindmap-grandchild-datanode",
+              x: select_cell.position().x + select_cell.size().width + 119 + (m + 1) * 10 + w,
+              y: startY + getY(linkIndex) + Math.floor(index / 3) * 66,
+              width: widthArr[m],
+              height: 66,
+              type: "datanode-grandchild",
+              attrs: {
+                body: {
+                  stroke: "",
+                  strokeWidth: 0,
+                  fill: "transparent",
+                  "pointer-events": "none",
+                },
+                text: {
+                  fill: this.$store.state.sand.styleConfig.dataTextColor,
+                  text: item.label,
+                  refWidth: 1,
+                  refY: 10,
+                  textVerticalAnchor: "top",
+                  "pointer-events": "none",
+                },
+                value: {
+                  fill: this.$store.state.sand.styleConfig.dataTextColor,
+                  text: item.value,
+                  refWidth: 1,
+                  refX: "50%",
+                  refY: "100%",
+                  refY2: -10,
+                  textVerticalAnchor: "bottom",
+                  "text-anchor": "middle",
+                  "pointer-events": "none",
+                },
+              },
+              zIndex:0,
+              data: item,
+            });
+            cells.push(innerNode)
+            return innerNode
+          });
+          currentNode.setChildren(titleNode ? [...inners,titleNode] : inners)
+        }
+      });
+      select_cell.setChildren(childNodeCells);
+      let sortCells = cells.sort((cell) => cell.shape.indexOf("edge"));
+      let cells_result = sortCells.sort((cell) =>
+        cell.shape.indexOf("mindmap-grandchild-datanode")
+      );
+      
+      this.graph.addCell(cells_result);
+      this.graph.stopBatch("renderMindmap");
+    },
+  },
+};

+ 9 - 5
src/views/sandbox_manage/common/events.js

@@ -2,13 +2,13 @@ import { store } from "../../../main";
 import { configOpt } from './toolConfig';
 import _ from "lodash"
 const { line} = configOpt;
-
+const cantHandleShapes = ['mindmap-child-datanode-title','mindmap-child-datanode','mindmap-grandchild-datanode','mindmap-child-background-datanode'];
 /* 节点操作监听事件 */
 export const myEvents = (graph,mindmapDataUseFun) => {
 		/* 节点双击编辑 */
 		graph.on('node:dblclick', ({ node, e }) => {
 			// 节点当前设置的样式同步到编辑区
-
+            if(cantHandleShapes.includes(node.shape)) return;
 			const { text, rect} = node.attrs;
 			const edit_area = document.createElement('div');
 			edit_area.contentEditable = "true";
@@ -104,6 +104,7 @@ export const myEvents = (graph,mindmapDataUseFun) => {
 
 		/* 节点右键 */
 		graph.on('node:contextmenu',({node,e}) => {
+			if(cantHandleShapes.includes(node.shape)) return;
 			graph.resetSelection(node);
 			const dom = $('#contextMenu-wrapper')[0];
 			dom.style.left = e.clientX-3 + 'px';
@@ -210,10 +211,10 @@ export const bindKey = (graph,mindmapDataUseFun) => {
 }
 
 /* 右键事件 */
-export const contextEvent = (graph,key,mindmapDataUseFun) => {
+export const contextEvent = (graph,key,mindmapDataUseFun,that) => {
 	switch (key) {
 		case 'copy':
-			nodeCopyAndPaste(graph);
+			nodeCopyAndPaste(graph,that);
 			break;
 		case 'del': 
 			deleteNodes(graph,mindmapDataUseFun);
@@ -222,13 +223,16 @@ export const contextEvent = (graph,key,mindmapDataUseFun) => {
 }
 
 /* 复制粘贴节点 */
-const nodeCopyAndPaste = (graph) => {
+const nodeCopyAndPaste = (graph,that) => {
 	const select_cell = graph.getSelectedCells();
 	if (select_cell.length) {
 		graph.copy(select_cell);
 		const copy_cell = graph.paste({ offset: 30 });
 		graph.cleanSelection();
 		graph.select(copy_cell);
+		if(select_cell[0] && select_cell[0].data && select_cell[0].data.linkData && select_cell[0].data.linkData.length > 0){ //复制子数据节点
+			that && that.saveLink && that.saveLink(select_cell[0].data.linkData) //sandFlowNew/index.vue
+		}
 	}
 }
 

+ 6 - 1
src/views/sandbox_manage/common/gragh.js

@@ -85,7 +85,12 @@ export function myGraph (wrapper,mindmapDataUseFun,type='edit') {
 			vertexMovable:false,
 			vertexMovable:false,
 			vertexDeletable:false
-		}:{},
+		}:function(cellView){
+		  if(cellView.cell.shape == 'mindmap-child-datanode-title' && cellView.cell.data && cellView.cell.data.calculationMethod && cellView.cell.data.calculationMethod.length > 0){
+            return {nodeMovable:false};
+		  }
+		  return true
+		},
 		connecting: {
 			snap: true,
 			// 允许连接到空白位置

+ 37 - 0
src/views/sandbox_manage/common/measure.js

@@ -0,0 +1,37 @@
+export const getTextSize = (text, width, fontSize , fontFamily) => {
+    // 创建临时元素
+    const tempEl = document.createElement('div');
+   
+    // 设置元素样式
+    tempEl.style.position = 'absolute';
+    tempEl.style.visibility = 'hidden';
+    tempEl.style.width = `${width}px`; // 设置固定宽度
+    tempEl.style.whiteSpace = 'pre-wrap'; // 防止文字换行
+    tempEl.style.fontSize = fontSize + 'px'; // 默认字体大小,可以根据需要调整
+    tempEl.style.fontFamily = fontFamily;
+   
+    // 添加文字到元素
+    tempEl.textContent = text;
+   
+    // 将元素添加到文档中
+    document.body.appendChild(tempEl);
+   
+    // 获取宽度和高度
+    const size = {
+      width: tempEl.offsetWidth,
+      height: tempEl.offsetHeight
+    };
+   
+    // 移除元素
+    document.body.removeChild(tempEl);
+   
+    return size;
+  }
+
+ export const getTextWidth = (text, fontFamily, fontSize) => {
+    const canvas = document.createElement('canvas');
+    const context = canvas.getContext('2d');
+    context.font = `${fontSize}px ${fontFamily}`;
+    const metrics = context.measureText(text);
+    return Math.ceil(metrics.width);
+  }

+ 498 - 1
src/views/sandbox_manage/common/mindmap.js

@@ -1,4 +1,5 @@
 import { Graph, Cell, Node, Path } from '@antv/x6'
+import { getTextSize, getTextWidth } from "./measure.js"
 import Hierarchy from '@antv/hierarchy'
 
 export default {
@@ -13,6 +14,9 @@ export default {
         deletedMindmapData:[],// 用于撤销删除,恢复删除掉的数据
         mindmapDataRecoverUse:[],//用于 重做时 恢复思维导图数据
       },
+      childNodeSizes:[],//数据节点内部内容宽度数组
+      linkLists:[], //link列表
+      childNodeCells:[],//存放所有child子数据节点
     }
   },
   mounted() {
@@ -190,6 +194,137 @@ export default {
       },
       true,
     )
+    //数据节点标题
+    Graph.registerNode(
+      'mindmap-child-datanode-title',
+      {
+        inherit: 'rect',
+        markup: [
+          {
+            tagName: 'rect',
+            selector: 'body',
+          },
+          {
+            tagName: 'text',
+            selector: 'text',
+          },
+        ],
+        attrs: {
+          body: {
+            rx: 4,
+            ry: 4,
+            width:132,
+            height:28,
+            fill:this.$store.state.sand.styleConfig.titleBackgoundColor,
+            strokeWidth: 1,
+            class: 'mindmap-child-datanode-title',
+          },
+          text: {
+            fontSize: 14,
+            fill: '#fff',
+            textWrap:{
+              width:-10
+            },
+            class: 'mindmap-child-datanode-title-text',
+          }
+        },
+      }
+    )
+    //数据子框节点
+    Graph.registerNode(
+      'mindmap-child-background-datanode',          
+      {
+        inherit: 'rect',
+        markup: [
+          {
+            tagName: 'rect',
+            selector: 'body',
+          },
+          {
+            tagName: 'text',
+            selector: 'text',
+          },
+        ],
+        attrs: {
+          body: {
+            strokeWidth: 1,
+            width:110,
+            height:66
+          },
+        },
+      },
+      true,
+    );
+    //数据子节点
+    Graph.registerNode(
+      'mindmap-child-datanode',          
+      {
+        inherit: 'rect',
+        markup: [
+          {
+            tagName: 'rect',
+            selector: 'body',
+          },
+          {
+            tagName: 'text',
+            selector: 'text',
+          },
+        ],
+        attrs: {
+          body: {
+            rx: 6,
+            ry: 6,
+            strokeWidth: 1,
+            width:110,
+            height:66
+          },
+          text: {
+            fontSize: 14,
+            fill:this.$store.state.sand.styleConfig.color,
+            textWrap:{
+              width:-10
+            }
+          }
+        },
+      },
+      true,
+    );
+    //数据子内部节点
+    Graph.registerNode(
+      'mindmap-grandchild-datanode',          
+      {
+        inherit: 'rect',
+        markup: [
+          {
+            tagName: 'rect',
+            selector: 'body',
+          },
+          {
+            tagName: "text",
+            selector: "text",
+          },
+          {
+            tagName: "text",
+            selector: "value",
+
+          },
+        ],
+        attrs: {
+          body: {
+            width:110,
+            height:66,
+          },
+          text: {
+            fontSize: 14,
+          },
+          value:{
+            fontSize: 14,
+
+          },
+        },
+      },
+      true,
+    );
     // 连接器
     Graph.registerConnector(
       'mindmap',
@@ -431,7 +566,29 @@ export default {
             )
           }else{
             // 有,更新下位置信息
-            currentCell.position(xGap+hierarchyItem.x,yGap+hierarchyItem.y)
+            currentCell.position(xGap+hierarchyItem.x,yGap+hierarchyItem.y);
+            if(currentCell.shape == 'mindmap-child-background-datanode' && currentCell.getChildren().length > 0){
+              let titleNodeSize = this.getTitleNodeSize(currentCell.data.Name,currentCell.size().width);
+               let childDataNode = currentCell.getChildren()[0];
+               childDataNode.position(xGap+hierarchyItem.x,yGap+hierarchyItem.y + titleNodeSize.height)
+
+               let childrens = childDataNode.getChildren() || [];
+               let cs = _.cloneDeep(childrens)
+               cs.sort((a, b) => {
+                if (a.shape === 'mindmap-child-datanode-title') return 1;
+                if (b.shape === 'mindmap-child-datanode-title') return -1;
+                return 0;
+               });
+               cs.map((v,i)=>{
+                  if(v.shape == 'mindmap-grandchild-datanode'){
+                    let m = i % 3;
+                    let w = m == 0 ? 0 : (m == 1 ? cs[0].size().width : cs[0].size().width + cs[1].size().width);
+                    v.position(xGap+hierarchyItem.x + (m + 1) * 10 + w , yGap+hierarchyItem.y + Math.floor(i / 3) * 66 + titleNodeSize.height);
+                  } else {
+                    v.position(xGap+hierarchyItem.x , yGap+hierarchyItem.y);
+                  }
+               })
+            } 
           }
    
           if (children) {
@@ -544,6 +701,346 @@ export default {
       }
       return null
     },
+    //添加数据节点
+    handleGetDataNodeWidth(list,widthIndex){
+      let arr = [[],[],[]];  //按列分组,获取当前列的内容的最大长度作为该列的最大长度
+      list.map((item,index)=>{
+        arr[index % 3].push(item)
+      });
+      let widthArr = [];
+      arr.map((arrs,arrsIndex)=>{
+         let widths = [];
+         arrs.map(item=>{
+          widths.push(getTextWidth(item.label,'Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif',14) || 0);
+          widths.push(getTextWidth(item.value,'Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif',14) || 0);
+         })
+         let max = widths.length > 0 ? Math.max.apply(null,widths) : 0;
+         if(max) widthArr[arrsIndex] = max > 106 ? max : 106;
+      });
+
+      this.childNodeSizes[widthIndex] = widthArr || [];
+      let sum =  widthArr.reduce((accumulator, current) => {
+        return accumulator + current;
+      },0);
+      sum += list.filter(_=>_).length >= 3 ? 40 : (20 + 10*(list.length - 1));
+      return sum;
+    },
+    getDataNodeSize(data,index){
+      const list = data.calculationMethod;
+      let height = Math.ceil(list.length / 3) * 66;
+      let width = this.handleGetDataNodeWidth(list,index);
+      return {
+        height:height || 66,
+        width:width || 50,
+      }
+    },
+
+    getTitleNodeSize(name,width){
+      let nameWidth = getTextWidth(name,'Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif',14) + 10;
+      let titleWidth =  nameWidth < width ? nameWidth : width;
+      titleWidth = titleWidth < 126 ? 126 : titleWidth;
+      let h = getTextSize(name,titleWidth,14,'Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif');
+      h.height = h.height < 30 ? 30 : h.height;
+      return h
+    },
+
+    addMindmapDataNodes(id,list,direction){
+        // 重做不了 清空重做栈
+        this.mindmapAssistData.mindmapDataRecoverUse = []
+        const res = this.findItem(this.mindMapDataCurrent, id);
+        const dataItem = res && res.node;
+        if(dataItem.children && dataItem.children.length > 0){  //将原数据清空
+          const types = ['mindmap-child-background','datanode-title','datanode-grandchild','datanode-child']
+          dataItem.children = dataItem.children.filter(_=>!types.includes(_.type))
+        }
+
+        this.linkLists = [];
+        this.childNodeSizes = [];
+        this.childNodeCells = [];
+        if (dataItem) {
+          list.map((_,index)=>{
+            let item = null
+            let addId ='1'
+            if(dataItem.children && dataItem.children.length>0){
+              let ids = dataItem.children[dataItem.children.length-1].id.split('-')
+              addId = parseInt(ids[ids.length-1])+1+''
+            };
+
+            let h = {height:30,width:200};
+            let titleH = {height:0,width:0}
+            if(!_.calculationMethod || !_.calculationMethod.length){
+              h = getTextSize(_.Name,200,14,'Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif');
+              h.height = h.height < 30 ? 30 : h.height;
+            } else {
+              h = this.getDataNodeSize(_,index);
+              titleH = this.getTitleNodeSize(_.Name,h.width);
+            }
+            item = {
+              id: `${id}-${addId}`,
+              type: !_.calculationMethod || !_.calculationMethod.length ? 'datanode-title' : 'mindmap-child-background',
+              label: !_.calculationMethod || !_.calculationMethod.length ? _.Name : '',
+              width: h.width,
+              height: h.height + titleH.height,
+              direction:direction,
+              data:_,
+            }
+            
+            this.linkLists.push(item);
+            if (item) {
+              if (dataItem.children) {
+                dataItem.children.push(item)
+              } else {
+                dataItem.children = [item]
+              }
+              this.mindMapDataRender();
+              if(this.childNodeCells.length == list.length){ //添加完成
+                const select_cell = this.graph.getSelectedCells()[0];
+                select_cell.setChildren(this.childNodeCells)
+              }
+            }
+          })
+        }
+    },
+    mindMapDataRender(i){  //添加数据节点的渲染
+      this.graph.startBatch('renderMindmap')
+      let mindMapType = i || i==0?this.mindmapAssistData.mindmapDataUse[i].addType:this.addTypeCurrent
+      this.mindMapDataCurrent = i || i==0?this.mindmapAssistData.mindmapDataUse[i].mindmapData:this.mindMapDataCurrent
+      this.positionCurrent = i || i==0?this.mindmapAssistData.mindmapDataUse[i].position:this.positionCurrent
+      const result = Hierarchy.mindmap(this.mindMapDataCurrent, {
+        direction: 'H',
+        getHeight(d) {
+          return d.height
+        },
+        getWidth(d) {
+          return d.width
+        },
+        getHGap() {
+          return 40
+        },
+        getVGap() {
+          return 20
+        },
+        getSide: (d) => {
+          return mindMapType.indexOf('double') != -1?d.data.direction || 'left':'right'
+        }
+      })
+      const cells = [];
+      let xGap = this.positionCurrent?this.positionCurrent.x-result.x:0
+      let yGap = this.positionCurrent?this.positionCurrent.y-result.y:0
+      const traverse = (hierarchyItem) => {
+        if (hierarchyItem) {
+          const { data, children } = hierarchyItem
+          let mindmapDirection = mindMapType.indexOf('double') != -1?data.direction:'right'
+          let currentCell=this.graph.getCellById(data.id)
+          const shapesObject = {
+             'datanode-title':'mindmap-child-datanode-title',
+             'datanode-child':'mindmap-child-datanode',
+             'datanode-grandchild':'mindmap-grandchild-datanode',
+             'mindmap-child-background':'mindmap-child-background-datanode'
+          }
+          if(!currentCell){
+            // 没有 新增
+            const wrapNode = this.graph.createNode({
+              id: data.id,
+              shape:shapesObject[data.type],
+              x: xGap+hierarchyItem.x,
+              y: yGap+hierarchyItem.y,
+              width: data.width,
+              height: data.height,
+              label: data.label,
+              type: data.type,
+              attrs:{
+                body: {
+                  stroke: data.type == 'datanode-title' ? this.$store.state.sand.styleConfig.titleBorderColor : 'transparent',
+                  fill: data.type == 'datanode-title' ? this.$store.state.sand.styleConfig.titleBackgoundColor :  'transparent',
+                },
+                text:{
+                  fill:data.type == 'datanode-title' ? this.$store.state.sand.styleConfig.titleTextColor  :  'transparent',
+                }
+              },
+              zIndex:0,
+              data:data.data,
+            })
+            cells.push(wrapNode);
+            if(data.type == 'mindmap-child-background' || data.type == 'datanode-title') this.childNodeCells.push(wrapNode);
+            
+            let titleNodeSize = this.getTitleNodeSize(data.data.Name,data.width);
+            let currentNode = null;
+            if(data.type == 'mindmap-child-background'){
+              currentNode = this.graph.createNode({
+                id: `${data.id}+0` ,
+                shape:'mindmap-child-datanode',
+                x: xGap+hierarchyItem.x,
+                y: yGap+hierarchyItem.y + titleNodeSize.height,
+                width: data.width,
+                height: data.height - titleNodeSize.height,
+                label: '',
+                type:'datanode-child',
+                attrs:{
+                  body: {
+                    stroke: this.$store.state.sand.styleConfig.dataBorderColor,
+                    fill: this.$store.state.sand.styleConfig.dataBackgroundColor,
+                    'pointer-events': 'none',
+                  },
+                  text:{
+                    fill:this.$store.state.sand.styleConfig.dataTextColor,
+                    'pointer-events': 'none',
+                  }
+                },
+                zIndex:0,
+                data:data.data,
+              })
+              cells.push(currentNode);
+              wrapNode.setChildren([currentNode])
+            }
+
+
+            let titleNode = null;
+            if(data.data && data.data.detailParams && data.data.detailParams.id && data.data && data.data.calculationMethod && data.data.calculationMethod.length > 0){
+              titleNode = this.graph.createNode({
+                id: `${data.id}-0`,
+                shape:'mindmap-child-datanode-title',
+                x: xGap+hierarchyItem.x,
+                y: yGap+hierarchyItem.y,
+                width: titleNodeSize.width,
+                height: titleNodeSize.height,
+                label: data.data.Name,
+                type: 'datanode-title',
+                attrs:{
+                  body: {
+                    stroke: this.$store.state.sand.styleConfig.titleBorderColor,
+                    fill: this.$store.state.sand.styleConfig.titleBackgoundColor
+                  },
+                  text:{
+                    fill:this.$store.state.sand.styleConfig.titleTextColor 
+                  }
+                },
+                zIndex:0,
+                data:data.data,
+              });
+              cells.push(titleNode);
+            }
+            // 处理内部数据节点
+            if(data.data && data.data.calculationMethod && data.data.calculationMethod.length > 0){
+              let cNodes = data.data.calculationMethod.map((v,i)=>{
+                let linkIndex = this.linkLists.findIndex(x=>x.id == data.id);
+                let widthArr = this.childNodeSizes[linkIndex] ? this.childNodeSizes[linkIndex] : [];
+                let m = i % 3;
+                let w = m == 0 ? 0 : (m == 1 ? widthArr[0] : widthArr[0] + widthArr[1])
+                let innerNode = this.graph.createNode({
+                  id: `${data.id}-${i + 1}`,
+                  shape:'mindmap-grandchild-datanode',
+                  x: xGap+hierarchyItem.x + (m + 1) * 10 + w,
+                  y: yGap+hierarchyItem.y + titleNodeSize.height + Math.floor(i / 3) * 66,
+                  width: widthArr[m],
+                  height: 66,
+                  type: 'datanode-grandchild',
+                  attrs:{
+                    body:{
+                      stroke: '',
+                      strokeWidth: 0,
+                      fill: 'transparent',
+                      'pointer-events': 'none',
+                    },
+                    text:{
+                      fill:this.$store.state.sand.styleConfig.dataTextColor,
+                      text:v.label,
+                      refWidth:1,
+                      refY: 10,
+                      textVerticalAnchor:'top',
+                      'pointer-events': 'none',
+                    },
+                    value:{
+                      fill:this.$store.state.sand.styleConfig.dataTextColor,
+                      text:v.value,
+                      refWidth:1,
+                      refX:"50%",
+                      refY: '100%',
+                      refY2:-10,
+                      textVerticalAnchor:'bottom',
+                      'text-anchor':'middle',
+                      'pointer-events': 'none',
+                    },
+                  },
+                  zIndex:0,
+                  data:v,
+                });
+                cells.push(innerNode);
+                return innerNode
+              })
+              currentNode.setChildren(titleNode ? [...cNodes,titleNode] : cNodes)
+            }
+          }else{
+            // 有,更新下位置信息
+            currentCell.position(xGap+hierarchyItem.x,yGap+hierarchyItem.y);
+            if(currentCell.shape == 'mindmap-child-background-datanode' && currentCell.getChildren().length > 0){
+              let titleNodeSize = this.getTitleNodeSize(currentCell.data.Name,currentCell.size().width);
+               let childDataNode = currentCell.getChildren()[0];
+               childDataNode.position(xGap+hierarchyItem.x,yGap+hierarchyItem.y + titleNodeSize.height)
+
+               let childrens = childDataNode.getChildren() || [];
+               let cs = _.cloneDeep(childrens)
+               cs.sort((a, b) => {
+                if (a.shape === 'mindmap-child-datanode-title') return 1;
+                if (b.shape === 'mindmap-child-datanode-title') return -1;
+                return 0;
+               });
+               cs.map((v,i)=>{
+                  if(v.shape == 'mindmap-grandchild-datanode'){
+                    let m = i % 3;
+                    let w = m == 0 ? 0 : (m == 1 ? cs[0].size().width : cs[0].size().width + cs[1].size().width);
+                    v.position(xGap+hierarchyItem.x + (m + 1) * 10 + w , yGap+hierarchyItem.y + Math.floor(i / 3) * 66 + titleNodeSize.height);
+                  } else {
+                    v.position(xGap+hierarchyItem.x , yGap+hierarchyItem.y);
+                  }
+               })
+            } 
+          }
+          if (children) {
+            children.forEach((item) => {
+              const { id, data } = item
+              let mindmapChildDirection = mindMapType.indexOf('double') != -1?data.direction:'right'
+              let currentEdge=this.graph.getCellById(data.id)
+              if(!currentEdge){
+                cells.push(
+                  this.graph.createEdge({
+                    shape: 'mindmap-edge',
+                    attrs:{
+                      line:{
+                        stroke:this.$store.state.sand.styleConfig.lineColor
+                      }
+                    },
+                    source: {
+                      cell: hierarchyItem.id,
+                      anchor: {
+                        name: 'center',
+                        args: {
+                          dx: mindmapChildDirection=='right'?'25%':mindmapChildDirection=='left'?'-25%':0,
+                        },
+                      },
+                    },
+                    target: {
+                      cell: id,
+                      anchor: {
+                        name: mindmapChildDirection =='left'?'right':'left',
+                      },
+                    },
+                  }),
+                )
+              }
+
+              traverse(item)
+            })
+          }
+        }
+      }
+      traverse(result)
+      // 排下序,把边放最后面 不然 边 会找不到 节点
+      let sortCells = cells.sort(cell => cell.shape.indexOf('edge'))
+      let cells_result = sortCells.sort(cell => cell.shape.indexOf('mindmap-grandchild-datanode'));
+      this.graph.addCell(cells_result)
+      this.graph.stopBatch('renderMindmap')
+    },
     getMindmapDataUse(){
       return this.mindmapAssistData
     },

+ 23 - 4
src/views/sandbox_manage/common/options.js

@@ -1,4 +1,4 @@
-
+import bus from "@/api/bus";
 /* 右键菜单配置 */
 export const contextMenuOption = [
 	{
@@ -14,15 +14,34 @@ export const contextMenuOption = [
 		show:true
 	},
 	{
-		label: '添加链接',
+		label: '添加节点数据',
 		key: 'addLink',
 		icon: 'el-icon-link',
 		show:true
 	},
 	{
-		label: '清除链接',
+		label: '清除节点数据',
 		key: 'deleteLink',
 		icon: 'el-icon-delete',
 		show:true
 	},
-]
+]
+//计算方式
+export const calculateOption = [
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.Detail.e_latest_date') : '最新日期',source: 98,fromEdbKey:98 },
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.Detail.e_latest_value') : '最新值',source: 99,fromEdbKey:99 },
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.to_month_quarter') : '累计值转月/季值',source: 1,fromEdbKey:5,source2: 2},
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.on_year') : '同比值',source: 3,fromEdbKey:6 },
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.differ') : '同差值',source: 4,fromEdbKey:7 },
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.rule_move_average') : 'N期移动均值',source: 5,fromEdbKey:8 },
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.period_over_period') : 'N期环比值',source: 6,fromEdbKey:12 },
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.period_difference') : 'N期环差值',source: 7,fromEdbKey:13 },
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.up_conver') : '升频',source: 8,fromEdbKey:14 },
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.time_move') : '时间移位',source: 10,fromEdbKey:22 },
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.super_season') : '超季节性',source: 11,fromEdbKey:35 },
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.annualized') : '年化值',source: 12,fromEdbKey:52 },
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.frequency') : '降频',source: 9,fromEdbKey:51 },
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.cumulate') : '累计值',source: 13,fromEdbKey:62 ,source2: 14},
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.ex_smooth') : '指数修匀',source: 15,fromEdbKey:'alpha' },
+	{ label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.day_mean') : '日均值',source: 16,fromEdbKey:75 },
+]

+ 28 - 4
src/views/sandbox_manage/common/toolConfig.js

@@ -80,7 +80,13 @@ export const styleSettings=[
 		color:'#1841AA',
 		textColor:'#1841AA',
 		borderColor:'#1841AA',
-		lineColor:'#1841AA'
+		lineColor:'#1841AA',
+
+		dataBackgroundColor:'#FFFFFF',
+		dataBorderColor:'#0052D9',
+		titleBackgoundColor:'#1841AA',
+		titleBorderColor:'#1841AA',
+		titleTextColor:'#FFFFFF',
 	},
 	{
 		id:2,
@@ -88,7 +94,13 @@ export const styleSettings=[
 		color:'#FFFFFF',
 		textColor:'#1841AA',
 		borderColor:'#1841AA',
-		lineColor:'#1841AA'
+		lineColor:'#1841AA',
+
+		dataBackgroundColor:'#FFFFFF',
+		dataBorderColor:'#1841AA',
+		titleBackgoundColor:'#1841AA',
+		titleBorderColor:'#1841AA',
+		titleTextColor:'#FFFFFF',
 	},
 	{
 		id:3,
@@ -96,7 +108,13 @@ export const styleSettings=[
 		color:'#333333',
 		textColor:'#333333',
 		borderColor:'#333333',
-		lineColor:'#333333'
+		lineColor:'#333333',
+
+		dataBackgroundColor:'#FFFFFF',
+		dataBorderColor:'#333333',
+		titleBackgoundColor:'#333333',
+		titleBorderColor:'#333333',
+		titleTextColor:'#FFFFFF',
 	},
 	{
 		id:4,
@@ -104,6 +122,12 @@ export const styleSettings=[
 		color:'#AA3218',
 		textColor:'#AA3218',
 		borderColor:'#AA3218',
-		lineColor:'#AA3218'
+		lineColor:'#AA3218',
+
+		dataBackgroundColor:'#FFFFFF',
+		dataBorderColor:'#AA3218',
+		titleBackgoundColor:'#AA3218',
+		titleBorderColor:'#AA3218',
+		titleTextColor:'#FFFFFF',
 	}
 ]

+ 53 - 1
src/views/sandbox_manage/index_new_version.vue

@@ -106,6 +106,18 @@
         </div>
         <div id="link-reference" slot="reference"></div>
       </el-popover>
+      <el-popover
+          placement="right"
+          trigger="manual"
+          v-model="calculationPopoverObj.show">
+          <div class="calculation-wrap">
+              <div class="calculation-title">{{ $t('SandboxManage.SandFlow.calculation_configuration_parameters') }}:</div>
+              <div v-for="(item,index) in calculationPopoverObj.list" :key="index">
+                    {{ item.label }} : {{ item.tip }}
+              </div>
+          </div>
+          <div id="calculation-reference" slot="reference"></div>
+        </el-popover>
       </div>
     </div>
     <!-- 目录自定义按钮区域 -->
@@ -314,7 +326,12 @@ import {reportVarietyInterence} from '@/api/modules/reportVariety'
         linkNode:null,
         popoverTimeout:null,
         isSlideLeft:false,
-        locationParentIds:''
+        locationParentIds:'',
+        calculationPopoverObj:{
+          show:false,
+          dom:null,
+          list:[],
+        },
       }
     },
     created(){
@@ -329,6 +346,7 @@ import {reportVarietyInterence} from '@/api/modules/reportVariety'
     mounted(){
       this.popoverDom = $('#link-popover')[0];
       this.popoverTriggerDom = $('#link-reference')[0];
+      this.calculationPopoverObj.dom = $('#calculation-reference')[0];
       
       this.popoverDom.addEventListener('mouseenter',this.clearPopoverTimeout)
       this.popoverDom.addEventListener('mouseleave',this.closePopover)
@@ -1066,9 +1084,26 @@ import {reportVarietyInterence} from '@/api/modules/reportVariety'
       init() {
         const graph = new myGraph('sand-chart-body',null,'view');
         this.graph = graph;
+        graph.on('node:click',({ node, e }) => {
+          if(node && node.shape == 'mindmap-child-datanode-title' && node.data){ //数据节点标题跳转
+            this.navigateTo && this.navigateTo(node.data);
+          }
+        });
+
         graph.on('node:mouseenter', ({ node, e }) => {
           let data = node.data
           this.linkNode = node
+
+          if(data && data.calculationMethod && data.calculationMethod.length > 0){
+                let clinetPositon=this.graph.localToClient(node.position())
+                let size=node.size()
+                this.calculationPopoverObj.dom.style.left = clinetPositon.x + size.width * this.graph.zoom() +'px';
+                this.calculationPopoverObj.dom.style.top = clinetPositon.y + size.height / 2 * this.graph.zoom() + 'px';
+                this.calculationPopoverObj.list = data.calculationMethod.filter(_=>_.tip) || [];
+                if(this.calculationPopoverObj.list.length > 0){
+                  this.calculationPopoverObj.show=true;
+                }
+          }
           if(data && data.linkData && data.linkData.length>0){
             this.popoverFlod = data.linkFold
             this.popoverVisible=false
@@ -1127,6 +1162,9 @@ import {reportVarietyInterence} from '@/api/modules/reportVariety'
               this.popoverTimeout=null
             },500)
           }
+            this.calculationPopoverObj.dom.style.left = '-99999px';
+            this.calculationPopoverObj.dom.top = '-99999px';
+            this.calculationPopoverObj.show=false;
         })
 		  },
       foldLink(){
@@ -1508,6 +1546,13 @@ import {reportVarietyInterence} from '@/api/modules/reportVariety'
     left: -99999px;
     background-color: transparent;
   }
+  #calculation-reference{
+    position: fixed;
+    z-index: -1;
+    top: -99999px;
+    left: -99999px;
+    background-color: transparent;
+  }
   .minimap{
     position:absolute;
     right:6px;
@@ -1517,6 +1562,13 @@ import {reportVarietyInterence} from '@/api/modules/reportVariety'
   #sand-chart-body{
     flex: 1;
   }
+  .mindmap-child-datanode-title{
+    cursor: pointer;
+  }
+  .mindmap-child-datanode-title-text{
+    cursor: pointer;
+    pointer-events: none;
+  }
   .x6-graph-scroller {
     flex: 1;
   }

+ 290 - 121
src/views/sandbox_manage/sandFlowNew/components/addLInkDia.vue

@@ -1,9 +1,10 @@
 <template>
-    <el-dialog :modal-append-to-body='false' :title="$t('SandboxManage.SandFlow.add_link')" :visible.sync="show" 
-    :close-on-click-modal="false" width="872px" top="5vh" @close="cancelHandle">
+    <div>
+      <el-dialog v-dialogDrag :modal-append-to-body='false' :title="$t('SandboxManage.SandFlow.add_node_data')" :visible.sync="show" 
+    :close-on-click-modal="false" width="1000px" top="5vh" @close="cancelHandle" v-show="!dialogDisplayNone">
       <div class="add-link-box">
         <div class="link-box-option">
-          <el-select v-model="addLinkSearchParams.linkType" placeholder="链接类型" style="width: 240px;" @change="changeLinkType">
+          <el-select v-model="addLinkSearchParams.linkType" placeholder="节点数据类型" style="width: 240px;" @change="changeLinkType">
             <el-option :label="item.label" :value="item.value" v-for="item in linkTypeList" :key="item.value"></el-option>
           </el-select>
           <el-select v-if="addLinkSearchParams.linkType==1"
@@ -75,6 +76,20 @@
             <i slot="prefix" class="el-input__icon el-icon-search"></i>
           </el-input>
         </div>
+        <div class="link-box-tags">
+            <div class="link-box-tag"  
+                 v-for="(item,index) in linkListInShow" 
+                 :key="item.RId" 
+                :class="{'unchoose-tag':item.Id != activeItem.Id,'choosed-tag':item.Id == activeItem.Id}">
+              <span @dblclick.stop="editLinkName(item)" 
+                    v-if="!item.editing" 
+                    @click="linkClick(item)"
+                    :style="{color:item.Id == activeItem.Id?'#0052D9':'#666666'}">{{ item.Name }}</span>
+              <el-input v-else @blur="editLinkNameFinish(item)" 
+                v-model.trim="editingLabel" class="label-edit-input" ref="labelEditInput"/>
+              <img src="~@/assets/img/sand_new/delete_outline_1.png" @click="linkDelete(item,index)">
+            </div>
+        </div>
         <div class="link-box-content">
           <!-- 指标 -->
           <div class="link-content-dataIndex" v-if="addLinkSearchParams.linkType==1 && databaseTableData && databaseTableData.length>0">
@@ -89,46 +104,40 @@
                 <el-table-column :label="$t('Table.frequency')" align="center" width="50">
                   <template slot-scope="scope">{{ getFrequencyTrans(scope.row.Frequency||'null') }}</template>
                 </el-table-column>
-                <el-table-column :label="$t('Table.unit')" align="center">
+                <el-table-column :label="$t('Table.unit')" align="center" width="100">
                   <template slot-scope="scope">{{ currentLang==='en'?(scope.row.UnitEn||getUnitTrans(scope.row.Unit)):getUnitTrans(scope.row.Unit) }}</template>
                 </el-table-column>
-                <el-table-column :label="$t('Table.start_time')" align="center" width="100">
-                  <template slot-scope="scope">{{ scope.row.StartDate }}</template>
+                <el-table-column :label="$t('Edb.Detail.e_latest_value')" align="center" width="100">
+                  <template slot-scope="scope">{{ scope.row.LatestValue }}</template>
                 </el-table-column>
-                <el-table-column :label="$t('Table.update_time')" align="center" width="160">
-                  <template slot-scope="scope">{{ scope.row.ModifyTime }}</template>
+                <el-table-column :label="$t('Edb.Detail.e_latest_date')" align="center" width="130">
+                  <template slot-scope="scope">{{ scope.row.LatestDate }}</template>
                 </el-table-column>
                 <el-table-column :label="$t('Table.source')" align="center">
                   <template slot-scope="scope">{{ scope.row.SourceName }}</template>
                 </el-table-column>
-                <el-table-column :label="$t('Table.column_operations')" align="center" width="50">
-                  <template slot-scope="scope">
-                    <span class="delete-button">{{$t('Table.delete_btn')}}</span>
-                  </template>
-                </el-table-column>
               </el-table>
-              <ul 
-                class="value-ul" 
-                ref="valueUl" 
-                @scroll="databaseScrollHandle" 
-                v-show="databaseList.length">
-                <li
-                  class="value-item"
-                  v-for="item in databaseList"
-                  :key="item.EdbDataId"
-                >
-                  <span class="value-label">
-                    <span style="position: relative;">
-                      <i class="new-tag" v-if="databaseTableData[0].LatestDate===item.DataTime"></i>
-                      {{item.DataTime}}
-                    </span>
-                  </span>
-                  <span :class="['value-label',{'predict-act': databaseTableData[0].DataInsertConfig.Date===item.DataTime}]" style="min-width:200px;text-align:center;">
-                    <span :class="['value-style',{'predict-act': databaseTableData[0].DataInsertConfig.Date===item.DataTime}]">{{item.Value}}</span>
-                  </span>
-                </li>
-                <li class="nodata value-item" v-if="!databaseList.length">{{$t('Table.prompt_slogan')}}</li>
+              <ul class="link-count-wrap">
+                  <li v-for="item in calculateOption" 
+                      :key="item.source" 
+                      class="link-count-item" 
+                      :class="{'link-count-item-un':!handleCountChoose(item),'link-count-item-on':handleCountChoose(item)}"
+                      @click="clickCountItem(item)">
+                      <span>{{ item.label }}</span>
+                      <img v-if="handleCountChoose(item) && item.source != 98 && item.source != 99"  
+                        src="~@/assets/img/sand_new/blue_edit_icon.png" 
+                        style="width: 13px;height: 13px;margin-left: 8px;" 
+                        @click.stop="handleEditCal(item)">
+                  </li>
               </ul>
+              <div v-if="threeCalculation && threeCalculation.length > 0" class="calculate-result-wrap">
+                 <div class="calculate-result-title">{{ $t('ETableChildren.calculate_result') }}</div>
+                 <div class="calculate-result-table">
+                     <div v-for="(item,index) in threeCalculation" :key="index" class="calculate-result-table-tr">
+                          <div v-for="(v) in item" :key="v.source" class="calculate-result-table-item">{{ v.label }}:{{ v.value }}</div>
+                     </div>
+                 </div>
+              </div>
             </template>
 
             <noDataAuth v-if="databaseTableData[0].HaveOperaAuth===false" :text="$t('MsgPrompt.no_edb_auth')"/>
@@ -169,20 +178,25 @@
           </div>
           <tableNoData :text="$t('Table.prompt_slogan')" v-else/>
         </div>
-        <div class="link-box-tags">
-          <div class="link-box-tag" v-for="(item,index) in checkedLinkList" :key="item.RId">
-            <span @dblclick.stop="editLinkName(item)" v-if="!item.editing" @click="linkClick(item)">{{ item.Name }}</span>
-            <el-input v-else @blur="editLinkNameFinish(item)" 
-              v-model.trim="editingLabel" class="label-edit-input" ref="labelEditInput"/>
-            <img src="~@/assets/img/sand_new/delete_outline_1.png" @click="linkDelete(item,index)">
-          </div>
-        </div>
         <div class="link-box-buttons">
           <el-button type="info" style="width:120px;color:#333333;background-color:#F4F8FE" @click="cancelHandle">{{$t('Dialog.cancel_btn')}}</el-button>
           <el-button type="primary" style="width:120px;margin-left: 30px;" @click="saveLink">{{$t('Dialog.confirm_btn')}}</el-button>
         </div>
       </div>
 		</el-dialog>
+    <calculateEdb
+       :isShow.sync="isOpenCalculationDia"
+       :calculationItem="calculationItem"
+       :activeLink="activeItem"
+       :linkList="linkListInShow"
+       @editEdbName="handleEditEdbName"
+       @addEdbItem="handleAddEdbItem"
+       @changeActiveEdb="handleChangeActiveEdb"
+       @edbDelete="handleEdbDelete"
+       @addCalculation="handleAddCalculation"
+       @handleCloseDialog="handleCloseDialog"
+      ></calculateEdb>
+    </div>
 </template>
 
 <script>
@@ -190,11 +204,13 @@ import { chartSetMixin } from '../../../dataEntry_manage/mixins/chartPublic'
 import * as sheetInterface from "@/api/modules/sheetApi.js";
 import mPage from "@/components/mPage.vue";
 import Chart from '../../../dataEntry_manage/components/chart.vue'
+import calculateEdb from './calculateEdb.vue';
 import { dataBaseInterface,reportlist} from '@/api/api.js';
 import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
+import { calculateOption } from "../../common/options"
   export default {
     components:{
-      mPage,Chart
+      mPage,Chart,calculateEdb
     },
     props:{
       show:{
@@ -211,6 +227,9 @@ import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
       /* 选中搜索指标 展开目录 选中指标 展示数据 */
       search_dataBaseId(newval) {
         if (newval) {
+          if(this.linkListInShow.find(_=>_.Id == newval)){
+               return this.$message.warning(this.$t('SandboxManage.SandFlow.data_already_exists'))
+          }
           if(this.addLinkSearchParams.linkType==1){
             let search_obj = this.dataBaseOptions.find(
               (item) => item.EdbInfoId === newval
@@ -223,14 +242,16 @@ import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
                 Type:this.addLinkSearchParams.linkType,
                 editing:false,
                 databaseType:search_obj.EdbInfoType, //0 普通指标 | 1 预测指标
+                EdbType:search_obj.EdbType || 0,
                 detailParams:{
                   code:search_obj.UniqueCode,
                   id:search_obj.EdbInfoId,
                   classifyId:search_obj.ClassifyId
-                }
+                },
+                calculationMethod:[],
               }
               this.checkedLinkList.push(this.activeItem)
-              
+              this.handleLinkListInShow()
               this.activeItemRId=this.addLinkSearchParams.linkType+'-'+search_obj.EdbInfoId
               this.initGetData()
             }
@@ -248,9 +269,11 @@ import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
                 detailParams:{
                   code:search_obj.UniqueCode,
                   id:search_obj.ChartInfoId
-                }
+                },
+                calculationMethod:[],
               }
               this.checkedLinkList.push(this.activeItem)
+              this.handleLinkListInShow()
               this.activeItemRId=this.addLinkSearchParams.linkType+'-'+search_obj.ChartInfoId
               this.getChartDetail(search_obj.ChartInfoId)
             }
@@ -265,17 +288,26 @@ import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
       },
       show(value){
         if(value){
-          this.checkedLinkList = JSON.parse(JSON.stringify(this.linkList))
+          this.isOpenCalculationDia = false;
+          this.checkedLinkList = JSON.parse(JSON.stringify(this.linkList.map(_=>({calculationMethod:[],..._}))))
+          this.handleLinkListInShow()
           let firstCheckedLink = this.checkedLinkList[0]
           if(firstCheckedLink){
-            this.activeItemRId=''
+            this.addLinkSearchParams.linkType = firstCheckedLink.Type;
+            this.activeItemRId='';
             this.linkClick(firstCheckedLink)
           }else{
             this.addLinkSearchParams.linkType=1
           }
-          this.changeLinkType()
+          this.doDataInit()
         }
-      }
+      },
+      activeItem:{
+        deep:true,
+        handler(){
+          this.handleThreeCalculation()
+        }
+      },
     },
     computed:{
         linkTypeList(){
@@ -284,7 +316,10 @@ import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
                 {value:2,label:this.$t('SandboxManage.SandFlow.link_type_opt2')},
                 {value:3,label:this.$t('SandboxManage.SandFlow.link_type_opt3')}
             ]
-        }
+        },
+        calculateOption(){
+          return calculateOption
+        },
     },
     data() {
       return {
@@ -315,15 +350,105 @@ import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
         reportList:[],
         selections:[],
         checkedLinkList:[],
+        linkListInShow:[],//当前种类下的标签
         reportTotal:0,
         editingLabel:'',
         activeItemRId:'',
-        activeItem:''
+        activeItem:'',
+        threeCalculation:[],//三个一组
+        isOpenCalculationDia:false,
+        calculationItem:{},
+        dialogDisplayNone:false,
       }
     },
     methods: {
-      // -------------------------------添加链接
+      handleThreeCalculation(){
+        let i = this.checkedLinkList.findIndex(_=>_.RId == this.activeItem.RId);
+        if(i < 0) return;
+        if(!this.checkedLinkList[i].calculationMethod) this.checkedLinkList[i].calculationMethod = [];
+        
+        let data = this.checkedLinkList[i].calculationMethod || [];
+        let arr = [];
+        if(data && data.length > 0) {
+          for(var x=0;x<data.length;x+=3){
+              arr.push(data.slice(x,x+3));
+          }
+        } 
+        this.threeCalculation = arr || [];
+      },
+      handleCountChoose(item){
+        let i = this.checkedLinkList.findIndex(_=>_.RId == this.activeItem.RId);
+        if(i < 0) return false;
+        let arr = this.checkedLinkList[i].calculationMethod || [];
+        return arr.find(_=>_.source == item.source || _.source == item.source2);
+      },
+      handleEditCal(v){ //编辑状态
+          const getManySourseJump = (item) => {
+            let i = this.checkedLinkList.find(_=>_.RId == this.activeItem.RId);
+            if(i && i.calculationMethod && i.calculationMethod.length > 0){
+              let calItem =  i.calculationMethod.find(_=>_.source == item.source || _.source == item.source2);
+              let _ = !calItem ? item : {
+                ...item,
+                source:calItem.source
+              }
+              return _;
+            } else {
+              return item;
+            }
+
+          }
+          let hasManySource = v.source2 ? true : false;
+          this.calculationItem = !hasManySource ? v : getManySourseJump(v);
+          this.isOpenCalculationDia = true;
+          this.dialogDisplayNone = true;
+      },
+      clickCountItem(item){
+         let i = this.checkedLinkList.findIndex(_=>_.RId == this.activeItem.RId);
+         if(i < 0) return;
+         if(!this.checkedLinkList[i].calculationMethod) this.checkedLinkList[i].calculationMethod = [];
+         let isChoosed = this.checkedLinkList[i].calculationMethod.findIndex(_=>_.source == item.source || _.source == item.source2);
+         if(isChoosed >= 0){ //已经选中
+          this.checkedLinkList[i].calculationMethod.splice(isChoosed,1)
+         } else { //未选中
+              if(item.source == 99 || item.source == 98){ //最新值和最新日期
+                this.checkedLinkList[i].calculationMethod.unshift({
+                  ...item,
+                  value:item.source == 99 ? this.databaseTableData[0].LatestValue : this.databaseTableData[0].LatestDate
+                 })
+              } else {
+                this.calculationItem = item;
+                this.isOpenCalculationDia = true;
+                this.dialogDisplayNone = true;
+              }
+        };
+        this.handleThreeCalculation();
+      },
+      handleAddCalculation({item}){
+        let i = this.checkedLinkList.findIndex(_=>_.RId == this.activeItem.RId);
+        if(i < 0) return;
+        if(!this.checkedLinkList[i].calculationMethod) this.checkedLinkList[i].calculationMethod = [];
+        let x = this.calculateOption.find(_=>item.source == _.source || item.source == _.source2);
+        let isChoosed = this.checkedLinkList[i].calculationMethod.findIndex(_=>_.source == x.source || _.source == x.source2);
+        if(isChoosed >= 0) {
+          this.checkedLinkList[i].calculationMethod.splice(isChoosed,1);
+        }
+        this.checkedLinkList[i].calculationMethod.unshift(item);
+        this.handleThreeCalculation();
+      },
       changeLinkType(){
+        this.doDataInit();
+        this.handleLinkListInShow();
+          let firstCheckedLink = this.linkListInShow[0];
+          if(firstCheckedLink){
+            this.activeItemRId=''
+            this.linkClick(firstCheckedLink)
+          }
+          this.doDataInit();
+      },
+      handleLinkListInShow(){
+        this.linkListInShow = (this.checkedLinkList || []).filter(_=>_.Type == this.addLinkSearchParams.linkType);
+      },
+      doDataInit(){
         this.search_dataBaseId=''
         this.dataBaseOptions=[]
         this.dataBaseParams={
@@ -439,7 +564,9 @@ import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
         const chartTypeMap = {
           7: this.initBarData, //柱形图
           10: this.initSectionScatterData, //截面散点
-          11: this.initRadarData(res.Data)
+          // (res.Data)
+          11: this.initRadarData, //雷达图
+          14:this.initSectionalCombinationChart, //截面组合图
         }
         chartTypeMap[this.chartInfo.ChartType] && chartTypeMap[this.chartInfo.ChartType](res.Data);
 
@@ -460,31 +587,33 @@ import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
         this.activeItemRId = item.RId
         this.activeItem = item
         this.addLinkSearchParams.linkType=item.Type
+        this.handleLinkListInShow();
         if(item.Type==3){
           if(!config.noInfo){
             this.$message.info('研报类型的暂无回显')
           }
         }else if(item.Type==1){          
-          this.changeLinkType()
+          this.doDataInit()
           this.initGetData() 
         }else if(item.Type==2){
-          this.changeLinkType()
+          this.doDataInit()
           this.getChartDetail(item.Id)
         }
 
       },
       linkDelete(item,index){
         let rId = item.RId
-        this.checkedLinkList.splice(index,1)
+        this.linkListInShow.splice(index,1);
+        this.checkedLinkList.splice(this.checkedLinkList.findIndex(_=>_.RId == rId),1);
         if(this.activeItemRId == rId){
-          let firstCheckedLink = this.checkedLinkList[0]
+          let firstCheckedLink = this.linkListInShow[0]
           if(firstCheckedLink){
             this.linkClick(firstCheckedLink,{noInfo:true})
           }else{
-            this.activeItemRId = ""
-            this.addLinkSearchParams.linkType=1
+            this.activeItemRId = "";
+            this.activeItem = {};
           }
-          this.changeLinkType()
+          this.doDataInit()
         }
 
         if(item.Type==3){
@@ -498,10 +627,36 @@ import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
         if (this.editingLabel) {
           item.editing=false
           item.Name = this.editingLabel
+          let i = this.checkedLinkList.findIndex(_=>_.RId == item.RId);
+          if(i >= 0) this.checkedLinkList[i].Name = this.editingLabel;
         } else {
           this.$message.warning('不能为空');
         }
       },
+      handleEditEdbName(options){
+          let {item} = options;
+          let i = this.checkedLinkList.findIndex(_=>_.RId == item.RId);
+          if(i >= 0) this.checkedLinkList[i].Name = item.Name;
+          let j = this.linkListInShow.findIndex(_=>_.RId == item.RId);
+          if(j >= 0) this.linkListInShow[j].Name = item.Name;
+      },
+      handleAddEdbItem(options){
+          let {item} = options;
+          this.doDataInit()
+          this.activeItem = item;
+          this.checkedLinkList.push(item)
+          this.handleLinkListInShow()
+          this.activeItemRId=item.RId;
+          this.initGetData()
+      },
+      handleChangeActiveEdb({item}){
+         if(!item) return;
+         this.linkClick(item)
+      },
+      handleEdbDelete({item}){
+        let index = this.linkListInShow.findIndex(_=>_.RId == item.RId)
+        this.linkDelete(item,index)
+      },
       searchReport(){
         this.reportParams.CurrentIndex=1
         if(!this.reportKeyWord){
@@ -559,8 +714,10 @@ import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
               Name:item.Name,
               Type:this.addLinkSearchParams.linkType,
               editing:false,
-              detailParams:{id:item.Id,code:item.Code}
+              detailParams:{id:item.Id,code:item.Code},
+              calculationMethod:[]
             })
+            this.handleLinkListInShow()
           }
         })
         //有就去掉
@@ -569,13 +726,18 @@ import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
           let index = this.checkedLinkList.findIndex(link => rId==link.RId)
           if(index!=-1){
             this.checkedLinkList.splice(index,1)
+            this.handleLinkListInShow()
           }
         })
       },
       saveLink(){
         this.$emit("saveLink", this.checkedLinkList);
       },
+      handleCloseDialog(){
+        this.dialogDisplayNone = false;
+      },
       cancelHandle(){
+        this.linkListInShow = [];
         this.$emit("update:show", false);
       }
     },
@@ -584,78 +746,78 @@ import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
 
 <style lang="scss" scoped>
     .add-link-box{
+      max-height: 72vh;
+      overflow: auto;
       padding: 15px 40px 35px;
       .link-box-option{
         display: flex;
         align-items: center;
         justify-content: space-between;
-        margin-bottom: 30px;
+        margin-bottom: 20px;
       }
       .link-box-content{
         margin-bottom: 30px;
         .link-content-dataIndex{
           display: flex;
           flex-direction: column;
-          .value-ul {
-            flex-grow: 1;
-            overflow-y: auto;
-            margin-top: 10px;
-            height: 200px;
-            border-bottom: 1px solid #EBEFF6;
-            .value-item {
-              /* width: 100%; */
-              padding: 10px 0;
-              border: 1px solid #dcdfe6;
-              border-bottom: none;
-              display: flex;
-              justify-content: space-around;
-              >span{
-                padding:0 16px;
+          .link-count-wrap{
+             margin-top: 13px;
+             display: flex;
+             justify-content: start;
+             align-items: center;
+             flex-wrap: wrap;
+             .link-count-item{
+                cursor: pointer;
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                margin-top: 20px;
+                margin-right: 20px;
+                font-size: 14px;
                 box-sizing: border-box;
-              }
-              .value-label {
-                position: relative;
-                color: #666;
-                .value-style{
-                  padding:5px;
-                  border-radius: 4px;
-                  &.predict-act {
-                    color: orange;
-                  }
+                height: 40px;
+                padding: 4px 8px 4px 8px;
+                border-radius: 4px;
+             }
+             .link-count-item-on{
+              border: 1px solid #0052D9;
+              color: #666666;
+              background: #ECF2FE;
+             }
+             .link-count-item-un{
+              border: 1px solid #C8CDD9;
+              color: #666666;
+             }
+          }
+
+          .calculate-result-wrap{
+             margin-top: 20px;
+             .calculate-result-title{
+                font-size: 14px;
+                color: #333333;
+                margin-bottom: 10px;
+             }
+             .calculate-result-table{
+                border: 1px solid #C8CDD9;
+                box-sizing: border-box;
+                padding: 0 20px;
+                border-radius: 4px;
+                .calculate-result-table-tr:nth-of-type(n+2){
+                  border-top: 1px solid #C8CDD9;
                 }
-                &.date{
-                  &::after{
-                    content: '';
-                    position:absolute;
-                    right:0;
-                    top:-14px;
-                    height:calc(100% + 28px);
-                    width:1px;
-                    background-color: #dcdfe6;
+                .calculate-result-table-tr{
+                  height: 50px;
+                  display: flex;
+                  align-items: center;
+                  .calculate-result-table-item{
+                    width: 33.3%;
+                    color: #333333;
+                    font-weight: 400;
                   }
                 }
-              }
-              .predict-act {
-                color: orange;
-              }
-              .new-tag {
-                width: 6px;
-                height: 6px;
-                display: inline-block;
-                position: absolute;
-                left: -12px;
-                top: 50%;
-                transform: translateY(-50%);
-                border-radius: 50%;
-                background: #f00;
-              }
-            }
-            .nodata {
-              text-align: center;
-              padding: 40px 0;
-              color: #999;
-            }
+             }
           }
+
           .delete-button{
             color: #AD352F;
             font-size: 14px;
@@ -674,20 +836,27 @@ import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
         display: flex;
         align-items: center;
         overflow-x: auto;
+        margin-bottom: 20px;
+        .unchoose-tag{
+          border: 1px solid #C8CDD9;
+        }
+        .choosed-tag{
+          border: 1px solid #0052D9;
+          background: rgba(236, 242, 254, 1);
+        }
         .link-box-tag{
           display: flex;
           align-items: center;
           padding: 0 8px;
-          height: 30px;
+          height: 40px;
           max-width: 250px;
-          background-color: #F8F8F8;
           margin-right: 30px;
+          border-radius: 4px;
           cursor: pointer;
           &:last-child{
             margin-right: 0;
           }
           span{
-            color: #666666;
             white-space: nowrap;
             overflow: hidden;
             text-overflow: ellipsis;

+ 835 - 0
src/views/sandbox_manage/sandFlowNew/components/calculateEdb.vue

@@ -0,0 +1,835 @@
+<template>
+    <div v-dialogDrag v-if="isShow">
+      <div class="calculate-edb-value-dialog el-dialog">
+        <div class="header el-dialog__header">
+          <span>{{ calculationItem.label }}</span>
+          <i class="el-icon-close" @click="cancelHandle" />
+        </div>
+  
+        <div class="main">
+          <section class="main-top">
+            <template v-if="calculationItem.fromEdbKey === 5">
+              <el-radio-group
+                v-model="formData.source"
+                @change="handleRadioGroup"
+              >
+                <el-radio :label="1">{{
+                  $t("Edb.CalculateBtns.to_month")
+                }}</el-radio>
+                <el-radio :label="2">{{
+                  $t("Edb.CalculateBtns.to_quarter")
+                }}</el-radio>
+              </el-radio-group>
+            </template>
+  
+            <template v-else-if="calculationItem.fromEdbKey === 62">
+              <el-radio-group
+                v-model="formData.source"
+                @change="handleRadioGroup"
+              >
+                <el-radio :label="13">{{
+                  $t("Edb.CalculateBtns.cumulate")
+                }}</el-radio>
+                <el-radio :label="14">{{
+                  $t("Edb.CalculateBtns.cumulate_oneyear")
+                }}</el-radio>
+              </el-radio-group>
+            </template>
+  
+            <selectTarget
+              :defaultId="search_edb"
+              :defaultOpt="searchOptions"
+              ref="selectRef"
+              @select="selectTargetHandle"
+              :filter="false"
+              style="margin: 20px 0"
+            />
+  
+            <div class="link-box-tags">
+              <div
+                class="link-box-tag"
+                v-for="(item, index) in edbList"
+                :key="item.RId"
+                :class="{
+                  'unchoose-tag': item.Id != edbActive.Id,
+                  'choosed-tag': item.Id == edbActive.Id,
+                }"
+              >
+                <span
+                  @dblclick.stop="editLinkName(item)"
+                  v-if="!item.editing"
+                  @click="linkClick(item)"
+                  :style="{
+                    color: item.Id == edbActive.Id ? '#0052D9' : '#666666',
+                  }"
+                  >{{ item.Name }}</span
+                >
+                <el-input
+                  v-else
+                  @blur="editLinkNameFinish(item)"
+                  v-model.trim="editingLabel"
+                  class="label-edit-input"
+                  ref="labelEditInput"
+                />
+                <img
+                  src="~@/assets/img/sand_new/delete_outline_1.png"
+                  @click="linkDelete(item, index)"
+                />
+              </div>
+            </div>
+          </section>
+          <!-- 指标详情 -->
+          <edbDetailSection :tableData="selectEdbInfo ? [selectEdbInfo] : []" />
+  
+          <section class="form-section">
+            <el-form
+              ref="form"
+              label-position="left"
+              inline
+              label-width="80px"
+              :model="formData"
+              :rules="formRules"
+            >
+              <el-form-item
+                :label="$t('OnlineExcelPage.label_move_way')"
+                style="display: block"
+                v-if="calculationItem.fromEdbKey === 22"
+                prop="moveVal"
+              >
+                <el-select
+                  v-model="formData.moveType"
+                  style="width: 100px"
+                  placeholder=""
+                  size="mini"
+                >
+                  <el-option
+                    v-for="item in moveTypeOpions"
+                    :key="item.key"
+                    :label="item.label"
+                    :value="item.key"
+                  >
+                  </el-option>
+                </el-select>
+                <el-input
+                  style="width: 80px"
+                  type="number"
+                  min="0"
+                  size="mini"
+                  v-model="formData.moveVal"
+                  @keyup.native="filterCode(formData)"
+                ></el-input>
+                <el-select
+                  v-model="formData.moveUnit"
+                  size="mini"
+                  placeholder=""
+                  style="width: 100px"
+                >
+                  <el-option
+                    v-for="item in fre_options"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                  >
+                  </el-option>
+                </el-select>
+              </el-form-item>
+  
+              <el-form-item
+                :label="$t('OnlineExcelPage.label_n_val')"
+                prop="nNum"
+                v-if="[8, 12, 13, 35].includes(calculationItem.fromEdbKey)"
+              >
+                <el-input
+                  v-model="formData.nNum"
+                  style="width: 200px"
+                  :placeholder="$t('ETableChildren.enter_n_value')"
+                  type="number"
+                />
+              </el-form-item>
+  
+              <el-form-item
+                :label="$t('OnlineExcelPage.label_calendar')"
+                prop="calendarType"
+                v-if="calculationItem.fromEdbKey === 35"
+              >
+                <el-select
+                  v-model="formData.calendarType"
+                  :placeholder="$t('OnlineExcelPage.select_calendar_pld')"
+                  style="width: 200px"
+                >
+                  <el-option
+                    v-for="item in calendarOptions"
+                    :key="item.key"
+                    :label="item.label"
+                    :value="item.key"
+                  >
+                  </el-option>
+                </el-select>
+              </el-form-item>
+  
+              <el-form-item
+                :label="$t('ETableChildren.frequentness_lable')"
+                prop="frequency"
+                v-if="[9, 13].includes(formData.source)"
+              >
+                <el-select
+                  v-model="formData.frequency"
+                  :placeholder="$t('OnlineExcelPage.please_select_frequency')"
+                  style="width: 200px"
+                  clearable
+                >
+                  <el-option
+                    v-for="item in frequencyArr"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                  >
+                  </el-option>
+                </el-select>
+              </el-form-item>
+  
+              <el-form-item
+                :label="$t('OnlineExcelPage.label_val_type')"
+                prop="valueType"
+                v-if="calculationItem.fromEdbKey === 51"
+              >
+                <el-select
+                  v-model="formData.valueType"
+                  :placeholder="$t('OnlineExcelPage.select_data_type')"
+                  style="width: 200px"
+                >
+                  <el-option
+                    key="期末值"
+                    :label="$t('ETableChildren.final_value_lable')"
+                    value="期末值"
+                  />
+                  <el-option
+                    key="平均值"
+                    :label="$t('ETableChildren.average_value_lable')"
+                    value="平均值"
+                  />
+                </el-select>
+              </el-form-item>
+  
+              <el-form-item
+                :label="$t('ETableChildren.alpha_value_lable')"
+                prop="alphaValue"
+                v-if="calculationItem.fromEdbKey === 'alpha'"
+              >
+                <el-input
+                  v-model="formData.alphaValue"
+                  :placeholder="$t('Edb.InputHolderAll.input_alpha_val')"
+                  style="width: 200px"
+                />
+              </el-form-item>
+            </el-form>
+          </section>
+  
+          <section>
+            <!-- 依赖日期选择方式 -->
+            <ul class="date-select-cont">
+              <li class="flex">
+                <div class="flex">
+                  <el-radio v-model="dateSelectForm.Type" :label="1">{{
+                    $t("ETableChildren.latest_date_indicator")
+                  }}</el-radio>
+                  <div>
+                    <label class="el-form-item__label">{{
+                      $t("ETableChildren.lagging_period_label")
+                    }}</label>
+                    <el-input
+                      v-model="dateSelectForm.MoveForward"
+                      type="number"
+                      :min="0"
+                      style="margin-right: 10px; width: 80px"
+                      @change="
+                        (e) => {
+                          dateSelectForm.MoveForward = Number(e);
+                        }
+                      "
+                    />{{ $t("ETableChildren.term_ipt") }}
+                  </div>
+                </div>
+              </li>
+              <li>
+                <dateMoveWaySec ref="dateMoveWayRef" />
+              </li>
+            </ul>
+          </section>
+  
+          <section class="bot">
+            <el-button
+              type="primary"
+              @click="calculateHandle"
+              style="width: 120px; margin-right: 30px"
+              >{{ $t("ETableChildren.calculation_btn") }}</el-button
+            >
+            <el-button
+              type="primary"
+              plain
+              @click="cancelHandle"
+              style="width: 120px"
+              >{{ $t("ETable.Btn.cancel_btn") }}</el-button
+            >
+            <el-popover width="300" trigger="hover" placement="right">
+              <div v-html="formulaTipContent"></div>
+              <el-button class="tips-btn" type="text" slot="reference">{{
+                $t("Edb.formula_instru")
+              }}</el-button>
+            </el-popover>
+          </section>
+        </div>
+      </div>
+    </div>
+  </template>
+  <script>
+  import { dataBaseInterface } from "@/api/api.js";
+  import * as sheetInterface from "@/api/modules/sheetApi.js";
+  import * as preDictEdbInterface from "@/api/modules/predictEdbApi.js";
+  import selectTarget from "@/views/chartRelevance_manage/components/selectTarget.vue";
+  import edbDetailSection from "@/views/datasheet_manage/components/edbDetailSection.vue";
+  import dateMoveWaySec from "@/views/datasheet_manage/components/dateMoveWaySection.vue";
+  import {
+    formRules,
+    formulaTip,
+  } from "@/views/dataEntry_manage/databaseComponents/util";
+  export default {
+    components: {
+      selectTarget,
+      edbDetailSection,
+      dateMoveWaySec,
+    },
+    props: {
+      isShow: {
+        type: Boolean,
+      },
+      calculationItem: {
+        //传入的计算种类
+        type: Object,
+      },
+      linkList: {
+        //指标列表
+        type: Array,
+        default: [],
+      },
+      activeLink: {
+        //选中的指标
+        type: Object,
+        default: {},
+      },
+    },
+    computed: {
+      frequencyArr() {
+        return [
+          { label: this.$t("ETable.Date.day_lable"), value: "日度" },
+          { label: this.$t("ETable.Date.week_lable"), value: "周度" },
+          { label: this.$t("ETable.Date.dekad_lable"), value: "旬度" },
+          { label: this.$t("ETable.Date.month_lable"), value: "月度" },
+          { label: this.$t("ETable.Date.quarter_lable"), value: "季度" },
+          { label: this.$t("ETable.Date.year_lable"), value: "年度" },
+        ];
+      },
+      moveTypeOpions() {
+        return [
+          {
+            label: this.$t("ETableChildren.ahead_lable"),
+            key: 1,
+          },
+          {
+            label: this.$t("ETableChildren.lagging_lable"),
+            key: 2,
+          },
+        ];
+      },
+      fre_options() {
+        return [
+          { label: this.$t("ETable.Date.day"), value: "天" },
+          { label: this.$t("ETable.Date.week_min"), value: "周" },
+          { label: this.$t("ETable.Date.month"), value: "月" },
+          { label: this.$t("ETable.Date.quarter_min"), value: "季" },
+          { label: this.$t("ETable.Date.year"), value: "年" },
+        ];
+      },
+      calendarOptions() {
+        return [
+          { label: this.$t("ETable.Date.calendar_gre"), key: "公历" },
+          { label: this.$t("ETable.Date.calendar_lunar"), key: "农历" },
+        ];
+      },
+  
+      currentLang() {
+        return this.$store.state.lang;
+      },
+    },
+    watch: {
+      isShow(newv) {
+        if (!newv) return;
+        this.formData.source = +this.calculationItem.source;
+        this.edbList = _.cloneDeep(this.linkList);
+        this.edbActive = _.cloneDeep(this.activeLink);
+        this.selectEdbInfo = null;
+        this.linkClick(this.edbActive);
+        this.handleFormulaTipContent()
+      },
+      edbActive:{
+        deep:true,
+        handler(){
+          this.handleEditData();
+        },
+      }
+    },
+    data() {
+      return {
+        isCalculateDia: true,
+        formData: {
+          source: + this.calculationItem.source,
+          frequency: "",
+          nNum: 1,
+          moveType: 1,
+          moveUnit: "天",
+          moveVal: "",
+          calendarType: "公历",
+          valueType: "期末值",
+          alphaValue: 0,
+        },
+        formRules,
+        formulaTip,
+        formulaTipContent:'',
+  
+        edbList: [], //指标标签列表
+        edbActive: {}, //目前选中的标签
+        editingLabel: "", //编辑标签名称
+  
+        search_edb: "",
+        searchOptions: [],
+        selectEdbInfo: null,
+  
+        dateSelectForm: {
+          Type: 1,
+          MoveForward: 0,
+        },
+      };
+    },
+    methods: {
+      async handleEditData(){
+        await this.$nextTick();
+        let v = this.linkList.find(_=>_.Id == this.edbActive.Id);
+        if(!v || !v.calculationMethod || !v.calculationMethod.length) return this.clearFormValue();
+        let item = v.calculationMethod.find(_=>_.source == this.formData.source);
+        if(!item) return this.clearFormValue();
+        // 累计值有问题
+        //处理编辑数据
+        this.formData = {
+          source:+item.source,
+          frequency:item.frequency || '',
+          moveUnit:item.moveFrequency || '天',
+          moveType:item.moveType || 1,
+          calendarType:item.calendar || "公历",
+          nNum:1,
+          moveVal:'',
+          valueType:'期末值',
+          alphaValue:0,
+        };
+        const valueMap = {
+          22: "moveVal",
+          51: "valueType",
+          alpha: "alphaValue",
+        };
+        this.formData[[22,51,'alpha'].includes(this.calculationItem.fromEdbKey) ? valueMap[this.calculationItem.fromEdbKey] : 'nNum'] = +item.formula || item.formula;
+        
+        this.dateSelectForm = {
+          Type: 1,
+          MoveForward: item.moveForward || 0,
+        };
+        this.$refs.dateMoveWayRef.dateChangeArr = item.dateChange || [];
+      },
+      handleFormulaTipContent(){
+         this.formulaTipContent = this.formulaTip.get(this.calculationItem.fromEdbKey);
+         if(this.formData.source == 2) this.formulaTipContent = this.formulaTip.get(61); //积累季度
+         if(this.formData.source == 14) this.formulaTipContent = this.formulaTip.get(63); //年初至今计算
+      },
+      handleRadioGroup() {
+        this.handleEditData()
+        this.$refs.selectRef.targetTypeChange();
+        this.handleFormulaTipContent()
+        this.selectEdbInfo = null;
+        this.edbActive = null;
+        let firstEdb = this.edbList[0];
+        if (firstEdb) {
+          this.edbActive = firstEdb;
+          this.$emit("changeActiveEdb", { item: firstEdb });
+          this.linkClick(firstEdb);
+        }
+      },
+      async calculateHandle() {
+        await this.$refs.form.validate();
+        if (!this.selectEdbInfo)
+          return this.$message.warning(
+            this.$t("SandboxManage.SandFlow.select_indicator_criteria")
+          );
+        const { source, nNum, moveType, moveUnit, calendarType, frequency } =
+          this.formData;
+        const valueMap = {
+          22: "moveVal",
+          51: "valueType",
+          alpha: "alphaValue",
+        };
+  
+        let params = {
+          DataTime: "",
+          Source: +source,
+          Frequency: frequency,
+          Formula: valueMap[this.calculationItem.fromEdbKey]
+            ? String(this.formData[valueMap[this.calculationItem.fromEdbKey]])
+            : String(nNum),
+          EdbInfoId: this.selectEdbInfo.EdbInfoId,
+          MoveFrequency: moveUnit,
+          MoveType: moveType,
+          Calendar: calendarType,
+          MoveForward: this.dateSelectForm.MoveForward,
+          DateChange: this.$refs.dateMoveWayRef.dateChangeArr,
+        };
+        const res = await sheetInterface.getMixedCalculateData(params);
+        if (res.Ret !== 200) return;
+        let value = res.Data.ShowValue || "";
+        const tips = {
+          5: `N=${params.Formula}`,
+          6: `N=${params.Formula}`,
+          7: `N=${params.Formula}`,
+          10: `移动方式${params.MoveType == 1 ? "领先" : "滞后"}${
+            params.Formula
+          }${params.MoveFrequency}`,
+          11: `N=${params.Formula} ${params.Calendar}`,
+          9: `数据取值${params.Formula} 频度${params.Frequency}`,
+          15: `alpha值=${params.Formula}`,
+        };
+        let calculation = {
+          fromEdbKey: this.calculationItem.fromEdbKey,
+          label: this.calculationItem.label,
+          source: +this.formData.source,
+          value,
+          calendar: params.Calendar,
+          dateChange: params.DateChange,
+          edbInfoId: params.EdbInfoId,
+          formula: params.Formula,
+          frequency: params.Frequency,
+          moveForward: params.MoveForward,
+          moveFrequency: params.MoveFrequency,
+          moveType: params.MoveType,
+          dataTime: params.DataTime,
+          tip: tips[params.Source] || "",
+        };
+        this.$emit("addCalculation", { item: calculation });
+        this.cancelHandle();
+      },
+      /* 过滤负数 小数点*/
+      filterCode(item) {
+        item.moveVal = item.moveVal.replace(/[^\.\d]/g, "").replace(".", "");
+      },
+      editLinkName(item) {
+        this.search_edb = "";
+        this.editingLabel = item.Name;
+        item.editing = true;
+        this.$nextTick(() => {
+          this.$refs.labelEditInput[0].focus();
+        });
+      },
+      editLinkNameFinish(item) {
+        this.search_edb = "";
+        if (this.editingLabel) {
+          item.editing = false;
+          item.Name = this.editingLabel;
+          this.$emit("editEdbName", { item });
+        } else {
+          this.$message.warning("不能为空");
+        }
+      },
+      async linkClick(item) {
+        this.search_edb = "";
+        const res = await dataBaseInterface.targetDetail({ EdbInfoId: item.Id });
+        if (res.Ret !== 200) return;
+        const { EdbInfoId, EdbInfoType, EdbName, Frequency, HaveOperaAuth } =
+          res.Data;
+        if (!HaveOperaAuth)
+          return this.$message.warning(this.$t("MsgPrompt.no_edb_auth"));
+        if (this.formData.source === 1 && Frequency !== "月度")
+          return this.$message.warning(this.$t("ETableChildren.only_select_msg"));
+        else if (this.formData.source === 2 && Frequency !== "季度")
+          return this.$message.warning(
+            this.$t("ETableChildren.only_quarterly_msg")
+          );
+        else if (this.formData.source === 8 && Frequency === "日度")
+          return this.$message.warning(this.$t("ETableChildren.no_day_msg"));
+        else if (this.formData.source === 14 && Frequency === "年度")
+          return this.$message.warning(this.$t("ETableChildren.no_year_msg"));
+        this.selectTargetHandle({ EdbInfoId, EdbInfoType, EdbName }, "change");
+        this.edbActive = item;
+        this.$emit("changeActiveEdb", { item });
+      },
+      linkDelete(item, index) {
+        this.search_edb = "";
+        this.edbList.splice(index, 1);
+        this.$emit("edbDelete", { item });
+        if (this.edbActive.RId == item.RId) {
+          let firstEdb = this.edbList[0];
+          if (firstEdb) {
+            this.edbActive = firstEdb;
+            this.$emit("changeActiveEdb", { item: firstEdb });
+            this.selectEdbInfo = null;
+            this.linkClick(firstEdb);
+          } else {
+            this.edbActive = {};
+            this.$emit("changeActiveEdb", { item: null });
+            this.selectEdbInfo = null;
+          }
+        }
+      },
+      /* 选择指标 */
+      async selectTargetHandle(e, type = "add") {
+        //add添加  change标签切换
+        if (!e) {
+          this.selectEdbInfo = null;
+          return;
+        }
+        if (this.edbList.find((_) => _.Id == e.EdbInfoId) && type == "add") {
+          return this.$message.warning(
+            this.$t("SandboxManage.SandFlow.data_already_exists")
+          );
+        }
+        if (type == "add") {
+          let activeItem = {
+            RId: 1 + "-" + e.EdbInfoId,
+            Id: e.EdbInfoId,
+            Name:
+              this.currentLang === "en" ? e.EdbNameEn || e.EdbName : e.EdbName,
+            Type: 1,
+            editing: false,
+            databaseType: e.EdbInfoType, //0 普通指标 | 1 预测指标
+            detailParams: {
+              code: e.UniqueCode,
+              id: e.EdbInfoId,
+              classifyId: e.ClassifyId,
+            },
+            calculationMethod: [],
+          };
+          this.edbActive = activeItem;
+          this.edbList.push(activeItem);
+          this.$emit("addEdbItem", { item: activeItem });
+        }
+  
+        const res =
+          e.EdbInfoType === 1
+            ? await preDictEdbInterface.edbDataInfo({
+                EdbInfoId: e.EdbInfoId,
+                CurrentIndex: 1,
+              })
+            : await dataBaseInterface.targetList({
+                EdbInfoId: e.EdbInfoId,
+                CurrentIndex: 1,
+              });
+  
+        if (res.Ret !== 200) return;
+  
+        const {
+          EdbInfoId,
+          EdbCode,
+          EdbName,
+          Frequency,
+          Unit,
+          StartDate,
+          ModifyTime,
+          PredictDataList,
+          DataList,
+          HaveOperaAuth,
+        } = res.Data.Item;
+  
+        this.selectEdbInfo = {
+          EdbCode,
+          EdbName,
+          Frequency,
+          Unit,
+          StartDate,
+          ModifyTime,
+          EdbInfoId,
+          HaveOperaAuth,
+          DataList: PredictDataList
+            ? [...PredictDataList, ...DataList].slice(0, 5)
+            : DataList.slice(0, 5),
+        };
+      },
+      cancelHandle() {
+        this.initData();
+        this.$emit('handleCloseDialog')
+        this.$emit("update:isShow", false);
+      },
+      clearFormValue(){
+        this.formData = {
+          source: +this.formData.source,
+          frequency: "",
+          nNum: 1,
+          moveType: 1,
+          moveUnit: "天",
+          moveVal: "",
+          calendarType: "公历",
+          valueType: "期末值",
+          alphaValue: 0,
+        };
+        this.dateSelectForm = {
+          Type: 1,
+          MoveForward: 0,
+        };
+        this.$refs.dateMoveWayRef && this.$refs.dateMoveWayRef.initData();
+      },
+      initData() {
+        this.clearFormValue();
+        this.search_edb = "";
+        this.selectEdbInfo = null;
+        this.edbList = [];
+        this.edbActive = {};
+        this.editingLabel = "";
+      },
+    },
+  };
+  </script>
+  <style scoped lang="scss">
+  @import "~@/styles/theme-vars.scss";
+  
+  .calculate-edb-value-dialog {
+    background: #fff;
+    position: fixed;
+    top: 5vh;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 1058px;
+    border-radius: 2px;
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
+    z-index: 9999;
+  
+    .header {
+      font-size: 16px;
+      background: $theme-color;
+      color: #fff;
+      padding: 15px;
+      display: flex;
+      align-content: center;
+      justify-content: space-between;
+  
+      .el-icon-close {
+        font-size: 20px;
+        cursor: pointer;
+      }
+    }
+  
+    .main {
+      padding: 30px;
+      max-height: 75vh;
+      min-height: 300px;
+      overflow-y: auto;
+      position: relative;
+  
+     
+  
+      .main-top {
+        margin-bottom: 20px;
+      }
+  
+      .link-box-tags {
+        display: flex;
+        align-items: center;
+        overflow-x: auto;
+        margin-bottom: 20px;
+  
+        .unchoose-tag {
+          border: 1px solid #c8cdd9;
+        }
+  
+        .choosed-tag {
+          border: 1px solid #0052d9;
+          background: rgba(236, 242, 254, 1);
+        }
+  
+        .link-box-tag {
+          display: flex;
+          align-items: center;
+          padding: 0 8px;
+          height: 40px;
+          max-width: 250px;
+          margin-right: 30px;
+          border-radius: 4px;
+          cursor: pointer;
+  
+          &:last-child {
+            margin-right: 0;
+          }
+  
+          span {
+            white-space: nowrap;
+            overflow: hidden;
+            text-overflow: ellipsis;
+          }
+  
+          img {
+            height: 16px;
+            width: 16px;
+            margin-left: 8px;
+          }
+        }
+      }
+  
+      .edb-list {
+        display: flex;
+        flex-wrap: wrap;
+        gap: 10px;
+  
+        .el-tag {
+          cursor: pointer;
+        }
+      }
+  
+      .form-section {
+        margin: 20px 0;
+      }
+  
+      .bot {
+        display: flex;
+        justify-content: center;
+        margin: 30px 0;
+        position: relative;
+      }
+  
+      .tips-btn {
+        position: absolute;
+        bottom: -10px;
+        right: 40px;
+      }
+  
+      .data-cont {
+        margin: 15px 0;
+        border: 1px solid #dcdfe6;
+  
+        .data-li {
+          display: flex;
+          padding: 15px;
+          text-align: center;
+          justify-content: space-around;
+  
+          &.choose {
+            background: #ecf5ff;
+          }
+        }
+      }
+  
+      .date-select-cont {
+        li {
+          margin: 20px 0;
+        }
+  
+        .flex {
+          display: flex;
+          align-items: center;
+        }
+      }
+    }
+  }
+  </style>
+  

+ 138 - 17
src/views/sandbox_manage/sandFlowNew/index.vue

@@ -436,9 +436,21 @@
           </div>
           <div id="link-reference" slot="reference"></div>
         </el-popover>
+        <el-popover
+          placement="right"
+          trigger="manual"
+          v-model="calculationPopoverObj.show">
+          <div class="calculation-wrap">
+              <div class="calculation-title">{{ $t('SandboxManage.SandFlow.calculation_configuration_parameters') }}:</div>
+              <div v-for="(item,index) in calculationPopoverObj.list" :key="index">
+                    {{ item.label }} : {{ item.tip }}
+              </div>
+          </div>
+          <div id="calculation-reference" slot="reference"></div>
+        </el-popover>
       </div>
     </div>
-    <!-- 添加链接--弹窗 -->
+    <!-- 添加节点数据--弹窗 -->
     <addLInkDia :show.sync="addLinkShow" :linkList="linkList" @saveLink="saveLink" />
   </div>
 </template>
@@ -450,6 +462,7 @@ import { myNodes,myNodeOption } from '../common/node';
 import { myEdgeOption } from '../common/edge';
 import { Addon } from '@antv/x6'
 import mindmap from "../common/mindmap"
+import customize from '../common/customize';
 import {styleSettings,familyOptions,fontSizeOptions,colorsOptions,lineHeightOptions} from "../common/toolConfig"
 import { ElDropdownMenu as DropdownMenu } from 'element-ui';
 import { contextMenuOption } from '../common/options';
@@ -501,7 +514,7 @@ import addLInkDia from './components/addLInkDia.vue';
         treeData:[],
         lockLoding: null,
         loopTimer:null,
-        // 添加链接弹窗
+        // 添加节点数据弹窗
         addLinkShow:false,
         linkList:[],
         popoverVisible:false,
@@ -510,10 +523,15 @@ import addLInkDia from './components/addLInkDia.vue';
         popoverTimeout:null,
         linkNode:null,
         popoverFlod:true,
-        isSlideLeft:false
+        isSlideLeft:false,
+        calculationPopoverObj:{
+          show:false,
+          dom:null,
+          list:[],
+        },
       }
     },
-    mixins:[mindmap],
+    mixins:[mindmap,customize],
     watch: {
       initData(newval) {
         if(!this.graph){
@@ -572,6 +590,7 @@ import addLInkDia from './components/addLInkDia.vue';
       document.getElementById('sand-mainBody-chart').addEventListener("drop",this.edgeDrop)
       this.popoverDom = $('#link-popover')[0];
       this.popoverTriggerDom = $('#link-reference')[0];
+      this.calculationPopoverObj.dom = $('#calculation-reference')[0];
       
       this.popoverDom.addEventListener('mouseenter',this.clearPopoverTimeout)
       this.popoverDom.addEventListener('mouseleave',this.closePopover)
@@ -589,8 +608,8 @@ import addLInkDia from './components/addLInkDia.vue';
       getContentMenuOptText(e){
         if(e==='复制') return this.$t('SandboxManage.SandFlow.copy_tag')
         if(e==='删除') return this.$t('SandboxManage.SandFlow.delete_tag')
-        if(e==='添加链接') return this.$t('SandboxManage.SandFlow.add_link')
-        if(e==='清除链接') return this.$t('SandboxManage.SandFlow.clear_link')
+        if(e==='添加节点数据') return this.$t('SandboxManage.SandFlow.add_node_data')
+        if(e==='清除节点数据') return this.$t('SandboxManage.SandFlow.clear_node_data')
         return e
       },
       getSandboxClassify(){
@@ -650,6 +669,11 @@ import addLInkDia from './components/addLInkDia.vue';
           this.canRedo = this.graph.canRedo()
         })
 
+        this.graph.on('node:click',({ node, e }) => {
+          if(node && node.shape == 'mindmap-child-datanode-title' && node.data){ //数据节点标题跳转
+            this.navigateTo && this.navigateTo(node.data);
+          }
+        });
         this.graph.on('node:mouseenter', ({ node, e }) => {
           let data = node.data
           this.linkNode = node
@@ -660,6 +684,18 @@ import addLInkDia from './components/addLInkDia.vue';
               item.show=!isMindmap
             }
           })
+
+          if(data && data.calculationMethod && data.calculationMethod.length > 0){
+                let clinetPositon=this.graph.localToClient(node.position())
+                let size=node.size()
+                this.calculationPopoverObj.dom.style.left = clinetPositon.x + size.width * this.graph.zoom() +'px';
+                this.calculationPopoverObj.dom.style.top = clinetPositon.y + size.height / 2 * this.graph.zoom() + 'px';
+                this.calculationPopoverObj.list = data.calculationMethod.filter(_=>_.tip) || [];
+                if(this.calculationPopoverObj.list.length > 0){
+                  this.calculationPopoverObj.show=true;
+                }
+          }
+
           if(data && data.linkData && data.linkData.length>0){
             this.popoverFlod = data.linkFold
             this.popoverVisible=false
@@ -703,7 +739,7 @@ import addLInkDia from './components/addLInkDia.vue';
 
                 this.contextMenuOption.map(item =>{
                   if(item.key=='addLink'){
-                    item.label=(this.linkList && this.linkList.length>0)?this.$t('SandboxManage.SandFlow.edit_link'):this.$t('SandboxManage.SandFlow.add_link')
+                    item.label=(this.linkList && this.linkList.length>0)?this.$t('SandboxManage.SandFlow.edit_node_data'):this.$t('SandboxManage.SandFlow.add_node_data')
                   }else if(item.key=='deleteLink'){
                     item.show=(this.linkList && this.linkList.length>0)
                   }
@@ -720,7 +756,7 @@ import addLInkDia from './components/addLInkDia.vue';
           }else{
             this.contextMenuOption.map(item =>{
               if(item.key=='addLink'){
-                item.label=this.$t('SandboxManage.SandFlow.add_link')
+                item.label=this.$t('SandboxManage.SandFlow.add_node_data')
               }else if(item.key=='deleteLink'){
                 item.show=false
               }
@@ -738,6 +774,10 @@ import addLInkDia from './components/addLInkDia.vue';
             },500)
           }
 
+              this.calculationPopoverObj.dom.style.left = '-99999px';
+              this.calculationPopoverObj.dom.top = '-99999px';
+              this.calculationPopoverObj.show=false;
+
         })
 
         this.graph.on('node:change:position', (args) => { 
@@ -793,20 +833,59 @@ import addLInkDia from './components/addLInkDia.vue';
         let styleData=styleSettings[activeNum-1]
         this.styleActive = activeNum
         let cells = this.graph.getCells()
-
         for (let i = 0; i < cells.length; i++) {
           const element = cells[i];
+          if(element.shape == 'mindmap-child-background-datanode' || element.shape == 'mindmap-grandchild-datanode') continue;
           if(element.shape.indexOf("edge") !=-1){
             element.setAttrs({
               line:{
                 stroke:styleData.lineColor
               }
             })
-          }if(element.data && element.data.key == 'text'){
+          }
+          //添加数据节点样式特殊处理
+          if(element.shape == 'mindmap-child-datanode') {
+            element.setAttrs({
+              body: {
+                stroke:styleData.dataBorderColor,
+                fill:styleData.dataBackgroundColor,
+                },
+                text: {
+                  fill:styleData.dataTextColor,
+                },
+              });
+            continue;
+          } else if(element.shape == 'mindmap-child-datanode-title') {
+            element.setAttrs({
+              body: {
+                  stroke: styleData.titleBorderColor,
+                  fill: styleData.titleBackgoundColor,
+                },
+                text: {
+                  fill: styleData.titleTextColor,
+                },
+              });
+              continue;
+          } else if(element.shape == 'mindmap-grandchild-datanode') {
+            element.setAttrs({
+                  body: {
+                    fill: "transparent",
+                  },
+                  text: {
+                    fill: styleData.dataTextColor,
+                  },
+                  value: {
+                    fill: styleData.dataTextColor,
+                  },
+              });
+              continue;
+          }
+           //  普通节点样式调整
+          if(element.data && element.data.key == 'text'){
             element.setAttrs({
               text:{
                 fill:styleData.textColor
-              }
+              },
             })
           }else{
             element.setAttrs({
@@ -816,7 +895,7 @@ import addLInkDia from './components/addLInkDia.vue';
               },
               text:{
                 fill:styleData.color
-              }
+              },
             })
           }
         }
@@ -828,7 +907,7 @@ import addLInkDia from './components/addLInkDia.vue';
         }else if(key=="deleteLink"){
           this.deleteLink()
         }else{
-          contextEvent(this.graph, key,this.getMindmapDataUse);
+          contextEvent(this.graph, key,this.getMindmapDataUse,this);
         }
         this.hideContextMenu();
       },
@@ -851,8 +930,9 @@ import addLInkDia from './components/addLInkDia.vue';
       deleteLink(){
         const select_cell = this.graph.getSelectedCells()[0]
         if(select_cell){
-          select_cell.data.linkData=[]
-          this.$message.success(this.$t('SandboxManage.SandFlow.clear_link_success'))
+          select_cell.data.linkData=[];
+          this.clearDataLinks(select_cell);
+          this.$message.success(this.$t('SandboxManage.SandFlow.successfully_cleared_node_data'))
         }
       },
       saveLink(list){
@@ -866,10 +946,36 @@ import addLInkDia from './components/addLInkDia.vue';
           if(!select_cell.data.linkFold){
             select_cell.data.linkFold=true
           }
-        }
-        this.$message.success(this.$t('SandboxManage.SandFlow.save_link'))
+        };
+        let edbLists = list.filter(_=>_.Type == 1) || [];
+        this.handleAddDataNodes(select_cell,edbLists)  //只增加指标类型的数据节点
+        this.$message.success(this.$t('SandboxManage.SandFlow.node_data_saved_successfully'))
         this.addLinkShow=false
       },
+      handleAddDataNodes(select_cell,list){
+        if(!select_cell) return;
+        let rootId = select_cell.id.split('-')[0];
+        let index = this.mindmapAssistData.mindmapDataUse.findIndex(it =>it.mindmapData.id == rootId);
+        let addType = this.mindmapAssistData.mindmapDataUse[index]?this.mindmapAssistData.mindmapDataUse[index].addType:'';
+        let type = addType.indexOf("Mindmap")>=0 ? 2 : 1; //1为自定义  2为思维导图
+
+        let childs = select_cell.getChildren() || [];
+        if(childs && childs.length > 0) this.graph.removeCells(childs);
+        if(type == 2){
+          if(!list || !list.length) return;
+          const { id } = select_cell
+          this.setCurrent(id);
+          let direction = select_cell.shape.includes('left') ? 'left' : 'right';
+          this.addMindmapDataNodes(id,list,direction)
+        } else {
+          if(!list || !list.length) return;
+          this.addCustomDataNodes(select_cell,list)
+        }
+      },
+      clearDataLinks(select_cell){
+        let childs = select_cell.getChildren() || [];
+        if(childs && childs.length > 0) this.graph.removeCells(childs);
+      },
       backList(){
         let ids = ''
         if(this.parentIds && this.parentIds.length>0){
@@ -1527,6 +1633,14 @@ import addLInkDia from './components/addLInkDia.vue';
       left: -99999px;
       background-color: transparent;
     }
+    #calculation-reference{
+      position: fixed;
+      z-index: -1;
+      top: -99999px;
+      left: -99999px;
+      background-color: transparent;
+    }
+
     #sand-chart-container{
       flex: 1;
     }
@@ -1577,6 +1691,13 @@ import addLInkDia from './components/addLInkDia.vue';
   .x6-node-selected rect {
     stroke-width: 2px;
   }
+  .mindmap-child-datanode-title{
+    cursor: pointer;
+  }
+  .mindmap-child-datanode-title-text{
+    cursor: pointer;
+    pointer-events: none;
+  }
   #sand-mainBody-tool{
     .el-select{
       .el-input{

+ 14 - 1
src/vuex/modules/sand.js

@@ -131,7 +131,14 @@ const sand = {
 			color:'#1841AA',
 			textColor:'#1841AA',
 			borderColor:'#1841AA',
-			lineColor:'#1841AA'
+			lineColor:'#1841AA',
+
+			dataBackgroundColor:'#FFFFFF',
+			dataBorderColor:'#1841AA',
+			dataTextColor:'#333333',
+			titleBackgoundColor:'#1841AA',
+			titleBorderColor:'#1841AA',
+			titleTextColor:'#FFFFFF',
 		},
 		toolStatus:{
 			nodeDisabled:true,
@@ -230,6 +237,12 @@ const sand = {
 			state.styleConfig.textColor = styleData.textColor
 			state.styleConfig.borderColor = styleData.borderColor
 			state.styleConfig.lineColor = styleData.lineColor
+
+			state.styleConfig.dataBackgroundColor = styleData.dataBackgroundColor
+			state.styleConfig.dataBorderColor = styleData.dataBorderColor
+			state.styleConfig.titleBackgoundColor = styleData.titleBackgoundColor
+			state.styleConfig.titleBorderColor = styleData.titleBorderColor
+			state.styleConfig.titleTextColor = styleData.titleTextColor
 		}
 	},
   actions: {