소스 검색

合master 处理冲突

cxmo 9 달 전
부모
커밋
4aaa3aa00f
61개의 변경된 파일7039개의 추가작업 그리고 617개의 파일을 삭제
  1. 4 2
      src/api/api.js
  2. 19 0
      src/api/modules/chartApi.js
  3. 153 11
      src/api/modules/chartRelevanceApi.js
  4. 65 2
      src/api/modules/dataApi.js
  5. 20 1
      src/api/modules/thirdBaseApi.js
  6. BIN
      src/assets/img/icons/edb-stopping.png
  7. BIN
      src/assets/img/icons/formula-add.png
  8. 10 1
      src/components/antvVueComponents/tooltipCom.vue
  9. 36 12
      src/components/lzTable.vue
  10. 8 0
      src/lang/commonLang.js
  11. 16 0
      src/lang/modules/ETATables/commonLang.js
  12. 13 1
      src/lang/modules/EtaBase/commonLang.js
  13. 4 2
      src/lang/modules/Slides/pptPresent.js
  14. 73 2
      src/lang/modules/StatisticAnalysis/ChartRelevance.js
  15. 59 0
      src/lang/modules/systemManage/DataRefresh.js
  16. 11 0
      src/routes/modules/chartRoutes.js
  17. 8 0
      src/routes/modules/dataRoutes.js
  18. 3 0
      src/utils/buttonConfig.js
  19. 54 14
      src/views/chartRelevance_manage/components/chartCard.vue
  20. 10 2
      src/views/chartRelevance_manage/components/explainText.js
  21. 111 0
      src/views/chartRelevance_manage/components/saveChartSetting.vue
  22. 44 8
      src/views/chartRelevance_manage/components/saveChartTobaseDia.vue
  23. 2 2
      src/views/chartRelevance_manage/components/saveEdbToBaseDia.vue
  24. 5 0
      src/views/chartRelevance_manage/components/selectTarget.vue
  25. 4 1
      src/views/chartRelevance_manage/css/index.scss
  26. 10 2
      src/views/chartRelevance_manage/mixins/classifyMixin.js
  27. 210 0
      src/views/chartRelevance_manage/relevance/components/batchSelectFormula.vue
  28. 257 0
      src/views/chartRelevance_manage/relevance/components/batchSelectTable.vue
  29. 38 0
      src/views/chartRelevance_manage/relevance/components/formMixin.js
  30. 137 0
      src/views/chartRelevance_manage/relevance/components/modifyClassifyDialog.vue
  31. 616 0
      src/views/chartRelevance_manage/relevance/components/multipleIndForm.vue
  32. 268 0
      src/views/chartRelevance_manage/relevance/components/singleIndForm.vue
  33. 294 23
      src/views/chartRelevance_manage/relevance/list.vue
  34. 1089 0
      src/views/chartRelevance_manage/relevance/relevanceChartEditorV2.vue
  35. 111 0
      src/views/chartRelevance_manage/relevance/utils/config.js
  36. 70 0
      src/views/chartRelevance_manage/relevance/utils/index.js
  37. 17 4
      src/views/dataEntry_manage/components/SaveChartOther.vue
  38. 1 3
      src/views/dataEntry_manage/components/barOptionSection.vue
  39. 14 0
      src/views/dataEntry_manage/databaseComponents/chartTrendRender.vue
  40. 55 1
      src/views/dataEntry_manage/databaseList.vue
  41. 17 9
      src/views/dataEntry_manage/mixins/addOreditMixin.js
  42. 47 35
      src/views/dataEntry_manage/mixins/chartPublic.js
  43. 387 0
      src/views/dataEntry_manage/thirdBase/Wind.vue
  44. 2 2
      src/views/dataEntry_manage/thirdBase/selfDataBase.vue
  45. 7 5
      src/views/dataEntry_manage/thirdBase/steelChemicalbase.vue
  46. 70 32
      src/views/datasheet_manage/common/customTable.js
  47. 742 85
      src/views/datasheet_manage/components/BalanceTable.vue
  48. 43 39
      src/views/datasheet_manage/components/CustomTable.vue
  49. 651 97
      src/views/datasheet_manage/components/MixedTable.vue
  50. 116 40
      src/views/datasheet_manage/components/toolBarSection.vue
  51. 12 15
      src/views/edbHistoryPage.vue
  52. 16 4
      src/views/mychart_manage/components/chartDetailDia.vue
  53. 47 34
      src/views/ppt_manage/mixins/mixins.js
  54. 12 1
      src/views/ppt_manage/mixins/pptEditorMixins.js
  55. 15 11
      src/views/ppt_manage/mixins/pptMixins.js
  56. 2 1
      src/views/ppt_manage/newVersion/pptEditor.vue
  57. 2 1
      src/views/ppt_manage/newVersion/pptEnEditor.vue
  58. 2 1
      src/views/ppt_manage/newVersion/utils/untils.js
  59. 146 0
      src/views/system_manage/components/defaultRefreshStatusDia.vue
  60. 74 0
      src/views/system_manage/components/referenceCountDia.vue
  61. 710 111
      src/views/system_manage/dataRefreshSetting.vue

+ 4 - 2
src/api/api.js

@@ -18,7 +18,8 @@ import {
   zczxInterface,
   coalWordInterface,
   bloombergInterface,
-  ccfDataInterface
+  ccfDataInterface,
+  windInterface
 } from './modules/thirdBaseApi';
 
 //手工指标 手工数据 手工数据权限
@@ -128,7 +129,8 @@ export {
   zczxInterface,
   coalWordInterface,
   bloombergInterface,
-  ccfDataInterface
+  ccfDataInterface,
+  windInterface
 };
 
 //老接口 研报 ppt等

+ 19 - 0
src/api/modules/chartApi.js

@@ -307,6 +307,15 @@ const dataBaseInterface = {
 	/* 刷新校验 */
 	updateCheck: params => {
 		return http.post('/datamanage/edb_info/updates/check',params)
+	},
+		/**
+	 * 设置指标刷新状态
+	 * @param {EdbInfoId} params 
+	 * @param {ModifyStatus} params 需要更改的状态:启用、暂停
+	 * @returns 
+	 */
+	edbRefreshStatusSet: params => {
+		return http.post('/datamanage/edb_info/single_refresh/status/save',params)
 	},
 	/**
 	 * 指标替换
@@ -411,10 +420,20 @@ const dataBaseInterface = {
 		return http.post('/datamanage/edb_info/batch/add',params)
 	},
 	// 批量计算指标时获取当前筛选条件下选择的指标
+	/**
+	 * @param {Object} params
+	 * @param {Number} params.EdbInfoType 0-指标;1-预测指标
+	 * @returns 
+	 */
 	getBatchFilterAddEdbList:params=>{
 		return http.get('/datamanage/edb_info/calculate/multi/choice',params)
 	},
 	//批量计算指标时待选指标的搜索列表
+	/**
+	 * @param {Object} params
+	 * @param {Number} params.EdbInfoType 0-指标;1-预测指标
+	 * @returns 
+	 */
 	getBatchAddEdbSearchList:params=>{
 		return http.get('/datamanage/edb_info/calculate/multi/search',params)
 	},

+ 153 - 11
src/api/modules/chartRelevanceApi.js

@@ -3,11 +3,22 @@ import http from "@/api/http.js"
 export default{
     /**
    * 获取分类
+   * IsShowMe 是否仅展示我的:true-是
+   * ParentId 父级ID,一级分类不传或者0即可
+   * Source 来源:3-相关性(不传默认也为这个);4-滚动相关性
    * @returns 
    */
   classifyList:  params =>{
     return http.get('/correlation/chart_classify/list',params)
   },
+  /**
+   * 分类树
+   * @param {*} params 
+   * @returns 
+   */
+  classifyTree:params=>{
+    return http.get('/correlation/chart_classify/tree',params)
+  },
 
   /**
    * 新增分类
@@ -46,8 +57,14 @@ export default{
   },
 
   /**
-   * 移动分类
-   * @param {*} params ClassifyId "PrevClassifyId":1, "NextClassifyId":2,
+   * 移动分类or图表
+   * @param {*} params "ClassifyId": 228, //分类ID
+    "ParentClassifyId": 0, //父级分类ID
+    "PrevClassifyId": 0, //上一个兄弟节点分类ID
+    "NextClassifyId": 227, //下一个兄弟节点分类ID
+    "ChartInfoId": 0, //图表ID,如果图表ID>0则移动对象为图表,否则默认为移动分类
+    "PrevChartInfoId": 0, //上一个兄弟节点图表ID
+    "NextChartInfoId": 0 //下一个兄弟节点图表ID
    * @returns 
    */
   classifyMove: params => {
@@ -253,15 +270,140 @@ export default{
     return http.post('/datamanage/multiple_graph/preview_cure',params)
   },
 
-  /**
-	 * 设置图表对应版本信息
-	 * @param {*} params 
-	 * ChartInfoId ChartName
-	 * @returns 
-	 */
-	setChartLangInfo: params => {
-		return http.post('/correlation/chart_info/base/edit',params)
-	},
+    /**
+     * 设置图表对应版本信息
+     * @param {*} params 
+     * ChartInfoId ChartName
+     * @returns 
+     */
+    setChartLangInfo: params => {
+        return http.post('/correlation/chart_info/base/edit',params)
+    },
+
+    /* 相关性功能拓展 */
+
+    /**
+     * 获取计算方式列表
+     * @param {Object} params 
+     * @param {Number} params.EdbInfoType  指标类型:0-普通指标;1-预测指标
+     * @returns 
+     */
+    getCalculateFormula:params => {
+        return http.get('/datamanage/factor_edb_series/calculate_func/list',params)
+    },
+    /**
+     * 添加多因子系列
+     * @param {Object} params 
+     * @param {String} params.SeriesName 系列名称
+     * @param {Number} params.EdbInfoType 指标类型:0-普通指标; 1-预测指标
+     * @param {Object[]} params.Calculates 选择的计算公式
+     * @param {String} params.Calculates[].Formula N值/移动天数/指数修匀alpha值/计算公式等
+     * @param {String} params.Calculates[].Calendar 公历/农历
+     * @param {String} params.Calculates[].Frequency 需要转换的频度
+     * @param {String} params.Calculates[].MoveType 移动方式:1-领先(默认);2-滞后
+     * @param {String} params.Calculates[].MoveFrequency 移动频度
+     * @param {String} params.Calculates[].FromFrequency 来源的频度
+     * @param {Number} params.Calculates[].Source 计算方式来源
+     * @param {Number} params.Calculates[].Sort 计算顺序
+     * @param {Number[]} params.EdbInfoIds 需要计算的指标
+     * @returns 
+     */
+    addFactorSeries:params=>{
+        return http.post('/datamanage/factor_edb_series/add',params)
+    },
+    /**
+     * 编辑多因子系列
+     * @param {Object} params 
+     * @param {String} params.SeriesId //因子系列ID
+     * //其他同添加
+     * @returns 
+     */
+    editFactorSeries:params=>{
+        return http.post('/datamanage/factor_edb_series/edit',params)
+    },
+    /**
+     * 获取多因子系列详情
+     * @param {Object} params
+     * @param {Number} params.SeriesId 因子指标系列ID
+     * @returns 
+     */
+    getFactorSeriesDetail:params=>{
+        return http.get('/datamanage/factor_edb_series/detail',params)
+    },
+    /**
+     * 获取相关性矩阵
+     * @param {Object} params
+     * @param {Number} params.BaseEdbInfoId 标的指标ID
+     * @param {Object} params.Correlation
+     * @param {Number} params.Correlation.CalculateValue 计算窗口
+     * @param {String} params.Correlation.CalculateUnit 计算窗口频度
+     * @param {Number} params.Correlation.LeadValue 分析周期
+     * @param {String} params.Correlation.LeadUnit 分析周期频度
+     * @param {Number[]} params.SeriesIds 因子系列Id
+     * @returns 
+     */
+    getCorrelationMatrix:params=>{
+        return http.post('datamanage/factor_edb_series/correlation/matrix',params)
+    },
+    /**
+     * 新增多因子相关性图表
+     * @param {Object} params 
+     * @param {String} params.ChartName
+     * @param {Number} params.ClassifyId
+     * @param {Number} params.AnalysisMode 分析模式:0-单因子;1-多因子
+     * @param {Number} params.BaseEdbInfoId 标的指标ID
+     * @param {Object} params.FactorCorrelation
+     * @param {Number} params.FactorCorrelation.CalculateValue 领先期数
+     * @param {String} params.FactorCorrelation.CalculateUnit 频度
+     * @param {Number} params.FactorCorrelation.LeadValue 计算窗口
+     * @param {String} params.FactorCorrelation.LeadUnit 计算频度
+     * @param {Object[]} params.FactorCorrelation.SeriesEdb 关联系列指标
+     * @param {Number} params.FactorCorrelation.SeriesEdb[].SeriesId
+     * @param {Number} params.FactorCorrelation.SeriesEdb[].EdbInfoId
+     * @param {Object} params.ExtraConfig
+     * @param {Object[]} params.ExtraConfig.LegendConfig 
+     * @param {String} params.ExtraConfig.LegendConfig.LegendName
+     * @param {Number} params.ExtraConfig.LegendConfig.SeriesId
+     * @param {Number} params.ExtraConfig.LegendConfig.EdbInfoId 
+     * @param {String} params.ExtraConfig.LegendConfig.Color 
+     * @param {Object} params.SourcesFrom
+     * @param {Boolean} params.SourcesFrom.isShow
+     * @param {String} params.SourcesFrom.text
+     * @param {String} params.SourcesFrom.color
+     * @param {Number} params.SourcesFrom.fontSize
+     * @returns 
+     */
+    addMultipleFactor:params=>{
+        return http.post('/correlation/chart_info/multi_factor/add',params)
+    },
+    /**
+     * 更新多因子相关性图表
+     * @param {*} params 
+     * @param {Number} params.ChartInfoId
+     * 其他同新增
+     * @returns 
+     */
+    editMultipleFactor:params=>{
+        return http.post('/correlation/chart_info/multi_factor/edit',params)
+    },
+    /**
+     * 多因子图表详情
+     * @param {Object} params 
+     * @param {String} params.UniqueCode
+     * @returns 
+     */
+    getMultipleChartDetail:params=>{
+        return http.get('/datamanage/chart_info/common/detail/from_unique_code',params)
+    },
+    /**
+     * 多因子表单及矩阵详情
+     * @param {*} params
+     * @param {Number} params.UniqueCode 
+     * @returns 
+     */
+    getMultipleFactorDetail:params=>{
+        return http.get('/correlation/chart_info/multi_factor/detail',params)
+    }
 
 }
 

+ 65 - 2
src/api/modules/dataApi.js

@@ -515,8 +515,71 @@ const dataRefreshInterface = {
     getSimgleEdbRefreshTime(params){
         return http.get("/datamanage/edb_info/refresh/edb_config",params)
     },
-
-
+// -------------------刷新状态设置
+	/**
+	 * 获取引用指标数据
+	 * @param {Object} params 
+	 * @param {Number} params.Source
+	 * @param {String} params.ClassifyId 多选
+	 * @param {String} params.SysUserId 多选
+	 * @param {String} params.Frequency
+	 * @param {String} params.Keyword
+	 * @param {String} params.Status
+	 * @param {String} params.SortParam 枚举值:'RelationTime':引用日期 'RelationNum' 引用次数
+	 * @param {String} params.SortType
+	 * @param {String} params.CurrentIndex
+	 * @param {String} params.PageSize
+	 * @returns 
+	 */
+	getRelationEdbDataList:params=>{
+		return http.get("/datamanage/edb_info/relation/edb_list",params)
+	},
+	/**
+	 * 获取指标的引用详情
+	 * @param {Object} params 
+	 * @param {Number} params.EdbInfoId
+	 * @returns 
+	 */
+	getRelationEdbDetail:params=>{
+		return http.get("/datamanage/edb_info/relation/detail",params)
+	},
+	/**
+	 * 获取默认刷新规则
+	 * @param {Object} params 
+	 * @param {Number} params.ConfKey EdbStopRefreshRule
+	 * @returns 
+	*/
+	getEdbStopRefreshRule:params=>{
+		return http.get("/business_conf/single",params)
+	},
+		/**
+	 * 设置默认刷新规则
+	 * @param {Object} params 
+	 * @param {Number} params.ConfKey EdbStopRefreshRule
+	 * @param {Number} params.ConfVal "{\"IsOpen\":1,\"BaseIndexStopDays\":90,\"EdbStopDays\":300}"
+	 * @returns 
+	*/
+	setEdbStopRefreshRule:params=>{
+		return http.post("/business_conf/single/save",params)
+	},
+	/**
+	 * 批量设置被引用的指标刷新的状态
+	 * @param {Object} params 
+	 * @param {Number} params.Source
+	 * @param {String} params.ClassifyId 多选
+	 * @param {String} params.SysUserId 多选
+	 * @param {String} params.Frequency
+	 * @param {String} params.Keyword
+	 * @param {String} params.Status
+	 * @param {String} params.IsSelectAll 是否全选
+	 * @param {String} params.EdbSelectIdList 如果不是全选,则表示选中的指标,如果全选则表示需要排除的指标
+	 * @param {String} params.ModifyStatus 枚举值:状态,枚举值:启用、暂停
+	 * @returns 
+	*/
+	setRelationEdbsRefreshStatus:params=>{
+		return http.post("/datamanage/edb_info/relation/refresh/save",params)
+	},
+	
 }
 
 export {

+ 20 - 1
src/api/modules/thirdBaseApi.js

@@ -1065,6 +1065,24 @@ const ccfDataInterface={
 		return http.get('/datamanage/ccf/search_list',params);
 	}
 }
+/* 数据源-Wind */
+const windInterface={
+	/**
+	 * 分类列表
+	 * params: ParentId
+	 */
+	classifyList:params=>{
+			return http.get('/datamanage/wind/classify',params)
+	},
+	/**
+	 * 数据列表
+	 * params:  EdbInfoId,ClassifyId
+	 */
+	dataList:params=>{
+			return http.get('/datamanage/wind/index',params)
+	}
+}
+
 export { 
 	lzDataInterface,
 	glDataInterface,
@@ -1083,5 +1101,6 @@ export {
 	zczxInterface,
 	coalWordInterface,
 	bloombergInterface,
-	ccfDataInterface
+	ccfDataInterface,
+	windInterface
 }

BIN
src/assets/img/icons/edb-stopping.png


BIN
src/assets/img/icons/formula-add.png


+ 10 - 1
src/components/antvVueComponents/tooltipCom.vue

@@ -7,6 +7,7 @@
     </el-tooltip>
     <i :class="data.fold?'el-icon-circle-plus':'el-icon-remove'" v-if="!data.isLeaf"
     class="fold-icon" @click="flodApi" v-show="show"></i>
+    <img src="~@/assets/img/icons/edb-stopping.png" class="stop-mark" v-if="data.isStop==1" />
   </div>
 </template>
 
@@ -50,7 +51,7 @@ export default {
       this.graph= this.getGraph()
       this.node.data = this.node.data?{...this.data,...this.node.data}:this.data
       this.data = this.node.data
-      
+
       let {style} = this.data
       this.initStyle(style)
 
@@ -150,5 +151,13 @@ export default {
     left: 50%;
     transform: translateX(-50%);
   }
+  .stop-mark{
+    height: 48px;
+    width: 48px;
+    position: absolute;
+    right: -1px;
+    top: 0;
+    pointer-events: none;
+  }
 }
 </style>

+ 36 - 12
src/components/lzTable.vue

@@ -8,18 +8,24 @@
 				class="header"
 			>
 				<th>{{ labelArr.get(item) }}</th>
-				<td v-for="(data, sub_index) in tableOption" :key="sub_index">
+				<td v-for="(data, sub_index) in tableOption" :key="sub_index"  
+					:style="{color:item=='IsStop' && data.IsStop?'#F56C6C':'#333333'}">
 					<template v-if="source!=='baiinfo'">
-						{{
-							(['FrequencyName','Frequency'].includes(item)) 
-							? (source === 'lz')
-								? frequencyType.get(data[item])
-								: frequencyMap.get(data[item])
-							: data[item] 
-						}}
-						<span v-if="item==='Opt'&&$route.path==='/steelChemical'&&data['IndexCode'] ">
-							<el-button type="text" @click.stop="$emit('addToLib',data)">{{$t('ManualEdbListPage.add_tobase_btn')}}</el-button>
-						</span>
+						<template v-if="item=='IsStop'">
+							{{ refreshStatusMap.get(data[item]) }}
+						</template>
+						<template v-else>
+							{{
+								(['FrequencyName','Frequency'].includes(item)) 
+								? (source === 'lz')
+									? frequencyType.get(data[item])
+									: frequencyMap.get(data[item])
+								: data[item] 
+							}}
+							<span v-if="item==='Opt'&&$route.path==='/steelChemical'&&data['IndexCode'] ">
+								<el-button type="text" @click.stop="$emit('addToLib',data)">{{$t('ManualEdbListPage.add_tobase_btn')}}</el-button>
+							</span>
+						</template>
 					</template>
 					<!-- 百川盈孚数据源 频度和单位需要可编辑 -->
 					<template v-else>
@@ -82,6 +88,8 @@ export default {
 
 			if(this.source==='gl'){
 				arr=['IndexName','IndexCode','FrequencyName','UnitName','UpdateTime']
+			}else if(this.source === 'glhg'){
+				arr=['IndexName','IndexCode','FrequencyName','UnitName','UpdateTime','IsStop']
 				if(this.$route.path==='/steelChemical'){
 					arr.push('Opt')
 				}
@@ -102,13 +110,22 @@ export default {
 			let sourceTypeOne = ['smm','coal','baiinfo','yyzx','icpi','coalWord','ccf']
 
 			if(this.source==='gl'){
+				temMap=new Map([
+					['IndexName', this.$t('Edb.Detail.e_name')],
+					['IndexCode', this.$t('Edb.Detail.e_id')],
+					['FrequencyName', this.$t('Edb.Detail.e_fre')],
+					['UnitName', this.$t('Edb.Detail.e_unit')],
+					['UpdateTime', this.$t('Edb.Detail.e_update_time')]
+				])
+			}else if(this.source === 'glhg'){
 				temMap=new Map([
 					['IndexName', this.$t('Edb.Detail.e_name')],
 					['IndexCode', this.$t('Edb.Detail.e_id')],
 					['FrequencyName', this.$t('Edb.Detail.e_fre')],
 					['UnitName', this.$t('Edb.Detail.e_unit')],
 					['UpdateTime', this.$t('Edb.Detail.e_update_time')],
-					['Opt','操作']
+					['IsStop',this.$t('Edb.Detail.e_status')],
+					['Opt',this.$t('Table.column_operations')],
 				])
 			}else if(sourceTypeOne.includes(this.source)){
 				temMap=new Map([
@@ -154,6 +171,13 @@ export default {
 				['半年度',this.$t('Edb.FreAll.half_year')],
 				['年度',this.$t('Edb.FreAll.year')]
 			])
+		},
+		//刷新状态
+		refreshStatusMap(){
+			return new Map([
+				[0,this.$t('SystemManage.DataRefresh.enabled')],
+				[1,this.$t('SystemManage.DataRefresh.disabled')]
+			])
 		}
 	},
 	data() {

+ 8 - 0
src/lang/commonLang.js

@@ -13,6 +13,10 @@ export default {
       en: "Confirm",
       zh: "确定",
     },
+    calculate_btn:{
+        en:'Calculate',
+        zh:'计算'
+    },
     confirm_save_btn: {
       en: "Save",
       zh: "保存 ",
@@ -312,6 +316,10 @@ export default {
       en: 'No data available for this date.',
       zh: '该日期暂无数据'
     },
+    request_frequency:{
+      zh:'请求频繁,请数据加载完成后再试!',
+      en:'Request frequency, please try again after the data is loaded!'
+    }
   },
   Common: {
     category: {

+ 16 - 0
src/lang/modules/ETATables/commonLang.js

@@ -52,6 +52,18 @@ export default {
       en: "Renewing",
       zh: "更新中...",
     },
+    merge_cell:{
+      en: "Merge Cells",
+      zh: "合并单元格",
+    },
+    unmerge_cell:{
+      en: "Unmerge Cells",
+      zh: "取消合并单元格",
+    },
+    unmerge:{
+      en: "Unmerge",
+      zh: "取消合并",
+    }
   },
   Msg: {
     is_del_table_msg: {
@@ -86,6 +98,10 @@ export default {
       en:'After deletion, this chart will no longer be referenced. Are you sure to delete it?',
       zh:'删除后该图表将不能再引用,确认删除吗?',
     },
+    merge_cell_fail_msg:{
+      en:'Select cells to merge, ensuring that at most one value or relationship exists within the selected cells.',
+      zh:'选择合并的单元格中最多存在一个值或关联关系',
+    },
   },
   Date: {
     monday: {

+ 13 - 1
src/lang/modules/EtaBase/commonLang.js

@@ -48,6 +48,10 @@ export default {
     zh:'查看数据',
     en:'View indicators'
   },
+  detail_lookdata2_btn: {
+    zh:'查看详情',
+    en:'View indicators'
+  },
   detail_formula_btn: {
     zh:'查看公式',
     en:'Formula'
@@ -192,6 +196,10 @@ export default {
       zh:'指标目录',
       en:'Data Catalogue'
     },
+    e_catalogue: {
+      zh:'目录',
+      en:'Catalogue'
+    },
     e_start_time: {
       zh:'起始时间',
       en:'Start Time'
@@ -206,7 +214,7 @@ export default {
     },
     e_status: {
       zh:'刷新状态',
-      en:'Update Status'
+      en:'Refresh Status'
     },
     e_latest_date: {
       zh:'最新日期',
@@ -216,6 +224,10 @@ export default {
       zh:'起始日期',
       en:'Start Date'
     },
+    e_creator: {
+      zh:'创建人',
+      en:'Creator'
+    },
     e_latest_value: {
       zh:'最新值',
       en:'Latest Value'

+ 4 - 2
src/lang/modules/Slides/pptPresent.js

@@ -103,7 +103,8 @@ export const presentEn = {
   apply_to_the_entire:'Apply to the entire PPT',
   title_style_fontfamily:"Font Family",
   title_style_fontsize:'Font Size',
-  title_style_color:'Font Color'
+  title_style_color:'Font Color',
+  title_paste_hint:'The clipboard is empty, please paste the text',
 };
 
 /* 中文 */
@@ -207,7 +208,8 @@ export const presentZh = {
   apply_to_the_entire:'应用至整个PPT',
   title_style_fontfamily:"字体设置",
   title_style_fontsize:'字号设置',
-  title_style_color:'字体颜色'
+  title_style_color:'字体颜色',
+  title_paste_hint:'粘贴板获取为空,请粘贴文本',
 };
 
 /**

+ 73 - 2
src/lang/modules/StatisticAnalysis/ChartRelevance.js

@@ -34,7 +34,31 @@ export const ChartRelevanceEn = {
     update_edb:'update',
     update_success:'Update success',
     chart_save_as:'Save Chart As',
-    check_value_hint:'Correlation calculation window must be ≥2* analysis period'
+    check_value_hint:'Correlation calculation window must be ≥2* analysis period',
+
+    analytical_model:'Mode',
+    single_indicator:'Single Indicator',
+    multiple_indicators:'Multiple Indicators',
+    target_indicator:'Target Indicator',
+    factor_indicators:'Factor Indicators',
+    add_factor_indicators:'Add factor indicators',
+
+    multiple_table_head_01:'Correlation matrix with the Target Indicator',
+    multiple_table_head_02:'Original Indicator name',
+    multiple_table_head_03:'Number of leading periods({unit})', //$t('xxx',{unit:''})
+    multiple_table_btn_add:'Add Curve',
+    multiple_table_btn_del:'Del Curve',
+    chart_curve_add_hint:'Only 10 curves are supported',
+    infoform_rules_hint_01:'IndexA not selected',
+    infoform_rules_hint_02:'IndexB not selected',
+    infoform_rules_hint_03:'Target Index not selected',
+    infoform_rules_hint_04:'Calculation Window not filled in',
+    infoform_rules_hint_05:'Analysis Period not filled in',
+    formula_add_btn:'Add Formula',
+    series_name:'Index Series Name',
+    series_name_placeholder:'Input Index Series Name',
+    formulaform_add_hint:'Only 5 formulas are supported',
+    batch_select_hint:'Please Select Index',
 };
   
 /* 中文 */
@@ -70,7 +94,54 @@ export const ChartRelevanceZh = {
     update_success:'更新成功',
     chart_save_as:'图表另存为',
 
-    check_value_hint:'相关性计算窗口必须≥2*分析周期'
+    check_value_hint:'相关性计算窗口必须≥2*分析周期',
+
+    analytical_model:'分析模式',
+    single_indicator:'单因子',
+    multiple_indicators:'多因子',
+    target_indicator:'标的指标',
+    factor_indicators:'因子指标系列',
+    add_factor_indicators:'添加因子指标系列',
+    /**
+     * Chart.ChartType
+     * 曲线图:spline_name
+     * 相关性:correlation_name
+     * 滚动相关性:rolling_correlation_name
+     * Chart
+     * 请选择时间段:choose_time
+     * 
+     * 操作 Edb.Detail.e_opera
+     * 数据来源 Edb.Detail.source
+     * 暂无信息 Common.no_info_msg
+     * 加入已选指标 EtaBasePage.add_to_selections
+     * N不能为空 Edb.Valids.n_msg
+     * alpha值不能为空 Edb.Valids.alpha_msg
+     */
+    multiple_table_head_01:'与标的指标的相关性矩阵',
+    multiple_table_head_02:'原始指标名称',
+    multiple_table_head_03:'领先期数({unit})', //$t('xxx',{unit:''})
+    multiple_table_btn_add:'添加曲线',
+    multiple_table_btn_del:'删除曲线',
+    chart_curve_add_hint:'最多只支持添加10条曲线',
+    infoform_rules_hint_01:'指标A未选择',
+    infoform_rules_hint_02:'指标B未选择',
+    infoform_rules_hint_03:'标的指标未选择',
+    infoform_rules_hint_04:'计算窗口未填写',
+    infoform_rules_hint_05:'分析周期未填写',
+    formula_add_btn:'添加计算公式',
+    series_name:'指标系列名称',
+    series_name_placeholder:'请输入指标系列名称',
+    formulaform_add_hint:'最多仅能添加5个计算公式',
+    batch_select_hint:'请选择需要添加的指标',
+
+
+
+
+
+
+
+
+
 };
   
 /**

+ 59 - 0
src/lang/modules/systemManage/DataRefresh.js

@@ -25,9 +25,11 @@ export const DataRefreshZh = {
 
   terminal_code_select: "终端编码",
   eta_class_select: "ETA指标库分类",
+  edb_classify: "指标库分类",
   enable_op: "启用刷新",
   pause_op: "暂停刷新",
   all_list: "列表全选",
+  selected:"已选",
   set_time: "设置刷新时间",
   please_select: "请选择",
   set_status: "设置刷新状态",
@@ -43,6 +45,17 @@ export const DataRefreshZh = {
   table_creator: "创建人",
   table_status: "刷新状态",
 
+  table_Id:"指标ID",
+  table_recent_reference_time:"最近引用时间",
+  table_reference_count:"引用次数",
+  table_refresh_status:"刷新状态",
+  enabled:"启用",
+  disabled:"停用",
+
+  reference_time:"引用时间",
+  reference_source:"引用来源",
+  reference_chart_table:"引用图表/表格",
+
   refresh_rate: "刷新频率",
   trading_day: "每交易日",
   daily_date: "每自然日",
@@ -56,6 +69,23 @@ export const DataRefreshZh = {
   last_day: "最后一天",
   select_refresh_rate: "请选择刷新频率",
   select_refresh_time: "请选择刷新时间",
+
+  time_setting_tab:"刷新时间设置",
+  status_setting_tab:"刷新状态设置",
+  enable:"启用",
+  disable:"停用",
+
+  default_refresh_rule:"默认刷新规则",
+  set_default_refresh_rule:"设置默认刷新规则",
+  disableRulePrompt:"关闭配置后,指标将不会自动处理为停用",
+  enable_configuration:"启用配置",
+  baseIndexStopDays_hint_front:"数据源间隔",
+  baseIndexStopDays_hint_behind:"天未加入指标库则停用",
+  edbStopDays_hint_front:"指标库间隔",
+  edbStopDays_hint_behind:"天未引用则停用",
+  IntervalDaysError:"请输入正确的格式",
+  disable_indicator_prompt:"停用后该数据将停止刷新,是否继续操作?",
+  status_rule_prompt:"只针对wind和钢联化工指标生效"
 };
 
 /* 英文 */
@@ -77,9 +107,11 @@ export const DataRefreshEn = {
 
   terminal_code_select: "Terminal Code",
   eta_class_select: "ETA Indicator Library Classification",
+  edb_classify: "Indicator Library Classification",
   enable_op: "Enable Refresh",
   pause_op: "Pause Refresh",
   all_list: "Select All in List",
+  selected: "Selected",
   set_time: "Set Refresh Time",
   please_select: "Please Select",
   set_status: "Set Refresh Status",
@@ -95,6 +127,16 @@ export const DataRefreshEn = {
   table_creator: "Creator",
   table_status: "Refresh Status",
 
+  table_Id:"Indicator ID",
+  table_recent_reference_time:"Recent Reference Time",
+  table_reference_count:"Reference Count",
+  table_refresh_status:"Refresh Status",
+  enabled:"Enabled",
+  disabled:"Disabled",
+  
+  reference_time:"Reference Time",
+  reference_source:"Reference Source",
+  reference_chart_table:"Refer to the chart/table",
 
   refresh_rate: "Refresh Rate",
   trading_day: "Every Trading Day",
@@ -109,4 +151,21 @@ export const DataRefreshEn = {
   last_day: "Last Day",
   select_refresh_rate: "Please select a refresh rate",
   select_refresh_time: "Please select a refresh time",
+
+  time_setting_tab:"Refresh Time Setting",
+  status_setting_tab:"Refresh Status Setting",
+  enable:"Enable",
+  disable:"Disable",
+
+  default_refresh_rule:"Default Refresh Rules",
+  set_default_refresh_rule:"Set Default Refresh Rules",
+  enable_configuration:"Enable configuration",
+  baseIndexStopDays_hint_front:"If a data source has not been added to the metric repository for",
+  baseIndexStopDays_hint_behind:"days, it will be deactivated.",
+  edbStopDays_hint_front:"If the metric repository has not been referenced for",
+  edbStopDays_hint_behind:"days, it will be deactivated.",
+  disableRulePrompt:"After closing the configuration, metrics will not be automatically processed as disabled",
+  IntervalDaysError:"Please enter the correct format",
+  disable_indicator_prompt:"After disabling, the data will stop refreshing. Do you want to continue?",
+  status_rule_prompt:"Only effective for Wind and Ganglian Chemical indicators."
 };

+ 11 - 0
src/routes/modules/chartRoutes.js

@@ -381,6 +381,17 @@ export default [
 					pathName_en:"Correlation analysis"
 				}
 			},
+			{
+				path: 'relevancechartEditorV2',
+				name: '编辑图表',
+				component:()=>import('@/views/chartRelevance_manage/relevance/relevanceChartEditorV2.vue'),
+				meta: {
+					name_en:"edit Correlation analysis",
+					pathFrom: "chartrelevance",
+					pathName: "相关性图表",
+					pathName_en:"Correlation analysis"
+				}
+			},
 			{
 				path: 'statisticFeatureList',
 				name: '统计特征',

+ 8 - 0
src/routes/modules/dataRoutes.js

@@ -340,6 +340,14 @@ export default [
           name_en:'CCF Fiber Info'
         },
       },
+      {
+        path: "windbase",
+        component: () => import("@/views/dataEntry_manage/thirdBase/Wind.vue"),
+        name: "Wind",
+        meta:{
+          name_en:'Wind'
+        },
+      },
     ],
   },
 ];

+ 3 - 0
src/utils/buttonConfig.js

@@ -271,6 +271,7 @@ export const dataSourcePermission = {
     Bloomberg_add2edb:'Bloomberg:add2edb',//添加指标库
     /* 自有数据 */
     selfData_addEdb:'selfData:addEdb',//添加到指标库
+    selfData_detail:'selfData:detail',//查看详情
     /*--------卓创资讯---- */
     zczx_showData:'zczx:showData',
     zczx_exportData:'zczx:exportData',
@@ -312,6 +313,7 @@ export const edbDataPermission = {
     edbData_checkRelatedChart:'edbData:checkRelatedChart',//查看关联图表
     edbData_checkRelatedEdb:'edbData:checkRelatedEdb',//查看关联指标
     edbData_checkCalcChart:'edbData:checkCalcChart',//查看计算指标
+    edbData_enableOrDisable:'edbData:enableOrDisable',//启用/停用
 }
 /*
  * ---------------------------------------------------------------------------ETA预测指标------------------------------------------------
@@ -547,6 +549,7 @@ export const statisticPermission = {
     corrAnalysis_onlyMine:'corrAnalysis:onlyMine',//只看我的
     corrAnalysis_classifyOpt_edit:'corrAnalysis:classifyOpt:edit',//添加/编辑分类
     corrAnalysis_classifyOpt_delete:'corrAnalysis:classifyOpt:delete',//删除分类
+    corrAnalysis_classifyOpt_move:'corrAnalysis:classifyOpt:move',//移动分类
         /*---图表操作栏--- */
     corrAnalysis_del:'corrAnalysis:del',
     corrAnalysis_enNameSetting:'corrAnalysis:enNameSetting',

+ 54 - 14
src/views/chartRelevance_manage/components/chartCard.vue

@@ -18,6 +18,7 @@
               <el-dropdown-item :command="{entryType,scence:'saveOther'}">{{$t('StatisticAnalysis.ChartRelevance.save_other')}}</el-dropdown-item>
             </el-dropdown-menu>
           </el-dropdown>
+          <!-- 保存指标 -->
           <el-button type="primary" v-show="!isEdbAdd" @click="saveEdb(entryType)">{{$t('StatisticAnalysis.ChartRelevance.save_edb')}}</el-button>
         </template>
 
@@ -28,13 +29,17 @@
           @click="updateChartHandle(entryType)" 
           @command="chartCommandHandle"
         >
+          <!-- 更新图表/指标 -->
           {{$t('StatisticAnalysis.ChartRelevance.update_edb')}}
           <el-dropdown-menu slot="dropdown" v-show="isHaveSaveOtherHandle">
+            <!-- 另存为图表/指标 -->
             <el-dropdown-item :command="{entryType,scence:'saveOther'}">{{$t('Table.save_as')}}</el-dropdown-item>
           </el-dropdown-menu>
         </el-dropdown>
+        <!-- 保存图表 -->
         <el-button type="primary" @click="saveChart(entryType)" v-show="!isChartAdd">{{$t('Dialog.confirm_save_btn')}}</el-button>
-
+        <!-- 图例设置 -->
+        <el-button type="primary" plain @click="handleChartSettiing" v-show="isChartSetting">图例设置</el-button>
       </div>
     </div>
     <div class="chartWrapper">
@@ -46,7 +51,7 @@
         :options="options"
         :index="String(entryType)"
         :ref="`chartRef${entryType}`"
-        height="350"
+        :height="height||350"
       />
     </div>
   </div>
@@ -62,32 +67,42 @@ export default {
   mixins: [chartSetMixin],
   computed: {
     isHaveButton() {
-      let routes = ['/relevancechartEditor','/statisticFeatureChartEditor']
+      let routes = ['/relevancechartEditor','/statisticFeatureChartEditor','/relevancechartEditorV2']
       return routes.includes(this.$route.path)
     },
     cardTitle() {
       let title='';
       if(this.$route.path==='/relevancechartEditor') {
         title = [3,4].includes(this.entryType) ? `滚动相关性${this.entryType-2}` : this.entryType===1 ? this.chartInfo.ChartName : ''
-      }else if(this.$route.path==='/statisticFeatureChartEditor') {
+      }else if(this.$route.path==='/relevancechartEditorV2'){
+        if(this.settings.Model===1){
+            title = [3,4].includes(this.entryType) ? `滚动相关性${this.entryType-2}` : this.entryType===1 ? this.chartInfo.ChartName : this.relevanceChartData.ChartName
+        }else{
+            title = this.relevanceChartData.ChartName
+        }
+      }
+      else if(this.$route.path==='/statisticFeatureChartEditor') {
         title = this.chartInfo.ChartName
       }
       return title
     },
     isHaveEdbHandle() { //有指标操作的区域
       //相关性 3,4区域可保存指标 统计图 2,3区域
-      return (([3,4].includes(this.entryType)&&this.$route.path==='/relevancechartEditor')
+      return (([3,4].includes(this.entryType)&&['/relevancechartEditor','/relevancechartEditorV2'].includes(this.$route.path))
         || ([2,3].includes(this.entryType)&&this.$route.path==='/statisticFeatureChartEditor'))
     },
     isHaveSaveOtherHandle() {//有图表另存的区域
         //相关性 1,2区域有另存 统计图 4个区域都有另存
-      return (([1,2].includes(this.entryType) && this.$route.path==='/relevancechartEditor')
+      return (([1,2].includes(this.entryType) && ['/relevancechartEditor','/relevancechartEditorV2'].includes(this.$route.path))
        || (this.$route.path==='/statisticFeatureChartEditor'))
     }
   },
   watch: {
-    data(nval) {
-      this.setRenderChartData(nval)
+    data:{
+        handler(nval) {
+            this.setRenderChartData(nval)
+        },
+        deep:true
     }
   },
   props: {
@@ -108,6 +123,13 @@ export default {
     },
     settings: {
       type: Object
+    },
+    isChartSetting:{ //是否显示图表设置
+        type:Boolean,
+        default:false
+    },
+    height:{
+        type:String
     }
 
   },
@@ -132,6 +154,7 @@ export default {
         case 3: //3相关性 
           this.chartInfo = data.ChartInfo;
           this.relevanceChartData={
+            ChartName:data.ChartInfo.ChartName,
             ChartInfo:data.ChartInfo,
             EdbInfoList:data.EdbInfoList,
             XEdbIdValue:data.XEdbIdValue || data.XDateTimeValue,
@@ -139,12 +162,16 @@ export default {
             YDataList:[
               {
                 Value:data.YDataList[0].Value,
-                Color:'#00f',
-                Name:data.ChartInfo.ChartName,
+                Color:data.YDataList[0].Color||'#00f',
+                Name:data.YDataList[0].Name||data.ChartInfo.ChartName,
                 NameEn:''
               }
             ]
           }
+          if(this.settings.Model===2){
+            this.relevanceChartData.YDataList = data.YDataList
+            //this.relevanceChartData.ChartName = data.ChartInfo.EdbName+'相关性分析(xxx)'
+          }
           this.tableData=data.EdbInfoList||[]
           this.initRelevanceChartData()
           break
@@ -172,6 +199,10 @@ export default {
           break
       }
     },
+    handleChartSettiing(){
+        this.$emit('chartSettingChange',this.relevanceChartData)
+    },
+    
 
     /* 拟合方程曲线 */
     initFittingEquation(data) {
@@ -239,8 +270,17 @@ export default {
         4: 10
       }
       let Source;
-      if(this.$route.path==='/relevancechartEditor') {
+      if(['/relevancechartEditor','/relevancechartEditorV2'].includes(this.$route.path)) {
         Source = entryType;
+        //多因子参数不一样,这里直接返回
+        if(this.$parent.chartInfo.Model===2){
+            this.$emit('handleEdit',{
+                ChartName:this.chartInfo.ChartName,
+                ClassifyId:this.chartInfo.ClassifyId,
+                type:'edit'
+            })
+            return
+        }
       }else if(this.$route.path==='/statisticFeatureChartEditor') {
         Source = sourceMap[entryType]
       }
@@ -251,7 +291,7 @@ export default {
         ...this.settings
       }
       let res = null;
-      if(this.$route.path==='/relevancechartEditor') {
+      if(['/relevancechartEditor','/relevancechartEditorV2'].includes(this.$route.path)) {
         res = await chartRelevanceApi.saveChart(params)
       }else if(this.$route.path==='/statisticFeatureChartEditor') {
         res = await statisticFeatureInterface.saveChart(params);
@@ -273,7 +313,7 @@ export default {
         4: 10
       }
       let Source;
-      if(this.$route.path==='/relevancechartEditor') {
+      if(['/relevancechartEditor','/relevancechartEditorV2'].includes(this.$route.path)) {
         Source = entryType;
       }else if(this.$route.path==='/statisticFeatureChartEditor') {
         Source = sourceMap[entryType]
@@ -286,7 +326,7 @@ export default {
 			}
       
       let res = null;
-      if(this.$route.path==='/relevancechartEditor') {
+      if(['/relevancechartEditor','/relevancechartEditorV2'].includes(this.$route.path)) {
         res = await chartRelevanceApi.saveEdb(params)
       }else if(this.$route.path==='/statisticFeatureChartEditor') {
         res = await statisticFeatureInterface.saveEdb(params);

+ 10 - 2
src/views/chartRelevance_manage/components/explainText.js

@@ -1,6 +1,7 @@
 //相关性分析
 export const chartrelevanceTextArr = [
     `<p style='font-weight:bold;'>相关性计算处理逻辑:</p>
+    <p style='font-weight:bold;'>单因子:</p>
     <p>1、取数:取计算窗口的时间长度,从当前时间往前推移对应的时间长度,取该日期区间,指标A序列值和指标B序列值;</p>
     <p>2、变频:根据指标A和指标B的频度对取出的数据序列做如下处理</p>
     <p>①指标A高频,对指标B升频(线性方程插值法补全数据);</p>
@@ -14,10 +15,14 @@ export const chartrelevanceTextArr = [
     <p>2、分析周期:指标B领先A的期数,如配置参数10个月,表示B领先A -10月、B领先A -9月,...,B领先A 9月、B领先A 10月,每期分别计算相关性值;</p>`,
     `<p style='font-weight:bold;'>滚动相关性配置:</p>
     <p>1、计算窗口:参与计算的时间段长度,从两个指标都有值的日期开始滚动的取计算窗口长度的值进行计算,如配置计算窗口1个月,则2023.7.28的值取2023.6.28~2023.7.28时间段,2023.7.27的值取2023.6.27~2023.7.27时间段;</p>
-    <p>2、B领先A:B指标领先A指标的参数,为0时不领先;</p>`
+    <p>2、B领先A:B指标领先A指标的参数,为0时不领先;</p>
+    <p style='height:20px;'></p>
+    <p style='font-weight:bold;'>多因子:</p>
+    <p>可一次选择多个指标,与标的指标进行相关性计算。每一个因子指标与标的指标的计算逻辑,同单因子模式。</p>`
 ]
 export const chartrelevanceTextArrEn=[
     `<p style='font-weight:bold;'>Instruction for Correlation Calculation Processing Logic:</p>
+    <p style='font-weight:bold;'>Single Indicator:</p>
     <p>1、 Data Retrieval: Determine the time length of the calculation window, and move backwards from the current time by this duration to obtain a range of dates. Retrieve values for indicator A series and indicator B series within this date range.</p>
     <p>2、Frequency Adjustment:</p>
     <p>a. If indicator A is higher frequency, upsample indicator B (use linear equation interpolation to fill in data).</p>
@@ -31,7 +36,10 @@ export const chartrelevanceTextArrEn=[
     <p>2. Analysis Period: The number of periods that indicator B leads ahead of A; for instance, if configured with a parameter of 10 months, it indicates that B leads A by -10 months to +10 months, with correlation values calculated separately for each period.</p>`,
     `<p style='font-weight:bold;'>Rolling Correlation Configuration:</p>
     <p>1. Calculation Window: The length of time involved in calculations starts from when both indicators have available values and rolls forward taking values within the duration of the calculation window for computation. For example, if configured with a 1-month calculation window, then the value for July 28th, 2023 will be taken from June 28th to July 28th, 2023; while the value for July 27th will be taken from June 27th to July 27th.</p>
-    <p>2. B Leads A: The parameter by which indicator B leads ahead of indicator A; when set to 0, there is no lead.</p>`
+    <p>2. B Leads A: The parameter by which indicator B leads ahead of indicator A; when set to 0, there is no lead.</p>
+    <p style='height:20px;'></p>
+    <p style='font-weight:bold;'>Multiple Indicators:</p>
+    <p>Multiple indicators can be selected at a time to calculate the correlation with the target indicator. The calculation logic of each factor index and the target index is the same as the Single Indicato.</p>`
 ]
 
 //拟合方程曲线

+ 111 - 0
src/views/chartRelevance_manage/components/saveChartSetting.vue

@@ -0,0 +1,111 @@
+<template>
+    <el-dialog 
+        :visible.sync="isSettingChartShow"
+        :close-on-click-modal="false"
+        :modal-append-to-body='false'
+        @close="$emit('close')"
+        center width="500px"
+        title="图例设置"
+        custom-class="chart-setting-dialog"
+    >
+        <div class="dialog-content">
+            <el-form 
+                :modal="settingData" 
+                :rules="formRules"
+                label-width="100px"
+                ref="settingForm">
+                <el-form-item label="图表名称">
+                    <el-input v-model="settingData.chartName"></el-input>
+                </el-form-item>
+                <el-form-item label="图例名称" style="margin-bottom: 0;">
+                </el-form-item>
+                <el-form-item label-width="0px">
+                    <div class="option-box">
+                        <div class="option-item" v-for="(data,index) in settingData.YDataList" :key="index">
+                            <el-color-picker
+                                v-model="data.Color"
+                                size="mini"
+                                show-alpha
+                                :predefine="predefineColors"/>
+                            <el-input v-model="data.Name"></el-input>
+                        </div>
+                    </div>
+                </el-form-item>
+                <el-form-item label="数据来源">
+                    <el-input v-model="settingData.SourcesFrom.text"></el-input>
+                    <el-switch v-model="settingData.SourcesFrom.isShow"></el-switch>
+                </el-form-item>
+            </el-form>
+        </div>
+        <div class="dialog-footer">
+            <el-button type="primary" plain @click="$emit('close')">{{$t('Dialog.cancel_btn')}}</el-button>
+            <el-button type="primary" @click="handleSaveChartSetting">{{$t('Dialog.confirm_btn')}}</el-button>
+        </div>
+
+    </el-dialog>
+</template>
+
+<script>
+import { defaultOpts } from '@/utils/defaultOptions';
+export default {
+    props:{
+        isSettingChartShow:{
+            type:Boolean
+        },
+        settingData:{
+            type:Object,
+        }
+    },
+    data() {
+        return {
+            predefineColors: defaultOpts.colors.slice(0, 2),
+            formRules:{},
+        };
+    },
+    methods: {
+        handleSaveChartSetting(){
+            this.$emit('saveChartSetting')
+        },
+
+    },
+};
+</script>
+
+<style lang="scss">
+.chart-setting-dialog{
+    .el-input{
+        width:230px;
+    }
+    .el-color-picker--mini .el-color-picker__trigger {
+        width: 60px;
+        height: 25px;
+        padding: 0;
+        margin:0 12px 0 28px;
+    }
+    .el-color-picker--mini .el-color-picker__mask {
+        width: 60px;
+        height: 25px;
+    }
+    .el-form{
+        display: flex;
+        flex-direction: column;
+        margin:0 auto;
+        .option-box{
+            .option-item{
+                display: flex;
+                align-items: center;
+                margin-bottom:10px;
+                &:last-child{
+                    margin-bottom: 0;
+                }
+            }
+
+        }
+    }
+    
+    .dialog-footer{
+        text-align:center;
+        margin:30px 0 20px 0;
+    }
+}
+</style>

+ 44 - 8
src/views/chartRelevance_manage/components/saveChartTobaseDia.vue

@@ -34,7 +34,8 @@
                 label: 'ChartClassifyName',
                 value: 'ChartClassifyId',
                 children: 'Children',
-                emitPath: false
+                emitPath: false,
+                checkStrictly:isRelevanceChart
               }"
               style="width: 80%"
               :placeholder="$t('Edb.InputHolderAll.input_classify')"
@@ -92,6 +93,9 @@ export default {
 					{ required: true, message: /* '图表分类不能为空' */this.$t('Chart.Vailds.classify_msg'), trigger: 'blur' },
 				],
 			}
+		},
+		isRelevanceChart(){
+			return ['/relevancechartEditor','/relevancechartEditorV2'].includes(this.$route.path)&&this.chartData.Source!==1
 		}
 	},
 	data () {
@@ -111,19 +115,31 @@ export default {
       let res = null;
       if(this.chartData.Source===1) {
         res = await dataBaseInterface.chartClassify();
-      }else if(this.$route.path==='/relevancechartEditor'&&this.chartData.Source!==1) {
-        res = await chartRelevanceApi.classifyList();
+      }else if(['/relevancechartEditor','/relevancechartEditorV2'].includes(this.$route.path)&&this.chartData.Source!==1) {
+        res = await chartRelevanceApi.classifyTree();
       }else if(this.$route.path==='/statisticFeatureChartEditor'&&this.chartData.Source!==1) {
         res = await statisticFeatureInterface.classifyList();
       }
 
       if(res.Ret !== 200) return
-      this.filterNodes(res.Data.AllNodes,this.chartData.Source===1?3:1)
+      if(['/relevancechartEditor','/relevancechartEditorV2'].includes(this.$route.path)&&this.chartData.Source!==1){
+        this.filterNodesAll(res.Data.AllNodes)
+      }else{
+        this.filterNodes(res.Data.AllNodes,this.chartData.Source===1?3:1)
+      }
+      
 
 			this.classifyOptions = res.Data.AllNodes || [];
     
 		},
-
+		filterNodesAll(arr){
+			arr.length && arr.forEach(item => {
+				item.Children && item.Children.length && this.filterNodesAll(item.Children)
+				if(!item.Children.length) {
+					delete item.Children
+				}
+			})
+		},
 		// 递归改变第三级目录结构
 		filterNodes(arr,n) {
 			arr.length && arr.forEach(item => {
@@ -147,8 +163,14 @@ export default {
         4: 10
       }
       let Source;
-      if(this.$route.path==='/relevancechartEditor') {
+      if(['/relevancechartEditor','/relevancechartEditorV2'].includes(this.$route.path)) {
         Source = this.source;
+        //多因子的参数和接口都不一样,这里直接返回
+        if(this.$parent.chartInfo.Model===2){
+            this.$emit('handleSave',{ChartName: name,ClassifyId: classify,type:this.saveScence})
+            return
+        }
+        
       }else if(this.$route.path==='/statisticFeatureChartEditor') {
         Source = sourceMap[this.source]
       }
@@ -162,8 +184,22 @@ export default {
       }
 
       let res = null;
-      if(this.$route.path==='/relevancechartEditor') {
-        res = await chartRelevanceApi.saveChart(params)
+      if(['/relevancechartEditor','/relevancechartEditorV2'].includes(this.$route.path)) {
+        //单因子-相关性额外参数
+        let otherParams = this.source===2?{
+            CorrelationExtraConfig:{
+                LegendConfig:this.$parent.chartBatchData.CorrelationData.YDataList.map(i=>{
+                    return {
+                        LegendName:i.Name,
+                        SeriesId:i.SeriesId,
+                        EdbInfoId:i.Id,
+                        Color:i.Color
+                    }
+                })
+            },
+            SourcesFrom:this.$parent.chartBatchData.SourcesFrom
+        }:{}
+        res = await chartRelevanceApi.saveChart({...params,...otherParams})
       }else if(this.$route.path==='/statisticFeatureChartEditor') {
         res = await statisticFeatureInterface.saveChart(params);
       } 

+ 2 - 2
src/views/chartRelevance_manage/components/saveEdbToBaseDia.vue

@@ -173,7 +173,7 @@ export default {
         4: 10
       }
       let Source;
-      if(this.$route.path==='/relevancechartEditor') {
+      if(['/relevancechartEditor','/relevancechartEditorV2'].includes(this.$route.path)) {
         Source = this.source;
       }else if(this.$route.path==='/statisticFeatureChartEditor') {
         Source = sourceMap[this.source]
@@ -190,7 +190,7 @@ export default {
 			}
 
 			let res = null;
-      if(this.$route.path==='/relevancechartEditor') {
+      if(['/relevancechartEditor','/relevancechartEditorV2'].includes(this.$route.path)) {
         res = await chartRelevanceApi.saveEdb(params);
       }else if(this.$route.path==='/statisticFeatureChartEditor') {
         res = await statisticFeatureInterface.saveEdb(params);

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

@@ -4,6 +4,7 @@
       style="width: 100%"
       v-model="targetType"
       :placeholder="$t('StatisticAnalysis.StatisticFeatureChart.selecr_indicator_pld')"
+      :disabled="isDisabled"
       @change="targetTypeChange"
       v-if="selectStyleType===1&&filter"
     >
@@ -82,6 +83,7 @@
       :filterable="!search_txt"
       remote
       clearable
+      :disabled="isDisabled"
       :placeholder="$t('Edb.InputHolderAll.select_edb_name')"
       :style="`width: ${width}; ${filter?'margin-top: 20px':''}`"
       :remote-method="searchHandle"
@@ -136,6 +138,9 @@ export default {
       },
       width: {
         default:'100%'
+      },
+      isDisabled:{
+        default:false
       }
     },
     watch:{

+ 4 - 1
src/views/chartRelevance_manage/css/index.scss

@@ -146,13 +146,16 @@ $normal-font: 14px;
               text-align: center;
               margin-bottom: 10px;
             }
-            .chart-author {
+            .chart-author,.chart-source {
               font-size: 14px;
               color: #333;
               position: absolute;
               bottom: 0;
               right: 50px;
             }
+            .chart-source{
+                left:50px;
+            }
             .chartWrapper {
               position: relative;
               .range-cont {

+ 10 - 2
src/views/chartRelevance_manage/mixins/classifyMixin.js

@@ -37,6 +37,14 @@ export default {
         let search_obj = this.searchOptions.find(
           (_) => _.ChartInfoId === newval
         );
+        if(this.$route.path==='/chartrelevance'){
+            if(!search_obj) return 
+            // 重置筛选状态
+            this.select_id = newval;
+            this.select_node = search_obj.UniqueCode;
+            this.select_classify = 0;
+            return 
+        }
         let deep_arr = _.cloneDeep(this.treeData);
         // 查找图表的分类父级id
 
@@ -121,8 +129,8 @@ export default {
 				width > 500
 					? 'auto'
 					: width <= 260
-					? 90
-					: 0.7 * width;
+					? 80
+					: 0.4 * width;
 			this.$set(node, 'Nodewidth', label_wid + 'px');
 		},200),
 

+ 210 - 0
src/views/chartRelevance_manage/relevance/components/batchSelectFormula.vue

@@ -0,0 +1,210 @@
+<template>
+    <div class="batch-select-formula-wrap">
+        <el-form :model="formulaForm" :rules="formulaRules" label-width="80px" ref="formulaForm">
+            <div class="formula-list">
+                <div class="list-item" v-for="(item,index) in formulaForm.CalculateStep" :key="index">
+                    <span>
+                        <img @click="deleteFormula(index)" style="width:15px;height:15px;cursor: pointer;" src="~@/assets/img/ai_m/delete.png" alt="">
+                    </span>
+                    <el-select v-model="item.formulaType">
+                        <el-option 
+                            v-for="option in formulaOpt"
+                            :key="option.Source"
+                            :value="option.Source"
+                            :label="option.CalculateName"
+                        />
+                    </el-select>
+                    <div class="form-item-box">
+                        <!-- N期 N等于-->
+                        <el-form-item
+                            v-if="[5,6,7].includes(item.formulaType)"
+                            :label="$t('EtaBasePage.label_n_val')"
+                            :prop="`CalculateStep[${index}].nNum`"
+                            :rules="{required:true,message:$t('Edb.Valids.n_msg'),trigger:'blur'}"
+                        >
+                            <el-input v-model="item.nNum" :placeholder="$t('Edb.InputHolderAll.input_n_value')" type="number"></el-input>
+                        </el-form-item>
+                        <!-- 超季节性 N等于 日历-->
+                        <el-form-item 
+                            v-if="item.formulaType===11"
+                            :label="$t('EtaBasePage.label_n_val')"
+                            :prop="`CalculateStep[${index}].nNum`"
+                            :rules="{required:true,message:$t('Edb.Valids.n_msg'),trigger:'blur'}"
+                        >
+                            <el-input v-model="item.nNum" :placeholder="$t('Edb.InputHolderAll.input_n_value')" type="number"></el-input>
+                        </el-form-item>
+                        <el-form-item 
+                            v-if="item.formulaType===11"
+                            :label="$t('EtaBasePage.label_calendar')"
+                        >
+                            <el-select v-model="item.Calendar">
+                                <el-option :label="$t('Chart.calendar_gre')" value="公历"></el-option>
+                                <el-option :label="$t('Chart.calendar_lunar')" value="农历"></el-option>
+                            </el-select>
+                        </el-form-item>
+                        <!-- 指数修匀 alpha值 -->
+                        <el-form-item
+                            v-if="item.formulaType===15"
+                            :label="$t('EtaBasePage.alpha_value_lable')" 
+                            :prop="`CalculateStep[${index}].alphaValue`"
+                            :rules="[
+                                {required:true,message:$t('Edb.Valids.alpha_msg'),trigger:'blur'},
+                                {validator:validator,trigger:['change','blur']}]">
+                            <el-input v-model.trim="item.alphaValue" style="width:140px" :placeholder="$t('Edb.InputHolderAll.input_alpha_val')" type="number"></el-input>
+                        </el-form-item>
+                    </div>
+                    
+                </div>
+            </div>
+            <div class="tool-box-wrap">
+                <!-- 添加计算公式 -->
+                <div class="add-btn" @click="addFormula">
+                        <img style="width:15px;height:15px;vertical-align: middle;" src="~@/assets/img/icons/formula-add.png" alt="">
+                    {{ $t('StatisticAnalysis.ChartRelevance.formula_add_btn') }}
+                </div>
+                <div class="input-box">
+                    <el-form-item
+                        required
+                        :label="$t('StatisticAnalysis.ChartRelevance.series_name')"
+                        label-width="120px"
+                    >
+                        <el-input v-model.trim="formulaForm.SeriesName" style="width:230px" 
+                        :placeholder="$t('StatisticAnalysis.ChartRelevance.series_name_placeholder')"></el-input>
+                    </el-form-item>
+                </div>
+            </div>
+        </el-form>
+        
+    </div>
+</template>
+
+<script>
+export default {
+    props:{
+        formulaOpt:{
+            type:Array,
+            default:[]
+        },
+        factorData:{
+            type:Object,
+            default:{}
+        }
+    },
+    computed:{
+        //计算方式列表-改为后端获取
+        /* formulaOption(){
+            return [
+                {
+                    value:5,
+                    label:this.$t('Edb.CalculatesAll.on_year'),//同比值
+                },
+                {
+                    value:7,
+                    label:this.$t('Edb.CalculatesAll.differ'),//同差值
+                },
+                {
+                    value:8,
+                    label:this.$t('Edb.CalculatesAll.rule_move_average'),//N期移动均值
+                },
+                {
+                    value:12,
+                    label:this.$t('Edb.CalculatesAll.period_over_period'),//N期环比值
+                },
+                {
+                    value:13,
+                    label:this.$t('Edb.CalculatesAll.period_difference'),//N期环差值
+                },
+                {
+                    value:35,
+                    label:this.$t('Edb.CalculatesAll.super_seasonal'),//超季节性
+                },
+                {
+                    value:72,
+                    label:this.$t('Edb.CalculatesAll.ex_smooth'),//指数修匀
+                },
+            ]
+        } */
+    },
+    watch:{
+        factorData:{
+            handler(newValue){
+                this.formulaForm = _.cloneDeep(newValue)
+            },
+            immediate:true
+        },
+    },
+    data() {
+        return {
+            formulaForm:{
+                CalculateStep:[],
+                SeriesName:''
+            },
+            formulaRules:{},
+        };
+    },
+    methods: {
+        //打开弹窗时,在外层组件调用
+        initFormulaList(){
+            //this.formulaForm.CalculateStep = _.cloneDeep(this.dataFormulaList)
+            this.getFormulaOption()
+        },
+        validator(rule,value,callback){
+            if(Number(value)<=0||Number(value)>=1){
+                callback(new Error(this.$t('Edb.Valids.alpha_value_vaild')))
+            }else{
+                callback()
+            }
+        },
+        addFormula(){
+            this.formulaForm.CalculateStep.push({
+                formulaType:5,
+                Calendar:'公历',
+                nNum:1,
+                alphaValue:0.5
+            })
+        },
+        deleteFormula(index){
+            if(this.formulaForm.CalculateStep.length>=5){
+                return this.$message.warning(/* "最多仅能添加5个计算公式" */ this.$t('StatisticAnalysis.ChartRelevance.formulaform_add_hint'))
+            }
+            this.formulaForm.CalculateStep.splice(index,1)
+        },
+        async checkForm(){
+            return await this.$refs.formulaForm.validate()
+        },
+    },
+};
+</script>
+
+<style lang="scss">
+.batch-select-formula-wrap{
+    .el-input,.el-select{
+        width:140px;
+    }
+    .formula-list{
+        margin-top: 20px;
+        .list-item{
+            margin-bottom: 15px;
+            display: flex;
+            align-items: center;
+            gap:0 15px;
+            .form-item-box{
+                display: flex;
+                .el-form-item{
+                    margin-bottom: 0;
+                }
+            }
+        }
+    }
+    .tool-box-wrap{
+        margin-top: 20px;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        .add-btn{
+            color:#0052D9;
+            cursor: pointer;
+        }
+    }
+}
+</style>

+ 257 - 0
src/views/chartRelevance_manage/relevance/components/batchSelectTable.vue

@@ -0,0 +1,257 @@
+<template>
+    <!-- 封装表格跨页多选逻辑 -->
+    <div class="batch-select-table">
+        <div class="table-box" style="width:50%;">
+            <el-table
+                border height="500px"
+                v-loading="tableLoading"
+                ref="tableRef" 
+                :data="tableData"
+                @select="selectHandle" 
+                @select-all="selectAllHandle"
+            >
+                <el-table-column type="selection" min-width="50" align="center"/>
+                <el-table-column 
+                    align="center"
+                    v-for="column in tableColumns" 
+                    :key="column.key"
+                    :label="column.label"
+                    :prop="column.key"
+                    :width="column.width"
+                    :show-overflow-tooltip="column.showOverflowTooltip">
+                    <template slot-scope="{row}">
+                        <span v-if="column.key==='Frequency'">{{ getFrequencyTrans(row.Frequency) }}</span>
+                        <span v-else-if="['UniEn','Unit'].includes(column.key)">{{ getUnitTrans(row.Unit) }}</span>
+                        <span v-else>{{ row[column.key] }}</span>
+                    </template>
+                </el-table-column>
+            </el-table>
+            <m-page 
+                style="margin-top:10px"
+                class="table-page" 
+                v-show="tableParams.total"
+                :total="tableParams.total" 
+                :pageSize="tableParams.pageSize"
+                :page_no="tableParams.pageNo"
+                :pagercount="tableParams.pagerCount"
+                @handleCurrentChange="pageNumberChange"
+            />
+        </div>
+        <!-- 加入已选指标 -->
+        <el-button type="primary" @click="handleAddSelectData">{{ $t('EtaBasePage.add_to_selections') }}</el-button>
+        <div class="select-box" style="width: 35%;">
+            <el-table
+                border height="500px"
+                ref="selectRef" 
+                :data="selectData"
+            >
+            <el-table-column
+                align="center"
+                :label="tableColumns[0].label"
+                :prop="tableColumns[0].key"
+             />
+             <el-table-column width="50px" align="center" v-if="selectData.length">
+                <template slot="header" slot-scope="scope">
+                    <img @click="handleDelSelect(_,'all')" style="width:15px;height:15px;cursor: pointer;" src="~@/assets/img/ai_m/delete.png" alt="">
+                </template>
+                <template slot-scope="{row,$index}">
+                    <img @click="handleDelSelect($index,'')" style="width:15px;height:15px;cursor: pointer;" src="~@/assets/img/ai_m/delete.png" alt="">
+                </template>
+            </el-table-column>
+        </el-table>
+        </div>
+    </div>
+</template>
+
+<script>
+import mPage from '@/components/mPage.vue'
+export default {
+    components:{mPage},
+    props:{
+        tableData:{
+            type:Array,
+            default:[]
+        },
+        tableLoading:{
+            type:Boolean,
+            default:false
+        },
+        tableColumns:{
+            type:Array,
+            default:[]
+        },
+        tableParams:{
+            type:Object,
+            default:()=>{
+                return {
+                    total:0,
+                    pageSize:20,
+                    pageNo:1,
+                    pagerCount:5,
+                    uniqueKey:'Id'
+                }
+            }
+        },
+        isSelectAll:{
+            type:Boolean,
+            default:false,
+        },
+        factorData:{
+            type:Object,
+            default:{}
+        }
+    },
+    watch:{
+        /* isSelectAll(newValue){
+            this.listCheckAllChange(newValue)
+        }, */
+        factorData:{
+            handler(newValue){
+                this.selectData = _.cloneDeep(newValue.EdbMappings||[])
+            },
+            immediate:true,
+            deep:true
+        }
+        
+    },
+    data() {
+        return {
+            selectList:[],//左侧表格已选择/已剔除的数据
+            selectData:[],//右侧表格的数据
+            selectionReactCancel:false,
+        };
+    },
+    methods: {
+        //点击数据行的checkbox触发 selection:已选择的所有数据行;row:当前点击的数据行
+        selectHandle(selection,row){
+            const {uniqueKey} = this.tableParams
+            //通过判断selection中有无row确定是勾选了checkbox还是取消勾选
+            //当为勾选时,判断selectList是否表示已选择的数据(isSelectAll===false),若不是则不加入
+            //当为取消勾选时,判断selectList是否表示已剔除的数据(isSelectAll===true),若不是则不加入
+            let check = selection.some(i=>i[uniqueKey] == row[uniqueKey])?(!this.isSelectAll):(this.isSelectAll)
+            if(check){
+                this.selectList.push(row[uniqueKey])
+            }else{
+                this.selectList = this.selectList.filter(i=>i!=row[uniqueKey])
+            }
+            this.selectionChange()
+        },
+        //点击表头全选 or 调用toggleAllSelection 触发
+        selectAllHandle(selection){
+            //当前table的所有数据
+            const tableIds = this.tableData.map(it => it[this.tableParams.uniqueKey])
+            //通过判断selection中有无数据确定是全选or取消全选
+            //当为全选时,判断selectList是否表示已选择的数据(isSelectAll===false),若不是则从selectList中剔除
+            //当为取消全选时,判断selectList是否表示已剔除的数据(isSelectAll===true),若不是则从selectList中剔除
+            let check = selection&&selection.length?(!this.isSelectAll):this.isSelectAll
+            if(check){
+                this.selectList =  [...this.selectList,...tableIds]
+            }else{
+                this.selectList = this.selectList.filter(it => !tableIds.includes(it))
+            }
+            this.selectionChange()
+        },
+        //当勾选项改变时 处理数据
+        selectionChange(){
+            //去重 selectList
+            let duplicateArr = Array.from(new Set(this.selectList))
+            let isCheckAll = false,isIndeterminate = false
+            //判断已选择的数据,更改列表全选checkbox的状态
+            /**
+             * 全选:
+             * 1.selectList.length === total && isSelectAll === false (已选择的数据为全部数据)
+             * 2.selectList.length === 0 && isSelectAll === true (已剔除的指标为空)
+             * 以上两种满足其一即可
+             */
+            const selectAll = duplicateArr.length===this.tableParams.total && (!this.isSelectAll)
+                || duplicateArr.length===0 && this.isSelectAll
+            /**
+             * 全不选:
+             * 1.selectList.length === total && isSelectAll === true (剔除了全部数据)
+             * 2.selectList.length === 0 && isSelectAll === false (没选择任何数据)
+             * 以上两种满足其一即可
+             */
+            const selectNone = duplicateArr.length===this.tableParams.total && this.isSelectAll
+                || duplicateArr.length===0 && (!this.isSelectAll)
+            //其余情况均为半选
+
+            if(selectAll){
+                isCheckAll = true
+                isIndeterminate = false
+            }else if(selectNone){
+                isCheckAll = false
+                isIndeterminate = false
+            }else{
+                isCheckAll = false
+                isIndeterminate = true
+            }
+
+            this.$emit('changeCheckAll',{isCheckAll,isIndeterminate})
+        },
+        //切换页面时调整勾选项 (在外层组件调用)
+        adjustSelection(){
+            const {uniqueKey} = this.tableParams
+            this.$refs.tableRef.clearSelection()
+            this.tableData.forEach(data=>{
+                if(this.selectList.includes(data[uniqueKey])){
+                    //isSelectAll===false,selectList为已选择的数据,则对应数据行打勾
+                    //isSelectAll === true,selectList为已剔除的数据,则对应的数据行取消打勾
+                    this.$nextTick(()=>{
+                        this.$refs.tableRef.toggleRowSelection(data,!this.isSelectAll)
+                    })
+                }else{
+                    this.$nextTick(()=>{
+                        this.$refs.tableRef.toggleRowSelection(data,this.isSelectAll)
+                    })
+                }
+            })
+        },
+        listCheckAllChange(newValue){
+            this.selectList = []
+            this.$refs.tableRef && this.tableData.length && this.$refs.tableRef.clearSelection()
+            if(newValue){
+                //会触发select-all
+                this.$refs.tableRef && this.tableData.length && this.$refs.tableRef.toggleAllSelection()
+                /* //不会触发select-all
+                this.$refs.tableRef && this.tableData.length && this.$refs.tableRef.toggleRowSelection(this.tableData[0],true) */
+            }
+        },
+        pageNumberChange(page){
+            this.$emit('pageChange',page)
+        },
+        handleAddSelectData(){
+            //外层组件处理校验和添加逻辑
+            this.$emit('addSelectData',{selectList:this.selectList,selectData:this.selectData})
+
+        },
+        //外层组件调用
+        addSelectData(data){
+            this.selectData = _.cloneDeep(data)
+            
+        },
+        handleDelSelect(index,type){
+            if(type==='all'){
+                return (this.selectData = [])
+            }
+            this.selectData.splice(index,1)
+        },
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.batch-select-table{
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    gap:0 20px;
+    .table-box,.select-box{
+        flex:1;
+    }
+    &::after{
+        content:'';
+        flex:0 0 auto;
+        visibility: hidden;
+    }
+}
+</style>

+ 38 - 0
src/views/chartRelevance_manage/relevance/components/formMixin.js

@@ -0,0 +1,38 @@
+//单因子,多因子的表单 共同逻辑
+import {yearSelector} from '@/utils/defaultOptions';
+import selectTarget from '../../components/selectTarget.vue'
+export default{
+    components:{selectTarget},
+    props:{
+        chartInfoData:{
+            type:Object,
+            default:{}
+        },
+        infoForm:{
+            type:Object,
+            default:()=>{return {Curve:{},Correlation:{},RollingCorrelation:[]}}
+        }
+    },
+    computed:{
+        yearSelector(){
+            return [
+                ...yearSelector,
+                { name: this.$i18n.locale == 'zh'?'自定义':'custom',value: 5 }
+            ]
+        },
+        dayOpt(){
+            return [
+                {label:this.$t('Edb.FreAll.year_min'),val:'年'},
+                {label:this.$t('Edb.FreAll.quarter_min'),val:'季'},
+                {label:this.$t('Edb.FreAll.month_min'),val:'月'},
+                {label:this.$t('Edb.FreAll.week_min'),val:'周'},
+                {label:this.$t('Edb.FreAll.day_min'),val:'天'},
+            ]
+        }
+    },
+    methods: {
+        handleSelectTarget(type='A',target=''){
+            this.$emit(`selectTarget`,{type,target})
+        },
+    },
+}

+ 137 - 0
src/views/chartRelevance_manage/relevance/components/modifyClassifyDialog.vue

@@ -0,0 +1,137 @@
+<template>
+    <div class="Dialog-box">
+        <el-dialog
+        :visible.sync="isOpenDialog"
+        :close-on-click-modal="false"
+        :modal-append-to-body='false'
+        @close="cancelHandle"
+        custom-class="dialog"
+        center
+        width="560px"
+        v-dialogDrag>
+            <div slot="title" style="display:flex;alignItems:center;">
+                <img :src="type=='add'?$icons.add:$icons.edit" style="color:#fff;width:16px;height:16px;marginRight:5px;">
+                <span style="fontSize:16px;">{{type==='add' ? $t('Table.add_btn') : $t('Table.edit_btn')}}</span>
+            </div>
+            <div class="dialog-main">
+                <el-form
+                ref="diaForm"
+                label-position="left"
+                hide-required-asterisk
+                label-width="120px"
+                :model="formData"
+                :rules="formRules">
+                    <el-form-item :label="$t('OnlineExcelPage.parent_directory_lable')" v-if="formData.level>0">
+                        <el-tooltip class="item" effect="dark" :content="getParentName" placement="top">
+                            <span class="parentStr">{{getParentName}}</span>
+                        </el-tooltip>
+                    </el-form-item>
+                    <el-form-item :label="$t('EtaBasePage.menu_name')" prop="levelVal">
+                        <el-input
+                        v-model="formData.levelVal"
+                        style="width: 80%"
+                        :placeholder="$t('Dialog.require_vaild')"></el-input>
+                    </el-form-item>
+                </el-form>
+            </div>
+            <div class="dia-bot">
+                <el-button type="primary" style="margin-right:20px" @click="saveHandle"><!-- 保存 -->{{$t('Dialog.confirm_save_btn')}}</el-button>
+                <el-button type="primary" plain @click="cancelHandle"><!-- 取消 -->{{$t('Dialog.cancel_btn')}}</el-button>
+            </div>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+import chartRelevanceApi from "@/api/modules/chartRelevanceApi.js";
+export default {
+    props: {
+        isOpenDialog: {
+            type: Boolean,
+        },
+        type:{
+            type:String,
+            default:'add'
+        },
+        formData: {
+            type: Object,//{parentArr父级数据}
+        }
+    },
+    computed:{
+        getParentName(){
+            const arr=this.formData.parentArr||['无']
+            let strArr=arr.reverse().map(item=>{
+                return item.classifyName
+            })
+            
+            return strArr.join('/')
+        }
+    },
+    data () {
+        return {
+            formRules: {
+                levelVal:[
+                    { required: true, message: this.$t('EtaBasePage.input_menu_msg'), trigger: 'blur' },
+                ],
+            },
+            options:  [],
+
+        };
+    },
+    methods: {
+        async saveHandle() {
+            await this.$refs.diaForm.validate();
+            let addParams = {
+                ChartClassifyName:this.formData.levelVal,
+                Level:this.formData.level,
+                ParentId:this.formData.parent_id,
+            }
+            let editParams = {
+                ChartClassifyName:this.formData.levelVal,
+                ChartClassifyId:this.formData.nodeId
+            }
+            const res = this.type==='add'?await chartRelevanceApi.classifyAdd(addParams):await chartRelevanceApi.classifyEdit(editParams)
+            if(res.Ret!==200) return 
+            this.$message.success(`${this.type==='add'?'新增':'编辑'}成功`)
+            this.callbackHandle()
+
+
+        },
+        /* 成功回调 */
+        callbackHandle(type) {
+            this.$refs.diaForm.resetFields();
+            this.$emit('sucessCallback',type)
+        },
+        /* 取消 */
+        cancelHandle() {
+            this.$refs.diaForm.resetFields();
+            this.$emit('closeDia')
+        },
+    },
+    created() {},
+    mounted() {},
+}
+</script>
+<style lang='scss'>
+.Dialog-box {
+    .parentStr{
+        display: block;
+        width: 304px;
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+    }
+    .dialog-main {
+        padding-left: 50px;
+    }
+    .el-cascader .el-input {
+        width: 100%;
+    }
+    .dia-bot {
+        margin: 52px 0 30px;
+        display: flex;
+        justify-content: center;
+
+    }
+    }
+</style>

+ 616 - 0
src/views/chartRelevance_manage/relevance/components/multipleIndForm.vue

@@ -0,0 +1,616 @@
+<template>
+    <div class="multiple-model-form model-form">
+        <!-- 标的指标 -->
+        <el-form-item 
+            :label="$t('StatisticAnalysis.ChartRelevance.target_indicator')" 
+            prop="IndTarget" class="select-target">
+            <!-- 添加后的图表不允许修改标的指标 -->
+            <selectTarget 
+                :isDisabled="isMultipleChartAdd"
+                :defaultId="chartInfoData.EdbInfoList?chartInfoData.EdbInfoList[0].EdbInfoId:''"
+                :defaultOpt="chartInfoData.EdbInfoList?[chartInfoData.EdbInfoList[0]]:[]" 
+                :defaultType="chartInfoData.EdbInfoList?chartInfoData.EdbInfoList[0].EdbInfoCategoryType:''"
+                @select="(target)=>handleSelectTarget('IndTarget',target)"
+            />
+        </el-form-item>
+        <!-- 因子指标系列 -->
+        <div class="factor-form-item">
+            <el-form-item 
+                :label="$t('StatisticAnalysis.ChartRelevance.factor_indicators')" required>
+            </el-form-item>
+            <div class="factor-list">
+                    <div class="list-item" 
+                        v-for="(item,index) in factorList" :key="index">
+                        <span>
+                            <!-- <i class="el-icon-arrow-right"></i> -->
+                            {{ item.SeriesName }}
+                        </span>
+                        <span  @click.stop="openAddDialog(item)" style="margin-left: auto;">
+                            <img src="~@/assets/img/icons/edit_blue_new.png" alt="" style="width: 16px; height: 16px; margin-right: 5px">
+                        </span>
+                        <span @click="deleteFactorIndicators(index)">
+                            <img src="~@/assets/img/set_m/del_icon.png" alt="" style="width: 14px; height: 14px;">
+                        </span>
+                    </div>
+            </div>
+            <div class="add-factor-btn" @click="openAddDialog(null)">
+                <img src="~@/assets/img/add-quadrate-blue.png" />
+                {{ $t('StatisticAnalysis.ChartRelevance.add_factor_indicators') }}
+            </div>
+        </div>
+        <div class="form-box">
+            <!-- 相关性 -->
+            <div class="label-title">{{ $t('Chart.ChartType.correlation_name') }}</div>
+            <el-form-item 
+                :label="$t('StatisticAnalysis.ChartRelevance.calculation_window')"
+                prop="Correlation.CalculateValue" class="flex-form-item">
+                <el-input
+                    style="flex:2"
+                    :step="1"
+                    type="number"
+                    v-model="infoForm.Correlation.CalculateValue"
+                    @change="val => { infoForm.Correlation.CalculateValue = Number(val); }"
+                />
+                <el-select
+                        style="flex:2"
+                        v-model="infoForm.Correlation.CalculateUnit">
+                    <el-option
+                        v-for="item in dayOpt"
+                        :key="item.val"
+                        :label="item.label"
+                        :value="item.val"
+                    />
+                </el-select>
+            </el-form-item>
+            <el-form-item 
+                :label="$t('StatisticAnalysis.ChartRelevance.analysis_cycle')" 
+                prop="Correlation.LeadValue" class="flex-form-item">
+                <el-input
+                    style="flex:2"
+                    :step="1"
+                    type="number"
+                    v-model="infoForm.Correlation.LeadValue"
+                    @change="val => { infoForm.Correlation.LeadValue = Number(val); }"
+                />
+                <el-select
+                    style="flex:2"
+                    v-model="infoForm.Correlation.LeadUnit">
+                    <el-option
+                        v-for="item in dayOpt"
+                        :key="item.val"
+                        :label="item.label"
+                        :value="item.val"
+                    />
+                </el-select>
+            </el-form-item>
+        </div>
+        <!-- 添加/编辑因子系列弹窗 -->
+        <el-dialog
+            :visible.sync="isAddFactorDialogShow"
+            :close-on-click-modal="false"
+            :modal-append-to-body='false'
+            @close="isAddFactorDialogShow=false"
+            center width="75%" top="30px"
+            :title="$t('StatisticAnalysis.ChartRelevance.add_factor_indicators')"
+            custom-class="add-factor-dialog"
+        >
+            <div class="dialog-content">
+                <!-- 选择指标 or 预测指标 -->
+                <div class="table-radio-wrap">
+                    <el-radio-group v-model="factorData.EdbInfoType" @input="changeEdbType">
+                        <el-radio :label="0">ETA指标</el-radio>
+                        <el-radio :label="1">预测指标</el-radio>
+                    </el-radio-group>
+                    
+                </div>
+                <!-- 表格筛选项 -->
+                <div class="table-select-box">
+                    <el-cascader
+                        v-model="tableSelectParams.classify"
+                        :options="classifyOpt"
+                        :props="{
+                            label: 'ClassifyName',
+                            value: 'ClassifyId',
+                            children: 'Children',
+                            multiple: true,
+                            emitPath:false
+                        }"
+                        clearable collapse-tags
+                        :placeholder="$t('EtaBasePage.label_classify')"
+                        @change="handleFilter"
+                    />
+                    <el-select
+                        v-model="tableSelectParams.frequency"
+                        :placeholder="$t('EtaBasePage.select_frequency')"
+                        clearable multiple collapse-tags
+                        @change="handleFilter">
+                        <el-option
+                            v-for="item in frequencyArr"
+                            :key="item.value"
+                            :label="item.label"
+                            :value="item.value"
+                        >
+                        </el-option>
+                    </el-select>
+                    <el-cascader
+                        v-model="tableSelectParams.creator"
+                        :placeholder="$t('EtaBasePage.table_col_creator')"
+                        :options="sysUserOpt"
+                        :props="{
+                            value: 'AdminId',
+                            label: 'RealName',
+                            children: 'ChildrenList',
+                            multiple: true,
+                            emitPath:false
+                        }"
+                        collapse-tags
+                        :show-all-levels="false"
+                        clearable filterable
+                        @change="handleFilter"
+                    />
+                    <el-input 
+                        :placeholder="$t('Edb.InputHolderAll.input_name_orid')" 
+                        v-model="tableSelectParams.keyword"
+                        style="width: 240px"
+                        @keydown.enter.native="handleFilter"
+                    >
+                        <i slot="prefix" class="el-input__icon el-icon-search"></i>
+                    </el-input>
+                    <el-checkbox 
+                        :label="$t('EtaBasePage.label_all_check')"
+                        :indeterminate="isIndeterminate" 
+                        v-model="isCheckAll" 
+                        @change="listCheckAllChange"/>
+                </div>
+                <!-- 表格 -->
+                <batchSelectTable
+                    ref="batchSelectTable"
+                    :tableColumns="tableColumns"
+                    :tableData="tableData"
+                    :tableParams="tableParams"
+                    :tableLoading="tableLoading"
+                    :isSelectAll="isSelectAll"
+                    :factorData="factorData"
+                    @pageChange="tablePageChange"
+                    @changeCheckAll="changeCheckAll"
+                    @addSelectData="addSelectData"
+                ></batchSelectTable>
+                <!-- 计算公式 -->
+                <batchSelectFormula
+                    ref="batchSelectFormula"
+                    :factorData="factorData"
+                    :formulaOpt="formulaOpt"
+                ></batchSelectFormula>
+            </div>
+            <div class="dialog-footer">
+                <el-button type="primary" plain @click="isAddFactorDialogShow=false">{{$t('Dialog.cancel_btn')}}</el-button>
+                <el-button type="primary" @click="handleAddFactor" :loading="addFactorLoading">{{$t('Dialog.confirm_btn')}}</el-button>
+            </div>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+import batchSelectTable from './batchSelectTable'
+import batchSelectFormula from './batchSelectFormula'
+import formMixin from './formMixin'
+import { frequencySelectList } from '@/utils/defaultOptions'
+import {checkListChange,checkStepsChange} from '../utils/index'
+
+import { dataBaseInterface,departInterence } from '@/api/api.js'
+import * as preDictEdbInterface from "@/api/modules/predictEdbApi.js"
+import chartRelevanceApi from '@/api/modules/chartRelevanceApi'
+export default {
+    mixins:[formMixin],
+	components: { batchSelectTable, batchSelectFormula },
+    props:{
+        SeriesList:{
+            type:Object,
+            default:[]
+        },
+        isMultipleChartAdd:{
+            type:Boolean,
+            default:false
+        }
+    },
+    computed:{
+        tableColumns(){
+            return [
+                {
+                    key:this.$i18nt.locale==='en'?'EdbNameEn':'EdbName',
+                    label:this.$t('EtaBasePage.full_metric_name'),//指标全称
+                    width:'240px',
+                    showOverflowTooltip:true,
+                },
+                {
+                    key:'EndDate',
+                    label:this.$t('Edb.Detail.e_latest_date'),//最新日期
+                    width:'120px',
+                },
+                {
+                    key:'EndValue',
+                    label:this.$t('Edb.Detail.e_latest_value'),//最新值
+                    width:'80px',
+                    showOverflowTooltip:true,
+                },
+                {
+                    key:'SysUserRealName',
+                    label:this.$t('EtaBasePage.table_col_creator'),//创建人
+                    width:'80px',
+                    showOverflowTooltip:true,
+                },
+                {
+                    key:'Frequency',
+                    label:this.$t('Edb.Detail.e_fre'),//频率
+                    width:'50px',
+                    showOverflowTooltip:true,
+                },
+                {
+                    key:this.$i18nt.locale==='en'?'UnitEn':'Unit',
+                    label:this.$t('Edb.Detail.e_unit'),//单位
+                    width:'50px',
+                    showOverflowTooltip:true,
+                },
+            ]
+        },
+        frequencyArr(){
+            return frequencySelectList()
+        },
+    },
+    data(){
+        return {
+            factorList:[], //多因子系列列表
+            isAddFactorDialogShow:false,
+            addFactorLoading:false,
+            factorData:{
+                SeriesName:'',//因子系列名称
+                CalculateStep:[],//因子系列计算公式
+                EdbMappings:[],//因子系列选择的指标
+                EdbInfoType:0,//选择的指标类型:0指标1预测指标
+            },
+            tableData:[],
+            tableSelectParams:{
+                classify:'',
+                frequency:'',
+                creator:'',
+                keyword:'',
+            },
+            classifyOpt:[],
+            sysUserOpt:[],
+            formulaOpt:[],
+            tableParams:{
+                total:0,
+                pageSize:20,
+                pageNo:1,
+                pagerCount:5,
+                uniqueKey:'EdbInfoId',//数据行的唯一key
+            },
+            tableLoading:false,
+            isIndeterminate:false,//与isCheckAll一起表示列表全选的状态
+            isCheckAll:false,//与isIndeterminate一起表示列表全选的状态
+            isSelectAll:false,//是否勾选了列表全选:为true时,selectList是剔除的指标,为false时selectList是已选择的指标
+        }
+    },
+    methods:{
+        openAddDialog(data){
+            if(data){
+                this.factorData = _.cloneDeep(data)
+            }else{
+                this.factorData = {
+                    SeriesName:'',
+                    CalculateStep:[],
+                    EdbMappings:[],
+                    EdbInfoType:0,
+                }
+            }
+            
+            this.getClassifyOpt()
+            this.getSysUserOpt()
+            this.getFormulaOption()
+            //清空筛选项
+            this.initSelectOpt()
+            this.tableData = []
+            this.isAddFactorDialogShow = true
+        },
+        changeEdbType(){
+            if(this.isAddFactorDialogShow){
+                //若切换指标类型,清空选项
+                this.factorData.SeriesName = ''
+                this.factorData.EdbMappings = []
+                this.factorData.CalculateStep =[]
+                this.getFormulaOption()
+                this.getClassifyOpt()
+            }
+        },
+        initSelectOpt(){
+            this.tableSelectParams = {
+                classify:'',
+                frequency:'',
+                creator:'',
+                keyword:'',
+            }
+            this.tableParams = {
+                total:0,
+                pageSize:20,
+                pageNo:1,
+                pagerCount:5,
+                uniqueKey:'EdbInfoId',//数据行的唯一key
+            }
+            this.isIndeterminate = false
+            this.isCheckAll = false
+            this.listCheckAllChange(false)
+        },
+        async getClassifyOpt(){
+            const res= this.factorData.EdbInfoType===0
+                        ?await dataBaseInterface.menuListV3()
+                        :await preDictEdbInterface.classifyListV2()
+            if (res.Ret !== 200) return
+
+            const filterNodes = (arr)=>{
+                arr.length &&
+                    arr.forEach((item) => {
+                        item.Children.length && filterNodes(item.Children);
+                        if (!item.Children.length) {
+                            delete item.Children;
+                        }
+                    });
+            }
+            filterNodes(res.Data.AllNodes||[]);
+
+            this.classifyOpt = res.Data.AllNodes || [];
+        },
+        async getSysUserOpt(){
+            const res = await departInterence.getQuestionAdminList();
+            if (res.Ret === 200) {
+                this.sysUserOpt = res.Data.List||[];
+            }
+        },
+        async getFormulaOption(){
+            const res = await chartRelevanceApi.getCalculateFormula({
+                EdbInfoType:this.factorData.EdbInfoType
+            })
+            if(res.Ret===200){
+                this.formulaOpt = res.Data||[]
+            }
+        },
+        handleFilter(){
+            this.tableParams.pageNo = 1
+            this.tableData = []
+            this.getTableData()
+        },
+        listCheckAllChange(value){
+            this.isSelectAll = value
+            this.$nextTick(()=>{
+                this.$refs.batchSelectTable&&this.$refs.batchSelectTable.listCheckAllChange(value)
+            })
+        },
+        changeCheckAll({isCheckAll,isIndeterminate}){
+            this.isCheckAll = isCheckAll
+            this.isIndeterminate = isIndeterminate
+        },
+        tablePageChange(page){
+            this.tableParams.pageNo = page
+            this.getTableData('pageChange')
+        },
+        async addSelectData({selectList=[],selectData=[]}){
+            //校验:没选择任何指标
+            if(!this.isCheckAll&&!this.isIndeterminate){
+                return this.$message.warning(this.$t('StatisticAnalysis.ChartRelevance.batch_select_hint'))
+            }
+            //通过接口获取选中的所有指标
+            const {classify,frequency,creator,keyword} = this.tableSelectParams
+            const ClassifyIds = classify?classify.join(','):''
+            const Frequency = frequency?frequency.join(','):''
+            const SysUserIds = creator?creator.join(','):''
+            const res=await dataBaseInterface.getBatchFilterAddEdbList({
+                SysUserIds,ClassifyIds,
+                Keyword:keyword,
+                Frequency,
+                SelectAll:this.isSelectAll,
+                EdbInfoIds:selectList.join(','),
+                EdbInfoType:Number(this.factorData.EdbInfoType||0)
+            })
+            if(res.Ret!==200) return 
+            //去重
+            //const data = this.mergeAndDistinct(selectData,res.Data.SearchItem||[])
+            const data = selectData.concat(res.Data.SearchItem||[]).filter((item,index,self)=>{
+                return index ===self.findIndex(t=>t.EdbInfoId === item.EdbInfoId)
+            })||[]
+            //加入到selectData中
+            this.$refs.batchSelectTable.addSelectData(data)
+            //自动填写指标系列名称
+            if(!this.$refs.batchSelectFormula.formulaForm.SeriesName){
+                this.$refs.batchSelectFormula.formulaForm.SeriesName = selectData[0]?selectData.EdbName:data[0]?data[0].EdbName:''
+            }
+        },
+        async getTableData(type){
+            this.tableLoading=true
+            const {classify,frequency,creator,keyword} = this.tableSelectParams
+            const ClassifyIds = classify?classify.join(','):''
+            const Frequency = frequency?frequency.join(','):''
+            const SysUserIds = creator?creator.join(','):''
+            //没有任何筛选项时不展示数据
+            if(!ClassifyIds&&!Frequency&&!SysUserIds&&!keyword){
+                this.tableLoading = false
+                this.tableData = []
+                this.tableParams.total = 0
+                this.isIndeterminate = false
+                this.isCheckAll = false
+                return 
+            }
+            const res=await dataBaseInterface.getBatchAddEdbSearchList({
+                CurrentIndex:this.tableParams.pageNo,
+                PageSize: this.tableParams.pageSize,
+                SysUserIds,ClassifyIds,Frequency,
+                Keyword:keyword,
+                NotFrequency:'',
+                EdbInfoType:Number(this.factorData.EdbInfoType||0)
+            })
+            this.tableLoading=false
+            if(res.Ret!==200) return 
+
+            this.tableData=res.Data.SearchItem||[]
+            this.tableParams.total=res.Data.Paging.Totals||0
+
+            if(type==='pageChange'){
+                this.$nextTick(()=>{
+                    this.$refs.batchSelectTable.adjustSelection()
+                })
+            }else{
+                this.listCheckAllChange(true)
+            }
+        },
+        async handleAddFactor(){
+            //校验 是否选择了指标
+            //校验 计算公式填写
+            await this.$refs.batchSelectFormula.checkForm()
+            //是否超过100个指标
+            if(!this.checkLimitFactor()){
+                return this.$message.warning('所有因子指标已超过100个,请检查')
+            }
+            this.addFactorIndicators()
+        },
+        checkLimitFactor(){
+            let total = 0
+            //已添加过的因子系列
+            this.factorList.forEach(i=>total += i.EdbMappings.length)
+            //当前要添加的因子系列
+            const selectData = this.$refs.batchSelectTable.selectData
+            if(!this.factorData.SeriesId){
+                total+=selectData.length
+            }else{
+                const currentFactor = this.factorList.find(i=>i.SeriesId===this.factorData.SeriesId)
+                const EdbNum = (currentFactor&&currentFactor.EdbMappings.length)||0
+                total -=EdbNum
+                total+=selectData.length
+            }
+            return total<=100
+        },
+        //格式化因子系列计算方式的格式
+        formattingStep(steps=[],isTrans=true){
+            return isTrans
+                ?steps.map((step,index)=>{ //接口需要的格式
+                    const {formulaType,nNum,alphaValue,Calendar} = step
+                    return {
+                        Sort:index+1,
+                        Source:formulaType,
+                        Formula:(formulaType===15?alphaValue:nNum)+'', //N值取nNum,alpha值取alphaValue
+                        Calendar:formulaType===11?Calendar:'',//超季节性取值,其他为空
+                    }
+                })
+                :steps.map(step=>{ //回显需要的格式
+                    const {Source,Calendar,Formula} = step
+                    return {
+                        formulaType:Source,
+                        nNum:Source===15?1:Formula,
+                        alphaValue:Source===15?Formula:0.5,
+                        Calendar
+                    }
+                })
+        },
+        //格式化因子系列所选指标的格式
+        formattingData(data=[],isTrans=true){
+            return isTrans
+                ?data.map(item=>item.EdbInfoId)
+                :data
+        },
+        async addFactorIndicators(){
+            this.addFactorLoading = true
+            //因子指标系列push
+            const selectData = this.$refs.batchSelectTable.selectData
+            const {SeriesName,CalculateStep} = this.$refs.batchSelectFormula.formulaForm
+            const checkList = checkListChange(
+                this.formattingData(selectData),
+                this.formattingData(this.factorData.EdbMappings),
+            )
+            const checkSteps = checkStepsChange(
+                this.formattingStep(CalculateStep),
+                this.formattingStep(this.factorData.CalculateStep),
+            )
+            let factor = {
+                SeriesName,
+                EdbInfoType:this.factorData.EdbInfoType,
+                Calculates:this.formattingStep(CalculateStep),
+                EdbInfoIds:this.formattingData(selectData),
+                Recalculate:checkList||checkSteps,//是否需要重新计算
+            }
+            //添加 Recalculate必为true
+            //编辑 取factor.Recalculate
+            console.log('check list',checkList)
+            console.log('check steps',checkSteps)
+            const res = this.factorData.SeriesId
+                ?await chartRelevanceApi.editFactorSeries({...factor,SeriesId:this.factorData.SeriesId})
+                :await chartRelevanceApi.addFactorSeries({...factor,Recalculate:true})
+            //计算中...
+            this.addFactorLoading = false
+            if(res.Ret!==200) return 
+            //标记计算失败的指标
+            const calculatFailList = res.Data.Fail
+            const baseEdbMappings = selectData
+            //更新factorList
+            if(!this.factorData.SeriesId){
+                this.factorList.push({
+                    SeriesId:res.Data.SeriesId,//接口返的
+                    SeriesName,
+                    EdbInfoType:this.factorData.EdbInfoType,
+                    CalculateStep:CalculateStep,
+                    EdbMappings:selectData,
+                })
+            }else{
+                const index = this.factorList.findIndex(i=>i.SeriesId===this.factorData.SeriesId)
+                this.factorList.splice(index,1,{
+                    SeriesId:this.factorData.SeriesId,
+                    SeriesName,
+                    EdbInfoType:this.factorData.EdbInfoType,
+                    CalculateStep:CalculateStep,
+                    EdbMappings:selectData,
+                })
+            }
+            //如果需要重新计算 抛出事件外层组件处理
+            if(!this.factorData.SeriesId||factor.Recalculate){
+                this.$emit('checkRecalculate')
+            }
+            this.isAddFactorDialogShow = false
+        },
+        deleteFactorIndicators(index){
+            this.factorList.splice(index,1)
+            this.$emit('checkRecalculate')
+        }
+    },
+    mounted(){
+        this.factorList = this.SeriesList.map(i=>{
+            return {
+                SeriesId:i.SeriesId,
+                SeriesName:i.SeriesName,
+                CalculateStep:this.formattingStep(i.CalculateStep||[],false),
+                EdbMappings:i.EdbMappings||[],
+                EdbInfoType:i.EdbInfoType,
+            }
+        })
+    },
+};
+</script>
+
+<style lang="scss">
+.add-factor-dialog{
+    .dialog-content{
+        height: 70%;
+        overflow-y: auto;
+        .table-select-box{
+            margin-bottom: 15px;
+            display: flex;
+            align-items: center;
+            gap:0 15px;
+            .el-cascader,.el-select{
+                .el-input{
+                    width:100%;
+                }
+            }
+        }
+    }
+    .dialog-footer{
+        text-align:center;
+        margin:30px 0 20px 0;
+    }
+}
+</style>

+ 268 - 0
src/views/chartRelevance_manage/relevance/components/singleIndForm.vue

@@ -0,0 +1,268 @@
+<template>
+    <div class="single-model-form model-form">
+        <!-- 指标A -->
+        <el-form-item 
+            :label="$t('StatisticAnalysis.ChartRelevance.edbTagA')" 
+            prop="EdbInfoIdA" class="select-target">
+            <selectTarget  
+                :defaultId="chartInfoData.EdbInfoList?chartInfoData.EdbInfoList[0].EdbInfoId:''"
+                :defaultOpt="chartInfoData.EdbInfoList?[chartInfoData.EdbInfoList[0]]:[]"
+                :defaultType="chartInfoData.EdbInfoList?chartInfoData.EdbInfoList[0].EdbInfoCategoryType:''"
+                @select="(target)=>handleSelectTarget('EdbInfoIdA',target)"
+            />
+        </el-form-item>
+        <!-- 指标B -->
+        <el-form-item 
+            :label="$t('StatisticAnalysis.ChartRelevance.edbTagB')" 
+            prop="EdbInfoIdB" class="select-target">
+            <selectTarget 
+                :defaultId="chartInfoData.EdbInfoList?chartInfoData.EdbInfoList[1].EdbInfoId:''"
+                :defaultOpt="chartInfoData.EdbInfoList?[chartInfoData.EdbInfoList[1]]:[]" 
+                :defaultType="chartInfoData.EdbInfoList?chartInfoData.EdbInfoList[1].EdbInfoCategoryType:''"
+                @select="(target)=>handleSelectTarget('EdbInfoIdB',target)"
+            />
+        </el-form-item>
+        <!-- 曲线图 -->
+        <div class="form-box">
+            <div class="label-title">{{ $t('Chart.ChartType.spline_name') }}</div>
+            <!-- 时间 -->
+            <el-form-item 
+                :label="$t('StatisticAnalysis.ChartRelevance.time')" 
+                class="flex-form-item">
+                <!-- 时间类型 -->
+                <el-select
+                    style="width:100%"
+                    v-model="infoForm.Curve.DateType"
+                    @change="getPreviewSplineChart"
+                >
+                    <el-option
+                        v-for="item in yearSelector"
+                        :key="item.value"
+                        :label="item.name"
+                        :value="item.value"
+                    />
+                </el-select>
+                <!-- 时间段 -->
+                <date-picker
+                    v-model="infoForm.Curve.Date"
+                    v-show="infoForm.Curve.DateType===5"
+                    style="margin-left:10px;"
+                    type="month"
+                    range
+                    value-type="format"
+                    :placeholder="$t('Chart.choose_time')"
+                    @change="dateChange"
+                />
+            </el-form-item>
+            <!-- 左轴 -->
+            <el-form-item 
+                :label="$t('StatisticAnalysis.ChartRelevance.left_axis')" 
+                class="flex-form-item">
+                <el-input
+                    style=""
+                    :step="1"
+                    type="number"
+                    v-model="infoForm.Curve.LeftMin"
+                    @change="val => { infoForm.Curve.LeftMin=Number(val);changeSplineOption() }"
+                />
+                <span>{{ $t('StatisticAnalysis.ChartRelevance.to') }}</span>
+                <el-input
+                    style=""
+                    :step="1"
+                    type="number"
+                    v-model="infoForm.Curve.LeftMax"
+                    @change="val => { infoForm.Curve.LeftMax=Number(val);changeSplineOption() }"
+                />
+            </el-form-item>
+            <!-- 右轴 -->
+            <el-form-item 
+                :label="$t('StatisticAnalysis.ChartRelevance.right_axis')" 
+                class="flex-form-item">
+                <el-input
+                    style=""
+                    :step="1"
+                    type="number"
+                    v-model="infoForm.Curve.RightMin"
+                    @change="val => { infoForm.Curve.RightMin=Number(val);changeSplineOption() }"
+                />
+                <span>{{ $t('StatisticAnalysis.ChartRelevance.to') }}</span>
+                <el-input
+                    style=""
+                    :step="1"
+                    type="number"
+                    v-model="infoForm.Curve.RightMax"
+                    @change="val => { infoForm.Curve.RightMax=Number(val);changeSplineOption() }"
+                />
+            </el-form-item>
+            <!-- 指标B -->
+            <el-form-item 
+                :label="$t('StatisticAnalysis.ChartRelevance.edbTagB')" >
+                <el-checkbox v-model="infoForm.Curve.IsOrder"  @change="getPreviewSplineChart" style="width:100%">
+                    {{ $t('StatisticAnalysis.ChartRelevance.reverse_sequence') }}
+                </el-checkbox>
+                <div class="edb-type-box">
+                    <el-radio
+                        v-model="infoForm.Curve.EdbInfoType"
+                        :label="true"
+                        style="margin-right:10px;"
+                        @change="getPreviewSplineChart">
+                        {{ $t('StatisticAnalysis.ChartRelevance.standard_index') }}
+                    </el-radio>
+                    <el-radio
+                        v-model="infoForm.Curve.EdbInfoType"
+                        :label="false"
+                        style="margin-right:10px;"
+                        @change="getPreviewSplineChart">
+                        {{ $t('StatisticAnalysis.ChartRelevance.leading_indicator') }}
+                    </el-radio>
+                </div>
+                <div class="edb-type-lead-box" style="text-align: right;" v-if="!infoForm.Curve.EdbInfoType">
+                    <span>{{ $t('StatisticAnalysis.ChartRelevance.lead_tag') }}</span>
+                    <el-input
+                        style="width: 60px"
+                        size="mini"
+                        type="number"
+                        v-model="infoForm.Curve.LeadValue"
+                        @change="(val) => { infoForm.Curve.LeadValue = Number(val);getPreviewSplineChart()}"
+                    ></el-input>
+                    <el-select
+                        v-model="infoForm.Curve.LeadUnit"
+                        placeholder=""
+                        size="mini"
+                        style="width: 60px"
+                        @change="getPreviewSplineChart">
+                        <el-option
+                            v-for="item in dayOpt"
+                            :key="item.val"
+                            :label="item.label"
+                            :value="item.val"
+                        />
+                    </el-select>
+                </div>
+            </el-form-item>
+        </div>
+        <!-- 相关性 -->
+        <div class="form-box">
+            <div class="label-title">{{ $t('Chart.ChartType.correlation_name') }}</div>
+            <el-form-item 
+                :label="$t('StatisticAnalysis.ChartRelevance.calculation_window')" 
+                prop="Correlation.CalculateValue" class="flex-form-item">
+                <el-input
+                    style="flex:2"
+                    :step="1"
+                    type="number"
+                    v-model="infoForm.Correlation.CalculateValue"
+                    @change="val => { infoForm.Correlation.CalculateValue = Number(val); }"
+                />
+                <el-select
+                        style="flex:2"
+                        v-model="infoForm.Correlation.CalculateUnit"
+                >
+                    <el-option
+                        v-for="item in dayOpt"
+                        :key="item.val"
+                        :label="item.label"
+                        :value="item.val"
+                    />
+                </el-select>
+            </el-form-item>
+            <el-form-item 
+                :label="$t('StatisticAnalysis.ChartRelevance.analysis_cycle')" 
+                prop="Correlation.LeadValue" class="flex-form-item">
+                <el-input
+                    style="flex:2"
+                    :step="1"
+                    type="number"
+                    v-model="infoForm.Correlation.LeadValue"
+                    @change="val => { infoForm.Correlation.LeadValue = Number(val); }"
+                />
+                <el-select
+                    style="flex:2"
+                    v-model="infoForm.Correlation.LeadUnit">
+                    <el-option
+                        v-for="item in dayOpt"
+                        :key="item.val"
+                        :label="item.label"
+                        :value="item.val"
+                    />
+                </el-select>
+            </el-form-item>
+        </div>
+        <!-- 滚动相关性 -->
+        <div class="form-box" v-for="(item,index) in infoForm.RollingCorrelation" :key="index">
+            <div class="label-title">{{  $t('Chart.ChartType.rolling_correlation_name') }} {{ index+1 }}</div>
+            <el-form-item 
+                :label="$t('StatisticAnalysis.ChartRelevance.calculation_window')" 
+                class="flex-form-item">
+                <el-input
+                    style="flex:2"
+                    :step="1"
+                    type="number"
+                    v-model="item.CalculateValue"
+                    @change="val => { item.CalculateValue = Number(val); }"
+                />
+                <el-select
+                    style="flex:2"
+                    v-model="item.CalculateUnit">
+                    <el-option
+                        v-for="item in dayOpt"
+                        :key="item.val"
+                        :label="item.label"
+                        :value="item.val"
+                    />
+                </el-select>
+            </el-form-item>
+            <el-form-item 
+                :label="$t('StatisticAnalysis.ChartRelevance.B_leads_A')" 
+                class="flex-form-item">
+                <el-input
+                    style="flex:2"
+                    :step="1"
+                    type="number"
+                    v-model="item.LeadValue"
+                    @change="val => { item.LeadValue = Number(val); }"
+                />
+                <el-select
+                    style="flex:2"
+                    v-model="item.LeadUnit">
+                    <el-option
+                        v-for="item in dayOpt"
+                        :key="item.val"
+                        :label="item.label"
+                        :value="item.val"
+                    />
+                </el-select>
+            </el-form-item>
+        </div>
+    </div>
+</template>
+
+<script>
+import formMixin from './formMixin';
+export default {
+    mixins:[formMixin],
+    methods:{
+        dateChange(val){
+            this.infoForm.Curve.DateType = 5
+            if(val[0]) {
+                this.infoForm.Curve.StartDate = val[0];
+                this.infoForm.Curve.EndDate = val[1];
+            }else {
+                this.infoForm.Curve.StartDate = '';
+                this.infoForm.Curve.EndDate = '';
+            }
+            this.getPreviewSplineChart()
+        },
+        getPreviewSplineChart(){
+            this.$emit('previewChart')
+        },
+        changeSplineOption(){
+            this.$emit('changeSpline')
+        },
+    }
+};
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 294 - 23
src/views/chartRelevance_manage/relevance/list.vue

@@ -68,8 +68,9 @@
             :default-expanded-keys="defaultShowNodes"
             draggable
             :expand-on-click-node="false"
-            check-strictly
             empty-text="暂无分类"
+            lazy
+            :load="getLazyTreeData"
             @node-expand="handleNodeExpand"
             @node-collapse="handleNodeCollapse"
             @current-change="nodeChange"
@@ -95,6 +96,7 @@
                 :style="`width:${
                   (select_node === data.UniqueCode && node.Nodewidth) || ''
                 }`"
+                :id="`node${data.UniqueCode}`"
               >
                 <span>{{ currentLang==='en' ? (data.ChartClassifyNameEn||data.ChartClassifyName) : data.ChartClassifyName  }}</span>
               </span>
@@ -106,6 +108,15 @@
                   src="~@/assets/img/data_m/move_ico.png"
                   alt=""
                   style="width: 14px; height: 14px; margin-right: 8px"
+                  v-if="permissionBtn.isShowBtn('statisticPermission','corrAnalysis_classifyOpt_move')"
+                />
+                <!-- 添加子项 -->
+                <img
+                    src="~@/assets/img/set_m/add.png"
+                    alt=""
+                    style="width: 14px; height: 14px; margin-right: 8px"
+                    @click.stop="addNode(node,data)"
+                    v-if="data.Button.AddButton&&node.level<6"
                 />
                 <img
                   src="~@/assets/img/set_m/edit.png"
@@ -167,6 +178,9 @@
                     ref="chartRef"
                   />
                 </div>
+                <span class="chart-source" v-if="chartInfo.SourcesFrom.isShow&&chartInfo.SourcesFrom.text">
+                    数据来源:{{ chartInfo.SourcesFrom.text }}
+                </span>
                 <span class="chart-author"
                   >{{$t('MsgPrompt.author')}}:{{ chartInfo.SysUserRealName }}</span
                 >
@@ -262,7 +276,7 @@
           :total="chart_total" 
           :list="chartList" 
           @loadMoreHandle="loadMoreHandle"
-          @detailShowHandle="detailShowHandle"
+          @detailShowHandle="handleShowChartDetail"
           @addMychartHandle="addMychartHandle"
           ref="chartListWrap"
         />
@@ -270,11 +284,18 @@
     </div>
 
     <!-- 分类弹窗 -->
-    <classify-dia
+    <!-- <classify-dia
       :isOpenDialog.sync="classifyDia"
       :title="dialog_title"
       :form="classifyForm"
       @successCallback="getTreeData"
+    /> -->
+    <modifyClassifyDialog
+      :isOpenDialog.sync="classifyDia"
+      :type="classifyDiaType"
+      :formData="classifyForm"
+      @sucessCallback="sucessCallback"
+      @closeDia="classifyDia = false"
     />
 
     <!-- 加入我的图库弹窗 -->
@@ -319,12 +340,14 @@ import leftMixin from "../mixins/classifyMixin";
 import Chart from "@/views/dataEntry_manage/components/chart";
 import changeLang from "@/views/dataEntry_manage/components/changeLang.vue";
 import classifyDia from "@/views/datasheet_manage/components/sheetClassifyDia.vue";
+import modifyClassifyDialog from './components/modifyClassifyDialog.vue'
 import addMyClassifyDia from "@/views/dataEntry_manage/components/addMyClassifyDia";
 import SaveChartOther from "@/views/dataEntry_manage/components/SaveChartOther";
 import setEnNameDia from "@/views/dataEntry_manage/components/setEnNameDia.vue";
 import { chartSetMixin } from "@/views/dataEntry_manage/mixins/chartPublic";
 import { copyOtherOptions } from '@/utils/defaultOptions';
 import setLangInfoDia from '@/views/dataEntry_manage/components/setLangInfo.vue'
+import { baseSourcesFrom } from './utils/config'
 export default {
   components: {
     changeLang,
@@ -333,7 +356,8 @@ export default {
     addMyClassifyDia,
     SaveChartOther,
     setEnNameDia,
-    setLangInfoDia
+    setLangInfoDia,
+    modifyClassifyDialog
   },
   mixins: [leftMixin, chartSetMixin],
   computed: {
@@ -359,11 +383,12 @@ export default {
       defaultProp: {
         label: "ChartClassifyName",
         children: "Children",
+        isLeaf:'isLeaf'
       }, //树结构配置项
       dynamicNode: null,
 
       /* 分类弹窗 */
-      dialog_title: "",
+      classifyDiaType: "add",//add or edit
       classifyDia: false, //
       classifyForm: {},
 
@@ -392,10 +417,196 @@ export default {
     };
   },
   methods: {
+    /* 判断节点是否能被拖拽 */
+    canDragHandle({data}) {
+        return data.Button.MoveButton&&this.permissionBtn.isShowBtn('statisticPermission','corrAnalysis_classifyOpt_move');
+    },
+    /* 判断节点是否能被拖入 */
+    canDropHandle(draggingNode, dropNode, type) {
+        let canDrop=false
+        
+        // 如果拖动的是图表
+        if(draggingNode.data.ChartInfoId){
+            if(!(dropNode.level===1&&type!=='inner')){
+                canDrop=true
+            }
+        }else{//拖动的是目录
+            //目录层级不能改变
+            if((dropNode.level+1==draggingNode.level&&type==='inner'&&!dropNode.data.ChartInfoId)||(dropNode.level===draggingNode.level&&type!=='inner')){
+                canDrop=true
+            }
+        }
+        return canDrop
+    },
+    /* 拖拽完成 */
+    dropOverHandle(b,a,i,e) {
+        // 被拖拽节点对应的 Node、结束拖拽时最后进入的节点、被拖拽节点的放置位置
+        const isChart=b.data.ChartInfoId?true:false
+        let list=a.parent.childNodes;
+        let targetIndex=0
+        let ClassifyId=0,//分类ID,若当前节点为图表,则为0
+        ParentClassifyId=0,//移动后,所在位置的父级分类ID
+        PrevClassifyId=0,//前一个节点的分类ID,若前一个节点为图表,则为0
+        NextClassifyId=0,//后一个节点的分类ID,同上
+        ChartInfoId=0,//图表ID,若当前节点为分类,则为0
+        PrevChartInfoId=0,//前一个节点的图表ID,若前一个节点为分类,则为0
+        NextChartInfoId=0;//后一个节点的图表ID
+
+        ClassifyId=isChart?0:b.data.ChartClassifyId
+        ChartInfoId=isChart?b.data.ChartInfoId:0
+        
+
+        if(i!=='inner'){
+            ParentClassifyId=a.parent.data.ChartClassifyId||0
+            list.forEach((item,index)=>{
+                if(isChart){
+                    if(item.data.ChartInfoId===b.data.ChartInfoId){
+                        targetIndex=index
+                    }
+                }else{
+                    if(item.data.ChartClassifyId===b.data.ChartClassifyId){
+                        targetIndex=index
+                    }
+                }
+            })
+
+            console.log(targetIndex);
+            
+            
+            if(targetIndex===0){
+                const data=list[targetIndex+1].data
+                NextClassifyId=data.ChartInfoId?0:data.ChartClassifyId
+                NextChartInfoId=data.ChartInfoId?data.ChartInfoId:0
+            }else if(targetIndex===list.length-1){
+                const data=list[targetIndex-1].data
+                PrevClassifyId=data.ChartInfoId?0:data.ChartClassifyId
+                PrevChartInfoId=data.ChartInfoId?data.ChartInfoId:0
+            }else{
+                const pData=list[targetIndex-1].data
+                PrevClassifyId=pData.ChartInfoId?0:pData.ChartClassifyId
+                PrevChartInfoId=pData.ChartInfoId?pData.ChartInfoId:0
+
+                const nData=list[targetIndex+1].data
+                NextClassifyId=nData.ChartInfoId?0:nData.ChartClassifyId
+                NextChartInfoId=nData.ChartInfoId?nData.ChartInfoId:0
+            }
+        }else{
+            ParentClassifyId=a.data.ChartClassifyId||0
+        }
+
+        const params={
+            ClassifyId,
+            ParentClassifyId,
+            PrevClassifyId,
+            NextClassifyId,
+            ChartInfoId,
+            PrevChartInfoId,
+            NextChartInfoId
+        }
+        console.log(params);
+        chartRelevanceApi.classifyMove(params).then(res=>{
+            if(res.Ret===200){
+                // this.$message.success('移动成功!')
+                this.$message.success(this.$t('MsgPrompt.move_sort_success'))
+            }
+            this.getTreeData()
+            if(this.select_id){
+                this.getDetailHandle();
+            }
+            
+        })
+    },
+
+    /* 拖拽覆盖添加背景色 */
+    dropMouseOver(node1,node2,e) {
+        // console.log(e.layerY);
+        
+        // 被拖拽节点对应的 Node、所进入节点对应的 Node、event
+        if(!node2.data.EdbInfoId&&(node1.level>node2.level||(node1.data.EdbInfoId>0&&!node2.data.EdbInfoId)) && (e.target.childNodes[0].className.includes('el-tree-node__content') 
+        || e.target.className.includes('el-tree-node__content'))) {
+            // console.log(e.target.childNodes[0])
+            e.target.childNodes[0].className.includes('el-tree-node__content') 
+            ? e.target.childNodes[0].style.backgroundColor = '#409eff' 
+            : e.target.style.backgroundColor = '#409eff';
+        }
+        
+    },
+    /* 拖拽离开/拖拽完成重置背景色 */
+    dropMouseLeave(node1,node2,e) {
+        let arrs = $('.el-tree-node__content');
+        for( let a of arrs ) {
+            a.style.backgroundColor = 'transparent';
+        }
+    },
+    sucessCallback(type){
+        this.classifyDia = false;
+        this.getTreeData();
+        if(type === 'add') {
+            //新增分类完成之后,展开父节点显示刚新增的分类,若已展开节点则不做处理
+            let code = sessionStorage.getItem('expandCode');
+            let flag = 	this.defaultShowNodes.some((item) => {
+                return item === code
+            });
+            !flag &&code&& this.defaultShowNodes.push(code);
+            sessionStorage.removeItem('expandCode');
+        }
+    },
+    // 递归节点
+    getNodeParentData(data,arr){
+        if(data.level===0) return
+        arr.push({classifyName:this.currentLang==='en'?data.data.ChartClassifyNameEn:data.data.ChartClassifyName,classifyId:data.data.ChartClassifyId})
+        this.getNodeParentData(data.parent,arr)
+        return arr
+    },
+    addNode(node,data){
+        this.classifyDiaType = 'add';
+        let arr=[]
+        arr=this.getNodeParentData(node,arr)
+        /* 添加目录 */
+        this.classifyForm = {
+            parentArr:arr,
+            parent_id: data.ChartClassifyId,
+            level: node.level,
+            levelVal:'',
+            nodeId:'',
+        }
+        //存储当前要新增子级的目录code
+        sessionStorage.setItem('expandCode', data.UniqueCode);
+        this.classifyDia = true;
+    },
+    //绑定el-tree的load属性
+    async getLazyTreeData (node,resolve){
+        if(node.level===0){
+            resolve(this.treeData)
+        }else{
+            let arr=[]
+            const res=await chartRelevanceApi.classifyList({
+                ParentId:node.data.ChartClassifyId,
+                IsShowMe:this.isOnlyMe,
+                Source: this.classify_tab ? 4 : 3})
+            if (res.Ret === 200) {
+                const temarr = res.Data.AllNodes || [];
+                arr=temarr.map(item=>{
+                    return {
+                        ...item,
+                        isLeaf:item.ChartInfoId?true:false
+                    }
+                })
+            }
+            resolve(arr)
+        }
+    },
+    //展开选中图表父级,选中选择图表
+    handleShowChartDetail({ UniqueCode, ChartInfoId }){
+        this.select_classify = 0;
+        this.select_id = ChartInfoId;
+        this.select_node = UniqueCode;
+    },
     /* 添加图表 */
     goAddChart() {
       if (!this.treeData.length) return this.$message.warning("请先添加分类");
-      this.$router.push({ path: "/relevancechartEditor" });
+      //this.$router.push({ path: "/relevancechartEditor" });
+      this.$router.push({ path: "/relevancechartEditorV2" });
     },
 
     /* 获取分类 */
@@ -410,10 +621,20 @@ export default {
           if (Ret !== 200) return;
 
           this.showData = true;
-          this.treeData = Data.AllNodes || [];
+          //this.treeData = Data.AllNodes || [];
+          this.treeData = Data.AllNodes?Data.AllNodes.map(d=>{
+            return {
+                ...d,
+                Children:[]
+            }
+          }):[]
           this.$nextTick(() => {
             /* 新增完成后 处理树展开和选中 */
-            params && this.selectCurrentNode(params);
+            //params && this.selectCurrentNode(params);
+            if(params){
+                this.select_node = params.code;
+                this.select_id = params.id;
+            }
           });
         });
     },
@@ -471,29 +692,33 @@ export default {
       this.search_txt = "";
       this.select_node = UniqueCode;
       this.select_classify = !ChartInfoId ? ChartClassifyId : 0;
-      // if(this.select_id !== ChartInfoId) {
       this.select_id = ChartInfoId || 0;
-      // }
       this.resetNodeStyle(node);
       this.dynamicNode = node;
     },
 
     /* 添加一级目录 */
     addLevelOneHandle() {
-      this.dialog_title = this.$t('StatisticAnalysis.ChartRelevance.add_chart_classify')||"添加图表分类";
-      this.classifyForm = {
-        classify_name: "",
-      };
-      this.classifyDia = true;
+        this.classifyDiaType = 'add';
+        this.classifyForm = {
+            parent_id: 0,
+            level: 0,
+            levelVal:'',
+        };
+        this.classifyDia = true;
     },
 
     /* 编辑节点 */
     editNode(node, { ChartClassifyName,ChartClassifyNameEn, ChartClassifyId }) {
-      this.dialog_title = this.$t('StatisticAnalysis.ChartRelevance.edit_chart_classify')||"编辑图表分类";
+      this.classifyDiaType = 'edit'
+      let arr=[]
+      arr=this.getNodeParentData(node.parent,arr)
       /* 编辑目录 */
       this.classifyForm = {
-        classify_name: this.currentLang==='en'?ChartClassifyNameEn:ChartClassifyName,
-        classify_id: ChartClassifyId,
+        parentArr:arr,
+        level:node.level,
+        levelVal: this.currentLang==='en'?ChartClassifyNameEn:ChartClassifyName,
+        nodeId: ChartClassifyId,
       };
       this.classifyDia = true;
     },
@@ -520,7 +745,13 @@ export default {
           }).then(() => {
             this.delApi(ChartClassifyId, ChartInfoId);
           })
-        : null;
+        : DeleteStatus===2
+        ? this.$confirm(this.$t('Edb.MsgPrompt.del_confirm_menu_or_children'),this.$t('Confirm.prompt'),{
+            type:"warning",
+        }).then(()=>{
+            this.delApi(ChartClassifyId, ChartInfoId);
+        })
+        :null;
     },
 
     /* 删除方法 */
@@ -618,10 +849,21 @@ export default {
         })
         .then((res) => {
           if (res.Ret !== 200) return;
-
           this.chartInfo = res.Data.ChartInfo;
           this.tableData = res.Data.EdbInfoList;
+          this.defaultShowNodes = res.Data.ClassifyLevels||[];
+          this.$nextTick(()=>{
+            setTimeout(() => {
+                this.$refs.treeRef.setCurrentKey(this.select_node);
+            }, 1200);
+          })
           if(this.chartInfo.Source === 3) {
+            const SourcesFrom = this.chartInfo.SourcesFrom
+            try{
+                this.chartInfo.SourcesFrom = SourcesFrom?JSON.parse(SourcesFrom):baseSourcesFrom
+            }catch(e){
+                this.chartInfo.SourcesFrom = baseSourcesFrom
+            }
             this.relevanceChartData = {
               ChartInfo: res.Data.ChartInfo,
               EdbInfoList: res.Data.EdbInfoList,
@@ -630,12 +872,16 @@ export default {
               YDataList: [
                 {
                   Value: res.Data.YDataList[0].Value,
-                  Color: "#00f",
+                  Color: res.Data.YDataList[0].Color,
                   Name: res.Data.ChartInfo.ChartName,
                   NameEn: res.Data.ChartInfo.ChartNameEn
                 },
               ],
             };
+            //多因子
+            if(res.Data.CorrelationChartInfo.AnalysisMode===1){
+                this.relevanceChartData.YDataList = res.Data.YDataList
+            }
             this.initRelevanceChartData() 
           }else if(this.chartInfo.Source === 4) { //滚动相关性逻辑又换成曲线了
             this.relevanceChartData = {
@@ -643,7 +889,25 @@ export default {
             }
             this.setDefaultChart([res.Data.DataResp]);
           }
-          
+          this.$nextTick(()=>{
+                const _node = this.$refs.treeRef.getNode(this.select_node)
+                this.dynamicNode = _node;
+                this.dynamicNode&&this.resetNodeStyle(this.dynamicNode)
+                setTimeout(() => {
+                    let node = document.getElementById(`node${this.select_node}`)||{}
+                    let parent = document.getElementsByClassName('tree-cont')[0];
+                    //parent可视区间:[scrollTop,scrollTop+offsetHeight]
+                    //node位置:node.offsetTop
+                    const overTop = node.offsetTop+node.clientHeight+30<parent.scrollTop
+                    const overBottom = node.offsetTop+node.clientHeight+30>parent.scrollTop+parent.offsetHeight
+                    if(overTop){
+                        parent.scrollTop = node.offsetTop-60
+                    }
+                    if(overBottom){
+                        parent.scrollTop =  node.offsetTop - parent.offsetHeight/2
+                    }
+                },1500)
+            })
         });
     },
 
@@ -685,11 +949,18 @@ export default {
 
     /* 编辑图表 */
     editChartHandle() {
-      this.$router.push({
+      /* this.$router.push({
         path: "/relevancechartEditor",
         query: {
           code: this.chartInfo.UniqueCode,
         },
+      }); */
+      this.$router.push({
+        path: "/relevancechartEditorV2",
+        query: {
+          code: this.chartInfo.UniqueCode,
+          type:this.relevanceChartData.CorrelationChartInfo.AnalysisMode
+        },
       });
     },
 

+ 1089 - 0
src/views/chartRelevance_manage/relevance/relevanceChartEditorV2.vue

@@ -0,0 +1,1089 @@
+<template>
+    <div class="relevance-chart-editor-wrap" v-loading="previewMatrixLoading" element-loading-text="正在计算相关性矩阵...">
+        <div class="info-wrap content-wrap">
+            <div class="info-top">
+                <el-button type="primary" @click="previewChart">{{$t('Dialog.calculate_btn')}}</el-button>
+                <el-button type="primary" plain @click="$router.back()">{{$t('Dialog.cancel_btn')}}</el-button>
+                <!-- 操作说明 -->
+                <span @click="showExplain = true">
+                    <img style="width:15px;height:15px;" src="~@/assets/img/icons/formula-add.png" alt="">
+                    {{$t('StatisticAnalysis.ChartRelevance.opt_tip_btn')}}
+                </span>
+            </div>
+            <div class="info-form-wrap">
+                <el-form :model="infoForm" :rules="infoRules" label-width="80px" ref="infoFormRef">
+                    <!-- 分析模式 -->
+                    <el-form-item 
+                        :label="$t('StatisticAnalysis.ChartRelevance.analytical_model')" 
+                        prop="Model" required>
+                        <el-select v-model="infoForm.Model" style="width: 100%;" 
+                        :disabled="$route.query.code||isMultipleChartAdd||buttonAuth.isRelevanceChartAdd"
+                        @change="changeModel">
+                            <el-option :label="$t('StatisticAnalysis.ChartRelevance.single_indicator')" :value="1"></el-option>
+                            <el-option :label="$t('StatisticAnalysis.ChartRelevance.multiple_indicators')" :value="2"></el-option>
+                        </el-select>
+                    </el-form-item>
+                    <!-- 单因子模式需要填的 -->
+                    <singleIndForm
+                        v-if="infoForm.Model===1"
+                        :info-form="infoForm"
+                        :chart-info-data="chartInfoData"
+                        @selectTarget="handleSelectTarget"
+                        @previewChart="getPreviewSplineChart"
+                        @changeSpline="changeSplineOption"
+                    ></singleIndForm>
+                    <!-- 多因子模式需要填的 -->
+                    <multipleIndForm
+                        v-if="infoForm.Model===2"
+                        ref="multipleIndForm"
+                        :info-form="infoForm"
+                        :isMultipleChartAdd="isMultipleChartAdd"
+                        :chart-info-data="chartInfoData"
+                        :SeriesList="SeriesList"
+                        @selectTarget="handleSelectTarget"
+                        @checkRecalculate="checkRecalculate"
+                    ></multipleIndForm>
+                </el-form>
+            </div>
+        </div>
+        <div class="model-wrap">
+            <!-- 单因子模式 -->
+            <div class="single-model-wrap" v-if="infoForm.Model===1">
+                <div
+                    class="chart-min-cont"
+                    v-if="chartBatchData"
+                >
+                    <!-- 曲线图 -->
+                    <div class="card-wrapper content-wrap">
+                        <chartCard 
+                            :entryType="1"
+                            ref="chartCard1"
+                            :data="chartBatchData.CurveData"
+                            :settings="infoForm"
+                            :isChartAdd="buttonAuth.isCurveChartAdd"
+                            @saveChart="(params)=>{handleSave(params);isSaveChartToBase = true;}"
+                            @saveEdb="(params)=>{handleSave(params);isSaveEdbToBase = true;}"
+                        />
+                    </div>
+                    <!-- 相关性图表 -->
+                    <div class="card-wrapper content-wrap" v-if="chartBatchData.CorrelationData">
+                        <chartCard 
+                            :entryType="2"
+                            ref="chartCard2"
+                            :data="chartBatchData.CorrelationData"
+                            :settings="infoForm"
+                            :isChartAdd="buttonAuth.isRelevanceChartAdd"
+                            :isChartSetting="true"
+                            @chartSettingChange="handleChangeChartSetting"
+                            @saveChart="(params)=>{handleSave(params);isSaveChartToBase = true;}"
+                            @saveEdb="(params)=>{handleSave(params);isSaveEdbToBase = true;}"
+                        />
+                        <!-- 图表数据来源 -->
+                        <div class="source" v-if="chartBatchData.SourcesFrom.text&&chartBatchData.SourcesFrom.isShow">
+                            {{ $t('Edb.Detail.source') }}:{{ chartBatchData.SourcesFrom.text }}
+                        </div>
+                    </div>
+                    <!-- 滚动相关性1 -->
+                    <template v-if="chartBatchData.RollingCorrelationData">
+                        <div class="card-wrapper content-wrap" v-if="chartBatchData.RollingCorrelationData[0]">
+                            <chartCard 
+                                :entryType="3"
+                                ref="chartCard3"
+                                :data="chartBatchData.RollingCorrelationData[0]"
+                                :settings="infoForm"
+                                :isChartAdd="buttonAuth.isRollChartAdd"
+                                :isEdbAdd="buttonAuth.isRollEdbAdd"
+                                @saveChart="(params)=>{handleSave(params);isSaveChartToBase = true;}"
+                                @saveEdb="(params)=>{handleSave(params);isSaveEdbToBase = true;}"
+                            />
+                        </div>
+                        <!-- 滚动相关性2 -->
+                        <div class="card-wrapper content-wrap" v-if="chartBatchData.RollingCorrelationData[1]">
+                            <chartCard 
+                                :entryType="4"
+                                ref="chartCard4"
+                                :data="chartBatchData.RollingCorrelationData[1]"
+                                :settings="infoForm"
+                                :isChartAdd="buttonAuth.isRollChartTwoAdd"
+                                :isEdbAdd="buttonAuth.isRollEdbTwoAdd"
+                                @saveChart="(params)=>{handleSave(params);isSaveChartToBase = true;}"
+                                @saveEdb="(params)=>{handleSave(params);isSaveEdbToBase = true;}"
+                            />
+                        </div>
+                    </template>
+                </div>
+
+                <div class="nodata" v-else>
+                    <tableNoData text="暂无信息"/>
+                </div>
+            </div>
+            <!-- 多因子模式 -->
+            <div class="multiple-model-wrap" v-if="infoForm.Model===2">
+                <!-- 相关性矩阵表格 -->
+                <div class="relevant-matrix-table-box" v-if="factorTableData.length">
+                    <el-table style="width: 100%;" height="100%" :data="factorTableData" :row-class-name="getTableRowClassname" @sort-change="sortChange">
+                        <el-table-column 
+                            fixed
+                            :label="$t('StatisticAnalysis.ChartRelevance.multiple_table_head_01')"
+                            width="220px"
+                            align="center"
+                            class-name="zip-cell"
+                            >
+                            <el-table-column
+                                width="80px" align="center"
+                                class-name="zip-cell"
+                                :label="$t('Edb.Detail.e_opera')">
+                               <template slot-scope="{row}">
+                                    <template v-if="row.isSuccess">
+                                        <span style="color:#0052D9;cursor: pointer;" @click="addCurve(row)" v-if="!row.isAdd">{{$t('StatisticAnalysis.ChartRelevance.multiple_table_btn_add')}}</span>
+                                        <span style="color:#D54941;cursor: pointer;" @click="deleteCurve(row)" v-else>{{$t('StatisticAnalysis.ChartRelevance.multiple_table_btn_del')}}</span>
+                                    </template>
+                               </template>
+                            </el-table-column>
+                            <el-table-column
+                                width="140px" align="center"
+                                class-name="zip-cell"
+                                show-overflow-tooltip
+                                prop="EdbName"
+                                :label="$t('StatisticAnalysis.ChartRelevance.multiple_table_head_02')">
+                            </el-table-column>
+                        </el-table-column>
+                        <!-- 领先天数 -->
+                        <el-table-column
+                            v-if="SortedArray.length"
+                            class-name="zip-cell"
+                            :label="LeadLabelName">
+                            <el-table-column v-for="(num,index) in SortedArray" :key="num"
+                                min-width="45px"
+                                sortable="custom"
+                                prop="LeadValue"
+                                align="center"
+                                class-name="zip-cell"
+                                :label="num">
+                                <template slot-scope="{row}">
+                                    {{ row.dataList[index] }}
+                                </template>
+                            </el-table-column>
+                        </el-table-column>
+                    </el-table>
+                </div>
+                <!-- 相关性图表 -->
+                <div class="relevant-chart-box content-wrap" v-if="showMultipleChart">
+                    <chartCard
+                        ref="chartCard2"
+                        :data="multipleChartData"
+                        :settings="infoForm"
+                        :entryType="2"
+                        :isChartSetting="true"
+                        :isChartAdd="isMultipleChartAdd"
+                        height="300"
+                        @handleEdit="saveMultipleChart"
+                        @saveChart="(params)=>{handleSave(params);isSaveChartToBase = true;}"
+                        @saveEdb="(params)=>{handleSave(params);isSaveEdbToBase = true;}"
+                        @chartSettingChange="handleChangeChartSetting"
+                    />
+                    <!-- 数据来源 -->
+                    <div class="source" v-if="multipleChartData.SourcesFrom.text&&multipleChartData.SourcesFrom.isShow">
+                        {{ $t('Edb.Detail.source') }}:{{ multipleChartData.SourcesFrom.text }}
+                    </div>
+                </div>
+
+                <div class="nodata" v-if="!factorTableData.length">
+                    <tableNoData :text="$t('Common.no_info_msg')"/>
+                </div>
+            </div>
+        </div>
+        <!-- 图表保存/另存为 -->
+        <saveChartToBase
+            :isShow.sync="isSaveChartToBase"
+            :source="saveSource"
+            :saveScence="saveScence"
+            :chartData="chartData"
+            @saveBack="saveChartBack"
+            @handleSave="saveMultipleChart"
+        />
+
+        <!-- 指标保存/另存为 -->
+        <saveEdbToBase
+            :isShow.sync="isSaveEdbToBase"
+            :source="saveSource"
+            :saveScence="saveScence"
+            :chartData="chartData"
+            @saveBack="saveEdbBack"
+        />
+        <!-- 图例设置 -->
+        <saveChartSetting
+            :isSettingChartShow="isSettingChartShow"
+            :settingData="settingData"
+            @saveChartSetting="changeChartSettingBack"
+            @close="isSettingChartShow = false"
+        />
+        <!-- 操作说明 -->
+        <ExplainDialog 
+            :show-explain="showExplain"
+            @close="showExplain = false"
+        />
+    </div>
+</template>
+
+<script>
+/* api */
+import { dataBaseInterface } from '@/api/api.js'
+import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js'
+import chartRelevanceApi from '@/api/modules/chartRelevanceApi'
+import {etaBaseConfigInterence} from '@/api/modules/etaBaseConfigApi.js';
+
+/*components */
+import selectTarget from '../components/selectTarget.vue'
+import singleIndForm from './components/singleIndForm.vue'
+import multipleIndForm from './components/multipleIndForm.vue'
+import chartCard from '../components/chartCard.vue'
+import saveChartToBase from '../components/saveChartTobaseDia.vue'
+import saveEdbToBase from '../components/saveEdbToBaseDia.vue'
+import saveChartSetting from './../components/saveChartSetting.vue'
+import ExplainDialog from '../components/explainDialog.vue'
+/* utils */
+import {generateSortedArray,generateXEdbValue,generateYDataValue} from './utils/index'
+import { baseForm, baseChartInfo,baseSourcesFrom } from './utils/config'
+export default {
+    components:{
+        selectTarget, singleIndForm, multipleIndForm,
+        chartCard,saveChartToBase,saveEdbToBase,saveChartSetting,
+        ExplainDialog
+    },
+    data() {
+        return {
+            typeModel:0,
+            infoForm:_.cloneDeep(baseForm),
+            chartInfoData: {},//单因子指标信息,新增时为空,编辑时有值,用于回显selectTarget,多因子取第一项
+            chartBatchData:null,//单因子图表信息
+            buttonAuth: { //单因子图表按钮控制
+                isCurveChartAdd: false,
+                isRelevanceChartAdd: false,
+                isRollChartAdd: false,
+                isRollEdbAdd: false,
+                isRollChartTwoAdd: false,
+                isRollEdbTwoAdd: false,
+            },
+            isMultipleChartAdd:false,//多因子图表按钮控制
+            SeriesList:[],//多因子系列列表,编辑时有值
+            SortedArray:[],//多因子-领先期数数组 ±N
+            factorTableData:[],//多因子-相关性矩阵表格
+            factorTableDataSortCopy:[],//复制一份,用于还原排序
+            multipleChartData:_.cloneDeep(baseChartInfo),//多因子图表信息
+            IndTarget:{},//存储标的指标信息
+            showMultipleChart:false,//是否显示多因子相关性图表
+
+            isSaveChartToBase:false,
+            isSaveEdbToBase:false,
+            saveScence:'',
+            saveSource:0,
+            chartData:'',
+
+            settingData:{SourcesFrom:{}},//图例信息
+            isSettingChartShow:false,
+
+            showExplain:false,//显示操作说明
+            SourcesFromVisable:false,//数据来源的默认值,仅在新增时生效
+            previewMatrixLoading:false,//计算相关性矩阵loading
+        };
+    },
+    computed:{
+        //领先期数label
+        LeadLabelName(){
+            const UnitEnMap = {
+                    '年': 'Year',
+                    '季': 'Season',
+                    '月': 'Month',
+                    '周': 'Week',
+                    '天': 'Day',
+                }
+            return this.$t('StatisticAnalysis.ChartRelevance.multiple_table_head_03',{unit:UnitEnMap[this.infoForm.Correlation.LeadUnit]})
+        },
+        infoRules(){
+            return {
+                EdbInfoIdA:[{
+                    required:true,
+                    message:/* '指标A未选择' */this.$t('StatisticAnalysis.ChartRelevance.infoform_rules_hint_01'),
+                    trigger:'blur'
+                }],
+                EdbInfoIdB:[{
+                    required:true,
+                    message:/* '指标B未选择' */this.$t('StatisticAnalysis.ChartRelevance.infoform_rules_hint_02'),
+                    trigger:'blur'
+                }],
+                IndTarget:[{
+                    required:true,
+                    message:/* '标的指标未选择' */this.$t('StatisticAnalysis.ChartRelevance.infoform_rules_hint_03'),
+                    trigger:'blur'
+                }],
+                'Correlation.CalculateValue':[{
+                    required:true,
+                    message:/* '计算窗口未填写' */this.$t('StatisticAnalysis.ChartRelevance.infoform_rules_hint_04'),
+                    trigger:'blur'}],
+                'Correlation.LeadValue':[{
+                    required:true,
+                    message:/* '分析周期未填写' */this.$t('StatisticAnalysis.ChartRelevance.infoform_rules_hint_05'),
+                    trigger:'blur'
+                }]
+            }
+        },
+        chartInfo(){ //单因子系列保存/更新/另存为会用到
+            return this.infoForm
+        }
+    },
+    mounted(){
+        this.getRelevanceChartDetail()
+        this.getChartBaseSetting()
+    },
+    methods: {
+        //获取图表全局设置
+        async getChartBaseSetting(){
+            //目前是用基本配置的接口,后续有多个配置再改
+            const res = await etaBaseConfigInterence.getBaseConfig()
+            if(res.Ret!==200) return 
+            const {ChartSourceDisplay} = res.Data||{}
+            this.SourcesFromVisable = ChartSourceDisplay==='true'?true:false
+            //多因子的配置一开始就初始化,在这里设置默认值
+            if(!this.$route.query.code){
+                this.multipleChartData.SourcesFrom.isShow = this.SourcesFromVisable
+            }
+        },
+        sortChange({column,prop,order}){
+            const {label} = column
+            this.factorTableData.sort((a,b)=>{
+                if(order==='ascending'){
+                    return a.dataList[label] - b.dataList[label]
+                }else{
+                    return b.dataList[label] - a.dataList[label]
+                }
+            })
+            //取消order 排序还原为factorTableDataSortCopy的顺序
+            if(!order){
+                const table = this.factorTableDataSortCopy.map(copyItem=>{
+                    return this.factorTableData.find(i=>i.EdbInfoId===copyItem.EdbInfoId&&i.SeriesId===copyItem.SeriesId)
+                })
+                this.factorTableData = table
+            }
+            
+
+        },
+        //禁用表格行的样式
+        getTableRowClassname({row}){
+            if(!row.isSuccess){
+                return 'disable-row'
+            }
+            return ''
+        },
+        changeModel(){
+            this.typeModel = this.infoForm.Model
+            this.resetForm()
+        },
+        //重置表单
+        resetForm(){
+            this.infoForm = _.cloneDeep(baseForm)
+            this.chartBatchData = null
+            this.factorTableData = []
+            this.factorTableDataSortCopy=[]
+            this.showMultipleChart = false
+            this.infoForm.Model = this.typeModel
+            this.typeModel = 0
+        },
+        //选择指标后获取指标详情
+        async getEdbDetail({EdbInfoId,EdbInfoType}) {
+            const { Data } = EdbInfoType 
+            ? await preDictEdbInterface.edbDetail({EdbInfoId})
+            : await dataBaseInterface.calculateDetail({EdbInfoId})
+            return { 
+                max: EdbInfoType ? Data.MaxValue : Data.EdbInfoDetail.MaxValue,
+                min: EdbInfoType ? Data.MinValue : Data.EdbInfoDetail.MinValue,
+                data:EdbInfoType ? Data : Data.EdbInfoDetail,
+            }
+        },
+        //选择指标
+        async handleSelectTarget({type,target}){
+            if(!target) return
+            this.infoForm[type] = target.EdbInfoId||''
+            const {max,min,data} = await this.getEdbDetail(target)
+            if(type==='IndTarget'){
+                this.IndTarget = data
+                //点计算时,才真正赋值ChartInfo
+                //this.multipleChartData.ChartInfo = data
+            }
+            //若为单因子,选择AB指标后预览曲线图
+            if(!['EdbInfoIdA','EdbInfoIdB'].includes(type)) return 
+            if(type==='EdbInfoIdA'){
+                this.infoForm.Curve.LeftMin = min;
+                this.infoForm.Curve.LeftMax = max;
+            }else if(type==='EdbInfoIdB'){
+                this.infoForm.Curve.RightMin = min;
+                this.infoForm.Curve.RightMax = max;
+            }
+            this.getPreviewSplineChart()
+        },
+        //单因子-选择指标后生成曲线图
+        async getPreviewSplineChart(){
+            if(!this.infoForm.EdbInfoIdA || !this.infoForm.EdbInfoIdB) return
+            if(this.infoForm.Curve.DateType===5&&!this.infoForm.Curve.Date[0]) return 
+            let params = {
+                ...this.infoForm 
+            }
+            const res = await chartRelevanceApi.previewSplineChart(params);
+            if(res.Ret !== 200) return
+            this.chartBatchData = this.chartBatchData?{
+                ...this.chartBatchData,
+                CurveData: res.Data.CurveData
+            }:{CurveData: res.Data.CurveData};
+        },
+        //单因子-曲线配置变化时重绘
+        changeSplineOption() {
+            const { LeftMin,LeftMax,RightMin,RightMax,IsOrder } = this.infoForm.Curve;
+            this.$refs.chartCard1.options.yAxis[0].max = Number(LeftMax);
+            this.$refs.chartCard1.options.yAxis[0].min = Number(LeftMin);
+
+            this.$refs.chartCard1.options.yAxis[1].max = Number(RightMax);
+            this.$refs.chartCard1.options.yAxis[1].min = Number(RightMin);
+            this.chartBatchData.CurveData.EdbInfoList[1].IsOrder = IsOrder;
+        },
+        //预览相关性图表/相关性矩阵
+        async previewChart(){
+            //表单校验
+            await this.$refs.infoFormRef.validate()
+            //相关性值校验
+            if(!this.checkValue()) return 
+            
+            if(this.infoForm.Model===1){
+                //单因子:渲染相关性图表,需要保存MultipleGraphConfigId
+                const res = await chartRelevanceApi.chartOptionsSet({...this.infoForm});
+                if(res.Ret !== 200) return
+                const { MultipleGraphConfigId } = res.Data;
+                this.infoForm.MultipleGraphConfigId = MultipleGraphConfigId;
+                this.previewSingleChart({})
+            }else{
+                //已添加指标后重新计算
+                if(this.isMultipleChartAdd){
+                    const {ChartInfoId,UniqueCode,ClassifyId} = this.multipleChartData.ChartInfo
+                    this.multipleChartData.ChartInfo = this.IndTarget
+                    this.multipleChartData.ChartInfo.ChartInfoId = ChartInfoId
+                    this.multipleChartData.ChartInfo.UniqueCode = UniqueCode
+                    this.multipleChartData.ChartInfo.ClassifyId = ClassifyId
+                }else{
+                    this.multipleChartData.ChartInfo = this.IndTarget
+                }
+                //多因子:根据分析周期生成相关性矩阵,在未添加曲线前不生成图表
+                this.previewMultipleTable()
+            }
+        },
+        //校验规则
+        checkValue() {
+            //只用于校验规则条件大小
+            let checkBool = true;
+            const valueMap = {
+                '年': 365,
+                '季': 90,
+                '月': 30,
+                '周': 7,
+                '天': 1
+            }
+            const { Correlation } = this.infoForm;
+            if(Correlation.CalculateValue*valueMap[Correlation.CalculateUnit] < Correlation.LeadValue*valueMap[Correlation.LeadUnit]*2) {
+                this.infoForm.Correlation.CalculateValue = 0;
+                this.$message.warning(/* '相关性计算窗口必须≥2*分析周期' */this.$t('StatisticAnalysis.ChartRelevance.check_value_hint'))
+                checkBool = false
+            }
+            return checkBool
+        },
+        //预览单因子图表 初始化 chartBatchData
+        async previewSingleChart(initConfig=null){
+            const res = await chartRelevanceApi.previewChartBatch({...this.infoForm});
+            if(res.Ret !== 200) return
+            this.chartBatchData = res.Data;
+            //第一次初始化时,需初始化图例和数据来源信息
+            if(initConfig){
+                const {CorrelationExtraConfig,SourcesFrom} = initConfig
+                try{
+                    this.chartBatchData.SourcesFrom = SourcesFrom?JSON.parse(SourcesFrom):_.cloneDeep(baseSourcesFrom)
+                }catch(e){
+                    this.chartBatchData.SourcesFrom = _.cloneDeep(baseSourcesFrom)
+                }
+                //新增时 来源与基本配置设置的一致
+                if(!this.$route.query.code){
+                    this.chartBatchData.SourcesFrom.isShow = this.SourcesFromVisable
+                }
+                //拼接来源
+                const {EdbInfoList} = res.Data.CorrelationData
+                const tempStr = EdbInfoList[0].SourceName+','+EdbInfoList[1].SourceName
+                this.chartBatchData.SourcesFrom.text += `${this.chartBatchData.SourcesFrom.text.length?',':''}${tempStr}`
+                //拼接后去重
+                let concatSourceArr = `${this.chartBatchData.SourcesFrom.text}`.split(',');
+                let sourceStr = Array.from(new Set(concatSourceArr)).join(',');
+                this.chartBatchData.SourcesFrom.text = sourceStr
+                try{
+                    const {LegendConfig} = CorrelationExtraConfig?JSON.parse(CorrelationExtraConfig):{LegendConfig:[]}
+                    this.chartBatchData.CorrelationData.YDataList[0].Color = LegendConfig[0].Color
+                    this.chartBatchData.CorrelationData.YDataList[0].Name = LegendConfig[0].Legendlame
+                }catch(e){
+
+                }
+            }
+        },
+        //预览多因子矩阵 初始化 factorTableData
+        previewMultipleTable(){
+            //全局loading
+            this.previewMatrixLoading = true
+            const {IndTarget,Correlation} = this.infoForm
+            const SeriesIds = this.$refs.multipleIndForm.factorList.map(i=>i.SeriesId)
+            //清空表格和图表
+            this.factorTableData = []
+            this.factorTableDataSortCopy=[]
+            this.multipleChartData.YDataList=[]
+            this.showMultipleChart = false
+            chartRelevanceApi.getCorrelationMatrix({
+                BaseEdbInfoId:IndTarget,
+                Correlation,
+                SeriesIds,
+            }).then(res=>{
+                //loading结束
+                this.previewMatrixLoading = false
+                if(res.Ret!==200) return
+
+                const {Fail=[],Success=[]} = res.Data
+                if(!Success||Success&&!Success.length){
+                    this.$message.warning('所有指标计算失败,请重新选择指标')
+                    return 
+                }
+                //标记失败的
+                const FailList = Fail?Fail.map(i=>{
+                    return {
+                        ...i,
+                        isSuccess:false,
+                        dataList:[]
+                    }
+                }):[]
+                const SuccessList = Success.map(i=>{
+                    return {
+                        ...i,
+                        isSuccess:true,
+                        isAdd:false,
+                        dataList:i.Values.map(v=>v.YData)
+                    }
+                })
+                this.factorTableData = [...SuccessList,...FailList]
+                this.factorTableDataSortCopy = _.cloneDeep(this.factorTableData)
+                //获取分析周期,生成±分析周期的数组
+                const {LeadValue,LeadUnit,CalculateUnit,CalculateValue} = this.infoForm.Correlation
+                this.SortedArray = generateSortedArray(LeadValue)
+                //设置图表默认值
+                this.multipleChartData.ChartInfo.Source = 3
+                this.multipleChartData.ChartInfo.ChartName = this.multipleChartData.ChartInfo.EdbName+`相关性分析(${CalculateValue}${CalculateUnit})`
+                this.multipleChartData.CorrelationChartInfo = {
+                    LeadValue:LeadValue,
+                    LeadUnit:LeadUnit
+                }
+                this.multipleChartData.XEdbIdValue = generateXEdbValue(LeadValue)
+            })
+        },
+        checkRecalculate(){
+            //若当前已预览过图表/矩阵,则重新请求矩阵接口,初始化矩阵和图表数据
+            if(this.showMultipleChart||this.factorTableData.length){
+                this.previewMultipleTable()
+            }
+        },
+        //相关性矩阵-添加曲线
+        addCurve(row){
+            const length = this.multipleChartData.YDataList.length
+            if(length>=10) return this.$message.warning('最多只支持添加10条曲线')
+            this.showMultipleChart = true
+            
+            const colors = ['#00f','#f00','#999','#000','#7cb5ec', '#90ed7d', '#f7a35c', '#8085e9', '#f15c80', '#e4d354', '#2b908f', '#f45b5b', '#91e8e1']
+            this.multipleChartData.YDataList.push({
+                Id:row.EdbInfoId,
+                SeriesId:row.SeriesId,
+                Value:generateYDataValue(row.dataList,this.infoForm.Correlation.LeadValue),
+                Color:colors[length%colors.length],
+                Name:row.EdbName,
+                NameEn:row.EdbNameEn
+            })
+            row.isAdd = true
+            //数据来源拼接
+            this.multipleChartData.SourcesFrom.text += `${this.multipleChartData.SourcesFrom.text.length?',':''}${row.SourceName}`
+            //拼接后去重
+            let concatSourceArr = `${this.multipleChartData.SourcesFrom.text}`.split(',');
+            let sourceStr = Array.from(new Set(concatSourceArr)).join(',');
+            this.multipleChartData.SourcesFrom.text = sourceStr
+        },
+        //相关性矩阵-删除曲线
+        deleteCurve(row){
+            const index = this.multipleChartData.YDataList.findIndex(i=>i.Id===row.EdbInfoId&&i.SeriesId===row.SeriesId)
+            index!==-1&&this.multipleChartData.YDataList.splice(index,1)
+            row.isAdd = false
+            if(!this.multipleChartData.YDataList.length){
+                this.showMultipleChart = false
+            }
+        },
+        //打开图例设置弹窗
+        handleChangeChartSetting(data){
+            //单多因子的data结构是相同的
+            /**
+             * 图表名称:data.ChartName/en
+             * 图例:data.YDataList.Color data.YDataList.Name
+             * 数据来源:新字段 SourcesFrom.text
+             * 数据来源开关:新字段 SourcesFrom.isShow
+             */
+            const SourcesFrom = this.infoForm.Model===1?_.cloneDeep(this.chartBatchData.SourcesFrom):_.cloneDeep(this.multipleChartData.SourcesFrom)
+            this.settingData = {
+                SourcesFrom,
+                chartName:data.ChartName,
+                YDataList:_.cloneDeep(data.YDataList)
+            }
+            this.isSettingChartShow = true
+        },
+        //图例设置回调
+        changeChartSettingBack(){
+            const {chartName,YDataList,SourcesFrom} = this.settingData
+            if(this.infoForm.Model===1){
+                this.chartBatchData.CorrelationData.ChartInfo.ChartName = chartName
+                this.chartBatchData.CorrelationData.YDataList = YDataList
+                this.chartBatchData.SourcesFrom = SourcesFrom
+            }else{
+                //多因子
+                this.multipleChartData.ChartInfo.ChartName = chartName
+                this.multipleChartData.YDataList = YDataList
+                this.multipleChartData.SourcesFrom = SourcesFrom
+            }
+            this.isSettingChartShow = false
+        },
+        //打开保存/另存为图表/指标弹窗
+        handleSave({type,chartData,scence}){
+            this.saveSource = type
+            this.chartData = chartData;
+            this.saveScence = scence;
+           /*  this.isSaveEdbToBase = true;
+            this.isSaveChartToBase = true; */
+        },
+        //单因子-保存/另存为指标回调
+        saveEdbBack({source}){
+            if(source===3) this.buttonAuth.isRollEdbAdd = true;
+            else if(source===4)  this.buttonAuth.isRollEdbTwoAdd = true;
+        },
+        //单因子-保存/另存为图表回调
+        saveChartBack({source,id}){
+            this.$message.success(this.$t('MsgPrompt.saved_msg'));
+            this.setButtonAuth(source);
+            //设置封面图
+            this.$refs[`chartCard`+source].setChartImage(source,id)
+        },
+        //单因子-保存图表后按钮控制 
+        setButtonAuth(source) {
+            const sourceMap = {
+                1: 'isCurveChartAdd',
+                2: 'isRelevanceChartAdd',
+                3: 'isRollChartAdd',
+                4: 'isRollChartTwoAdd'
+            }
+            this.buttonAuth[sourceMap[source]] = true;
+        },
+        //编辑-获取相关性图表详情
+        getRelevanceChartDetail(){
+            //判断是单因子or多因子
+            if(this.$route.query.type!=1){
+                this.getSingleDetail()
+            }else{
+                this.getMultiplyDetail()
+            }
+            
+        },
+        //获取单因子图表详情
+        async getSingleDetail(){
+            if(!this.$route.query.code) return
+            const res = await chartRelevanceApi.getOptionByCode({ UniqueCode: this.$route.query.code});
+            if(res.Ret !== 200) return 
+            this.chartInfoData = {
+                EdbInfoList: res.Data.EdbInfoList
+            }
+            //初始化infoForm
+            const { MultipleGraphConfigId,EdbInfoIdA,EdbInfoIdB,Curve,Correlation,RollingCorrelation } = res.Data.MultipleGraphConfig;
+            this.infoForm = {
+                Model:1,
+                MultipleGraphConfigId,
+                EdbInfoIdA,
+                EdbInfoIdB,
+                Curve: {
+                ...JSON.parse(Curve),
+                Date: [JSON.parse(Curve).StartDate,JSON.parse(Curve).EndDate],
+                },
+                Correlation: JSON.parse(Correlation),
+                RollingCorrelation: JSON.parse(RollingCorrelation)
+            }
+            //初始化权限
+            this.buttonAuth =  {
+                isCurveChartAdd: res.Data.ChartMappingList.some(_ => _.MultipleLocationSource===1),
+                isRelevanceChartAdd: res.Data.ChartMappingList.some(_ => _.MultipleLocationSource===2),
+                isRollChartAdd: res.Data.ChartMappingList.some(_ => _.MultipleLocationSource===3),
+                isRollEdbAdd: res.Data.EdbMappingList.some(_ => _.MultipleLocationSource===3),
+                isRollChartTwoAdd: res.Data.ChartMappingList.some(_ => _.MultipleLocationSource===4),
+                isRollEdbTwoAdd: res.Data.EdbMappingList.some(_ => _.MultipleLocationSource===4)
+            }
+            //初始化chartBatch
+            const RelevanceInfo = res.Data.ChartMappingList.find(_=>_.MultipleLocationSource===2)||{}
+            const {CorrelationExtraConfig,SourcesFrom} = RelevanceInfo
+            this.previewSingleChart({CorrelationExtraConfig,SourcesFrom})
+        },
+        //获取多因子图表详情
+        getMultiplyDetail(){
+            if(!this.$route.query.code) return
+            //获取图表详情
+            chartRelevanceApi.getMultipleChartDetail({
+                UniqueCode:this.$route.query.code
+            }).then(res=>{
+                if(res.Ret!==200) return
+                const {ChartName,ChartClassifyId,ChartInfoId,UniqueCode,ExtraConfig,SourcesFrom} = res.Data.ChartInfo
+                this.multipleChartData.ChartInfo = {
+                    ClassifyId:ChartClassifyId,ChartName,ChartInfoId,UniqueCode,Source:3
+                }
+                const {EdbInfoList,XEdbIdValue,YDataList,CorrelationChartInfo} = res.Data
+                const {LeadValue,LeadUnit} = CorrelationChartInfo
+                this.multipleChartData.CorrelationChartInfo = {
+                    LeadValue,LeadUnit
+                }
+                this.multipleChartData.XEdbIdValue = XEdbIdValue
+                this.multipleChartData.EdbInfoList = EdbInfoList
+                this.multipleChartData.YDataList = YDataList.map(i=>{
+                    return {
+                        ...i,
+                        Id:i.SeriesEdb.EdbInfoId,
+                        SeriesId:i.SeriesEdb.SeriesId
+                    }
+                })
+                try{
+                    this.multipleChartData.SourcesFrom = SourcesFrom?JSON.parse(SourcesFrom):_.cloneDeep(baseSourcesFrom)
+                }catch(e){
+                    this.multipleChartData.SourcesFrom = _.cloneDeep(baseSourcesFrom)
+                }
+                this.showMultipleChart = true
+                this.isMultipleChartAdd = true
+
+            })
+            //获取表单及矩阵详情
+            chartRelevanceApi.getMultipleFactorDetail({
+                UniqueCode:this.$route.query.code
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                const {BaseEdbInfo,CorrelationConfig,EdbSeries,CorrelationMatrix} = res.Data
+                const {LeadValue,LeadUnit,CalculateValue,CalculateUnit} = CorrelationConfig
+                this.infoForm.Model = 2
+                //基础信息表单
+                this.infoForm = {
+                    Model:2,
+                    IndTarget:BaseEdbInfo.EdbInfoId,
+                    Correlation:{
+                        LeadValue,LeadUnit,CalculateValue,CalculateUnit
+                    }
+                }
+                //标的因子信息
+                this.IndTarget = _.cloneDeep(BaseEdbInfo)
+                this.chartInfoData = {
+                    EdbInfoList:[BaseEdbInfo]
+                }
+                //因子列表
+                this.SeriesList = EdbSeries
+                //相关性矩阵
+                this.factorTableData = CorrelationMatrix.map(i=>{
+                    return {
+                        ...i,
+                        isSuccess:true,
+                        isAdd:i.Used,
+                        dataList:i.Values.map(v=>v.YData)
+                    }
+                })
+                this.factorTableDataSortCopy = _.cloneDeep(this.factorTableData)
+                this.SortedArray = generateSortedArray(LeadValue)
+            })
+        },
+        //多因子-保存/更新/另存为图表
+        async saveMultipleChart({ChartName,ClassifyId,type}){
+            const {IndTarget,Correlation} = this.infoForm
+            const {SourcesFrom,YDataList} = this.multipleChartData
+            const SeriesEdb = YDataList.map(i=>{
+                return {
+                    SeriesId:i.SeriesId,
+                    EdbInfoId:i.Id
+                }
+            })
+            //BaseEdbInfoId优先取当前图表内的EdbInfoId,若没有值取表单内的
+            const BaseEdbInfoId = this.multipleChartData.ChartInfo.EdbInfoId||IndTarget
+            const SeriesIds = this.$refs.multipleIndForm.factorList.map(i=>i.SeriesId)
+            const LegendConfig = YDataList.map(i=>{
+                return {
+                    LegendName:i.Name,
+                    SeriesId:i.SeriesId,
+                    EdbInfoId:i.Id,
+                    Color:i.Color
+                }
+            })
+            let params = {
+                ChartName,ClassifyId,
+                AnalysisMode:1,
+                BaseEdbInfoId:BaseEdbInfoId/* IndTarget */,
+                FactorCorrelation:{
+                    ...Correlation,
+                    SeriesEdb,
+                    SeriesIds
+                },
+                ExtraConfig:{
+                    LegendConfig,
+                },
+                SourcesFrom,
+            }
+            const {ChartInfoId} = this.multipleChartData.ChartInfo
+            const isEdit = ChartInfoId&&type!=='saveOther'
+            //另存为/新增->add 更新->edit
+            const res = isEdit
+                ?await chartRelevanceApi.editMultipleFactor({...params,ChartInfoId})
+                :await chartRelevanceApi.addMultipleFactor({...params,SaveAs:type==='saveOther'})
+            //计算中...
+            if(res.Ret!==200) return 
+            if(!isEdit){
+                this.isMultipleChartAdd = true
+                this.multipleChartData.ChartInfo.ChartInfoId = res.Data.ChartInfoId
+                this.multipleChartData.ChartInfo.UniqueCode = res.Data.UniqueCode
+                this.multipleChartData.ChartInfo.ClassifyId = res.Data.ClassifyId
+            }
+            //更新图表名称
+            this.multipleChartData.ChartInfo.ChartName = ChartName
+            this.$message.success(`${isEdit?'更新':'保存'}成功`)
+            //设置缩略图
+            this.$refs[`chartCard`+2].setChartImage(2,res.Data.ChartInfoId)
+            this.isSaveChartToBase = false
+        },
+    },
+};
+</script>
+
+<style lang="scss">
+.relevance-chart-editor-wrap{
+    display: flex;
+    *{
+        box-sizing: border-box;
+    }
+    .content-wrap{
+        background: #fff;
+        border: 1px solid #ececec;
+        border-radius: 4px;
+        .source{
+            padding-left: 20px;
+            padding-bottom:20px;
+            margin-top: -20px;
+        }
+    }
+    .info-wrap{
+        width:380px;
+        min-width: 380px;
+        margin-right: 20px;
+        display: flex;
+        flex-direction: column;
+        height: calc(100vh - 120px);
+        .info-top{
+            padding: 15px 20px;
+            border-bottom: 1px solid #ececec;
+            box-shadow: 0px 3px 6px rgba(167, 167, 167, 0.09);
+            display: flex;
+            align-items: center;
+            >span{
+                color:#0052D9;
+                cursor: pointer;
+                flex: 1;
+                text-align: right;
+                img{
+                    vertical-align: middle;
+                }
+            }
+        }
+        .info-form-wrap{
+            flex: 1;
+            overflow-y: auto;
+            padding:20px;
+            .el-form-item{
+                margin-bottom: 10px;
+            }
+            .form-box{
+                margin-top: 10px;
+                padding-top: 10px;
+                border-top:1px dashed #DCDFE6;
+            }
+            .model-form{
+                .select-target{
+                    display: flex;
+                    margin-top: 10px;
+                    .el-form-item__label{
+                        flex-shrink: 0;
+                    }
+                    .el-form-item__content{
+                        margin-left: 0 !important;
+                        .el-select{
+                            margin-top: 10px !important;
+                        }
+                    }
+                    .el-date-editor.el-input, .el-date-editor.el-input__inner{
+                        width: auto;
+                    }
+                }
+                .flex-form-item{
+                    .el-form-item__content{
+                        display: flex;
+                        gap:0 5px;
+                    }
+                }
+            }
+            .multiple-model-form{
+                .factor-form-item{
+                    .el-form-item {
+                        margin-bottom: 0;
+                    }
+                    .el-form-item__label{
+                        width:auto !important;
+                    }
+                    .factor-list{
+                        .list-item{
+                            padding:10px 20px;
+                            background-color: #EBEFF6;
+                            border:1px solid #C8CDD9;
+                            cursor: pointer;
+                            display: flex;
+                            justify-content: space-between;
+                            align-items: center;
+                            border-bottom: none;
+                            &:last-child{
+                                border-bottom: 1px solid #C8CDD9;
+                            }
+                        }
+                    }
+                    .add-factor-btn{
+                        margin-top: 20px;
+                        display: flex;
+                        gap:10px;
+                        align-items: center;
+                        cursor: pointer;
+                        color:#0052D9;
+                        img{
+                            width: 15px;
+                            height: 15px;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    .model-wrap{
+        flex:1;
+        height: calc(100vh - 120px);
+        overflow-x: hidden;
+        .single-model-wrap{
+            width: 100%;
+            overflow: hidden;
+        }
+        .chart-min-cont {
+            height: calc(100vh - 120px);
+            overflow-y: auto;
+            display: flex;
+            flex-wrap: wrap;
+            gap:15px;
+            .card-wrapper {
+                width: 48%;
+                min-height: 350px;
+                min-width:410px;
+                .card-item {
+                    padding: 20px;
+                    .top {
+                        display: flex;
+                        justify-content: space-between;
+                        align-items: center;
+                        margin-bottom: 15px;
+                    }
+                    .title {
+                        font-size: 15px;
+                        text-align: left;
+                        margin: 10px 0;
+                    }
+                }
+            }
+        }
+        .nodata {
+            height: calc(100vh - 120px);
+            background-color: #fff;
+            text-align: center;
+            font-size: 16px;
+            color: #666;
+            padding: 100px 0;
+        }
+        .multiple-model-wrap{
+            display: flex;
+            flex-direction: column;
+            justify-content: space-between;
+            height: calc(100vh - 120px);
+            .relevant-matrix-table-box,.relevant-chart-box{
+                height: 49%;
+                overflow: auto;
+            }
+            
+            .relevant-matrix-table-box{
+                display: flex;
+                .el-table{
+                    flex:1;
+                    thead{
+                        color:#333;
+                    }
+                    th.zip-cell{
+                        padding:0;
+                        font-size: 12px;
+                        background: #F5F7FA !important;
+                        .cell{
+                            padding:0;
+                            .caret-wrapper{
+                                height:24px;
+                                width:20px;
+                                .sort-caret.ascending{
+                                    top:0;
+                                }
+                                .sort-caret.descending{
+                                    bottom:0;
+                                }
+                            }
+                        }
+                    }
+                    td.zip-cell{
+                        padding:0;
+                        font-size: 12px;
+                        background-color: #fff !important;
+                        .cell{
+                            padding:0;
+                            line-height: 23px;//调整单元格高度
+                        }
+                    }
+                }
+            }
+            .relevant-chart-box{
+                .card-item {
+                    padding: 20px;
+                    .top {
+                        display: flex;
+                        justify-content: space-between;
+                        align-items: center;
+                        .title {
+                            font-size: 15px;
+                            text-align: left;
+                            margin: 10px 0;
+                        }
+                    }
+                    
+                }
+            }
+        }
+    }
+    .disable-row{
+        pointer-events: none;
+        opacity: 0.5;
+        cursor: default; 
+    }
+}
+</style>

+ 111 - 0
src/views/chartRelevance_manage/relevance/utils/config.js

@@ -0,0 +1,111 @@
+//相关性表单
+export const baseForm = {
+    Model:1,//模式 1单因子 2 多因子
+    EdbInfoIdA:'',//指标A
+    EdbInfoIdB:'',//指标B
+    IndTarget:'',//标的指标
+    Curve:{//曲线图
+        DateType:3,
+        Date:'',
+        StartDate:'',
+        EndDate:'',
+        LeftMin:'',
+        LeftMax:'',
+        RightMin:'',
+        RightMax:'',
+        EdbInfoType:true,//显示为标准指标(true)或领先指标(false)
+        LeadValue:0,
+        LeadUnit:'天',
+    },
+    Correlation:{//相关性
+        CalculateValue:0,//计算窗口
+        CalculateUnit:'天',//计算窗口单位(时间)
+        LeadValue:0,//分析周期
+        LeadUnit:'天',//分析周期单位(时间)
+    },
+    RollingCorrelation:[//滚动相关性
+        {
+            CalculateValue:0,
+            CalculateUnit:'天',
+            LeadValue:0,
+            LeadUnit:'天'
+        },
+        {
+            CalculateValue:0,
+            CalculateUnit:'天',
+            LeadValue:0,
+            LeadUnit:'天'
+        }
+    ],
+}
+//多因子图表信息
+export const baseChartInfo = {
+    ChartInfo:{
+        Source:3,
+        ChartName:'',//与单因子保持一致,用于保存/另存为回显
+        ChartInfoId:'',//新增前为空
+        UniqueCode:'',//新增前为空
+        ClassifyId:'',//新增前为空
+        /**
+         * EdbInfoId 当前页面点击计算后有值 标的指标的ID
+         * EdbName 当前页面点击计算后有值 标的指标的名称
+         */
+    },
+    EdbInfoList:[],//第一项为标的指标,其他项为添加的指标
+    XEdbIdValue:[],//SourtedArray
+    CorrelationChartInfo:{
+        LeadValue:0,//分析周期
+        LeadUnit:'天',//分析周期单位(时间)
+    },
+    YDataList:[
+        /* {
+            Value:[],//factorTableData.dataList
+            Color:'#00f',
+            Name:'',//factorTableData.name
+            NameEn:''
+        } */
+    ],
+    SourcesFrom:{
+        isShow:true,//是否显示
+        text:'',//内容
+        color:'#333',
+        fontSize:12,
+    },//
+}
+//多因子-相关性矩阵表格
+const factorTableData = [
+    {
+        EdbInfoId:'指标ID',
+        SeriesId:'指标所属系列ID',//与EdbInfoId一起表示指标的唯一性
+        EdbName:'指标名称',
+        dataList:[],//领先期数数据,下标需和期数对应
+        isAdd:false,//是否已添加曲线
+    }
+]
+//多因子-因子系列
+const factorList = [
+    {
+        "SeriesId": 4, //系列Id
+        "SeriesName": "系列名称A001", //系列名称
+        "EdbInfoType": 0, //0指标,1预测指标
+        "CalculateStep":[ //计算公式
+            {
+                "Formula": "", //N值/移动天数/指数修匀alpha值/计算公式等
+                "Calendar": "", //公历/农历
+                "Source": 3, //计算方式来源
+                "Sort": 1 
+            },
+        ],
+        "EdbMappings":[
+            
+        ],//所选的指标
+    },
+]
+
+//数据来源
+export const baseSourcesFrom = {
+    isShow:true,//是否显示
+    text:'',//内容
+    color:'#333',
+    fontSize:12,
+}

+ 70 - 0
src/views/chartRelevance_manage/relevance/utils/index.js

@@ -0,0 +1,70 @@
+//相关性矩阵表头
+export const generateSortedArray = (N)=>{
+    let positiveArr = [];
+    for (let i = 0; i <= N; i++) {
+        positiveArr.push(i);
+    }
+    
+    let negativeArr = [];
+    for (let i = -1; i >= -N; i--) {
+        negativeArr.push(i);
+    }
+    
+    return positiveArr.concat(negativeArr);
+}
+//mock用 相关性图表x轴
+export const generateXEdbValue = (N)=>{
+    let positiveArr = [];
+    for (let i = 0; i <= N; i++) {
+        positiveArr.push(i);
+    }
+    
+    let negativeArr = [];
+    for (let i = -N; i <= -1; i++) {
+        negativeArr.push(i);
+    }
+    return [...negativeArr,...positiveArr]
+}
+//转换YDataList data是领先期数从0开始的数组
+export const generateYDataValue = (data,n)=>{
+    //取[n+1,length]项 为-1~-n 翻转为-n~-1
+    let arr = data.slice(n+1).reverse()
+    //data从下标n+1处放置
+    let dataArr = data.slice(0,n+1)
+    return [...arr,...dataArr]
+}
+//判断两个指标ID数组是否有变化:指标ID一致视为无变化
+export const checkListChange = (listA,listB)=>{
+    // 将两个数组转换为 Set 对象
+    const setA = new Set(listA);
+    const setB = new Set(listB);
+
+    if (setA.size !== setB.size) {
+        return true;
+    }
+    // 检查 setA 中的每一项是否都在 setB 中
+    for (const item of setA) {
+        if (!setB.has(item)) {
+            return true;
+        }
+    }
+    // 如果所有检查都通过,说明两个数组包含相同的项
+    return false;
+}
+//判断两个计算方式是否有变化:顺序,Source以及Formula的值一致视为无变化
+export const checkStepsChange = (stepsA,stepsB)=>{
+    if(stepsA.length!==stepsB.length) return true
+
+     // 逐个比较数组中的每一项是否都相同且顺序一致
+     for (let i = 0; i < stepsA.length; i++) {
+        if (  stepsA[i].Sort!==stepsB[i].Sort
+            ||stepsA[i].Source!==stepsB[i].Source
+            ||stepsA[i].Formula!==stepsB[i].Formula) {
+            return true
+        }
+        if(stepsA[i].Source===11&&stepsA[i].Calendar!==stepsB[i].Calendar){
+            return true
+        }
+    }
+    return false
+}

+ 17 - 4
src/views/dataEntry_manage/components/SaveChartOther.vue

@@ -33,7 +33,8 @@
             label: currentLang==='en'?'ChartClassifyNameEn':'ChartClassifyName',
             value: 'ChartClassifyId',
             children: 'Children',
-            emitPath: false
+            emitPath: false,
+            checkStrictly:isRelevanceChart
           }"
           style="width: 80%"
           :placeholder="$t('Chart.InputHolderAll.input_classify')"
@@ -75,6 +76,11 @@ export default {
       }
     }
   },
+  computed:{
+    isRelevanceChart(){
+        return ['/chartrelevance'].includes(this.$route.path)||this.source===3||this.source===4
+    }
+  },
   data() {
     return {
       form: {
@@ -109,7 +115,7 @@ export default {
       if([2,5,'good_price'].includes(this.source)){//商品价格
         res=await futuresInterface.classifyList()
       }else if([3,4,'relevance_chart'].includes(this.source)){//相关性图表
-        res=await chartRelevanceApi.classifyList()
+        res=await chartRelevanceApi.classifyTree()
       }else if([6,'fitting_equation'].includes(this.source)){//拟合方程
         res=await fittingEquationInterface.classifyList()
       }else if([7,8,9,'statistic_feature'].includes(this.source)) { //标准差 百分位 频率图
@@ -125,7 +131,7 @@ export default {
       if([2,5,'good_price'].includes(this.source)){//商品价格
         this.filterNodes(res.Data.AllNodes,1)
       }else if([3,4,'relevance_chart'].includes(this.source)){//相关性图表
-        this.filterNodes(res.Data.AllNodes,1)
+        this.filterNodesAll(res.Data.AllNodes)
       }else if([6,'fitting_equation'].includes(this.source)){//拟合方程
         this.filterNodes(res.Data.AllNodes,1)
       }else if([7,8,9,'statistic_feature'].includes(this.source)) { //标准差 百分位 频率图
@@ -139,7 +145,14 @@ export default {
 			this.classifyOptions = res.Data.AllNodes || [];
     
 		},
-
+		filterNodesAll(arr){
+			arr.length && arr.forEach(item => {
+				item.Children && item.Children.length && this.filterNodesAll(item.Children)
+				if(!item.Children.length) {
+					delete item.Children
+				}
+			})
+		},
 		// 递归改变第三级目录结构
 		filterNodes(arr,n) {
 			arr.length && arr.forEach(item => {

+ 1 - 3
src/views/dataEntry_manage/components/barOptionSection.vue

@@ -259,10 +259,8 @@ export default {
         this.dateList.push(date_item)
         
         let themeOpt = this.chartInfo.ChartThemeStyle ? JSON.parse(this.chartInfo.ChartThemeStyle) : null;
-        // 看colorsOptions返不返回再说
-        console.log(themeOpt,'themeOpt');
         this.dateList.forEach((item,index) => {
-          item.Color = item.Color || (themeOpt &&themeOpt.lineOptionList[index].color || defaultOpts.colors[index]);
+          item.Color = item.Color || (themeOpt&&themeOpt.colorsOptions[index]||defaultOpts.colors[index]);
         })
       }
       this.cancelDialog()

+ 14 - 0
src/views/dataEntry_manage/databaseComponents/chartTrendRender.vue

@@ -114,6 +114,7 @@
 					</el-radio-group>
 				</div>
 			</div>
+			<img src="~@/assets/img/icons/edb-stopping.png" class="stop-mark" v-if="([2,34].includes(chartInfo.Source) || chartInfo.EdbType==2) && chartInfo.NoUpdate==1" />
 		</div>
 		<div class="table-data">
 
@@ -279,6 +280,10 @@ export default {
 						}
 					})
 		},
+		// 切换刷新状态
+		toggleEdbRefreshStatusFun(){
+			this.chartInfo.NoUpdate = 1-this.chartInfo.NoUpdate
+		},
 		//保存指标缩略图
 		async saveEdbImg(EdbInfo){
 			let svg = this.$refs.chartRef.chart.getSVG({
@@ -844,6 +849,7 @@ export default {
 		}
 	}
 	.min-wrapper {
+		position: relative;
 		.el-input__inner {
 			padding: 0 0 0 5px;
 		}
@@ -867,6 +873,14 @@ export default {
 				}
 			}
 		}
+		.stop-mark{
+			height: 48px;
+			width: 48px;
+			position: absolute;
+			right: 0;
+			top: 0;
+			pointer-events: none;
+		}
 	}
 }
 </style>

+ 55 - 1
src/views/dataEntry_manage/databaseList.vue

@@ -239,7 +239,12 @@
 							</div>
 							<div class="info">
 								{{$t('EtaBasePage.time_show')}}:{{item.CreateTime.substring(0,10)}}
+								<!-- wind和钢联化工的指标、计算指标显示 启用/停用-->
+								<span v-if="([2,34].includes(item.Source) || item.EdbType==2) && isEdbBtnShow('enableOrDisable')" 
+								class="enable-toggle-btn" :style="{'color': item.NoUpdate==1?'#0052D9':'#D54941'}"
+								@click="toggleEdbRefreshStatus(item)">{{item.NoUpdate==1?$t('SystemManage.DataRefresh.enable'):$t('SystemManage.DataRefresh.disable') }}</span>
 							</div>
+							<img src="~@/assets/img/icons/edb-stopping.png" class="stop-mark" v-if="([2,34].includes(item.Source) || item.EdbType==2) && item.NoUpdate==1" />
 						</div>
 					</div>
 					
@@ -259,6 +264,10 @@
 							</el-tab-pane>
 						</el-tabs>
 						<div class="edb-tool-icon edb-tool" style="align-items: center;">
+							<el-button v-if="([2,34].includes(EdbData.Source) || EdbData.EdbType==2) && isEdbBtnShow('enableOrDisable')" 
+								type="text" :style="{'color': EdbData.NoUpdate==1?'#0052D9':'#D54941'}"
+								@click="toggleEdbRefreshStatus(EdbData,'detail')" 
+							>{{EdbData.NoUpdate==1?$t('SystemManage.DataRefresh.enable'):$t('SystemManage.DataRefresh.disable') }}<!-- 启用/停用 --></el-button>
 							<el-button 
 								v-if="isEdbBtnShow('update')"
 								type="text" 
@@ -960,6 +969,7 @@ export default {
 				'checkRelatedChart':edbDataPermission.edbData_checkRelatedChart,//查看关联图表
 				'checkRelatedEdb':edbDataPermission.edbData_checkRelatedEdb,//查看关联指标
 				'checkCalcChart':edbDataPermission.edbData_checkCalcChart,//查看计算指标
+				'enableOrDisable':edbDataPermission.edbData_enableOrDisable,//启用/停用
 			}
 			return checkPermissionBtn(BtnMap[type])
 		},
@@ -1089,6 +1099,29 @@ export default {
 
 			})
 		},
+		// 切换刷新状态
+		async toggleEdbRefreshStatus(item,type='list'){
+			let flag = true
+			if(item.NoUpdate==0){
+				flag=false
+				await this.$confirm(this.$t('SystemManage.DataRefresh.disable_indicator_prompt'),this.$t('Confirm.prompt'),{
+					type:"warning"
+				}).then(res=>{
+					flag=true
+				}).catch(()=>{})
+			}
+			if(!flag) return
+			let ModifyStatus = item.NoUpdate==1?'启用':'暂停'
+			dataBaseInterface.edbRefreshStatusSet({EdbInfoId:item.EdbInfoId,ModifyStatus}).then(res=>{
+				if(res.Ret == 200){
+					item.NoUpdate=1-item.NoUpdate
+					if(type=='detail'){
+						this.$refs.createChart.toggleEdbRefreshStatusFun()
+					}
+					this.$message.success(this.$t('MsgPrompt.operate_success_msg'))
+				}
+			})
+		},
 		//指标图表列表-加载更多
 		loadMoreHandle: _.throttle(function() {
 			let scrollTop = this.$refs.listRef.scrollTop;
@@ -2495,11 +2528,24 @@ export default {
 						border-radius: 4px;
 						border:1px solid #DCDFE6;
 						box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
-						.header,.info{
+						position: relative;
+						.header{
 							padding:10px;
 							box-sizing: border-box;
 							text-align: left;
 						}
+						.info{
+							padding:10px;
+							box-sizing: border-box;
+							display: flex;
+							align-items: center;
+							justify-content: space-between;
+							.enable-toggle-btn{
+								cursor: pointer;
+								color: #0052D9;
+								font-size: 14px;
+							}
+						}
 						.header{
 							white-space: nowrap;
 							overflow: hidden;
@@ -2515,6 +2561,14 @@ export default {
 							padding-bottom: 67%;
 							cursor: pointer;
 						}
+						.stop-mark{
+							height: 48px;
+							width: 48px;
+							position: absolute;
+							right: -1px;
+							top: 0;
+							pointer-events: none;
+						}
 					}
 				}
 			}

+ 17 - 9
src/views/dataEntry_manage/mixins/addOreditMixin.js

@@ -632,14 +632,18 @@ export default {
 		setAddChartDefault() {
 
 			let themeOpt = this.chartInfo.ChartThemeStyle ? JSON.parse(this.chartInfo.ChartThemeStyle) : null;
-			console.log(themeOpt,'themeOpt');
 			this.tableData.forEach((item,index) => {
-				item.ChartColor = item.ChartColor || (themeOpt&&themeOpt.colorsOptions[index]||defaultOpts.colors[index]);
-				item.PredictChartColor = item.PredictChartColor || (themeOpt&&themeOpt.colorsOptions[index]||defaultOpts.colors[index]);
-				item.ChartStyle = item.ChartStyle || (themeOpt&&themeOpt.lineOptionList[index].lineType||'spline');
+				//图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const colorIndex = themeOpt ? index%themeOpt.colorsOptions.length : index
+				const defaultOptIndex = index%defaultOpts.colors.length
+				const lineIndex = themeOpt ? index%themeOpt.lineOptionList.length : index
+
+				item.ChartColor = item.ChartColor || (themeOpt&&themeOpt.colorsOptions[colorIndex]||defaultOpts.colors[defaultOptIndex]);
+				item.PredictChartColor = item.PredictChartColor || (themeOpt&&themeOpt.colorsOptions[colorIndex]||defaultOpts.colors[defaultOptIndex]);
+				item.ChartStyle = item.ChartStyle || (themeOpt &&themeOpt.lineOptionList[lineIndex].lineType||'spline');
 				
 				let configLineWid = index===0?3:1;//兼容预测指标绘图无主题配置
-				this.tableData[index].ChartWidth = this.tableData[index].ChartWidth || (themeOpt&&themeOpt.lineOptionList[index].lineWidth||configLineWid);
+				this.tableData[index].ChartWidth = this.tableData[index].ChartWidth || (themeOpt&&themeOpt.lineOptionList[lineIndex].lineWidth||configLineWid);
 			})
 		},
 
@@ -969,12 +973,16 @@ export default {
 
 			let themeOpt = JSON.parse(this.chartInfo.ChartThemeStyle);
 			this.tableData.forEach((item,index) => {
-				item.ChartColor = themeOpt.colorsOptions[index];
-				item.PredictChartColor = themeOpt.colorsOptions[index];
-				item.ChartStyle = themeOpt.lineOptionList[index].lineType||'spline';
+				//图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const colorIndex = themeOpt ? index%themeOpt.colorsOptions.length : index
+				const lineIndex = themeOpt ? index%themeOpt.lineOptionList.length : index
+
+				item.ChartColor = themeOpt && themeOpt.colorsOptions[colorIndex];
+				item.PredictChartColor = themeOpt && themeOpt.colorsOptions[colorIndex];
+				item.ChartStyle = themeOpt && themeOpt.lineOptionList[lineIndex].lineType||'spline';
 				item.isAxis = item.isAxis||1;
 
-				this.tableData[index].ChartWidth = themeOpt.lineOptionList[index].lineWidth;
+				this.tableData[index].ChartWidth = themeOpt && themeOpt.lineOptionList[lineIndex].lineWidth;
 			})
 
 		},

+ 47 - 35
src/views/dataEntry_manage/mixins/chartPublic.js

@@ -677,11 +677,11 @@ export const chartSetMixin = {
     /* 切换相关性图中英文 */
     changeRelevanceLang(){
         this.options.yAxis.forEach(item => {
-          item.title.text = this.currentLang == 'zh' ? item.title.textCh : item.title.textEn
+          item.title.text = this.currentLang == 'zh' ? item.title.textCh : item.title.textEn||item.title.textCh
         });
         //图例
         this.options.series.forEach(item => {
-          item.name = this.currentLang == 'zh' ? item.nameCh : item.nameEn
+          item.name = this.currentLang == 'zh' ? item.nameCh : item.nameEn||item.nameCh
         });
         //tooltip
         this.options.tooltip.formatter = this.currentLang == 'zh' ? this.options.tooltip.formatterCh : this.options.tooltip.formatterEn
@@ -819,12 +819,13 @@ export const chartSetMixin = {
           
         //预测指标配置
         let predict_params = item.EdbInfoCategoryType === 1 ? this.getPredictParams(item) : {};
-
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         //数据列
         let obj = {
           data: [],
-          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
-          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid',
           yAxis: sameSideIndex,
           name:
             dynamic_arr.length > 1
@@ -835,12 +836,12 @@ export const chartSetMixin = {
           : `${item.EdbAliasName||item.EdbName}${dynamic_tag}`,
           nameEn:item.EdbNameEn?`${item.EdbNameEn}${dynamic_tag_en}`:`${item.EdbAliasName||item.EdbName}${dynamic_tag}`,
           color: item.ChartColor,
-          lineWidth: Number(item.ChartWidth)||(chartTheme&&chartTheme.lineOptionList[index].lineWidth),
-          marker: chartTheme && chartTheme.lineOptionList[index].dataMark && chartTheme.lineOptionList[index].dataMark!='none'?{
+          lineWidth:Number(item.ChartWidth)|| (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth)||1,
+          marker: chartTheme && chartTheme.lineOptionList[lineIndex].dataMark && chartTheme.lineOptionList[lineIndex].dataMark!='none'?{
             enabled:true,
-            symbol: chartTheme.lineOptionList[index].markType || 'circle',
-            fillColor:chartTheme.lineOptionList[index].markColor,
-            radius: chartTheme.lineOptionList[index].markSize
+            symbol: chartTheme.lineOptionList[lineIndex].markType || 'circle',
+            fillColor:chartTheme.lineOptionList[lineIndex].markColor,
+            radius: chartTheme.lineOptionList[lineIndex].markSize
           }:{},
           ...predict_params
         };
@@ -1024,7 +1025,8 @@ export const chartSetMixin = {
 
         //预测指标配置
         let predict_params = item.EdbInfoCategoryType === 1 ? this.getPredictParams(item,chartStyle) : {};
-
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         //数据列
         let obj = {
           data: [],
@@ -1039,7 +1041,7 @@ export const chartSetMixin = {
           : `${item.EdbAliasName||item.EdbName}${dynamic_tag}`,
           nameEn:item.EdbNameEn?`${item.EdbNameEn}${dynamic_tag_en}`:`${item.EdbAliasName||item.EdbName}${dynamic_tag}`,
           color: item.ChartColor,
-          lineWidth: Number(item.ChartWidth)||(chartTheme&&chartTheme.lineOptionList[index].lineWidth),
+          lineWidth: Number(item.ChartWidth)||(chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 1,
           fillColor: (this.chartInfo.ChartType === 3 || (this.chartInfo.ChartType === 6 && item.ChartStyle === 'areaspline')) ? item.ChartColor : undefined,
           borderWidth: 1,
           borderColor: item.ChartColor,
@@ -1050,7 +1052,7 @@ export const chartSetMixin = {
         for (let i of item.DataList) {
           obj.data.push([i.DataTimestamp, i.Value]);
         }
-
+        console.log(obj,'obj');
         data.push(obj);
         ydata.push(yItem);
       });
@@ -1121,19 +1123,20 @@ export const chartSetMixin = {
         // console.log(j,index);
         //预测指标配置
         let predict_params =  chartData.EdbInfoCategoryType === 1 ? this.getSeasonPredictParams(j.CuttingDataTimestamp) : {};
-
+        // 图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+        const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         let serie_item = {
           data: [],
-          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || chartData.ChartStyle,
-          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
+          type: (chartTheme && chartTheme.lineOptionList[lineIndex].lineType) || chartData.ChartStyle,
+          dashStyle: (chartTheme && chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid',
           yAxis: 0,
           name: this.isPredictorChart?j.Year:j.ChartLegend,
-          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 1,
-          marker: chartTheme && chartTheme.lineOptionList[index].dataMark && chartTheme.lineOptionList[index].dataMark!='none'?{
+          lineWidth: (chartTheme && chartTheme.lineOptionList[lineIndex].lineWidth) || 1,
+          marker: chartTheme && chartTheme.lineOptionList[lineIndex].dataMark && chartTheme.lineOptionList[lineIndex].dataMark!='none'?{
             enabled:true,
-            symbol: chartTheme.lineOptionList[index].markType || 'circle',
-            fillColor:chartTheme.lineOptionList[index].markColor,
-            radius: chartTheme.lineOptionList[index].markSize
+            symbol: chartTheme.lineOptionList[lineIndex].markType || 'circle',
+            fillColor:chartTheme.lineOptionList[lineIndex].markColor,
+            radius: chartTheme.lineOptionList[lineIndex].markSize
           }:{},
           ...predict_params
         };
@@ -1604,18 +1607,19 @@ export const chartSetMixin = {
         //处理首或/尾全是无效数据的以null填充
         let filterData = this.filterInvalidData(item)
         // console.log(filterData)
-      
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         let serie_item = {
           data: filterData,
-          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
-          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid',
           yAxis: 0,
           name: item.Name,
           nameCh: item.Name,
           nameEn: item.NameEn,
           color: item.Color,
           chartType: 'linear',
-          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 3,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 3,
           marker: {
             enabled: false
           }
@@ -1841,17 +1845,19 @@ export const chartSetMixin = {
       //处理series
       let seriesData=[]
       this.relevanceChartData.YDataList.forEach((item,index)=>{
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         let serie_item = {
           data: item.Value,
-          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
-          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid',
           yAxis: 0,
           name: item.Name,
           nameCh: item.Name,
           nameEn: item.NameEn,
           color: item.Color,
           chartType: 'linear',
-          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 3,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 3,
           marker: {
             enabled: false
           }
@@ -1966,6 +1972,8 @@ export const chartSetMixin = {
       //数据列
       let series = [];
       DataList.forEach((item,index) => {
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         //数据列
         let series_item = {
           data: [],
@@ -1977,7 +1985,7 @@ export const chartSetMixin = {
           chartType: 'linear',
           zIndex:1,
           marker: {
-            radius: (chartTheme&&chartTheme.lineOptionList[index].radius)||5,
+            radius: (chartTheme&&chartTheme.lineOptionList[lineIndex].radius)||5,
           },
         }
         item.EdbInfoList.forEach(_ => {
@@ -2172,17 +2180,19 @@ export const chartSetMixin = {
       //系列
       let series = [];
       YDataList.forEach((item,index) => {
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         let serie_item = {
           data: item.Value,
           pointPlacement: 'on',
-          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'line',
-          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'line',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid',
           yAxis: 0,
           name: item.Name || item.Date,
           nameCh: item.Name || item.Date,
           nameEn: item.Date,
           color: item.Color,
-          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 1,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 1,
           chartType: 'linear'
         };
         series.push(serie_item)
@@ -2258,16 +2268,18 @@ export const chartSetMixin = {
           tickWidth: 1,
         }
 
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         let series_item = {
           data: item.Value.map(_ =>[_.X,_.Y]),
-          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
-          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'spline',
           yAxis: index,
           name: item.Name,
           nameCh: item.Name,
           nameEn: item.NameEn||item.Name,
           color: item.Color,
-          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth)||3,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth)||3,
           chartType: 'linear',
           zIndex:1
         }

+ 387 - 0
src/views/dataEntry_manage/thirdBase/Wind.vue

@@ -0,0 +1,387 @@
+<template>
+  <div class="Wind-container" id="box">
+    <div class="left-cont" id="left">
+      <div class="scroll-wrap">
+        <el-tree
+          ref="treeRef"
+          class="target_tree"
+          :data="classifyList"
+          node-key="UniqueCode"
+          :props="{
+            label: 'ClassifyName',
+            children: 'Children',
+            isLeaf:'isLeaf'
+          }"
+          :current-node-key="select_node"
+          :default-expanded-keys="defaultShowNodes"
+          :expand-on-click-node="false"
+          check-strictly
+          :empty-text="$t('Common.no_classify_msg')"
+          lazy
+					:load="getLazyTreeData"
+          @node-expand="handleNodeExpand"
+          @node-collapse="handleNodeCollapse"
+          @current-change="nodeChangeHandle"
+        >
+          <span slot-scope="{ node, data }">{{ currentLang==='zh' ? data.ClassifyName : (data.ClassifyNameEn||data.ClassifyName) }}</span>
+        </el-tree>
+      </div>
+    </div>
+
+    <div
+      class="right-cont"
+      id="right"
+      v-loading="dataloading"
+      :element-loading-text="$t('Table.data_loading')"
+    >
+      <div class="right-cont-top">
+        <el-select
+					v-model="search_txt"
+					v-loadMore="searchLoad"
+					ref="searchRef"
+					:filterable="!search_txt"
+					remote
+					clearable
+					:placeholder="$t('Edb.InputHolderAll.input_name_orid')"
+					style="width: 360px;"
+					:remote-method="searchHandle"
+					@click.native="inputFocusHandle"
+				>
+					<i slot="prefix" class="el-input__icon el-icon-search"></i>
+					<el-option
+						v-for="item in searchOptions"
+						:key="item.EdbInfoId"
+						:label="currentLang==='en'?(item.EdbNameEn||item.EdbName):item.EdbName"
+						:value="item.EdbInfoId"
+					>
+						<div>
+							<img 
+								:src="$icons.lock_ico2" 
+								width="18" 
+								height="18" 
+								style="vertical-align:middle" 
+								v-if="!item.HaveOperaAuth"
+							/>
+							{{currentLang==='en'?(item.EdbNameEn||item.EdbName):item.EdbName}}
+						</div>
+					</el-option>
+				</el-select>
+      </div>
+      <el-table ref="tableRef" :data="tableData" border class="data-source-table" height="calc(100% - 60px)">
+        <!-- 指标Id -->
+        <el-table-column prop="EdbCode" :label="$t('Edb.Detail.e_id')" show-overflow-tooltip>
+          <template slot-scope="scope">
+            {{scope.row.EdbCode}}
+          </template>
+        </el-table-column>
+        <!-- 指标名称 -->
+        <el-table-column prop="EdbName" :label="$t('Edb.Detail.e_name')" show-overflow-tooltip>
+          <template slot-scope="scope">
+            {{currentLang==='en'?scope.row.EdbNameEn:scope.row.EdbName}}
+          </template>
+        </el-table-column>
+        <!-- 频度 -->
+        <el-table-column prop="Frequency" :label="$t('Edb.Detail.e_fre')">
+          <template slot-scope="scope">
+            {{scope.row.Frequency}}
+          </template>
+        </el-table-column>
+        <!-- 单位 -->
+        <el-table-column prop="Unit" :label="$t('Edb.Detail.e_unit')">
+          <template slot-scope="scope">
+            {{currentLang==='en'?scope.row.UnitEn:scope.row.Unit}}
+          </template>
+        </el-table-column>
+        <!-- 目录 -->
+        <el-table-column prop="ClassifyList" :label="$t('Edb.Detail.e_catalogue')" show-overflow-tooltip>
+          <template slot-scope="scope">
+            {{scope.row.ClassifyList.map(cl => cl.ClassifyName).reverse().join('/')+'/'}}
+          </template>
+        </el-table-column>
+        <!-- 起始时间 -->
+        <el-table-column prop="StartDate" :label="$t('Edb.Detail.e_start_time')">
+          <template slot-scope="scope">
+            {{scope.row.StartDate}}
+          </template>
+        </el-table-column>
+        <!-- 更新时间 -->
+        <el-table-column prop="ModifyTime" :label="$t('Edb.Detail.e_update_time')">
+          <template slot-scope="scope">
+            {{scope.row.ModifyTime}}
+          </template>
+        </el-table-column>
+        <!-- 刷新状态 -->
+        <el-table-column prop="NoUpdate" :label="$t('Edb.Detail.e_status')">
+          <template slot-scope="scope">
+            {{scope.row.NoUpdate==0?'启用':'停用'}}
+          </template>
+        </el-table-column>
+        <!-- 创建人 -->
+        <el-table-column prop="SysUserRealName" :label="$t('Edb.Detail.e_creator')">
+          <template slot-scope="scope">
+            {{scope.row.SysUserRealName}}
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+  </div>
+</template>
+
+<script>
+import { windInterface } from "@/api/modules/thirdBaseApi";
+import { dataBaseInterface } from '@/api/api.js';
+import leftMixin from "./mixins/leftMixin.js";
+export default {
+  name: "Wind",
+  mixins: [leftMixin],
+  components: {},
+  data() {
+    return {
+      dataloading: false,
+      classifyList: [],
+      select_classify: 0,
+      select_edbId: 0, //添加指标后的code,无论是否加载出来,无论是否加载成功
+      select_node: "",
+      defaultShowNodes: [], //展开节点
+      tableData:[],
+
+      search_txt:"",
+      search_page: 1,
+			search_have_more: false,
+			current_search:'',
+      searchOptions:[],
+    };
+  },
+  watch:{
+    select_edbId(newval) {
+			if(newval) {
+				this.getDataList()
+			}
+		},
+    select_classify(newval){
+			if(newval){
+				this.getDataList()
+			}
+		},
+    /* 选中搜索指标 展开目录 选中指标 展示数据 */
+		search_txt(newval) {
+			if (newval) {
+				let [search_obj] = this.searchOptions.filter(
+					(item) => item.EdbInfoId === newval
+				);
+				this.select_node = search_obj.UniqueCode;
+				this.select_edbId = newval;
+				this.select_classify = 0;
+			}
+		},
+  },
+  methods: {
+    /* 获取分类 */
+    getClassify() {
+      windInterface.classifyList().then((res) => {
+        if (res.Ret !== 200) return;
+        this.classifyList = res.Data && res.Data.AllNodes || [];
+        this.select_classify=this.classifyList[0]?this.classifyList[0].ClassifyId||0:0
+        this.select_node=this.classifyList[0]?this.classifyList[0].UniqueCode||'':''
+        this.nodeLocation()
+        this.getDataList()
+      });
+    },
+    //指标懒加载
+    async getLazyTreeData(node,resolve){
+			if(node.level===0){
+				resolve(this.classifyList)
+        this.nodeLocation()
+			}else{
+				let arr=[]
+				const res=await windInterface.classifyList({ParentId:node.data.ClassifyId})
+				if (res.Ret === 200) {
+					const temarr = res.Data.AllNodes || [];
+					arr=temarr.map(item=>{
+						return {
+							...item,
+							isLeaf:item.EdbInfoId?true:false
+						}
+					})
+				}
+				resolve(arr)
+        this.nodeLocation()
+			}
+    },
+
+    /* 获取数据 */
+    getDataList() {
+      this.dataloading = true;
+      windInterface.dataList({
+        ClassifyId:this.select_classify,
+        EdbInfoId:this.select_edbId,
+        PageSize:9999999,
+        CurrentIndex:1
+      }).then((res) => {
+        if (res.Ret !== 200) return;
+        this.tableData=res.Data.List || []
+        if(this.$refs.tableRef && this.$refs.tableRef.$el.querySelector('.el-table__body-wrapper')){
+          this.$refs.tableRef.$el.querySelector('.el-table__body-wrapper').scrollTop=0
+        }
+        // 选中指标对应树节点应该展开的目录
+        if(this.search_txt && this.select_edbId && this.tableData[0]){
+          let classify_arr = this.tableData[0].ClassifyList || [];
+          // 展开目录
+          this.defaultShowNodes=classify_arr.map(item=>item.UniqueCode)
+        }
+      }).finally(()=>{
+        this.dataloading = false;
+      })
+    },
+    /* 改变节点 */
+    nodeChangeHandle(data, node) {
+      if (this.dataloading)
+        return this.$message(this.$t('MsgPrompt.request_frequency'));
+      this.search_txt=''
+      this.select_node = data.UniqueCode;
+      this.select_classify = !data.EdbInfoId?data.ClassifyId:0;
+      this.select_edbId = data.EdbInfoId
+    },
+    // 定位
+    nodeLocation(){
+      this.$nextTick(()=>{
+        setTimeout(() => {
+          this.$refs.treeRef && this.select_node && this.$refs.treeRef.setCurrentKey(this.select_node);
+        }, 100);
+      })
+    },
+    /* 聚焦获取当前检索 */
+		inputFocusHandle(e) {
+			this.search_page = 1;
+			this.current_search = e.target.value;
+			this.searchApi(this.current_search);
+		},
+    searchLoad() {
+			if(!this.search_have_more) return;
+			this.searchApi(this.current_search,++this.search_page);
+		},
+    /* 搜索 */
+		searchHandle(query) {
+			this.search_page = 1;
+			this.current_search = query;
+			this.searchApi(this.current_search)
+		},
+    searchApi(query,page=1) {
+			dataBaseInterface.targetSearchByPage({
+				KeyWord:query,
+				CurrentIndex: page,
+        Source:2, // Wind的
+			}).then(res => {
+				if(res.Ret !== 200) return
+
+				const { List,Paging } = res.Data;
+				this.search_have_more = page < Paging.Pages;
+				this.searchOptions = page === 1 ? List : this.searchOptions.concat(List);
+					
+			})
+		},
+  },
+  computed: {
+    currentLang() {
+      return this.$store.state.lang
+    }
+  },
+  mounted() {
+    this.getClassify();
+  },
+};
+</script>
+<style lang="scss" scoped>
+.Wind-container {
+  display: flex;
+  position: relative;
+  height:calc(100vh - 115px);
+  .left-cont {
+    min-width: 300px;
+    width: 300px;
+    margin-right: 20px;
+    padding: 20px;
+    overflow: hidden;
+    position: relative;
+    height: 100%;
+    background-color: #ffffff;
+    box-sizing: border-box;
+    .scroll-wrap {
+      height: 100%;
+      overflow: hidden auto;
+    }
+    .target_tree {
+      color: #333;
+    }
+  }
+  .right-cont {
+    flex:1;
+    padding: 20px;
+    background-color: #ffffff;
+    box-sizing: border-box;
+    .right-cont-top{
+      display: flex;
+      align-items: center;
+      justify-content: flex-end;
+      margin-bottom: 20px;
+    }
+  }
+}
+</style>
+<style lang="scss">
+.Wind-container {
+  .el-tree-node__content {
+    margin-bottom: 14px !important;
+  }
+
+  .el-tree-node__children {
+    .el-tree-node {
+      margin-bottom: 0px !important;
+      padding-left: 18px;
+    }
+    .el-tree-node__content {
+      margin-bottom: 5px !important;
+      padding-left: 0 !important;
+    }
+  }
+  .expanded.el-icon-caret-right:before {
+    content: url("~@/assets/img/set_m/down.png") !important;
+  }
+  .el-icon-caret-right:before {
+    content: url("~@/assets/img/set_m/slide.png") !important;
+  }
+  .el-tree-node__expand-icon.is-leaf.el-icon-caret-right:before {
+    content: "" !important;
+  }
+  .el-tree-node__expand-icon.expanded {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  .el-tree-node.is-current > .el-tree-node__content {
+    background-color: #f0f4ff !important;
+  }
+  .el-tree-node__content {
+    padding-right: 10px !important;
+  }
+  .right-cont {
+    .data-source-table{
+      .el-table__header{
+        tr{
+          th{
+            background-color: #F0F2F5!important;
+            .cell{
+              font-weight:normal;
+              color:#666666;
+            }
+          }
+        }
+      }
+      .el-table__body{
+        tr{
+          background-color: #ffffff!important;
+        }
+      }
+    }
+  }
+}
+</style>

+ 2 - 2
src/views/dataEntry_manage/thirdBase/selfDataBase.vue

@@ -80,11 +80,11 @@
           >
             <template slot-scope="{row}">
               <template v-if="item.key==='handle'">
-                <span 
+                <span v-permission="permissionBtn.dataSourcePermission.selfData_detail"
                   class="editsty"
                   @click="lookDataHandle(row)"
                 >
-                  <!-- 查看数据 -->{{$t('Edb.detail_lookdata_btn')}}
+                  <!-- 查看详情 -->{{$t('Edb.detail_lookdata2_btn')}}
                 </span>
 
                 <span 

+ 7 - 5
src/views/dataEntry_manage/thirdBase/steelChemicalbase.vue

@@ -173,7 +173,7 @@
               :tableOption="tableOption"
               tableType="header"
               ref="table"
-              source="gl"
+              source="glhg"
               @addToLib="handleAddToLib"
             />
           </div>
@@ -182,7 +182,7 @@
               :tableOption="tableOption"
               tableType="data"
               :dateArr="dateArr"
-              source="gl"
+              source="glhg"
             />
           </div>
           <div v-else class="nodata"></div>
@@ -404,7 +404,8 @@ export default {
                 IndexCode:this.index_code,
                 FrequencyName:'',
                 UnitName:'',
-                UpdateTime:''
+                UpdateTime:'',
+                IsStop:'',
               }]
               //为了美观
               for (let i = 0; i < 6; i++) {
@@ -413,7 +414,8 @@ export default {
                   IndexCode:'',
                   FrequencyName:'',
                   UnitName:'',
-                  UpdateTime:''
+                  UpdateTime:'',
+                  IsStop:'',
                 })
               }
               //为了美观
@@ -510,7 +512,7 @@ export default {
     /* 改变节点 */
     nodeChangeHandle(data, node) {
       if (this.dataloading)
-        return this.$message("请求频繁,请数据加载完成后再试!");
+        return this.$message(this.$t('MsgPrompt.request_frequency'));
       this.dynamicNode = node;
       this.select_node = data.UniqueCode;
       this.select_classify = data.BaseFromMysteelChemicalClassifyId;

+ 70 - 32
src/views/datasheet_manage/common/customTable.js

@@ -70,32 +70,51 @@ export function splitString(str) {
 }
 
 //选中整行整列样式
-export function selectMoreCellStyle(e,type=null) {
+export function selectMoreCellStyle(e) {
   let table = document.querySelector('.table');
   resetStyle();
-
+  let tableRect = table.getBoundingClientRect()
   if($(e.target).hasClass('th-col')) { //点击列
-    // 指标列 日期列显示显示有所区分
-    const columnIndex = Array.from(e.target.parentNode.children).indexOf(e.target);
-    table.rows.forEach((cell,index)=> {
-
-      if(index !==0) {
-        if(type === 1) index === 2 ? $(cell.children[columnIndex-1]).addClass('td-col-select') : $(cell.children[columnIndex]).addClass('td-col-select');
+    let eRect = e.target.getBoundingClientRect()
+    // console.log(eRect,tableRect);
+    $(table.querySelector('#row-col-select')).css({
+      'top':`${eRect.height}px`,
+      'left':`${eRect.x - tableRect.x}px`,
+      'visibility':`visible`,
+      'height':`${tableRect.height-eRect.height-1}px`,
+      'width':`${eRect.width}px`,
+      'border-width':'0 1px 0 1px'})
+    // if(!type){
+    //   $(e.target).addClass('td-col-select-new');
+    // }
 
-        if(type === 2) index === 1 ? $(cell.children[columnIndex-1]).addClass('td-col-select') : $(cell.children[columnIndex]).addClass('td-col-select');
-
-        if(!type) $(cell.children[columnIndex]).addClass('td-col-select');
-      }
-    })
+    // 指标列 日期列显示显示有所区分
+    // const columnIndex = Array.from(e.target.parentNode.children).indexOf(e.target);
+    // table.rows.forEach((cell,index)=> {
+    //   if(index !==0) {
+    //     if(type === 1) index === 2 ? $(cell.children[columnIndex-1]).addClass('td-col-select') : $(cell.children[columnIndex]).addClass('td-col-select');
+
+    //     if(type === 2) index === 1 ? $(cell.children[columnIndex-1]).addClass('td-col-select') : $(cell.children[columnIndex]).addClass('td-col-select');
+        
+    //     if(!type) $(cell.children[columnIndex]).addClass('td-col-select');
+    //   }
+    // })
   }else if($(e.target).hasClass('th-row')) { //点击行
-    e.target.parentNode.children.forEach((cell,index)=> {
-      if(index !==0) {
-        index === 2 ? $(cell).addClass('td-row-select') : $(cell).addClass('td-row-select');
-      }
-    })
+    let eRect = e.target.getBoundingClientRect()
+    // e.target.parentNode.children.forEach((cell,index)=> {
+    //   console.log(cell,index,'index');
+    //   if(index !==0) {
+    //     index === 2 ? $(cell).addClass('td-row-select') : $(cell).addClass('td-row-select');
+    //   }
+    // })
+    $(table.querySelector('#row-col-select')).css({
+      'top':`${eRect.y - tableRect.y}px`,
+      'left':`${eRect.width}px`,
+      'visibility':`visible`,
+      'height':`${eRect.height}px`,
+      'width':`${tableRect.width-eRect.width-1}px`,
+      'border-width':'1px 0 1px 0'})
   }
-
-
 }
 
 // 选中格子样式
@@ -119,15 +138,21 @@ export function resetStyle() {
   table.querySelectorAll(".td-chose").forEach(el => {
     el.classList.remove('td-chose')
   })
-  table.querySelectorAll(".td-col-select").forEach(el => {
-    el.classList.remove('td-col-select')
-  })
-  table.querySelectorAll(".td-row-select").forEach(el => {
-    el.classList.remove('td-row-select')
-  })
+  // table.querySelectorAll(".td-col-select").forEach(el => {
+  //   el.classList.remove('td-col-select')
+  // })
+  // table.querySelectorAll(".td-row-select").forEach(el => {
+  //   el.classList.remove('td-row-select')
+  // })
   table.querySelectorAll(".td-relation").forEach(el => {
     el.classList.remove('td-relation')
   })
+  $(table.querySelector('#row-col-select')).css({
+    'top':0,
+    'left':0,
+    'visibility':`hidden`,
+    'height':0,
+    'width':0})
 }
 
 //单击聚焦
@@ -146,11 +171,19 @@ export function setCellBg(e) {
   e.target.parentNode.parentNode.nodeName==='TD' && $(e.target.parentNode.parentNode).addClass("insert")
 }
 
-//右键菜单
-export function getRightClickMenu(pos,canEdit=false,isStaticTable=false) {
-  // 如果是静态表则只有清空功能
+/**
+ * 右键菜单
+ * @param {*} pos 类型 cell-单元格 selection-选区 col-列头 row-行头
+ * @param {*} canEdit 单元格是否可编辑
+ * @param {*} isStaticTable 是否是静态表 -- 平衡表中
+ * @param {*} extraConfig 额外的配置 cellMerged-是否合并了单元格
+ * @returns 
+ */
+export function getRightClickMenu(pos,canEdit=false,isStaticTable=false,extraConfig={}) {
+  // 如果是静态表则有清空功能、清除单元格
   if(isStaticTable){
-    return [{ label: bus.$i18nt ? bus.$i18nt.t('SystemManage.ReportApprove.clear_btn'):"清空", key: "reset" }]
+    return [{ label: bus.$i18nt ? bus.$i18nt.t('ETable.Btn.unmerge_cell') : '取消合并单元格',key: 'cell-unmerge',hidden:!extraConfig.cellMerged },
+      { label: bus.$i18nt ? bus.$i18nt.t('SystemManage.ReportApprove.clear_btn'):"清空", key: "reset" }].filter(me => !me.hidden)
   }
 
   let cellMenu = [
@@ -178,6 +211,7 @@ export function getRightClickMenu(pos,canEdit=false,isStaticTable=false) {
         { label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.day_mean') : '日均值',source: 16,fromEdbKey:75 },
       ]
     },
+    { label: bus.$i18nt ? bus.$i18nt.t('ETable.Btn.unmerge_cell') : '取消合并单元格',key: 'cell-unmerge',hidden:!extraConfig.cellMerged },
     { label: bus.$i18nt ? bus.$i18nt.t('SystemManage.ReportApprove.clear_btn'):"清空", key: "reset" },
   ]
 
@@ -193,8 +227,12 @@ export function getRightClickMenu(pos,canEdit=false,isStaticTable=false) {
       { label: bus.$i18nt ? bus.$i18nt.t('ETable.Btn.delete_btn') : "删除", key: "del" },
     ],
     'cell': canEdit 
-      ? [{ label: bus.$i18nt ? bus.$i18nt.t('ETable.Btn.edit_btn') : '编辑',key: 'cell-edit' },...cellMenu]
-      : cellMenu
+      ? [{ label: bus.$i18nt ? bus.$i18nt.t('ETable.Btn.edit_btn') : '编辑',key: 'cell-edit' },...cellMenu.filter(me => !me.hidden)]
+      : cellMenu.filter(me => !me.hidden),
+    'selection':[
+      extraConfig.cellMerged ? { label: bus.$i18nt ? bus.$i18nt.t('ETable.Btn.unmerge_cell') : '取消合并单元格',key: 'cell-unmerge' }:
+      { label: bus.$i18nt ? bus.$i18nt.t('ETable.Btn.merge_cell') : '合并单元格',key: 'cell-merge' }
+    ]
   }
 
   return menuMap[pos];

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 742 - 85
src/views/datasheet_manage/components/BalanceTable.vue


+ 43 - 39
src/views/datasheet_manage/components/CustomTable.vue

@@ -12,7 +12,7 @@
 
       <!-- 日期行表格 -->
       <div class="table-wrapper" v-if="config.type === 1">
-        <table width="auto" border="0" class="table" :style="disabled ? 'width:100%':''">
+        <table width="auto" border="0" class="table" :style="disabled ? 'width:100%':''" style="position: relative;">
           <thead>
             <tr>
               <!-- 行头 -->
@@ -143,13 +143,16 @@
               </td>
             </tr>
           </tbody>
+          <!-- 行列选中样式 -->
+          <div ref="rowColSelectRef" id="row-col-select" 
+          style="position: absolute;border-color: #18ad18;border-style: solid;background-color: transparent;visibility: hidden;z-index: 1;pointer-events: none;"></div>
         </table>
       </div>
       
 
       <!-- 日期列表格 -->
       <div class="table-wrapper" v-else>
-        <table width="auto" border="0" class="table" :style="disabled ? 'width:100%':''">
+        <table width="auto" border="0" class="table" :style="disabled ? 'width:100%':''" style="position: relative;">
           <thead>
             <tr>
               <!-- 行头 -->
@@ -312,6 +315,9 @@
         
             </tr>
           </tbody>
+          <!-- 行列选中样式 -->
+          <div ref="rowColSelectRef" id="row-col-select" 
+          style="position: absolute;border-color: #18ad18;border-style: solid;background-color: transparent;visibility: hidden;z-index: 1;pointer-events: none;"></div>
         </table>
       </div>
 
@@ -429,15 +435,6 @@ export default {
         resetStyle();
       })
     },
-    // 'config.data':{
-    //   handler(value){
-    //     console.log(value,'valuevaluevalue');
-    //     if(!this.disabled && this.hasInit){
-    //       this.$emit("autoSave")
-    //     }
-    //   },
-    //   deep:true
-    // },
     'config.textRowData':{
       handler(value){
         if(!this.disabled && this.hasInit){
@@ -705,7 +702,7 @@ export default {
 			dom.style.left = e.clientX-3 + 'px';
 			dom.style.top = e.clientY-3 + 'px';
       
-      selectMoreCellStyle(e,this.config.type)
+      selectMoreCellStyle(e)
     },
 
     /*  */
@@ -732,6 +729,10 @@ export default {
           this.config.textRowData.forEach(row => {
             row.splice(index+1,1)
           })
+          // 删除的是最后一列
+          if(!(index < this.config.data[0].length)){
+            resetStyle()
+          }
       }else if(cindex === '-1') { //删除行
         console.log('删除行',rindex)
 
@@ -746,7 +747,10 @@ export default {
             _.Data.splice(index,1)
           })
         }
-
+        // 删除的是最后一行
+        if(!(index < this.config.data.length)){
+          resetStyle()
+        }
         
       }
       if(!this.disabled && this.hasInit){
@@ -926,32 +930,32 @@ export default {
       border: 2px solid #0033FF;
       box-shadow: 0 0 5px rgba(73, 177, 249, .5)
     }
-    &.td-col-select::after {
-      position: absolute;
-      top: 0;
-      left: 0;
-      right: 0;
-      bottom: 0;
-      content: "";
-      display: block;
-      outline: 0;
-      border: 1px solid rgb(24, 173, 24);
-      border-bottom: none;
-      border-top: none;
-    }
-    &.td-row-select::after {
-      position: absolute;
-      top: 0;
-      left: 0;
-      right: 0;
-      bottom: 0;
-      content: "";
-      display: block;
-      outline: 0;
-      border: 1px solid rgb(24, 173, 24);
-      border-left: none;
-      border-right: none;
-    }
+    // &.td-col-select::after {
+    //   position: absolute;
+    //   top: 0;
+    //   left: 0;
+    //   right: 0;
+    //   bottom: 0;
+    //   content: "";
+    //   display: block;
+    //   outline: 0;
+    //   border: 1px solid rgb(24, 173, 24);
+    //   border-bottom: none;
+    //   border-top: none;
+    // }
+    // &.td-row-select::after {
+    //   position: absolute;
+    //   top: 0;
+    //   left: 0;
+    //   right: 0;
+    //   bottom: 0;
+    //   content: "";
+    //   display: block;
+    //   outline: 0;
+    //   border: 1px solid rgb(24, 173, 24);
+    //   border-left: none;
+    //   border-right: none;
+    // }
     &.insert {
       background: #FFEFDD;
     }

+ 651 - 97
src/views/datasheet_manage/components/MixedTable.vue

@@ -3,7 +3,8 @@
     <template v-if="config.data.length">
 
       <!-- 工具栏 -->
-      <toolBarSection v-if="!disabled" :cell="selectCell" @updateCell="updateCellStyle"/>
+      <toolBarSection v-if="!disabled" :cell="selectCell?selectCell:selectedCells" @cellMerge="toolCellMergeFun"
+        :echoParameter="{hasMergedCell}"/>
       
       <!-- 公式显示区 -->
       <div class="formula-wrapper" v-if="!disabled">
@@ -20,6 +21,9 @@
         border="0"
         class="table"
         :style="disabled ? 'width:100%' : ''"
+        ref="tableRef"
+        style="position: relative;"
+        @mousedown="selectCellHandle"
       >
         <thead>
           <tr>
@@ -57,7 +61,12 @@
               :key="`${index}_${cell_index}`"
               :data-rindex="rowHeader[index]"
               :data-cindex="columnHeader[cell_index]"
+              :data-datarindex="index"
+              :data-datacindex="cell_index"
               :data-key="cell.Uid"
+              v-show="!cell.merData || cell.merData.type!=='merged'"
+              :colspan="(cell.merData && cell.merData.type=='merge' && cell.merData.mer)?cell.merData.mer.colspan || 1:1"
+              :rowspan="(cell.merData && cell.merData.type=='merge' && cell.merData.mer)?cell.merData.mer.rowspan || 1:1"
               @click="clickCell($event, cell)"
               @dblclick="dblClickCellHandle($event,cell)"
               @contextmenu.prevent="rightClickHandle($event,cell)"
@@ -99,6 +108,8 @@
                   slot="reference"
                   :data-rindex="rowHeader[index]"
                   :data-cindex="columnHeader[cell_index]"
+                  :data-datarindex="index"
+                  :data-datacindex="cell_index"
                   :data-key="cell.Uid"
                 >{{ cell.ShowStyle?cell.ShowFormatValue:cell.ShowValue }}</span>
               </el-popover>
@@ -108,6 +119,8 @@
                 v-else-if="cell.ShowStyle"
                 :data-rindex="rowHeader[index]"
                 :data-cindex="columnHeader[cell_index]"
+                :data-datarindex="index"
+                :data-datacindex="cell_index"
                 :data-key="cell.Uid"
               >
                 {{cell.ShowFormatValue}}
@@ -116,6 +129,8 @@
               <span
                 :data-rindex="rowHeader[index]"
                 :data-cindex="columnHeader[cell_index]"
+                :data-datarindex="index"
+                :data-datacindex="cell_index"
                 :data-key="cell.Uid"
                 v-else
               >{{ cell.ShowValue }}</span>
@@ -129,6 +144,8 @@
                 :data-key="cell.Uid"
                 :data-rindex="rowHeader[index]"
                 :data-cindex="columnHeader[cell_index]"
+                :data-datarindex="index"
+                :data-datacindex="cell_index"
                 :fetch-suggestions="searchTarget"
                 @change.native="changeVal($event, cell)"
                 @keydown.native="keyEnterHandle($event,cell)"
@@ -152,6 +169,12 @@
             </td>
           </tr>
         </tbody>
+        <!-- 选区 -->
+        <div ref="selectionRef" id="selection-id"
+        style="position: absolute;border: 2px solid #0052D9;background-color: rgba(0, 82, 217, 0.1);visibility: hidden;z-index: 1;pointer-events: none;"></div>
+        <!-- 行列选中样式 -->
+        <div ref="rowColSelectRef" id="row-col-select" 
+        style="position: absolute;border-color: #18ad18;border-style: solid;background-color: transparent;visibility: hidden;z-index: 1;pointer-events: none;"></div>
       </table>
 
       <!-- 右键菜单 -->
@@ -239,7 +262,8 @@ import {
   toUpperCase,
   findCellKeyByFactor,
   isNumberVal,
-  transDecimalPlace
+  transDecimalPlace,
+  resetStyle
 } from "../common/customTable";
 import * as sheetInterface from "@/api/modules/sheetApi.js";
 import { dataBaseInterface } from '@/api/api.js';
@@ -301,6 +325,16 @@ export default {
       },
       deep:true
     },
+    'endCell.row':{
+      handler(newVal){
+        this.setSelectionStyle()
+      }
+    },
+    'endCell.column':{
+      handler(newVal){
+        this.setSelectionStyle()
+      }
+    }
   },
   data() {
     return {
@@ -349,8 +383,40 @@ export default {
       isInsertCalculateDate: false,//日期计算弹窗
       insertCalculateDateInfo: {},//日期计算info
 
-      activeNames: []
-
+      activeNames: [],
+      // 合并单元格data
+      isSelectionStart:false, //选区开始
+      startCell:{// 选区时鼠标开始的单元格
+        row:null,
+        column:null
+      }, 
+      endCell:{// 选区时鼠标结束的单元格
+        row:null,
+        column:null
+      },
+      selectionStart:{// 选区范围的左上角单元格
+        row:null,
+        rowSpan:0,
+        column:null,
+        colSpan:0
+      },
+      selectionEnd:{// 选区范围的右下角角单元格
+        row:null,
+        rowSpan:0,
+        column:null,
+        colSpan:0
+      },
+      hasMergedCell:false,// 选区内是否有合并的单元格
+      selectedCells:[],
+      // 选区有'值'单元格 因为超一个单元格有值不让合并,所以记录一个就行
+      hasValueCellItem:{
+        cellNumber:0, //有几个
+        row:null,
+        column:null
+      },
+      // 做个缓存
+      cacheKey:'',
+      cacheCellDom:{}
     };
   },
   mounted() {
@@ -390,8 +456,9 @@ export default {
       if(this.disabled) return
 
       selectCellStyle(e);
+      this.clearSelection()
+      this.hasMergedCell = !!(cell && cell.merData)
       this.selectCell = cell;
-      
       setFocus(e);
 
       //是插值单元格时寻找关联依赖的单元格 设置选框
@@ -399,7 +466,6 @@ export default {
         const { key } = e.target.dataset;
         if(!this.insertRelationArr.find(_ => _.key===key)) return
         let { relation_date,relation_edb } = this.insertRelationArr.find(_ => _.key===key)
-
         relation_date.key && setRelationStyle(relation_date)
         relation_edb.key && setRelationStyle(relation_edb)
       }
@@ -519,26 +585,25 @@ export default {
     },
 
     /* 选择指标 单元格类型为2 已经是指标单元格了就重置单元格 否则就视为选择指标*/
-    selectTarget(e,cell) {
-      const { EdbName,EdbInfoId }  = e;
-
-      //如果已经是指标单元格了再次点击就清空
-      if(cell.DataType===2&&cell.EdbInfoId) {
-        this.clearCell()
-      }else {
-        cell.DataType = 2;
-        cell.DataTime = '';
-        cell.ShowValue = EdbName;
-        cell.Value = EdbName;
-        cell.EdbInfoId = EdbInfoId;
-      }
-
-      this.checkCellRelation(cell)
-    },
+    // selectTarget(e,cell) {
+    //   const { EdbName,EdbInfoId }  = e;
+
+    //   //如果已经是指标单元格了再次点击就清空
+    //   if(cell.DataType===2&&cell.EdbInfoId) {
+    //     this.clearCell()
+    //   }else {
+    //     cell.DataType = 2;
+    //     cell.DataTime = '';
+    //     cell.ShowValue = EdbName;
+    //     cell.Value = EdbName;
+    //     cell.EdbInfoId = EdbInfoId;
+    //   }
+
+    //   this.checkCellRelation(cell)
+    // },
 
     /* 输入框失焦 设置单元格类型 处理关联关系 */
     async changeVal(e, cell) {
-
       // 是日期格式 DataType为1
       // 自定义内容 DataType 3
       //有=号为输入公式 DataType 6
@@ -563,14 +628,13 @@ export default {
           cell.DataTime = dateFormat;
           cell.Value = dateFormat;
         }else if(value.startsWith('=')) { //公式单元格
+          cell.Value = value;
           cell.DataType = 6;
           let calculateVal = await this.getValueByFormula(value);
           if(!calculateVal) return
           cell.ShowValue = calculateVal;
           //处理公式关系
           this.$set(cell,'Extra',this.dealFormulaConstruction(value))
-          
-
         }else {//自定义值
           cell.DataType = 3;
           cell.ShowValue = value;
@@ -637,7 +701,11 @@ export default {
       let relationIndex = this.insertRelationArr.findIndex(_ => _.key===key)
       this.insertRelationArr.splice(relationIndex,1)
     },
-
+    // 替换关联关系
+    replaceCellRelation(originKey,replaceKey){
+      if(!this.insertRelationArr.length) return
+      this.insertRelationArr = JSON.parse(JSON.stringify(this.insertRelationArr).replaceAll(originKey,replaceKey))
+    },
     /* 单元格更新时去更新有依赖关系单元格的值 目前只更4 5 7*/
     updateRelationCell(relation,cell) {
       const cellTypeMap = {
@@ -770,7 +838,6 @@ export default {
 
       // 提取因数数组
       let factors = extractFactorsFromFormula(val)
-      console.log(factors)
       
       //根据因数找单元格
       let isAllCell = factors.some(_ => findCellByFactorMixed(this.config.data,_)===null||isNaN(findCellByFactorMixed(this.config.data,_)))
@@ -785,7 +852,7 @@ export default {
           TagMap[_] = Number(findCellByFactorMixed(this.config.data,_))
         }
       });
-
+      
       const res = await sheetInterface.calculateCustomCellData({
         CalculateFormula: val,
         TagMap
@@ -803,10 +870,12 @@ export default {
     rightClickHandle(e,cell) {
       if(this.disabled) return
 
-      const { rindex,cindex,key } = e.target.dataset;
+      const { rindex,cindex,key,datacindex,datarindex } = e.target.dataset;
       this.rightClickCell = {
         rindex,
         cindex,
+        datarindex,
+        datacindex,
         key
       }
 
@@ -817,12 +886,20 @@ export default {
         pos = 'col'
       }else if(cindex==='-1') { //行头
         pos = 'row'
+      }else if( datarindex>=this.selectionStart.row && datarindex<=this.selectionEnd.row &&
+      datacindex>=this.selectionStart.column && datacindex<=this.selectionEnd.column &&
+      (this.selectionEnd.row-this.selectionStart.row>0||this.selectionEnd.column-this.selectionStart.column>0)){
+        // 选区
+        pos = 'selection'
       }else {//单元格
         pos = 'cell'
       }
+
+      pos==='cell' && this.clickCell(e,cell);
+
       this.config.contextMenuOption = pos === 'cell' 
-        ? getRightClickMenu(pos,(cell.DataType===1&&[1,2].includes(cell.DataTimeType))||[5,7,8].includes(cell.DataType))
-        : getRightClickMenu(pos)
+        ? getRightClickMenu(pos,(cell.DataType===1&&[1,2].includes(cell.DataTimeType))||[5,7,8].includes(cell.DataType),false,{cellMerged:this.hasMergedCell})
+        : getRightClickMenu(pos,false,false,{cellMerged:this.hasMergedCell})
 
       this.$nextTick(() => {
         let dom = $('#contextMenu-wrapper')[0];
@@ -835,9 +912,10 @@ export default {
           dom.style.top = e.clientY-3 + 'px';
         }
 
-        ['col','row'].includes(pos) && selectMoreCellStyle(e);
-        pos==='cell' && this.clickCell(e,cell);
-
+        if(['col','row'].includes(pos)){
+          this.clearSelection()
+          selectMoreCellStyle(e);
+        }
       })
       
     },
@@ -872,7 +950,9 @@ export default {
         // 'insert-edb-date': this.insertDateOpen,//导入指标日期
         'insert-date-calculate': this.insertDateCalculateOpen,//日期计算弹窗
         'reset': this.clearCell, //清空
-        'cell-edit': this.selectCell ? editHandlesMap[this.selectCell.DataType] : null
+        'cell-edit': this.selectCell ? editHandlesMap[this.selectCell.DataType] : null,
+        'cell-merge':this.mergeCellFun,
+        'cell-unmerge':this.unmergeCellsFun
       }
       keyMap[key] && keyMap[key](key)
       
@@ -929,22 +1009,38 @@ export default {
 
     },
 
-    /* 清除单元格内容 格式 关联关系 */
-    clearCell() {
-      if([4,5].includes(this.selectCell.DataType)) resetRelationStyle();
+    /* 
+      清除单元格内容 格式 关联关系 
+      config:{
+        single:true 清除单个,不考虑合并单元格的联系
+      }
+    */
+    clearCell(c) {
+      const isCell = c && typeof(c)=='object' && c.Uid
+      const cell = isCell ? c: this.selectCell
+
+      if([4,5].includes(cell.DataType)) resetRelationStyle();
+
+      cell.DataType = 3;
+      cell.ShowValue = '';
+      cell.Value = '';
+      cell.DataTime = '';
+      cell.DataTimeType = 0;
+      cell.EdbInfoId = 0;
+      cell.ShowStyle = '';
+      cell.ShowFormatValue = '';
+      cell.Extra && (cell.Extra = '');
 
-      this.selectCell.DataType = 3;
-      this.selectCell.ShowValue = '';
-      this.selectCell.Value = '';
-      this.selectCell.DataTime = '';
-      this.selectCell.DataTimeType = 0;
-      this.selectCell.EdbInfoId = 0;
-      this.selectCell.ShowStyle = '';
-      this.selectCell.ShowFormatValue = '';
+      this.checkCellRelation(cell)
 
-      this.checkCellRelation(this.selectCell)
     },
-
+    findDataByStartKey(key){
+      if(!key) return {data:{},row:-1,col:-1}
+      let mergeCellDom = this.$refs.tableRef.querySelector(`[data-key="${key}"]`)
+      let row = +mergeCellDom.dataset.datarindex
+      let col = +mergeCellDom.dataset.datacindex
+      return {data:this.config.data[row][col],row,col}
+    },
     /* 删除行列 */
     delColOrRow() {
       let { rindex,cindex } = this.rightClickCell;
@@ -956,23 +1052,113 @@ export default {
 
         let index = this.columnHeader.findIndex(_ => _ === cindex);
 
+        // 处理删除列对合并单元格的影响
+        let startMainKey=''
+        this.config.data.map((row,rowInd) => {
+          let rowEle=row[index]
+          if(rowEle.merData){
+            let {data,row,col} = this.findDataByStartKey(rowEle.merData.mer.sKey)
+            let r = row
+            let c = col
+            let rs = data.merData.mer.rowspan
+            let cs = data.merData.mer.colspan
+            if(cs == 1) return //只有一列
+
+            if(rowEle.merData.type == 'merged'){
+              // 每个大单元格只处理一次
+              if(startMainKey != rowEle.merData.mer.sKey){
+                if(data.merData.mer.colspan==2 && data.merData.mer.rowspan==1){
+                  //删除这一列之后,只有一个单元格了
+                  data.merData=null
+                  return
+                }
+                data.merData.mer.colspan--
+                startMainKey = rowEle.merData.mer.sKey
+              }
+            }else{
+              // 右一列的单元格作为新的左上角单元格
+              const newStartCell = this.config.data[r][c+1]
+              if(rowEle.merData.mer.colspan==2 && rowEle.merData.mer.rowspan==1){
+                //删除这一列之后,只有一个单元格了
+                newStartCell.merData=null
+                return
+              }
+              newStartCell.merData=rowEle.merData
+              newStartCell.merData.mer.sKey = newStartCell.Uid
+              newStartCell.merData.mer.colspan--
+              for (let i = r; i < (r+rs); i++) {
+                for (let j = c+1; j < (c+cs); j++) {
+                  const element = this.config.data[i][j];
+                  if(element.merData.type == 'merged'){
+                    element.merData.mer.sKey = newStartCell.Uid
+                  }
+                }                  
+              }
+            }
+          }
+        })
         //删除时清除关系
         if(this.insertRelationArr.length) {
           let delCellIds = this.config.data.map(row => row[index].Uid);
-          
           this.clearRelationInsertCell(delCellIds);
         }
-
         this.config.data.forEach(row => {
           row.splice(index,1)
         })
+        // 删除的是最后一列
+        if(!(index < this.config.data[0].length)){
+          resetStyle()
+        }
       }else if(cindex === '-1') { //删除行
         console.log('删除行',rindex)
 
         if(this.rowHeader.length === 1) return this.$message.warning(this.$t('OnlineExcelPage.keep_one_row_msg') )
 
         let index = this.rowHeader.findIndex(_ => _ === rindex)
-        
+        // 处理删除行对合并单元格的影响
+        let startMainKey=''
+        this.config.data[index].map((rowEle,rowInd) => {
+          if(rowEle.merData){
+            let {data,row,col} = this.findDataByStartKey(rowEle.merData.mer.sKey)
+            let r = row
+            let c = col
+            let rs = data.merData.mer.rowspan
+            let cs = data.merData.mer.colspan
+            if(rs == 1) return //只有一行
+
+            if(rowEle.merData.type == 'merged'){
+              // 每个大单元格只处理一次
+              if(startMainKey != rowEle.merData.mer.sKey){
+                if(data.merData.mer.colspan==1 && data.merData.mer.rowspan==2){
+                  //删除这一行之后,只有一个单元格了
+                  data.merData=null
+                  return
+                }
+                data.merData.mer.rowspan--
+                startMainKey = rowEle.merData.mer.sKey
+              }
+            }else{
+              // 下一行的单元格作为新的左上角单元格
+              const newStartCell = this.config.data[r+1][c]
+              if(rowEle.merData.mer.colspan==1 && rowEle.merData.mer.rowspan==2){
+                //删除这一行之后,只有一个单元格了
+                newStartCell.merData=null
+                return
+              }
+              newStartCell.merData=rowEle.merData
+              newStartCell.merData.mer.sKey = newStartCell.Uid
+              newStartCell.merData.mer.rowspan--
+              for (let i = r+1; i < (r+rs); i++) {
+                for (let j = c; j < (c+cs); j++) {
+                  const element = this.config.data[i][j];
+                  if(element.merData.type == 'merged'){
+                    element.merData.mer.sKey = newStartCell.Uid
+                  }
+                }                  
+              }
+            }
+          }
+        })
         if(this.insertRelationArr.length) {
           //删除时清除关系
           let delCellIds = this.config.data[index].map(cell => cell.Uid);
@@ -981,7 +1167,10 @@ export default {
         }
 
         this.config.data.splice(index,1)
-
+        // 删除的是最后一行
+        if(!(index < this.config.data.length)){
+          resetStyle()
+        }
       }
     },
 
@@ -1003,18 +1192,30 @@ export default {
       let { cindex } = this.rightClickCell;
       
       let index = this.columnHeader.findIndex(_ => _ === cindex);
-
+      let checkIndex = key==='insert-col-left'?index-1:index+1
+      let startMainKey=''
       this.config.data.forEach((row,rindex) => {
+        let isEnlargeCell = !!(row[index].merData && row[checkIndex] && row[checkIndex].merData)
+        if(isEnlargeCell && startMainKey != row[index].merData.mer.sKey){
+          const data = row[index].merData.type == 'merge'?row[index]:this.findDataByStartKey(row[index].merData.mer.sKey).data
+          data.merData.mer.colspan++
+          startMainKey = row[index].merData.mer.sKey
+        }
         row.splice(key==='insert-col-left'?index:index+1,0,{
           ShowValue: "",
           Value: "",
           DataType: 3,
           DataTime: "",
           EdbInfoId: 0,
-          Uid: md5.hex_md5(`${new Date().getTime()}${rindex}`)
+          Uid: md5.hex_md5(`${new Date().getTime()}${rindex}`),
+          merData:isEnlargeCell?{
+            type:'merged',
+            mer:{
+              sKey:row[index].merData.mer.sKey,//左上角第一个单元格的Uid
+            }
+          }:null
         })
       })
-      
     },
 
     /* 插入行 */
@@ -1022,15 +1223,35 @@ export default {
       let { rindex } = this.rightClickCell;
       
       let index = this.rowHeader.findIndex(_ => _ === rindex)
+      let checkIndex = key==='insert-row-up'?index-1:index+1
+      let startMainKey=''
+
+      let row = new Array(this.columnHeader.length).fill("").map((_,cindex) => {
+
+        let isEnlargeCell = !!(this.config.data[index][cindex].merData && this.config.data[checkIndex][cindex] && this.config.data[checkIndex][cindex].merData)
+        if(isEnlargeCell && startMainKey != this.config.data[index][cindex].merData.mer.sKey){
+          const data = this.config.data[index][cindex].merData.type == 'merge'?
+                      this.config.data[index][cindex]:
+                      this.findDataByStartKey(this.config.data[index][cindex].merData.mer.sKey).data
+          data.merData.mer.rowspan++
+          startMainKey = this.config.data[index][cindex].merData.mer.sKey
+        }
 
-      let row = new Array(this.columnHeader.length).fill("").map((_,cindex) => ({
-        ShowValue: "",
-        Value: "",
-        DataType: 3,
-        DataTime: "",
-        EdbInfoId: 0,
-        Uid: md5.hex_md5(`${new Date().getTime()}${cindex}`)
-      }));
+        return {
+          ShowValue: "",
+          Value: "",
+          DataType: 3,
+          DataTime: "",
+          EdbInfoId: 0,
+          Uid: md5.hex_md5(`${new Date().getTime()}${cindex}`),
+          merData:isEnlargeCell?{
+            type:'merged',
+            mer:{
+              sKey:this.config.data[index][cindex].merData.mer.sKey,//左上角第一个单元格的Uid
+            }
+          }:null
+        }
+      });
 
       this.config.data.splice( key==='insert-row-up'?index:index+1,0,row)
 
@@ -1083,7 +1304,6 @@ export default {
 
     /* 插入系统/指标日期 */
     insertDatehandle({insertValue,dataTimeType,str,sourceName}) {
-
       this.updateSourceFrom(sourceName)
 
       this.insertTargetCell.DataType = 1;
@@ -1202,7 +1422,7 @@ export default {
             DataTimeType: 0,
             DataTime: "",
             EdbInfoId:0,
-            Uid: md5.hex_md5(`${new Date().getTime()}${_rindex}${_cindex}`)
+            Uid: md5.hex_md5(`${new Date().getTime()}${_rindex}${_cindex}`),
           }));
         });
       }
@@ -1241,6 +1461,7 @@ export default {
         cell.EdbInfoId = this.copyCellItem.EdbInfoId;
         cell.ShowStyle = this.copyCellItem.ShowStyle;
         cell.ShowFormatValue = this.copyCellItem.ShowFormatValue;
+        cell.Extra = this.copyCellItem.Extra;
       }else {
         cell.DataType = 3;
         cell.ShowValue = this.copyCellItem.ShowValue;
@@ -1298,12 +1519,11 @@ export default {
       }
     },
 
-    /* 改变单元格显示文本 */
-    updateCellStyle({ShowStyle,ShowFormatValue}) {
-      
-      this.$set(this.selectCell,'ShowStyle',ShowStyle)
-      this.$set(this.selectCell,'ShowFormatValue',ShowFormatValue)
-    },
+    // /* 改变单元格显示文本 */
+    // updateCellStyle({ShowStyle,ShowFormatValue}) {
+    //   this.$set(this.selectCell,'ShowStyle',ShowStyle)
+    //   this.$set(this.selectCell,'ShowFormatValue',ShowFormatValue)
+    // },
     // 更新数据来源
     updateSourceFrom(source){
       if(!source) return
@@ -1311,6 +1531,339 @@ export default {
       let sourceStr = Array.from(new Set(concatSourceArr)).join(',');
       this.sourceFrom.text=sourceStr
       this.$emit('updateSourceName')
+    },
+    // ==================================================合并单元格
+    // 选区开始
+    selectCellHandle(e) {
+      // 不是左键的mousedown事件
+      if(e.button!==0) return
+      if(this.disabled) return
+      this.isSelectionStart=true
+      
+      let startTd;
+      if(e.target.nodeName==='TD'){
+        startTd = e.target
+      }else if(e.target.parentNode.nodeName==='TD'){
+        startTd = e.target.parentNode
+      }else if(e.target.parentNode.parentNode.nodeName==='TD'){
+        startTd = e.target.parentNode.parentNode
+      }else if(e.target.parentNode.parentNode.parentNode.nodeName==='TD'){
+        startTd = e.target.parentNode.parentNode.parentNode
+      }
+
+      if(!startTd) return
+
+      this.startCell={
+        row:+startTd.dataset.datarindex,
+        column:+startTd.dataset.datacindex
+      }
+      document.addEventListener('mousemove',this.selectZoneHandle)
+      document.addEventListener('mouseup',this.selectCellEndHandle)
+    },
+    // 选取
+    selectZoneHandle(e) {
+      if(!this.isSelectionStart) return 
+      if(this.disabled) return
+      const selection = window.getSelection();
+      if (selection.rangeCount>0) {
+        // 清除选中的文本范围
+        selection.removeAllRanges();
+      }
+
+      let tableRect=this.$refs.tableRef.getBoundingClientRect()
+      const mouseX = e.pageX;
+      const mouseY = e.pageY;
+
+      let endTd;
+
+      if(mouseX >= tableRect.left && mouseX <= tableRect.right &&
+      mouseY >= tableRect.top && mouseY <= tableRect.bottom){
+        // 表格内
+        if(e.target.nodeName==='TD'){
+          endTd = e.target
+        }else if(e.target.parentNode.nodeName==='TD'){
+          endTd = e.target.parentNode
+        }else if(e.target.parentNode.parentNode.nodeName==='TD'){
+          endTd = e.target.parentNode.parentNode
+        }else if(e.target.parentNode.parentNode.parentNode.nodeName==='TD'){
+          endTd = e.target.parentNode.parentNode.parentNode
+        }
+        if(!endTd) return 
+
+        this.endCell={
+          row:+endTd.dataset.datarindex,
+          column:+endTd.dataset.datacindex
+        }
+      }
+    },
+    // 选区结束
+    selectCellEndHandle(){
+      this.isSelectionStart=false
+      // click事件走在mouseup事件前面,延迟下
+      setTimeout(()=>{
+        if((this.selectionStart.row || this.selectionStart.row==0) 
+      && (this.selectionEnd.row || this.selectionEnd.row==0)
+      && (this.selectionStart.column || this.selectionStart.column==0)
+      && (this.selectionEnd.column || this.selectionEnd.column==0)){
+          this.selectedCells=[]
+          resetStyle()
+          this.selectCell=null
+          // 选区
+          for (let i = this.selectionStart.row; i < this.selectionEnd.row+1; i++) {
+            for (let j = this.selectionStart.column; j < this.selectionEnd.column+1; j++) {
+              this.selectedCells.push(this.config.data[i][j])
+            }        
+          }
+        }else{
+          this.selectedCells=[]
+        }
+      },1)
+      document.removeEventListener('mousemove',this.selectZoneHandle)
+      document.removeEventListener('mouseup',this.selectCellEndHandle)
+    },
+    findCellDom(key){
+      if(!key) return null
+      if(key !== this.cacheKey){
+        // 重新找
+        this.cacheCellDom = this.$refs.tableRef.querySelector(`[data-key="${key}"]`)
+        this.cacheKey=key
+      }
+      return this.cacheCellDom
+    },
+    // 确定选区范围和设置选区样式
+    setSelectionStyle(){
+     if(!this.isSelectionStart) return
+      // 开始的单元格没有
+      if(!( (this.startCell.row || this.startCell.row==0) && 
+        (this.startCell.column || this.startCell.column==0))) return 
+      // 结束的单元格没有
+      if(!( (this.endCell.row || this.endCell.row==0) && 
+        (this.endCell.column || this.endCell.column==0))) return
+
+      // 递归确定选区范围
+      const findZone = ({sR,eR,sC,eC})=>{
+        this.hasValueCellItem.cellNumber=0
+        
+        for (let i = sR; i < eR+1; i++) {
+          for (let j = sC; j < eC+1; j++) {
+            const element = this.config.data[i][j]
+            if(element.Value){
+              this.hasValueCellItem.cellNumber++
+              this.hasValueCellItem.row=i
+              this.hasValueCellItem.column=j
+            }
+
+            if(element.merData && element.merData.type==='merge'){
+              if(i+element.merData.mer.rowspan-1 > eR){
+                // 该单元格的行有合并 重新规定选取范围
+                return findZone({sR,eR:i+element.merData.mer.rowspan-1,sC,eC})
+              }
+              if(j+element.merData.mer.colspan-1 > eC){
+                // 该单元格的列有合并 重新规定选取范围
+                return findZone({sR,eR,sC,eC:j+element.merData.mer.colspan-1})
+              }
+              this.hasMergedCell=true
+            }
+            
+            if(element.merData && element.merData.type==='merged' ){
+              let item = this.findCellDom(element.merData.mer.sKey)
+              let row = +item.dataset.datarindex
+              let col = +item.dataset.datacindex
+              if(row < sR){
+                // 该单元格的行有被合并 重新规定选取范围
+                return findZone({sR:row,eR,sC,eC})
+              }
+              if(col < sC){
+                // 该单元格的行有被合并 重新规定选取范围
+                return findZone({sR,eR,sC:col,eC})
+              }
+              this.hasMergedCell=true
+            }
+          }
+        }
+        // 防止选中的区域不是整个的单元格(合并后的),后面确定selectionRef 区域大小有问题
+        if(this.config.data[eR][eC].merData && this.config.data[eR][eC].merData.type==='merged'){
+          let item = this.findCellDom(this.config.data[eR][eC].merData.mer.sKey) 
+          let row = +item.dataset.datarindex
+          let col = +item.dataset.datacindex
+          eR=row
+          eC=col
+          this.hasMergedCell=true
+        }
+        return {startR:sR,
+                endR:eR,
+                startC:sC,
+                endC:eC}
+      }
+
+      // 看是否是从下往上、从右往左选的
+      let rowReverse = this.startCell.row > this.endCell.row
+      let colReverse = this.startCell.column > this.endCell.column
+      let postion={
+        sR:rowReverse?this.endCell.row:this.startCell.row,
+        eR:rowReverse?this.startCell.row:this.endCell.row,
+        sC:colReverse?this.endCell.column:this.startCell.column,
+        eC:colReverse?this.startCell.column:this.endCell.column
+      }
+
+      this.hasMergedCell=false
+      const zone = findZone(postion)
+
+      let start = this.config.data[zone.startR][zone.startC]
+      let end = this.config.data[zone.endR][zone.endC]
+
+      this.selectionStart.row = zone.startR
+      this.selectionStart.column = zone.startC
+      this.selectionStart.rowSpan = start.merData?start.merData.mer.rowspan:1
+      this.selectionStart.colSpan = start.merData?start.merData.mer.colspan:1
+
+      this.selectionEnd.row = zone.endR
+      this.selectionEnd.column = zone.endC
+      this.selectionEnd.rowSpan = end.merData?end.merData.mer.rowspan:1
+      this.selectionEnd.colSpan = end.merData?end.merData.mer.colspan:1
+
+      let tableRect = this.$refs.tableRef.getBoundingClientRect()
+      let startTd = this.$refs.tableRef.querySelector(`[data-key="${start.Uid}"]`)
+      let endTd = this.$refs.tableRef.querySelector(`[data-key="${end.Uid}"]`)
+      if(!(startTd && endTd)) return
+      let startRect = startTd.getBoundingClientRect()
+      let endRect = endTd.getBoundingClientRect()
+
+      this.$refs.selectionRef.style.left = startRect.left-tableRect.left+'px'
+      this.$refs.selectionRef.style.top = startRect.top-tableRect.top+'px'
+      let width = Math.abs(endRect.right - startRect.right) + startRect.width
+      let height = Math.abs(endRect.bottom - startRect.bottom) + startRect.height
+      this.$refs.selectionRef.style.width = width+'px'
+      this.$refs.selectionRef.style.height = height + 'px'
+      this.$refs.selectionRef.style.visibility='visible'
+    },
+    clearSelection(){
+      this.$refs.selectionRef.style.width = 0
+      this.$refs.selectionRef.style.height = 0
+      this.$refs.selectionRef.style.visibility='hidden'
+      this.selectionStart={
+        row:null,
+        rowSpan:0,
+        column:null,
+        colSpan:0
+      }
+      this.selectionEnd={
+        row:null,
+        rowSpan:0,
+        column:null,
+        colSpan:0,
+      }
+      this.selectedCells=[]
+    },
+    mergeCellFun(){
+      // 无选区
+      if(!((this.selectionStart.row || this.selectionStart.row==0) 
+      && (this.selectionEnd.row || this.selectionEnd.row==0)
+      && (this.selectionStart.column || this.selectionStart.column==0)
+      && (this.selectionEnd.column || this.selectionEnd.column==0))) return
+
+      if(this.hasValueCellItem.cellNumber>1 || this.hasValueCellItem.cellNumber<0){
+        return this.$message.warning(this.$t('ETable.Msg.merge_cell_fail_msg'))
+      }
+      const firstCell = this.config.data[this.selectionStart.row][this.selectionStart.column]
+      if(this.hasValueCellItem.cellNumber!=0 && (this.hasValueCellItem.row!=this.selectionStart.row || this.hasValueCellItem.column!=this.selectionStart.column)){
+
+        const reserveCell=this.config.data[this.hasValueCellItem.row][this.hasValueCellItem.column]
+        // 将原本有值的单元格 移给左上角第一个单元格
+        firstCell.ShowValue=reserveCell.ShowValue
+        firstCell.ShowStyle=reserveCell.ShowStyle
+        firstCell.ShowFormatValue=reserveCell.ShowFormatValue
+        firstCell.Value=reserveCell.Value
+        firstCell.DataType=reserveCell.DataType
+        firstCell.DataTimeType=reserveCell.DataTimeType
+        firstCell.DataTime=reserveCell.DataTime
+        firstCell.EdbInfoId=reserveCell.EdbInfoId
+        reserveCell.CanEdit && (firstCell.CanEdit=reserveCell.CanEdit)
+        reserveCell.Extra && (firstCell.Extra=reserveCell.Extra)
+        // 处理合并后的依赖关系 就是替换
+        this.replaceCellRelation(reserveCell.Uid,firstCell.Uid)
+        // 清空
+        this.clearCell(reserveCell)
+      }
+
+
+      this.$set(firstCell,'merData',{
+        type:'merge',
+        mer:{
+          sKey:firstCell.Uid,//保留的单元格的Uid
+          rowspan: this.selectionEnd.row - this.selectionStart.row+1,
+          colspan: this.selectionEnd.column - this.selectionStart.column+1,
+        }
+      })
+
+      for (let i = this.selectionStart.row; i < this.selectionEnd.row+1; i++) {
+        for (let j = this.selectionStart.column; j < this.selectionEnd.column+1; j++) {
+          const element = this.config.data[i][j]
+          if(i == this.selectionStart.row && j == this.selectionStart.column){
+            continue
+          }
+          element.merData={
+            type:'merged',
+            mer:{
+              sKey:firstCell.Uid,//左上角第一个单元格的Uid
+            }
+          }
+        }        
+      }
+
+      let startCell = this.config.data[this.selectionStart.row][this.selectionStart.column]
+      let target = this.$refs.tableRef.querySelector(`[data-key="${startCell && startCell.Uid}"]`)
+      // 触发单元格的点击事件
+      target.click()
+    },
+    unmergeCellsFun(){
+      if((this.selectionStart.row || this.selectionStart.row==0) 
+      && (this.selectionEnd.row || this.selectionEnd.row==0)
+      && (this.selectionStart.column || this.selectionStart.column==0)
+      && (this.selectionEnd.column || this.selectionEnd.column==0)){
+        // 选区
+        for (let i = this.selectionStart.row; i < this.selectionEnd.row+1; i++) {
+          for (let j = this.selectionStart.column; j < this.selectionEnd.column+1; j++) {
+            this.unmergeCellFun(this.config.data[i][j])
+          }        
+        }
+      }else{
+        // 单个单元格
+        this.selectCell && this.unmergeCellFun(this.selectCell)
+      }
+      this.hasMergedCell=false
+      // 取消合并后,调整选区(有的话)
+      if((this.selectionStart.row || this.selectionStart.row==0) 
+      && (this.selectionEnd.row || this.selectionEnd.row==0)
+      && (this.selectionStart.column || this.selectionStart.column==0)
+      && (this.selectionEnd.column || this.selectionEnd.column==0)){
+        this.selectionStart.rowSpan=1
+        this.selectionStart.colSpan=1
+
+        this.selectionEnd.row += (this.selectionEnd.rowSpan-1)
+        this.selectionEnd.column += (this.selectionEnd.colSpan-1)
+        this.selectionEnd.rowSpan=1
+        this.selectionEnd.colSpan=1
+      }
+
+    },
+    unmergeCellFun(cell){
+      if(!(cell.merData && cell.merData.type=='merge')) return
+      let {row,col} = this.findDataByStartKey(cell.merData.mer.sKey)
+      const sRow = row,
+          sCol = col,
+          eRow = row+cell.merData.mer.rowspan-1,
+          eCol = col+cell.merData.mer.colspan-1
+
+      for (let i = sRow; i < eRow+1; i++) {
+        for (let j = sCol; j < eCol+1; j++) {
+          this.config.data[i][j].merData=null
+        }
+      }
+    },
+    toolCellMergeFun(){
+      if(this.hasMergedCell) this.unmergeCellsFun()
+      else this.mergeCellFun()
     }
   },
 };
@@ -1325,6 +1878,7 @@ export default {
 .table-wrapper {
   width: 100%;
   overflow: auto;
+  * { box-sizing: border-box; }
 
   .formula-wrapper {
     height: 42px;
@@ -1375,32 +1929,32 @@ export default {
       border: 2px dashed #0033ff;
       box-shadow: 0 0 5px rgba(73, 177, 249, 0.5);
     }
-    &.td-col-select::after {
-      position: absolute;
-      top: 0;
-      left: 0;
-      right: 0;
-      bottom: 0;
-      content: "";
-      display: block;
-      outline: 0;
-      border: 1px solid rgb(24, 173, 24);
-      border-bottom: none;
-      border-top: none;
-    }
-    &.td-row-select::after {
-      position: absolute;
-      top: 0;
-      left: 0;
-      right: 0;
-      bottom: 0;
-      content: "";
-      display: block;
-      outline: 0;
-      border: 1px solid rgb(24, 173, 24);
-      border-left: none;
-      border-right: none;
-    }
+    // &.td-col-select::after {
+    //   position: absolute;
+    //   top: 0;
+    //   left: 0;
+    //   right: 0;
+    //   bottom: 0;
+    //   content: "";
+    //   display: block;
+    //   outline: 0;
+    //   border: 1px solid rgb(24, 173, 24);
+    //   border-bottom: none;
+    //   border-top: none;
+    // }
+    // &.td-row-select::after {
+    //   position: absolute;
+    //   top: 0;
+    //   left: 0;
+    //   right: 0;
+    //   bottom: 0;
+    //   content: "";
+    //   display: block;
+    //   outline: 0;
+    //   border: 1px solid rgb(24, 173, 24);
+    //   border-left: none;
+    //   border-right: none;
+    // }
     &.td-choose-insert-target::after {
       position: absolute;
       top: 0;

+ 116 - 40
src/views/datasheet_manage/components/toolBarSection.vue

@@ -2,7 +2,7 @@
   <!-- 混合表格顶部工具栏 -->
   <div class="toolbar-wrapper">
     <div 
-      class="tool-btn-item" v-for="tool in toolIcons" 
+      class="tool-btn-item" v-for="tool in toolIcons.filter(ic => tools.split(',').includes(ic.tool))" 
       :key="tool.key" 
       @click="dealToolHandles(tool)"
     >
@@ -11,6 +11,11 @@
         <template v-if="tool.type==='icon'">
           <span class="icon-wrap" v-html="tool.icon"></span>
         </template>
+        
+        <div class="icon-box" v-if="tool.type=='icon-text'">
+          <span class="icon-wrap" v-html="tool.icon"></span>
+          <span class="icon-txt">{{tool.title}}</span>
+        </div>
 
         <template v-if="tool.type==='select'">
           <el-select 
@@ -18,7 +23,7 @@
             style="width: 90px" 
             size="small" 
             v-if="tool.key==='cell-type-edit'"
-            @change="changeCellType"
+            @change="changeCellsType"
           >
             <el-option
               v-for="item in numberTypeOptions"
@@ -40,15 +45,35 @@ export default {
     cell: {
       type: Object,
     },
+    /**工具
+     * cell-point-type(数字/百分位显示切换) 
+     * cell-merge(合并单元格)
+    */
+    tools:{
+      type:'String',
+      default:'cell-point-type,cell-merge',
+    },
+    // 回显参数
+    echoParameter:{
+      type:Object,
+      default:()=>{
+        return {}
+      },
+    }
   },
   watch: {
     cell(nval) {
-      if(nval&&nval.ShowStyle) {
-        this.option = {
-          ...JSON.parse(nval.ShowStyle)
+      if(nval) {
+        this.cellArray = Array.isArray(nval)?nval:[nval]
+        this.option = this.cellArray[0].ShowStyle?{
+          ...JSON.parse(this.cellArray[0].ShowStyle)
+        }:{
+          nt: "",//numberType
+          pn: 0,//ponitNum
         }
-      }else {
-        this.option = {
+      }else{
+        this.cellArray=[]
+        this.option ={
           nt: "",//numberType
           pn: 0,//ponitNum
         }
@@ -61,8 +86,7 @@ export default {
         nt: "",//numberType  number percent
         pn: 0,//ponitNum
       },
-
-
+      cellArray:[],
     };
   },
   computed:{
@@ -83,7 +107,8 @@ export default {
           </svg>`,
           key: "add-point",
           type: 'icon',
-          title: this.$t('ETableChildren.number_increase_title') 
+          title: this.$t('ETableChildren.number_increase_title') ,
+          tool:'cell-point-type'
         },
         { 
           icon: `<svg viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
@@ -100,13 +125,25 @@ export default {
           </svg>`, 
           key: "del-point", 
           type: 'icon',
-          title: this.$t('ETableChildren.number_reduce_title') 
+          title: this.$t('ETableChildren.number_reduce_title'),
+          tool:'cell-point-type'
         },
         { 
           icon: '',
           key: 'cell-type-edit',
           type:'select',
-          title:'' 
+          title:'' ,
+          tool:'cell-point-type'
+        },
+        { 
+          icon: `<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+            <path d="M17.9 1.45H2.1C1.55 1.45 1.1 1.9 1.1 2.45V18.25C1.1 18.8 1.55 19.25 2.1 19.25H17.9C18.45 19.25 18.9 18.8 18.9 18.25V2.45C18.9 1.9 18.45 1.45 17.9 1.45ZM17.7 6.54H12.87V2.65H17.7V6.54ZM7.15 6.54V2.65H11.68V6.54H7.15ZM5.95 2.65V6.54H2.3V2.65H5.95ZM5.95 12.23H2.3V7.74H5.95V12.23ZM2.3 13.43H5.95V18.06H2.3V13.43ZM7.15 18.05V7.74H17.7V18.05H7.15Z" fill="#333333"/>
+            </svg>
+            `,
+          key: 'cell-merge',
+          type:'icon-text',
+          title:this.echoParameter.hasMergedCell?this.$t('ETable.Btn.unmerge'):this.$t('ETable.Btn.merge_cell'),
+          tool:'cell-merge'
         }
       ]
     },
@@ -119,54 +156,71 @@ export default {
   },
   methods: {
     dealToolHandles({key}) {
-      //单元格不是数字就不用转了
-      if(!isNumberVal(this.cell.ShowValue)) return
 
       const handlesMap = {
-        'add-point': this.changeCellPoint,
-        'del-point': this.changeCellPoint,
+        'add-point': this.changeCellsPoint,
+        'del-point': this.changeCellsPoint,
+        'cell-merge': this.cellMergeHandle,
       }
 
       handlesMap[key]&&handlesMap[key](key)
     },
-
+    changeCellsPoint(key){
+      this.cellArray.map(item =>{
+        if(!item.merData || item.merData.type=='merge'){
+          this.changeCellPoint(key,item)
+        }
+      })
+    },
     /* 处理小数点位数 */
-    changeCellPoint(key) {
-      let value = _.cloneDeep(this.cell.ShowValue)
-      key==='add-point' ? this.option.pn++ : this.option.pn--;
+    changeCellPoint(key,cell) {
+      //单元格不是数字就不用转了
+      if( !isNumberVal(cell.ShowValue)) return
+      let cellValueStyle = cell.ShowStyle?JSON.parse(cell.ShowStyle):{
+        nt: "",//numberType
+        pn: 0,//ponitNum
+      }
+      key==='add-point' ? cellValueStyle.pn++ : cellValueStyle.pn--;
       
       //判断小数点后尾数 整数最小pn为0 小数最小为负位数
-      if(this.option.pn <= parseInt(`-${getDecimalPlaces(value)}`)) {
-        this.option.pn = parseInt(`-${getDecimalPlaces(value)}`)
+      if(cellValueStyle.pn <= parseInt(`-${getDecimalPlaces(cell.ShowValue)}`)) {
+        cellValueStyle.pn = parseInt(`-${getDecimalPlaces(cell.ShowValue)}`)
       }
 
       //百分比格式的话 pn最小为位数-2
-      if(this.option.nt==='percent' && this.option.pn <= parseInt(`-${getDecimalPlaces(value)-2}`)) {
-        this.option.pn = parseInt(`-${getDecimalPlaces(value)-2}`)
+      if(cellValueStyle.nt==='percent' && cellValueStyle.pn <= parseInt(`-${getDecimalPlaces(cell.ShowValue)-2}`)) {
+        cellValueStyle.pn = parseInt(`-${getDecimalPlaces(cell.ShowValue)-2}`)
       }
 
-      let nval = transDecimalPlace(value,this.option)
+      cell.ShowFormatValue = transDecimalPlace(cell.ShowValue,{...cellValueStyle,pn:cellValueStyle.pn})
+      cell.ShowStyle = JSON.stringify({...cellValueStyle,pn:cellValueStyle.pn})
       // console.log(nval)
-
-      this.$emit('updateCell',{
-        ShowStyle: JSON.stringify(this.option),
-        ShowFormatValue: nval
+      // this.$emit('updateCell',{
+      //   ShowStyle: JSON.stringify({...this.option,cellValueStyle.pn}),
+      //   ShowFormatValue: nval
+      // })
+    },
+    changeCellsType(){
+      this.cellArray.map(item =>{
+        if(!item.merData || item.merData.type=='merge'){
+          this.changeCellType(item)
+        }
       })
     },
-
     /* 处理百分位或数字格式 */
-    changeCellType() {
-      if(!isNumberVal(this.cell.ShowValue)) return
+    changeCellType(item) {
+      if(!isNumberVal(item.ShowValue)) return
       this.option.pn = 0
 
-      let value = _.cloneDeep(this.cell.ShowValue)
-
-      let nval = transNumPercentType(value,this.option.nt)
-
-      this.$emit('updateCell',{
-        ShowStyle: JSON.stringify(this.option),
-        ShowFormatValue: nval
-      })
+      item.ShowFormatValue = transNumPercentType(item.ShowValue,this.option.nt)
+      item.ShowStyle = JSON.stringify(this.option)
+      // this.$emit('updateCell',{
+      //   ShowStyle: JSON.stringify(this.option),
+      //   ShowFormatValue: nval
+      // })
+    },
+    cellMergeHandle(){
+      this.$emit('cellMerge')
     }
   },
 };
@@ -197,6 +251,28 @@ export default {
         height: 20px;
         display: inline-block;
       }
+      .icon-box{
+        display: flex;
+        align-items: center;
+        padding: 6px;
+        border: 1px solid #C8CDD9;
+        border-radius: 4px;
+        .icon-wrap{
+          width: 18px;
+          height: 18px;
+          display: inline-block;
+        }
+        .icon-txt{
+          white-space: nowrap;
+          font-size: 14px;
+          color: #333333;
+          margin-left: 4px;
+        }
+        &:hover {
+          background: #F4F8FE;
+        }
+      }
+
     }
   }
 }

+ 12 - 15
src/views/edbHistoryPage.vue

@@ -162,9 +162,7 @@ export default {
             this.mould = document.getElementById('mould')
             this.mouldText = document.getElementById('mould-text')
 
-            let edbName=this.treeData.EdbName+(this.treeData.IsStop?'(暂停更新)':'')
-            let edbNameEn=this.treeData.EdbNameEn+(this.treeData.IsStop?'(Pause Updates)':'')
-            this.mouldText.innerText=edbName
+            this.mouldText.innerText=this.treeData.EdbName
             let node = this.graph.createNode({
                 shape: 'vue-shape',
                 component: 'custom-rect',
@@ -179,8 +177,8 @@ export default {
                     },
                 },
                 data:{
-                    EdbName:edbName,
-                    EdbNameEn:edbNameEn,
+                    EdbName:this.treeData.EdbName,
+                    EdbNameEn:this.treeData.EdbNameEn,
                     RuleTitle:this.treeData.RuleTitle,
                     RuleTitleEn:this.treeData.RuleTitleEn,
                     routeQuery:{ 
@@ -191,9 +189,8 @@ export default {
                     },
                     isRoot:true,
                     isLeaf:(this.treeData.Child && this.treeData.Child.length>0)?false:true,
-                    style:{
-                        color:this.treeData.IsStop?"red!important":'#ffffff!important',
-                    },
+                    isStop:this.treeData.IsStop,
+                    style:{color:'#ffffff!important'},
                 }
             })
             let cells = [node,...this.createCells(this.treeData.Child,node)]
@@ -207,9 +204,8 @@ export default {
             }
             let dataList = []
             list.forEach(element => {
-                let edbName=element.EdbName+(element.IsStop?'(暂停更新)':'')
-                let edbNameEn=element.EdbNameEn+(this.treeData.IsStop?'(Pause Updates)':'')
-                this.mouldText.innerText=edbName
+
+                this.mouldText.innerText=element.EdbName
                 let node = this.graph.createNode({
                     shape: 'vue-shape',
                     component: 'custom-rect',
@@ -226,10 +222,10 @@ export default {
                     data:{
                         style:{
                             backgroundColor:'#f2f6fa',
-                            color:element.IsStop?"red!important":'#000000',
+                            color:'#000000',
                         },
-                        EdbName:edbName,
-                        EdbNameEn:edbNameEn,
+                        EdbName:element.EdbName,
+                        EdbNameEn:element.EdbNameEn,
                         RuleTitle:element.RuleTitle,
                         RuleTitleEn:element.RuleTitleEn,
                         routeQuery:{ 
@@ -239,7 +235,8 @@ export default {
                             EdbInfoType:element.EdbInfoType
                         },
                         isRoot:false,
-                        isLeaf:(element.Child && element.Child.length>0)?false:true
+                        isLeaf:(element.Child && element.Child.length>0)?false:true,
+                        isStop:element.IsStop,
                     }
                 })
                 let side = this.graph.createEdge({

+ 16 - 4
src/views/mychart_manage/components/chartDetailDia.vue

@@ -680,11 +680,15 @@ export default {
                   {
                     Value: res.Data.YDataList[0].Value,
                     Color:'#00f',
-                    Name:res.Data.ChartInfo.ChartName,
-                    NameEn:res.Data.ChartInfo.ChartNameEn
+                    Name:res.Data.YDataList[0].Name||res.Data.ChartInfo.ChartName,
+                    NameEn:res.Data.YDataList[0].NameEn||res.Data.ChartInfo.ChartNameEn
                   }
                 ]
             }
+            //多因子
+            if(res.Data.CorrelationChartInfo.AnalysisMode===1){
+                this.relevanceChartData.YDataList = res.Data.YDataList
+            }
             
             this.initRelevanceChartData()
             this.tableData = res.Data.EdbInfoList
@@ -1315,12 +1319,19 @@ export default {
     editChartHandle() {
       
       let path = '';
+      let type = '';
       if(this.chartInfo.Source === 1){
         path='/editchart'
       }else if([2,5].includes(this.chartInfo.Source)){
         path='/addCommodityChart'
       }else if([3,4].includes(this.chartInfo.Source)){
-        path='/relevancechartEditor'
+        //path='/relevancechartEditor'
+        path='/relevancechartEditorV2'
+        if(this.chartInfo.Source===3){
+            type = this.relevanceChartData.CorrelationChartInfo&&this.relevanceChartData.CorrelationChartInfo.AnalysisMode||0
+        }else{//滚动相关性也是单因子
+            type = 0
+        }
       }else if(this.chartInfo.Source===6){
         path='/fittingEquationChartEditor'
       }else if([7,8,9].includes(this.chartInfo.Source)) {
@@ -1334,7 +1345,8 @@ export default {
         path,
         query: {
           code: this.chartInfo.UniqueCode,
-          from: 'mychart'
+          from: 'mychart',
+          type,
         }
       })
       window.open(href,'_blank');

+ 47 - 34
src/views/ppt_manage/mixins/mixins.js

@@ -201,22 +201,25 @@ export default {
         ? `${item.EdbAliasName||item.EdbName}(${item.SourceName})${dynamic_tag}`
         : `${item.EdbAliasName||item.EdbName}${dynamic_tag}`
         const nameEn = item.EdbNameEn?`${item.EdbNameEn}${dynamic_tag_en}`:''
+
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         //数据列
         let obj = {
           data: [],
-          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
-          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid',
           yAxis: sameSideIndex,
           name:nameCh,
           nameCh:nameCh,
           nameEn:nameEn,
           color: item.ChartColor,
-          lineWidth: Number(item.ChartWidth)||(chartTheme&&chartTheme.lineOptionList[index].lineWidth),
-          marker: chartTheme && chartTheme.lineOptionList[index].dataMark && chartTheme.lineOptionList[index].dataMark!='none'?{
+          lineWidth: Number(item.ChartWidth)||(chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 1,
+          marker: chartTheme && chartTheme.lineOptionList[lineIndex].dataMark && chartTheme.lineOptionList[lineIndex].dataMark!='none'?{
             enabled:true,
-            symbol: chartTheme.lineOptionList[index].markType || 'circle',
-            fillColor:chartTheme.lineOptionList[index].markColor,
-            radius: chartTheme.lineOptionList[index].markSize
+            symbol: chartTheme.lineOptionList[lineIndex].markType || 'circle',
+            fillColor:chartTheme.lineOptionList[lineIndex].markColor,
+            radius: chartTheme.lineOptionList[lineIndex].markSize
           }:{},
           ...predict_params
         };
@@ -377,7 +380,8 @@ export default {
 
         //预测指标配置
         let predict_params = item.EdbInfoCategoryType === 1 ? this.getPredictParams(item,chartStyle) : {};
-        
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         //中英文名称
         const nameCh = dynamic_arr.length > 1
         ? `${item.EdbAliasName||item.EdbName}(${item.SourceName})${dynamic_tag}`
@@ -393,7 +397,7 @@ export default {
           nameCh:nameCh,
           nameEn:nameEn,
           color: item.ChartColor,
-          lineWidth: Number(item.ChartWidth),
+          lineWidth: Number(item.ChartWidth)||(chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 1,
           // fillColor: (this.chartInfo.ChartType === 3 || (this.chartInfo.ChartType === 6 && item.ChartStyle === 'areaspline')) ? item.ChartColor : undefined,
           borderWidth: 1,
           borderColor: item.ChartColor,
@@ -464,19 +468,20 @@ export default {
         let j = chartDataHandle[index]
           //预测指标配置
         let predict_params =  chartData.EdbInfoCategoryType === 1 ? this.getSeasonPredictParams(j.CuttingDataTimestamp) : {};
-
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         let serie_item = {
           data: [],
-          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || chartData.ChartStyle,
-          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || chartData.ChartStyle,
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid',
           yAxis: 0,
           name: j.ChartLegend,
-          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 1,
-          marker: chartTheme && chartTheme.lineOptionList[index].dataMark && chartTheme.lineOptionList[index].dataMark!='none'?{
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 1,
+          marker: chartTheme && chartTheme.lineOptionList[lineIndex].dataMark && chartTheme.lineOptionList[lineIndex].dataMark!='none'?{
             enabled:true,
-            symbol: chartTheme.lineOptionList[index].markType || 'circle',
-            fillColor:chartTheme.lineOptionList[index].markColor,
-            radius: chartTheme.lineOptionList[index].markSize
+            symbol: chartTheme.lineOptionList[lineIndex].markType || 'circle',
+            fillColor:chartTheme.lineOptionList[lineIndex].markColor,
+            radius: chartTheme.lineOptionList[lineIndex].markSize
           }:{},
           ...predict_params
         };
@@ -901,18 +906,19 @@ export default {
       data.forEach((item,index) => {
         //处理首或/尾全是无效数据的以null填充
         let filterData = this.filterInvalidData(item)
-
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         let serie_item = {
           data: filterData,
-          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
-          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid',
           yAxis: 0,
           name: item.Name,
           nameCh: item.Name,
           nameEn: item.NameEn,
           color: item.Color,
           chartType: 'linear',
-          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 3,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 3,
           marker: {
             enabled: false
           }
@@ -1113,21 +1119,22 @@ export default {
         opposite: false,
         tickWidth: 1,
       }
-
       //处理series
       let seriesData=[]
       this.relevanceChartData.YDataList.forEach((item,index)=>{
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         let serie_item = {
           data: item.Value,
-          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
-          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid',
           yAxis: 0,
           name: item.Name,
           nameCh: item.Name,
           nameEn: item.NameEn,
           color: item.Color,
           chartType: 'linear',
-          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 3,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 3,
           marker: {
             enabled: false
           }
@@ -1240,7 +1247,10 @@ export default {
 
       //数据列
       let series = [];
-      DataList.forEach(item => {
+      DataList.forEach((item,index) => {
+
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         //数据列
         let series_item = {
           data: [],
@@ -1253,7 +1263,7 @@ export default {
           chartType: 'linear',
           zIndex:1,
           marker: {
-            radius: (chartTheme&&chartTheme.lineOptionList.radius)||5,
+            radius: (chartTheme&&chartTheme.lineOptionList[lineIndex].radius)||5,
           },
         }
         item.EdbInfoList.forEach(_ => {
@@ -1416,17 +1426,18 @@ export default {
           max: index===0? Number(LeftMaxValue):Number(RightMaxValue),
           tickWidth: 1,
         }
-
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         let series_item = {
           data: item.Value.map(_ =>[_.X,_.Y]),
-          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
-          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'spline',
           yAxis: index,
           name: item.Name,
           nameCh: item.Name,
           nameEn: item.NameEn||item.Name,
           color: item.Color,
-          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth)||3,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth)||3,
           chartType: 'linear',
           zIndex:1
         }
@@ -1682,17 +1693,19 @@ export default {
       //系列
       let series = [];
       YDataList.forEach((item,index) => {
+        //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模
+				const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index
         let serie_item = {
           data: item.Value,
           pointPlacement: 'on',
-          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'line',
-          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'line',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid',
           yAxis: 0,
           name: item.Name || item.Date,
           nameCh: item.Name || item.Date,
           nameEn: item.Date,
           color: item.Color,
-          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 1,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 1,
           chartType: 'linear'
         };
         series.push(serie_item)

+ 12 - 1
src/views/ppt_manage/mixins/pptEditorMixins.js

@@ -88,7 +88,18 @@ export default{
     }
   },
   methods:{
-    testInput(e,item){
+    handlePaste(e,item){
+        //不触发input
+        e.preventDefault()
+        //只获取文字
+        const text = e.clipboardData.getData('text/plain')
+        if(!text.trim().length){
+            this.$message.warning(this.$t('Slides.title_paste_hint'))
+        }
+        e.target.innerHTML += text.trim()
+        item.title += text.trim()
+    },
+    handleInput(e,item){
         const text = e.target.innerHTML
         item.title = text
     },

+ 15 - 11
src/views/ppt_manage/mixins/pptMixins.js

@@ -306,17 +306,21 @@ export default {
       }else if([3].includes(this.chartInfo.Source)){//相关性
         this.relevanceChartData={
             ChartInfo:res.Data.ChartInfo,
-						EdbInfoList:res.Data.EdbInfoList,
-						XEdbIdValue:this.chartInfo.Source === 3 ? res.Data.XEdbIdValue : res.Data.DataResp.XDateTimeValue,
-						CorrelationChartInfo:res.Data.CorrelationChartInfo,
-						YDataList:[
-							{
-								Value:this.chartInfo.Source === 3 ? res.Data.YDataList[0].Value : res.Data.DataResp.YDataList[0].Value,
-								Color:'#00f',
-								Name:res.Data.ChartInfo.ChartName,
-								NameEn:res.Data.ChartInfo.ChartNameEn
-							}
-						]
+            EdbInfoList:res.Data.EdbInfoList,
+            XEdbIdValue:this.chartInfo.Source === 3 ? res.Data.XEdbIdValue : res.Data.DataResp.XDateTimeValue,
+            CorrelationChartInfo:res.Data.CorrelationChartInfo,
+            YDataList:[
+                {
+                    Value:this.chartInfo.Source === 3 ? res.Data.YDataList[0].Value : res.Data.DataResp.YDataList[0].Value,
+                    Color:res.Data.YDataList[0].Color||'#00f',
+                    Name:res.Data.YDataList[0].Name||res.Data.ChartInfo.ChartName,
+                    NameEn:res.Data.YDataList[0].NameEn||res.Data.ChartInfo.ChartNameEn
+                }
+            ]
+        }
+        //多因子重新赋值YDataList
+        if(res.Data.CorrelationChartInfo.AnalysisMode===1){
+            this.relevanceChartData.YDataList = res.Data.YDataList
         }
         this.initRelevanceChartData()
         this.changeRelevanceOptions(currentLang)

+ 2 - 1
src/views/ppt_manage/newVersion/pptEditor.vue

@@ -99,7 +99,8 @@
                                 }:{ color:'#333',fontSize:'22px',fontFamily:'helvetica',outline:0}"
                                     v-click-title-outside="exitEditTitle"
                                     @click.stop="handleEditTitle(item)"
-                                    @input="(e)=>testInput(e,item)"></div>
+                                    @paste.stop="(e)=>handlePaste(e,item)"
+                                    @input="(e)=>handleInput(e,item)"></div>
                         </div>
                         <!-- 内容 -->
                         <component  :is="getComponentName(item.modelId)"

+ 2 - 1
src/views/ppt_manage/newVersion/pptEnEditor.vue

@@ -85,7 +85,8 @@
                                 }:{ color:'#333',fontSize:'22px',fontFamily:'helvetica',outline:0}"
                                     v-click-title-outside="exitEditTitle"
                                     @click.stop="handleEditTitle(item)"
-                                    @input="(e)=>testInput(e,item)"></div>
+                                    @paste.stop="(e)=>handlePaste(e,item)"
+                                    @input="(e)=>handleInput(e,item)"></div>
                         </div>
                     <!-- 内容 -->
                     <component  :is="getComponentName(item.modelId)"

+ 2 - 1
src/views/ppt_manage/newVersion/utils/untils.js

@@ -721,6 +721,7 @@ export const getContextMenuPos = (layerId) =>{
     Source:1
     MyChartType: 2 季节性图,7 柱形图,  10 截面散点图,
     Source:2 商品价格曲线图
+    Source:3,4 相关性/滚动相关性
     Source:5 利润曲线
     Source:6 拟合方程曲线
     Source:7 统计特征-标准差
@@ -730,7 +731,7 @@ export const getContextMenuPos = (layerId) =>{
 */
 export const isShowPPTTitle = (Source,MyChartType)=>{
     const sense_1 = Source===1&&[2,7,10].includes(MyChartType)
-    const sense_2 = [2,5,6,7,8,9].includes(Source)
+    const sense_2 = [2,3,4,5,6,7,8,9].includes(Source)
     return sense_1||sense_2
 }
 

+ 146 - 0
src/views/system_manage/components/defaultRefreshStatusDia.vue

@@ -0,0 +1,146 @@
+<template>
+  <!-- 设置默认刷新状态 -->
+  <el-dialog custom-class="refresh-setting-dialog"
+    :title="$t('SystemManage.DataRefresh.set_default_refresh_rule')"
+    :visible.sync="show"
+    :close-on-click-modal="false"
+    :modal-append-to-body="false"
+    @close="closeDia"
+    width="420px"
+    v-dialogDrag
+    center
+  >
+      <div class="rule-container">
+          <div class="rule-enable">
+            <div class="rule-enable-item">
+              <span style="margin-right: 4px;">{{$t('SystemManage.DataRefresh.enable_configuration')}}</span>
+              <el-switch v-model="formData.IsOpen"></el-switch>
+            </div>
+            <div class="rule-enable-prompt" :style="{'opacity':formData.IsOpen?'0':'1'}">
+              {{$t('SystemManage.DataRefresh.disableRulePrompt')}}
+            </div>
+          </div>
+          <el-form ref="ruleformRef" :model="formData" :rules="rules">
+            <el-form-item label="" prop="BaseIndexStopDays">
+              <div class="rule-item">
+                <span style="word-break: keep-all;">{{$t('SystemManage.DataRefresh.baseIndexStopDays_hint_front')}}</span>
+                <el-input v-model.number="formData.BaseIndexStopDays" placeholder="" size="small" style="width: 68px;margin: 0 10px"></el-input>
+                <span style="word-break: keep-all;">{{$t('SystemManage.DataRefresh.baseIndexStopDays_hint_behind')}}</span>
+              </div>
+            </el-form-item>
+            <el-form-item label="" prop="EdbStopDays">
+              <div class="rule-item">
+                <span style="word-break: keep-all;">{{$t('SystemManage.DataRefresh.edbStopDays_hint_front')}}</span>
+                <el-input v-model.number="formData.EdbStopDays" placeholder="" size="small" style="width: 68px;margin: 0 10px"></el-input>
+                <span style="word-break: keep-all;">{{$t('SystemManage.DataRefresh.edbStopDays_hint_behind')}}</span>
+              </div>
+            </el-form-item>
+          </el-form>
+      </div>
+      <div class="rule-prompt">
+        ({{$t('SystemManage.DataRefresh.status_rule_prompt')}})
+      </div>
+      <!-- 弹窗按钮 -->
+      <div class="dialog-btn">
+          <el-button type="primary" plain @click="$emit('update:show',false)" style="width: 120px;">{{$t('Dialog.cancel_btn')}}</el-button>
+          <el-button type="primary" @click="handleSetRefreshRule" style="margin-left: 30px;width: 120px;">{{$t('Dialog.confirm_btn')}}</el-button>
+      </div>
+  </el-dialog>
+</template>
+
+<script>
+  export default {
+    name:'defaultRefreshStatusDia',
+    props:{
+      show:{
+        type:Boolean,
+        default:false
+      },
+      ruleData:{
+        type:Object,
+        default:()=>{
+          return {}
+        }
+      }
+    },
+    data(){
+      let reg=/^\d+$/
+      const IntervalDays=(rule, value, callback) => {
+        if (!reg.test(value)) {
+          callback(new Error(this.$t('SystemManage.DataRefresh.IntervalDaysError')));
+        } else {
+          callback();
+        }
+      }
+      return{
+        formData:{
+          IsOpen:true,
+          BaseIndexStopDays:0,
+          EdbStopDays:0
+        },
+        rules: {
+          BaseIndexStopDays: [
+            {
+              validator: IntervalDays,
+              trigger: ["blur","change"],
+            },
+          ],
+          EdbStopDays: [
+            {
+              validator: IntervalDays,
+              trigger: ["blur","change"],
+            },
+          ]
+        }
+      }
+    },
+    watch:{
+      show(value){
+        if(value){
+          this.formData.IsOpen=!!this.ruleData.IsOpen
+          this.formData.BaseIndexStopDays=this.ruleData.BaseIndexStopDays
+          this.formData.EdbStopDays=this.ruleData.EdbStopDays
+        }
+      }
+    },
+    methods:{
+      closeDia(){
+        this.$emit('update:show',false)
+      },
+      handleSetRefreshRule(){
+        this.$refs.ruleformRef.validate((valid) => {
+          if(valid){
+            this.$emit("setRule",this.formData)
+          }
+        })
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .rule-container{
+    padding-left: 35px;
+    .rule-enable{
+      .rule-enable-item,.rule-item{
+        display: flex;
+        align-items: center;
+      }
+      .rule-enable-prompt{
+        font-size:12px;
+        color: #F56C6C;
+        padding: 2px 0;
+      }
+    }
+  }
+  .rule-prompt{
+    font-size:14px;
+    color: #F56C6C;
+    text-align: center;
+  }
+  .dialog-btn{
+    padding: 40px 0 30px 0;
+    display: flex;
+    justify-content: center
+  }
+</style>

+ 74 - 0
src/views/system_manage/components/referenceCountDia.vue

@@ -0,0 +1,74 @@
+<template>
+  <!-- 引用次数 -->
+  <el-dialog custom-class="refresh-setting-dialog"
+    :title="$t('SystemManage.DataRefresh.table_reference_count')"
+    :visible.sync="show"
+    :close-on-click-modal="false"
+    :modal-append-to-body="false"
+    @close="closeDia"
+    top="5vh"
+    width="760px"
+    v-dialogDrag
+    center
+  >
+    <el-table :data="dataList" border max-height="600px">
+      <el-table-column align="center" prop="RelationTime" :label="$t('SystemManage.DataRefresh.reference_time')">
+          <template slot-scope="scope">
+            {{scope.row.RelationTime}}
+          </template>
+      </el-table-column>
+      <el-table-column align="center" prop="ReferObjectTypeName" :label="$t('SystemManage.DataRefresh.reference_source')">
+          <template slot-scope="scope">
+            {{scope.row.ReferObjectTypeName}}
+          </template>
+      </el-table-column>
+      <el-table-column align="center" prop="ReferObjectName" :label="$t('SystemManage.DataRefresh.reference_chart_table')">
+          <template slot-scope="scope">
+            {{scope.row.ReferObjectName}}
+          </template>
+      </el-table-column>
+    </el-table>
+    <!-- 弹窗按钮 -->
+    <div class="dialog-btn">
+        <el-button type="primary" @click="$emit('update:show',false)" style="width: 120px;">{{$t('Dialog.known')}}</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+  export default {
+    name:'referenceCountDia',
+    props:{
+      show:{
+        type:Boolean,
+        default:false
+      },
+      dataList:{
+        type:Array,
+        default:()=>[]
+      }
+    },
+    methods:{
+      closeDia(){
+        this.$emit('update:show',false)
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+
+.rule-container{
+    padding-left: 55px;
+    .rule-item{
+      display: flex;
+      align-items: center;
+      margin-bottom: 20px
+    }
+  }
+  .dialog-btn{
+    padding: 40px 0 30px 0;
+    display: flex;
+    justify-content: center
+  }
+</style>

+ 710 - 111
src/views/system_manage/dataRefreshSetting.vue

@@ -1,40 +1,167 @@
 <template>
     <!-- 数据源刷新设置 -->
     <div class="data-refresh-setting-wrap">
-        <div class="top-box">
-            <div class="select-box">
-                <span>{{$t('SystemManage.DataRefresh.select_source')}}</span>
-                <el-select :placeholder="$t('SystemManage.DataRefresh.select_source_pld')" v-model="Source" @change="handleSourceChange">
-                    <el-option v-for="item in SourceList" :key="item.Source" 
-                    :label="item.SourceName" :value="item.Source"/>
-                </el-select>
-                <el-select :placeholder="$t('SystemManage.DataRefresh.select_source_pld')" v-model="SubSource" v-if="SubSourceList.length" @change="handleSubSourceChange">
-                    <el-option v-for="item in SubSourceList" :key="item.Source" 
-                    :label="$i18nt.locale==='zh'?item.SubSourceName:item.SubSourceNameEn||item.SubSourceName" :value="item.SubSource"/>
-                </el-select>
-                <el-button type="primary" @click="showDialog(true)"
-                    v-permission="permissionBtn.sysDepartPermission.refresh_default"
-                >{{$t('SystemManage.DataRefresh.default_time')}}</el-button>
+        <div class="top-top">
+            <div class="tab-zone">
+                <div class="tab-item" :class="item.value==settingTab?'active':''" v-for="item in tabList.filter(it => checkPer(it))" :key="item.value" @click="changeTab(item.value)">
+                    {{ item.label }}
+                </div>
+            </div>
+            <div class="refresh-rule-setting" v-if="settingTab=='status'">
+                <el-button type="danger" plain @click="setEdbsRefreshStatus('暂停')" :disabled="!hasStatusSelection">{{$t('SystemManage.DataRefresh.disabled')}}</el-button>
+                <el-button type="primary" plain @click="setEdbsRefreshStatus('启用')" :disabled="!hasStatusSelection">{{$t('SystemManage.DataRefresh.enabled')}}</el-button>
+                <el-button type="primary" @click="openDefaultRefreshStatusDia">{{$t('SystemManage.DataRefresh.default_refresh_rule')}}</el-button>
             </div>
-            
-            <el-input :placeholder="$t('SystemManage.DataRefresh.indicator_name')" prefix-icon="el-icon-search" clearable
-                v-model="selectOption.keyWord" @input="selectOptionChange('keyWord')"
-                v-if="![34,11].includes(Source)&&Source"></el-input>
-            
         </div>
-        <div class="table-box" v-if="hasSelectOption">
-            <div class="table-select" v-loading="selectOptionLoading">
-                <div class="select-list">
-                    <el-select :placeholder="$t('SystemManage.DataRefresh.terminal_code_select')" :no-match-text="$t('SystemManage.DataRefresh.complete_data_source')" clearable
-                        v-model="selectOption.terminalCode" @change="selectOptionChange('terminalCode')">
-                        <el-option v-for="i in terminalCodeList" :key="i.TerminalCode"
-                            :label="i.Name" :value="i.TerminalCode"/>
+        <!-- 刷新时间 -->
+        <template v-if="settingTab=='time'">
+            <div class="top-box">
+                <div class="select-box">
+                    <span>{{$t('SystemManage.DataRefresh.select_source')}}</span>
+                    <el-select :placeholder="$t('SystemManage.DataRefresh.select_source_pld')" v-model="Source" @change="handleSourceChange">
+                        <el-option v-for="item in SourceList" :key="item.Source" 
+                        :label="item.SourceName" :value="item.Source"/>
                     </el-select>
-                    <el-cascader :placeholder="$t('SystemManage.DataRefresh.eta_class_select')" :no-match-text="$t('SystemManage.DataRefresh.complete_data_source')" clearable
-                        v-model="selectOption.classify" @change="selectOptionChange('classify')"
-                        :options="edbClassifyList" 
-                        :show-all-levels="false"
-                        collapse-tags
+                    <el-select :placeholder="$t('SystemManage.DataRefresh.select_source_pld')" v-model="SubSource" v-if="SubSourceList.length" @change="handleSubSourceChange">
+                        <el-option v-for="item in SubSourceList" :key="item.Source" 
+                        :label="$i18nt.locale==='zh'?item.SubSourceName:item.SubSourceNameEn||item.SubSourceName" :value="item.SubSource"/>
+                    </el-select>
+                    <el-button type="primary" @click="showDialog(true)"
+                        v-permission="permissionBtn.sysDepartPermission.refresh_default"
+                    >{{$t('SystemManage.DataRefresh.default_time')}}</el-button>
+                </div>
+                
+                <el-input :placeholder="$t('SystemManage.DataRefresh.indicator_name')" prefix-icon="el-icon-search" clearable
+                    v-model="selectOption.keyWord" @input="selectOptionChange('keyWord')"
+                    v-if="![34,11].includes(Source)&&Source"></el-input>
+                
+            </div>
+            <div class="table-box" v-if="hasSelectOption">
+                <div class="table-select" v-loading="selectOptionLoading">
+                    <div class="select-list">
+                        <el-select :placeholder="$t('SystemManage.DataRefresh.terminal_code_select')" :no-match-text="$t('SystemManage.DataRefresh.complete_data_source')" clearable
+                            v-model="selectOption.terminalCode" @change="selectOptionChange('terminalCode')">
+                            <el-option v-for="i in terminalCodeList" :key="i.TerminalCode"
+                                :label="i.Name" :value="i.TerminalCode"/>
+                        </el-select>
+                        <el-cascader :placeholder="$t('SystemManage.DataRefresh.eta_class_select')" :no-match-text="$t('SystemManage.DataRefresh.complete_data_source')" clearable
+                            v-model="selectOption.classify" @change="selectOptionChange('classify')"
+                            :options="edbClassifyList" 
+                            :show-all-levels="false"
+                            collapse-tags
+                            :props="{
+                                emitPath:true,
+                                value:'ClassifyId',
+                                label:'ClassifyName',
+                                children:'Children',
+                                multiple:true
+                            }" />
+                        <el-cascader
+                            :placeholder="$t('SystemManage.DataRefresh.table_creator')" :no-match-text="$t('SystemManage.DataRefresh.complete_data_source')" style="height: 40px;"
+                            v-model="selectOption.user" @change="selectOptionChange('user')"
+                            :options="userList"
+                            :props="{
+                                value: 'ItemId',
+                                label: 'ItemName',
+                                children: 'Children',
+                                emitPath: false,
+                                multiple:true,
+                            }"
+                            collapse-tags
+                            :show-all-levels="false"
+                            clearable
+                            filterable 
+                        />
+                        <el-select :placeholder="table_frequency" v-model="selectOption.frequency" @change="selectOptionChange('frequency')" multiple collapse-tags clearable>
+                            <el-option v-for="i in frequencyList" :key="i.value"
+                                :label="i.label" :value="i.value"
+                            />
+                        </el-select>
+                        <el-select :placeholder="$t('SystemManage.DataRefresh.table_status')" v-model="selectOption.state" @change="selectOptionChange('state')" clearable>
+                            <el-option :label="$t('SystemManage.DataRefresh.enable_op')" value="启用"/>
+                            <el-option :label="$t('SystemManage.DataRefresh.pause_op')" value="暂停"/>
+                        </el-select>
+                    </div>
+                    <div class="select-other">
+                        <el-checkbox :indeterminate="isIndeterminate" v-model="isCheckAll" @change="listCheckAllChange">{{$t('SystemManage.DataRefresh.all_list')}}</el-checkbox>
+                        <el-button type="primary" @click="showDialog(false)"
+                            v-permission="permissionBtn.sysDepartPermission.refresh_time"
+                            :disabled="!tableData.length"
+                        >{{$t('SystemManage.DataRefresh.set_time')}}</el-button>
+                        <el-button type="primary" @click="isSetStateDialogShow=true"
+                            v-permission="permissionBtn.sysDepartPermission.refresh_state"
+                            v-if="Source!=2"
+                            :disabled="!tableData.length"
+                        >{{$t('SystemManage.DataRefresh.set_status')}}</el-button>
+                    </div>
+                </div>
+                <el-table :data="tableData" border
+                    ref="edbDataRef"
+                    @selection-change="selectionChange"
+                    @select="selectHandle" 
+                    @select-all="selectAllHandle"
+                    @sort-change="handleSortChange"
+                    >
+                    <!-- 多选 -->
+                    <el-table-column
+                        align="center"
+                        type="selection"
+                        width="55">
+                    </el-table-column>
+                    <el-table-column v-for="column in columns" :key="column.key"
+                        :prop="column.key"
+                        :label="column.label"
+                        :min-width="column.minWidth"
+                        :sortable="column.sortable?column.sortable:false"
+                        align="center"
+                        >
+                        <template slot-scope="{row}">
+                            <span v-if="column.key==='IsStop'">
+                                {{row.IsStop? $t('SystemManage.DataRefresh.pause_op') : $t('SystemManage.DataRefresh.enable_op') }}
+                            </span>
+                            <span v-else>
+                                {{row[column.key]}}
+                            </span>
+                        </template>
+                    </el-table-column>
+                </el-table>
+                <el-pagination 
+                    :current-page="currentPage"
+                    :page-size="pageSize"
+                    :total="total"
+                    @current-change="handleCurrentChange"
+                />
+            </div>
+        </template>
+        <!-- 刷新状态 - 全拆开吧 -->
+        <template v-if="settingTab=='status'">
+            <div class="refresh-status-container">
+                <div class="refresh-status-search">
+                    <div class="refresh-status-search-left">
+                        <div class="select-source-box">
+                            <span>{{$t('SystemManage.DataRefresh.select_source')}}</span>
+                            <el-select :placeholder="$t('SystemManage.DataRefresh.select_source_pld')" v-model="searchParams.Source">
+                                <el-option v-for="item in statusSourceList" :key="item.Source" 
+                                :label="item.SourceName" :value="item.Source"/>
+                            </el-select>
+                        </div>
+                        <el-select :placeholder="$t('SystemManage.DataRefresh.table_status')" v-model="searchParams.Status" @change="searchList"
+                        class="select-item-small" clearable>
+                            <el-option :label="$t('SystemManage.DataRefresh.enable')" value="启用"/>
+                            <el-option :label="$t('SystemManage.DataRefresh.disable')" value="暂停"/>
+                        </el-select>
+                        <!-- 频度 -->
+                        <el-select :placeholder="$t('SystemManage.DataRefresh.table_frequency')" class="select-item-small"
+                            v-model="FrequencyArr" multiple collapse-tags clearable>
+                            <el-option v-for="i in frequencyList" :key="i.value"
+                                :label="i.label" :value="i.value"
+                            />
+                        </el-select>
+                        <!-- 指标库分类 -->
+                        <el-cascader :placeholder="$t('SystemManage.DataRefresh.edb_classify')" 
+                        :no-match-text="$t('SystemManage.DataRefresh.complete_data_source')" clearable
+                        v-model="ClassifyIdArr" class="select-item-small" 
+                        :options="statusEdbClassifyList" :show-all-levels="false" collapse-tags
                         :props="{
                             emitPath:true,
                             value:'ClassifyId',
@@ -42,81 +169,87 @@
                             children:'Children',
                             multiple:true
                         }" />
-                    <el-cascader
-                        :placeholder="$t('SystemManage.DataRefresh.table_creator')" :no-match-text="$t('SystemManage.DataRefresh.complete_data_source')" style="height: 40px;"
-                        v-model="selectOption.user" @change="selectOptionChange('user')"
-                        :options="userList"
-                        :props="{
-                            value: 'ItemId',
-                            label: 'ItemName',
-                            children: 'Children',
-                            emitPath: false,
-                            multiple:true,
-                        }"
-                        collapse-tags
-                        :show-all-levels="false"
-                        clearable
-                        filterable 
-                    />
-                    <el-select :placeholder="table_frequency" v-model="selectOption.frequency" @change="selectOptionChange('frequency')" multiple collapse-tags clearable>
-                        <el-option v-for="i in frequencyList" :key="i.value"
-                            :label="i.label" :value="i.value"
+                        <!-- 创建人 -->
+                        <el-cascader
+                            :placeholder="$t('SystemManage.DataRefresh.table_creator')" 
+                            :no-match-text="$t('SystemManage.DataRefresh.complete_data_source')" style="height: 40px;"
+                            v-model="SysUserIdArr" class="select-item-small" 
+                            :options="userList" collapse-tags :show-all-levels="false" clearable filterable
+                            :props="{
+                                value: 'ItemId',
+                                label: 'ItemName',
+                                children: 'Children',
+                                emitPath: false,
+                                multiple:true,
+                            }"
                         />
-                    </el-select>
-                    <el-select :placeholder="$t('SystemManage.DataRefresh.table_status')" v-model="selectOption.state" @change="selectOptionChange('state')" clearable>
-                        <el-option :label="$t('SystemManage.DataRefresh.enable_op')" value="启用"/>
-                        <el-option :label="$t('SystemManage.DataRefresh.pause_op')" value="暂停"/>
-                    </el-select>
-                </div>
-                <div class="select-other">
-                    <el-checkbox :indeterminate="isIndeterminate" v-model="isCheckAll" @change="listCheckAllChange">{{$t('SystemManage.DataRefresh.all_list')}}</el-checkbox>
-                    <el-button type="primary" @click="showDialog(false)"
-                        v-permission="permissionBtn.sysDepartPermission.refresh_time"
-                        :disabled="!tableData.length"
-                    >{{$t('SystemManage.DataRefresh.set_time')}}</el-button>
-                    <el-button type="primary" @click="isSetStateDialogShow=true"
-                        v-permission="permissionBtn.sysDepartPermission.refresh_state"
-                        :disabled="!tableData.length"
-                    >{{$t('SystemManage.DataRefresh.set_status')}}</el-button>
+                        <div class="selection-box">
+                            <el-checkbox :indeterminate="statusDataSelectionItem.isIndeterminate" v-model="statusDataSelectionItem.isCheckAll" 
+                            @change="statusListCheckAllChange">{{$t('SystemManage.DataRefresh.all_list')}}</el-checkbox>
+                            <span>{{$t('SystemManage.DataRefresh.selected')}}: {{ hasStatusSelection }}</span>
+                        </div>
+
+                    </div>
+
+                    <el-input :placeholder="$t('SystemManage.DataRefresh.indicator_name')" prefix-icon="el-icon-search" clearable
+                        v-model="searchParams.Keyword" @input="searchList" style="width: 360px;margin-left: 15px;"></el-input>
                 </div>
-            </div>
-            <el-table :data="tableData" border
-                ref="edbDataRef"
-                @selection-change="selectionChange"
-                @select="selectHandle" 
-                @select-all="selectAllHandle"
-                @sort-change="handleSortChange"
-                >
-                <!-- 多选 -->
-                <el-table-column
-                    align="center"
-                    type="selection"
-                    width="55">
-                </el-table-column>
-                <el-table-column v-for="column in columns" :key="column.key"
-                    :prop="column.key"
-                    :label="column.label"
-                    :min-width="column.minWidth"
-                    :sortable="column.sortable?column.sortable:false"
-                    align="center"
+                <el-table :data="statusTableData" border
+                    ref="statusTableRef"
+                    @selection-change="statusSelectionChange"
+                    @select="statusSelectHandle" 
+                    @select-all="statusSelectAllHandle"
+                    @sort-change="handleStatusTableSortChange"
                     >
-                    <template slot-scope="{row}">
-                        <span v-if="column.key==='IsStop'">
-                            {{row.IsStop? $t('SystemManage.DataRefresh.pause_op') : $t('SystemManage.DataRefresh.enable_op') }}
-                        </span>
-                        <span v-else>
-                            {{row[column.key]}}
-                        </span>
-                    </template>
-                </el-table-column>
-            </el-table>
-            <el-pagination 
-                :current-page="currentPage"
-                :page-size="pageSize"
-                :total="total"
-                @current-change="handleCurrentChange"
-            />
-        </div>
+                    <!-- 多选 -->
+                    <el-table-column
+                        align="center"
+                        type="selection"
+                        width="55">
+                    </el-table-column>
+                    <el-table-column align="center" prop="EdbCode" :label="$t('SystemManage.DataRefresh.table_Id')" show-overflow-tooltip>
+                        <template slot-scope="scope">
+                          {{scope.row.EdbCode}}
+                        </template>
+                    </el-table-column>
+                    <el-table-column align="center" prop="EdbName" :label="$t('SystemManage.DataRefresh.table_name')" show-overflow-tooltip>
+                        <template slot-scope="scope">
+                          {{scope.row.EdbName}}
+                        </template>
+                    </el-table-column>
+                    <el-table-column align="center" prop="RelationTime" :label="$t('SystemManage.DataRefresh.table_recent_reference_time')"
+                    sortable="custom">
+                        <template slot-scope="scope">
+                          {{scope.row.RelationTime}}
+                        </template>
+                    </el-table-column>
+                    <el-table-column align="center" prop="RelationNum" :label="$t('SystemManage.DataRefresh.table_reference_count')"
+                    sortable="custom">
+                        <template slot-scope="scope">
+                          <span :class="scope.row.RelationNum>0?'table-text-button':''" @click="openReferenceCountDia(scope.row)">{{scope.row.RelationNum}}</span>
+                        </template>
+                    </el-table-column>
+                    <el-table-column align="center" prop="IsStop" :label="$t('SystemManage.DataRefresh.table_refresh_status')">
+                        <template slot-scope="scope">
+                            {{scope.row.IsStop?  $t('SystemManage.DataRefresh.disabled'):$t('SystemManage.DataRefresh.enabled') }}
+                        </template>
+                    </el-table-column>
+                    <el-table-column align="center" prop="Operation" :label="$t('Table.column_operations')">
+                        <template slot-scope="scope">
+                            <span class="table-text-button" v-if="scope.row.IsStop" @click="enableToggle(scope.row)">{{$t('SystemManage.DataRefresh.enable')}}</span>
+                            <!-- v-permission="permissionBtn.outlinkConfigPermission.outlinkListConfig_del" -->
+                            <span class="table-text-button" style="color: #C54322;" @click="enableToggle(scope.row)" v-else>{{$t('SystemManage.DataRefresh.disable')}}</span>
+                        </template>
+                    </el-table-column>
+                </el-table>
+                <el-pagination 
+                    :current-page="searchParams.CurrentIndex"
+                    :page-size="searchParams.PageSize"
+                    :total="statusDataTotal"
+                    @current-change="handleStatusListPageNoChange"
+                />
+            </div>
+        </template>
         <!-- 默认刷新时间,设置刷新时间 -->
         <el-dialog custom-class="refresh-setting-dialog"
             :title="dlgTextLangShow((isDefault?'默认':'设置')+'刷新时间')"
@@ -177,14 +310,21 @@
                 <el-button type="primary" @click="setRefreshStatus">{{$t('Dialog.confirm_btn')}}</el-button>
             </div>
         </el-dialog>
+
+        <!-- 默认刷新规则 -->
+        <defaultRefreshStatusDia :show.sync="setDefaultRefreshStatusShow" :ruleData="settingRuleForm" @setRule="setDefaultRefreshRule"/>
+        <referenceCountDia :show.sync="referenceCountShow" :dataList="statusEdbRelationDetailList" />
     </div>
 </template>
 
 <script>
 import RefreshConfig from './components/refreshConfig.vue';
+import { dataBaseInterface } from '@/api/api.js';
 import {dataRefreshInterface,dataAuthInterface} from '@/api/modules/dataApi.js';
+import defaultRefreshStatusDia from './components/defaultRefreshStatusDia.vue';
+import referenceCountDia from './components/referenceCountDia.vue';
 export default {
-    components: { RefreshConfig },
+    components: { RefreshConfig ,defaultRefreshStatusDia,referenceCountDia},
     computed:{
         frequencyList() {
             return [
@@ -230,9 +370,23 @@ export default {
                 { key: "IsStop", label:/* '刷新状态' */ this.$t('SystemManage.DataRefresh.table_status')},
             ];
         },
+        tabList(){
+            return [
+                { value: "time", label:/* '刷新时间设置' */ this.$t('SystemManage.DataRefresh.time_setting_tab')},
+                { value: "status", label:/* '刷新状态设置' */ this.$t('SystemManage.DataRefresh.status_setting_tab')}
+            ];  
+        },
+        hasStatusSelection(){
+            if(this.statusDataSelectionItem.isSelectAll){
+                return this.statusDataTotal - (this.statusDataSelectionItem.selectList ? this.statusDataSelectionItem.selectList.length : 0)
+            }else{
+                return this.statusDataSelectionItem.selectList ? this.statusDataSelectionItem.selectList.length : 0
+            }
+        }
     },
     data() {
         return {
+            settingTab:'time',
             Source:'',
             SourceList:[],
             SubSource:'',
@@ -277,9 +431,128 @@ export default {
             //已选择/已剔除的指标id
             selectList:[],//监听table的select-all select
             selectionReactCancel:false,
+
+            // 刷新状态设置 
+            settingRuleForm:{},
+            setDefaultRefreshStatusShow:false,
+            referenceCountShow:false,
+            statusSourceList:[],
+            statusEdbClassifyList:[],
+            searchParams:{
+                Source:'',
+                Status:'',
+                Frequency:'',
+                SysUserId:'',
+                ClassifyId:'',
+                SortType:'',//排序类型
+                SortParam:'',//排序字段
+                Keyword:"",
+                PageSize:10,
+                CurrentIndex:1
+            },
+            SysUserIdArr:[],
+            stopUserIdRequest:false, //阻止watch中的请求
+            ClassifyIdArr:[],
+            stopClassifyIdRequest:false, //阻止watch中的请求
+            FrequencyArr:[],
+            stopFrequencyArrRequest:false, //阻止watch中的请求
+            statusTableData:[],
+            statusTableDataIds:[],
+            statusDataTotal:0,
+            statusEdbRelationDetailList:[],
+            statusDataSelectionItem:{
+                isIndeterminate:false,
+                isCheckAll:false,
+                selectionReactCancel:false,
+                isSelectAll:false,//为true时,selectList是剔除的指标,为false时selectList是已选择的指标
+                //已选择/已剔除的指标id
+                selectList:[],//监听table的select-all select
+            }
         };
     },
+    watch:{
+        SysUserIdArr(value){
+            if(value&&value.length>0){
+                this.searchParams.SysUserId=value.join(',')
+            }else{
+                this.searchParams.SysUserId=''
+            }
+            if(!this.stopUserIdRequest){
+                this.searchList()
+            }else{
+                this.stopUserIdRequest=false
+            }
+            
+        },
+        ClassifyIdArr(value){
+            if(value&&value.length>0){
+                this.searchParams.ClassifyId=value.join(',')
+            }else{
+                this.searchParams.ClassifyId=''
+            }
+            if(!this.stopClassifyIdRequest){
+                this.searchList()
+            }else{
+                this.stopClassifyIdRequest=false
+            }
+        },
+        FrequencyArr(value){
+            if(value&&value.length>0){
+                this.searchParams.Frequency=value.join(',')
+            }else{
+                this.searchParams.Frequency=''
+            }
+            if(!this.stopFrequencyArrRequest){
+                this.searchList()
+            }else{
+                this.stopFrequencyArrRequest=false
+            }
+        },
+        'searchParams.Source':{
+            handler:function (value) {
+                if(!value) return
+                this.searchParams.Status=''
+                // this.searchParams.Frequency=''
+                // this.searchParams.ClassifyId=''
+                // this.searchParams.SysUserId=''
+                this.FrequencyArr=[]
+                this.stopFrequencyArrRequest=true
+                this.ClassifyIdArr=[]
+                this.stopClassifyIdRequest=true
+                this.SysUserIdArr=[]
+                this.stopUserIdRequest=true
+                this.searchParams.SortType=''
+                this.searchParams.SortParam=''
+                this.searchParams.Keyword=''
+                this.getStatusClassifyList()
+                if(this.settingTab=='status') this.searchList()
+            }
+        }
+    },
     methods: {
+        checkPer(it){
+            if(it.value == 'status'){
+                // 同 设置刷新状态的权限按钮 控制整个刷新状态设置tab
+                return this.permissionBtn.isShowBtn('sysDepartPermission','refresh_state')
+            }
+            return true
+        },
+        changeTab(e){
+            this.settingTab=e||'time'
+            if(this.settingTab=='time'){
+                this.$nextTick(()=>{
+                    this.$refs.edbDataRef && this.adjustSelection()
+                })
+            }else{
+                if(!(this.statusTableData && this.statusTableData.length>0)){
+                    this.searchList()
+                }else{
+                    this.$nextTick(()=>{
+                        this.$refs.statusTableRef && this.adjustStatusSelection()
+                    })
+                }
+            }
+        },
         //展示刷新时间弹窗
         showDialog(isDefault){
             this.isDefault = isDefault
@@ -368,6 +641,10 @@ export default {
             dataRefreshInterface.getDataSourceList().then(res=>{
                 if(res.Ret!==200) return 
                 this.SourceList = res.Data||[]
+                this.statusSourceList=this.SourceList.filter(it => [2,34].includes(it.Source)).concat([
+                    {Source:-1,SourceName:"计算指标"}
+                ])
+                this.searchParams.Source = this.statusSourceList[0]?this.statusSourceList[0].Source:''
             })
         },
         //一级数据源改变时,二级数据源和筛选项也重新赋值
@@ -498,7 +775,7 @@ export default {
                     let row = this.tableData.find(da => da.EdbInfoId==it)
                     if(row){
                         setTimeout(()=>{
-                            this.$refs.edbDataRef.toggleRowSelection(row,true)
+                            this.$refs.edbDataRef && this.$refs.edbDataRef.toggleRowSelection(row,true)
                         },10)
                     }
                 })
@@ -509,7 +786,7 @@ export default {
                     let row = this.tableData.find(da => da.EdbInfoId==it)
                     if(row){
                         setTimeout(()=>{
-                            this.$refs.edbDataRef.toggleRowSelection(row,false)
+                            this.$refs.edbDataRef && this.$refs.edbDataRef.toggleRowSelection(row,false)
                         },50)
                     }
                 })
@@ -691,7 +968,245 @@ export default {
             if(e==='默认刷新时间') return this.$t('SystemManage.DataRefresh.default_time')
             if(e==='设置刷新时间') return this.$t('SystemManage.DataRefresh.set_time')
             return e
-        }
+        },
+        // -----------------------------刷新状态设置
+        //获取分类列表
+        async getStatusClassifyList(){
+            if(!this.searchParams.Source) return 
+            const res = await dataRefreshInterface.getClassifyList({
+                Source:Number(this.searchParams.Source)
+            })
+            if(res.Ret!==200) return 
+            this.statusEdbClassifyList = res.Data||[]
+        },
+         getStatusDataList(type){
+            dataRefreshInterface.getRelationEdbDataList(this.searchParams).then(res=>{
+                if(res.Ret!==200) return 
+                this.statusTableData=res.Data.List || []
+                this.statusDataTotal=res.Data.Paging.Totals || this.statusTableData.length
+                if(this.statusDataTotal>0){
+                    this.statusTableDataIds = this.statusTableData.map(it => it.EdbInfoId)
+                }else{
+                    this.statusTableDataIds = []
+                }
+                if(type==='search'){
+                    //如果是表格筛选项改变导致重新请求数据
+                    //数据获取完成后,清空所选
+                    this.statusDataSelectionItem.selectList = []
+                    this.statusListCheckAllChange(false)
+                }else{
+                    //若不是,数据获取完成后,查询列表全选的值
+                    //若当页有数据在selectList内,则勾选/剔除
+                    this.adjustStatusSelection()
+                }
+            })
+        },
+        handleStatusListPageNoChange(page){
+            this.searchParams.CurrentIndex = page
+            this.getStatusDataList()
+        },
+        // 列表
+        searchList(){
+            this.searchParams.CurrentIndex=1
+            this.getStatusDataList('search')
+        },
+        handleStatusTableSortChange({prop,order}){
+            if(order){
+                this.searchParams.SortParam = prop
+                this.searchParams.SortType = order==='ascending'?'asc':'desc'
+            }else{
+                this.searchParams.SortParam = ''
+                this.searchParams.SortType = ''
+            }
+            this.searchParams.CurrentIndex=1
+            this.getStatusDataList()
+        },
+        //勾选/取消勾选表格项-刷新状态设置
+        adjustStatusSelection(){
+            this.statusDataSelectionItem.selectionReactCancel=true
+            if(!this.statusDataSelectionItem.isSelectAll){
+                this.statusDataSelectionItem.selectList.map(it =>{
+                    let row = this.statusTableData.find(da => da.EdbInfoId==it)
+                    if(row){
+                        setTimeout(()=>{
+                            this.$refs.statusTableRef && this.$refs.statusTableRef.toggleRowSelection(row,true)
+                        },10)
+                    }
+                })
+            }else{
+                this.$refs.statusTableRef && this.$refs.statusTableRef.clearSelection()
+                this.$refs.statusTableRef &&this.$refs.statusTableRef.toggleAllSelection()
+                this.statusDataSelectionItem.selectList.map(it =>{
+                    let row = this.statusTableData.find(da => da.EdbInfoId==it)
+                    if(row){
+                        setTimeout(()=>{
+                            this.$refs.statusTableRef && this.$refs.statusTableRef.toggleRowSelection(row,false)
+                        },50)
+                    }
+                })
+            }
+            setTimeout(()=>{
+                this.statusDataSelectionItem.selectionReactCancel=false
+            },50)
+        },
+        //列表全选改变-刷新状态设置
+        statusListCheckAllChange(value){
+            this.statusDataSelectionItem.selectList = []
+            this.statusDataSelectionItem.isSelectAll = value
+            this.$refs.statusTableRef && this.$refs.statusTableRef.clearSelection()
+            if(value){
+                this.$refs.statusTableRef && this.$refs.statusTableRef.toggleAllSelection()
+            }
+        },
+        statusSelectionChange(selection){
+            if(this.statusDataSelectionItem.selectionReactCancel) return 
+            // selectAllHandle的触发在selectionChange后面,将selectionChange的逻辑延迟一下
+            setTimeout(()=>{
+                // 去重
+                let duplicateArr = Array.from(new Set(this.statusDataSelectionItem.selectList))
+                //isSelectAll为true时,selectList表示需要剔除的项
+                //isSelectAll为false时,selectList表示需要勾选的项
+                //全选
+                if((duplicateArr.length == this.statusDataTotal && (!this.statusDataSelectionItem.isSelectAll)) 
+                || (duplicateArr.length == 0 && this.statusDataSelectionItem.isSelectAll)){
+                    this.statusDataSelectionItem.isCheckAll = true
+                    this.statusDataSelectionItem.isIndeterminate=false
+                //全不选
+                }else if((duplicateArr.length == 0 && (!this.statusDataSelectionItem.isSelectAll)) 
+                || (duplicateArr.length == this.statusDataTotal && this.statusDataSelectionItem.isSelectAll)){
+                    this.statusDataSelectionItem.isCheckAll = false
+                    this.statusDataSelectionItem.isIndeterminate=false
+                //半选
+                }else{
+                    this.statusDataSelectionItem.isCheckAll = false
+                    this.statusDataSelectionItem.isIndeterminate=true
+                }
+            },1)
+        },
+        statusSelectHandle(selection,row){
+            if(this.statusDataSelectionItem.selectionReactCancel) return 
+            let check = false; 
+            if(selection.some(it => it.EdbInfoId == row.EdbInfoId)){
+                // 勾选
+                if(this.statusDataSelectionItem.isSelectAll){
+                    check=false
+                }else{
+                    check=true
+                }
+            }else{
+                // 取消勾选
+                if(this.statusDataSelectionItem.isSelectAll){
+                    check=true
+                }else{
+                    check=false
+                }
+            }
+            if(check){
+                this.statusDataSelectionItem.selectList.push(row.EdbInfoId)
+                }else{
+                this.statusDataSelectionItem.selectList=this.statusDataSelectionItem.selectList.filter(it => it!=row.EdbInfoId)
+            }
+        },
+        statusSelectAllHandle(selection){
+            if(this.statusDataSelectionItem.selectionReactCancel) return 
+            let check = false; 
+            if(selection && selection.length>0){
+                // 全选
+                if(this.statusDataSelectionItem.isSelectAll){
+                    check=false
+                }else{
+                    check=true
+                }
+            }else{
+                // 全不选
+                if(this.statusDataSelectionItem.isSelectAll){
+                    check=true
+                }else{
+                    check=false
+                }
+            }
+            if(check){
+                this.statusDataSelectionItem.selectList =  [...this.statusDataSelectionItem.selectList,...this.statusTableDataIds]
+            }else{
+                this.statusDataSelectionItem.selectList = this.statusDataSelectionItem.selectList.filter(it => !this.statusTableDataIds.includes(it))
+            }
+        },
+        openReferenceCountDia(row){
+            if(row.RelationNum==0) return 
+            dataRefreshInterface.getRelationEdbDetail({EdbInfoId:row.EdbInfoId,CurrentIndex:1,PageSize:9999999}).then(res=>{
+                if(res.Ret == 200){
+                    this.statusEdbRelationDetailList=res.Data.List || []
+                    this.referenceCountShow=true
+                }
+            })
+        },
+        async enableToggle(row){
+            let isRequest=true
+            if(!row.IsStop){
+                isRequest=false
+                await this.$confirm(this.$t('SystemManage.DataRefresh.disable_indicator_prompt'),this.$t('Confirm.prompt'),{
+                    type:"warning"
+                }).then(res=>{
+                    isRequest=true
+                }).catch(()=>{})
+            }
+            if(isRequest){
+                dataBaseInterface.edbRefreshStatusSet({EdbInfoId:row.EdbInfoId,ModifyStatus:row.IsStop==1?'启用':'暂停'}).then(res=>{
+                    if(res.Ret == 200){
+                        row.IsStop=1-row.IsStop
+                        this.$message.success(this.$t('MsgPrompt.operate_success_msg'))
+                    }
+                })
+            }
+        },
+        async setEdbsRefreshStatus(state){
+            let isRequest=true
+            if(state=='暂停'){
+                isRequest=false
+                await this.$confirm(this.$t('SystemManage.DataRefresh.disable_indicator_prompt'),this.$t('Confirm.prompt'),{
+                    type:"warning"
+                }).then(res=>{
+                    isRequest=true
+                }).catch(()=>{})
+            }
+            if(!isRequest) return 
+            
+            let params={
+                Source:Number(this.searchParams.Source),
+                ClassifyId:this.searchParams.ClassifyId,
+                SysUserId:this.searchParams.SysUserId,
+                Frequency:this.searchParams.Frequency,
+                Keyword:this.searchParams.Keyword,
+                Status:this.searchParams.Status,
+                IsSelectAll:this.statusDataSelectionItem.isSelectAll,
+                EdbSelectIdList:this.statusDataSelectionItem.selectList,
+                ModifyStatus:state
+            }
+
+            dataRefreshInterface.setRelationEdbsRefreshStatus(params).then(res=>{
+                if(res.Ret == 200){
+                    this.$message.success(this.$t('MsgPrompt.operate_success_msg'))
+                    this.getStatusDataList()
+                }
+            })
+        },
+        openDefaultRefreshStatusDia(){
+            dataRefreshInterface.getEdbStopRefreshRule({ConfKey:'EdbStopRefreshRule'}).then(res=>{
+                if(res.Ret == 200){
+                    this.settingRuleForm=res.Data.ConfVal?JSON.parse(res.Data.ConfVal):{}
+                    this.setDefaultRefreshStatusShow=true
+                }
+            })
+        },
+        setDefaultRefreshRule(rule){
+            let ruleText = rule?JSON.stringify({...rule,IsOpen:rule.IsOpen?1:0}):''
+            dataRefreshInterface.setEdbStopRefreshRule({ConfKey:'EdbStopRefreshRule',ConfVal:ruleText}).then(res=>{
+                if(res.Ret == 200){
+                    this.$message.success(this.$t('MsgPrompt.operate_success_msg'))
+                    this.setDefaultRefreshStatusShow=false
+                }
+            })
+        },
     },
     mounted(){
         this.getSourceList()
@@ -703,17 +1218,46 @@ export default {
 <style scoped lang="scss">
 .data-refresh-setting-wrap{
     min-height: calc(100vh - 120px);
+    background-color: #fff;
+    border:1px solid #C8CDD9;
+    border-radius: 4px;
     display: flex;
     flex-direction: column;
+    .top-top{
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        border-bottom:solid 1px #E7E7E7 ;
+        padding-right: 30px;
+        height: 62px;
+        .tab-zone{
+            display: flex;
+            align-items: center;
+            flex: 1;
+            height: 100%;
+            .tab-item{
+                cursor: pointer;
+                color: #666666;
+                padding: 0 16px;
+                height: 100%;
+                font-size: 16px;
+                display: flex;
+                align-items: center;
+                box-sizing: border-box;
+                border-bottom: solid 2px #ffffff;
+            }
+            .tab-item.active{
+                color: #0052D9;
+                border-bottom: solid 2px #0052D9;
+            }
+        }
+    }
     .top-box,.table-box{
         box-sizing: border-box;
         padding:20px;
-        background-color: #fff;
-        border:1px solid #C8CDD9;
-        border-radius: 4px;
     }
     .top-box{
-        margin-bottom: 20px;
+        // margin-bottom: 20px;
         display: flex;
         justify-content: space-between;
         .el-input{
@@ -773,5 +1317,60 @@ export default {
             padding: 25px 0;
         }
     }
+    // 刷新状态设置
+    .refresh-status-container{
+        padding: 20px 30px;
+        .refresh-status-search{
+            display: flex;
+            align-items: flex-start;
+            justify-content: space-between;
+            margin-left: -15px;
+            margin-bottom: 12px;
+            .select-source-box{
+                display: flex;
+                align-items: center;
+                margin-left:15px;
+                white-space: nowrap;
+                margin-bottom: 8px;
+                .el-select{
+                    margin-left:15px;
+                    margin-bottom: 0;
+                }
+            }
+            .el-select{
+                margin-left:15px;
+                margin-bottom: 8px;
+            }
+            .refresh-status-search-left{
+                display: flex;
+                align-items: center;
+                flex-wrap: wrap;
+            }
+            .select-item-small{
+                max-width: 140px;
+                margin-bottom: 8px;
+                margin-left:15px;
+            }
+            .selection-box{
+                margin-bottom: 8px;
+                margin-left:15px;
+                white-space: nowrap;
+                span{
+                    margin-left: 12px;
+                }
+            }
+        }
+        .el-table{
+            margin:12px 0 20px;
+        }
+        .table-text-button{
+            cursor: pointer;
+            color: #0052D9;
+            padding: 0 4px;
+        }
+        .el-pagination{
+            text-align: right;
+        }
+    }
 }
 </style>

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.