Przeglądaj źródła

Merge branch 'eta1.1.6'

Karsa 1 rok temu
rodzic
commit
a242a8945d

+ 21 - 0
src/api/modules/sheetApi.js

@@ -266,6 +266,27 @@ export const getDateLatelyData = params => {
 	return http.get('/datamanage/edb_info/date_data/before_after',params)
 }
 
+/**
+ * 获取系统日期
+ * @param {*} params 
+ * "DataTimeType": 1,
+    "Value": "{\"Source\":3,\"Frequency\":\"本周\",\"Day\":\"周日\",\"CalculateNum\":0,\"CalculateFrequency\":\"\"}"
+ * @returns 
+ */
+export const getSystemDate = params => {
+	return http.post('/datamanage/excel_info/get_system_date',params)
+}
+
+/**
+ * 混合表格指标计算
+ * @param {*} params 
+ * EdbInfoId Source Formula Frequency Calendar MoveType MoveFrequency
+ * @returns 
+ */
+export const getMixedCalculateData = params => {
+	return http.post('/datamanage/excel_info/mixed/calculate',params)
+}
+
 
 /* =====自定义分析==== */
 

+ 32 - 5
src/views/chartRelevance_manage/components/selectTarget.vue

@@ -5,7 +5,7 @@
       v-model="targetType"
       placeholder="请选择指标种类"
       @change="targetTypeChange"
-      v-if="selectStyleType===1"
+      v-if="selectStyleType===1&&filter"
     >
       <el-option
         v-for="item in etaTypeOpt"
@@ -15,7 +15,7 @@
       />
     </el-select>
 
-    <div v-else-if="selectStyleType===2" class="database-choose">
+    <div v-else-if="selectStyleType===2&&filter">
       <label>选择指标:</label>
       <el-radio-group v-model="targetType" @change="targetTypeChange">
         <el-radio  
@@ -26,7 +26,7 @@
       </el-radio-group>
     </div>
 
-    <div v-else-if="selectStyleType===3" style="display:flex;align-items:center">
+    <div v-else-if="selectStyleType===3&&filter" style="display:flex;align-items:center">
       <el-select
         v-model="targetType"
         placeholder="请选择指标种类"
@@ -73,7 +73,7 @@
       remote
       clearable
       placeholder="请选择指标名称"
-      style="width: 100%; margin-top: 20px"
+      :style="`width: 100%; ${filter?'margin-top: 20px':''}`"
       :remote-method="searchHandle"
       @click.native="inputFocusHandle"
       @change="handleSelectTarget"
@@ -96,6 +96,7 @@
 <script>
 import { dataBaseInterface } from '@/api/api.js';
 import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
+import * as sheetInterface from "@/api/modules/sheetApi.js";
 export default {
     props:{
       defaultId:{
@@ -109,6 +110,9 @@ export default {
       },
       selectStyleType: {
         default: 1
+      },
+      filter: { //是否要预测和eta的筛选
+        default: true
       }
     },
     watch:{
@@ -152,7 +156,30 @@ export default {
                 KeyWord: query,
                 CurrentIndex: page,
             }
-            const res = this.targetType=='1'?await dataBaseInterface.targetSearchByPage(params):await preDictEdbInterface.edbSearch(params)
+
+            let res;
+            if(this.filter) {
+               res = this.targetType=='1'?await dataBaseInterface.targetSearchByPage(params):await preDictEdbInterface.edbSearch(params)
+            }else {
+              const filterMap = {
+                1: 2,
+                8: 3,
+                14: 6
+              }
+
+              let FilterSource = (this.$route.path==='/addMixedSheet' && this.$parent.isCalculateDia)
+                ? filterMap[this.$parent.formData.source]||1 
+                : 1;
+              let Frequency = (this.$route.path==='/addMixedSheet' && this.$parent.isCalculateDia && this.$parent.formData.source===2)
+                ? '季度' 
+                : ''
+              res = await sheetInterface.searchTarget({
+                ...params,
+                FilterSource,
+                Frequency
+              })
+            }
+            
 
             if (res.Ret !== 200) return
             const { List, Paging } = res.Data;

+ 1 - 1
src/views/dataEntry_manage/databaseComponents/util.js

@@ -192,7 +192,7 @@ export const allFromArr = [
 	{ name: 'wind',key: 2 },
 	{ name: '同花顺',key: 1 },
 	{ name: '彭博',key: 3 },
-	{name:'彭博财务',key:28},
+	{ name:'彭博财务',key:28},
 	{ name: '路透', key: 25 },
 	{ name: '手工指标', key: 9 },
 	{ name: '隆众指标', key: 10 },

+ 1 - 1
src/views/datasheet_manage/addSheet.vue

@@ -10,7 +10,7 @@
             style="width:240px">
           </el-input>
         </li>
-        <li>          
+        <li>
           <el-select 
             v-model="sheetForm.classify" 
             placeholder="请选择表格分类"

+ 43 - 8
src/views/datasheet_manage/common/customTable.js

@@ -41,8 +41,7 @@ export function findCellByFactor (str) {
 
   let table = document.querySelector('.table');
   let el = table.querySelector("td span[data-rindex='" + newStr[1] + "'][data-cindex='" + newStr[0] + "']") || table.querySelector("td input[data-rindex='" + newStr[1] + "'][data-cindex='" + newStr[0] + "']");
-
-  return el ? (el.innerText||'') : null;
+  return el ? (el.innerText||el.value||'') : null;
 }
 
 //转大写
@@ -136,7 +135,35 @@ export function setCellBg(e) {
 }
 
 //右键菜单
-export function getRightClickMenu(pos) {
+export function getRightClickMenu(pos,canEdit=false) {
+
+  let cellMenu = [
+    { label: "根据表格中日期选择指标值", key: "choose-target" },
+    // { label: "插入指标值", key: "insert-value" },
+    { label: "导入系统日期", key: "insert-sys-date" },
+    { label: "导入指标日期", key: "insert-edb-date" },
+    { label: "指标计算",
+      key: "insert-edb-calculate",
+      children: [
+        { label: '累计值转月/季值',source: 1,fromEdbKey:5 },
+        { label: '同比值',source: 3,fromEdbKey:6 },
+        { label: '同差值',source: 4,fromEdbKey:7 },
+        { label: 'N数值移动平均计算',source: 5,fromEdbKey:8 },
+        { label: 'N数值环比值',source: 6,fromEdbKey:12 },
+        { label: 'N数值环差值',source: 7,fromEdbKey:13 },
+        { label: '升频',source: 8,fromEdbKey:14 },
+        { label: '时间移位',source: 10,fromEdbKey:22 },
+        { label: '超季节性',source: 11,fromEdbKey:35 },
+        { label: '年化',source: 12,fromEdbKey:52 },
+        { label: '降频',source: 9,fromEdbKey:51 },
+        { label: '累计值',source: 13,fromEdbKey:62 },
+        { label: '指数修匀',source: 15,fromEdbKey:'alpha' },
+        { label: '日均值',source: 16,fromEdbKey:75 },
+      ]
+    },
+    { label: "清空", key: "reset" },
+  ]
+
   const menuMap = {
     'col': [
       { label: "向左插入列", key: "insert-col-left" },
@@ -148,11 +175,9 @@ export function getRightClickMenu(pos) {
       { label: "向下插入行", key: "insert-row-down" },
       { label: "删除", key: "del" },
     ],
-    'cell': [
-      { label: "选择指标", key: "choose-target" },
-      { label: "插入指标值", key: "insert-value" },
-      { label: "清空", key: "reset" },
-    ]
+    'cell': canEdit 
+      ? [{ label: '编辑',key: 'cell-edit' },...cellMenu]
+      : cellMenu
   }
 
   return menuMap[pos];
@@ -226,3 +251,13 @@ export function resetDialogCellStyle() {
   })
 }
 
+
+// 根据行头列头位置找key
+export function findCellKeyByFactor(str) {
+  let newStr = splitString(toUpperCase(str));
+
+  let table = document.querySelector('.table');
+  let el = table.querySelector("td [data-rindex='" + newStr[1] + "'][data-cindex='" + newStr[0] + "']");
+
+  return el ? (el.dataset.key||'') : null;
+}

+ 38 - 3
src/views/datasheet_manage/components/CustomTable.vue

@@ -77,6 +77,8 @@
                 :class="([2,3,5].includes(edb.Data.find(_ =>_.DataTime === date).DataType)&&edb.Data.find(_ =>_.DataTime === date).ShowValue)?'insert': ''"
                 @click="clickCell($event,edb.Data.find(_ =>_.DataTime === date))"
                 @dblclick="dblClickCell($event,edb.Data.find(_ =>_.DataTime === date))"
+                @copy="copyCellHandle($event,edb.Data.find(_ =>_.DataTime === date))"
+                @paste="pasteCellHandle($event,edb.Data.find(_ =>_.DataTime === date))"
               >
                 <!-- 实际值/插值 -->
                 <span 
@@ -118,6 +120,8 @@
                 :class="([2,3,5].includes(cell.DataType)&&cell.ShowValue)?'insert': ''"
                 @click="clickCell($event,cell)"
                 @dblclick="dblClickCell($event,cell)"
+                @copy="copyCellHandle($event,cell)"
+                @paste="pasteCellHandle($event,cell)"
               >
               
                   <span 
@@ -193,7 +197,9 @@
                 :data-rindex="rowHeader[index+dateArr.length]"
                 :class="([2,3,5].includes(column[0].DataType)&&column[0].ShowValue)?'insert': ''"
                 @click="clickCell($event,column[0])"
-                 @dblclick="dblClickCell($event,column[0])"
+                @dblclick="dblClickCell($event,column[0])"
+                @copy="copyCellHandle($event,column[0])"
+                @paste="pasteCellHandle($event,column[0])"
               >
                 <span 
                   :data-cindex="-1"
@@ -250,6 +256,8 @@
                 :class="([2,3,5].includes(data.DataType)&&data.ShowValue)?'insert': ''"
                 @click="clickCell($event,data)"
                 @dblclick="dblClickCell($event,data)"
+                @copy="copyCellHandle($event,data)"
+                @paste="pasteCellHandle($event,data)"
               >
                 <!-- 实际值/插值 -->
                 <span
@@ -281,6 +289,8 @@
                 :class="([2,3,5].includes(column[edb_index+1].DataType)&&column[edb_index+1].ShowValue)?'insert': ''"
                 @click="clickCell($event,column[edb_index+1])"
                 @dblclick="dblClickCell($event,column[edb_index+1])"
+                @copy="copyCellHandle($event,column[edb_index+1])"
+                @paste="pasteCellHandle($event,column[edb_index+1])"
               >
                 <span 
                   :data-rindex="rowHeader[column_index+dateArr.length]"
@@ -494,6 +504,7 @@ export default {
       isEditEdbAliasDialog: false,
       editEdb: {},
 
+      copyCellItem: {},
       hasInit:false
     };
   },
@@ -629,7 +640,7 @@ export default {
         return
       }
 
-      if(value.includes('=')) {
+      if(value.startsWith('=')) {
         cell.DataType = 4;
         let calculateVal = await this.getValueByFormula(value);
         cell.ShowValue = calculateVal;
@@ -830,7 +841,31 @@ export default {
     dragEnd(e) {
       let dom = document.querySelector('.add-fixed');
       dom.style.top = e.clientY-10 + 'px';
-    }
+    },
+
+    /* 要支持复制粘贴把公式也带过去 公式单元格类型为6 其余就正常复制文本 */
+    copyCellHandle(e,cell) {
+      this.copyCellItem = cell;
+      // 阻止默认的复制操作
+      e.preventDefault();
+    },
+
+    /* 要支持复制粘贴把公式也带过去 公式单元格类型为4 其余就正常复制文本 */
+    pasteCellHandle(e,cell) {
+      if(this.copyCellItem.DataType === 4) {
+        cell.DataType = this.copyCellItem.DataType;
+        cell.ShowValue = this.copyCellItem.ShowValue;
+        cell.Value = this.copyCellItem.Value;
+      }else {
+        cell.DataType = 3;
+        cell.ShowValue = this.copyCellItem.ShowValue;
+        cell.Value = this.copyCellItem.ShowValue;
+      }
+      
+      // 阻止默认的粘贴操作
+      e.preventDefault();
+    }  
+    
   },
 };
 </script>

+ 458 - 64
src/views/datasheet_manage/components/MixedTable.vue

@@ -1,6 +1,17 @@
 <template>
-  <div class="table-wrapper">
+  <div class="table-wrapper" @keydown="handlekeyDownKeys">
     <template v-if="config.data.length">
+      
+      <!-- 公式显示区 -->
+      <div class="formula-wrapper" v-if="!disabled">
+        <span style="flex-shrink: 0;color:#C0C4CC">公式</span>
+        <el-input
+          v-if="selectCell&&selectCell.DataType===6"
+          v-model="selectCell.Value"
+          @change="updateValueByFormula"
+        />
+      </div>
+
       <table
         width="auto"
         border="0"
@@ -45,15 +56,23 @@
               :data-cindex="columnHeader[cell_index]"
               :data-key="cell.Uid"
               @click="clickCell($event, cell)"
+              @dblclick="dblClickCellHandle($event,cell)"
               @contextmenu.prevent="rightClickHandle($event,cell)"
               @mouseenter="getRelationEdbInfo(cell)"
+              @copy="copyCellHandle($event,cell)"
+              @paste="pasteCellHandle($event,cell)"
             >
 
             <!-- 插入单元格禁止编辑 -->
-            <template v-if="[4,5].includes(cell.DataType) || disabled">
-              <!-- 单元格类型5显示指标浮窗 -->
+            <template 
+              v-if="([4,5,6,7].includes(cell.DataType)&&!cell.CanEdit)
+              ||disabled
+              ||(cell.DataType===1&&[1,2].includes(cell.DataTimeType))"
+            >
+              
+              <!-- 单元格类型5 7显示指标浮窗 -->
               <el-popover
-                v-if="cell.DataType===5&&!disabled"
+                v-if="[5,7].includes(cell.DataType)&&!disabled"
                 placement="top-start"
                 width="350"
                 trigger="hover"
@@ -63,6 +82,10 @@
                     <label style="min-width:80px;">指标名称</label> 
                     {{cellrelationEdbInfo.EdbName}}
                   </li>
+                  <li style="display:flex;margin:10px;">
+                    <label style="min-width:80px;">最新日期</label> 
+                    {{cellrelationEdbInfo.LatestDate}}
+                  </li>
                   <li style="display:flex;margin:10px;">
                     <label style="min-width:80px;">指标ID</label> 
                     {{cellrelationEdbInfo.EdbCode}}
@@ -86,7 +109,8 @@
 
               <el-autocomplete
                 v-else
-                v-model="cell.ShowValue"
+                v-model="cell.Value"
+                :ref="`inputRef${cell.Uid}`"
                 :fetch-suggestions="searchTarget"
                 popper-class="edb-select-popover"
                 :data-key="cell.Uid"
@@ -96,6 +120,7 @@
                 @select="selectTarget($event,cell)"
                 @click="clickCell($event, cell)"
                 @change.native="changeVal($event, cell)"
+                @keydown.native="keyEnterHandle($event,cell)"
               >
                 <template slot-scope="scope">
                     <edbDetailPopover :info="scope.item">
@@ -115,7 +140,25 @@
 
       <!-- 右键菜单 -->
       <div class="contextMenu-wrapper" id="contextMenu-wrapper" @mouseleave="hideContextMenu">
-        <div :class="['item',{'deletesty': menu.key==='reset'}]" v-for="menu in config.contextMenuOption" :key="menu.key" @click="handleContext(menu.key)">{{menu.label}}</div>
+        <div :class="['item',{'deletesty': menu.key==='reset'}]" v-for="menu in config.contextMenuOption" :key="menu.key" @click="handleContext(menu.key)">
+          {{menu.label}}
+          
+          <i class="el-icon-arrow-right" v-if="menu.children"></i>
+
+          <!-- 二级菜单 -->
+          <div class="subMenu-wrapper" v-if="menu.children">
+            <div slot="reference" class="item" v-for="submenu in menu.children" :key="submenu.key" @click="edbCalculateInsertOpen(submenu)">
+                <el-popover
+                  width="300"
+                  trigger="hover"
+                  placement="right"
+                >
+                  <div v-html="formulaTip.get(submenu.fromEdbKey)"></div>
+                  <div slot="reference" style="width:100%">{{submenu.label}}</div>   
+                </el-popover>
+            </div>
+          </div>
+        </div>
       </div>
     </template>
 
@@ -129,6 +172,21 @@
       @insert="insertSelectData"
       ref="selectTargetValueRef"
     />
+
+    <!-- 插入系统/指标日期弹窗 -->
+    <insertDateDia
+      :isShow.sync="isInsertDateDialog"
+      :info="insertDateInfo"
+      @insert="insertDatehandle"
+    />
+
+    <!-- 指标计算弹窗 -->
+    <calculateEdbDia
+      ref="calculateEdbDiaRef"
+      :isShow.sync="isInsertCalculate"
+      :info="insertCalculateInfo"
+      @insert="insertCalculateData"
+    />
   </div>
 </template>
 <script>
@@ -143,12 +201,20 @@ import {
   setFocus,
   findCellByKey,
   resetRelationStyle,
-  resetDialogCellStyle
+  resetDialogCellStyle,
+  extractFactorsFromFormula,
+  findCellByFactor,
+  splitString,
+  toUpperCase,
+  findCellKeyByFactor
 } from "../common/customTable";
 import * as sheetInterface from "@/api/modules/sheetApi.js";
 import { dataBaseInterface } from '@/api/api.js';
 import md5 from '@/utils/md5.js';
 import selectTargetValueDia from './selectTargetValueDia.vue';
+import insertDateDia from './insertDateDia.vue';
+import calculateEdbDia from './calculateEdbDia.vue';
+import { formulaTip } from '@/views/dataEntry_manage/databaseComponents/util';
 export default {
   props: {
     disabled: { //是否只预览
@@ -156,7 +222,7 @@ export default {
       default: false,
     }
   },
-  components: { selectTargetValueDia },
+  components: { selectTargetValueDia,insertDateDia,calculateEdbDia },
   computed: {
     //列头
     columnHeader() {
@@ -192,7 +258,18 @@ export default {
   data() {
     return {
       config: {
-        data: [], //单元格类型 1日期格 2指标格 3自定义输入 4插入值 有关联的日期和指标格 5弹窗里的插入值 有关联日期格
+        /* 单元格类型 
+          1手动日期格 DataTimeType 0
+          2指标格 
+          3自定义输入 
+          4插入值 表格里有关联的日期和指标格  //隐藏 又不要这个功能了
+          5弹窗里的插入值 有关联日期格 
+          6公式计算单元格 
+          1系统日期导入格 DataTimeType 1
+          1指标日期导入格 DataTimeType 2
+          7指标计算的插入值单元格
+        */
+        data: [], 
         contextMenuOption: [],
       },
 
@@ -200,14 +277,32 @@ export default {
 
       rightClickCell: {},//右键单元格 key c r
 
-      insertTargetCell: {},//选择右键插入指标的单元格 可和右键单元格不一样 key c r
+      insertTargetCell: {},//选择右键插入的单元格 可和右键单元格不一样 key c r
 
-      insertRelationArr: [],
+      insertRelationArr: [], //表格单元格依赖关系数组
 
       isSelectTargetValueDialog: false,
 
-      cellrelationEdbInfo: {},
+      cellrelationEdbInfo: {}, //指标浮窗信息
+
+      copyCellItem: {},//复制时的单元格信息 用于粘贴赋值
+
+      calculateClickCell: null,//双击公式单元格时的单元格信息 用于之后选其他单元格拼接公式
+
+      isInsertDateDialog: false,//导入日期弹窗
+      insertDateInfo: {
+        key: '',
+      },
+
+      calculateChainList: [],//公式链 key数组 后端需要
+
+      isInsertCalculate: false,//插入指标计算值
+      insertCalculateInfo: {},//指标计算单元格info
+
+      formulaTip,
+      
       hasInit:false,
+
     };
   },
   mounted() {
@@ -215,8 +310,15 @@ export default {
   },
   methods: {
 
+    /* 输入时实时搜索 满足日期格式不搜索 有=视为输入公式不搜索 */
     async searchTarget(query,cb) {
-      if(!query||checkDateFormat(query)) return cb([])
+      //又要过滤掉2020-05-这样的奇葩其他格式 不让检索
+      let dateOtherRegex = /^(?:(?:19|20)\d\d)([-])(0[1-9]|1[0-2])(-?)$/
+      if(!query
+        ||checkDateFormat(query)
+        ||dateOtherRegex.test(query)
+        ||query.startsWith('=')
+      ) return cb([])
       
       const { DataType,EdbInfoId } = this.selectCell;
 
@@ -242,8 +344,15 @@ export default {
       
       setFocus(e);
 
-      //插入值时寻找关联依赖的单元格 设置选框
-      if([4,5].includes(cell.DataType)) {
+      /* 如果当前有公式单元格在编辑就拼接当前单元格进公式 */
+      // if(this.calculateClickCell && this.calculateClickCell.Uid!==cell.Uid) {
+      //   console.log(this.calculateClickCell)
+      //   const { cindex,rindex } = e.target.dataset;
+      //   this.calculateClickCell.Value += `${cindex}${rindex}`
+      // }
+
+      //是插值单元格时寻找关联依赖的单元格 设置选框
+      if([4,5,7].includes(cell.DataType)) {
         const { key } = e.target.dataset;
         if(!this.insertRelationArr.find(_ => _.key===key)) return
         let { relation_date,relation_edb } = this.insertRelationArr.find(_ => _.key===key)
@@ -252,7 +361,11 @@ export default {
         relation_edb.key && setRelationStyle(relation_edb)
       }
 
+      //选择指标弹窗打开时选择日期更新弹窗数据
       this.isSelectTargetValueDialog&&this.$refs.selectTargetValueRef.chooseEdb(this.$refs.selectTargetValueRef.edbInfo)
+
+      //计算指标弹窗打开时选择日期更新弹窗数据
+      this.isInsertCalculate&&this.$refs.calculateEdbDiaRef.showResult&&this.$refs.calculateEdbDiaRef.calculateHandle()
     },
 
     /* 插入值 往左往上寻找同行同列是否有符合条件的一指标一日期 */
@@ -262,6 +375,7 @@ export default {
       console.log(params)
       if(!params) {
         this.selectCell.DataType = 3;
+        this.selectCell.DataTimeType = 0;
         this.selectCell.ShowValue = '';
         this.selectCell.Value = '';
         this.selectCell.DataTime = '';
@@ -270,22 +384,24 @@ export default {
         return
       }
 
-      const { EdbInfoId,Date } = params
+      const { EdbInfoId,Date,DataTimeType } = params
 
       const res = await sheetInterface.insertData({EdbInfoId,Date})
       if(res.Ret !==200) return
 
-      if(!res.Data){
-        this.selectCell.DataType = 3;
-        this.selectCell.ShowValue = '';
-        this.selectCell.Value = '';
-        this.selectCell.DataTime = '';
-        this.selectCell.EdbInfoId = 0;
-        this.$message.warning('所选指标的所选日期无值')
-        return
-      }
+      //日期无值也要建立关联关系
+      // if(!res.Data&&!DataTimeType){
+      //   this.selectCell.DataType = 3;
+      //   this.selectCell.DataTimeType = 0;
+      //   this.selectCell.ShowValue = '';
+      //   this.selectCell.Value = '';
+      //   this.selectCell.DataTime = '';
+      //   this.selectCell.EdbInfoId = 0;
+      //   this.$message.warning('所选指标的所选日期无值')
+      //   return
+      // }
 
-      this.$message.success('插入成功')
+      res.Data ? this.$message.success('插入成功') : this.$message.warning('当前日期暂无值') 
 
       this.selectCell.DataType = 4;
       this.selectCell.ShowValue = res.Data;
@@ -299,6 +415,7 @@ export default {
     // 建立插入单元格和依赖单元格关联关系
     setRelation(data,cellType=4) {
       const { insert_cell } = data;
+
       let relation_obj = {
         type: cellType,
         key: insert_cell.key,
@@ -348,6 +465,7 @@ export default {
             if((row_cell_arr[i].DataType===1&&col_cell_arr[j].DataType===2)
             ||(row_cell_arr[i].DataType===2&&col_cell_arr[j].DataType===1)) {
               params = {
+                DataTimeType: row_cell_arr[i].DataType===1 ? row_cell_arr[i].DataTimeType : col_cell_arr[j].DataTimeType,
                 Date: row_cell_arr[i].DataType===1 ? row_cell_arr[i].ShowValue : col_cell_arr[j].ShowValue,
                 EdbInfoId: row_cell_arr[i].DataType===2 ? row_cell_arr[i].EdbInfoId : col_cell_arr[j].EdbInfoId,
                 insert_cell: {
@@ -383,10 +501,12 @@ export default {
       this.checkCellRelation(cell)
     },
 
-    /* 输入框失焦  */
+    /* 输入框失焦 设置单元格类型 处理关联关系 */
     async changeVal(e, cell) {
+
       // 是日期格式 DataType为1
-      // 否则是3
+      // 自定义内容 DataType 3
+      //有=号为输入公式 DataType 6
 
       const {value} = e.target;
       if(!value){ //无值重置单元格
@@ -395,24 +515,34 @@ export default {
         cell.Value = value;
         cell.EdbInfoId = 0;
         cell.DataTime = '';
+        cell.Extra=''
       }else {
         //指标类型不做格式处理
         if(cell.DataType===2) return
         
         console.log(checkDateFormat(value))
-        if(checkDateFormat(value)) { //是日期格式
+        let dateFormat = checkDateFormat(value);
+        if(dateFormat) { //是日期格式
           cell.DataType = 1;
+          cell.Extra='';
+          cell.ShowValue = dateFormat;
+          cell.Value = dateFormat;
+        }else if(value.startsWith('=')) { //公式单元格
+          cell.DataType = 6;
+          let calculateVal = await this.getValueByFormula(value);
+          if(!calculateVal) return
+          cell.ShowValue = calculateVal;
+          //处理公式关系
+          this.$set(cell,'Extra',this.dealFormulaConstruction(value))
           
-          cell.ShowValue = checkDateFormat(value);
-          cell.Value = checkDateFormat(value);
-        }else if(cell.EdbInfoId&&!cell.DataTime&&cell.Value===value) {//指标
-  
+
         }else {//自定义值
           cell.DataType = 3;
           cell.ShowValue = value;
           cell.Value = value;
           cell.EdbInfoId = 0;
           cell.DataTime = '';
+          cell.Extra=''
         }
       }
 
@@ -457,9 +587,10 @@ export default {
           const res = await sheetInterface.insertData(params)
           if(res.Ret !==200) return
 
-          !res.Data && this.updateInsertCell(relation.key);
-  
-          res.Data && this.config.data.forEach(row => {
+          //现在日期无值也不清除关系了
+          // !res.Data && this.updateInsertCell(relation.key);
+          
+          this.config.data.forEach(row => {
             row.forEach(cell => {
               if(cell.Uid === relation.key) {
                   cell.DataType = relation.type;
@@ -497,6 +628,40 @@ export default {
       this.insertRelationArr.splice(relationIndex,1)
     },
 
+    /* 输入公式的计算值 */
+    async getValueByFormula(val) {
+
+      // 提取因数数组
+      let factors = extractFactorsFromFormula(val)
+      console.log(factors)
+      
+      //根据因数找单元格
+      let isAllCell = factors.some(_ => findCellByFactor(_)===null||isNaN(findCellByFactor(_)))
+      if(isAllCell) {
+        this.$message.warning('公式参数有误')
+        return '';
+      } 
+
+      let TagMap = {};
+      factors.forEach(_ => {
+        if(!TagMap[_]) {
+          TagMap[_] = Number(findCellByFactor(_))
+        }
+      });
+
+      const res = await sheetInterface.calculateCustomCellData({
+        CalculateFormula: val,
+        TagMap
+      })
+      if(res.Ret !== 200) return 
+      return res.Data
+    },
+
+    /* 顶部公式改变 */
+    async updateValueByFormula(value) {
+      this.changeVal({target: {value}},this.selectCell)
+    },
+
     /* 右键 */
     rightClickHandle(e,cell) {
       if(this.disabled) return
@@ -518,15 +683,26 @@ export default {
       }else {//单元格
         pos = 'cell'
       }
-      this.config.contextMenuOption = getRightClickMenu(pos)
+      this.config.contextMenuOption = pos === 'cell' 
+        ? getRightClickMenu(pos,(cell.DataType===1&&[1,2].includes(cell.DataTimeType))||cell.DataType===7)
+        : getRightClickMenu(pos)
 
+      this.$nextTick(() => {
+        let dom = $('#contextMenu-wrapper')[0];
 
-      const dom = $('#contextMenu-wrapper')[0];
-			dom.style.left = e.clientX-3 + 'px';
-			dom.style.top = e.clientY-3 + 'px';
+        if(e.clientY > window.innerHeight/2) {
+          dom.style.left = e.clientX-3 + 'px';
+          dom.style.top = e.clientY-dom.offsetHeight-3 + 'px';
+        }else {
+          dom.style.left = e.clientX-3 + 'px';
+          dom.style.top = e.clientY-3 + 'px';
+        }
+
+        ['col','row'].includes(pos) && selectMoreCellStyle(e);
+        pos==='cell' && this.clickCell(e,cell);
+
+      })
       
-      ['col','row'].includes(pos) && selectMoreCellStyle(e);
-      pos==='cell' && this.clickCell(e,cell);
     },
 
     /*  */
@@ -538,52 +714,66 @@ export default {
 
     /* 右键事件 */
     async handleContext(key) {
+
+      let editHandlesMap = {
+        1: this.insertDateOpen,
+        7: this.edbCalculateInsertOpen
+      }
+
       const keyMap = {
-        'del': this.delColOrRow,
-        'insert-col-left': this.insertCol,
-        'insert-col-right': this.insertCol,
-        'insert-row-up': this.insertRow,
-        'insert-row-down': this.insertRow,
-        'insert-value': this.insertValue,
-        'choose-target': this.selectTargetOpen,
-        'reset': this.clearCell
+        'del': this.delColOrRow,//删除
+        'insert-col-left': this.insertCol,//向左插入列
+        'insert-col-right': this.insertCol,//向右插入列
+        'insert-row-up': this.insertRow,//向上插入行
+        'insert-row-down': this.insertRow,//向下插入行
+        'insert-value': this.insertValue,//插入值
+        'choose-target': this.selectTargetOpen,//选择指标插入值
+        'insert-sys-date': this.insertDateOpen,//导入系统日期
+        'insert-edb-date': this.insertDateOpen,//导入指标日期
+        'reset': this.clearCell, //清空
+        'cell-edit': this.selectCell ? editHandlesMap[this.selectCell.DataType] : null
       }
       keyMap[key] && keyMap[key](key)
       
-      this.hideContextMenu()
+      key!=='insert-edb-calculate' && this.hideContextMenu()
     },
 
     /* 打开选择指标弹窗  
-    打开弹窗后仍可以在页面上点击 多存一个选择指标时的信息 */
+    打开弹窗后仍可以在页面上点击 多存一个选择指标时的当前单元格信息 */
     selectTargetOpen() {
       this.insertTargetCell = this.selectCell;
       resetDialogCellStyle();
       setRelationStyle({ key:this.insertTargetCell.Uid },'td-choose-insert-target')
       this.isSelectTargetValueDialog = true;
+
+      this.isInsertCalculate = false;
+      this.$refs.calculateEdbDiaRef.initData();
     },
 
     /* 插入选择指标的值 */
-    insertSelectData({ edbId,value }) {
+    insertSelectData({ edbId,value,date }) {
 
       this.insertTargetCell.DataType = 5;
       this.insertTargetCell.ShowValue = value;
       this.insertTargetCell.Value = value;
       this.insertTargetCell.EdbInfoId = edbId;
-      this.insertTargetCell.DataTime = this.selectCell.ShowValue;
+      this.insertTargetCell.DataTime = date;
 
       this.$message.success('插入成功')
 
-      //建立新的关联关系
-      let relation = {
-        insert_cell: {
-          key: this.insertTargetCell.Uid,
-          relation_date: this.selectCell.Uid,
-          relation_edb: '',
+      //如果有关联表格日期就建立新的关联关系
+      if(date) {
+        let relation = {
+          insert_cell: {
+            key: this.insertTargetCell.Uid,
+            relation_date: this.selectCell.Uid,
+            relation_edb: '',
+          }
         }
+  
+        this.setRelation(relation,5);
       }
 
-      this.setRelation(relation,5);
-
     },
 
     /* 清除单元格内容 格式 关联关系 */
@@ -594,6 +784,7 @@ export default {
       this.selectCell.ShowValue = '';
       this.selectCell.Value = '';
       this.selectCell.DataTime = '';
+      this.selectCell.DataTimeType = 0;
       this.selectCell.EdbInfoId = 0;
 
       this.checkCellRelation(this.selectCell)
@@ -637,7 +828,6 @@ export default {
         this.config.data.splice(index,1)
 
       }
-      // console.log(this.insertRelationArr)
     },
 
     /* 删除时清除关联关系 和删除单元格有关联的插入值单元格和 */
@@ -693,7 +883,7 @@ export default {
 
     /* 单元格类型5 浮到上面展示指标信息浮窗 */
     async getRelationEdbInfo({EdbInfoId,DataType}) {
-      if(DataType!==5||this.disabled) return
+      if(![5,7].includes(DataType)||this.disabled) return
 
       const res = await dataBaseInterface.targetDetail({EdbInfoId})
 
@@ -702,6 +892,95 @@ export default {
       this.cellrelationEdbInfo =  res.Data;
     },
 
+    /* 导入系统/指标日期弹窗 */
+    insertDateOpen(type) {
+      this.insertTargetCell = this.selectCell;
+      resetDialogCellStyle();
+
+      if(type === 'cell-edit') { //编辑日期
+        const { DataTimeType } = this.insertTargetCell;
+        this.insertDateInfo = {
+          key: DataTimeType===1? 'insert-sys-date' : 'insert-edb-date',
+          ...this.insertTargetCell
+        }
+      }else {
+        this.insertDateInfo = {
+          key:type
+        }
+      }
+      this.isInsertDateDialog = true;
+
+      this.isSelectTargetValueDialog = false;
+      this.$refs.selectTargetValueRef.initData();
+      this.isInsertCalculate = false;
+      this.$refs.calculateEdbDiaRef.initData();
+    },
+
+    /* 插入系统/指标日期 */
+    insertDatehandle({insertValue,dataTimeType,str}) {
+
+      this.insertTargetCell.DataType = 1;
+      this.insertTargetCell.DataTimeType = dataTimeType;
+      this.insertTargetCell.ShowValue = insertValue;
+      this.insertTargetCell.Value = str;
+      this.insertTargetCell.EdbInfoId = 0;
+      this.insertTargetCell.DataTime = insertValue;
+    },
+
+    /* 指标计算弹窗 */
+    edbCalculateInsertOpen(item) {
+      this.insertTargetCell = this.selectCell;
+      resetDialogCellStyle();
+      setRelationStyle({ key:this.insertTargetCell.Uid },'td-choose-insert-target');
+
+      if(item === 'cell-edit') { //编辑
+        const { Value } = this.insertTargetCell;
+
+        let menuInfo = this.config.contextMenuOption
+          .find(_ => _.key==='insert-edb-calculate').children
+          .find(menu => menu.source === JSON.parse(Value).Source);
+
+        this.insertCalculateInfo = {
+          ...menuInfo,
+          formStr: Value,
+        }
+      }else {
+        this.insertCalculateInfo = {
+          ...item
+        }
+      }
+      this.isInsertCalculate = true;
+
+      this.isSelectTargetValueDialog = false;
+      this.$refs.selectTargetValueRef.initData();
+    },
+
+    /* 导入指标计算值 */
+    insertCalculateData(item) {
+      console.log(item)
+      const { InsertValue,EdbInfoId,Str,Date } = item;
+      this.insertTargetCell.DataType = 7;
+      this.insertTargetCell.ShowValue = InsertValue;
+      this.insertTargetCell.Value = Str;
+      this.insertTargetCell.EdbInfoId = EdbInfoId;
+      this.insertTargetCell.DataTime = Date;
+
+      this.$message.success('插入成功')
+
+      //如果有关联表格日期就建立新的关联关系
+      if(Date) {
+        let relation = {
+          insert_cell: {
+            key: this.insertTargetCell.Uid,
+            relation_date: this.selectCell.Uid,
+            relation_edb: '',
+          }
+        }
+  
+        this.setRelation(relation,7);
+      }
+    },
+
     /* 初始化8行5列 */
     initData(initData=null) {
       console.log('initData');
@@ -717,6 +996,7 @@ export default {
             ShowValue: "",
             Value: "",
             DataType: 3,
+            DataTimeType: 0,
             DataTime: "",
             EdbInfoId:0,
             Uid: md5.hex_md5(`${new Date().getTime()}${_rindex}${_cindex}`)
@@ -727,6 +1007,91 @@ export default {
         this.hasInit=true
       })
     },
+
+     /* 处理因数结构 =a1+b1 => [{ Tag: a,Row:1,Key:'' }] */
+    dealFormulaConstruction(val) {
+      // 提取因数数组
+      let factors = extractFactorsFromFormula(val)
+      let arr = factors.map(str => ({
+          Tag: splitString(toUpperCase(str))[0],
+          Row: splitString(toUpperCase(str))[1],
+          Key: findCellKeyByFactor(str)
+      }))
+      return JSON.stringify(arr)
+    },
+
+
+    /* 要支持复制粘贴把公式也带过去 公式单元格类型为6 其余就正常复制文本 */
+    copyCellHandle(e,cell) {
+      this.copyCellItem = cell;
+      // 阻止默认的复制操作
+      e.preventDefault();
+    },
+
+    /* 要支持复制粘贴把公式也带过去 公式单元格类型为6 其余就正常复制文本 */
+    pasteCellHandle(e,cell) {
+      if(this.copyCellItem.DataType === 6) {
+        cell.DataType = this.copyCellItem.DataType;
+        cell.ShowValue = this.copyCellItem.ShowValue;
+        cell.Value = this.copyCellItem.Value;
+        cell.DataTime = this.copyCellItem.DataTime;
+        cell.EdbInfoId = this.copyCellItem.EdbInfoId;
+      }else {
+        cell.DataType = 3;
+        cell.ShowValue = this.copyCellItem.ShowValue;
+        cell.Value = this.copyCellItem.ShowValue;
+        cell.DataTime = '';
+        cell.EdbInfoId = 0;
+      }
+
+      // 阻止默认的粘贴操作
+      e.preventDefault();
+    },
+
+    /* 单元格enter时切换编辑状态 */
+    keyEnterHandle(e,cell) {
+      if(e.keyCode===13) {
+        //非得搞个要回车失焦
+        e.target.nodeName && e.target.blur();
+        this.$refs[`inputRef${e.target.dataset.key}`]&&this.$refs[`inputRef${e.target.dataset.key}`][0].close()
+
+        cell.DataType===6 && this.$set(cell,'CanEdit',false)
+        // this.calculateClickCell = null
+      }
+    },
+
+    /* 支持公式单元格双击切换状态 */
+    dblClickCellHandle(e,cell) {
+      if(this.disabled || cell.DataType!==6) return
+
+      this.$set(cell,'CanEdit',true)
+
+      // this.calculateClickCell = cell;
+      // setRelationStyle({ key:cell.Uid },'td-choose-insert-target')
+
+      this.$nextTick(() => {
+        if(e.target.childNodes[0].childNodes[0].childNodes[1].nodeName==='INPUT') e.target.childNodes[0].childNodes[0].childNodes[1].focus();
+      })
+    },
+
+    /* 处理保存的参数 */
+    getSaveParams() {
+      const { data } = this.config;
+
+      let params = {
+        CellRelation: JSON.stringify(this.insertRelationArr),
+        Data: data
+      }
+
+      return params
+    },
+
+    /* tab禁掉 */
+    handlekeyDownKeys(e) {
+      if(e.keyCode === 9) {
+        e.preventDefault();
+      }
+    }
   },
 };
 </script>
@@ -740,10 +1105,23 @@ export default {
 .table-wrapper {
   width: 100%;
   overflow: auto;
+
+  .formula-wrapper {
+    height: 42px;
+    display: flex;
+    align-items: center;
+    background: #fff;
+    border-radius: 4px;
+    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
+    border: 1px solid #DCDFE6;
+    margin-bottom: 15px;
+    padding: 0 15px;
+  }
   .table td,th {
     width: 104px;
     min-width: 104px;
     height: 35px;
+    max-height: 35px;
     background: #fff;
     text-align: center;
     word-break: break-all;
@@ -862,6 +1240,21 @@ export default {
       &:hover {
         background-color: #f5f7fa;
       }
+      &:hover .subMenu-wrapper {
+        display: block;
+      }
+    }
+
+    .subMenu-wrapper {
+      display: none;
+      padding: 10px 0;
+      box-shadow: 0 1px 4px #999;
+      background: #fff;
+      position: absolute;
+      right: -172px;
+      top:-205px;
+      max-height: 400px;
+      overflow-y: auto;
     }
   }
 }
@@ -881,6 +1274,7 @@ export default {
     background-color: #fff;
   }
 }
+.formula-wrapper .el-input__inner { border: none; outline: none; }
 .edb-select-popover {
   width: 300px !important;
   .edb-item {

+ 521 - 0
src/views/datasheet_manage/components/calculateEdbDia.vue

@@ -0,0 +1,521 @@
+<template>
+  <div v-dialogDrag v-if="isShow" >
+    <div class="calculate-edb-value-dialog el-dialog" >
+      <div class="header el-dialog__header">
+        <span>{{info.label}}</span>
+        <i class="el-icon-close" @click="cancelHandle"/>
+      </div>
+
+      <div class="main">
+
+        <section class="main-top">
+
+          <template v-if="info.fromEdbKey===5">
+            <el-radio-group 
+              v-model="formData.source"
+              @change="changeSource"
+            >
+              <el-radio :label="1">累计值转月</el-radio>
+              <el-radio :label="2">累计值转季值</el-radio>
+            </el-radio-group>
+          </template>
+
+          <template v-else-if="info.fromEdbKey===62"> 
+            <el-radio-group 
+              v-model="formData.source"
+              @change="changeSource"
+            >
+              <el-radio :label="13">累计值</el-radio>
+              <el-radio :label="14">年初至今累计值</el-radio>
+            </el-radio-group>
+          </template>
+
+          <selectTarget
+            :defaultId="search_edb"
+            :defaultOpt="searchOptions"
+            ref="selectRef"
+            @select="selectTargetHandle"
+            :filter="false"
+            style="margin: 20px 0"
+          />
+
+          <!-- 表格已存在的指标列表 -->
+          <div class="edb-list">
+              <el-tag 
+                :effect="selectEdbInfo&&selectEdbInfo.EdbInfoId===item.EdbInfoId?'dark':'plain'" 
+                v-for="(item,index) in edbArrFromTable" 
+                :key="index"
+                @click="selectTableEdbHandle(item)"
+              >{{ item.ShowValue }}</el-tag>
+          </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="移动方式" style="display: block;" v-if="info.fromEdbKey === 22" prop="moveVal">
+							<el-select
+								v-model="formData.moveType"
+								style="width: 100px"
+								placeholder=""
+								size="mini"
+								@change="changeParams"
+							>
+								<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)"
+                @change="changeParams"
+							></el-input>
+							<el-select
+								v-model="formData.moveUnit"
+								size="mini"
+								placeholder=""
+								style="width: 100px"
+                @change="changeParams"
+							>
+								<el-option
+									v-for="item in fre_options"
+									:key="item"
+									:label="item"
+									:value="item"
+								>
+								</el-option>
+							</el-select>
+						</el-form-item>
+
+						<el-form-item label="N等于" prop="nNum" v-if="[8,12,13,35].includes(info.fromEdbKey)">
+							<el-input
+								v-model="formData.nNum"
+								style="width: 200px"
+								placeholder="请输入N数值"
+								type="number"
+								@change="changeParams"
+							/>
+						</el-form-item>
+
+						<el-form-item label="日历" prop="calendarType" v-if="info.fromEdbKey===35">
+							<el-select
+								v-model="formData.calendarType"
+								placeholder="请选择日历"
+								style="width: 200px"
+								@change="changeParams"
+							>
+								<el-option
+									v-for="item in calendarOptions"
+									:key="item.key"
+									:label="item.label"
+									:value="item.label"
+								>
+								</el-option>
+							</el-select>
+						</el-form-item>
+
+            <el-form-item label="频度" prop="frequency" v-if="[9,13].includes(formData.source)">
+							<el-select
+								v-model="formData.frequency"
+								placeholder="请选择频度"
+								style="width: 200px"
+								clearable
+                @change="changeParams"
+							>
+								<el-option
+									v-for="item in frequencyArr"
+									:key="item"
+									:label="item"
+									:value="item"
+								>
+								</el-option>
+							</el-select>
+						</el-form-item>
+
+						<el-form-item label="数据取值" prop="valueType" v-if="info.fromEdbKey===51">
+							<el-select
+								v-model="formData.valueType"
+								placeholder="请选择数据取值类型"
+								style="width: 200px"
+                @change="changeParams"
+							>
+								<el-option key="期末值" label="期末值" value="期末值"/>
+								<el-option key="平均值" label="平均值" value="平均值"/>
+							</el-select>
+						</el-form-item>
+
+						<el-form-item label="alpha值" prop="alphaValue" v-if="info.fromEdbKey==='alpha'">
+              <el-input 
+                v-model="formData.alphaValue" 
+                placeholder="请选择alpha值"
+                style="width: 200px"
+                @change="changeParams"
+              />
+						</el-form-item>
+					</el-form>
+        </section>
+
+        <!-- 计算结果 -->
+        <section class="result-section" v-if="showResult">
+          <label>计算结果:</label>
+          <ul class="data-cont" v-if="calculateShowData.length">
+              <li 
+                v-for="(item,index) in calculateShowData" 
+                :key="index" 
+                :class="[{'choose': item.DataTime===chooseItem.Date || (!chooseItem.Date&&index===0)},'data-li']"
+              >
+                <span>{{item.DataTime}}</span>
+                <span style="min-width:150px">{{item.Value}}</span>
+              </li>
+          </ul>
+
+          <tableNoData text="无对应的数据" size="mini" v-else/>
+        </section>
+
+        <section class="bot">
+          <el-button type="primary" @click="insertData" v-if="showResult">插入值</el-button>
+          <el-button type="primary" @click="calculateHandle" v-else>计算</el-button>
+          <el-button type="primary" plain @click="cancelHandle">取消</el-button>
+
+        </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 { resetDialogCellStyle } from "../common/customTable";
+import selectTarget from '@/views/chartRelevance_manage/components/selectTarget.vue';
+import edbDetailSection from './edbDetailSection.vue';
+import { formRules } from '@/views/dataEntry_manage/databaseComponents/util';
+export default {
+  props: {
+    isShow: {
+      type: Boolean
+    },
+    info: {
+      type: Object
+    }
+  },
+  components: { selectTarget,edbDetailSection },
+  computed: {
+    edbArrFromTable() {
+      let arr = this.$parent.config.data.flat().filter(_ =>_.DataType === 2);
+      let filterArr =  []
+      
+      arr.forEach(item => {
+        if(filterArr.findIndex(_ => _.EdbInfoId===item.EdbInfoId)===-1) {
+          filterArr.push(item)
+        }
+      })
+      
+       return filterArr
+    }
+  },
+  watch: {
+    isShow(nval) {
+      if(!nval) return
+      console.log(this.info)
+      const { source,formStr } = this.info;
+
+      this.formData.source = source;
+      //回显
+      if(formStr) {
+        const {
+          Source,
+          Frequency,
+          Formula,
+          EdbInfoId,
+          MoveFrequency,
+          MoveType, 
+          Calendar 
+        } = JSON.parse(formStr);
+
+        this.formData = {
+          source: Source,
+          frequency: Frequency,
+          nNum: Formula,
+          moveType: MoveType,
+          moveUnit: MoveFrequency,
+          moveVal: Formula,
+          calendarType: Calendar,
+          valueType: Formula,
+          alphaValue: Formula,
+        }
+        this.selectTableEdbHandle({EdbInfoId})
+      }
+    }
+  },
+  data() {
+    return {
+      isCalculateDia: true,
+      formData: {
+        source: this.info.fromEdbKey,
+        frequency: '',
+        nNum: 1,
+				moveType: 1,
+				moveUnit: '天',
+				moveVal: '',
+				calendarType: '公历',
+				valueType: '期末值',
+        alphaValue: 0,
+      },
+      formRules,
+      frequencyArr: ['日度', '周度','旬度', '月度', '季度', '年度'],
+
+      showResult: false,
+      calculateShowData: [], //计算全部数据
+      chooseItem: {
+        Date: ''
+      },//要插入表格的项
+
+      search_edb: '',
+      searchOptions: [],
+      selectEdbInfo: null,
+
+      moveTypeOpions: [
+				{
+					label: '领先',
+					key: 1
+				},
+				{
+					label: '滞后',
+					key: 2
+				},
+			],
+      fre_options: ['天','周','月','季','年'],
+      calendarOptions: [
+				{label: '公历',key: 1},
+				{label: '农历',key: 2},
+			],
+    }
+  },
+  mounted(){
+
+  },
+  methods:{
+    /* 计算结果 */
+    async calculateHandle() {
+      await this.$refs.form.validate();
+      
+      const {  
+        source,
+        nNum,
+				moveType,
+				moveUnit,
+				calendarType,
+        frequency
+      } = this.formData;
+
+      const valueMap = {
+        22: 'moveVal',
+        51: 'valueType',
+        'alpha': 'alphaValue'
+      }
+
+      let DataTime = this.$parent.selectCell.DataType === 1 ? this.$parent.selectCell.ShowValue : ''
+
+      let params = {
+        DataTime,
+        Source: source,
+        Frequency: frequency,
+        Formula: valueMap[this.info.fromEdbKey] ? String(this.formData[valueMap[this.info.fromEdbKey]]) : String(nNum),
+        EdbInfoId: this.selectEdbInfo.EdbInfoId,
+        MoveFrequency: moveUnit,
+        MoveType: moveType, 
+        Calendar: calendarType
+      }
+
+      const res = await sheetInterface.getMixedCalculateData(params)
+      if(res.Ret!==200) return 
+
+      this.showResult = true;
+      this.calculateShowData = res.Data.List || [];
+
+      // if(!this.calculateShowData.length && DataTime) return this.$message.warning('所选指标所选日期无值')
+
+      let InsertValue = this.calculateShowData.length 
+        ? (this.calculateShowData.find(_ => _.DataTime===DataTime) ? this.calculateShowData.find(_ => _.DataTime===DataTime).Value.toString() : this.calculateShowData[0].Value.toString()) 
+        : ''
+      this.chooseItem = {
+          Date:DataTime,
+          EdbInfoId: this.selectEdbInfo.EdbInfoId,
+          InsertValue,
+          Str: JSON.stringify(params)
+        }
+      
+    },
+
+    /* 已计算过改参数重新计算 */
+    changeParams() {
+      this.showResult && this.calculateHandle()
+    },
+
+    /* 插入值 */
+    insertData() {
+
+      // if(this.$parent.selectCell.DataType !== 1) return this.$message.warning('请在表格中选择日期')
+        
+      if(!this.calculateShowData.length) return this.$message.warning('该日期无数据')
+      
+      this.$emit('insert',this.chooseItem)
+      this.cancelHandle();
+    },
+
+    /* 选择指标 */
+    async selectTargetHandle(e) {
+      this.changeSource();
+      if(!e) {
+        this.selectEdbInfo = null
+        return
+      }
+
+      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,SourceName,PredictDataList,DataList } = res.Data.Item;
+      this.selectEdbInfo = {
+        EdbCode,EdbName,Frequency,Unit,StartDate,ModifyTime,SourceName,EdbInfoId,
+        DataList: PredictDataList ? [...PredictDataList,...DataList].slice(0,5) : DataList.slice(0,5)
+      };
+    },
+
+    /* 选择表格指标 */
+    async selectTableEdbHandle(item) {
+      const res = await dataBaseInterface.targetDetail({EdbInfoId:item.EdbInfoId})
+      if(res.Ret !== 200) return
+
+      const { EdbInfoId,EdbInfoType,EdbName,Frequency } = res.Data;
+
+      if(this.formData.source===1&&Frequency!=='月度') return this.$message.warning('只能选择月度指标')
+      else if(this.formData.source===2&&Frequency!=='季度') return this.$message.warning('不能选择季度指标')
+      else if(this.formData.source===8&&Frequency==='日度') return this.$message.warning('不能选择日度指标')
+      else if(this.formData.source===14&&Frequency==='年度') return this.$message.warning('不能选择年度指标')
+
+
+      this.search_edb = EdbName;
+      this.selectTargetHandle({EdbInfoId,EdbInfoType,EdbName})
+    },
+
+    /*  */
+    changeSource() {
+      this.showResult = false;
+      this.calculateShowData = [];
+      this.chooseItem = { Date: '' };
+    },
+
+    initData() {
+      this.search_edb='';
+      this.selectEdbInfo = null;
+      this.showResult = false;
+      this.calculateShowData = [];
+      this.chooseItem = { Date: '' };
+      this.formData = {
+        source: this.formData.source, 
+        frequency: '',
+        nNum: 1,
+				moveType: 1,
+				moveUnit: '天',
+				moveVal: '',
+				calendarType: '公历',
+				valueType: '期末值'
+      }
+    },
+
+    cancelHandle() {
+      this.initData();
+      this.$emit('update:isShow',false);
+      resetDialogCellStyle();
+    }
+  },
+}
+</script>
+<style scoped lang='scss'>
+@import "~@/styles/theme-vars.scss";
+.calculate-edb-value-dialog {
+  background: #fff;
+  position: fixed;
+  top: 20%;
+  left: 50%;
+  width: 750px;
+  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: 20px;
+    max-height: calc(100vh - 350px);
+    min-height: 300px;
+    overflow-y: auto;
+    .main-top {
+      margin-bottom: 20px;
+    }
+    .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;
+    }
+    .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;
+        }
+      }
+    }
+  }
+}  
+</style>

+ 127 - 0
src/views/datasheet_manage/components/edbDetailSection.vue

@@ -0,0 +1,127 @@
+<template>
+  <div class="edb-detail">
+    <label>已选指标:</label>
+    <el-table
+      :data="tableData"
+      style="box-shadow: 0px 3px 6px rgba(155, 170, 219, 0.2); margin-top: 10px"
+      border
+    >
+      <el-table-column
+        v-for="item in tableColums"
+        :key="item.label"
+        :label="item.label"
+        :width="item.widthsty"
+        :min-width="item.minwidthsty"
+        align="center"
+      >
+        <template slot-scope="scope">
+          <span>{{ scope.row[item.key] }}</span>
+        </template>
+      </el-table-column>
+      <div slot="empty">
+        <tableNoData text="暂无指标" size="mini" />
+      </div>
+    </el-table>
+    <ul
+      class="data-ul"
+      ref="dataUl"
+      v-if="tableData[0]&&tableData[0].DataList.length"
+    >
+      <li
+        class="value-item"
+        v-for="(item, index) in tableData[0].DataList"
+        :key="item.EdbDataId"
+      >
+        <span class="value-label">
+          <i class="new-tag" v-if="index === 0"></i>
+          {{ item.DataTime }}
+        </span>
+        <span
+          class="value-label"
+          style="min-width: 200px; text-align: center"
+          >{{ item.Value }}</span
+        >
+      </li>
+    </ul>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    tableData: {
+      type: Array
+    }
+  },
+  data() {
+    return {
+      tableColums:[
+				{
+					label: '指标ID',
+					key: 'EdbCode',
+				},
+				{
+					label: '指标名称',
+					key: 'EdbName',
+				},
+				{
+					label: '频度',
+					key: 'Frequency',
+				},
+				{
+					label: '单位',
+					key: 'Unit',
+				},
+				{
+					label: '起始时间',
+					key: 'StartDate',
+					minwidthsty: '100px'
+				},
+				{
+					label: '更新时间',
+					key: 'ModifyTime',
+					minwidthsty: '110px'
+				},
+				{
+					label: '来源',
+					key: 'SourceName',
+				},
+			],
+      dataList: []
+    };
+  },
+  methods: {},
+};
+</script>
+<style scoped lang="scss">
+.edb-detail {
+  .data-ul {
+    margin-top: 5px;
+    border-bottom: 1px solid #dcdfe6;
+    max-height: 140px;
+    overflow-y: auto;
+    .value-item {
+      /* width: 100%; */
+      padding: 14px 0;
+      border: 1px solid #dcdfe6;
+      border-bottom: none;
+      display: flex;
+      justify-content: space-around;
+      .value-label {
+        position: relative;
+        color: #666;
+      }
+      .new-tag {
+        width: 6px;
+        height: 6px;
+        display: inline-block;
+        position: absolute;
+        left: -12px;
+        top: 50%;
+        transform: translateY(-50%);
+        border-radius: 50%;
+        background: #f00;
+      }
+    }
+  }
+}
+</style>

+ 289 - 0
src/views/datasheet_manage/components/insertDateDia.vue

@@ -0,0 +1,289 @@
+<template>
+  <el-dialog
+		:visible.sync="isShow"
+		:close-on-click-modal="false"
+		:modal-append-to-body='false'
+    :title="titleMap[info.key]"
+		@close="cancelHandle"
+		custom-class="dialog"
+		center
+		width="560px"
+		v-dialogDrag>
+			<div class="dialog-main">
+          <!-- 导入系统日期 -->
+            <ul v-if="info.key==='insert-sys-date'">
+              <li class="form-item">
+                <label>导入方式</label>
+                <el-select
+                    v-model="formData.Source"
+                    placeholder="请选择导入方式"
+                    @change="init('form')"
+                >
+                  <el-option
+                      v-for="item in wayOptions"
+                      :key="item.value"
+                      :label="item.name"
+                      :value="item.value"
+                  />
+                </el-select>
+
+                <template v-if="formData.Source===3">
+                  <el-select
+                      style="max-width: 120px;margin:0 10px"
+                      v-model="formData.Frequency"
+                      placeholder="请选择频度"
+                      @change="formData.Day=frequencyDaysOptions[0].name"
+                  >
+                    <el-option
+                        v-for="item in frequencyOptions"
+                        :key="item.value"
+                        :label="item.name"
+                        :value="item.value"
+                    />
+                  </el-select>
+
+                  <el-select
+                      style="max-width: 120px;"
+                      v-model="formData.Day"
+                      placeholder="请选择"
+                  >
+                    <el-option
+                        v-for="item in frequencyDaysOptions"
+                        :key="item.name"
+                        :label="item.name"
+                        :value="item.name"
+                    />
+                  </el-select>
+                </template>
+
+                <el-tooltip effect="dark" style="margin-left:10px">
+                  <div
+                    slot="content"
+                    v-html="tips[info.key]"
+                    style="line-height: 20px;"
+                  ></div>
+                  <i class="el-icon-question" style="font-size:18px;"/>
+                </el-tooltip>
+              </li>
+              <template v-if="formData.Source===2">
+                <li class="form-item">
+                  <label>天数</label>
+                  <el-input
+                    v-model="formData.CalculateNum"
+                    type="number"
+                    style="margin-right:10px;width:200px"
+                    @change="e => {formData.CalculateNum=Number(e)}"
+                  />
+                  {{formData.CalculateFrequency}}
+                </li>
+                <li style="color:#999">示例:5,表示当前日期+5天的日期; -5,表示当前日期-5天的日期;</li>
+              </template>
+            </ul>
+
+          <!-- 导入指标日期 -->
+          <ul v-else> 
+            <li class="form-item">
+
+              <selectTarget
+                :defaultId="search_edb"
+                :defaultOpt="searchOptions"
+                ref="selectRef"
+                @select="e => { selectEdbInfo = e ||{} }"
+                :filter="false"
+              />
+
+              <el-tooltip effect="dark" style="margin-left:10px">
+                <div
+                  slot="content"
+                  v-html="tips[info.key]"
+                  style="line-height: 20px;"
+                ></div>
+                <i class="el-icon-question" style="font-size:18px;"/>
+              </el-tooltip>
+            </li>
+            <li class="form-item" v-if="selectEdbInfo.Frequency">
+              <label>更新频度</label>
+              {{ selectEdbInfo.Frequency }}
+            </li>
+            <li class="form-item" v-if="selectEdbInfo.LatestDate">
+              <label>最新日期</label>
+              {{ selectEdbInfo.LatestDate }}
+            </li>
+          </ul>
+			</div>
+			<div class="dia-bot">
+				<el-button type="primary" style="margin-right:20px" @click="saveInsertHandle">保存</el-button>
+				<el-button type="primary" plain @click="cancelHandle">取消</el-button>
+			</div>
+	</el-dialog>
+</template>
+<script>
+import * as sheetInterface from "@/api/modules/sheetApi.js";
+import { dataBaseInterface } from '@/api/api.js';
+import selectTarget from '@/views/chartRelevance_manage/components/selectTarget.vue'
+export default {
+  props: {
+    isShow: {
+      type: Boolean
+    },
+    info: {
+      type: Object
+    }
+  },
+  components: { selectTarget },
+  watch: {
+    isShow : { 
+      async handler(nval) {
+        if(nval && this.info.Value) { //处理日期编辑回显
+          const valueObj = JSON.parse(this.info.Value);
+
+          this.formData = {
+            ...this.formData,
+            ...valueObj
+          }
+
+          if(this.info.DataTimeType===2) { //指标日期时获取指标详情
+            const { Data } = await dataBaseInterface.targetDetail({EdbInfoId: valueObj.EdbInfoId})
+
+            const { EdbName,LatestDate,Frequency,EdbInfoId } = Data;
+            this.selectEdbInfo = { EdbName,LatestDate,Frequency,EdbInfoId }
+
+            this.search_edb = valueObj.EdbInfoId;
+            this.searchOptions = [this.selectEdbInfo];
+          }
+        }
+      }
+    }  
+
+  },
+  computed: {
+    frequencyDaysOptions() {
+      let typeMap = {
+        '本周': [
+          { name: '周一' },
+          { name: '周二' },
+          { name: '周三' },
+          { name: '周四' },
+          { name: '周五' },
+          { name: '周六' },
+          { name: '周日' },
+        ]
+      }
+      return typeMap[this.formData.Frequency] 
+        ? typeMap[this.formData.Frequency] 
+        : [{name:'第一天'},{name:'最后一天'}]
+    }
+  },
+  data() {
+    return {
+      formData: {
+        Source: 1,
+        Frequency: '本周',
+        Day: '周一',
+        CalculateNum: 0,
+        CalculateFrequency: '日'
+      },
+
+      wayOptions: [
+        { name: '直接导入', value: 1 },
+        { name: '日期计算', value: 2 },
+        { name: '指定频率', value: 3 },
+      ],
+      frequencyOptions: [
+        { name: '本周', value: '本周' },
+        { name: '本旬', value: '本旬' },
+        { name: '本月', value: '本月' },
+        { name: '本季', value: '本季' },
+        { name: '本半年', value: '本半年' },
+        { name: '本年', value: '本年' },
+      ],
+
+      search_edb: '',
+      searchOptions:[],
+
+      titleMap: {
+        'insert-sys-date': '导入系统日期',
+        'insert-edb-date': '导入指标日期'
+      },
+
+      tips: {
+        'insert-sys-date': `1、直接导入:直接取系统日期,跟随系统日期更新<br>
+        2、日期计算:取系统日期进行公式计算,跟随系统日期更新 <br>
+        3、指定频率:取系统日期相关的指定日期,跟随系统日期更新`,
+        'insert-edb-date': '取指标的最新日期,跟随指标最新日期更新'
+      },
+
+      selectEdbInfo: {}
+
+    }
+  },
+  methods:{
+    // 保存插入信息
+    async saveInsertHandle() {
+
+      if(this.info.key==='insert-edb-date' && !this.selectEdbInfo.EdbInfoId) return this.$message.warning('请选择指标')
+      
+      let backData = {}
+      //插入系统日期
+      if(this.info.key==='insert-sys-date') {
+        let { Data } = await sheetInterface.getSystemDate({
+          DataTimeType: 1,
+          Value: JSON.stringify(this.formData)
+        })
+        
+        backData = {
+          insertValue: Data.Date,
+          dataTimeType: 1,
+          str: JSON.stringify(this.formData)
+        }
+      }else { //指标日期
+        backData = {
+          insertValue: this.selectEdbInfo.LatestDate,
+          dataTimeType: 2,
+          str:  JSON.stringify({EdbInfoId: this.selectEdbInfo.EdbInfoId})
+        }
+      }
+      this.$emit('insert',backData)
+      this.cancelHandle()
+    },
+
+    init(type='') {
+
+      this.formData = {
+        Source: this.formData.Source,
+        Frequency: '本周',
+        Day: '周一',
+        CalculateNum: 0,
+        CalculateFrequency: '日'
+      }
+
+      this.search_edb = '';
+      this.searchOptions = [];
+      if(this.$refs.selectRef) this.$refs.selectRef.search_txt='';
+
+      if(!type) this.formData.Source = 1;
+      this.selectEdbInfo = {}
+    },
+    cancelHandle() {
+      this.init()
+      this.$emit('update:isShow',false)
+    }
+  },
+}
+</script>
+<style scoped lang='scss'>
+.dialog-main {
+  padding: 20px;
+  .form-item { 
+    margin: 15px 0; 
+    display: flex;
+    align-items: center;
+    label { width: 80px;flex-shrink: 0; }
+  }
+}
+.dia-bot {
+  margin: 30px 0;
+  display: flex;
+  justify-content: center;
+}
+</style>

+ 26 - 14
src/views/datasheet_manage/components/selectTargetValueDia.vue

@@ -13,8 +13,12 @@
       />
 
       <ul class="data-cont">
-        <template v-if="result.List">
-          <li v-for="(item,index) in result.List" :key="index" :class="[{'choose': item.DataTime===result.Date},'data-li']">
+        <template v-if="result.List&&result.List.length">
+          <li 
+            v-for="(item,index) in result.List" 
+            :key="index" 
+            :class="[{'choose': item.DataTime===chooseItem.date || (!chooseItem.date&&index===0)},'data-li']"
+          >
             <span>{{item.DataTime}}</span>
             <span style="min-width:150px">{{item.Value}}</span>
           </li>
@@ -23,7 +27,7 @@
       </ul>
 
       <div class="dia-bot">
-        <el-button type="primary" style="margin-right: 20px" :disabled="!result.Date" @click="insertData"
+        <el-button type="primary" style="margin-right: 20px" @click="insertData"
           >插入值</el-button
         >
         <el-button type="primary" plain @click="cancelHandle">取消</el-button>
@@ -63,30 +67,38 @@ export default {
       } 
 
       this.edbInfo = edb;
-      
-      if(this.$parent.selectCell.DataType !== 1){
 
-        this.$message.warning('请在表格中选择日期')
-        this.initData();
-        return
-      }
+      let Date = this.$parent.selectCell.DataType === 1 ? this.$parent.selectCell.ShowValue : ''
 
       const res = await sheetInterface.getDateLatelyData({ 
         EdbInfoId: edb.EdbInfoId,
-        Date: this.$parent.selectCell.ShowValue
+        Date
       })
       if(res.Ret !== 200) return
 
       this.result = res.Data;
-      if(!this.result.Date) return this.$message.warning('所选指标所选日期无值')
+      // if(!this.result.Date && Date) return this.$message.warning('所选指标所选日期无值')
+
+      let value = (this.result.List&&this.result.List.length)
+        ? (this.result.List.find(_ => _.DataTime===Date) ? this.result.List.find(_ => _.DataTime===Date).Value.toString() : this.result.List[0].Value.toString()) 
+        : ''
       this.chooseItem = {
+        date: Date,
         edbId: edb.EdbInfoId,
-        value: this.result.Date?this.result.List.find(_ =>_.DataTime===this.result.Date).Value.toString():''
+        value
       }
 
+      console.log( this.chooseItem)
+
     },
 
     insertData() {
+      // if(this.$parent.selectCell.DataType !== 1){
+      //   this.$message.warning('请在表格中选择日期')
+      //   return
+      // }
+      if(!this.chooseItem.value) return this.$message.warning('该日期无数据')
+
       this.$emit('insert',this.chooseItem)
       this.cancelHandle();
     },
@@ -95,7 +107,7 @@ export default {
       this.$refs.selectRef.search_txt='';
       this.result = {};
       this.edbInfo=null;
-      this.chooseItem = { edbId: 0,value: '' }
+      this.chooseItem = { edbId: 0,value: '',date: '' }
     },
 
     cancelHandle() {
@@ -116,7 +128,7 @@ export default {
   width: 500px;
   border-radius: 2px;
   box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
-  z-index: 999;
+  z-index: 9999;
   .header { 
     height: 50px;
     font-size: 16px;

+ 5 - 8
src/views/datasheet_manage/mixedSheetEdit.vue

@@ -163,6 +163,7 @@ export default {
         this.classifyArr = res.Data.AllNodes || [];
       })
     },
+
     autoSaveFun:_.debounce(async function(){
       if(!this.sheetId || this.cancelAutoSave) return 
       const { name,classify,sheetType } = this.sheetForm;
@@ -175,16 +176,14 @@ export default {
         ExcelClassifyId: classify,
         ExcelImage:'',
         Source: 3,
-        TableData: {
-          CellRelation: JSON.stringify(this.$refs.mixedTableRef.insertRelationArr),
-          Data: this.$refs.mixedTableRef.config.data
-        }
+        TableData: this.$refs.mixedTableRef.getSaveParams()
       };
       console.log("自动保存");
       const res = await sheetInterface.sheetEdit({ ExcelInfoId: Number(this.sheetId),...params })
       if(res.Ret !==200) return
       this.updateTime = this.$moment().format('YYYY-MM-DD HH:mm:ss')
     },1500),
+
     /* 保存表格 */
     saveSheetHandle: _.debounce(async function() {
 
@@ -213,10 +212,7 @@ export default {
         ExcelClassifyId: classify,
         ExcelImage: Data.ResourceUrl,
         Source: 3,
-        TableData: {
-          CellRelation: JSON.stringify(this.$refs.mixedTableRef.insertRelationArr),
-          Data: this.$refs.mixedTableRef.config.data
-        }
+        TableData: this.$refs.mixedTableRef.getSaveParams()
       };
       let isAdd = this.sheetId?false:true
       const res = this.sheetId
@@ -230,6 +226,7 @@ export default {
       this.$message.success('保存成功')
       isAdd && this.$router.replace({path:'/addMixedSheet',query:{id:this.sheetId}})
     },300),
+
     markFinishStatus(){
       if((!this.sheetId) || (!this.isCanEdit)) return
       sheetInterface.markSheetEditStatus({ExcelInfoId: +this.sheetId,Status:2}).then(res=>{

+ 1 - 0
src/views/datasheet_manage/sheetList.vue

@@ -1101,6 +1101,7 @@ $normal-font: 14px;
           position: relative;
           height: calc(100vh - 210px);
           padding: 15px;
+          overflow-y: auto;
           /* min-height: 500px; */
         }
       }