Browse Source

Merge branch 'master' of http://8.136.199.33:3000/eta_front/eta_front into eta1.6.3

cxmo 9 tháng trước cách đây
mục cha
commit
3371ed520a
100 tập tin đã thay đổi với 7597 bổ sung514 xóa
  1. 2 1
      package.json
  2. 6 2
      src/api/api.js
  3. 58 10
      src/api/http.js
  4. 7 2
      src/api/modules/chartApi.js
  5. 74 6
      src/api/modules/sheetApi.js
  6. 45 1
      src/api/modules/thirdBaseApi.js
  7. 19 0
      src/api/modules/toolBoxApi.js
  8. 1 0
      src/components/edbDetailPopover.vue
  9. 3 3
      src/components/lzTable.vue
  10. 8 4
      src/components/selectUnit.vue
  11. 12 0
      src/lang/commonLang.js
  12. 20 0
      src/lang/modules/ETATables/En.js
  13. 21 0
      src/lang/modules/ETATables/Zh.js
  14. 32 0
      src/lang/modules/ETATables/commonLang.js
  15. 1 1
      src/lang/modules/EtaBase/En.js
  16. 1 1
      src/lang/modules/EtaBase/Zh.js
  17. 21 1
      src/lang/modules/EtaBase/commonLang.js
  18. 2 0
      src/lang/modules/Slides/commonLang.js
  19. 4 0
      src/lang/modules/Slides/pptList.js
  20. 30 0
      src/lang/modules/Slides/pptPresent.js
  21. 4 2
      src/lang/modules/systemManage/BaseConfig.js
  22. 34 0
      src/lang/modules/systemManage/ChartSet.js
  23. 2 0
      src/lang/modules/systemManage/OperateAuth.js
  24. 36 0
      src/routes/modules/chartRoutes.js
  25. 24 2
      src/routes/modules/dataRoutes.js
  26. 10 0
      src/styles/element-ui.scss
  27. 4 5
      src/styles/global.scss
  28. 17 0
      src/utils/buttonConfig.js
  29. 2 2
      src/views/chartRelevance_manage/components/selectTarget.vue
  30. 0 1
      src/views/chartRelevance_manage/crossVarietyAnalysis/list.vue
  31. 0 1
      src/views/chartRelevance_manage/fittingEquation/fittingEquationList.vue
  32. 0 7
      src/views/chartRelevance_manage/relevance/list.vue
  33. 0 1
      src/views/chartRelevance_manage/statistic/statisticFeatureList.vue
  34. 1 0
      src/views/dataEntry_manage/addChart.vue
  35. 0 1
      src/views/dataEntry_manage/chartSetting.vue
  36. 3 2
      src/views/dataEntry_manage/codecount/index.vue
  37. 3 1
      src/views/dataEntry_manage/components/barOptionSection.vue
  38. 1 1
      src/views/dataEntry_manage/components/chartSourceEditDialog.vue
  39. 82 0
      src/views/dataEntry_manage/components/edbHasUsedDia.vue
  40. 25 1
      src/views/dataEntry_manage/databaseComponents/dataAssociateChart.vue
  41. 11 0
      src/views/dataEntry_manage/databaseComponents/dataAssociateComputeData.vue
  42. 6 9
      src/views/dataEntry_manage/databaseComponents/edbDetailData.vue
  43. 4 3
      src/views/dataEntry_manage/databaseComponents/fittingResidueDia.vue
  44. 86 19
      src/views/dataEntry_manage/databaseList.vue
  45. 1 0
      src/views/dataEntry_manage/editChart.vue
  46. 19 9
      src/views/dataEntry_manage/mixins/addOreditMixin.js
  47. 50 36
      src/views/dataEntry_manage/mixins/chartPublic.js
  48. 299 0
      src/views/dataEntry_manage/thirdBase/ZczxData.vue
  49. 3 3
      src/views/dataEntry_manage/thirdBase/bloombergSource.vue
  50. 513 0
      src/views/dataEntry_manage/thirdBase/ccfData.vue
  51. 1 1
      src/views/dataEntry_manage/thirdBase/icpiConsumption.vue
  52. 5 1
      src/views/dataEntry_manage/thirdBase/selfDataBase.vue
  53. 638 0
      src/views/datasheet_manage/balanceSheetEdit.vue
  54. 5 1
      src/views/datasheet_manage/common/customTable.js
  55. 995 0
      src/views/datasheet_manage/components/BalanceAddChart.vue
  56. 160 0
      src/views/datasheet_manage/components/BalanceSheetChartItem.vue
  57. 157 0
      src/views/datasheet_manage/components/BalanceSheetList.vue
  58. 2083 0
      src/views/datasheet_manage/components/BalanceTable.vue
  59. 22 5
      src/views/datasheet_manage/components/MixedTable.vue
  60. 12 4
      src/views/datasheet_manage/components/calculateEdbDia.vue
  61. 19 4
      src/views/datasheet_manage/components/insertDateDia.vue
  62. 12 3
      src/views/datasheet_manage/components/selectTargetValueDia.vue
  63. 2 1
      src/views/datasheet_manage/components/sheetClassifyDia.vue
  64. 1 1
      src/views/datasheet_manage/components/toolBarSection.vue
  65. 56 13
      src/views/datasheet_manage/customAnalysis/list.vue
  66. 81 11
      src/views/datasheet_manage/customSheetEdit.vue
  67. 76 8
      src/views/datasheet_manage/mixedSheetEdit.vue
  68. 119 0
      src/views/datasheet_manage/mixins/balanceTableMixin.js
  69. 2 1
      src/views/datasheet_manage/mixins/classifyMixin.js
  70. 206 11
      src/views/datasheet_manage/sheetList.vue
  71. 0 1
      src/views/futures_manage/commodityChartBase.vue
  72. 15 13
      src/views/mychart_manage/components/chartDetailDia.vue
  73. 1 2
      src/views/mychart_manage/index.vue
  74. 3 0
      src/views/ppt_manage/mixins/layerMixins.js
  75. 73 29
      src/views/ppt_manage/mixins/mixins.js
  76. 361 31
      src/views/ppt_manage/mixins/pptEditorMixins.js
  77. 97 13
      src/views/ppt_manage/mixins/pptMixins.js
  78. 1 0
      src/views/ppt_manage/mixins/virtualScrollMixins.js
  79. 5 1
      src/views/ppt_manage/newVersion/components/IndexItem.vue
  80. 1 0
      src/views/ppt_manage/newVersion/components/TextEditor.vue
  81. 25 2
      src/views/ppt_manage/newVersion/components/catalog/pptContent.vue
  82. 25 2
      src/views/ppt_manage/newVersion/components/catalog/pptContentEn.vue
  83. 73 17
      src/views/ppt_manage/newVersion/components/editor/AddFormat.vue
  84. 3 1
      src/views/ppt_manage/newVersion/components/editor/ChangeFormatDialog.vue
  85. 2 1
      src/views/ppt_manage/newVersion/components/editor/DeletePageDialog.vue
  86. 2 2
      src/views/ppt_manage/newVersion/components/editor/InsertPageDialog.vue
  87. 219 0
      src/views/ppt_manage/newVersion/components/editor/TitleEditorTool.vue
  88. 3 20
      src/views/ppt_manage/newVersion/components/editor/chooseCover/TextEl.vue
  89. 1 1
      src/views/ppt_manage/newVersion/components/formatEl/ChartEl.vue
  90. 21 2
      src/views/ppt_manage/newVersion/components/formatEl/SheetEl.vue
  91. 2 55
      src/views/ppt_manage/newVersion/components/formatEl/TextEl.vue
  92. 80 0
      src/views/ppt_manage/newVersion/components/formatPage/FormatThirteen.vue
  93. 12 4
      src/views/ppt_manage/newVersion/components/formatPage/mixins.js
  94. 4 1
      src/views/ppt_manage/newVersion/components/formatPreview/FormatPreEle.vue
  95. 26 0
      src/views/ppt_manage/newVersion/components/formatPreview/FormatPreThirteen.vue
  96. 3 22
      src/views/ppt_manage/newVersion/components/layer/Element/TextShape.vue
  97. 111 1
      src/views/ppt_manage/newVersion/css/common.scss
  98. 37 16
      src/views/ppt_manage/newVersion/css/format.scss
  99. 14 14
      src/views/ppt_manage/newVersion/pptCatalog.vue
  100. 118 60
      src/views/ppt_manage/newVersion/pptEditor.vue

+ 2 - 1
package.json

@@ -66,7 +66,8 @@
     "vue2-datepicker": "^3.8.0",
     "vuedraggable": "^2.24.3",
     "vuex": "^2.0.0-rc.6",
-    "webpack-parallel-uglify-plugin": "1.0.0"
+    "webpack-parallel-uglify-plugin": "1.0.0",
+    "xlsx": "^0.18.5"
   },
   "devDependencies": {
     "@babel/runtime-corejs2": "^7.9.2",

+ 6 - 2
src/api/api.js

@@ -15,8 +15,10 @@ import {
   fwmtInterface,
   guangqiInterface,
   icpiInterface,
+  zczxInterface,
   coalWordInterface,
-  bloombergInterface
+  bloombergInterface,
+  ccfDataInterface
 } from './modules/thirdBaseApi';
 
 //手工指标 手工数据 手工数据权限
@@ -123,8 +125,10 @@ export {
   fwmtInterface,
   guangqiInterface,
   icpiInterface,
+  zczxInterface,
   coalWordInterface,
-  bloombergInterface
+  bloombergInterface,
+  ccfDataInterface
 };
 
 //老接口 研报 ppt等

+ 58 - 10
src/api/http.js

@@ -1,6 +1,16 @@
 "use strict";
 import axios from "axios";
 import bus from "./bus.js";
+let store=null
+// 异步加载store模块 不异步加载的话,@/api/modules/oldApi.js的导入导出写法会有问题
+import('@/vuex/index.js')
+.then(module => {
+  store=module.default
+})
+.catch(err => {
+  console.error(err,'vuex加载错误');
+});
+
 axios.defaults.withCredentials = true;
 axios.defaults.timeout = 0;
 axios.interceptors.request.use(
@@ -43,16 +53,29 @@ function getData(val, url) {
   return val;
 }
 
-function checkStatus(response) {
+function errorMsgShow(closableErrMsg,msg){
+  if(closableErrMsg){
+    let messageHint = bus.$message.error({
+      message:msg,
+      duration:0,
+      showClose:true
+    })
+    store.mutations.PUSH_CLOSABLE_HINT(store.state,messageHint)
+  }else{
+    bus.$message.error(msg);
+  }
+}
+
+function checkStatus(response,closableErrMsg) {
   //处理响应数据
   if (response && response.status === 200) {
     // loading,如果http状态码正常,则直接返回数据
     let res = bus.$parseData(response);
     if (!res) {
-      bus.$message.error("服务器开了个小差");
+      errorMsgShow(closableErrMsg,'服务器开了个小差')
       return false;
     } else if (res.Ret == 403) {
-      bus.$message.error(res.Msg);
+      errorMsgShow(closableErrMsg,res.Msg)
     } else if (res.Ret === 408) {
       localStorage.setItem("auth", "")
       localStorage.setItem("loginTime", "")
@@ -66,14 +89,19 @@ function checkStatus(response) {
     }
     return res;
   } else {
-    bus.$message.error("网络异常");
+    errorMsgShow(closableErrMsg,'网络异常')
     return false;
   }
 }
 
-function checkCode(res) {
-  bus.$message.error("网络异常");
+function checkCode(res,closableErrMsg) {
+  errorMsgShow(closableErrMsg,'网络异常')
 }
+
+function isFormData(obj) {
+  return typeof obj === 'object' && obj instanceof FormData;
+}
+
 // 请求时间需要过长,取消限制
 const cancelTimeoutUrlPost = ["/cloud_disk/resource/upload"];
 
@@ -81,6 +109,16 @@ export default {
   post(url, data) {
     //post请求方式
     let timeout = cancelTimeoutUrlPost.includes(url) ? 0 : 600000;
+    // 自定义参数
+    /**
+     * closableErrMsg123 -- 错误提示需要时可关闭类型的
+     */
+    let closableErrMsg=false
+    if(data){
+      // 区分formData格式
+      closableErrMsg = isFormData(data)?!!data.get('closableErrMsg123'):!!data.closableErrMsg123
+      isFormData(data)?data.delete('closableErrMsg123'):(data.closableErrMsg123=undefined)
+    }
     return axios({
       method: "post",
       url: url,
@@ -90,13 +128,23 @@ export default {
       headers: { "Content-Type": "application/json; charset=utf-8" },
     })
       .then((response) => {
-        return checkStatus(response);
+        return checkStatus(response,closableErrMsg);
       })
       .catch((res) => {
-        return checkCode(res);
+        return checkCode(res,closableErrMsg);
       });
   },
   get(url, data, responseType = "json") {
+    // 自定义参数
+    /**
+     * closableErrMsg123 -- 错误提示需要时可关闭类型的
+     */
+    let closableErrMsg=false
+    if(data){
+      closableErrMsg = !!data.closableErrMsg123
+      data.closableErrMsg123=undefined
+    }
+
     //get请求方式
     return axios({
       method: "get",
@@ -123,10 +171,10 @@ export default {
         if(responseType==='blob'){
           return response
         }
-        return checkStatus(response);
+        return checkStatus(response,closableErrMsg);
       })
       .catch((res) => {
-        return checkCode(res);
+        return checkCode(res,closableErrMsg);
       });
   },
   Base64,

+ 7 - 2
src/api/modules/chartApi.js

@@ -689,7 +689,10 @@ const dataBaseInterface = {
 		},
 		/**
 		 * 多图表一键刷新
-		 * @param {ChartInfoCode} params 
+		 * @param {Object} params
+		 * @param {Array} params.ChartInfoCode
+		 * @param {String} params.Source 来源,枚举值:report、english_report、smart_report、ppt、en_ppt
+		 * @param {Number} params.PrimaryId 报告id/pptId
 		 * @returns 
 		 */
 		reportRefresh: params => {
@@ -972,7 +975,9 @@ const dataBaseInterface = {
 
 	/** 
 	 * 获取图表批量刷新结果
-	 *   Source ReportId ReportChapterId
+	 * @param {Object} params
+	 * @param {String} params.Source 来源,枚举值:report、english_report、smart_report、ppt、en_ppt
+	 * @param {Number} params.PrimaryId 报告id/pptId
 	 * 
 	 */
 	getReportrefreshStatus: params => {

+ 74 - 6
src/api/modules/sheetApi.js

@@ -141,6 +141,67 @@ export const uploadImg = params => {
   return http.get('/datamanage/excel_info/table_data',params)
 }
 
+// 平衡表获取子表列表
+export const getBalanceChildTable=params=>{
+	return http.get('/datamanage/excel_info/child_table',params)
+}
+
+// 平衡表修改子表名称
+export const balanceChildTableRename=params=>{
+	return http.post('/datamanage/excel_info/rename',params)
+}
+
+//获取平衡表协作人数据
+export const getBalanceTableWorker=params=>{
+	return http.get('/datamanage/excel_info/worker',params)
+}
+
+//设置平衡表协作人数据
+export const setBalanceTableWorker=params=>{
+	return http.post('/datamanage/excel_info/worker/save',params)
+}
+
+//获取平衡表中图表数据
+export const getBalanceChartData=params=>{
+	return http.get('/datamanage/excel_info/balance/chart_list',params)
+}
+
+//平衡表中新增图表数据
+export const addBalanceChart=params=>{
+	return http.post('/datamanage/excel_info/balance/chart_add',params)
+}
+
+//平衡表中编辑图表数据
+export const editBalanceChart=params=>{
+	return http.post('/datamanage/excel_info/balance/chart_edit',params)
+}
+
+//平衡表中删除图表
+export const delBalanceChart=params=>{
+	return http.post('/datamanage/excel_info/balance/chart_del',params)
+}
+
+//平衡表季节图预览 获取数据
+export const balanceSeasonChart=params=>{
+	return http.post('/datamanage/excel_info/balance/chartLegend/preview',params)
+}
+
+//平衡表获取版本列表
+export const balanceTableVersion=params=>{
+	return http.get('/datamanage/excel_info/balance/version',params)
+}
+
+//平衡表存为静态表
+export const balanceTableSaveStatic=params=>{
+	return http.post('/datamanage/excel_info/balance/static/add',params)
+}
+
+//平衡表静态表重命名
+export const balanceStaticTableRename=params=>{
+	return http.post('/datamanage/excel_info/balance/version/modify',params)
+}
+
+
 /* =====自定义表格====== */
 
 /**
@@ -219,6 +280,15 @@ export const refreshCustomSheet = params => {
 	return http.get('/datamanage/excel_info/table/refresh',params)
 }
 
+/**
+ * 表格 获取原始指标来源
+ * @param {*} params  EdbInfoId
+ * @returns  
+ */
+export const getEdbBaseSource = params => {
+	return http.get('/datamanage/excel_info/get_edb_source',params)
+}
+
 /**
  * 下载excel
  * @param {*} params ExcelInfoId authorization
@@ -291,9 +361,8 @@ export const getMixedCalculateData = params => {
  * 表格一键刷新
  * @param {Object} params
  * @param {Array} params.ExcelCodes 表格唯一编码
- * @param {String} params.Source 来源,枚举值:report、english_report、smart_report
- * @param {Number} params.ReportId 报告id
- * @param {Number} params.ReportChapterId 章节id 非章节传0
+ * @param {String} params.Source 来源,枚举值:report、english_report、smart_report、ppt、en_ppt
+ * @param {Number} params.PrimaryId 报告id/pptId
  */
 export const refreshSheet = (params)=>{
     return http.post('/datamanage/excel_info/table/batch_refresh',params)
@@ -301,9 +370,8 @@ export const refreshSheet = (params)=>{
 /**
  * 获取表格刷新结果
  * @param {Object} params
- * @param {String} params.Source 来源,枚举值:report、english_report、smart_report
- * @param {Number} params.ReportId 报告id
- * @param {Number} params.ReportChapterId 章节id 非章节传0
+ * @param {String} params.Source 来源,枚举值:report、english_report、smart_report、ppt、en_ppt
+ * @param {Number} params.PrimaryId 报告id/pptId
  */
 export const getRefreshResult = (params)=>{
     return http.post('/datamanage/excel_info/table/batch_refresh/result',params)

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

@@ -966,7 +966,49 @@ const bloombergInterface={
     },
 
 }
+/* 卓创资讯数据源 */
+const zczxInterface={
+	/**
+	 * 分类列表
+	 */
+	classifyList:params=>{
+			return http.get('/data_source/sci99/classify/list',params)
+	},
+	/**
+	 * 数据列表
+	 * @param {String} ClassifyId
+	 * @returns 
+	 */
+	dataList:params=>{
+			return http.get('/data_source/sci99/index/data',params)
+	}
+}
 
+/* CCF化纤信息 */
+const ccfDataInterface={
+	/**
+	 * 分类列表
+	 * @param {} params 
+	 * @returns 
+	 */
+	classifyList: params => {
+		return http.get('/datamanage/ccf/classify',params);
+	},
+	/**
+	 * 获取指标列表详情
+	 */
+	dataList: params => {
+		return http.get('/datamanage/ccf/index/data',params);
+	},
+	//单个指标数据
+	getTargetDataList:params=>{
+		return http.get('/datamanage/ccf/single_data',params);
+	},
+	// 搜索
+	getTargetListByName:params=>{
+		return http.get('/datamanage/ccf/search_list',params);
+	}
+}
 export { 
 	lzDataInterface,
 	glDataInterface,
@@ -982,6 +1024,8 @@ export {
   fwmtInterface,
 	guangqiInterface,
 	icpiInterface,
+	zczxInterface,
 	coalWordInterface,
-    bloombergInterface
+	bloombergInterface,
+	ccfDataInterface
 }

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

@@ -92,4 +92,23 @@ export const ForexCalendarInterface = {
     searchEdbInfo:(params)=>{
         return http.get("/datamanage/edb_info/filter_by_es/all",params)
     }
+}
+
+//CCF化纤信息装置
+export const CCFStockInterface = {
+    /**
+     * 获取分类列表
+     */
+    classifyList:()=>{
+        return http.get("/datamanage/ccf/stock/classify")
+    },
+    /**
+     * 获取数据详情
+     * @param {*} params 
+     * @param {Number} params.ClassifyId 分类Id
+     * @param {String} params.TableDate 时间
+     */
+    excelDataDetail:(params)=>{
+        return http.get("/datamanage/ccf/stock/table",params)
+    }
 }

+ 1 - 0
src/components/edbDetailPopover.vue

@@ -5,6 +5,7 @@
     width="350"
     offset="100"
     trigger="hover"
+    :disabled="!info.HaveOperaAuth"
   >
     <ul class="edb-info-cont">
       <li v-for="key in keysArr" :key="key">

+ 3 - 3
src/components/lzTable.vue

@@ -75,7 +75,7 @@ export default {
 		headerArr(){
 			let arr=['QuotaName','LzCode','Frequency','UnitName','ModifyTime']
 
-			let sourceTypeOne = ['smm','coal','baiinfo','yyzx','icpi','coalWord']
+			let sourceTypeOne = ['smm','coal','baiinfo','yyzx','icpi','coalWord','ccf']
 
 			if(this.source==='gl'){
 				arr=['IndexName','IndexCode','FrequencyName','UnitName','UpdateTime']
@@ -93,7 +93,7 @@ export default {
 				['UnitName', /* '单位' */this.$t('Edb.Detail.e_unit')],
 				['ModifyTime', /* '更新时间' */this.$t('Edb.Detail.e_update_time')],
 			])
-			let sourceTypeOne = ['smm','coal','baiinfo','yyzx','icpi','coalWord']
+			let sourceTypeOne = ['smm','coal','baiinfo','yyzx','icpi','coalWord','ccf']
 
 			if(this.source==='gl'){
 				temMap=new Map([
@@ -117,7 +117,7 @@ export default {
 		},
 		dynamic_key(){
 			let key='InputValue'
-			if(['smm','baiinfo','coal','yyzx','icpi'].includes(this.source)){
+			if(['smm','baiinfo','coal','yyzx','icpi','ccf'].includes(this.source)){
 				key='Value'
 			}else if(this.source=='coalWord'){
 				key='DealValue'

+ 8 - 4
src/components/selectUnit.vue

@@ -50,10 +50,14 @@ export default {
         }
     },
     watch:{
-        value(){
-            if(this.value){
-                this.unit = this.getUnitTrans(this.value)
-            }
+        value:{
+            handler(){
+                if(this.value){
+                    console.log('value',this.value)
+                    this.unit = this.getUnitTrans(this.value)
+                }
+            },
+            immediate:true
         }
     },
     data() {

+ 12 - 0
src/lang/commonLang.js

@@ -304,6 +304,14 @@ export default {
       zh:'暂无表格权限,如有问题请联系管理员!',
       en:'You currently have no table permissions. If there is an issue, please contact the administrator!'
     },
+    no_file_for_download_btn:{
+      en: 'No files available for download.',
+      zh: '暂无下载文件'
+    },
+    no_data_date_msg:{
+      en: 'No data available for this date.',
+      zh: '该日期暂无数据'
+    },
   },
   Common: {
     category: {
@@ -330,6 +338,10 @@ export default {
       en:'Add',
       zh:'新增'
     },
+    edit_btn:{
+      en:'Edit',
+      zh:'编辑'
+    },
     to: {
       en: ' To ',
       zh:'至'

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

@@ -83,6 +83,18 @@ export default {
     table_data_update_msg: "The table data has been updated",
     formula_lable: "Formula",
     parent_directory_lable: "Parent directory",
+    add_balance_table_btn:'Add Balance Sheet',
+    Co_editor:'Co-editor',
+    save_static_table:'Save as a static table',
+    save_static_table_tip:'Please enter the version name',
+    static_table_version_name:'Version name',
+    chart_source_placehoder:'please enter data source',
+    left_limit:'Left axis limits',
+    right_limit:'Right axis limits',
+    right_two_limit:'limits of the right second axis',
+    y_limit:'Vertical axis limits',
+    time_serial:'Time Series',
+    value_serial:'numerical sequence',
     not_allow_edit:'Currently not editable'
   },
 
@@ -159,4 +171,12 @@ export default {
     lagging_lable: "lagging",
     select_metric: "Please select a metric",
   },
+
+  /* 平衡表  */
+  BalanceSheet:{
+    version:'Version',
+    active_table:'Active',
+    save_static_table:'Save as a static table',
+    only_edit:'Editable',
+  },
 };

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

@@ -83,6 +83,18 @@ export default {
     table_data_update_msg: "表格数据已更新",
     formula_lable: "公式",
     parent_directory_lable: "上级目录",
+    add_balance_table_btn:'添加平衡表',
+    Co_editor:'协作人',
+    save_static_table:'存为静态表',
+    save_static_table_tip:'请输入版本名称',
+    static_table_version_name:'版本名称',
+    chart_source_placehoder:'请输入数据来源',
+    left_limit:'左轴上下限',
+    right_limit:'右轴上下限',
+    right_two_limit:'右二轴上下限',
+    y_limit:'纵轴上下限',
+    time_serial:'时间序列',
+    value_serial:'数值序列',
     not_allow_edit:'当前不可编辑'
   },
 
@@ -171,4 +183,13 @@ export default {
   lagging_lable: "滞后",
   select_metric: "请选择指标",
   },
+
+  /* 平衡表  */
+  BalanceSheet:{
+    version:'版本',
+    active_table:'动态表',
+    save_static_table:'存为静态表',
+    only_edit:'只看可编辑',
+    
+  },
 };

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

@@ -82,6 +82,10 @@ export default {
       en: "Insertion Successful",
       zh: "插入成功",
     },
+    is_del_balance_chart_msg:{
+      en:'After deletion, this chart will no longer be referenced. Are you sure to delete it?',
+      zh:'删除后该图表将不能再引用,确认删除吗?',
+    },
   },
   Date: {
     monday: {
@@ -219,6 +223,34 @@ export default {
       en: "Insert row below",
     },
   },
+  BalanceSheetTable:{
+    name:{
+      zh: "名称",
+      en: "Name",
+    },
+    creator:{
+      zh: "创建人",
+      en: "Creator",
+    },
+    updater:{
+      zh: "更新人",
+      en: "Updater",
+    },
+    update_time:{
+      zh: "更新时间 ",
+      en: "Updating Time",
+    }
+  },
+  Common:{
+    data_source:{
+      zh: "数据来源",
+      en: "Source",
+    },
+    source:{
+      zh: "来源",
+      en: "Source",
+    }
+  }
 };
 
 //ETable

+ 1 - 1
src/lang/modules/EtaBase/En.js

@@ -62,7 +62,7 @@ export default {
     origin_edb: 'Original Indicator',
     replace: 'Replace to',
     replace_all: 'Replace all',
-    replace_tip: 'Tip: After the replacement, charts and calculated indicators that refer to the original indicator will be replaced by the replacement indicator.',
+    replace_tip: 'Note: After replacement, all references to the original metric in charts, tables, calculated metrics, and logic diagrams will be substituted with the replacement metric.',
     replace_success_msg: 'This replacement will last for a longer period of time, confirm the replacement?',
     replace_ing_msg: 'The replacement is currently in progress, please be patient',
     input_origin_vaild: 'Original Indicator can not be empty',

+ 1 - 1
src/lang/modules/EtaBase/Zh.js

@@ -62,7 +62,7 @@ export default {
     origin_edb: '原指标',
     replace: '替换为',
     replace_all: '全部替换',
-    replace_tip: '提示:替换后,图表和计算指标引用到原指标的会全部由替换指标替代',
+    replace_tip: '提示:替换后,图、表、计算指标和逻辑图引用到原指标的会全部由替换指标替代',
     replace_success_msg: '本次替换将持续较长时间,是否确认替换?',
     replace_ing_msg: '当前正在替换中,请耐心等待',
     input_origin_vaild: '原指标不能为空',

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

@@ -48,6 +48,22 @@ export default {
     zh:'查看数据',
     en:'View indicators'
   },
+  detail_formula_btn: {
+    zh:'查看公式',
+    en:'Formula'
+  },
+  detail_related_charts_btn: {
+    zh:'关联图',
+    en:'Related Charts'
+  },
+  detail_related_metrics_btn: {
+    zh:'关联指标',
+    en:'Related Metrics'
+  },
+  detail_return_btn:{
+    zh:'返回',
+    en:'Return'
+  },
   detail_del_btn:{
     zh:'删除',
     en:'Delete'
@@ -1213,7 +1229,11 @@ export default {
     },
     del_edb_use_chart: {
       zh: '当前指标已用作画图,不可删除',
-      en: 'The current indicator is being used for drawing and cannot be deleted.'
+      en: 'The current metric is in use for charting and cannot be deleted.'
+    },
+    del_edb_use_table: {
+      zh: '当前指标已被表格引用,不可删除',
+      en: 'The current metric is referenced by a table and cannot be deleted.'
     },
     del_menu_confirm: {
       zh: '确定删除当前目录吗?',

+ 2 - 0
src/lang/modules/Slides/commonLang.js

@@ -18,6 +18,7 @@ export const operationsEn = {
   operations_presentation: "Presentation",
   go_to_publish: "Go to publish",
   operations_save: "Save",
+  operations_refresh:"Refresh",
   operations_insert: "Insert PPT",
   operations_switch: "Switch template",
   paste_before_slide: "Paste before this slide",
@@ -49,6 +50,7 @@ export const operationsZh = {
   operations_presentation: "演示",
   go_to_publish: "去发布",
   operations_save: "保存",
+  operations_refresh:"一键刷新",
   operations_insert: "插入PPT",
   operations_switch: "切换模板",
   paste_before_slide: "粘贴到此页前",

+ 4 - 0
src/lang/modules/Slides/pptList.js

@@ -14,10 +14,12 @@ export const listEn = {
   select_user_btn: "Select user",
   add_my_directory: "Add My Directory",
   creation_time: "Creation time",
+  update_time: "Update time",
   author_info: "Author",
   time_info: "Time",
   operation_info: "Operation",
   publish_info: "Publish",
+  publish_ab:'Pub',
   save_info: "Save",
   rename_successful: "Rename Successful",
   copy_successfully: "Copy Successful",
@@ -136,10 +138,12 @@ export const listZh = {
   select_user_btn: "选择用户",
   add_my_directory: "添加我的目录",
   creation_time: "创建时间",
+  update_time: "更新时间",
   author_info: "作者",
   time_info: "时间",
   operation_info: "操作",
   publish_info: "发布",
+  publish_ab:'发布',//缩写
   save_info: "保存",
   rename_successful: "重命名成功",
   copy_successfully: "复制成功",

+ 30 - 0
src/lang/modules/Slides/pptPresent.js

@@ -35,6 +35,8 @@ export const presentEn = {
   text_element: "Text settings",
   batch_deletion_successful: "Batch deletion successfu",
   retrieving_ppt_data: "Retrieving PPT data",
+  refresh_ppt_el:"Refreshing the charts and tables in the PPT...",
+  refresh_ppt_hint:"Charts and tables have not been added and cannot be refreshed",
   loading_urgently: "Loading urgently",
   convert_to_report_dlg: "PPT convert to report",
   report_type_select: "Report type",
@@ -89,6 +91,19 @@ export const presentEn = {
   table_chart: "Chart",
   is_incomplete_please_edit:'Slide {num} content is incomplete, please re-edit!',
   publishing_loading:'Publishing',
+
+  page_title_style_setting:'Title Style Setting',
+  title_location_settings:'Location Settings',
+  title_location_up_down:'up and down',
+  title_location_left_right:'left and right',
+  title_size_settings:'Size Settings',
+  title_size_width:'width',
+  title_size_height:'height',
+  title_content_settings:'Content Settings',
+  apply_to_the_entire:'Apply to the entire PPT',
+  title_style_fontfamily:"Font Family",
+  title_style_fontsize:'Font Size',
+  title_style_color:'Font Color'
 };
 
 /* 中文 */
@@ -126,6 +141,8 @@ export const presentZh = {
   text_element: "文本设置",
   batch_deletion_successful: "批量删除成功",
   retrieving_ppt_data: "正在获取ppt数据",
+  refresh_ppt_el:"正在刷新PPT内图表和表格...",
+  refresh_ppt_hint:"还未添加图表和表格,无法刷新",
   loading_urgently: "拼命加载中",
   convert_to_report_dlg: "PPT转报告",
   report_type_select: "报告类型",
@@ -178,6 +195,19 @@ export const presentZh = {
   previous_sheet_default: "上一张",
   is_incomplete_please_edit:'第{num}页内容不完整,请重新编辑!',
   publishing_loading:'发布中...',
+
+  page_title_style_setting:'标题编辑模式',
+  title_location_settings:'位置设置',
+  title_location_up_down:'上下',
+  title_location_left_right:'左右',
+  title_size_settings:'大小设置',
+  title_size_width:'宽度',
+  title_size_height:'高度',
+  title_content_settings:'内容设置',
+  apply_to_the_entire:'应用至整个PPT',
+  title_style_fontfamily:"字体设置",
+  title_style_fontsize:'字号设置',
+  title_style_color:'字体颜色'
 };
 
 /**

+ 4 - 2
src/lang/modules/systemManage/BaseConfig.js

@@ -67,7 +67,8 @@ export const BaseConfigEn = {
     resource_label02:'Image Type',
     report_title:"Report Title",
     report_author:"Report Author",
-    report_creation_time:"Creation Time",
+    // report_creation_time:"Creation Time",
+    report_release_time:"Release Time",
     select_layout:"Select Layout",
     edit_layout:"Edit Layout",
     completed_step:"Completed Step",
@@ -169,7 +170,8 @@ export const BaseConfigZh = {
     resource_label02:'图片类型',
     report_title:"研报标题",
     report_author:"研报作者",
-    report_creation_time:"创建时间",
+    // report_creation_time:"创建时间",
+    report_release_time:"发布时间",
     select_layout:"选择版图",
     edit_layout:"编辑版图",
     completed_step:"已完成步骤",

+ 34 - 0
src/lang/modules/systemManage/ChartSet.js

@@ -4,10 +4,14 @@
 
 /* 英文 */
 export const ChartSetEn = {
+    label00:'Chart Data Source Setting',
+    label00_hint:`<p>The state of "enabled" indicates that when creating a new chart or table, the data source switch is set to "on" by default, and can be manually switched on or off. The "disabled" state works in the same way. </p>
+                <p style="margin-top:10px">Note: This only applies to newly created charts and tables; it does not affect historical charts.</p>`,
     label01:'Chart Types',
     label02:'Chart Library Default Theme',
     add_btn:'Add Custom Theme',
     edit_btn:'Edit Custom Theme',
+    rename:'Rename',
     theme_name:'Theme Name',
     theme_name_placeholder:'Please enter theme name',
     alert_msg:'After deletion, all charts using this theme will adopt the ETA theme. Are you sure you want to proceed with the deletion?',
@@ -33,21 +37,38 @@ export const ChartSetEn = {
     config_opt08:'Font Size',
     config_opt09:'Alignment Method',
     config_opt10:'Background Color',
+    config_opt11:'数据标记',
+    config_opt12:'标记类型',
+    config_opt13:'标记大小',
+    config_opt14:'标记颜色',
+
+    square:'Square',
+    circle:'Circle',
+    // diamond-砖石 highcharts里面菱形标记的值,所以这边用diamond
+    diamond:'Rhomboid',
+    triangle:'Triangle',
+    triangle_down:'Inverted Triangle',
 
     unit01:'st Line',
     unit02:'st Bar',
     unit03:'st Series',
     config_opt05_yes:'Yes',
     config_opt05_no:'No',
+    config_opt11_none:'无',
+    config_opt11_inside:'内置',
     set_hint:'The default theme is set successfully',
 };
   
 /* 中文 */
 export const ChartSetZh = {
+    label00:'图表的数据来源',
+    label00_hint:`<p>开启状态表示新建图表或表格时,数据来源开关默认开启,可手动切换,关闭状态同理。</p>
+                <p style="margin-top:10px">注:仅对新增图表、表格生效,历史图表不处理。</p>`,
     label01:'图表类型',
     label02:'图库默认主题',
     add_btn:'添加自定义主题',
     edit_btn:'编辑自定义主题',
+    rename:'重命名',
     theme_name:'主题名称',
     theme_name_placeholder:'请输入主题名称',
     alert_msg:'删除后,所有采用该主题的图表,将采用ETA主题,是否确定删除?',
@@ -73,12 +94,25 @@ export const ChartSetZh = {
     config_opt08:'字号',
     config_opt09:'对齐方式',
     config_opt10:'背景色',
+    config_opt11:'数据标记',
+    config_opt12:'标记类型',
+    config_opt13:'标记大小',
+    config_opt14:'标记颜色',
+
+    square:'正方形',
+    circle:'圆形',
+    // diamond-砖石 highcharts里面菱形标记的值,所以这边用diamond
+    diamond:'菱形',
+    triangle:'三角形',
+    triangle_down:'倒三角形',
 
     unit01:'条',
     unit02:'根',
     unit03:'系列',
     config_opt05_yes:'是',
     config_opt05_no:'否',
+    config_opt11_none:'无',
+    config_opt11_inside:'内置',
     set_hint:'默认主题设置成功',
 };
   

+ 2 - 0
src/lang/modules/systemManage/OperateAuth.js

@@ -53,6 +53,7 @@ export const OperateAuthEn = {
     tab_sub_sheet1:'Custom analysis',
     tab_sub_sheet2:'Time Series Table',
     tab_sub_sheet3:'Mixed Table ',
+    tab_sub_sheet4:'Balance Table ',
     label_count: 'Quantity',
     label_checked:'Selected',
     ph_see_user:'Please select visible users',
@@ -124,6 +125,7 @@ export const OperateAuthZh = {
     tab_sub_sheet1:'自定义分析',
     tab_sub_sheet2:'时间序列表格',
     tab_sub_sheet3:'混合表格',
+    tab_sub_sheet4:'平衡表',
     label_count: '数量',
     label_checked:'已选',
     ph_see_user:'请选择可见用户',

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

@@ -223,6 +223,33 @@ export default [
 					name_en:"Generated pointer"
 				}
 			},
+			{
+				path:"sheetBalanceList",
+				name:"平衡表",
+				component:()=>import('@/views/datasheet_manage/sheetList.vue'),
+				meta:{
+					name_en:'Balance Sheet'
+				}
+			},
+			{
+				path:"viewBalanceSheet",
+				name:"平衡表",
+				component:()=>import('@/views/datasheet_manage/balanceSheetEdit.vue'),
+				meta:{
+					name_en:'Balance Sheet'
+				}
+			},
+			{
+				path:"editBalanceSheet",
+				name:"编辑平衡表",
+				component:()=>import('@/views/datasheet_manage/balanceSheetEdit.vue'),
+				meta: {
+					name_en:'Edit Balance sheet',
+					pathFrom: "sheetBalanceList",
+					pathName: "平衡表",
+					pathName_en:'Balance Sheet'
+				}
+			},
 		]
 	},
 
@@ -491,6 +518,15 @@ export default [
 					name_en:'ForexCalendar'
 				},
 			},
+			{
+				path:"CCFStock",
+				name:"CCF化纤信息装置",
+				component:()=>import('@/views/toolBox_manage/CcfDevice.vue'),
+				meta:{
+          name_en:'CCF Fiber Device'
+        },
+			},
+			
 		]
 	}
 ]

+ 24 - 2
src/routes/modules/dataRoutes.js

@@ -310,13 +310,35 @@ export default [
         path: 'selfData',
         component: () => import("@/views/dataEntry_manage/thirdBase/selfDataBase.vue"),
         name: "自有数据",
-        hidden: false
+        hidden: false,
+        meta:{
+          name_en:"Proprietary Data"
+        }
       },  
       {
         path: "bloomberg",
         component: () => import("@/views/dataEntry_manage/thirdBase/bloombergSource.vue"),
         name: "Bloomberg",
-        hidden: false
+        hidden: false,
+        meta:{
+          name_en:"Bloomberg"
+        }
+      },
+      {
+        path: "zczx",
+        component: () => import("@/views/dataEntry_manage/thirdBase/ZczxData.vue"),
+        name: "卓创资讯",
+        meta:{
+          name_en:'Innovusion Infotech'
+        }
+      },
+      {
+        path: "ccfData",
+        component: () => import("@/views/dataEntry_manage/thirdBase/ccfData.vue"),
+        name: "CCF化纤信息",
+        meta:{
+          name_en:'CCF Fiber Info'
+        },
       },
     ],
   },

+ 10 - 0
src/styles/element-ui.scss

@@ -64,3 +64,13 @@ $--font-path: '~element-ui/lib/theme-chalk/fonts';
   max-height: 100vh;
   overflow-y: auto;
 }
+.el-message--error{
+  .el-message__closeBtn{
+    color: $danger-btn-color;
+  }
+}
+.el-message--success{
+  .el-message__closeBtn{
+    color: $--color-success;
+  }
+}

+ 4 - 5
src/styles/global.scss

@@ -137,12 +137,12 @@ button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusri
 .chart-bottom-insruction-info {
     margin-top: 10px;
     display: flex;
-    gap: 0 20px;
     .chart-source {
-        width: 30%;
-        min-width: 150px;
+        /* width: 30%; */
+        flex:auto;
     }
 
+
     .calendar-cont {
         display: block;
         margin: 0 auto;
@@ -151,7 +151,6 @@ button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusri
     }
 
     .chart-instruction {
-        flex: 1;
-        text-align: right;
+        width:30%;
     }
 }

+ 17 - 0
src/utils/buttonConfig.js

@@ -271,6 +271,12 @@ export const dataSourcePermission = {
     Bloomberg_add2edb:'Bloomberg:add2edb',//添加指标库
     /* 自有数据 */
     selfData_addEdb:'selfData:addEdb',//添加到指标库
+    /*--------卓创资讯---- */
+    zczx_showData:'zczx:showData',
+    zczx_exportData:'zczx:exportData',
+    /*--------CCF化纤信息--- */
+    ccfData_view:'ccfData:view',//查看
+    ccfData_exportExcel:'ccfData:exportExcel',//导出
 }
 
 /*
@@ -461,6 +467,16 @@ export const etaTablePermission = {
     etaTable_analysis_del:'etaTable:analysis:del',//删除
     etaTable_analysis_save:'etaTable:analysis:save',//保存
     etaTable_analysis_edit:'etaTable:analysis:edit',//编辑
+
+    // 平衡表
+    etaTable_customize_balance_sheetAdd:'etaTable:customize:balance:sheetAdd',//添加
+    etaTable_customize_balance_del:'etaTable:customize:balance:del',//删除
+    etaTable_customize_balance_download:'etaTable:customize:balance:download',//下载
+    etaTable_customize_balance_otherSave:'etaTable:customize:balance:otherSave',//另存为
+    etaTable_customize_balance_refresh:'etaTable:customize:balance:refresh',//刷新
+    etaTable_customize_balance_edit:'etaTable:customize:balance:edit',//编辑
+    etaTable_customize_balance_classifyOpt_delete:'etaTable:customize:balance:classifyOpt:delete',//删除分类
+    etaTable_customize_balance_classifyOpt_edit:'etaTable:customize:balance:classifyOpt:edit',//添加/编辑分类
 }
 /*
  * --------------------------------------------------------------------------ETA逻辑------------------------------------------------
@@ -762,6 +778,7 @@ export const chartThemePermission = {
     chartTheme_add:'chartTheme:add',//添加
     chartTheme_edit:'chartTheme:edit',//编辑
     chartTheme_del:'chartTheme:del',//删除
+    chartTheme_chartsource:'chartTheme:chartsource',//图表的数据来源
 }
 
 

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

@@ -208,10 +208,10 @@ export default {
                 14: 6
               }
 
-              let FilterSource = (this.$route.path==='/addMixedSheet' && this.$parent.isCalculateDia)
+              let FilterSource = (['/addMixedSheet','/editBalanceSheet'].includes(this.$route.path) && this.$parent.isCalculateDia)
                 ? filterMap[this.$parent.formData.source]||1 
                 : 1;
-              let Frequency = (this.$route.path==='/addMixedSheet' && this.$parent.isCalculateDia && this.$parent.formData.source===2)
+              let Frequency = (['/addMixedSheet','/editBalanceSheet'].includes(this.$route.path) && this.$parent.isCalculateDia && this.$parent.formData.source===2)
                 ? '季度' 
                 : ''
               res = await sheetInterface.searchTarget({

+ 0 - 1
src/views/chartRelevance_manage/crossVarietyAnalysis/list.vue

@@ -132,7 +132,6 @@
                 :span="21"
                 style="padding: 20px 0;"
               >
-                <div class="chartEn-mark" v-show="chartInfo.IsEnChart" style="top: 0;left: 0;">En</div>
                 <div class="chart-show-cont"  v-if="!chartInfo.WarnMsg">
                   <div class="chartWrapper" id="chartWrapper">
                     <h2 class="chart-title">{{ currentLang==='en'?(chartInfo.ChartNameEn||chartInfo.ChartName):chartInfo.ChartName }}</h2>

+ 0 - 1
src/views/chartRelevance_manage/fittingEquation/fittingEquationList.vue

@@ -156,7 +156,6 @@
                 :span="21"
                 style="padding: 20px 0;"
               >
-                <div class="chartEn-mark" v-show="chartInfo.IsEnChart" style="top: 0;left: 0;">En</div>
                 <div class="chart-show-cont"  v-if="!chartInfo.WarnMsg">
                   <div class="chartWrapper" id="chartWrapper">
                     <h2 class="chart-title">{{ currentLang==='en'?(chartInfo.ChartNameEn||chartInfo.ChartName):chartInfo.ChartName }}</h2>

+ 0 - 7
src/views/chartRelevance_manage/relevance/list.vue

@@ -164,13 +164,6 @@
         <div class="chart-detail-wrapper" v-if="chartInfo.ChartInfoId">
           <el-row class="bottom-min">
             <el-col :span="21" style="padding: 20px 0">
-              <div
-                class="chartEn-mark"
-                v-show="chartInfo.IsEnChart"
-                style="top: 0; left: 0"
-              >
-                En
-              </div>
               <div class="chart-show-cont" v-if="!chartInfo.WarnMsg">
                 <div class="chartWrapper" id="chartWrapper">
                   <h2 class="chart-title">

+ 0 - 1
src/views/chartRelevance_manage/statistic/statisticFeatureList.vue

@@ -142,7 +142,6 @@
                 :span="21"
                 style="padding: 20px 0;"
               >
-                <div class="chartEn-mark" v-show="chartInfo.IsEnChart" style="top: 0;left: 0;">En</div>
                 <div class="chart-show-cont"  v-if="!chartInfo.WarnMsg">
                   <div class="chartWrapper" id="chartWrapper">
                     <h2 class="chart-title">{{ currentLang==='en'?(chartInfo.ChartNameEn||chartInfo.ChartName):chartInfo.ChartName }}</h2>

+ 1 - 0
src/views/dataEntry_manage/addChart.vue

@@ -934,6 +934,7 @@ export default {
 	},
   mounted() {
 		this.getMenu();
+		this.getChartBaseSetting()
 		this.getThemeList('init');
 		window.addEventListener('resize', this.reloadRightWid);
 	},

+ 0 - 1
src/views/dataEntry_manage/chartSetting.vue

@@ -391,7 +391,6 @@
                   style="padding-bottom: 30px;"
                 >
                 
-                  <div class="chartEn-mark" v-show="chartInfo.IsEnChart" style="top: 0;left: 0;">En</div>
                   <div class="chart-show-cont"  v-if="!chartInfo.WarnMsg">
                     <div class="chartWrapper" id="chartWrapper">
                       <h2 

+ 3 - 2
src/views/dataEntry_manage/codecount/index.vue

@@ -67,7 +67,8 @@
 									label: 'ClassifyName',
 									value: 'ClassifyId',
 									children: 'Children',
-									checkStrictly: true
+									checkStrictly: true,
+									emitPath: false,
 								}"
 								@change="menuChange"
 								clearable
@@ -359,7 +360,7 @@ export default {
 				EdbName: edb_name,
 				Frequency: frequency,
 				Unit: unit,
-				ClassifyId: menu&&menu[menu.length-1]
+				ClassifyId: menu
 			}
 			
 			const { Ret,Data } = this.$route.query.edbid ? await dataBaseInterface.editCountCode({ ...params,EdbInfoId: Number(this.$route.query.edbid) }) : await dataBaseInterface.addCountCode(params);

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

@@ -259,8 +259,10 @@ 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.colorsOptions[index]||defaultOpts.colors[index]);
+          item.Color = item.Color || (themeOpt &&themeOpt.lineOptionList[index].color || defaultOpts.colors[index]);
         })
       }
       this.cancelDialog()

+ 1 - 1
src/views/dataEntry_manage/components/chartSourceEditDialog.vue

@@ -20,7 +20,7 @@
         <el-form-item :label="$t('Edb.Detail.source')">
           <el-input
             v-model="chartSourceForm.text"
-            :placeholder="$t('Chart.Detail.input_content')"
+            :placeholder="$t('Chart.InputHolderAll.input_content')"
           />
         </el-form-item>
         <el-form-item :label="$t('Chart.Detail.color')" style="margin-bottom:8px;">

+ 82 - 0
src/views/dataEntry_manage/components/edbHasUsedDia.vue

@@ -0,0 +1,82 @@
+<template>
+  <el-dialog
+  :modal-append-to-body='false'
+  :title="$t('Edb.MsgPrompt.del_failed')" 
+  :visible.sync="show"
+  :close-on-click-modal="false"
+  @close="cancelHandle"
+  custom-class="dateDialog"
+  width="650px">
+    <div class="dialog-main">
+      <div class="main-title">
+        <i class="el-icon-error"  style="color: #F56C6C;"></i>
+        <span>{{ $t('Edb.MsgPrompt.del_edb_use_table') }}</span>
+      </div>
+      <div class="main-list">
+        <div class="used-item" v-for="(data,index) in dataList" :key="data.id">
+          <span>{{ index+1 }}、</span><span @click="navigateTo(data.routeUrl)">{{ data.ExcelName }}</span>
+        </div>
+      </div>
+    </div>
+    <div class="dia-bot">
+      <el-button @click="cancelHandle" type="primary" style="width: 120px;"><!-- 知道了 -->{{$t('Dialog.known')}}</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+  export default {
+    name:"",
+    props:{
+      show:{
+        type:Boolean,
+        default:false
+      },
+      dataList:{
+        type:Array,
+        default:()=>[]
+      }
+    },
+    methods:{
+      navigateTo(url){
+        console.log(url);
+        if(!url) return
+        window.open(url, '_blank'); 
+      },
+      cancelHandle(){
+        this.$emit('update:show',false)
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+.main-title{
+  display: flex;
+  align-items: center;
+  font-size: 15px;
+  i{
+    font-size: 20px;
+    margin-right: 10px
+  }
+}
+.main-list{
+  margin: 20px 0 0 30px;
+  max-height: 420px;
+  overflow: auto;
+  .used-item{
+    span{
+      color:#333333 ;
+      cursor: pointer;
+      &:hover{
+        text-decoration: underline
+      }
+    }
+  }
+
+}
+.dia-bot{
+  display: flex;
+  justify-content: flex-end
+}
+</style>

+ 25 - 1
src/views/dataEntry_manage/databaseComponents/dataAssociateChart.vue

@@ -1,10 +1,14 @@
 <template>
     <div class="associate-chart">
         <div v-if="list.length===0&&finished" style="text-align:center;display:block" class="empty-list">
+            <span class="return-btn" @click="()=>{$emit('returnHandle')}">{{$t('Edb.detail_return_btn')}}</span>
             <tableNoData :text="$t('EtaBasePage.no_quote_chart')"/>
         </div>
         <template v-else>
-        <p style="position:relative;font-size:16px">{{$t('Chart.total_chart_show',{limit: chartTotal})}}</p>
+        <p class="associate-chart-title">
+            <span>{{$t('Chart.total_chart_show',{limit: chartTotal})}}</span>
+            <span class="return-btn-tow" @click="()=>{$emit('returnHandle')}">{{$t('Edb.detail_return_btn')}}</span>
+        </p>
         <div
             class="chart-public-list"
             v-infinite-scroll="load"
@@ -203,11 +207,31 @@ export default {
     display: flex;
     flex-direction: column;
 }
+.associate-chart-title{
+    position:relative;
+    font-size:16px;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    .return-btn-tow{
+        color: #409eff;
+        font-size: 14px;
+        cursor: pointer;
+    }
+}
 .empty-list{
     min-height: calc(100vh - 300px);
     background-color: #fff;
     margin-top: -30px;
     padding-top: 100px;
+    position: relative;
+    .return-btn{
+        position: absolute;
+        top: 32px;
+        right: 2px;
+        cursor: pointer;
+        color: #409eff;
+    }
 }
 .chart-public-list{
     flex: 1;

+ 11 - 0
src/views/dataEntry_manage/databaseComponents/dataAssociateComputeData.vue

@@ -1,10 +1,12 @@
 <template>
     <div class="main-box">
+        <p class="return-btn" @click="()=>{$emit('returnHandle')}">{{$t('Edb.detail_return_btn')}}</p>
         <el-table 
             :data="list" 
             ref="tableRef" 
             highlight-current-row 
             border
+            style="margin-top: 18px;"
         >
             <el-table-column
                 v-for="item in tableColums"
@@ -134,5 +136,14 @@ export default {
     padding: 30px;
     height: 100%;
     overflow-y: auto;
+    position: relative;
+    .return-btn{
+        color: #409eff;
+        font-size: 14px;
+        cursor: pointer;
+        position: absolute;
+        right: 16px;
+        top: 12px;
+    }
 }
 </style>

+ 6 - 9
src/views/dataEntry_manage/databaseComponents/edbDetailData.vue

@@ -10,19 +10,16 @@
 				:min-width="item.minwidthsty"
 				align="center">
 				<template slot="header" slot-scope="scope">
-					<div class="chartEn-mark" style="top: -10px;" v-show="scope.$index ==0 && tableData[0] && tableData[0].IsEnEdb" >En</div>
+					<!-- <div class="chartEn-mark" style="top: -10px;" v-show="scope.$index ==0 && tableData[0] && tableData[0].IsEnEdb" >En</div> -->
 					<span>{{item.label}}</span>
 				</template>	
 				<template slot-scope="scope">
-					<template v-if="$i18nt.locale==='zh'">
-						<span>{{ currentLang==='en'?scope.row[item.enKey||item.key] || scope.row[item.key]:scope.row[item.key] }}</span> 
-					</template>
-					<template v-else>
-						<span v-if="item.key==='Frequency'">{{ getFrequencyTrans(scope.row.Frequency||'null') }}</span>
-						<span v-else-if="item.key==='Unit'">{{ getUnitTrans(scope.row.Unit) }}</span>
+
+						<span v-if="item.key === 'Unit'">{{ currentLang === 'en'?scope.row.UnitEn||getUnitTrans(scope.row.Unit):getUnitTrans(scope.row.Unit) }}</span>
+						<span v-else-if="item.key === 'Frequency'">{{ currentLang === 'en' ? scope.row.FrequencyEn||getFrequencyTrans(scope.row.Frequency):getFrequencyTrans(scope.row.Frequency) }}</span>
+						<span v-else-if="item.key === 'EdbName'">{{ currentLang==='en' ? (scope.row.EdbNameEn||scope.row.EdbName) : scope.row.EdbName }}</span>
+
 						<span v-else>{{ scope.row[item.key] }}</span>
-					</template>
-					
 				</template>
 			</el-table-column>
 		</el-table>

+ 4 - 3
src/views/dataEntry_manage/databaseComponents/fittingResidueDia.vue

@@ -228,7 +228,7 @@ export default {
 				this.formData = {
 					date: backData.date.split(','),
 					edb_name: backData.targetName,
-					menu: backData.menu,
+					menu: backData.menu[backData.menu.length-1],
 					frequency: backData.frequency,
 					unit: backData.unit,
 					self_variate: backData.from_arr[0].FromEdbInfoId,
@@ -278,7 +278,8 @@ export default {
 				label: 'ClassifyName',
 				value: 'ClassifyId',
 				children: 'Children',
-				checkStrictly: true
+				checkStrictly: true,
+				emitPath: false,
 			},
 			/* frequencyArr, */
 			fre_options: ['天','周','月','季','年'],
@@ -534,7 +535,7 @@ export default {
 					Source: this.type,
 					EdbName: edb_name,
 					Unit: unit,
-					ClassifyId: menu[menu.length - 1],
+					ClassifyId: menu,
 					Frequency: frequency,
 					Formula: date.join(','),
 					EdbInfoIdArr: [

+ 86 - 19
src/views/dataEntry_manage/databaseList.vue

@@ -143,12 +143,12 @@
 								style="display: flex; align-items: center"
 								v-if="select_node===data.UniqueCode&&data.HaveOperaAuth"
 							>
-								<img
+								<!-- <img
 									src="~@/assets/img/data_m/move_ico.png"
 									alt=""
 									style="width: 14px; height: 14px; margin-right: 8px"
 									v-if="data.Button.MoveButton&&isEdbBtnShow('moveCatalog')"
-								/>
+								/> -->
 								<!-- 添加子项 -->
 								<img
 									src="~@/assets/img/set_m/add.png"
@@ -175,25 +175,25 @@
 									v-if="!data.EdbCode&&(data.Button.DeleteButton)&&isEdbBtnShow('deleteCatalog')"
 								/>
 								<!-- 查看计算指标 -->
-								<i class="el-icon-view" 
+								<!-- <i class="el-icon-view" 
 									v-if="data.EdbType===2&&![58,59,67,68,74].includes(data.Source)&&isEdbBtnShow('checkCalcChart')" 
-									@click.stop="viewNode(node,data)"></i>
+									@click.stop="viewNode(node,data)"></i> -->
 								<!-- 查看关联图表 -->
-								<img 
+								<!-- <img 
 									v-if="data.Button.ShowChartRelation&&isEdbBtnShow('checkRelatedChart')" 
 									@click.stop="showAssociateChart=true,showAssociateComputeData=false"
 									src="~@/assets/img/icons/associate_chart.png" 
 									style="width: 14px; height: 14px;margin-left: 8px"
 									alt=""
-								/>
+								/> -->
 								<!-- 查看关联指标 -->
-								<img 
+								<!-- <img 
 									v-if="data.Button.ShowEdbRelation&&isEdbBtnShow('checkRelatedEdb')" 
 									@click.stop="showAssociateComputeData=true,showAssociateChart=false"
 									src="~@/assets/img/icons/associate_data.png" 
 									style="width: 14px; height: 14px;margin-left: 8px"
 									alt=""
-								/>
+								/> -->
 							</span>
 						</span>
 					</el-tree>
@@ -219,10 +219,10 @@
 			</div>
 			<!-- 指标关联图模块 -->
 			<div class="main-right right" id="right" style="background:transparent;border:none;box-shadow:none" v-if="showAssociateChart">
-				<dataAssociateChart :edbInfoId="selected_edbid"></dataAssociateChart>
+				<dataAssociateChart :edbInfoId="selected_edbid" @returnHandle="showAssociateChart=false,showAssociateComputeData=false"></dataAssociateChart>
 			</div>
 			<div class="main-right right" id="right" style="background:transparent;border:none;box-shadow:none;padding-top: 30px;box-sizing: border-box;" v-if="showAssociateComputeData">
-				<dataAssociateComputeData :edbInfoId="selected_edbid"></dataAssociateComputeData>
+				<dataAssociateComputeData :edbInfoId="selected_edbid" @returnHandle="showAssociateChart=false,showAssociateComputeData=false"></dataAssociateComputeData>
 			</div>
 			<!-- 指标图表列表 -->
 			<div class="main-right right list" id="right" v-show="isShowList">
@@ -316,6 +316,21 @@
 										type="text" 
 										@click="copyCode"
 									>{{$t('Edb.detail_copydata_btn')}}<!-- 复制数据 --></el-button>
+									<el-button 
+									v-if="EdbData.EdbType===2&&![58,59,67,68,74].includes(EdbData.Source)&&isEdbBtnShow('checkCalcChart')" 
+										type="text" 
+										@click.stop="viewNode"
+									>{{$t('Edb.detail_formula_btn')}}<!-- 查看公式 --></el-button>
+									<el-button 
+										v-if="EdbData.Button.ShowChartRelation&&isEdbBtnShow('checkRelatedChart')"
+										type="text" 
+										@click="showAssociateChart=true,showAssociateComputeData=false" 
+									>{{$t('Edb.detail_related_charts_btn')}}<!-- 关联图 --></el-button>
+									<el-button 
+										v-if="EdbData.Button.ShowEdbRelation&&isEdbBtnShow('checkRelatedEdb')" 
+										type="text"
+										@click="showAssociateComputeData=true,showAssociateChart=false"
+									>{{$t('Edb.detail_related_metrics_btn')}}<!-- 关联指标 --></el-button>
 									<el-button 
 										v-if="EdbData.Button.DeleteButton&&isEdbBtnShow('deleteEdb')"
 										type="text" 
@@ -369,7 +384,7 @@
 						<div class="list" v-show="activeTab==='Data'">
 							<edb-detail-data 
 								ref="edb_detail_data"
-								:current-lang="currentLang"
+								:currentLang="currentLang"
 								:table-data="tableData"
 								:table-colums-one="tableColumsOne"
 								:table-colums-two="tableColumsTwo"
@@ -567,6 +582,10 @@
 			@updateLang="updateLang"
 			cType="ebd" 
 		/>
+
+		<!-- 指标已经被引用 -->
+		<edbHasUsedDia :show.sync="edbHasUsedDiaShow" :dataList="hasUsedList"/>
+
 	</div>
 </template>
 
@@ -597,6 +616,7 @@ import edbDetailData from './databaseComponents/edbDetailData.vue';
 import SmoothEdbDialog from './databaseComponents/smoothEdbDialog.vue';
 import batchComputedV2 from './databaseComponents/batchComputedV2.vue';
 import setLangInfoDia from './components/setLangInfo.vue'
+import edbHasUsedDia from './components/edbHasUsedDia.vue';
 export default {
 	name: '',
 	components: {
@@ -622,7 +642,8 @@ export default {
 		edbDetailData,
 		SmoothEdbDialog,
 		batchComputedV2,
-		setLangInfoDia
+		setLangInfoDia,
+		edbHasUsedDia
 	},
 	directives: {
 		drag(el, bindings,vnode) {
@@ -757,7 +778,10 @@ export default {
 			showBatchComputedPop:false,
 
 			/* 修改对应版本信息弹窗  替换原有设置英文*/
-			isLangInfoDia: false
+			isLangInfoDia: false,
+
+			edbHasUsedDiaShow:false,
+			hasUsedList:[]
 		};
 	},
 	watch: {
@@ -1492,15 +1516,23 @@ export default {
 					 * 0 可删除
 					 * 1 关联指标
 					 * 2 有子目录无指标
+					 * 4 当前指标已用作指标运算,不可删除
+					 * 5 当前指标已用作预测指标,不可删除
+					 * 6 当前指标已被表格引用,不可删除
+					 * 7 当前指标已添加到跨品种分析,不可删除
 					*/
 					const deleteLabelMap = {
 						1: /* '该目录关联指标不可删除' */this.$t('Edb.MsgPrompt.del_not_relate_edb'),
 						2: /* '确认删除当前目录及包含的子目录吗?' */this.$t('Edb.MsgPrompt.del_confirm_menu_or_children'),
 						3: /* '当前指标已用作画图,不可删除' */this.$t('Edb.MsgPrompt.del_edb_use_chart'),
-						4: res.Data.TipsMsg
+						4: res.Data.TipsMsg,
+						5: res.Data.TipsMsg,
+						6: res.Data.TipsMsg,
+						7: res.Data.TipsMsg,
 					}
 
-					if([1,3,4].includes(res.Data.DeleteStatus)) this.$confirm(
+					if([1,3,4,5,7].includes(res.Data.DeleteStatus)){
+						this.$confirm(
 							deleteLabelMap[res.Data.DeleteStatus],
 							/* '删除失败' */this.$t('Edb.MsgPrompt.del_failed'),
 							{
@@ -1508,7 +1540,12 @@ export default {
 							showCancelButton:false,
 							type: 'error'
 						})
-					else if([0,2].includes(res.Data.DeleteStatus)) this.$confirm(
+					}else if(res.Data.DeleteStatus == 6){
+						this.edbHasUsedDiaShow=true
+						this.hasUsedList=res.Data.TableList.map(it =>{
+							return {...it,routeUrl:this.getRouteUrl(it)}
+						})
+					}else if([0,2].includes(res.Data.DeleteStatus)) this.$confirm(
 							res.Data.DeleteStatus === 2 
 							? deleteLabelMap[res.Data.DeleteStatus]
 							: data.EdbCode? this.$t('Edb.MsgPrompt.del_edb_confirm')/* '删除后指标和指标值均不可使用,确认删除吗?' */:/* '确定删除当前目录吗?' */this.$t('Edb.MsgPrompt.del_menu_confirm'), 
@@ -1525,6 +1562,36 @@ export default {
 			})
 
 		},
+		getRouteUrl(table){
+			/**
+			 	1 // 自定义excel
+				2 // 时间序列表格
+				3 // 混合表格
+				4 // 自定义分析表格
+				5 // 平衡表
+			 */
+			let url=''
+			switch (table.Source) {
+				case 1:
+					url = this.$router.resolve({ path: '/sheetAnalysisList',query:{code:table.UniqueCode,id:table.ExcelInfoId}}).href;
+					break;
+				case 2:
+					url = this.$router.resolve({ path: '/sheetTimeList',query:{code:table.UniqueCode,id:table.ExcelInfoId}}).href;
+					break;
+				case 3:
+					url = this.$router.resolve({ path: '/sheetMixedList',query:{code:table.UniqueCode,id:table.ExcelInfoId}}).href;
+					break;
+				case 4:
+					url = this.$router.resolve({ path: '/sheetList',query:{code:table.UniqueCode,id:table.ExcelInfoId}}).href;
+					break;
+				case 5:
+					url = this.$router.resolve({ path: '/viewBalanceSheet',query:{id:table.ExcelInfoId}}).href;
+					break;
+				default:
+					break;
+			}
+			return url
+		},
 		/* 删除方法 */
 		delHandle(ClassifyId,EdbInfoId) {
 			dataBaseInterface.nodeDelete({
@@ -1785,7 +1852,7 @@ export default {
 
 		/* 查看计算公式 打开弹窗 */
 		viewNode(node,data) {
-			const { EdbInfoId,Source } = data;
+			const { EdbInfoId,Source } = this.EdbData;
 
 			//代码运算指标
 			if( Source === 27 ) return this.$router.push({
@@ -1801,7 +1868,7 @@ export default {
 			}).then(res => {
 				if(res.Ret !== 200) return
 				this.setComputedDialogForm(Source,res.Data,true);
-				switch (data.Source) {
+				switch (this.EdbData.Source) {
 					case 23: 
 					case 24: 
 						this.computed_type = 'joint';
@@ -1811,7 +1878,7 @@ export default {
 						this.computed_type = 'alpha';
 						break
 					default:
-						this.computed_type = data.Source;
+						this.computed_type = this.EdbData.Source;
 						break
 				}
 			})

+ 1 - 0
src/views/dataEntry_manage/editChart.vue

@@ -1033,6 +1033,7 @@ export default {
 	},
   mounted() {
 		this.getMenu();
+		this.getChartBaseSetting()
 		this.getChartInfo();
 		this.reloadRightWid();
 		window.addEventListener('resize', this.reloadRightWid);

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

@@ -1,6 +1,7 @@
 import { dataBaseInterface } from '@/api/api.js';
 import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
 import * as chartThemeInterface from '@/api/modules/chartThemeApi';
+import {etaBaseConfigInterence} from '@/api/modules/etaBaseConfigApi.js';
 import { defaultOpts } from '@/utils/defaultOptions';
 import { mapState } from 'vuex';
 
@@ -631,14 +632,14 @@ 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.lineOptions.lineType||'spline');
+				item.ChartStyle = item.ChartStyle || (themeOpt&&themeOpt.lineOptionList[index].lineType||'spline');
 				
 				let configLineWid = index===0?3:1;//兼容预测指标绘图无主题配置
-				this.tableData[index].ChartWidth = this.tableData[index].ChartWidth || (themeOpt&&themeOpt.lineOptions.lineWidth||configLineWid);
+				this.tableData[index].ChartWidth = this.tableData[index].ChartWidth || (themeOpt&&themeOpt.lineOptionList[index].lineWidth||configLineWid);
 			})
 		},
 
@@ -703,9 +704,11 @@ export default {
 			this.updateData.splice(index, 1)
 			this.$message.success(this.$t('MsgPrompt.delete_msg'))
 			//删除指标时,检测上下限,修改上下限
-			this.isModifyEdb = true
-			if(this.updateLimit){
-				this.EdbAxisChange()
+			if(![7,10,11].includes(this.chartInfo.ChartType)){
+				this.isModifyEdb = true
+				if(this.updateLimit){
+					this.EdbAxisChange()
+				}
 			}
 			//添加图表时重置默认样式
 			this.$route.path==='/addchart' && this.resetChartEdbDefault();
@@ -968,10 +971,10 @@ export default {
 			this.tableData.forEach((item,index) => {
 				item.ChartColor = themeOpt.colorsOptions[index];
 				item.PredictChartColor = themeOpt.colorsOptions[index];
-				item.ChartStyle = themeOpt.lineOptions.lineType||'spline';
+				item.ChartStyle = themeOpt.lineOptionList[index].lineType||'spline';
 				item.isAxis = item.isAxis||1;
 
-				this.tableData[index].ChartWidth = themeOpt.lineOptions.lineWidth;
+				this.tableData[index].ChartWidth = themeOpt.lineOptionList[index].lineWidth;
 			})
 
 		},
@@ -1073,7 +1076,14 @@ export default {
 				? chartTypeMap[this.chartInfo.ChartType]() 
 				: this.setChartOptionHandle(this.tableData);
 		},
-
+		//获取图表全局设置
+		async getChartBaseSetting(){
+			//目前是用基本配置的接口,后续有多个配置再改
+			const res = await etaBaseConfigInterence.getBaseConfig()
+			if(res.Ret!==200) return 
+			const {ChartSourceDisplay} = res.Data||{}
+			this.chartInfo.SourcesFromVisable = ChartSourceDisplay==='true'?true:false
+		},
 		/* 数据来源显示隐藏 */
 		changeSourceVisable() {
 			this.chartInfo.SourcesFrom = JSON.stringify({

+ 50 - 36
src/views/dataEntry_manage/mixins/chartPublic.js

@@ -480,7 +480,7 @@ export const chartSetMixin = {
         placeholder:/* '请输入图表名称' */this.$t('Chart.InputHolderAll.input_common',{label:this.$t('Chart.Detail.chart_name')})
       })
 
-      if([1,2,5].includes(this.chartInfo.Source)){ //需要设置指标的
+      if([1,2,5,11].includes(this.chartInfo.Source)){ //需要设置指标的
         this.tableData.map(item =>{
             this.formItemArray.chartsList.push([
               {
@@ -731,7 +731,6 @@ export const chartSetMixin = {
 
       /* 主题样式*/
       const chartTheme =  this.chartInfo.ChartThemeStyle ? JSON.parse(this.chartInfo.ChartThemeStyle) : null;
-
       //拼接标题 数据列
       let data = [];
       let ydata = [];
@@ -749,7 +748,7 @@ export const chartSetMixin = {
         const useTableLimit = ['/predictEdb','/addpredictEdb','/editpredictEdb','/chartThemeSet'].includes(this.$route.path)
         //非ETA图库图表也不设置自定义上下限,相关性和统计特征也会用到曲线图
         //若chartInfo.Source为1,需在之前调用setLimitData
-        const isETASource = this.chartInfo.Source===1
+        const isETASource = [1,11].includes(this.chartInfo.Source)
         let minLimit = 0,maxLimit = 0
         if(useTableLimit||!isETASource){
             minLimit = newval[sameSideIndex].MinData
@@ -824,8 +823,8 @@ export const chartSetMixin = {
         //数据列
         let obj = {
           data: [],
-          type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
-          dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
           yAxis: sameSideIndex,
           name:
             dynamic_arr.length > 1
@@ -836,7 +835,13 @@ 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.lineOptions.lineWidth),
+          lineWidth: Number(item.ChartWidth)||(chartTheme&&chartTheme.lineOptionList[index].lineWidth),
+          marker: chartTheme && chartTheme.lineOptionList[index].dataMark && chartTheme.lineOptionList[index].dataMark!='none'?{
+            enabled:true,
+            symbol: chartTheme.lineOptionList[index].markType || 'circle',
+            fillColor:chartTheme.lineOptionList[index].markColor,
+            radius: chartTheme.lineOptionList[index].markSize
+          }:{},
           ...predict_params
         };
         item.DataList = item.DataList || [];
@@ -1034,7 +1039,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.lineOptions.lineWidth),
+          lineWidth: Number(item.ChartWidth)||(chartTheme&&chartTheme.lineOptionList[index].lineWidth),
           fillColor: (this.chartInfo.ChartType === 3 || (this.chartInfo.ChartType === 6 && item.ChartStyle === 'areaspline')) ? item.ChartColor : undefined,
           borderWidth: 1,
           borderColor: item.ChartColor,
@@ -1090,16 +1095,17 @@ export const chartSetMixin = {
       const chartDataHandle=this.calendar_type === '农历'?
                             this.isPredictorChart?chartData.DataList.List.filter((item, index) => index > 0):
                             chartData.DataList.filter((item, index) => index > 0):
-                            chartData.DataList
-       /* 主题样式*/
-       const chartTheme =  this.chartInfo.ChartThemeStyle ? JSON.parse(this.chartInfo.ChartThemeStyle) : null;
-
+                            chartData.DataList||[]
+      /* 主题样式*/
+      const chartTheme =  this.chartInfo.ChartThemeStyle ? JSON.parse(this.chartInfo.ChartThemeStyle) : null;
+      // 跟颜色对应
+      chartTheme.lineOptionList=chartTheme.lineOptionList.reverse().slice(-chartDataHandle.length)
       let seasonYdata = [],
         seasonData = [];
 
         //获取对应轴的上下限
         //预测指标-走势图;图表配置-主题设置;不使用自定义上下限,剔除
-        const useTableLimit = ['/predictEdb','/chartThemeSet','/addpredictEdb','/editpredictEdb'].includes(this.$route.path)
+        const useTableLimit = ['/predictEdb','/chartThemeSet','/addpredictEdb','/editpredictEdb','/viewBalanceSheet','/editBalanceSheet'].includes(this.$route.path)
         let minLimit = 0,maxLimit = 0
         if(useTableLimit){
             minLimit = chartData.MinData
@@ -1110,17 +1116,25 @@ export const chartSetMixin = {
         }
 
       //数据列
-      for (let j of chartDataHandle) {
+      for (let index in chartDataHandle) {
+        let j = chartDataHandle[index]
+        // console.log(j,index);
         //预测指标配置
         let predict_params =  chartData.EdbInfoCategoryType === 1 ? this.getSeasonPredictParams(j.CuttingDataTimestamp) : {};
-        
+
         let serie_item = {
           data: [],
-          type: (chartTheme&&chartTheme.lineOptions.lineType) || chartData.ChartStyle,
-          dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || chartData.ChartStyle,
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
           yAxis: 0,
           name: this.isPredictorChart?j.Year:j.ChartLegend,
-          lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 1,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 1,
+          marker: chartTheme && chartTheme.lineOptionList[index].dataMark && chartTheme.lineOptionList[index].dataMark!='none'?{
+            enabled:true,
+            symbol: chartTheme.lineOptionList[index].markType || 'circle',
+            fillColor:chartTheme.lineOptionList[index].markColor,
+            radius: chartTheme.lineOptionList[index].markSize
+          }:{},
           ...predict_params
         };
         const data_array = this.calendar_type === '农历' && this.isPredictorChart?_.cloneDeep(j.Items):_.cloneDeep(j.DataList);
@@ -1234,7 +1248,7 @@ export const chartSetMixin = {
             enabled: false,
           };
 
-
+          console.log('季节图配置');
       this.options = {
         colors: colors.slice(-chartDataHandle.length),
         series: seasonData,
@@ -1415,7 +1429,7 @@ export const chartSetMixin = {
         color: ChartColor,
         chartType: 'linear',
         marker: {
-          radius: (chartTheme&&chartTheme.lineOptions.radius)||5,
+          radius: (chartTheme&&chartTheme.lineOptionList[0].radius)||5,
         },
       }
       real_data.forEach(_ => {
@@ -1586,22 +1600,22 @@ export const chartSetMixin = {
       }
 
       //数据列
-      data.forEach(item => {
+      data.forEach((item,index) => {
         //处理首或/尾全是无效数据的以null填充
         let filterData = this.filterInvalidData(item)
         // console.log(filterData)
       
         let serie_item = {
           data: filterData,
-          type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
-          dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
           yAxis: 0,
           name: item.Name,
           nameCh: item.Name,
           nameEn: item.NameEn,
           color: item.Color,
           chartType: 'linear',
-          lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 3,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 3,
           marker: {
             enabled: false
           }
@@ -1826,18 +1840,18 @@ export const chartSetMixin = {
 
       //处理series
       let seriesData=[]
-      this.relevanceChartData.YDataList.forEach(item=>{
+      this.relevanceChartData.YDataList.forEach((item,index)=>{
         let serie_item = {
           data: item.Value,
-          type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
-          dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
           yAxis: 0,
           name: item.Name,
           nameCh: item.Name,
           nameEn: item.NameEn,
           color: item.Color,
           chartType: 'linear',
-          lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 3,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 3,
           marker: {
             enabled: false
           }
@@ -1951,7 +1965,7 @@ export const chartSetMixin = {
 
       //数据列
       let series = [];
-      DataList.forEach(item => {
+      DataList.forEach((item,index) => {
         //数据列
         let series_item = {
           data: [],
@@ -1963,7 +1977,7 @@ export const chartSetMixin = {
           chartType: 'linear',
           zIndex:1,
           marker: {
-            radius: (chartTheme&&chartTheme.lineOptions.radius)||5,
+            radius: (chartTheme&&chartTheme.lineOptionList[index].radius)||5,
           },
         }
         item.EdbInfoList.forEach(_ => {
@@ -2157,18 +2171,18 @@ export const chartSetMixin = {
 
       //系列
       let series = [];
-      YDataList.forEach(item => {
+      YDataList.forEach((item,index) => {
         let serie_item = {
           data: item.Value,
           pointPlacement: 'on',
-          type: (chartTheme&&chartTheme.lineOptions.lineType) || 'line',
-          dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'line',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
           yAxis: 0,
           name: item.Name || item.Date,
           nameCh: item.Name || item.Date,
           nameEn: item.Date,
           color: item.Color,
-          lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 1,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 1,
           chartType: 'linear'
         };
         series.push(serie_item)
@@ -2246,14 +2260,14 @@ export const chartSetMixin = {
 
         let series_item = {
           data: item.Value.map(_ =>[_.X,_.Y]),
-          dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
-          type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
           yAxis: index,
           name: item.Name,
           nameCh: item.Name,
           nameEn: item.NameEn||item.Name,
           color: item.Color,
-          lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth)||3,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth)||3,
           chartType: 'linear',
           zIndex:1
         }

+ 299 - 0
src/views/dataEntry_manage/thirdBase/ZczxData.vue

@@ -0,0 +1,299 @@
+<template>
+  <div class="zczx-container coal-similarity-container" v-if="isShowData">
+    <span
+        class="slide-btn-icon"
+        :class="{'slide-left':isLeftWrapShow,'slide-right':!isLeftWrapShow}"
+        @click="isLeftWrapShow = !isLeftWrapShow"
+    >
+        <i :class="{'el-icon-d-arrow-left':isLeftWrapShow,'el-icon-d-arrow-right':!isLeftWrapShow}"></i>
+    </span>
+    <div class="left-cont minHeight" v-show="isLeftWrapShow">
+      <div class="left-top">
+        <el-button
+          v-permission="permissionBtn.dataSourcePermission.zczx_exportData"
+          style="width: 100%;"
+          type="primary"
+          plain
+          size="medium"
+          @click="exportClick"
+          :loading="btnload"
+          ><!-- 导出Excel -->{{$t('Common.exp_excel')}}</el-button
+        >
+        <el-autocomplete
+          style="margin-top: 20px; width: 100%"
+          prefix-icon="el-icon-search"
+          v-model="leftSearchVal"
+          :fetch-suggestions="handleLeftSearch"
+          :trigger-on-focus="false"
+          :placeholder="$t('Edb.InputHolderAll.input_name_orid')"
+          @select="handleSelectLeftSearchval"
+          popper-class="el-autocomplete-suggestion-data-entry"
+          @clear="clearSearchVal"
+          clearable
+        >
+          <template slot-scope="scope">
+            <div v-if="scope.item.nodata" style="text-align: center">
+              <!-- 暂无数据 -->{{$t('Table.prompt_slogan')}}
+            </div>
+            <div v-else>
+              {{ scope.item.IndexName }}
+            </div>
+          </template>
+        </el-autocomplete>
+      </div>
+      <ul class="classify-list">
+        <li
+          :class="['classify-item', { act: select_classify === item.BaseFromSciClassifyId }]"
+          v-for="item in classifyList"
+          :key="item.BaseFromSciClassifyId"
+          @click="changeClassify(item)"
+        >
+          {{ item.ClassifyName }}
+        </li>
+      </ul>
+    </div>
+    <div
+      class="right-cont minHeight"
+      v-loading="dataloading"
+      :element-loading-text="$t('Table.data_loading')"
+    >
+      <div class="right-box" v-if="rightShow" @scroll="scrollHandle">
+        <template v-if="dateArr.length">
+          <div class="data-header">
+            <lz-table
+              :tableOption="tableOption"
+              tableType="header"
+              ref="table"
+              source="icpi"
+            />
+          </div>
+          <div class="data-cont">
+            <lz-table
+              :tableOption="tableOption"
+              tableType="data"
+              :dateArr="dateArr"
+              source="icpi"
+            />
+          </div>
+        </template>
+        <tableNoData v-else :text="$t('Table.prompt_slogan')" class="nodata"></tableNoData>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import lzTable from "@/components/lzTable.vue";
+import { zczxInterface } from "@/api/api.js";
+
+export default {
+  name: "ZczxData",
+  components: { lzTable },
+  data() {
+    return {
+      isLeftWrapShow:true,
+      dataloading: false,
+      rightShow: false,
+      exportBase: process.env.VUE_APP_API_ROOT + "/data_source/sci99/export/sci99DataList", //数据导出接口
+      select_classify: "",
+      classifyList: [],
+      tableOption: [],
+      dateArr: [], //最长的日期数组
+      btnload: false,
+
+      leftSearchVal: "", //左侧搜索值
+      pageParams:{
+        PageSize:20,
+        CurrentIndex:1,
+        KeyWord:''
+      },
+      havemore:true
+    };
+  },
+  computed: {
+    exportIcpiApi() {
+      // 数据导出接口
+      let urlStr = this.exportBase;
+      // token
+      urlStr += `?${localStorage.getItem("auth") || ""}`;
+      // 分类Id参数
+      urlStr += `&ClassifyId=${this.select_classify}`;
+      urlStr += `&KeyWord=${this.pageParams.KeyWord}`;
+      return this.escapeStr(urlStr);
+    },
+    //是否有查看权限
+    isShowData(){
+      return this.permissionBtn.isShowBtn('dataSourcePermission','zczx_showData')
+    },
+  },
+  created() {
+    if(!this.isShowData) return
+    this.getClassify();
+  },
+  methods: {
+    /* 获取分类 */
+    getClassify() {
+      zczxInterface.classifyList().then((res) => {
+        if (res.Ret !== 200) return;
+        this.classifyList = res.Data || [];
+        this.select_classify =
+          this.select_classify || this.classifyList[0].BaseFromSciClassifyId;
+        
+        this.getDataList()
+      });
+    },
+
+    /* 获取数据 */
+    getDataList() {
+      this.dataloading = true;
+      zczxInterface.dataList({
+        ClassifyId: Number(this.select_classify),
+        PageSize:this.pageParams.PageSize,
+        CurrentIndex:this.pageParams.CurrentIndex,
+        KeyWord:this.pageParams.KeyWord
+      }).then((res) => {
+        this.rightShow = true;
+        if (res.Ret !== 200) return;
+
+        // 找出最多的页码 判断是否还有数据
+        let page_arrs = res.Data.map((item) => item.Paging?item.Paging.Pages:0);
+        let totalPage = Math.max.apply(Math, page_arrs);
+        this.havemore = this.pageParams.CurrentIndex < totalPage ? true : false;
+        
+        // 设置表格数据
+        this.setDataList(res.Data);
+        this.pageParams.CurrentIndex === 1 &&
+          this.$nextTick(() => {
+            this.initWidth();
+          });
+      }).finally(()=>{
+        this.dataloading = false;
+      })
+    },
+    /* 改变品种 */
+    changeClassify(item) {
+      this.select_classify = item.BaseFromSciClassifyId;
+      this.leftSearchVal = ""
+      this.pageParams.KeyWord=''
+      this.pageParams.CurrentIndex=1
+      this.getDataList()
+    },
+
+    initWidth() {
+      $(".right-box")[0].style.width =
+      this.$refs.table ? this.$refs.table.$el.clientWidth + 2 + "px":'0';
+      $(".right-box")[0].scrollTop = 0;
+      $(".right-box")[0].scrollLeft = 0;
+    },
+    // 对[#,;]转义
+    escapeStr(str) {
+      return str.replace(/#/g, escape("#")).replace(/;/g, escape(";")); 
+    },
+    /* 导出 */
+    exportClick() {
+      this.btnload = true;
+      const link = document.createElement("a");
+      link.href = this.exportIcpiApi;
+      link.download = "";
+      link.click();
+      setTimeout(() => {
+        this.btnload = false;
+      }, 2000);
+    },
+
+    //左侧搜索
+    async handleLeftSearch(query, cb) {
+      cb([]);
+      if (!query) return;
+      const res = await zczxInterface.dataList({
+        KeyWord: query
+      });
+      if (res.Ret === 200) {
+        let arr = res.Data || [];
+        if (!arr.length) {
+          cb([{ nodata: true }]);
+        } else {
+          cb(arr);
+        }
+      }
+    },
+    // 选中左侧搜索值
+    handleSelectLeftSearchval(e) {
+      if (!e.BaseFromSciIndexId) return;
+      this.rightShow = false;
+      this.leftSearchVal = e.IndexName;
+      this.pageParams.KeyWord=e.IndexName
+      this.select_classify = e.ClassifyId;
+      this.pageParams.CurrentIndex=1
+      this.getDataList()
+      this.$nextTick(() => {
+        this.rightShow = true;
+        this.handleScrollLeftWrap();
+      });
+    },
+    clearSearchVal(){
+      this.pageParams.KeyWord=''
+      this.getDataList()
+    },
+    // 左侧滚动
+    handleScrollLeftWrap() {
+      let top = $(".act")[0].offsetTop;
+      $(".classify-list").animate({
+        scrollTop: top - 200,
+      });
+    },
+    /* 滚动加载 */
+    scrollHandle(e) {
+      const dom = e.target;
+      let total = dom.scrollTop + dom.clientHeight;
+      if (total >= dom.scrollHeight && this.havemore) {
+        this.pageParams.CurrentIndex++;
+        // console.log("load下一页");
+        this.getDataList();
+      }
+    },
+    // 设置表格数据
+    setDataList(data) {
+      if(this.pageParams.CurrentIndex==1){
+        this.tableOption = data;
+        /* 不满7个追加7个空的显示一排 别问 问就是为了美观  */
+        if (this.tableOption.length < 7){
+          for (let i = 0; i < 7; i++) {
+            this.tableOption.push({
+              DataList: [],
+            });
+            if (this.tableOption.length >= 7) break;
+          }
+        }
+      }else{
+        this.tableOption.forEach((item) => {
+          data.forEach((_item) => {
+            if (item.IndexCode === _item.IndexCode) {
+              item.DataList = item.DataList.concat(_item.DataList);
+            }
+          });
+        });
+      }
+
+      // 合并所有日期
+      let arr = this.tableOption.map((item) => item.DataList);
+      let obj = [];
+      arr.forEach((dataList) => {
+        obj.push(...dataList.map((item) => item.DataTime));
+      });
+      // 日期去重倒序排序
+      this.dateArr = [...new Set(obj)].sort().reverse();
+      //数据最大长度小于13个 追加数据满13个 别问 问就是为了美观
+      if (this.dateArr.length < 13){
+        for (let i = 0; i < 13; i++) {
+          this.dateArr.push("");
+          if (this.dateArr.length >= 13) break;
+        }
+      }
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+@import "../css/coalCommon.scss";
+</style>

+ 3 - 3
src/views/dataEntry_manage/thirdBase/bloombergSource.vue

@@ -124,13 +124,13 @@
                             </el-form-item>
                             <el-form-item :prop="`list[${index}].Unit`" :rules="{required:true,message:$t('Edb.InputHolderAll.input_unit'),trigger: 'blur'}">
                                 <el-input v-model="item.Unit"
-                                    :placeholder="$t('Edb.InputHolderAll.input_fre')">
+                                    :placeholder="$t('Edb.InputHolderAll.input_unit')">
                                 </el-input>
                             </el-form-item>
                             <el-form-item :prop="`list[${index}].Frequency`" :rules="{required:true,message:$t('Edb.InputHolderAll.input_fre'),trigger: 'blur'}">
                                 <el-select v-model="item.Frequency" :placeholder="$t('Edb.InputHolderAll.input_fre')" >
-                                    <el-option v-for="i in frequencyList" :key="i"
-                                            :label="i" :value="i"
+                                    <el-option v-for="i in frequencyList" :key="i.label"
+                                            :label="i.label" :value="i.value"
                                         />
                                 </el-select>
                             </el-form-item>

+ 513 - 0
src/views/dataEntry_manage/thirdBase/ccfData.vue

@@ -0,0 +1,513 @@
+<template>
+  <div class="CCF-container target-container" id="box" v-if="canView">
+    <span
+        v-show="!isLeftWrapShow"
+        class="slide-btn-icon slide-right"
+        @click="isLeftWrapShow = !isLeftWrapShow"
+    >
+        <i :class="{'el-icon-d-arrow-left':isLeftWrapShow,'el-icon-d-arrow-right':!isLeftWrapShow}"></i>
+    </span>
+    <div class="left-cont minHeight" id="left" v-show="isLeftWrapShow">
+        <span
+            v-show="isLeftWrapShow"
+            class="slide-btn-icon slide-left"
+            @click="isLeftWrapShow = !isLeftWrapShow"
+        >
+            <i :class="{'el-icon-d-arrow-left':isLeftWrapShow,'el-icon-d-arrow-right':!isLeftWrapShow}"></i>
+        </span>
+      <div class="left-top">
+        <el-button
+          v-permission="permissionBtn.dataSourcePermission.ccfData_exportExcel"
+          style="width: 100%"
+          type="primary"
+          plain
+          size="medium"
+          @click="exportClick"
+          :loading="btnload"
+          :disabled="!select_classify&&!leftSearchTradeCode"
+          ><!-- 导出Excel -->{{$t('Common.exp_excel')}}</el-button
+        >
+        <el-autocomplete
+          style="margin: 20px 0; width: 100%"
+          prefix-icon="el-icon-search"
+          v-model="leftSearchVal"
+          :fetch-suggestions="handleLeftSearch"
+          :trigger-on-focus="false"
+          :placeholder="$t('Edb.InputHolderAll.input_name_orid')"
+          @select="handleSelectLeftSearchval"
+          popper-class="el-autocomplete-suggestion-data-entry"
+          clearable
+          @clear="clearSearch"
+        >
+          <template slot-scope="scope">
+            <div v-if="scope.item.nodata" style="text-align: center">
+              <!-- 暂无数据 -->{{$t('Table.prompt_slogan')}}
+            </div>
+            <div v-else>
+              {{ scope.item.IndexName }}
+            </div>
+          </template>
+        </el-autocomplete>
+      </div>
+      <div class="scroll-wrap">
+        <el-tree
+          ref="treeRef"
+          class="target_tree word-wrap"
+          :data="classifyList"
+          node-key="ClassifyId"
+          :props="{
+            label: 'ClassifyName',
+            children: 'Child',
+          }"
+          :current-node-key="select_classify"
+          check-strictly
+          highlight-current
+          :default-expanded-keys="defaultShowNodes"
+          @node-expand="handleNodeExpand"
+          @node-collapse="handleNodeCollapse"
+          :empty-text="$t('Common.no_classify_msg')"
+          @current-change="nodeChangeHandle"
+        >
+        </el-tree>
+      </div>
+      <span
+        class="move-btn resize"
+        v-drag
+        id="resize"
+      >
+      </span>
+    </div>
+    <div
+      class="right-cont minHeight"
+      id="right"
+      v-loading="dataloading"
+      :element-loading-text="$t('Table.data_loading')"
+    >
+      <template v-if="rightShow">
+        <div class="right-box" @scroll="scrollHandle">
+          <div class="data-header">
+            <lz-table
+              :tableOption="tableOption"
+              tableType="header"
+              ref="table"
+              source="ccf"
+            />
+          </div>
+          <div class="data-cont" v-if="dateArr.length">
+            <lz-table
+              :tableOption="tableOption"
+              tableType="data"
+              :dateArr="dateArr"
+              source="ccf"
+            />
+          </div>
+        </div>
+      </template>
+      <div v-else class="nodata-cont">
+        <tableNoData :text="$t('Table.prompt_slogan')"/>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import lzTable from "@/components/lzTable.vue";
+import { ccfDataInterface } from "@/api/api.js";
+export default {
+  name: "ccfData",
+  components: { lzTable },
+  directives: {
+    drag(el, bindings) {
+      el.onmousedown = function (e) {
+        var init = e.clientX;
+        // console.log(init);
+        var box = $('#box')[0];
+        // console.log(box.clientWidth)
+        let total_wid = box.offsetWidth;
+        var left = $('#left')[0];
+        var right = $('#right')[0];
+        var initWidth = left.offsetWidth;
+        document.onmousemove = function (e) {
+          var end = e.clientX;
+          var newWidth = end - init + initWidth;
+          left.style.width = newWidth + 'px';
+          right.style.width = newWidth > 320 ? total_wid - newWidth + 'px' : total_wid - 320 + 'px';
+        };
+        document.onmouseup = function () {
+          document.onmousemove = document.onmouseup = null;
+          e.releaseCapture && e.releaseCapture();
+        };
+        e.setCapture && e.setCapture();
+        return false;
+      };
+    }
+  }, 
+  data() {
+    return {
+      isLeftWrapShow:true,
+      exportBase:process.env.VUE_APP_API_ROOT + "/datamanage/ccf/export", //CCF数据导出接口
+      dataloading: false,
+      rightShow: false,
+      select_classify: 0,
+      classifyList: [],
+      tableOption: [],
+      dateArr: [], //最长的日期数组
+      btnload: false,
+      page_no: 1,
+      page_size: 20,
+      havemore: true, //是否还有数据
+
+      leftSearchVal: "", //左侧搜索值
+      leftSearchTradeCode: "", //如果是搜索选择的 则有此code
+      isShowSingleData: false, //右侧是否展示的是单个指标数据
+      defaultShowNodes: [], //展开的节点
+    };
+  },
+  methods: {
+    /* 获取分类 */
+    getClassify() {
+      ccfDataInterface.classifyList().then((res) => {
+        if (res.Ret !== 200) return;
+        this.classifyList = res.Data || [];
+        this.select_classify = this.classifyList[0].Child[0].ClassifyId
+        this.getDataList();
+        this.$nextTick(()=>{
+          this.orientationNode(this.select_classify)
+        })
+      });
+    },
+    /* 获取数据 */
+    getDataList: _.throttle(function () {
+      this.isShowSingleData = false;
+      this.dataloading = true;
+      ccfDataInterface
+        .dataList({
+          ClassifyId: this.select_classify,
+          PageSize: this.page_size,
+          CurrentIndex: this.page_no,
+        })
+        .then((res) => {
+          this.rightShow = true;
+          if (res.Ret !== 200) return;
+
+          // 找出最多的页码 判断是否还有数据
+          let page_arrs = res.Data.map((item) => item.Paging.Pages);
+          let totalPage = Math.max.apply(Math, page_arrs);
+          this.havemore = this.page_no < totalPage ? true : false;
+
+          // 合并数据
+          if (this.page_no === 1) {
+            this.tableOption = res.Data;
+          } else {
+            this.tableOption.forEach((item) => {
+              res.Data.forEach((_item) => {
+                if (item.IndexCode === _item.IndexCode) {
+                  item.DataList = item.DataList.concat(_item.DataList);
+                }
+              });
+            });
+          }
+
+          // 合并所有指标中的日期 作为日期数组
+          let arr = res.Data.map((item) => {
+            return item.DataList;
+          });
+
+          let obj = [];
+          for (let i of arr) {
+            for (let j of i) {
+              obj.push(j.DataTime);
+            }
+          }
+          let arr2 = [...new Set(obj)].sort().reverse();
+          let concatArr = [...new Set([...this.dateArr, ...arr2])]
+            .sort()
+            .reverse();
+          this.dateArr = this.page_no === 1 ? arr2 : concatArr;
+
+          /* 不满6个追加6个空的显示一排 别问 问就是为了美观  */
+          if (this.tableOption.length < 7)
+            for (let i = 0; i < 7; i++) {
+              this.tableOption.push({
+                DataList: [],
+              });
+              if (this.tableOption.length >= 7) break;
+            }
+
+          //数据最大长度小于12个 追加数据满12个 别问 问就是为了美观
+          if (this.dateArr.length < 12)
+            for (let i = 0; i < 12; i++) {
+              this.dateArr.push("");
+              if (this.dateArr.length >= 12) break;
+            }
+
+          this.dataloading = false;
+          this.page_no === 1 &&
+            this.$nextTick(() => {
+              this.rightShow && this.initWidth();
+            });
+        });
+    }, 200),
+    // 获取单个指标数据
+    async getTargetDataList(code) {
+      this.isShowSingleData = true;
+      this.dataloading = true;
+      try {
+        const res = await ccfDataInterface.getTargetDataList({
+          IndexCode: code,
+        });
+        this.rightShow = true;
+        if (res.Ret !== 200) return;
+        const DataList = res.Data.Data || [];
+        // 合并数据
+        this.tableOption = [
+          {
+            DataList: DataList,
+            ...res.Data,
+          },
+        ];
+        this.orientationNode(res.Data ? res.Data.ClassifyId:-1)
+        // 这里是单个指标所以不用合并日期
+        const arr = DataList.map((item) => item.DataTime);
+        this.dateArr = [...new Set(arr)].sort().reverse();
+        /* 不满6个追加6个空的显示一排 别问 问就是为了美观  */
+        for (let i = 0; i < 7; i++) {
+          this.tableOption.push({
+            DataList: [],
+          });
+          if (this.tableOption.length >= 7) break;
+        }
+        //数据最大长度小于12个 追加数据满12个 别问 问就是为了美观
+        if (this.dateArr.length < 12)
+          for (let i = 0; i < 12; i++) {
+            this.dateArr.push("");
+            if (this.dateArr.length >= 12) break;
+          }
+        this.dataloading = false;
+        this.rightShow && this.initWidth();
+      } catch (err) {
+        console.log(err);
+      }
+    },
+    // 左侧目录定位
+    orientationNode(Id){
+      this.select_classify = Id;
+      this.defaultShowNodes.push(Id)
+      this.$refs.treeRef.setCurrentKey(Id);
+      this.$nextTick(() => {
+        setTimeout(()=>{
+          let parent = document.getElementsByClassName('scroll-wrap')[0]
+          let node = parent.querySelector('.is-current')
+          parent.scrollTo({
+            top: node.offsetTop-200
+          })
+        },300)
+      })
+    },
+    // 树节点展开
+    handleNodeExpand(data) {
+      // 保存当前展开的节点
+      let flag = this.defaultShowNodes.some((item) => item === data.ClassifyId);
+
+      if (!flag) {
+        // 不存在则存到数组里
+        this.defaultShowNodes.push(data.ClassifyId);
+      }
+    },
+
+    // 树节点关闭
+    handleNodeCollapse(data) {
+      let shouldCollapseIds=data.Child ? [...data.Child.map(it => it.ClassifyId),data.ClassifyId] : [data.ClassifyId]
+
+      this.defaultShowNodes = this.defaultShowNodes.filter(it =>{
+        return !shouldCollapseIds.includes(it)
+      })
+    },
+    initWidth() {
+      this.$nextTick(() => {
+        $(".right-box")[0].style.width =
+          this.$refs.table.$el.clientWidth + 5 + "px";
+        $(".right-box")[0].scrollTop = 0;
+        $(".right-box")[0].scrollLeft = 0;
+      });
+    },
+    /* 无频度的异常显示处理 7*12*/
+    nodataDeal() {
+      this.tableOption = [];
+      this.dateArr = [];
+      for (let i = 0; i < 7; i++) {
+        this.tableOption.push({
+          DataList: [],
+        });
+        if (this.tableOption.length >= 7) break;
+      }
+      for (let i = 0; i < 12; i++) {
+        this.dateArr.push("");
+        if (this.dateArr.length >= 12) break;
+      }
+    },
+    /* 滚动加载 */
+    scrollHandle(e) {
+      if (this.isShowSingleData) return;
+      const dom = e.target;
+      let total = dom.scrollTop + dom.clientHeight;
+      if (total >= dom.scrollHeight && this.havemore) {
+        this.page_no++;
+        console.log("load下一页");
+        this.getDataList();
+      }
+    },
+    /* 数据导出 */
+    exportClick() {
+      this.btnload = true;
+      const link = document.createElement("a");
+      link.href = this.exportDataUrl;
+      link.download = "";
+      link.click();
+      setTimeout(() => {
+        this.btnload = false;
+      }, 5000);
+    },
+    //左侧搜索
+    async handleLeftSearch(query, cb) {
+      cb([]);
+      if (!query) return;
+      const res = await ccfDataInterface.getTargetListByName({
+        Keyword: query,
+      });
+      if (res.Ret === 200) {
+        let arr = res.Data || [];
+        if (!arr.length) {
+          cb([{ nodata: true }]);
+        } else {
+          cb(arr);
+        }
+      }
+    },
+    // 选中左侧搜索值
+    handleSelectLeftSearchval(e) {
+      if (!e.IndexCode) return;
+      this.leftSearchTradeCode = e.IndexCode;
+      this.leftSearchVal = e.IndexName;
+
+      // 获取单独指标数据
+      this.getTargetDataList(e.IndexCode);
+    },
+    // 对[#,;]转义
+    escapeStr(str) {
+      return str.replace(/#/g, escape("#")).replace(/;/g, escape(";")); 
+    },
+  
+    //改变选中节点
+    nodeChangeHandle(data, node) {
+      if (data.Level==1) return;
+      this.select_classify = data.ClassifyId;
+      this.leftSearchVal=''
+      this.page_no = 1;
+      this.page_size = 20;
+      this.getDataList()
+    },
+    clearSearch(){
+      this.page_no=1
+      this.leftSearchTradeCode=''
+      this.getDataList();
+    }
+  },
+  computed: {
+    exportDataUrl() {
+      // 数据导出接口
+      let urlStr = this.exportBase;
+      // token
+      urlStr += `?${localStorage.getItem("auth") || ""}`;
+      if (this.isShowSingleData) {
+        // 指标id
+        urlStr += `&IndexCode=${
+          this.isShowSingleData ? this.leftSearchTradeCode : ""
+        }`;
+      } else {
+        // 目录id
+        urlStr += `&ClassifyId=${
+          this.isShowSingleData ? "" : this.select_classify
+        }`;
+      }
+      return this.escapeStr(urlStr);
+    },
+    canView(){
+      return this.permissionBtn.isShowBtn('dataSourcePermission','ccfData_view')
+    }
+  },
+  mounted() {
+    this.canView && this.getClassify();
+  },
+};
+</script>
+<style lang="scss" scoped>
+@import "../css/customtree.scss";
+@import "../css/baseTargetPage.scss";
+.CCF-container {
+  display: flex;
+  * {
+    box-sizing: border-box;
+  }
+  .minHeight {
+    height: calc(100vh - 120px);
+    background-color: #fff;
+    box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.05);
+    border-radius: 4px;
+  }
+  .left-cont {
+    min-width: 300px;
+    width: 300px;
+    margin-right: 20px;
+    padding: 30px 0;
+    overflow: hidden;
+    position: relative;
+    .left-top {
+      padding: 0 20px;
+    }
+    .scroll-wrap {
+      padding: 0 20px;
+      height: calc(100vh - 280px);
+      overflow-y: auto;
+      margin-right: 20px;
+      .target_tree {
+        color: #333;
+      }
+    }
+    .move-btn {
+      height: 100%;
+      width: 4px;
+      position: absolute;
+      right: 0px;
+      top: 0;
+      &:hover {
+        cursor: col-resize;
+      }
+    }
+  }
+  .right-cont {
+    width: 82%;
+    padding: 30px;
+    .right-box {
+      max-width: 100%;
+      max-height: calc(100vh - 180px);
+      border-left: 1px solid #dcdfe6;
+      border-right: 1px solid #dcdfe6;
+      overflow: auto;
+      .data-header {
+        width: 100%;
+        position: sticky;
+        top: 0;
+        z-index: 2;
+      }
+    }
+    .nodata-cont {
+      width: 200px !important;
+      text-align: center;
+      color: #666;
+      font-size: 16px;
+      margin: 0 auto;
+    }
+  }
+}
+</style>

+ 1 - 1
src/views/dataEntry_manage/thirdBase/icpiConsumption.vue

@@ -157,7 +157,7 @@ export default {
         
         // 设置表格数据
         this.setDataList(res.Data);
-        this.CurrentIndex === 1 &&
+        this.pageParams.CurrentIndex === 1 &&
           this.$nextTick(() => {
             this.initWidth();
           });

+ 5 - 1
src/views/dataEntry_manage/thirdBase/selfDataBase.vue

@@ -96,6 +96,10 @@
                 </span>
               </template>
 
+              <template v-else-if="item.key==='IndexName'">
+                <span style="white-space: pre-wrap;">{{ row.IndexName }}</span>
+              </template>
+
               <span v-else>{{ row[item.key] }}</span>
             </template>
           </el-table-column>
@@ -189,7 +193,7 @@ export default {
           },
           {
             label: /* '指标最新时间' */this.$t('SelftDataPage.col_newest_time'),
-            key: 'DataUpdateTime',
+            key: 'EndDate',
             sortable:true,
           },
           {

+ 638 - 0
src/views/datasheet_manage/balanceSheetEdit.vue

@@ -0,0 +1,638 @@
+<template>
+  <div class="balance-sheet-detail-wrap">
+    <noDataAuth class="no-auth-box" v-if="!excelInfo.HaveOperaAuth&&isView" :text="$t('MsgPrompt.no_sheet_auth')"/>
+    <div class="wrap-top">
+      <ul class="form-ul">
+        <li>
+          <el-input
+            v-model="sheetForm.name"
+            :placeholder="$t('OnlineExcelPage.please_table_name_ipt')"
+            style="width: 200px"
+            clearable
+            :disabled="isView||isStaticTable"
+          >
+          </el-input>
+        </li>
+        <li>
+          <el-cascader
+            v-model="sheetForm.classify"
+            :options="classifyArr"
+            style="width: 120px"
+            :props="{
+              label: 'ExcelClassifyName',
+              value: 'ExcelClassifyId',
+              children: 'Children',
+              emitPath: false,
+              checkStrictly: true,
+            }"
+            :placeholder="$t('OnlineExcelPage.select_table_category')"
+            :disabled="isView||isStaticTable"
+          />
+        </li>
+        <li v-if="excelInfo.Button&&excelInfo.Button.OpWorkerButton">
+          <el-cascader
+            v-model="sheetForm.user"
+            :options="userList"
+            style="width: 120px"
+            :show-all-levels="false"
+            collapse-tags
+            :props="{
+              label: 'NodeName',
+              value: 'NodeId',
+              children: 'Children',
+              multiple: true,
+              emitPath: false,
+              checkStrictly: false,
+            }"
+            clearable
+            :placeholder="$t('OnlineExcelPage.Co_editor')"
+            :disabled="isView||isStaticTable"
+          />
+        </li>
+      </ul>
+      <div class="form-ul">
+        <span>{{ $t("BalanceSheet.version") }}</span>
+        <el-select
+          v-model="sheetForm.version"
+          style="width: 90px; margin-right: 5px"
+          @change="handleVersionChange"
+        >
+          <el-option
+            v-for="item in versionOpts"
+            :key="item.ExcelInfoId"
+            :label="item.VersionName"
+            :value="item.ExcelInfoId"
+          ></el-option>
+        </el-select>
+        <!-- 存为静态表按钮 -->
+        <el-button type="primary" @click="handleShowSaveStaticTable" v-if="!isView&&!isStaticTable">{{
+          $t("BalanceSheet.save_static_table")
+        }}</el-button>
+        <!-- 静态表操作 -->
+        <span v-if="!isView&&isStaticTable">
+        <span
+          class="editsty"
+          @click="handleShowSaveStaticTable('rename')"
+          style="margin-right: 10px"
+          >{{$t('MyEtaPage.option_op_rename')}}</span
+        >
+        <span
+          class="deletesty"
+          @click="handleStaticTableDel"
+          >{{$t("Table.delete_btn")}}</span
+        >
+        </span>
+        <div>
+          <!-- {{ $t("OnlineExcelPage.table_explaination_text") }} -->
+          <el-tooltip effect="dark">
+            <div
+              slot="content"
+              v-html="rules"
+              style="line-height: 20px; width: 350px"
+            ></div>
+            <i class="el-icon-question" />
+          </el-tooltip>
+        </div>
+      </div>
+      <div>
+        <span v-if="updateTime" style="color: #999999"
+          >{{ $t("OnlineExcelPage.recent_save_time_info")
+          }}{{ updateTime }}</span
+        >
+        <!-- 预览页面操作按钮 -->
+        <template v-if="isView">
+          <!-- <div> -->
+          <span
+            class="editsty"
+            @click="itemHandle(excelInfo, 'edit')"
+            style="margin-right: 10px"
+            v-if="isSheetBtnShow('edit')&&excelInfo.Button&&excelInfo.Button.OpButton"
+            >{{excelInfo.CanEdit?$t("ETable.Btn.edit_btn"):excelInfo.Editor+$t('OnlineExcelPage.editing_msg')}}</span
+          >
+          <span
+            class="editsty"
+            @click="itemHandle(excelInfo, 'refresh')"
+            style="margin-right: 10px"
+            v-if="isSheetBtnShow('refresh')&&excelInfo.Button&&excelInfo.Button.RefreshButton"
+            >{{ $t("ETable.Btn.refresh_btn") }}</span
+          >
+          <span
+            class="editsty"
+            @click="itemHandle(excelInfo, 'save')"
+            style="margin-right: 10px"
+            v-if="isSheetBtnShow('otherSave')&&excelInfo.Button&&excelInfo.Button.CopyButton"
+            >{{ $t("ETable.Btn.save_as") }}</span
+          >
+          <span
+            class="editsty"
+            @click="itemHandle(excelInfo, 'download')"
+            style="margin-right: 10px"
+            v-if="isSheetBtnShow('download')&&excelInfo.HaveOperaAuth"
+            >{{ $t("ETable.Btn.download_btn") }}</span
+          >
+          <span
+            class="deletesty"
+            @click="itemHandle(excelInfo, 'del')"
+            style="margin-right: 10px"
+            v-if="isSheetBtnShow('del')&&excelInfo.Button&&excelInfo.Button.DeleteButton"
+            >{{ $t("Table.delete_btn") }}</span
+          >
+          <!-- </div> -->
+        </template>
+        <!-- icon="el-icon-refresh-right" -->
+        <el-button
+          type="primary"
+          size="medium"
+          :loading="updating"
+          @click="updateHandle"
+          style="margin-left: 10px"
+          v-if="!isView"
+          >{{
+            updating
+              ? $t("ETable.Btn.renewing_btn")
+              : $t("ETable.Btn.renew_btn")
+          }}</el-button
+        >
+        <el-button
+          type="primary"
+          size="medium"
+          @click="saveSheetHandle"
+          style="margin-left: 10px"
+          v-if="!isView"
+          >{{ $t("ETable.Btn.save_btn") }}</el-button
+        >
+        <el-button type="primary" size="medium" plain @click="backHandle">{{
+          $t("ETable.Btn.back_btn")
+        }}</el-button>
+      </div>
+    </div>
+
+    <BalanceTable 
+      ref="balanceTableRef"
+      :disabled="isView"
+      :isStaticTable="isStaticTable"
+    />
+
+    <!-- 存为静态表弹窗 -->
+    <el-dialog
+      :visible.sync="showSaveStaticTable"
+      :close-on-click-modal="false"
+      :modal-append-to-body='false'
+      :title="isStaticTable?$t('MyEtaPage.option_op_rename'):$t('OnlineExcelPage.save_static_table')"
+      @close="showSaveStaticTable=false"
+      custom-class="dialog"
+      center
+      width="500px"
+      v-dialogDrag
+    >
+      <div style="text-align:center">
+        <span>{{$t('OnlineExcelPage.static_table_version_name')}}</span>
+        <el-input v-model="staticTableName" :placeholder="$t('OnlineExcelPage.save_static_table_tip')"></el-input>
+      </div>
+      <div class="dia-bot" style="text-align:center;padding:30px 0">
+				<el-button type="primary" style="margin-right:20px" @click="createdStaticTable">{{$t('ETable.Btn.save_btn')}}</el-button>
+				<el-button type="primary" plain @click="showSaveStaticTable=false">{{$t('ETable.Btn.cancel_btn')}}</el-button>
+			</div>
+    </el-dialog>
+
+    <!-- 表格另存 -->
+    <m-dialog
+      :show.sync="isSaveOther"
+      width="650px"
+      :title="$t('ETable.Btn.save_as')"
+      @close="cancelSaveOther"
+    >
+      <div style="padding-left: 80px">
+        <el-form
+          ref="formRef"
+          label-position="left"
+          hide-required-asterisk
+          label-width="80px"
+          :model="saveOtherForm"
+          :rules="saveOtherFormRule"
+        >
+          <el-form-item :label="$t('OnlineExcelPage.excel_name_ipt')" prop="name">
+            <el-input
+              v-model="saveOtherForm.name"
+              style="width: 80%"
+              :placeholder="$t('OnlineExcelPage.please_table_name_ipt')"
+            />
+          </el-form-item>
+          <el-form-item :label="$t('OnlineExcelPage.table_classification_label')" prop="classify">
+            <el-cascader
+              v-model="saveOtherForm.classify"
+              :options="classifyArr"
+              :props="{
+                label: 'ExcelClassifyName',
+                value: 'ExcelClassifyId',
+                children: 'Children',
+                emitPath: false,
+                checkStrictly: true,
+              }"
+              style="width: 80%"
+              :placeholder="$t('OnlineExcelPage.select_appropriate_category_lable')"
+              class="sheet-classify-cascader"
+            />
+          </el-form-item>
+        </el-form>
+      </div>
+      <div style="display: flex; justify-content: center; margin-top: 30px">
+        <el-button
+          type="primary"
+          style="margin-right: 60px"
+          @click="saveCopyOther"
+          >{{$t('Dialog.confirm_save_btn')}}</el-button
+        >
+        <el-button type="primary" plain @click="cancelSaveOther"
+          >{{$t('Dialog.cancel_btn')}}</el-button
+        >
+      </div>
+    </m-dialog>
+
+  </div>
+</template>
+
+<script>
+import * as sheetInterface from '@/api/modules/sheetApi.js';
+import { departInterence } from "@/api/api.js";
+import moment from 'moment';
+import mDialog from "@/components/mDialog.vue";
+import BalanceTable from './components/BalanceTable.vue';
+import BalanceTableMixin from './mixins/balanceTableMixin'
+export default {
+  mixins:[BalanceTableMixin],
+  components: {
+    BalanceTable,
+    mDialog
+  },
+  computed: {
+    downExcelFileUrl() {
+      let url = `${
+        process.env.VUE_APP_API_ROOT
+      }/datamanage/excel_info/table/download?${localStorage.getItem("auth")}`;
+      return url;
+    },
+    rules() {
+      return this.$t('OnlineExcelPage.TableInstructionsText') || ''
+    },
+    isView(){
+      return this.$route.path==='/viewBalanceSheet'
+    },
+    // 当前是否为静态表
+    isStaticTable(){
+      let flag=false
+      this.versionOpts.forEach(item=>{
+        if(item.ExcelInfoId===this.sheetForm.version&&item.BalanceType==1){
+          flag=true
+        }
+      })
+      return flag
+    },
+    saveOtherFormRule(){
+      return {
+        name: [
+          { required: true, message: this.$t('OnlineExcelPage.table_name_empty_msg') , trigger: "blur" },
+        ],
+        classify: [
+          { required: true, message: this.$t('OnlineExcelPage.cannot_be_empty_table') , trigger: "blur" },
+        ],
+      }
+    }
+  },
+  data() {
+    return {
+      sheetId: this.$route.query.id || '',
+      excelInfo:{},
+
+      updating:false,
+
+      sheetForm: {
+        name: '',
+        classify: '',
+        user: '',
+        version: Number(this.$route.query.id),
+      },
+      classifyArr: [],
+      userList: [],//系统用户
+      updateTime: moment().format('YYYY-MM-DD HH:mm:ss'),
+      versionOpts: [],
+
+      showSaveStaticTable:false,//存为静态表弹窗
+      staticTableName:moment().format('YYYY-MM-DD'),
+
+      /* 另存为 */
+      isSaveOther: false,
+      saveOtherForm: {
+        name: '',
+				classify: ''
+      },
+
+    }
+  },
+  created() {
+    this.getClassify();
+    this.getSystemUserList()
+    this.getChildTable()
+    this.getDetail()
+    this.getVersionList()
+  },
+  beforeRouteLeave(to,from,next){
+    console.log('退出编辑',from);
+    if(from.path==='/editBalanceSheet'){
+      this.markFinishStatus()
+    }
+    next()
+  },
+  methods: {
+    // 获取版本列表
+    getVersionList(){
+      sheetInterface.balanceTableVersion({ExcelInfoId:this.sheetId}).then(res=>{
+        if(res.Ret===200){
+          const arr=res.Data.List||[]
+          if(this.$i18nt.locale!=='zh'){
+            arr[0].VersionName='Active'
+          }
+          this.versionOpts=arr
+        }
+      })
+    },
+
+    handleVersionChange(){
+      this.getChildTable()
+    },
+
+    cancelSaveOther() {
+      this.$refs.formRef.resetFields();
+      this.saveOtherForm = {
+        name: '',
+				classify: ''
+      };
+      this.isSaveOther = false;
+    },
+
+    /* 另存为 */
+    async saveCopyOther() {
+      await this.$refs.formRef.validate();
+      let { classify, name } = this.saveOtherForm;
+
+      const res = await sheetInterface.copyExcel({
+        ExcelInfoId: this.excelInfo.ExcelInfoId,
+        ExcelName: name,
+        ExcelClassifyId: classify,
+      });
+
+      if (res.Ret !== 200) return;
+
+      this.$message.success(this.$t('MsgPrompt.saved_msg') );
+      this.cancelSaveOther();
+    },
+
+    handleShowSaveStaticTable(type){
+      console.log(type);
+      if(type==='rename'){
+        this.versionOpts.forEach(item=>{
+          if(item.ExcelInfoId===this.sheetForm.version){
+            this.staticTableName=item.VersionName
+          }
+        })
+      }else{
+        this.staticTableName=this.$moment().format('YYYY-MM-DD')
+      }
+      this.showSaveStaticTable=true
+    },
+    // 创建/重命名静态表
+    createdStaticTable(){
+      if(!this.staticTableName){
+        this.$message.warning(this.$t('OnlineExcelPage.save_static_table_tip'))
+        return
+      }
+      // 重命名
+      if(this.isStaticTable){
+        sheetInterface.balanceStaticTableRename({
+          ExcelInfoId:Number(this.sheetForm.version),
+          VersionName:this.staticTableName
+        }).then(res=>{
+          if(res.Ret===200){
+            this.$message.success(res.Msg);
+            this.getVersionList()
+            this.showSaveStaticTable=false
+            this.$refs.balanceTableRef.getChartList()//更新图表数据
+          }
+        })
+        return
+      }
+
+      sheetInterface.balanceTableSaveStatic({
+        ExcelInfoId:Number(this.sheetForm.version),
+        VersionName:this.staticTableName
+      }).then(res=>{
+        if(res.Ret===200){
+          this.getVersionList()
+          this.sheetForm.version=res.Data.ExcelInfoId
+          this.getChildTable()
+          this.showSaveStaticTable=false
+        }
+      })
+    },
+
+    // 删除当前静态表
+    handleStaticTableDel(){
+      this.$confirm(this.$t('ETable.Msg.is_del_table_msg') , this.$t('Confirm.prompt') , {
+        confirmButtonText:  this.$t('Dialog.confirm_btn'),
+        cancelButtonText: this.$t('Dialog.cancel_btn'),
+        type: "warning",
+      }).then(()=>{
+        sheetInterface.classifyDel({
+          ExcelClassifyId:0,
+          ExcelInfoId:Number(this.sheetForm.version),
+          Source: 5
+        }).then(res=>{
+          if(res.Ret===200){
+            this.$message.success(res.Msg);
+            this.sheetForm.version=Number(this.sheetId)
+            this.getVersionList()
+            this.getChildTable()
+          }
+        })
+      }).catch(()=>{})
+    },
+
+    //获取所有子表数据
+    async getChildTable(){
+      if(!this.sheetForm.version) return
+      const res = await sheetInterface.getBalanceChildTable({
+				ParentId: Number(this.sheetForm.version)
+			})
+      if(res.Ret !== 200)  return
+      this.$refs.balanceTableRef.initSheetListData(res.Data.List||[]);
+
+    },
+
+    /* 获取表格详情 */
+    async getDetail(type='init') {
+      if(!this.sheetId) return
+      const res = await sheetInterface.sheetDetail({
+				ExcelInfoId: Number(this.sheetId)
+			})
+      if(res.Ret !== 200)  return
+      this.excelInfo=res.Data
+      const { ExcelName,ExcelClassifyId,TableData,ModifyTime,Button } = res.Data;
+      this.sheetForm.name=ExcelName
+      this.sheetForm.classify=ExcelClassifyId
+      this.getTableWorker()
+    },
+
+    // 保存父表基础信息
+    async saveTableInfo(){
+      let params = {
+        ExcelInfoId:Number(this.sheetId),
+        ExcelName: this.sheetForm.name,
+        ExcelType: 1,
+        ExcelClassifyId: this.sheetForm.classify,
+        ExcelImage: '',
+        Source: 5,
+        TableData: {
+          CellRelation:"[]",
+          Data:[]
+        }
+      };
+      const res=await sheetInterface.sheetEdit(params)
+    },
+
+    //获取协作人
+    async getTableWorker(){
+      const res=await sheetInterface.getBalanceTableWorker({
+        ExcelInfoId:Number(this.sheetId)
+      })
+      if(res.Ret !== 200)  return
+      const arr=res.Data.List||[]
+      this.sheetForm.user=arr.map(e=>e.SysUserId)
+    },
+
+    // 保存设置的协作人
+    async setTableWorker(){
+      if(!this.excelInfo.Button.OpWorkerButton) return
+      const res=await sheetInterface.setBalanceTableWorker({
+        ExcelInfoId:Number(this.sheetId),
+        SysUserIds:this.sheetForm.user?this.sheetForm.user.join(','):''
+      })
+      if(res.Ret !== 200)  return
+    },
+
+    //点击保存
+    saveSheetHandle(){
+      this.setTableWorker()// 保存协作人
+      this.saveTableInfo()// 保存父表基础信息
+      this.$refs.balanceTableRef.saveChildSheet('manualSave')
+      this.$refs.balanceTableRef.getChartList()//更新图表数据
+
+    },
+
+    // 点击更新
+    async updateHandle(){
+      if(this.updating) return
+      this.updating=true
+      // 保存一次
+      await this.$refs.balanceTableRef.saveChildSheet()
+      // 重新获取当前子表的数据
+      this.$refs.balanceTableRef.getSheetDetail('refresh')
+    },
+
+    backHandle(){
+      this.$router.back()
+    },
+
+
+    /* 获取分类 */
+    getClassify() {
+      sheetInterface.excelClassifyOne({ Source: 5 }).then(res => {
+        if (res.Ret !== 200) return
+
+        this.classifyArr = res.Data.AllNodes || [];
+      })
+    },
+
+    // 递归处理数组
+    deleteUserEmpty(arr) {
+      arr.length && arr.forEach(item => {
+        item.Children && item.Children.length && this.deleteUserEmpty(item.Children)
+        if (!item.Children || !item.Children.length) {
+          delete item.Children
+        }
+      })
+    },
+
+    getSystemUserList() {
+      departInterence.getSystemUser({
+        KeyWord: ''
+      }).then(res => {
+        if (res.Ret === 200) {
+          this.deleteUserEmpty(res.Data || [])
+          this.userList = res.Data || []
+        }
+      })
+    },
+
+    //更新编辑状态
+    markFinishStatus(){
+      if(!this.sheetId) return
+      sheetInterface.markSheetEditStatus({ExcelInfoId:Number(this.sheetId),Status:2}).then(res=>{
+        if(res.Ret != 200) return 
+      })
+    },
+
+    isSheetBtnShow(type){
+      return this.permissionBtn.isShowBtn('etaTablePermission',`etaTable_customize_balance_${type}`)
+    }
+  },
+}
+</script>
+
+<style lang="scss">
+.sheet-classify-cascader .el-input {
+	width: 100%;
+}
+</style>
+<style scoped lang="scss">
+* {
+  box-sizing: border-box;
+}
+.balance-sheet-detail-wrap {
+  min-width: 1070px;
+  min-height: calc(100vh - 120px);
+  position: relative;
+  .no-auth-box{
+    position: absolute;
+    z-index: 99;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    top: 0;
+    background-color: #F2F6FA;
+  }
+  .wrap-top {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 20px;
+    padding: 20px;
+    background: #fff;
+    border: 1px solid #ececec;
+    border-radius: 4px;
+    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
+    display: flex;
+    z-index: 1;
+    .form-ul {
+      //   flex: 1;
+      display: flex;
+      align-items: center;
+      gap: 0 5px;
+      li {
+        &:first-child {
+          padding-top: 0;
+        }
+      }
+    }
+  }
+}
+</style>

+ 5 - 1
src/views/datasheet_manage/common/customTable.js

@@ -147,7 +147,11 @@ export function setCellBg(e) {
 }
 
 //右键菜单
-export function getRightClickMenu(pos,canEdit=false) {
+export function getRightClickMenu(pos,canEdit=false,isStaticTable=false) {
+  // 如果是静态表则只有清空功能
+  if(isStaticTable){
+    return [{ label: bus.$i18nt ? bus.$i18nt.t('SystemManage.ReportApprove.clear_btn'):"清空", key: "reset" }]
+  }
 
   let cellMenu = [
     { label: bus.$i18nt ? bus.$i18nt.t('Edb.CalculatesAll.select_date'):"根据日期选择指标值", key: "choose-target" },

+ 995 - 0
src/views/datasheet_manage/components/BalanceAddChart.vue

@@ -0,0 +1,995 @@
+<template>
+  <div v-dialogDrag v-if="isShow">
+    <div class="balance-add-chart-wrap el-dialog">
+      <div class="header el-dialog__header">
+        <span>{{ $t("Chart.add_chart_btn") }}</span>
+        <i class="el-icon-close" @click="cancelHandle" />
+      </div>
+      <div class="dialog-main">
+        <el-form
+          label-position="left"
+          hide-required-asterisk
+          label-width="80px"
+          :model="formData"
+          :rules="formRules"
+          inline
+        >
+          <div class="item-tr">
+            <!-- 图表名称 -->
+            <el-form-item
+              :label="$t('Chart.Detail.chart_name')"
+              prop="chartName"
+            >
+              <el-input
+                v-model="formData.chartName"
+                :placeholder="$t('Dialog.require_vaild')"
+                style="width: 200px"
+              ></el-input>
+            </el-form-item>
+            <!-- 数据来源 -->
+            <el-form-item :label="$t('Edb.Detail.source')" prop="chartSource">
+              <el-input
+                v-model="formData.chartSource"
+                :placeholder="$t('OnlineExcelPage.chart_source_placehoder')"
+                style="width: 150px"
+              ></el-input>
+              <el-switch
+                style="display: inline-block"
+                v-model="formData.showChartSource"
+              >
+              </el-switch>
+            </el-form-item>
+          </div>
+          <div class="item-tr">
+            <!-- 图表类型 -->
+            <el-form-item :label="$t('SystemManage.ChartSet.label01')" prop="chartType">
+              <el-select v-model="formData.chartType" style="width: 200px" @change="handleChartTypeChange">
+                <el-option
+                  :label="item.label"
+                  :value="item.key"
+                  v-for="item in chartTypeOpts"
+                  :key="item.key"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+            <!--  上下限 -->
+            <el-form-item v-if="formData.chartType == 1">
+              <span
+                style="display: inline-block; margin-right: 20px"
+                v-if="hasLeftAxis"
+              >
+                <span>
+                  <!-- 左轴上下限 -->
+                  {{$t('OnlineExcelPage.left_limit')}}</span>
+                <el-input
+                  class="number-input"
+                  size="mini"
+                  type="number"
+                  style="width: 60px"
+                  v-model="formData.leftMin"
+                ></el-input>
+                <span>{{$t('Common.to')}}</span>
+                <el-input
+                  class="number-input"
+                  size="mini"
+                  type="number"
+                  style="width: 60px"
+                  v-model="formData.leftMax"
+                ></el-input>
+              </span>
+              <span
+                style="display: inline-block; margin-right: 20px"
+                v-if="hasRightAxis"
+              >
+                <span>
+                  <!-- 右轴上下限 -->
+                  {{$t('OnlineExcelPage.right_limit')}}
+                </span>
+                <el-input
+                  class="number-input"
+                  size="mini"
+                  type="number"
+                  style="width: 60px"
+                  v-model="formData.rightMin"
+                ></el-input>
+                <span>{{$t('Common.to')}}</span>
+                <el-input
+                  class="number-input"
+                  size="mini"
+                  type="number"
+                  style="width: 60px"
+                  v-model="formData.rightMax"
+                ></el-input>
+              </span>
+              <span
+                style="display: inline-block; margin-right: 20px"
+                v-if="hasRightTwoAxis"
+              >
+                <span>
+                  <!-- 右二轴上下限 -->
+                  {{$t('OnlineExcelPage.right_two_limit')}}
+                </span>
+                <el-input
+                  class="number-input"
+                  size="mini"
+                  type="number"
+                  style="width: 60px"
+                  v-model="formData.rightTwoMin"
+                ></el-input>
+                <span>{{$t('Common.to')}}</span>
+                <el-input
+                  class="number-input"
+                  size="mini"
+                  type="number"
+                  style="width: 60px"
+                  v-model="formData.rightTwoMax"
+                ></el-input>
+              </span>
+            </el-form-item>
+            <el-form-item v-if="formData.chartType == 2">
+              <span style="display: inline-block; margin-right: 20px">
+                <span>
+                  <!-- 纵轴上下限 -->
+                  {{$t('OnlineExcelPage.y_limit')}}
+                </span>
+                <el-input
+                  class="number-input"
+                  size="mini"
+                  type="number"
+                  style="width: 60px"
+                  v-model="formData.leftMin"
+                ></el-input>
+                <span>{{$t('Common.to')}}</span>
+                <el-input
+                  class="number-input"
+                  size="mini"
+                  type="number"
+                  style="width: 60px"
+                  v-model="formData.leftMax"
+                ></el-input>
+              </span>
+            </el-form-item>
+            <el-form-item v-if="formData.chartType == 4">
+              <span
+                style="display: inline-block; margin-right: 20px"
+                v-if="edbList[0].axis===1"
+              >
+                <span>
+                  <!-- 纵轴上下限 -->
+                  {{$t('OnlineExcelPage.y_limit')}}</span>
+                <el-input
+                  class="number-input"
+                  size="mini"
+                  type="number"
+                  style="width: 60px"
+                  v-model="formData.leftMin"
+                ></el-input>
+                <span>{{$t('Common.to')}}</span>
+                <el-input
+                  class="number-input"
+                  size="mini"
+                  type="number"
+                  style="width: 60px"
+                  v-model="formData.leftMax"
+                ></el-input>
+              </span>
+              <span
+                style="display: inline-block; margin-right: 20px"
+                v-if="edbList[0].axis===0"
+              >
+                <span>
+                  <!-- 纵轴上下限 -->
+                  {{$t('OnlineExcelPage.y_limit')}}
+                </span>
+                <el-input
+                  class="number-input"
+                  size="mini"
+                  type="number"
+                  style="width: 60px"
+                  v-model="formData.rightMin"
+                ></el-input>
+                <span>{{$t('Common.to')}}</span>
+                <el-input
+                  class="number-input"
+                  size="mini"
+                  type="number"
+                  style="width: 60px"
+                  v-model="formData.rightMax"
+                ></el-input>
+              </span>
+            </el-form-item>
+          </div>
+          <!-- 指标模块 -->
+          <div class="item-tr" v-for="(item, index) in edbList" :key="item.tag">
+            <img
+              @click="handleDelEdb(index)"
+              v-if="edbList.length > 1"
+              src="~@/assets/img/icons/delete-red.png"
+              style="width: 16px; position: relative; top: 3px; cursor: pointer"
+              alt=""
+            />
+            <span class="edb-tag-box">{{$t('Edb.eta_name')}}{{ item.tag }}</span>
+            <el-form-item :label="$t('OnlineExcelPage.time_serial')" label-width="70px">
+              <el-input
+                :class="{'select_input': selectInput===item.tag+'_timeSerial'}"
+                v-model="item.timeSerial"
+                :placeholder="$t('CustomAnalysisPage.select_date_sequence')"
+                style="width: 150px"
+                @focus="handleChooseInput(item.tag+'_timeSerial')"
+              ></el-input>
+            </el-form-item>
+            <el-form-item :label="$t('OnlineExcelPage.value_serial')" label-width="70px">
+              <el-input
+                :class="{'select_input': selectInput===item.tag+'_valueSerial'}"
+                v-model="item.valueSerial"
+                :placeholder="$t('CustomAnalysisPage.select_date_numerical')"
+                style="width: 150px"
+                @focus="handleChooseInput(item.tag+'_valueSerial')"
+                @change="handleValInputChange"
+              ></el-input>
+            </el-form-item>
+            <el-form-item :label="$t('Table.edb_name')" label-width="70px">
+              <el-input
+                v-model="item.name"
+                :placeholder="$t('Edb.InputHolderAll.input_name')"
+                style="width: 120px"
+              ></el-input>
+            </el-form-item>
+            <el-form-item :label="$t('Table.unit')" label-width="40px">
+              <el-input
+                v-model="item.unit"
+                :placeholder="$t('Edb.InputHolderAll.input_unit')"
+                style="width: 90px"
+              ></el-input>
+            </el-form-item>
+            <div
+              style="
+                display: flex;
+                align-items: center;
+                justify-content: center;
+                gap: 0 40px;
+                margin-bottom: 20px;
+              "
+              v-if="formData.chartType !== 2"
+            > 
+              <!-- 堆积柱状图只有第一个指标有设置左右轴和逆序功能 -->
+              <template v-if="!(formData.chartType ===4&&index>0)">
+              <el-radio-group v-model="item.axis" size="mini" @change="handleAxisChange">
+                <el-radio-button :label="1">{{
+                  $t("Chart.Detail.l_axis")
+                }}</el-radio-button>
+                <el-radio-button :label="0">{{
+                  $t("Chart.Detail.r_axis")
+                }}</el-radio-button>
+                <el-radio-button
+                  :label="2"
+                  :disabled="
+                    !hasRightAxis ||
+                    (item.axis === 0 &&
+                      edbList.filter((_) => _.axis === 0).length === 1)
+                  "
+                  >{{ $t("Chart.Detail.rtwo_axis") }}</el-radio-button
+                >
+              </el-radio-group>
+              <!-- 逆序 -->
+              <el-checkbox v-model="item.IsOrder">{{
+                $t("Chart.Detail.re_order")
+              }}</el-checkbox>
+              </template>
+              <el-radio-group v-model="item.EdbInfoType" size="mini">
+                <!-- 标准指标 -->
+                <el-radio :label="1">{{
+                  $t("Chart.Detail.stand_lead")
+                }}</el-radio>
+                <!-- 领先指标 -->
+                <el-radio :label="0">{{
+                  $t("Chart.Detail.leading_lead")
+                }}</el-radio>
+              </el-radio-group>
+              <span v-if="item.EdbInfoType === 0">
+                <span><!-- 领先 -->{{ $t("EtaChartAddPage.label_lead") }}</span>
+                <el-input
+                  class="number-input"
+                  size="mini"
+                  type="number"
+                  min="0"
+                  style="width: 60px"
+                  v-model="item.leadVal"
+                  @keyup.native="filterCode(item)"
+                ></el-input>
+                <el-select
+                  v-model="item.leadUnit"
+                  style="width: 60px"
+                  placeholder=""
+                  size="mini"
+                >
+                  <el-option
+                    v-for="item in fre_options"
+                    :key="item"
+                    :label="item"
+                    :value="item"
+                  >
+                  </el-option>
+                </el-select>
+              </span>
+            </div>
+          </div>
+          <!-- 季节图配置 -->
+          <div class="item-tr" style="display: flex;align-items:center;justify-content:center" v-if="formData.chartType === 2">
+            <div class="xaxis-range-tip">
+              {{ $t("EtaChartAddPage.label_xserie_range")
+              }}<!-- 横坐标显示范围 -->
+              <!-- <el-tooltip>
+                <div
+                  slot="content"
+                  v-html="$t('EtaChartAddPage.xserie_range_tip')"
+                ></div>
+                <img
+                  src="~@/assets/img/icons/question_mark_black.png"
+                  style="height: 16px; cursor: pointer; margin-left: 6px"
+                />
+              </el-tooltip> -->
+            </div>
+            <el-date-picker
+              style="width: 100px;margin-left:30px"
+              v-model="SeasonExtraConfig.XStartDate"
+              value-format="MM-dd"
+              popper-class="x-range-picker-date"
+              format="MM-dd"
+              :placeholder="$t('Common.ph_time_start')"
+              :clearable="false"
+            ></el-date-picker>
+            <el-date-picker
+              style="width: 100px;margin-left:10px"
+              v-model="SeasonExtraConfig.XEndDate"
+              value-format="MM-dd"
+              popper-class="x-range-picker-date"
+              format="MM-dd"
+              :placeholder="$t('Common.ph_time_end')"
+              :clearable="false"
+            ></el-date-picker>
+            <!-- 跨年 -->
+            <el-checkbox
+              style="margin-left:20px;margin-right:30px"
+              :label="$t('EtaChartAddPage.label_cross_year')" 
+              v-model="SeasonExtraConfig.JumpYear" 
+              :disabled="SeasonExtraConfig.isSpanYearDisable"
+            ></el-checkbox>
+            <!-- 春节对齐 -->
+            <el-radio-group v-model="SeasonExtraConfig.type" size="mini">
+              <!-- 公历 -->
+              <el-radio-button label="公历">{{$t('Chart.calendar_gre')}}</el-radio-button>
+              <!-- 农历 -->
+              <el-radio-button label="农历">{{$t('Chart.calendar_lunar')}}</el-radio-button>
+            </el-radio-group>
+          </div>
+          <!-- 季节图设置图例名称按钮 -->
+          <div
+            class="add-edb-btn"
+            style="color: #0052d9; cursor: pointer"
+            v-if="formData.chartType === 2"
+            @click="handleShowEditLegend"
+          >
+            <span>{{$t('EtaChartAddPage.label_legend_set')}}<!-- 图例名称设置 --></span>
+						<img style="width:15px" src="~@/assets/img/icons/edit-blue.png" />
+          </div>
+
+          <!-- 添加指标按钮 -->
+          <div
+            class="add-edb-btn"
+            style="color: #0052d9; cursor: pointer;display:inline-block"
+            @click="handleAddEdb"
+            v-if="formData.chartType !== 2"
+          >
+            <!-- 添加指标 -->
+            {{$t('SteelChemicalPage.add_edb')}}
+          </div>
+        </el-form>
+      </div>
+      <div class="dia-bot">
+        <el-button type="primary" plain @click="cancelHandle">{{
+          $t("ETable.Btn.cancel_btn")
+        }}</el-button>
+        <el-button
+          type="primary"
+          style="margin-right: 20px"
+          @click="saveHandle"
+          >{{ $t("Dialog.confirm_btn") }}</el-button
+        >
+      </div>
+    </div>
+
+    <!-- 季节性 图例设置 -->
+		<LegendEditDia
+      :isEditLegend="legendEditDiaShow"
+			:legendList="SeasonExtraConfig.ChartLegend"
+      @cancel="legendEditDiaShow = false"
+      @saveLegend="saveLegend"
+    />
+  </div>
+</template>
+
+<script>
+import * as sheetInterface from "@/api/modules/sheetApi.js";
+import LegendEditDia from '@/views/dataEntry_manage/components/LegendEditDia.vue';
+import { generateSeriesArray } from '@/views/dataEntry_manage/databaseComponents/util'
+import {etaBaseConfigInterence} from '@/api/modules/etaBaseConfigApi.js';
+const tag_arr = generateSeriesArray();
+const MAX_ADD_NUM = 30//添加指标最大数量
+export default {
+  components:{LegendEditDia},
+  props: {
+    isShow: {
+      type: Boolean,
+    },
+    ExcelInfoId:0
+  },
+  watch: {
+    'formData.chartType':{
+      handler(newVal,oldVal){
+        if(newVal===2&&this.edbList.length>1){
+          this.formData.chartType = oldVal;
+					return this.$message.warning(/* '您选择的图表样式为季节性图表,只支持单指标画图' */this.$t('Chart.OptMsg.season_one_msg'));
+        }
+      }
+    }
+  },
+  computed: {
+    hasLeftAxis() {
+      return this.edbList.some(item => item.axis === 1)
+    },
+    hasRightAxis() {
+      return this.edbList.some(item => item.axis === 0)
+    },
+    hasRightTwoAxis() {
+      return this.edbList.some(item => item.axis === 2)
+    },
+  },
+  data() {
+    return {
+      fre_options: ['年', '季', '月', '周', '天'], //领先指标频度配置
+      chartTypeOpts: [
+        { label: /* '曲线图' */this.$t('Chart.ChartType.spline_name'), key: 1 },
+        { label: /* '季节性图' */this.$t('Chart.ChartType.season_name'), key: 2 },
+        { label: /* '堆积柱状图' */this.$t('Chart.ChartType.stack_column_name'), key: 4 },
+      ],
+      formData: {
+        chartName: '',
+        chartSource: '平衡表',
+        showChartSource: false,
+        chartType: 1,
+        leftMin: 0,
+        leftMax: 0,
+        rightMin: 0,
+        rightMax: 0,
+        rightTwoMin: 0,
+        rightTwoMax: 0,
+      },
+      // 季节性图和额外配置
+			SeasonExtraConfig:{
+				ChartLegend:[], // 图例名称数组
+				XStartDate:"01-01", // 横坐标显示范围 - 开始
+				XEndDate:"12-31", // 横坐标显示范围-结束
+				JumpYear:false, //是否跨年
+        isSpanYearDisable:false,
+        type:'公历',
+			},
+      legendEditDiaShow:false,
+
+      formRules: {},
+
+      edbList: [],//sheet1!$A$3:$A$13
+      selectInput:'',
+
+      editChartInfoId:0,//编辑时的图表id
+
+      commonShowChartSource:false,//是否显示图表来源的公共配置
+    }
+  },
+  created() {
+    this.edbList.push(this.createEbdListItem('A'))
+    this.getChartCommonConfig()
+  },
+  methods: {
+    // 季节图点击编辑图例
+    async handleShowEditLegend(){
+      // 如果没有选择指标数据
+      if(!(this.edbList[0].timeSerial&&this.edbList[0].valueSerial)){
+        this.legendEditDiaShow=true
+        return
+      }
+      // 获取当前选择的 时间序列和数值序列的值
+      const dateObj=this.getSeriesNum(this.edbList[0].timeSerial)
+      const valueObj=this.getSeriesNum(this.edbList[0].valueSerial)
+      const dateArr=this.findLimitData(dateObj.start,dateObj.end).valueArr
+      const valueArr=this.findLimitData(valueObj.start,valueObj.end).valueArr
+      const params={
+        DateArr:dateArr,
+        DataArr:valueArr,
+        Calendar:this.SeasonExtraConfig.type,
+        SeasonExtraConfig:{
+          ChartLegend:this.SeasonExtraConfig.ChartLegend,// 图例名称数组
+          XStartDate:this.SeasonExtraConfig.XStartDate,
+          XEndDate:this.SeasonExtraConfig.XEndDate,
+          JumpYear:this.SeasonExtraConfig.JumpYear?1:0
+        }
+      }
+      console.log(params);
+      const res=await sheetInterface.balanceSeasonChart(params)
+      if(res.Ret===200){
+        const arr=res.Data.List||[]
+        const temarr=arr.map(item=>{
+          return {Name:item.Years,Value:item.ChartLegend}
+        })
+        this.SeasonExtraConfig.ChartLegend=this.SeasonExtraConfig.type==='公历'?temarr:temarr.filter((item,index)=>index>0)
+        this.legendEditDiaShow=true
+      }
+      
+    },
+
+    // 编辑时初始化数据
+    initEditData(e){
+      console.log('edit回显数据',e);
+      const {ChartInfo,EdbInfoList,ExcelEdbList}=e
+      this.editChartInfoId=ChartInfo.ChartInfoId
+      this.formData.chartName=ChartInfo.ChartName
+      this.formData.chartSource=JSON.parse(ChartInfo.SourcesFrom).text
+      this.formData.showChartSource=JSON.parse(ChartInfo.SourcesFrom).isShow
+      this.formData.chartType=ChartInfo.ChartType
+      this.formData.leftMin=ChartInfo.LeftMin?Number(ChartInfo.LeftMin):0
+      this.formData.leftMax=ChartInfo.LeftMax?Number(ChartInfo.LeftMax):0
+      this.formData.rightMin=ChartInfo.RightMin?Number(ChartInfo.RightMin):0
+      this.formData.rightMax=ChartInfo.RightMax?Number(ChartInfo.RightMax):0
+      this.formData.rightTwoMin=ChartInfo.Right2Min?Number(ChartInfo.Right2Min):0
+      this.formData.rightTwoMax=ChartInfo.Right2Max?Number(ChartInfo.Right2Max):0
+      if(ChartInfo.ChartType===2&&ChartInfo.SeasonExtraConfig){
+        this.SeasonExtraConfig.ChartLegend=JSON.parse(ChartInfo.SeasonExtraConfig).ChartLegend
+        this.SeasonExtraConfig.XStartDate=JSON.parse(ChartInfo.SeasonExtraConfig).XStartDate
+        this.SeasonExtraConfig.XEndDate=JSON.parse(ChartInfo.SeasonExtraConfig).XEndDate
+        this.SeasonExtraConfig.JumpYear=JSON.parse(ChartInfo.SeasonExtraConfig).JumpYear?true:false
+        this.SeasonExtraConfig.type=ChartInfo.Calendar
+      }
+
+      // 回显
+      const arr=EdbInfoList||[]
+      let temEdbList=[]
+      arr.forEach((item,index)=>{
+        temEdbList.push({
+          tag: ExcelEdbList[index].FromTag,
+          ExcelChartEdbId:item.EdbInfoId,
+          timeSerial: ExcelEdbList[index].DateSequenceStr,
+          valueSerial: ExcelEdbList[index].DataSequenceStr,
+          maxData:item.MaxData,//选中数据的最大值
+          minData:item.MinData,//选中数据的最小值
+          name: item.EdbAliasName,
+          unit:item.Unit,
+          axis: item.IsAxis,//哪个轴 1左轴 0右轴 2右二轴
+          EdbInfoType: item.EdbInfoType,//指标类型 1标准指标 0领先指标
+          leadVal: item.LeadValue,//领先值
+          leadUnit: item.LeadUnit,//领先单位 
+          IsOrder: item.IsOrder,//是否逆序
+        })
+      })
+
+      this.edbList=temEdbList
+      
+
+    },
+
+    // 点击选中哪个指标的时间\数值序列
+    handleChooseInput(e){
+      this.selectInput=e
+    },
+
+    // 指标轴改变
+    handleAxisChange(){
+      this.updateLimit()
+    },
+
+    // 通过字符串sheet1!$A$3:$A$13 获取开始和结束序列号
+    getSeriesNum(str){
+      // 正则表达式模式,确保格式正确且感叹号后面有两个$,冒号前后各两个$
+      const formatPattern = /^.*!\$[A-Z0-9]+\$[A-Z0-9]+:\$[A-Z0-9]+\$[A-Z0-9]/;
+      // 检查字符串是否符合格式要求
+      if (formatPattern.test(str)) {
+          // 正则表达式模式,用于提取美元符号后的值
+          let extractPattern = /\$([A-Z0-9]+)/g;
+
+          // 存储匹配结果的数组
+          let matches = [];
+          let match;
+
+          // 使用正则表达式的exec方法来找到所有匹配
+          while ((match = extractPattern.exec(str)) !== null) {
+              // 将匹配的字符数字转换为数字类型并存储
+              let value = match[1];
+              if (!isNaN(value)) {
+                  matches.push(Number(value));
+              } else {
+                  matches.push(value); // 保留非数字值(如字母)
+              }
+          }
+
+          // 获取出开始和结束单元格序号
+          let start={
+            col:0,
+            row:0
+          },
+          end={
+            col:0,
+            row:0
+          };
+          start.col=this.$parent.columnHeader.findIndex(_e=>_e===matches[0])
+          start.row=matches[1]-1
+          end.col=this.$parent.columnHeader.findIndex(_e=>_e===matches[2])
+          end.row=matches[3]-1
+
+          return {
+            start,
+            end
+          }
+
+      } else {
+          console.log("字符串格式不符合要求");
+          this.$message.warning('格式不合法')
+          return false
+      }
+    },
+
+    // 手动输入数值序列改变
+    handleValInputChange(str){
+      console.log('数值序列改变',str);
+      const obj=this.getSeriesNum(str)
+      if(!obj) return
+      this.tableSelect(obj.start,obj.end,str)
+    },
+
+    // 选中的序列
+    tableSelect(start,end,str){
+      console.log(start,end,str);
+      if(this.selectInput){
+
+        //查找到是哪个指标
+        const tag=this.selectInput.split('_')[0]
+        const type=this.selectInput.split('_')[1]
+        this.edbList.forEach(edb => {
+          if(edb.tag===tag){
+            if(type==='timeSerial'){
+              edb.timeSerial=str
+            }
+            if(type==='valueSerial'){
+              edb.valueSerial=str
+              edb.maxData=this.findLimitData(start,end).maxData
+              edb.minData=this.findLimitData(start,end).minData
+              this.updateLimit()
+            }
+          }
+        });
+      }
+    },
+
+    // 根据选择的数据更新上下限
+    updateLimit(){
+      let leftArr=[],rightArr=[],rightTwoArr=[];
+      this.edbList.forEach(item=>{
+        if(item.axis===1){
+          leftArr.push(...[item.minData,item.maxData])
+        }
+        if(item.axis===0){
+          rightArr.push(...[item.minData,item.maxData])
+        }
+        if(item.axis===2){
+          rightTwoArr.push(...[item.minData,item.maxData])
+        }
+      })
+      this.formData.leftMin=leftArr.length?Math.min(...leftArr):0
+      this.formData.leftMax=leftArr.length?Math.max(...leftArr):0
+      this.formData.rightMin=rightArr.length? Math.min(...rightArr):0
+      this.formData.rightMax=rightArr.length? Math.max(...rightArr):0
+      this.formData.rightTwoMin=rightTwoArr.length? Math.min(...rightTwoArr):0
+      this.formData.rightTwoMax=rightTwoArr.length? Math.max(...rightTwoArr):0
+    },
+
+    // 找出选择的最大最小值
+    findLimitData(start,end){
+      let minData=0,maxData=0;
+      const data=this.$parent.config.data
+      // console.log(data);
+      let numArr=[]
+      // 判断是选择的同行还是同列
+      if(start.col===end.col&&start.row!=end.row){//同列
+        for (let index = start.row; index <= end.row; index++) {
+         numArr.push(data[index][start.col].ShowValue)
+        }
+      }
+      if(start.col!=end.col&&start.row==end.row){//同行
+        const rowData=data[start.row]
+        for (let index = start.col; index <= end.col; index++) {
+          numArr.push(rowData[index].ShowValue)
+        }
+      }
+      //只选择了一个单元格
+      if(start.row===end.row&&start.col===end.col){
+        numArr.push(data[start.row][start.col].ShowValue)
+      }
+
+      const valueArr=JSON.parse(JSON.stringify(numArr))
+
+      numArr=[...new Set(numArr)]
+      numArr=numArr.filter(item=>!isNaN(item)).map(Number)
+      
+      if(numArr.length!==0){
+        maxData=Math.max(...numArr)
+        minData=Math.min(...numArr)
+      }
+
+      // console.log(numArr);
+      // console.log(minData,maxData);
+      return{
+        valueArr,
+        maxData,
+        minData
+      }
+    },
+
+    // 图例编辑接口保存
+		saveLegend(copyList){
+			if(copyList && copyList.length>0){
+				this.SeasonExtraConfig.ChartLegend = copyList
+				this.legendEditDiaShow=false
+			}
+		},
+
+    // 图表类型切换
+    handleChartTypeChange(){
+      this.edbList.forEach(item=>{
+        item.axis=1
+      })
+    },
+
+    //添加指标
+    handleAddEdb() {
+      if (this.edbList.length === MAX_ADD_NUM) {
+        this.$message.warning(this.$t('EtaBasePage.num_overrun_msg'))
+        return
+      }
+      const t = this.edbList[this.edbList.length - 1].tag
+      const index = tag_arr.findIndex(item => item === t);
+      const obj = this.createEbdListItem(tag_arr[index + 1])
+      this.edbList.push(obj)
+
+    },
+    createEbdListItem(t) {
+      return {
+        tag: t,
+        ExcelChartEdbId:0,
+        timeSerial: '',
+        valueSerial: '',
+        maxData:0,//选中数据的最大值
+        minData:0,//选中数据的最小值
+        name: '',
+        unit:'',
+        axis: 1,//哪个轴 1左轴 0右轴 2右二轴
+        EdbInfoType: 1,//指标类型 1标准指标 0领先指标
+        leadVal: 0,//领先值
+        leadUnit: '',//领先单位 
+        IsOrder: false,//是否逆序
+      }
+    },
+
+    handleDelEdb(index) {
+      this.edbList.splice(index, 1)
+    },
+    // 初始化表单
+    initData() {
+      this.editChartInfoId=0
+      this.formData={
+        chartName: '',
+        chartSource: '平衡表',
+        showChartSource: this.commonShowChartSource|| false,
+        chartType: 1,
+        leftMin: 0,
+        leftMax: 0,
+        rightMin: 0,
+        rightMax: 0,
+        rightTwoMin: 0,
+        rightTwoMax: 0,
+      }
+      this.SeasonExtraConfig={
+        ChartLegend:[], // 图例名称数组
+				XStartDate:"01-01", // 横坐标显示范围 - 开始
+				XEndDate:"12-31", // 横坐标显示范围-结束
+				JumpYear:false, //是否跨年
+        isSpanYearDisable:false,
+        type:'公历',
+      }
+      this.edbList=[]
+      this.selectInput=''
+      this.edbList.push(this.createEbdListItem('A'))
+    },
+    async saveHandle() { 
+      const params={
+        ExcelInfoId:this.ExcelInfoId,
+        ChartInfoId:this.editChartInfoId||0,
+        ChartEdbInfoList:[],
+        ChartName:this.formData.chartName,
+        ChartType:this.formData.chartType,
+        SourcesFrom:JSON.stringify({
+          text:this.formData.chartSource,
+          isShow:this.formData.showChartSource
+        }),
+        LeftMin:`${this.formData.leftMin}`,
+        LeftMax:`${this.formData.leftMax}`,
+        RightMin:`${this.formData.rightMin}`,
+        RightMax:`${this.formData.rightMax}`,
+        Right2Min:`${this.formData.rightTwoMin}`,
+        Right2Max:`${this.formData.rightTwoMax}`,
+        MinMaxSave:1,
+        Source:11
+      }
+
+      // 季节图横坐标范围必须有
+      if(params.ChartType===2){
+        params.SeasonExtraConfig={
+          ChartLegend:this.SeasonExtraConfig.ChartLegend,// 图例名称数组
+          XStartDate:this.SeasonExtraConfig.XStartDate,
+          XEndDate:this.SeasonExtraConfig.XEndDate,
+          JumpYear:this.SeasonExtraConfig.JumpYear?1:0
+        }
+        params.Calendar=this.SeasonExtraConfig.type
+
+        //季节图横坐标范围必须有
+        if(!(params.SeasonExtraConfig.XStartDate&&params.SeasonExtraConfig.XEndDate)){
+          this.$message.warning('横坐标显示范围不能为空');
+          return
+        }
+
+      }
+      if(!params.ChartName){
+        this.$message.warning('请填写图表名称')
+        return
+      }
+
+      // 处理指标数据
+      let arr=[]
+      this.edbList.forEach(item=>{
+        arr.push({
+          FromTag:item.tag,
+          ExcelChartEdbId:item.ExcelChartEdbId,
+          EdbName:item.name,
+          Unit:item.unit,
+          IsAxis:item.axis,
+          IsOrder:item.IsOrder,
+          EdbInfoType:item.EdbInfoType,
+          LeadUnit:item.leadUnit,
+          LeadValue:Number(item.leadVal),
+          MaxData:item.maxData,
+          MinData:item.minData,
+          DateSequenceStr:item.timeSerial,
+          DataSequenceStr:item.valueSerial
+        })
+      })
+      params.ChartEdbInfoList=arr
+      // 检测选择的指标名称是否填写了
+      for (let index = 0; index < params.ChartEdbInfoList.length; index++) {
+        const item = params.ChartEdbInfoList[index];
+        if(!item.EdbName) return this.$message.warning(`第${index+1}个指标名称未填写`)
+      }
+
+      const res=this.editChartInfoId?await sheetInterface.editBalanceChart(params):await sheetInterface.addBalanceChart(params)
+      if(res.Ret===200){
+        this.$message.success(this.$t('MsgPrompt.add_msg2'));
+        this.initData()
+        this.$emit('success')
+      }
+    },
+    cancelHandle() {
+      this.$emit('update:isShow', false);
+      this.initData()
+    },
+
+    /* 领先指标 过滤负数 小数点*/
+    filterCode(item) {
+      item.leadVal = item.leadVal.replace(/[^\.\d]/g, '').replace('.', '');
+    },
+
+    // 获取图表公共的是否显示来源配置
+    async getChartCommonConfig(){
+      const res = await etaBaseConfigInterence.getBaseConfig()
+      if(res.Ret===200){
+        this.commonShowChartSource=res.Data.ChartSourceDisplay=='true'?true:false
+        this.formData.showChartSource=this.commonShowChartSource
+      }
+    }
+    
+
+  }
+}
+</script>
+
+<style lang="scss">
+.balance-add-chart-wrap {
+  .number-input {
+    input {
+      padding: 0;
+    }
+  }
+  .select_input .el-input__inner {
+       border: 2px dashed #18ad18;
+      border-radius: 4px;
+    }
+}
+    /*他不要下拉选择框 QAQ */
+.x-range-picker-date {
+	display: none;
+}
+.dia-bot{
+  text-align: center;
+}
+</style>
+<style lang="scss" scoped>
+@import "~@/styles/theme-vars.scss";
+.balance-add-chart-wrap {
+  width: 985px;
+  background: #fff;
+  position: fixed;
+  top: 20%;
+  // left: 50%;
+  right: 10%;
+  border-radius: 2px;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
+  z-index: 999;
+  overflow: hidden;
+  .el-input {
+    width: 100%;
+  }
+  .number-input {
+    input {
+      padding: 0;
+    }
+  }
+  div::-webkit-scrollbar {
+    width: 6px !important;
+  }
+  .header {
+    font-size: 16px;
+    background: $theme-color;
+    color: #fff;
+    padding: 15px;
+    display: flex;
+    align-content: center;
+    justify-content: space-between;
+    .el-icon-close {
+      font-size: 20px;
+      cursor: pointer;
+    }
+  }
+  .dia-bot {
+    padding-bottom: 40px;
+    display: flex;
+    justify-content: center;
+  }
+  .dialog-main {
+    padding: 25px;
+    max-height: 600px;
+    overflow-y: auto;
+    .item-tr {
+      .edb-tag-box {
+        display: inline-block;
+        line-height: 40px;
+        width: 80px;
+      }
+    }
+
+    @media screen and (max-height: 850px) {
+      box-sizing: border-box;
+      height: 65vh;
+      overflow-y: auto;
+    }
+    .el-cascader .el-input {
+      width: 340px;
+    }
+  }
+}
+
+</style>

+ 160 - 0
src/views/datasheet_manage/components/BalanceSheetChartItem.vue

@@ -0,0 +1,160 @@
+<template>
+    <div class="chart-item-wrap">
+        <div class="chart-item-box">
+            <div style="text-align:center">{{chartInfo.ChartName}}</div>
+            <Chart 
+                :options="options" 
+                :chartInfo="chartInfo" 
+                :index="chartInfo.ChartInfoId"
+                height="330px"
+                ref="chartRef"
+            />
+        </div>
+        <div class="opt-box">
+            <span v-if="JSON.parse(chartInfo.SourcesFrom).isShow">{{$t('Chart.Detail.source')}}:{{ JSON.parse(chartInfo.SourcesFrom).text}}</span>
+            <span></span>
+            <div>
+                <!-- 加入我的图库 -->
+                <span class="btn-o" @click="handleAddMyChart" v-if="!isStaticTable">{{$t('Chart.chart_addmy_btn')}}</span>
+                <!-- 编辑 -->
+                <span class="btn-o" v-if="!disabled" @click="handleEditChart">{{$t('Chart.chart_edit_btn')}}</span>
+                <!-- 删除 -->
+                <span class="btn-o" v-if="!disabled" style="color:#f00" @click="handleDelChart">{{$t('Chart.chart_del_btn')}}</span>
+            </div>
+        </div>
+
+        <!-- 加入我的图库弹窗 -->
+        <addMyClassifyDia
+            :isAddMyDialog="isAddMyChart"
+            :add_id="add_chart_id"
+            :add_ids="add_ids"
+            @cancel="isAddMyChart = false"
+            @addSuccess="addMySuccess"
+        />
+    </div>
+</template>
+
+<script>
+import { dataBaseInterface } from '@/api/api.js';
+import { chartSetMixin } from '@/views/dataEntry_manage/mixins/chartPublic'
+import Chart from '@/views/dataEntry_manage/components/chart';
+import addMyClassifyDia from '@/views/dataEntry_manage/components/addMyClassifyDia';
+export default {
+    components:{Chart,addMyClassifyDia},
+    props:{
+        chartData:{},
+        disabled: { //是否只预览
+            type: Boolean,
+            default: false,
+        },
+        isStaticTable:{
+            type: Boolean,
+            default: false,
+        }
+    },
+    mixins: [chartSetMixin],
+    watch: {
+        chartData:{
+            handler(nval){
+                console.log('图表数据',nval);
+                this.initData(nval)
+            },
+            deep:true,
+            immediate:true
+        }
+    },
+    data() {
+        return {
+            chartInfo: {}, //图表信息
+
+            isAddMyChart:false,//加入图库弹窗
+            add_chart_id: 0, //要加入的图表
+            add_ids:[],//加入时已有的分类
+        }
+    },
+    methods: {
+        initData(data){
+            this.chartInfo=data.ChartInfo
+            this.tableData=data.EdbInfoList
+            this.calendar_type=data.ChartInfo.Calendar
+            //初始化上下限
+            this.setLimitData(this.tableData)
+            this.tableData.length&&this.setChartOptionHandle(this.tableData)
+        },
+
+        // 编辑图表
+        handleEditChart(){
+            this.$emit('edit',this.chartData)
+        },
+
+        handleDelChart(){
+            this.$confirm(this.$t('ETable.Msg.is_del_balance_chart_msg') , this.$t('Confirm.prompt') , {
+                confirmButtonText:  this.$t('Dialog.confirm_btn'),
+                cancelButtonText: this.$t('Dialog.cancel_btn'),
+                type: "warning",
+            }).then(() => {
+                this.$emit('delete',this.chartData)
+            }).catch(() => {});
+            
+        },
+
+        /* 加入我的图库成功 */
+        addMySuccess(params){
+            this.isAddMyChart = false;
+            this.chartInfo.IsAdd = true;
+            this.chartInfo.MyChartId = params.MyChartInfoId;
+            this.chartInfo.MyChartClassifyId = params.MyChartClassifyId
+
+            // 如果没有图表图片则生成一次
+            if(!this.chartInfo.ChartImage) {
+                this.getChartImg()
+            }
+        },
+        async getChartImg(){
+            let svg = this.$refs.chartRef.chart.getSVG({
+                chart: {
+                width: 340,
+                height: 230,
+                }
+            });
+            let form = new FormData();
+            form.append('Img', svg);
+            let { Data } = await dataBaseInterface.uploadImgSvg(form);
+
+            await dataBaseInterface.setChartImage({
+                ChartInfoId: this.chartInfo.ChartInfoId,
+                ImageUrl: Data.ResourceUrl,
+            });
+        },
+
+        handleAddMyChart(){
+            this.add_chart_id = this.chartInfo.ChartInfoId;
+            //已有的分类ids
+            this.add_ids = this.chartInfo.MyChartClassifyId ? this.chartInfo.MyChartClassifyId.split(',').map(item => Number(item)) : [];
+            this.isAddMyChart = true;
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+.chart-item-wrap{
+    margin-bottom: 20px;
+    .chart-item-box{
+        padding: 10px;
+        border: 1px solid #C8CDD9;
+        border-radius: 8px;
+    }
+    .opt-box{
+        margin-top: 5px;
+        display: flex;
+        justify-content: space-between;
+        .btn-o{
+            display: inline-block;
+            margin-left: 5px;
+            cursor: pointer;
+            color: #0052D9;
+        }
+    }
+}
+</style>

+ 157 - 0
src/views/datasheet_manage/components/BalanceSheetList.vue

@@ -0,0 +1,157 @@
+<template>
+  <div style="flex: 1">
+    <div>{{$t('OnlineExcelPage.all_table_num',{count:total})}}</div>
+    <el-table border :data="list" height="calc(100vh - 150px)" ref="tableRef">
+      <el-table-column
+        v-for="item in tableColums"
+        :key="item.label"
+        :label="item.label"
+        :prop="item.key"
+        :width="item.width"
+        align="center"
+      >
+        <template slot-scope="{ row }">
+          <span v-if="item.key === 'ModifyTime'">{{
+            row.ModifyTime | getTime
+          }}</span>
+          <span v-else-if="item.key === 'ExcelName'" style="cursor: pointer;" @click="goDetail(row)">{{
+            row.ExcelName
+          }}</span>
+          <span v-else>{{ row[item.key] }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column
+        width="260"
+        align="center"
+        :label="$t('Table.column_operations')"
+      >
+        <template slot-scope="{ row }">
+          <span
+            class="editsty"
+            @click="itemHandle(row, 'edit')"
+            style="margin-right: 10px"
+            v-if="$parent.isSheetBtnShow('edit')&&row.Button.OpButton"
+            >{{row.CanEdit?$t("ETable.Btn.edit_btn"):row.Editor+$t('OnlineExcelPage.editing_msg')}}</span
+          >
+          <span
+            class="editsty"
+            @click="itemHandle(row, 'refresh')"
+            style="margin-right: 10px"
+            v-if="$parent.isSheetBtnShow('refresh')&&row.Button.RefreshButton"
+            >{{ $t("ETable.Btn.refresh_btn") }}</span
+          >
+          <span
+            class="editsty"
+            @click="itemHandle(row, 'save')"
+            style="margin-right: 10px"
+            v-if="$parent.isSheetBtnShow('otherSave')&&row.Button.CopyButton"
+            >{{ $t("ETable.Btn.save_as") }}</span
+          >
+          <span
+            class="editsty"
+            @click="itemHandle(row, 'download')"
+            style="margin-right: 10px"
+            v-if="$parent.isSheetBtnShow('download')&&row.HaveOperaAuth"
+            >{{ $t("ETable.Btn.download_btn") }}</span
+          >
+          <span
+            class="deletesty"
+            @click="itemHandle(row, 'del')"
+            style="margin-right: 10px"
+            v-if="$parent.isSheetBtnShow('del')&&row.Button.DeleteButton"
+            >{{ $t("Table.delete_btn") }}</span
+          >
+        </template>
+      </el-table-column>
+
+      <div slot="empty" style="padding: 50px 0 50px">
+        <tableNoData :text="$t('Confirm.prompt_slogan')" size="mini" />
+      </div>
+    </el-table>
+  </div>
+</template>
+
+<script>
+import * as sheetInterface from "@/api/modules/sheetApi.js";
+import BalanceTableMixin from '../mixins/balanceTableMixin'
+import moment from 'moment'
+export default {
+  mixins:[BalanceTableMixin],
+  props: {
+    total: {
+      type: Number
+    },
+    list: [],
+    finished: false,
+    loading: false
+  },
+  filters: {
+    getTime(e) {
+      return moment(e).format('YYYY-MM-DD HH:mm:ss')
+    }
+  },
+  computed: {
+    tableColums() {
+      return [
+        {
+          label: this.$t('ETable.BalanceSheetTable.name'),
+          key: 'ExcelName',
+        },
+        {
+          label: this.$t('ETable.BalanceSheetTable.creator'),
+          key: 'SysUserRealName',
+          width: '120px',
+        },
+        {
+          label: this.$t('ETable.BalanceSheetTable.updater'),
+          key: 'UpdateUserRealName',
+          width: '120px',
+        },
+        {
+          label: this.$t('ETable.BalanceSheetTable.update_time'),
+          key: 'ModifyTime',
+          width: '160px',
+        },
+      ]
+    }
+  },
+  data() {
+    return {
+      sheetRefreshing:false
+    }
+  },
+  mounted() {
+    this.$refs.tableRef.bodyWrapper.addEventListener('mousewheel', this.handleScroll)
+  },
+  beforeDestroy() {
+    this.$refs.tableRef.bodyWrapper.removeEventListener('mousewheel', this.handleScroll)
+  },
+  methods: {
+    //查看平衡表
+    goDetail(data){
+      this.$router.push({
+          path:'/viewBalanceSheet',
+          query:{
+            id:data.ExcelInfoId
+          }
+      })
+    },
+
+    handleScroll(event) {
+      const target = event.target;
+      //滚动方向
+      const scrollDirection = event.deltaY > 0 ? 'down' : 'up'
+      if (scrollDirection === 'up'||this.loading||this.finished) return
+      const dom = $('.el-table__body-wrapper')[0]
+      const { clientHeight, scrollTop, scrollHeight } = dom
+      // 计算是否到达底部
+      if (scrollHeight - (clientHeight + scrollTop) <= 200) {
+        this.$emit('loadMoreHandle')
+      }
+    },
+  },
+}
+</script>
+
+<style>
+</style>

+ 2083 - 0
src/views/datasheet_manage/components/BalanceTable.vue

@@ -0,0 +1,2083 @@
+<template>
+  <div class="table-wrapper" @keydown="handlekeyDownKeys">
+    <template v-if="config.data.length">
+      <!-- 工具栏 -->
+      <toolBarSection
+        v-if="!disabled"
+        :cell="selectCell"
+        @updateCell="updateCellStyle"
+      />
+
+      <!-- 公式显示区 -->
+      <div class="formula-wrapper" v-if="!disabled">
+        <span style="flex-shrink: 0; color: #c0c4cc">{{
+          $t("OnlineExcelPage.formula_lable")
+        }}</span>
+        <el-input
+          v-if="selectCell && selectCell.DataType === 6"
+          v-model="selectCell.Value"
+          @change="updateValueByFormula"
+        />
+      </div>
+      <!-- startSelectTable?'text-select-disabled111':'' -->
+      <div class="table-content-wrap">
+        <div class="left-wrap">
+          <div style="padding:20px;background-color: #fff;" @mouseleave="endSelection">
+          <div class="table-wrap">
+            <table
+              width="auto"
+              border="0"
+              class="table"
+              :style="disabled ? 'width:100%' : ''"
+            >
+              <thead>
+                <tr>
+                  <!-- 行头 -->
+                  <th class="th-tg sm"></th>
+
+                  <!-- 列头 -->
+                  <th
+                    v-for="(item, index) in columnHeader"
+                    :key="index"
+                    class="th-tg th-col"
+                    :data-cindex="item"
+                    :data-rindex="-1"
+                    @contextmenu.prevent="rightClickHandle"
+                  >
+                    {{ item }}
+                  </th>
+                </tr>
+              </thead>
+
+              <tbody>
+                <tr v-for="(row, index) in config.data" :key="index">
+                  <!-- 行头 -->
+                  <th
+                    class="th-tg th-row sm"
+                    @contextmenu.prevent="rightClickHandle"
+                    :data-rindex="rowHeader[index]"
+                    :data-cindex="-1"
+                  >
+                    {{ rowHeader[index] }}
+                  </th>
+
+                  <td
+                    v-for="(cell, cell_index) in row"
+                    :key="`${index}_${cell_index}`"
+                    :data-rindex="rowHeader[index]"
+                    :data-cindex="columnHeader[cell_index]"
+                    :data-key="cell.Uid"
+                    @click="clickCell($event, cell)"
+                    @dblclick="dblClickCellHandle($event, cell)"
+                    @contextmenu.prevent="rightClickHandle($event, cell)"
+                    @mouseenter="getRelationEdbInfo(cell)"
+                    @copy="copyCellHandle($event, cell)"
+                    @paste="pasteCellHandle($event, cell)"
+
+                    @mousedown="startSelection(index, cell_index)"
+                    @mouseover="extendSelection(index, cell_index)"
+                    @mouseup="endSelection"
+                    :class="{ 
+                      'td_selected': isSelected(index, cell_index),
+                      'text-select-disabled':startSelectTable
+                    }"
+                  >
+                    <!-- 插入单元格禁止编辑 -->
+                    <!-- [4,5,6,7,8].includes(cell.DataType)&&!cell.CanEdit -->
+                    <template
+                      v-if="
+                        !cell.CanEdit ||
+                        disabled ||
+                        (cell.DataType === 1 &&
+                          [1, 2].includes(cell.DataTimeType))
+                      "
+                    >
+                      <!-- 单元格类型5 7显示指标浮窗 -->
+                      <el-popover
+                        v-if="[5, 7].includes(cell.DataType) && !disabled"
+                        placement="top-start"
+                        width="350"
+                        trigger="hover"
+                      >
+                        <ul>
+                          <li style="display: flex; margin: 10px">
+                            <label style="min-width: 80px">{{
+                              $t("OnlineExcelPage.indicator_name_lbl")
+                            }}</label>
+                            {{ cellrelationEdbInfo.EdbName }}
+                          </li>
+                          <li style="display: flex; margin: 10px">
+                            <label style="min-width: 80px">{{
+                              $t("OnlineExcelPage.lastest_date_lab")
+                            }}</label>
+                            {{ cellrelationEdbInfo.LatestDate }}
+                          </li>
+                          <li style="display: flex; margin: 10px">
+                            <label style="min-width: 80px">{{
+                              $t("Table.edb_id")
+                            }}</label>
+                            {{ cellrelationEdbInfo.EdbCode }}
+                          </li>
+                        </ul>
+                        <span
+                          slot="reference"
+                          :data-rindex="rowHeader[index]"
+                          :data-cindex="columnHeader[cell_index]"
+                          :data-key="cell.Uid"
+                          >{{
+                            cell.ShowStyle
+                              ? cell.ShowFormatValue
+                              : cell.ShowValue
+                          }}</span
+                        >
+                      </el-popover>
+
+                      <!-- 数字格式化显示 -->
+                      <span
+                        v-else-if="cell.ShowStyle"
+                        :data-rindex="rowHeader[index]"
+                        :data-cindex="columnHeader[cell_index]"
+                        :data-key="cell.Uid"
+                      >
+                        {{ cell.ShowFormatValue }}
+                      </span>
+
+                      <span
+                        :data-rindex="rowHeader[index]"
+                        :data-cindex="columnHeader[cell_index]"
+                        :data-key="cell.Uid"
+                        v-else
+                        >{{ cell.ShowValue }}</span
+                      >
+                    </template>
+
+                    <el-autocomplete
+                      v-else
+                      v-model="cell.Value"
+                      :ref="`inputRef${cell.Uid}`"
+                      popper-class="edb-select-popover"
+                      :data-key="cell.Uid"
+                      :data-rindex="rowHeader[index]"
+                      :data-cindex="columnHeader[cell_index]"
+                      :fetch-suggestions="searchTarget"
+                      @change.native="changeVal($event, cell)"
+                      @keydown.native="keyEnterHandle($event, cell)"
+                      @blur="
+                        () => {
+                          $set(cell, 'CanEdit', false);
+                        }
+                      "
+                    >
+                      <!-- @select="selectTarget($event,cell)"
+                  @click="clickCell($event, cell)"
+                :highlight-first-item="cell.DataType===2"
+                 -->
+                      <template slot-scope="scope">
+                        <edbDetailPopover :info="scope.item">
+                          <div
+                            slot="reference"
+                            v-if="cell.DataType === 2"
+                            class="edb-item"
+                          >
+                            <span class="edb-item-name text_oneLine">{{
+                              scope.item.EdbName
+                            }}</span>
+                            <i
+                              class="el-icon-check"
+                              style="color: #0052d9; font-size: 18px"
+                            />
+                          </div>
+
+                          <div slot="reference" v-else>
+                            {{ scope.item.EdbName }}
+                          </div>
+                        </edbDetailPopover>
+                      </template>
+                    </el-autocomplete>
+                  </td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+          </div>
+          <!-- 底部sheet -->
+          <div class="bot-sheet-box">
+            <ul class="sheet-list">
+              <div
+                class="sheet-item"
+                v-for="(item, index) in sheetOpts"
+                :key="item.ExcelInfoId"
+                @contextmenu.prevent="handleShowSheetDel(index)"
+                @mouseleave="item.showDel=false"
+              >
+                <div class="del-box" v-show="item.showDel" @click="delChildSheet">
+                  <span>{{$t('Table.delete_btn')}}</span>
+                </div>
+
+                <div
+                  :class="['el-button el-button--default el-button--mini box',activeSheetId===item.ExcelInfoId?'active':'']"
+                  size="mini"
+                  @dblclick="handleDbclickSheet(item)"
+                  @click="clickChangeSheet(item)"
+                >
+                  <span class="text" v-if="!item.isEdit">{{ item.ExcelName }}</span>
+                  <input
+                    ref="sheetInput"
+                    v-else
+                    class="input"
+                    type="text"
+                    v-model="temSheetInputVal"
+                    @blur="handleModifySheetName"
+                    @keyup.enter="handleModifySheetName"
+                  />
+                </div>
+              </div>
+
+              <el-button
+                size="mini"
+                icon="el-icon-plus"
+                @click="handleAddSheet"
+                v-if="!disabled&&sheetOpts.length < 10"
+              ></el-button>
+            </ul>
+            <el-button type="text" icon="el-icon-plus" @click="isShowAddChart=true" v-if="!disabled">{{$t('Chart.add_chart_btn')}}</el-button>
+          </div>
+        </div>
+        <!-- 图表模块 -->
+        <div class="right-wrap" v-if="chartList.length>0">
+          <div class="chart-list">
+            <BalanceSheetChartItem 
+              :chartData="item"
+              :disabled="disabled"
+              :isStaticTable="isStaticTable"
+              v-for="item in chartList" 
+              :key="item.ChartInfo.ChartInfoId"
+              @edit="handleEditChart"
+              @delete="handleDelChart"
+
+            />
+          </div>
+          
+        </div>
+      </div>
+
+      <!-- 右键菜单 -->
+      <div
+        class="contextMenu-wrapper"
+        id="contextMenu-wrapper"
+        @mouseleave="
+          () => {
+            activeNames = [];
+            hideContextMenu();
+          }
+        "
+      >
+        <div
+          :class="['item', { deletesty: menu.key === 'reset' }]"
+          v-for="menu in config.contextMenuOption"
+          :key="menu.key"
+          @click="handleContext(menu.key)"
+        >
+          <span v-if="!menu.children">{{ menu.label }}</span>
+
+          <el-collapse
+            v-model="activeNames"
+            @change="handleChange"
+            v-if="menu.children"
+          >
+            <el-collapse-item name="1">
+              <template slot="title">
+                {{ menu.label }}
+              </template>
+
+              <div class="subMenu-wrapper">
+                <div
+                  slot="reference"
+                  class="item"
+                  v-for="submenu in menu.children"
+                  :key="submenu.key"
+                  @click="edbCalculateInsertOpen(submenu)"
+                >
+                  <el-popover width="300" trigger="hover" placement="right">
+                    <div v-html="formulaTip.get(submenu.fromEdbKey)"></div>
+                    <div slot="reference" style="width: 100%">
+                      {{ submenu.label }}
+                    </div>
+                  </el-popover>
+                </div>
+              </div>
+            </el-collapse-item>
+          </el-collapse>
+
+          <!-- 二级菜单 -->
+          <!-- <div class="subMenu-wrapper" v-if="menu.children">
+            <div slot="reference" class="item" v-for="submenu in menu.children" :key="submenu.key" @click="edbCalculateInsertOpen(submenu)">
+                <el-popover
+                  width="300"
+                  trigger="hover"
+                  placement="right"
+                >
+                  <div v-html="formulaTip.get(submenu.fromEdbKey)"></div>
+                  <div slot="reference" style="width:100%">{{submenu.label}}</div>   
+                </el-popover>
+            </div>
+          </div> -->
+        </div>
+      </div>
+    </template>
+
+    <div class="nodata" v-else>
+      <tableNoData :text="$t('Table.prompt_slogan')" />
+    </div>
+
+    <!-- 选择指标 -->
+    <selectTargetValueDia
+      :isShow.sync="isSelectTargetValueDialog"
+      :info="insertTargetValueInfo"
+      @insert="insertSelectData"
+      ref="selectTargetValueRef"
+    />
+
+    <!-- 插入系统/指标日期弹窗 -->
+    <insertDateDia
+      :isShow.sync="isInsertDateDialog"
+      :info="insertDateInfo"
+      @insert="insertDatehandle"
+    />
+
+    <!-- 指标计算弹窗 -->
+    <calculateEdbDia
+      ref="calculateEdbDiaRef"
+      :isShow.sync="isInsertCalculate"
+      :info="insertCalculateInfo"
+      @insert="insertCalculateData"
+    />
+
+    <!-- 日期计算弹窗 -->
+    <calculateDateDia
+      ref="calculateDateDiaRef"
+      :isShow.sync="isInsertCalculateDate"
+      :info="insertCalculateDateInfo"
+      @insert="insertCalculateDateValue"
+    />
+
+    <!-- 添加图表 -->
+    <BalanceAddChart
+      ref="balanceAddChart"
+      :isShow.sync="isShowAddChart"
+      :ExcelInfoId="activeSheetId"
+      @success="addChartSuccess"
+    />
+  </div>
+</template>
+<script>
+import {
+  getRowHeaderCode,
+  getColumnHeaderCode,
+  selectCellStyle,
+  selectMoreCellStyle,
+  setRelationStyle,
+  getRightClickMenu,
+  checkDateFormat,
+  setFocus,
+  findCellByKey,
+  resetRelationStyle,
+  resetDialogCellStyle,
+  extractFactorsFromFormula,
+  findCellByFactorMixed,
+  splitString,
+  toUpperCase,
+  findCellKeyByFactor,
+  isNumberVal,
+  transDecimalPlace
+} from "../common/customTable";
+import * as sheetInterface from "@/api/modules/sheetApi.js";
+import { dataBaseInterface } from '@/api/api.js';
+import md5 from '@/utils/md5.js';
+import selectTargetValueDia from './selectTargetValueDia.vue';
+import insertDateDia from './insertDateDia.vue';
+import calculateEdbDia from './calculateEdbDia.vue';
+import calculateDateDia from './calculateDateDia.vue';
+import toolBarSection from './toolBarSection.vue';
+import { formulaTip } from '@/views/dataEntry_manage/databaseComponents/util';
+import BalanceAddChart from './BalanceAddChart.vue';
+import BalanceSheetChartItem from './BalanceSheetChartItem.vue';
+
+let autoSaveInterval=null;//自动保存定时器
+let dblclickInterval=null;//双击事件的定时器 为了解决同一个元素双击事件重复触发单击事件的问题
+
+export default {
+  props: {
+    disabled: { //是否只预览
+      type: Boolean,
+      default: false,
+    },
+    isStaticTable:{//当前是否为静态表
+      type: Boolean,
+      default: false,
+    }
+  },
+  components: {
+    selectTargetValueDia,
+    insertDateDia,
+    calculateEdbDia,
+    calculateDateDia,
+    toolBarSection,
+    BalanceAddChart,
+    BalanceSheetChartItem
+  },
+  computed: {
+    //列头
+    columnHeader() {
+      return getColumnHeaderCode(
+        this.config.data[0] ? this.config.data[0].length : 0
+      );
+    },
+    //行头
+    rowHeader() {
+      let total_length = this.config.data.length;
+      // console.log(this.config.data)
+      return getRowHeaderCode(total_length);
+    },
+  },
+
+  data() {
+    return {
+      config: {
+        /* 单元格类型 
+          1手动日期格 DataTimeType 0 /系统日期导入格 DataTimeType 1  /指标日期导入格 DataTimeType 2
+          2指标格 //eta1.5.6又弃用了
+          3自定义输入 
+          4插入值 表格里有关联的日期和指标格  // eta1.1.6弃用了
+          5弹窗里的插入值 有关联日期格 
+          6公式计算单元格 
+          7指标计算的插入值单元格
+          8日期计算值单元格
+        */
+        data: [],
+        contextMenuOption: [],
+      },
+
+      selectCell: {},//选中单元格info
+
+      rightClickCell: {},//右键单元格 key c r
+
+      insertTargetCell: {},//选择右键插入时的单元格 可和右键单元格不一样 key c r
+
+      insertRelationArr: [], //表格单元格依赖关系数组
+
+      isSelectTargetValueDialog: false,//选择指标插入值弹窗
+      insertTargetValueInfo: {},//编辑 关联info
+
+      cellrelationEdbInfo: {}, //指标浮窗信息
+
+      copyCellItem: {},//复制时的单元格信息 用于粘贴赋值
+
+      calculateClickCell: null,//双击公式单元格时的单元格信息 用于之后选其他单元格拼接公式
+
+      isInsertDateDialog: false,//导入日期弹窗
+      insertDateInfo: {},
+
+      isInsertCalculate: false,//插入指标计算值
+      insertCalculateInfo: {},//指标计算单元格info
+
+      formulaTip,
+
+      hasInit: false,
+
+      isInsertCalculateDate: false,//日期计算弹窗
+      insertCalculateDateInfo: {},//日期计算info
+
+      activeNames: [],
+
+
+      sheetOpts: [
+        // {
+        //   ...
+        //   isEdit: false,//双击后修改名称置为true
+        //   showDel: false
+        // }
+      ],//表格sheet
+      temSheetInputVal: '',
+      activeSheetId:0,//当前子表id
+
+      isShowAddChart:false,//添加图表
+      chartList:[],//当前平衡表图表数据
+
+      startSelectTable:false,//开始选择单元格
+      selectionStart: null,
+      selectionEnd: null,
+      selectedCells: []
+    };
+  },
+  mounted() {
+    if(!this.disabled){
+      // 每分钟自动保存一次
+      autoSaveInterval=setInterval(() => {
+        this.saveChildSheet()
+      }, 60*1000);
+    }
+    
+  },
+  beforeDestroy(){
+    // 清除自动保存定时器
+    clearInterval(autoSaveInterval)
+  },
+  methods: {
+    // 获取图表数据
+    async getChartList(){
+      const res = await sheetInterface.getBalanceChartData({
+				ExcelInfoId: Number(this.activeSheetId)
+			})
+      if(res.Ret!==200) return 
+      this.chartList=res.Data.List||[]
+    },
+
+    // 添加图表成功回调
+    addChartSuccess(){
+      this.isShowAddChart=false
+      this.getChartList()
+    },
+
+    // 编辑图表
+    handleEditChart(e){
+      this.isShowAddChart=true
+      this.$refs.balanceAddChart.initEditData(e)
+    },
+    //删除图表
+    handleDelChart(e){
+      sheetInterface.delBalanceChart({ChartInfoId:e.ChartInfo.ChartInfoId}).then(res=>{
+        if(res.Ret===200){
+          this.chartList=this.chartList.filter(item=>item.ChartInfo.ChartInfoId!==e.ChartInfo.ChartInfoId)
+        }
+      })
+    },
+
+
+    startSelection(startRow, startCol) {
+      // 只有添加图标弹窗弹起时有效
+      if(!this.isShowAddChart) return
+      if(this.disabled) return
+      console.log('开始选择');
+      this.startSelectTable=true
+      this.selectionStart = { row: startRow, col: startCol };
+      this.selectionEnd = { row: startRow, col: startCol };
+      this.selectedCells = [];
+    },
+    extendSelection(endRow, endCol) {
+      if(this.disabled) return
+      if (this.selectionStart) {
+        const start = this.selectionStart;
+        const end = { row: endRow, col: endCol };
+        const minRow = Math.min(start.row, end.row);
+        const maxRow = Math.max(start.row, end.row);
+        const minCol = Math.min(start.col, end.col);
+        const maxCol = Math.max(start.col, end.col);
+        this.selectedCells = [];
+        for (let row = minRow; row <= maxRow; row++) {
+          for (let col = minCol; col <= maxCol; col++) {
+            this.selectedCells.push({ row, col });
+          }
+        }
+        this.selectionEnd = end;
+      }
+    },
+    // 选择表格结束
+    endSelection() {
+      // 只有添加图标弹窗弹起时有效
+      if(!this.isShowAddChart) return
+      if(this.disabled) return
+      console.log('结束选择');
+      // console.log(this.selectedCells);
+      // console.log(this.selectionStart,this.selectionEnd);
+      if(this.selectionStart){
+        // 找到当前sheet 数据
+        const sobj=this.sheetOpts.filter(_e=>_e.ExcelInfoId===this.activeSheetId)[0]
+        // 如果选择的不是同行或者同列 
+        if(!(this.selectionStart.col==this.selectionEnd.col||this.selectionStart.row==this.selectionEnd.row)){
+          this.$message.warning(this.$t('CustomAnalysisPage.only_allowed_select_msg'));
+          return
+        }
+        // 判断选择的顺序如果是从后往前选择交换 start 和end
+        if((this.selectionStart.col==this.selectionEnd.col&&this.selectionStart.row>this.selectionEnd.row)||(this.selectionStart.row==this.selectionEnd.row&&this.selectionStart.col>this.selectionEnd.col)){
+          const temStart=JSON.parse(JSON.stringify(this.selectionStart))
+          const temEnd=JSON.parse(JSON.stringify(this.selectionEnd))
+          this.selectionEnd=temStart
+          this.selectionStart=temEnd
+        }
+
+
+        const str=`${sobj.ExcelName}!$${this.columnHeader[this.selectionStart.col]}$${this.selectionStart.row+1}:$${this.columnHeader[this.selectionEnd.col]}$${this.selectionEnd.row+1}`
+        this.$refs.balanceAddChart.tableSelect(this.selectionStart,this.selectionEnd,str)
+      }
+      
+      this.selectionStart = null;
+      this.startSelectTable=false
+      this.removeTextSelection()
+    },
+    isSelected(row, col) {
+      return this.selectedCells.some(cell => cell.row === row && cell.col === col);
+    },
+
+    removeTextSelection() {
+        if (window.getSelection) {
+            if (window.getSelection().empty) {
+                // Chrome, Firefox, Opera
+                window.getSelection().empty();
+            } else if (window.getSelection().removeAllRanges) {
+                // IE/Edge
+                window.getSelection().removeAllRanges();
+            }
+        } else if (document.selection) { // for IE < 9
+            document.selection.empty();
+        }
+    },
+
+    // 点击添加sheet
+    async handleAddSheet() {
+      // 先自动保存一次
+      const flag=await this.saveChildSheet()
+      if(!flag) return
+      this.sheetOpts.push({
+        ExcelName: '',
+        ExcelInfoId:0,
+        isEdit: true,
+        showDel: false
+      })
+      this.temSheetInputVal = ''
+      // 自动切换到新增的sheet
+      this.changeSheet(this.sheetOpts[this.sheetOpts.length-1])
+      this.$nextTick(() => {
+        this.$refs.sheetInput[0].focus()
+      })
+    },
+    // 双击编辑sheet名称
+    handleDbclickSheet(item) {
+      if(this.disabled) return
+      clearTimeout(dblclickInterval)//清除双击事件的定时器
+      item.isEdit = true
+      this.temSheetInputVal = item.ExcelName
+      this.$nextTick(() => {
+        this.$refs.sheetInput[0].focus()
+      })
+    },
+    // 修改sheet名称
+    handleModifySheetName() {
+      console.log('修改名称');
+      // 名称为空
+      if (!this.temSheetInputVal) {
+        this.$confirm('图表名称未填写', '提示', {
+          confirmButtonText: '输入表名',
+          cancelButtonText: '取消创建',
+          type: 'warning'
+        }).then(() => {
+          this.$nextTick(() => {
+            this.$refs.sheetInput[0].focus()
+          })
+        }).catch(() => {
+          if(this.activeSheetId===0){//当是新增表格时
+            this.sheetOpts = this.sheetOpts.filter(e => e.ExcelInfoId)
+            // 自动切换sheet
+            this.changeSheet(this.sheetOpts[this.sheetOpts.length-1])
+
+          }else{// 当编辑子表名称时 重置掉好了
+            this.sheetOpts.forEach(_e=>{
+              _e.isEdit=false
+            })
+          }
+          
+        });
+
+        return
+      }
+      // 如果activeSheetId=0 则是新增的子表
+      if(this.activeSheetId===0){
+        this.createNewChildSheet()
+        return
+      }
+
+      // 修改sheet名称
+      sheetInterface.balanceChildTableRename({
+        ExcelName:this.temSheetInputVal,
+        ExcelInfoId:this.activeSheetId
+      }).then(res=>{
+        if(res.Ret===200){
+          this.sheetOpts.forEach(item => {
+            if (item.ExcelInfoId===this.activeSheetId) {
+              item.ExcelName = this.temSheetInputVal
+              item.isEdit = false
+            }
+          })
+        }
+      })
+      
+    },
+    // 右键显示删除sheet
+    handleShowSheetDel(index) {
+      if(this.disabled) return
+      if (this.sheetOpts.length === 1) return
+      this.sheetOpts[index].showDel = true
+      // 切换到该子表
+      this.changeSheet(this.sheetOpts[index])
+    },
+
+    // 初始化子表列表数据
+    initSheetListData(data){
+      console.log(data);
+      this.sheetOpts=data.map(item=>{
+        return{
+          ...item,
+          isEdit:false,
+          showDel:false
+        }
+      })
+      this.changeSheet(this.sheetOpts[0])
+    },
+
+    // 切换sheet
+    changeSheet(item){
+      this.activeSheetId=item.ExcelInfoId
+      this.getSheetDetail()
+    },
+
+    // 点击切换子表
+    async clickChangeSheet(item){
+      if(this.isShowAddChart){
+        this.$message.warning('添加图表时禁止切换')
+        return
+      }
+      clearTimeout(dblclickInterval)//清除双击事件的定时器
+      dblclickInterval=setTimeout(async () => {
+        if(item.ExcelInfoId===this.activeSheetId) return
+        //保存一次
+        const flag=this.disabled?true:await this.saveChildSheet()
+        if(!flag) return
+        this.changeSheet(item)
+      }, 150);
+      
+    },
+
+    /* 获取表格详情 */
+    async getSheetDetail(type) {
+      // 如果是新增一个子表此时为0 直接创建一个空表
+      if(this.activeSheetId===0) {
+        this.initData(null);
+        return
+      }
+
+      const res = await sheetInterface.sheetDetail({
+				ExcelInfoId: Number(this.activeSheetId)
+			})
+      if(type==='refresh'){
+        this.$parent.updating=false
+      }
+
+      if(res.Ret !== 200)  return
+      // this.isCanEdit = res.Data.CanEdit
+      // if(!res.Data.CanEdit){
+      //   this.$message.warning(`${res.Data.Editor}${this.$t('OnlineExcelPage.currently_editing_msg') }`)
+      //   setTimeout(()=>{
+      //     this.backHandle()
+      //   },2000)
+      //   return 
+      // }
+
+      const { ExcelName,ExcelClassifyId,TableData,ModifyTime,Button } = res.Data;
+      // this.sheetButton=Button
+      // this.sheetForm.name=ExcelName
+      // this.sheetForm.classify=ExcelClassifyId
+
+      // this.$nextTick(()=>{
+      //   this.sheetInit=true
+      // })
+      this.updateTime =  this.$moment(ModifyTime).format('YYYY-MM-DD HH:mm:ss')
+
+      this.initData(TableData);
+
+      // 获取平衡表中的图表
+      this.getChartList()
+      
+      type==='refresh' && this.$message.success(this.$t('OnlineExcelPage.table_data_update_msg') )
+    },
+
+    // 新增子表
+    async createNewChildSheet(){
+      // 判断是否重名
+      const isDupName=this.sheetOpts.some(e=>e.ExcelName===this.temSheetInputVal)
+      if(isDupName) {
+        this.$confirm('此名称已被使用,请尝试其他名称', this.$t('Dialog.warn_tit'), {
+          confirmButtonText: this.$t('Dialog.confirm_btn'),
+          type: 'warning',
+          showClose:false,
+          center:true,
+          showCancelButton:false
+        }).then(()=>{
+          this.$nextTick(() => {
+            this.$refs.sheetInput[0].focus()
+          })
+        })
+
+        return
+      }
+      const params={
+        ExcelName: this.temSheetInputVal,
+        ExcelType: 1,
+        ExcelImage: '',
+        ExcelClassifyId:0,//写死
+        Source: 5,
+        ParentId:Number(this.$route.query.id),
+        TableData: {
+          CellRelation:"[]",
+          Data:[]
+        }
+      }
+      const res=await sheetInterface.sheetAdd(params)
+      if(res.Ret===200){
+        this.changeSheet({ExcelInfoId:res.Data.ExcelInfoId})
+        // 更新sheetOpts 内容
+        this.sheetOpts.forEach(item=>{
+          if(item.ExcelInfoId===0){
+            item.ExcelInfoId=res.Data.ExcelInfoId
+            item.ExcelName=this.temSheetInputVal
+            item.isEdit=false
+          }
+        })
+      }else{
+        //创建子表失败 删除sheetOpts这个数据 并且切换到左边一个表
+        const index=this.sheetOpts.findIndex(_e=>_e.ExcelInfoId===this.activeSheetId)
+        this.changeSheet(this.sheetOpts[index-1])
+        this.sheetOpts.splice(index,1)
+      }
+    },
+
+    // 保存子表 type:manualSave 手动保存
+    async saveChildSheet(type){
+      console.log('执行保存表格操作');
+      const item=this.sheetOpts.filter(e=>e.ExcelInfoId===this.activeSheetId)[0]
+      // console.log(item);
+      // console.log(this.sheetOpts,this.activeSheetId);
+      if(!this.activeSheetId) return
+      const params={
+        ExcelInfoId:this.activeSheetId,
+        ExcelName: item.ExcelName,
+        ExcelType: 1,
+        ExcelClassifyId: 0,
+        ExcelImage:'',
+        Source: 5,
+        ParentId:Number(this.$route.query.id),
+        TableData: this.getSaveParams()
+      }
+      const res = await sheetInterface.sheetEdit(params)
+      if(res.Ret !==200) return false
+      if(res.Data.Status==1){//有人在编辑 不允许编辑返回到列表
+        this.$message.warning(res.Data.Msg)
+        setTimeout(() => {
+          this.$router.back()
+        }, 1000);
+        return false
+      }
+      // 更新保存时间
+      this.$parent.updateTime=this.$moment().format('YYYY-MM-DD HH:mm:ss')
+      type==='manualSave'&&this.$message.success(this.$t('MsgPrompt.saved_msg'))
+      return true
+    },
+
+    //删除子表
+    async delChildSheet(){
+      await this.$confirm(this.$t('ETable.Msg.is_del_table_msg') , this.$t('Confirm.prompt') , {
+        confirmButtonText:  this.$t('Dialog.confirm_btn'),
+        cancelButtonText: this.$t('Dialog.cancel_btn'),
+        type: "warning",
+      })
+      const res=await sheetInterface.classifyDel({
+        ExcelInfoId:this.activeSheetId
+      })
+      if(res.Ret!==200) return
+      this.$message.success(res.Msg);
+      const index=this.sheetOpts.findIndex(_e=>_e.ExcelInfoId===this.activeSheetId)
+      if(index===0){
+        this.changeSheet(this.sheetOpts[index+1])
+      }else{
+        this.changeSheet(this.sheetOpts[index-1])
+      }
+      this.sheetOpts.splice(index,1)
+    },
+
+    
+
+
+
+    /* 输入时实时搜索 满足日期格式不搜索 有=视为输入公式不搜索  eta1.5.6弃用了*/
+    async searchTarget(query, cb) {
+      return cb([])
+
+      //又要过滤掉2020-05-这样的奇葩其他格式 不让检索
+      let dateOtherRegex = /^(?:(?:19|20)\d\d)([-])(0[1-9]|1[0-2])(-?)$/
+      if (!query
+        || checkDateFormat(query)
+        || dateOtherRegex.test(query)
+        || query.startsWith('=')
+      ) return cb([])
+
+      const { DataType, EdbInfoId } = this.selectCell;
+
+      const res = DataType === 2
+        ? await dataBaseInterface.targetDetail({ EdbInfoId })
+        : await sheetInterface.searchTarget({
+          KeyWord: query,
+          CurrentIndex: 1,
+          PageSize: 1000
+        })
+      if (res.Ret !== 200) return
+
+      let arr = DataType === 2 ? [res.Data] : (res.Data.List || [])
+      cb(arr);
+    },
+
+    /* 单击 */
+    clickCell(e, cell) {
+      if (this.disabled) return
+
+      selectCellStyle(e);
+      this.selectCell = cell;
+
+      setFocus(e);
+
+      //是插值单元格时寻找关联依赖的单元格 设置选框
+      if ([4, 5, 7].includes(cell.DataType)) {
+        const { key } = e.target.dataset;
+        if (!this.insertRelationArr.find(_ => _.key === key)) return
+        let { relation_date, relation_edb } = this.insertRelationArr.find(_ => _.key === key)
+
+        relation_date.key && setRelationStyle(relation_date)
+        relation_edb.key && setRelationStyle(relation_edb)
+      }
+
+      //选择指标弹窗打开时选择日期更新弹窗数据
+      this.isSelectTargetValueDialog && this.$refs.selectTargetValueRef.changeRleationDate(this.selectCell)
+
+      //计算指标弹窗打开时选择日期更新弹窗数据
+      this.isInsertCalculate && this.$refs.calculateEdbDiaRef.changeRleationDate(this.selectCell)
+
+      //日期计算弹窗打开选中日期框时且有选中item时更新选中值
+      cell.DataType === 1 && this.isInsertCalculateDate && this.$refs.calculateDateDiaRef.selectIndex && this.$refs.calculateDateDiaRef.setSelectItemValue(this.selectCell)
+    },
+
+    /* 插入值 往左往上寻找同行同列是否有符合条件的一指标一日期 */
+    async insertValue() {
+
+      let params = this.findNearestCell();
+      console.log(params)
+      if (!params) {
+        this.selectCell.DataType = 3;
+        this.selectCell.DataTimeType = 0;
+        this.selectCell.ShowValue = '';
+        this.selectCell.Value = '';
+        this.selectCell.DataTime = '';
+        this.selectCell.EdbInfoId = 0;
+        this.$message.warning(this.$t('OnlineExcelPage.no_here_val_msg'));
+        return
+      }
+
+      const { EdbInfoId, Date, DataTimeType } = params
+
+      const res = await sheetInterface.insertData({ EdbInfoId, Date })
+      if (res.Ret !== 200) return
+
+
+      res.Data ? this.$message.success(this.$t('OnlineExcelPage.insert_success_msg')) : this.$message.warning(this.$t('OnlineExcelPage.the_date_no_val_msg'))
+
+      this.selectCell.DataType = 4;
+      this.selectCell.ShowValue = res.Data;
+      this.selectCell.Value = res.Data;
+      this.selectCell.EdbInfoId = EdbInfoId;
+      this.selectCell.DataTime = Date;
+
+      this.setRelation(params)
+    },
+
+    // 建立插入单元格和依赖单元格关联关系
+    setRelation(data, cellType = 4) {
+      const { insert_cell } = data;
+
+      let relation_obj = {
+        type: cellType,
+        key: insert_cell.key,
+        relation_date: {
+          type: 1,
+          key: insert_cell.relation_date
+        },
+        relation_edb: {
+          type: 2,
+          key: insert_cell.relation_edb
+        }
+      }
+
+      let haveIndex = this.insertRelationArr.findIndex(_ => _.key === insert_cell.key);
+      if (haveIndex === -1) {
+        this.insertRelationArr.push(relation_obj)
+      } else {
+        this.insertRelationArr.splice(haveIndex, 1, relation_obj)
+      }
+      console.log(this.insertRelationArr)
+    },
+
+    /* 向左向上找出所有格子 找出离插入单元格最近的两个符合条件的单元格 看是否满足一指标一日期的条件
+      不满足就无法插入值
+    */
+    findNearestCell() {
+      let { rindex, cindex, key } = this.rightClickCell;
+
+      let index_row = this.rowHeader.findIndex(_ => _ === rindex);
+      let index_col = this.columnHeader.findIndex(_ => _ === cindex);
+
+      //同行左侧所有格子
+      let row_cell_arr = this.config.data[index_row].filter((_, cell_index) => cell_index < index_col);
+      //同列上侧所有格子
+      let col_cell_arr = this.config.data.filter((row, row_index) => row_index < index_row).map(row => row[index_col]);
+
+      if (!row_cell_arr.length || !col_cell_arr.length) {
+        return null
+      }
+
+      //寻找最近的符合1 2类型的两个格子
+      let params = null;
+
+      for (let i = row_cell_arr.length - 1; i >= 0; i--) {
+        for (let j = col_cell_arr.length - 1; j >= 0; j--) {
+          if (!params) {
+            if ((row_cell_arr[i].DataType === 1 && col_cell_arr[j].DataType === 2)
+              || (row_cell_arr[i].DataType === 2 && col_cell_arr[j].DataType === 1)) {
+              params = {
+                DataTimeType: row_cell_arr[i].DataType === 1 ? row_cell_arr[i].DataTimeType : col_cell_arr[j].DataTimeType,
+                Date: row_cell_arr[i].DataType === 1 ? row_cell_arr[i].ShowValue : col_cell_arr[j].ShowValue,
+                EdbInfoId: row_cell_arr[i].DataType === 2 ? row_cell_arr[i].EdbInfoId : col_cell_arr[j].EdbInfoId,
+                insert_cell: {
+                  key,
+                  relation_date: row_cell_arr[i].DataType === 1 ? row_cell_arr[i].Uid : col_cell_arr[j].Uid,
+                  relation_edb: row_cell_arr[i].DataType === 2 ? row_cell_arr[i].Uid : col_cell_arr[j].Uid,
+                },
+              }
+              break
+            }
+          }
+        }
+      }
+      return params;
+
+    },
+
+    /* 选择指标 单元格类型为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)
+    },
+
+    /* 输入框失焦 设置单元格类型 处理关联关系 */
+    async changeVal(e, cell) {
+
+      // 是日期格式 DataType为1
+      // 自定义内容 DataType 3
+      //有=号为输入公式 DataType 6
+      const { value } = e.target;
+      if (!value) { //无值重置单元格
+        cell.DataType = 3;
+        cell.ShowValue = value;
+        cell.Value = value;
+        cell.EdbInfoId = 0;
+        cell.DataTime = '';
+        cell.Extra = ''
+      } else {
+        //指标类型不做格式处理
+        if (cell.DataType === 2) return
+
+        console.log(checkDateFormat(value))
+        let dateFormat = checkDateFormat(value);
+        if (dateFormat) { //是日期格式
+          cell.DataType = 1;
+          cell.Extra = '';
+          cell.ShowValue = dateFormat;
+          cell.DataTime = dateFormat;
+          cell.Value = dateFormat;
+        } else if (value.startsWith('=')) { //公式单元格
+          cell.DataType = 6;
+          let calculateVal = await this.getValueByFormula(value);
+          if (!calculateVal) return
+          cell.ShowValue = calculateVal;
+          //处理公式关系
+          this.$set(cell, 'Extra', this.dealFormulaConstruction(value))
+
+
+        } else {//自定义值
+          cell.DataType = 3;
+          cell.ShowValue = value;
+          cell.Value = value;
+          cell.EdbInfoId = 0;
+          cell.DataTime = '';
+          cell.Extra = ''
+        }
+      }
+
+      /* 不是数字类型,清除原来设置的格式 */
+      if (!isNumberVal(value)) {
+        cell.ShowStyle = '';
+        cell.ShowStyle = '';
+      };
+
+      //判断是否是有插入值的依赖单元格 更新值或重置关系
+      this.checkCellRelation(cell)
+    },
+
+    /* 当前单元格是否和插入值有关联 无就不管 */
+    async checkCellRelation(cell) {
+      if (!this.insertRelationArr.length) return
+
+      const key = cell.Uid;
+
+      //有关联的N组数组
+      let haveRelationArr = this.insertRelationArr.filter(_ => _.relation_date.key === key || _.relation_edb.key === key);
+
+      if (!haveRelationArr.length) return
+
+      //去处理每一组关联的情况
+      haveRelationArr.forEach(async (relation) => {
+        const { relation_date, relation_edb, type } = relation;
+
+        if ((relation_date.key === key && cell.DataType === 1) || (relation_edb.key === key && cell.DataType === 2)) { //单元格类型不变只变值仍有关联关系 更新值
+
+          //类型4的表格插值才调接口刷数据 之后关联的有其他类型插值 区分一下
+          if (type === 4) {
+
+            //刷新插入值结果
+            let params = null;
+            if (relation_date.key === key && cell.DataType === 1) { //修改的是依赖日期格
+              let { EdbInfoId } = findCellByKey(this.config.data, relation.key)
+              params = {
+                EdbInfoId,
+                Date: cell.ShowValue
+              }
+
+            } else if (relation_edb.key === key && cell.DataType === 2) { //修改的依赖指标格
+              let { ShowValue } = findCellByKey(this.config.data, relation_date.key)
+              params = {
+                EdbInfoId: cell.EdbInfoId,
+                Date: ShowValue
+              }
+            }
+
+            const res = await sheetInterface.insertData(params)
+            if (res.Ret !== 200) return
+
+            //现在日期无值也不清除关系了
+            // !res.Data && this.updateInsertCell(relation.key);
+
+            this.config.data.forEach(row => {
+              row.forEach(cell => {
+                if (cell.Uid === relation.key) {
+                  cell.DataType = relation.type;
+                  cell.ShowValue = res.Data;
+                  cell.Value = res.Data;
+                  cell.EdbInfoId = params.EdbInfoId;
+                  cell.DataTime = params.Date;
+                }
+              })
+            })
+          }
+
+
+        } else {
+          // 清除插入值单元格式和关联关系
+          this.updateInsertCell(relation.key);
+        }
+      })
+
+    },
+
+    // 清除插入值单元格式和关联关系
+    updateInsertCell(key) {
+      this.config.data.forEach(row => {
+        row.forEach(cell => {
+          if (cell.Uid === key) {
+            cell.DataType = 3;
+            cell.EdbInfoId = 0;
+            cell.DataTime = '';
+            cell.ShowValue = '';
+            cell.Value = '';
+            cell.ShowStyle = ''
+          }
+        })
+      })
+
+      let relationIndex = this.insertRelationArr.findIndex(_ => _.key === key)
+      this.insertRelationArr.splice(relationIndex, 1)
+    },
+
+    /* 输入公式的计算值 */
+    async getValueByFormula(val) {
+
+      // 提取因数数组
+      let factors = extractFactorsFromFormula(val)
+      console.log(factors)
+
+      //根据因数找单元格
+      let isAllCell = factors.some(_ => findCellByFactorMixed(this.config.data, _) === null || isNaN(findCellByFactorMixed(this.config.data, _)))
+      if (isAllCell) {
+        this.$message.warning(this.$t('OnlineExcelPage.formula_val_error_msg'))
+        return '';
+      }
+
+      let TagMap = {};
+      factors.forEach(_ => {
+        if (!TagMap[_]) {
+          TagMap[_] = Number(findCellByFactorMixed(this.config.data, _))
+        }
+      });
+
+      const res = await sheetInterface.calculateCustomCellData({
+        CalculateFormula: val,
+        TagMap
+      })
+      if (res.Ret !== 200) return
+      return res.Data
+    },
+
+    /* 顶部公式改变 */
+    async updateValueByFormula(value) {
+      this.changeVal({ target: { value } }, this.selectCell)
+    },
+
+    /* 右键 */
+    rightClickHandle(e, cell) {
+      if (this.disabled) return
+
+      const { rindex, cindex, key } = e.target.dataset;
+      this.rightClickCell = {
+        rindex,
+        cindex,
+        key
+      }
+
+      this.selectCell = cell;
+
+      let pos;
+      if (rindex === '-1') { //列头处
+        pos = 'col'
+      } else if (cindex === '-1') { //行头
+        pos = 'row'
+      } else {//单元格
+        pos = 'cell'
+      }
+      this.config.contextMenuOption = pos === 'cell'
+        ? getRightClickMenu(pos, (cell.DataType === 1 && [1, 2].includes(cell.DataTimeType)) || [5, 7, 8].includes(cell.DataType),this.isStaticTable)
+        : getRightClickMenu(pos)
+
+      this.$nextTick(() => {
+        let dom = $('#contextMenu-wrapper')[0];
+
+        if (e.clientY > window.innerHeight / 2) {
+          dom.style.left = e.clientX - 3 + 'px';
+          dom.style.top = e.clientY - dom.offsetHeight - 3 + 'px';
+        } else {
+          dom.style.left = e.clientX - 3 + 'px';
+          dom.style.top = e.clientY - 3 + 'px';
+        }
+
+        ['col', 'row'].includes(pos) && selectMoreCellStyle(e);
+        pos === 'cell' && this.clickCell(e, cell);
+
+      })
+
+    },
+
+    /*  */
+    hideContextMenu() {
+      const dom = $('#contextMenu-wrapper')[0];
+      dom.style.left = '-9999px';
+      dom.style.top = '-9999px';
+    },
+
+    /* 右键事件 */
+    async handleContext(key) {
+
+      //可右键编辑的单元格类型
+      let editHandlesMap = {
+        1: this.insertDateOpen,
+        5: this.selectTargetOpen,
+        7: this.edbCalculateInsertOpen,
+        8: this.insertDateCalculateOpen
+      }
+
+      const keyMap = {
+        'del': this.delColOrRow,//删除
+        'insert-col-left': this.insertCol,//向左插入列
+        'insert-col-right': this.insertCol,//向右插入列
+        'insert-row-up': this.insertRow,//向上插入行
+        'insert-row-down': this.insertRow,//向下插入行
+        'insert-value': this.insertValue,//插入值
+        'choose-target': this.selectTargetOpen,//选择指标插入值
+        'insert-date': this.insertDateOpen,//导入系统日期
+        // 'insert-edb-date': this.insertDateOpen,//导入指标日期
+        'insert-date-calculate': this.insertDateCalculateOpen,//日期计算弹窗
+        'reset': this.clearCell, //清空
+        'cell-edit': this.selectCell ? editHandlesMap[this.selectCell.DataType] : null
+      }
+      keyMap[key] && keyMap[key](key)
+
+      key !== 'insert-edb-calculate' && this.hideContextMenu()
+    },
+
+    /* 打开选择指标弹窗  
+    打开弹窗后仍可以在页面上点击 多存一个选择指标时的当前单元格信息 */
+    selectTargetOpen(type) {
+      this.insertTargetCell = this.selectCell;
+      resetDialogCellStyle();
+      setRelationStyle({ key: this.insertTargetCell.Uid }, 'td-choose-insert-target')
+      if (type === 'cell-edit') {
+        this.insertTargetValueInfo = {
+          ...this.insertTargetCell
+        }
+      } else {
+        this.insertTargetValueInfo = {}
+      }
+      this.isSelectTargetValueDialog = true;
+
+      this.resetDialogStatus('insertEdbVal')
+    },
+
+    /* 插入选择指标的值 */
+    insertSelectData({ edbId, value, relationDate, relationUid, str }) {
+
+      this.insertTargetCell.DataType = 5;
+      this.insertTargetCell.ShowValue = value;
+      this.insertTargetCell.Value = str;
+      this.insertTargetCell.EdbInfoId = edbId;
+      this.insertTargetCell.DataTime = relationDate;
+      this.insertTargetCell.ShowFormatValue = this.insertTargetCell.ShowStyle ? transDecimalPlace(value, JSON.parse(this.insertTargetCell.ShowStyle)) : '';
+
+      value ? this.$message.success(this.$t('ETable.Msg.insertion_success_msg')) : this.$message.warning(this.$t('ETable.Msg.date_no_data'))
+
+      //如果有关联表格日期就建立新的关联关系
+      if (relationDate && relationUid) {
+        let relation = {
+          insert_cell: {
+            key: this.insertTargetCell.Uid,
+            relation_date: relationUid,
+            relation_edb: '',
+          }
+        }
+
+        this.setRelation(relation, 5);
+      } else { //重新插值后之后原来有关联的清除关系
+        let haveIndex = this.insertRelationArr.findIndex(_ => _.key === this.insertTargetCell.Uid);
+        haveIndex !== -1 && this.insertRelationArr.splice(haveIndex, 1)
+        resetRelationStyle();
+      }
+
+    },
+
+    /* 清除单元格内容 格式 关联关系 */
+    clearCell() {
+      if ([4, 5].includes(this.selectCell.DataType)) resetRelationStyle();
+
+      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(this.selectCell)
+    },
+
+    /* 删除行列 */
+    delColOrRow() {
+      let { rindex, cindex } = this.rightClickCell;
+
+      if (rindex === '-1') { //删除列
+        console.log('删除列', cindex)
+
+        if (this.columnHeader.length === 1) return this.$message.warning(this.$t('OnlineExcelPage.keep_one_column_msg'))
+
+        let index = this.columnHeader.findIndex(_ => _ === cindex);
+
+        //删除时清除关系
+        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)
+        })
+      } 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)
+
+        if (this.insertRelationArr.length) {
+          //删除时清除关系
+          let delCellIds = this.config.data[index].map(cell => cell.Uid);
+
+          this.clearRelationInsertCell(delCellIds);
+        }
+
+        this.config.data.splice(index, 1)
+
+      }
+    },
+
+    /* 删除时清除关联关系 和删除单元格有关联的插入值单元格和 */
+    clearRelationInsertCell(delCellIds) {
+      //清除关联插入值得单元格
+      let haveRelationArr = this.insertRelationArr.filter(_ => delCellIds.includes(_.relation_date.key) || delCellIds.includes(_.relation_edb.key));
+      // console.log(haveRelationArr)
+
+      haveRelationArr.forEach(relation => {
+        !delCellIds.includes(relation) && this.updateInsertCell(relation.key);
+      })
+
+      this.insertRelationArr = this.insertRelationArr.filter(_ => !delCellIds.includes(_.key) && !delCellIds.includes(_.relation_date.key) && !delCellIds.includes(_.relation_edb.key))
+    },
+
+    /* 插入列 */
+    insertCol(key) {
+      let { cindex } = this.rightClickCell;
+
+      let index = this.columnHeader.findIndex(_ => _ === cindex);
+
+      this.config.data.forEach((row, rindex) => {
+        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}`)
+        })
+      })
+
+    },
+
+    /* 插入行 */
+    insertRow(key) {
+      let { rindex } = this.rightClickCell;
+
+      let index = this.rowHeader.findIndex(_ => _ === rindex)
+
+      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}`)
+      }));
+
+      this.config.data.splice(key === 'insert-row-up' ? index : index + 1, 0, row)
+
+    },
+
+    /* 单元格类型5 浮到上面展示指标信息浮窗 */
+    async getRelationEdbInfo({ EdbInfoId, DataType }) {
+      if (![5, 7].includes(DataType) || this.disabled) return
+
+      const res = await dataBaseInterface.targetDetail({ EdbInfoId })
+
+      if (res.Ret !== 200) return
+
+      this.cellrelationEdbInfo = res.Data;
+    },
+
+    /* 导入系统/指标日期弹窗 */
+    insertDateOpen(type) {
+      this.insertTargetCell = this.selectCell;
+      resetDialogCellStyle();
+
+      if (type === 'cell-edit') { //编辑日期
+        this.insertDateInfo = {
+          ...this.insertTargetCell
+        }
+      } else {
+        this.insertDateInfo = {
+          // key:type
+        }
+      }
+      this.isInsertDateDialog = true;
+      this.resetDialogStatus();
+    },
+
+    /* 弹窗都是无遮罩的 弹一个就重置其他的 */
+    resetDialogStatus(type = 'init') {
+      if (type !== 'insertEdbVal') {
+        this.$refs.selectTargetValueRef && this.$refs.selectTargetValueRef.initData();
+        this.isSelectTargetValueDialog = false;
+      }
+      if (type !== 'insertEdbCalculateVal') {
+        this.$refs.calculateEdbDiaRef && this.$refs.calculateEdbDiaRef.initData();
+        this.isInsertCalculate = false;
+      }
+      if (type !== 'insertDateCalculateVal') {
+        this.$refs.calculateDateDiaRef && this.$refs.calculateDateDiaRef.initData();
+        this.isInsertCalculateDate = false;
+      }
+      if (type !== 'balanceAddChart') {
+        this.$refs.balanceAddChart && this.$refs.balanceAddChart.initData();
+        this.isShowAddChart = false;
+      }
+    },
+
+    /* 插入系统/指标日期 */
+    insertDatehandle({ insertValue, dataTimeType, str }) {
+
+      this.insertTargetCell.DataType = 1;
+      this.insertTargetCell.DataTimeType = dataTimeType;
+      this.insertTargetCell.ShowValue = insertValue;
+      this.insertTargetCell.Value = str;
+      this.insertTargetCell.EdbInfoId = 0;
+      this.insertTargetCell.DataTime = insertValue;
+    },
+
+    /* 指标计算弹窗 */
+    edbCalculateInsertOpen(item) {
+      this.insertTargetCell = this.selectCell;
+      resetDialogCellStyle();
+      setRelationStyle({ key: this.insertTargetCell.Uid }, 'td-choose-insert-target');
+
+      if (item === 'cell-edit') { //编辑
+        const { Value } = this.insertTargetCell;
+
+        let menuInfo = this.config.contextMenuOption
+          .find(_ => _.key === 'insert-edb-calculate').children
+          .find(menu => menu.source === JSON.parse(Value).Source);
+
+        this.insertCalculateInfo = {
+          ...menuInfo,
+          ...this.insertTargetCell
+        }
+      } else {
+        this.insertCalculateInfo = {
+          ...item
+        }
+      }
+      this.isInsertCalculate = true;
+
+      this.resetDialogStatus('insertEdbCalculateVal')
+    },
+
+    /* 导入指标计算值 */
+    insertCalculateData(item) {
+      // console.log(item)
+      const { InsertValue, EdbInfoId, Str, relationDate, relationUid } = item;
+      this.insertTargetCell.DataType = 7;
+      this.insertTargetCell.ShowValue = InsertValue;
+      this.insertTargetCell.Value = Str;
+      this.insertTargetCell.EdbInfoId = EdbInfoId;
+      this.insertTargetCell.DataTime = relationDate;
+      this.insertTargetCell.ShowFormatValue = this.insertTargetCell.ShowStyle ? transDecimalPlace(InsertValue, JSON.parse(this.insertTargetCell.ShowStyle)) : '';
+
+      InsertValue ? this.$message.success(this.$t('ETable.Msg.insertion_success_msg')) : this.$message.warning(this.$t('ETable.Msg.date_no_data'))
+
+      //如果有关联表格日期就建立新的关联关系
+      if (relationDate && relationUid) {
+        let relation = {
+          insert_cell: {
+            key: this.insertTargetCell.Uid,
+            relation_date: relationUid,
+            relation_edb: '',
+          }
+        }
+
+        this.setRelation(relation, 7);
+      } else { //重新插值后之后原来有关联的清除关系
+        let haveIndex = this.insertRelationArr.findIndex(_ => _.key === this.insertTargetCell.Uid);
+        haveIndex !== -1 && this.insertRelationArr.splice(haveIndex, 1)
+        resetRelationStyle();
+      }
+    },
+
+    /* 日期计算弹窗 */
+    insertDateCalculateOpen(type) {
+      this.insertTargetCell = this.selectCell;
+      resetDialogCellStyle()
+      setRelationStyle({ key: this.insertTargetCell.Uid }, 'td-choose-insert-target')
+
+      if (type === 'cell-edit') { //编辑
+        this.insertCalculateDateInfo = {
+          ...this.insertTargetCell
+        }
+      } else {
+        this.insertCalculateDateInfo = {}
+      }
+      this.isInsertCalculateDate = true;
+      this.resetDialogStatus('insertDateCalculateVal');
+    },
+
+    /* 插入日期计算值 */
+    insertCalculateDateValue(data) {
+      const { insertValue, str } = data;
+      this.insertTargetCell.DataType = 8;
+      this.insertTargetCell.ShowValue = insertValue;
+      this.insertTargetCell.Value = str;
+      this.insertTargetCell.EdbInfoId = 0;
+      this.insertTargetCell.DataTime = '';
+      this.insertTargetCell.ShowFormatValue = this.insertTargetCell.ShowStyle ? transDecimalPlace(insertValue, JSON.parse(this.insertTargetCell.ShowStyle)) : '';
+
+      this.$message.success(this.$t('ETable.Msg.insertion_success_msg'))
+    },
+
+    /* 初始化8行5列 */
+    initData(initData = null) {
+      console.log('initData');
+      this.hasInit = false
+      if (initData&&initData.Data.length>0) {
+        const { CellRelation, Data } = initData;
+        this.config.data = Data;
+        this.insertRelationArr = JSON.parse(CellRelation);
+      } else {
+
+        this.config.data = new Array(8).fill("").map((_, _rindex) => {
+          return new Array(5).fill("").map((cell, _cindex) => ({
+            ShowValue: "",
+            ShowStyle: '',
+            ShowFormatValue: '',
+            Value: "",
+            DataType: 3,
+            DataTimeType: 0,
+            DataTime: "",
+            EdbInfoId: 0,
+            Uid: md5.hex_md5(`${new Date().getTime()}${_rindex}${_cindex}`)
+          }));
+        });
+      }
+      this.$nextTick(() => {
+        this.hasInit = true
+      })
+    },
+
+    /* 处理因数结构 =a1+b1 => [{ Tag: a,Row:1,Key:'' }] */
+    dealFormulaConstruction(val) {
+      // 提取因数数组
+      let factors = extractFactorsFromFormula(val)
+      let arr = factors.map(str => ({
+        Tag: splitString(toUpperCase(str))[0],
+        Row: splitString(toUpperCase(str))[1],
+        Key: findCellKeyByFactor(str)
+      }))
+      return JSON.stringify(arr)
+    },
+
+
+    /* 要支持复制粘贴把公式也带过去 公式单元格类型为6 其余就正常复制文本 */
+    copyCellHandle(e, cell) {
+      this.copyCellItem = cell;
+      // 阻止默认的复制操作
+      e.preventDefault();
+    },
+
+    /* 要支持复制粘贴把公式也带过去 公式单元格类型为6 其余就正常复制文本 */
+    pasteCellHandle(e, cell) {
+      if (this.copyCellItem.DataType === 6) {
+        cell.DataType = this.copyCellItem.DataType;
+        cell.ShowValue = this.copyCellItem.ShowValue;
+        cell.Value = this.copyCellItem.Value;
+        cell.DataTime = this.copyCellItem.DataTime;
+        cell.EdbInfoId = this.copyCellItem.EdbInfoId;
+        cell.ShowStyle = this.copyCellItem.ShowStyle;
+        cell.ShowFormatValue = this.copyCellItem.ShowFormatValue;
+      } else {
+        cell.DataType = 3;
+        cell.ShowValue = this.copyCellItem.ShowValue;
+        cell.Value = this.copyCellItem.ShowValue;
+        cell.ShowStyle = this.copyCellItem.ShowStyle;
+        cell.ShowFormatValue = this.copyCellItem.ShowFormatValue;
+        cell.DataTime = '';
+        cell.EdbInfoId = 0;
+      }
+
+      // 阻止默认的粘贴操作
+      e.preventDefault();
+    },
+
+    /* 单元格enter失焦 */
+    keyEnterHandle(e, cell) {
+      if (e.keyCode === 13) {
+        //非得搞个要回车失焦
+        e.target.nodeName && e.target.blur();
+        this.$refs[`inputRef${e.target.dataset.key}`] && this.$refs[`inputRef${e.target.dataset.key}`][0].close()
+
+        // cell.DataType===6 && this.$set(cell,'CanEdit',false)
+        // this.$set(cell,'CanEdit',false)
+      }
+    },
+
+    /* 双击切换状态 插值单元格不允许切换 可切换类型1,2,3,6*/
+    dblClickCellHandle(e, cell) {
+      if (this.disabled || ![1, 2, 3, 6].includes(cell.DataType) || [1, 2].includes(cell.DataTimeType)) return
+
+      this.$set(cell, 'CanEdit', true)
+      console.log(cell)
+
+      this.$nextTick(() => {
+        if (e.target.childNodes[0].childNodes[0].childNodes[1].nodeName === 'INPUT') e.target.childNodes[0].childNodes[0].childNodes[1].focus();
+      })
+    },
+
+    /* 处理保存的参数 */
+    getSaveParams() {
+      const { data } = this.config;
+
+      let params = {
+        CellRelation: JSON.stringify(this.insertRelationArr),
+        Data: data
+      }
+
+      return params
+    },
+
+    /* tab禁掉 */
+    handlekeyDownKeys(e) {
+      if (e.keyCode === 9) {
+        e.preventDefault();
+      }
+    },
+
+    /* 改变单元格显示文本 */
+    updateCellStyle({ ShowStyle, ShowFormatValue }) {
+
+      this.$set(this.selectCell, 'ShowStyle', ShowStyle)
+      this.$set(this.selectCell, 'ShowFormatValue', ShowFormatValue)
+    }
+  },
+};
+</script>
+<style scoped lang="scss">
+.nodata {
+  text-align: center;
+  font-size: 16px;
+  color: #666;
+  padding: 100px 0;
+}
+.table-wrapper {
+  width: 100%;
+  overflow: auto;
+  .table-content-wrap {
+    display: flex;
+    .left-wrap {
+      flex: 1;
+      overflow: hidden;
+      .text-select-disabled{
+        -webkit-user-select: none;
+        -moz-user-select: none;
+        -ms-user-select: none;
+        user-select: none;
+      }
+    }
+    .right-wrap {
+      width: 400px;
+      margin-left: 20px;
+      flex-shrink: 0;
+      .chart-list{
+        background-color: #fff;
+        height: 100%;
+        height: calc(100vh - 440px);
+        overflow-y: auto;
+        padding: 20px;
+      }
+    }
+  }
+  .table-wrap {
+    width: 100%;
+    background-color: #fff;
+    // padding: 20px;
+    height: calc(100vh - 480px);
+    overflow: auto;
+  }
+  .bot-sheet-box {
+    margin-top: 20px;
+    display: flex;
+    justify-content: space-between;
+    .sheet-list {
+      flex: 1;
+      font-size: 12px;
+      display: flex;
+      align-items: center;
+      flex-wrap: wrap;
+      gap: 10px;
+      .sheet-item {
+        position: relative;
+        .del-box {
+          position: absolute;
+          background-color: #fff;
+          padding: 5px;
+          top: -22px;
+          right: -16px;
+          z-index: 10;
+          width: 40px;
+          text-align: center;
+          cursor: pointer;
+        }
+      }
+      .input {
+        width: 75px;
+        background-color: transparent;
+        border: none;
+        box-sizing: border-box;
+        color: #0033ff;
+        text-align: center;
+      }
+      .box {
+        max-width: 120px;
+        min-width: 75px;
+        text-align: center;
+        background-color: #eff4ff;
+        .text {
+          display: block;
+          overflow: hidden;
+          white-space: nowrap;
+          text-overflow: ellipsis;
+        }
+      }
+      .active {
+        background-color: #fff;
+        color: #0033ff;
+      }
+    }
+  }
+
+  .formula-wrapper {
+    height: 42px;
+    display: flex;
+    align-items: center;
+    background: #fff;
+    border-radius: 4px;
+    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
+    border: 1px solid #dcdfe6;
+    margin-bottom: 15px;
+    padding: 0 15px;
+  }
+  .table td,
+  th {
+    width: 104px;
+    min-width: 104px;
+    height: 35px;
+    max-height: 35px;
+    background: #fff;
+    text-align: center;
+    word-break: break-all;
+    border: 1px solid #dcdfe6;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    position: relative;
+    color: #606266;
+
+    &.td-chose::after {
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      content: "";
+      display: block;
+      outline: 0;
+      border: 2px solid #0033ff;
+      box-shadow: 0 0 5px rgba(73, 177, 249, 0.5);
+    }
+    &.td-relation::after {
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      content: "";
+      display: block;
+      outline: 0;
+      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-choose-insert-target::after {
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      content: "";
+      display: block;
+      outline: 0;
+      border: 2px dashed orange;
+      box-shadow: 0 0 5px rgba(73, 177, 249, 0.5);
+    }
+  }
+
+  .th-tg {
+    background: #ebeef5;
+    &:hover {
+      cursor: pointer;
+      background: #ddd;
+      /* border: 2px solid #409eff; */
+    }
+    &.sm {
+      width: 36px;
+      min-width: 36px;
+      max-width: 36px;
+    }
+  }
+  //整行选中
+  tr {
+    position: relative;
+    &.choose-all::after {
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      content: "";
+      display: block;
+      outline: 0;
+      border: 2px solid #5897fb;
+      box-shadow: 0 0 5px rgba(73, 177, 249, 0.5);
+    }
+  }
+
+  .td_selected{
+    background-color: #F5F7F9!important;
+  }
+
+  .contextMenu-wrapper {
+    position: fixed;
+    z-index: 99;
+    top: -9999px;
+    left: -9999px;
+    background: #fff;
+    padding: 10px 0;
+    min-width: 180px;
+    max-height: 400px;
+    overflow-y: auto;
+    /* border: 1px solid #999; */
+    box-shadow: 0 1px 4px #999;
+    .item {
+      padding: 10px 25px;
+      cursor: pointer;
+      &:hover {
+        background-color: #f5f7fa;
+      }
+      &:hover .subMenu-wrapper {
+        display: block;
+      }
+    }
+
+    .subMenu-wrapper {
+      width: 180px;
+      /* display: none; */
+      padding: 10px 0;
+      /* box-shadow: 0 1px 4px #999; */
+      /* background: #fff; */
+      /* position: absolute;
+      right: -178px;
+      top:-205px;
+      max-height: 400px;
+      overflow-y: auto; */
+      .item {
+        &:hover {
+          background: #fff;
+        }
+      }
+    }
+  }
+}
+</style>
+<style lang="scss">
+.table-wrapper {
+  td {
+    .el-input__inner {
+      border: none;
+      outline: none;
+      text-align: center;
+      height: 34px;
+      line-height: 34px;
+    }
+  }
+  .el-input.is-disabled .el-input__inner {
+    background-color: #fff;
+  }
+  .bot-sheet-box {
+    .el-button + .el-button {
+      margin-left: 0;
+    }
+  }
+}
+.formula-wrapper .el-input__inner {
+  border: none;
+  outline: none;
+}
+.edb-select-popover {
+  width: 300px !important;
+  .edb-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    .edb-item-name {
+      max-width: 260px;
+    }
+  }
+}
+.el-collapse {
+  border: none !important;
+  .el-collapse-item__header {
+    padding: 0;
+    height: auto;
+    line-height: normal;
+    margin-bottom: 0 !important;
+    background: transparent !important;
+  }
+  .el-collapse-item__wrap {
+    background: transparent !important;
+    border: none !important;
+  }
+  .el-collapse-item__content {
+    padding: 0 !important;
+  }
+}
+</style>

+ 22 - 5
src/views/datasheet_manage/components/MixedTable.vue

@@ -255,6 +255,12 @@ export default {
     disabled: { //是否只预览
       type: Boolean,
       default: false,
+    },
+    sourceFrom:{
+      type: Object,
+      default: ()=>{
+        return {}
+      },
     }
   },
   components: { 
@@ -892,7 +898,7 @@ export default {
     },
 
     /* 插入选择指标的值 */
-    insertSelectData({ edbId,value,relationDate,relationUid,str }) {
+    insertSelectData({ edbId,value,relationDate,relationUid,str,sourceName }) {
 
       this.insertTargetCell.DataType = 5;
       this.insertTargetCell.ShowValue = value;
@@ -903,6 +909,7 @@ export default {
 
       value ? this.$message.success(this.$t('ETable.Msg.insertion_success_msg')) : this.$message.warning(this.$t('ETable.Msg.date_no_data'))
 
+      this.updateSourceFrom(sourceName)
       //如果有关联表格日期就建立新的关联关系
       if(relationDate&&relationUid) {
         let relation = {
@@ -1075,7 +1082,9 @@ export default {
     },
 
     /* 插入系统/指标日期 */
-    insertDatehandle({insertValue,dataTimeType,str}) {
+    insertDatehandle({insertValue,dataTimeType,str,sourceName}) {
+
+      this.updateSourceFrom(sourceName)
 
       this.insertTargetCell.DataType = 1;
       this.insertTargetCell.DataTimeType = dataTimeType;
@@ -1115,7 +1124,7 @@ export default {
     /* 导入指标计算值 */
     insertCalculateData(item) {
       // console.log(item)
-      const { InsertValue,EdbInfoId,Str,relationDate,relationUid } = item;
+      const { InsertValue,EdbInfoId,Str,relationDate,relationUid,sourceName } = item;
       this.insertTargetCell.DataType = 7;
       this.insertTargetCell.ShowValue = InsertValue;
       this.insertTargetCell.Value = Str;
@@ -1125,6 +1134,8 @@ export default {
 
       InsertValue ? this.$message.success(this.$t('ETable.Msg.insertion_success_msg')) : this.$message.warning(this.$t('ETable.Msg.date_no_data'))
 
+      this.updateSourceFrom(sourceName)
+
       //如果有关联表格日期就建立新的关联关系
       if(relationDate&&relationUid) {
         let relation = {
@@ -1175,14 +1186,12 @@ export default {
 
     /* 初始化8行5列 */
     initData(initData=null) {
-      console.log('initData');
       this.hasInit=false
       if(initData) {
         const { CellRelation,Data } = initData;
         this.config.data = Data;
         this.insertRelationArr = JSON.parse(CellRelation);
       }else {
-
         this.config.data = new Array(8).fill("").map((_,_rindex) => {
           return new Array(5).fill("").map((cell,_cindex) => ({
             ShowValue: "",
@@ -1294,6 +1303,14 @@ export default {
       
       this.$set(this.selectCell,'ShowStyle',ShowStyle)
       this.$set(this.selectCell,'ShowFormatValue',ShowFormatValue)
+    },
+    // 更新数据来源
+    updateSourceFrom(source){
+      if(!source) return
+      let concatSourceArr = this.sourceFrom.text?`${this.sourceFrom.text},${source}`.split(','):[source];
+      let sourceStr = Array.from(new Set(concatSourceArr)).join(',');
+      this.sourceFrom.text=sourceStr
+      this.$emit('updateSourceName')
     }
   },
 };

+ 12 - 4
src/views/datasheet_manage/components/calculateEdbDia.vue

@@ -368,7 +368,7 @@ export default {
         MoveForward: 0,
         relationDate: '',//关联的表格日期
         relationUid: '',//关联格子的uid
-      }
+      },
     }
   },
   mounted(){
@@ -452,6 +452,13 @@ export default {
       const res = await sheetInterface.getMixedCalculateData(params)
       if(res.Ret!==200) return 
 
+      let baseSourceName=''
+      await sheetInterface.getEdbBaseSource({EdbInfoId:this.selectEdbInfo.EdbInfoId}).then(res=>{
+        if(res.Ret == 200){
+          // 获取原始指标的来源
+          baseSourceName = res.Data.ExcelSource || ''
+        }
+      })
       this.showResult = true;
       
       this.chooseItem = {
@@ -459,7 +466,8 @@ export default {
         relationUid: this.dateSelectForm.Type===2 ? this.dateSelectForm.relationUid : '',
         EdbInfoId: this.selectEdbInfo.EdbInfoId,
         InsertValue: res.Data.ShowValue||"",
-        Str: JSON.stringify(params)
+        Str: JSON.stringify(params),
+        sourceName:baseSourceName||''
       }
 
       // if(!this.calculateShowData.length) return this.$message.warning('该日期无数据')
@@ -482,8 +490,9 @@ export default {
         : await dataBaseInterface.targetList({EdbInfoId:e.EdbInfoId,CurrentIndex: 1})
 
       if(res.Ret !== 200) return
+      
+      const { EdbInfoId,EdbCode,EdbName,Frequency,Unit,StartDate,ModifyTime,PredictDataList,DataList,HaveOperaAuth } = res.Data.Item;
 
-      const { EdbInfoId,EdbCode,EdbName,Frequency,Unit,StartDate,ModifyTime,SourceName,PredictDataList,DataList,HaveOperaAuth } = res.Data.Item;
       this.selectEdbInfo = {
         EdbCode,
         EdbName,
@@ -491,7 +500,6 @@ export default {
         Unit,
         StartDate,
         ModifyTime,
-        SourceName,
         EdbInfoId,
         HaveOperaAuth,
         DataList: PredictDataList ? [...PredictDataList,...DataList].slice(0,5) : DataList.slice(0,5)

+ 19 - 4
src/views/datasheet_manage/components/insertDateDia.vue

@@ -7,7 +7,7 @@
 		@close="cancelHandle"
 		custom-class="dialog"
 		center
-		width="650px"
+		width="750px"
 		v-dialogDrag>
 			<div class="dialog-main">
 
@@ -151,22 +151,37 @@ export default {
       let backData = {}
       //插入系统日期
       // if(this.info.key==='insert-sys-date') {
-
+        // console.log(this.selectEdbInfo,'this.selectEdbInfo');
+        // return 
         let valueParam = {
           EdbInfoId: this.selectEdbInfo.EdbInfoId||0,
           MoveForward: this.formData.MoveForward,
           DateChange: this.$refs.dateMoveWayRef.dateChangeArr
         }
-
         let { Data } = await sheetInterface.getSystemDate({
           DataTimeType: this.dateChangeSelect,
           Value: JSON.stringify(valueParam)
         })
         
+        // 获取原始指标来源
+        let baseSourceName=''
+        if(this.dateChangeSelect==2){
+          // 获取指标日期的指标的原始来源
+          await sheetInterface.getEdbBaseSource({
+            EdbInfoId:this.selectEdbInfo.EdbInfoId
+          }).then(res=>{
+            if(res.Ret == 200){
+              baseSourceName = res.Data.ExcelSource || ''
+            }
+          })
+        }
+
+
         backData = {
           insertValue: Data.Date,
           dataTimeType: this.dateChangeSelect,
-          str: JSON.stringify(valueParam)
+          str: JSON.stringify(valueParam),
+          sourceName:baseSourceName||''
         }
       // }else { //指标日期
       //   backData = {

+ 12 - 3
src/views/datasheet_manage/components/selectTargetValueDia.vue

@@ -166,7 +166,6 @@ export default {
     //插入值的时候再去计算结果
     async insertData() {
       if(!this.edbInfo) return this.$message.warning(this.$t('ETableChildren.select_metric_first_msg') )
-
       let Date='';
       if(this.dateSelectForm.Type===2) { //选框为表格日期再去取Date
         Date = this.dateSelectForm.relationDate;
@@ -181,11 +180,20 @@ export default {
       if(res.Ret !== 200) return
 
       this.result = res.Data;
-
       let value = (this.result.List&&this.result.List.length)
         ? this.result.List.find(_ => _.DataTime===this.result.Date) ? this.result.List.find(_ => _.DataTime===this.result.Date).Value.toString() : ''
         : ''
 
+      let baseSourceName=''
+      // 获取指标日期的指标的原始来源
+      await sheetInterface.getEdbBaseSource({
+        EdbInfoId:this.edbInfo.EdbInfoId
+      }).then(res=>{
+        if(res.Ret == 200){
+          baseSourceName = res.Data.ExcelSource || ''
+        }
+      })
+
       this.chooseItem = {
         relationDate: Date,
         relationUid: this.dateSelectForm.Type===2 ? this.dateSelectForm.relationUid : '',
@@ -194,7 +202,8 @@ export default {
         str: JSON.stringify({
           MoveForward: this.dateSelectForm.MoveForward,
           DateChange: this.$refs.dateMoveWayRef.dateChangeArr
-        })
+        }),
+        sourceName:baseSourceName||''
       }
 
       this.$emit('insert',this.chooseItem)

+ 2 - 1
src/views/datasheet_manage/components/sheetClassifyDia.vue

@@ -105,7 +105,8 @@ export default {
 				'/chartrelevance':this.relevanceClassifyApi,
 				'/fittingEquationList': this.fittingEquationClassifyApi,
 				'/statisticFeatureList': this.statisticFeatureClassifyApi,
-				'/crossVarietyChartList': this.crossVarietyClassifyApi
+				'/crossVarietyChartList': this.crossVarietyClassifyApi,
+				'/sheetBalanceList':this.sheetClassifyApi,
 			}
 			handleMap[this.$route.path] && handleMap[this.$route.path](classify_name,classify_id)
 		},

+ 1 - 1
src/views/datasheet_manage/components/toolBarSection.vue

@@ -43,7 +43,7 @@ export default {
   },
   watch: {
     cell(nval) {
-      if(nval.ShowStyle) {
+      if(nval&&nval.ShowStyle) {
         this.option = {
           ...JSON.parse(nval.ShowStyle)
         }

+ 56 - 13
src/views/datasheet_manage/customAnalysis/list.vue

@@ -245,6 +245,7 @@
                 ref="sheetRef"
                 v-if="sheetConfigOpt.data"
                 :option="sheetConfigOpt"
+                @updated="hasChange=true"
               />
             </div>
           </template>
@@ -427,6 +428,8 @@ export default {
       saveTime:"",
 
       isEdbReFreshLoading: false,//指标刷新
+      // 内容是否更新
+      hasChange:false,
     };
   },
   watch: {
@@ -443,6 +446,7 @@ export default {
       this.sheetAllcellData = [],//全部单元格数据 分页push
       this.dataToalPage = 0;
       this.sheetConfigOpt.data = null;
+      this.hasChange=false
       newval && this.getDetailHandle();
     },
 
@@ -677,7 +681,10 @@ export default {
       this.handleDownloadResource(url,filename)
     },
     /* 保存表格 */
-    saveHandle: _.debounce(async function () {
+    saveHandle: _.debounce(function () {
+      this.saveApi()
+    }, 300),
+    async saveApi(){
       luckysheet.exitEditMode();
       let data = luckysheet.getAllSheets();
 
@@ -692,6 +699,7 @@ export default {
       let img = getSheetImage(data[0]);
       const form = new FormData();
       form.append("Image", img);
+      form.append("closableErrMsg123", true);
       const { Data } = await sheetInterface.uploadImg(form);
 
       data.luckysheet_select_save = [];
@@ -703,14 +711,16 @@ export default {
         ExcelClassifyId,
         ExcelImage: Data.ResourceUrl,
         Content: JSON.stringify(data),
+        closableErrMsg123:true
       });
       this.loading.close();
-      if (res.Ret !== 200) return;
+      if (res.Ret !== 200) return false;
+      this.hasChange=false
       this.saveTime = this.$moment().format('YYYY-MM-DD HH:mm:ss')
-      this.$message.success(this.$t('MsgPrompt.saved_msg'));
+      this.shouldClosedHintshow(this.$t('MsgPrompt.saved_msg'))
       this.getTreeData();
-    }, 300),
-
+      return true
+    },
     /* 获取表格列表 */
     getPublicList() {
       sheetInterface
@@ -854,15 +864,31 @@ export default {
     },
 
     /* 刷新表格 */
-    refreshSheet: _.debounce(async function() {
+    refreshSheet: _.debounce(function() {
       if(this.isEdbReFreshLoading) return
-      
-      this.isEdbReFreshLoading = true;
-      let res = await sheetInterface.sheetAnalysisInterface.sheetRefresh({ExcelInfoId: this.sheetDetailInfo.ExcelInfoId})
+      //退出编辑模式,让文本框失焦 
+      luckysheet.exitEditMode();
+      // 保存逻辑延后 让hasChange取得正确的值
+      setTimeout(async()=>{
+        this.isEdbReFreshLoading = true;
+        let res={}
+        // 内容有改变 刷新前需要先保存
+        if(this.hasChange){
+          let saveSuccess = await this.saveApi()
+          if(!saveSuccess){
+            // 没保存成功
+            this.isEdbReFreshLoading = false;
+            return
+          }
+          res = await sheetInterface.sheetAnalysisInterface.sheetRefresh({ExcelInfoId: this.sheetDetailInfo.ExcelInfoId,closableErrMsg123:true})
+        }else{
+          res = await sheetInterface.sheetAnalysisInterface.sheetRefresh({ExcelInfoId: this.sheetDetailInfo.ExcelInfoId,closableErrMsg123:true})
+        }
 
-      this.isEdbReFreshLoading = false;
-      if(res.Ret !== 200) return 
-      this.$message.success(res.Msg)
+        this.isEdbReFreshLoading = false;
+        if(res.Ret !== 200) return 
+        this.shouldClosedHintshow(res.Msg)
+      })
     },300),
 
     /* 重绘右侧区域宽度 */
@@ -899,7 +925,22 @@ export default {
         code: this.sheetDetailInfo.UniqueCode 
       }});
     },
-
+    shouldClosedHintshow(msg){
+      let messageHint=this.$message.success({
+        message:msg,
+        duration:0,
+        showClose:true
+      })
+      this.$store.commit('PUSH_CLOSABLE_HINT',messageHint)
+    },
+    closeHint(){
+      // console.log(this.$store.state.closableHints,'closableHints');
+      if(!(this.$store.state.closableHints && this.$store.state.closableHints.length>0)) return 
+      this.$store.state.closableHints.map(hint =>{
+        hint.close()
+      })
+      this.$store.commit('CLEAR_CLOSABLE_HINT')
+    }
   },
   mounted() {
     if (this.$route.query.code) {
@@ -913,9 +954,11 @@ export default {
     }
 
     window.addEventListener("resize", this.reloadRightWid);
+    document.addEventListener("click", this.closeHint);
   },
   destroyed() {
     window.removeEventListener("resize", this.reloadRightWid);
+    document.removeEventListener("click", this.closeHint);
   },
 };
 </script>

+ 81 - 11
src/views/datasheet_manage/customSheetEdit.vue

@@ -91,17 +91,45 @@
       ref="customTableRef"
       @autoSave="autoSaveFun"
     />
+    <div class="chart-source">
+      <span
+        v-if="sheetSourceFrom"
+        :style="`
+        color: ${sheetSourceFrom.isShow ? sheetSourceFrom.color : '#999'};
+        font-size: ${ sheetSourceFrom.fontSize }px;
+      `"
+      ><!-- 数据来源 -->{{$t('ETable.Common.data_source')}}:{{ sheetSourceFrom.text}}</span>
+      <el-switch
+        v-if="sheetSourceFrom"
+        v-model="sheetSourceFrom.isShow"
+        :active-value="true"
+        :inactive-value="false"
+        style="margin:0 15px;"
+        @change="(e) => {sheetSourceFrom.isShow=e,sheetForm.SourcesFrom=JSON.stringify(sheetSourceFrom)}"
+      />
+      <span class="editsty" @click="isShowSourceDialog=true"><!-- 编辑 -->{{$t('Common.edit_btn')}}</span>
+    </div>
+
+    <!-- 数据来源编辑弹窗 -->
+		<chartSourceEditDia
+			:isShow.sync="isShowSourceDialog"
+			:chartInfo="sheetForm"
+			@update="updateSheetSource"
+		/>
   </div>
 </template>
 
 <script>
 import * as sheetInterface from '@/api/modules/sheetApi.js';
 import { dataBaseInterface } from 'api/api.js';
+import {etaBaseConfigInterence} from '@/api/modules/etaBaseConfigApi.js';
 import selectTarget from '@/views/chartRelevance_manage/components/selectTarget.vue';
 import CustomTable from './components/CustomTable.vue'
 import html2canvas from 'html2canvas';
+import chartSourceEditDia from '@/views/dataEntry_manage/components/chartSourceEditDialog.vue';
+
 export default {
-  components: { selectTarget,CustomTable },
+  components: { selectTarget,CustomTable,chartSourceEditDia},
   beforeRouteEnter(to, from, next) {
     if(to.query.id){
       to.matched[1].name=`编辑表格`
@@ -157,7 +185,10 @@ export default {
       isCanEdit:false,
       sheetButton:'',
       // 取消自动保存,比如返回的时候
-      cancelAutoSave:false
+      cancelAutoSave:false,
+      sheetSourceFrom:null,
+      isShowSourceDialog:false,
+      showSourceFrom:true
     }
   },
   methods: {
@@ -169,7 +200,16 @@ export default {
 
     /* 获取表格详情 */
     async getDetail() {
-      if(!this.sheetId) return
+      if(!this.sheetId){
+        const res = await etaBaseConfigInterence.getBaseConfig()
+        if(res.Ret==200){
+          const Data = res.Data||{}
+          this.showSourceFrom = Data.ChartSourceDisplay==='true'?true:false
+        } 
+        this.sheetForm.SourcesFrom = this.setDefaultSource()
+        this.sheetSourceFrom = JSON.parse(this.sheetForm.SourcesFrom)
+        return
+      } 
 
       const res = await sheetInterface.sheetDetail({
 				ExcelInfoId: Number(this.sheetId)
@@ -184,13 +224,16 @@ export default {
         },1000)
         return 
       }
-      const { ExcelName,ExcelClassifyId,ExcelType,TableData,ModifyTime,Button} = res.Data;
+      const { ExcelName,ExcelClassifyId,ExcelType,TableData,ModifyTime,Button,SourcesFrom,ExcelSource} = res.Data;
       this.sheetButton=Button
       this.sheetForm = {
         name: ExcelName,
         classify: ExcelClassifyId,
-        sheetType: ExcelType
+        sheetType: ExcelType,
+        SourcesFrom:SourcesFrom || this.setDefaultSource(ExcelSource)
       }
+
+      this.sheetSourceFrom = JSON.parse(this.sheetForm.SourcesFrom)
       this.saveTime =  this.$moment(ModifyTime).format('YYYY-MM-DD HH:mm:ss')
 
       this.$nextTick(()=>{
@@ -198,11 +241,17 @@ export default {
       })
       this.$refs.customTableRef.initSheetData(TableData);
     },
-
+    setDefaultSource(sourceText){
+      return JSON.stringify({
+        isShow: this.showSourceFrom,
+        text: sourceText,
+        color: "#606266",
+        fontSize: 9
+      })
+    },
     /* 选择指标push指标数组 */
     async handleSelectTarget(e) {
       if(!e) return
-
       const { EdbName,EdbNameEn,UnitEn,EdbInfoId,Unit,Frequency } = e;
       if(this.$refs.customTableRef.config.data.find(_ => _.EdbInfoId===EdbInfoId)) return this.$message.warning(this.$t('OnlineExcelPage.already_exists_msg') )
       
@@ -217,7 +266,7 @@ export default {
         SortType: this.$refs.customTableRef.config.order===1 ? 'desc' : 'asc',
         Num: 12
       })
-      
+      this.updateSourceFrom(Data.ExcelSource)
       this.$refs.customTableRef.updateEdbData({
         Data: Data.Data.map(_ => ({..._,DataTimeType: 1,})),
         EdbAliasName: '',
@@ -253,7 +302,8 @@ export default {
         ExcelClassifyId: classify,
         ExcelImage:'',
         Source: 3,
-        TableData: this.$refs.customTableRef.getSaveParams()
+        TableData: this.$refs.customTableRef.getSaveParams(),
+        SourcesFrom:this.sheetForm.SourcesFrom
       };
       // console.log("自动保存");
       const res = await sheetInterface.sheetEdit({ ExcelInfoId: Number(this.sheetId),...params })
@@ -295,7 +345,8 @@ export default {
         ExcelClassifyId: classify,
         ExcelImage: Data.ResourceUrl,
         Source: 2,
-        TableData: this.$refs.customTableRef.getSaveParams()
+        TableData: this.$refs.customTableRef.getSaveParams(),
+        SourcesFrom:this.sheetForm.SourcesFrom
       };
 
       let isAdd = this.sheetId?false:true
@@ -331,7 +382,20 @@ export default {
     //   sheetInterface.markSheetEditStatus({ExcelInfoId: +this.sheetId,Status:2}).then(res=>{
     //     if(res.Ret != 200) return 
     //   })
-    // }
+    // },
+    updateSheetSource(value){
+      if(value){
+        this.sheetSourceFrom={...this.sheetSourceFrom,...value}
+        this.sheetForm.SourcesFrom=JSON.stringify(this.sheetSourceFrom)
+      }
+    },
+    updateSourceFrom(source){
+      if(!source) return
+      let concatSourceArr = this.sheetSourceFrom.text?`${this.sheetSourceFrom.text},${source}`.split(','):[source];
+      let sourceStr = Array.from(new Set(concatSourceArr)).join(',');
+      this.$set(this.sheetSourceFrom,'text',sourceStr)
+      this.sheetForm.SourcesFrom=JSON.stringify(this.sheetSourceFrom)
+    }
   },
   created() {
     this.getClassify();
@@ -350,6 +414,8 @@ export default {
 .customSheet-wrap {
   min-height: calc(100vh - 120px);
   min-width: 1020px;
+  position: relative;
+  padding-bottom: 30px;
   .wrap-top {
     // display: flex;
     // justify-content: space-between;
@@ -391,6 +457,10 @@ export default {
     }
 
   }
+  .chart-source{
+    position: absolute;
+    bottom: 0;
+  }
 }
 </style>
 <style lang="scss">

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

@@ -48,20 +48,49 @@
       </div>
     </div>
     
-    <MixedTable @autoSave="autoSaveFun"
+    <MixedTable @autoSave="autoSaveFun" @updateSourceName="updateSourceFromTable" :sourceFrom="sheetSourceFrom"
       ref="mixedTableRef"
     />
+    <div class="chart-source">
+      <span
+        v-if="sheetSourceFrom"
+        :style="`
+        color: ${sheetSourceFrom.isShow ? sheetSourceFrom.color : '#999'};
+        font-size: ${ sheetSourceFrom.fontSize }px;
+      `"
+      ><!-- 数据来源 -->{{$t('ETable.Common.data_source')}}:{{ sheetSourceFrom.text}}</span>
+      <el-switch
+        v-if="sheetSourceFrom"
+        v-model="sheetSourceFrom.isShow"
+        :active-value="true"
+        :inactive-value="false"
+        style="margin:0 15px;"
+        @change="(e) => {sheetSourceFrom.isShow=e,sheetForm.SourcesFrom=JSON.stringify(sheetSourceFrom)}"
+      />
+      <span class="editsty" @click="isShowSourceDialog=true"><!-- 编辑 -->{{$t('Common.edit_btn')}}</span>
+    </div>
+
+    <!-- 数据来源编辑弹窗 -->
+		<chartSourceEditDia
+			:isShow.sync="isShowSourceDialog"
+			:chartInfo="sheetForm"
+			@update="updateSheetSource"
+		/>
+
   </div>
 </template>
 
 <script>
 import * as sheetInterface from '@/api/modules/sheetApi.js';
 import { dataBaseInterface } from 'api/api.js';
+import {etaBaseConfigInterence} from '@/api/modules/etaBaseConfigApi.js';
 import selectTarget from '@/views/chartRelevance_manage/components/selectTarget.vue';
 import MixedTable from './components/MixedTable.vue'
 import html2canvas from 'html2canvas';
+import chartSourceEditDia from '@/views/dataEntry_manage/components/chartSourceEditDialog.vue';
+
 export default {
-  components: { selectTarget,MixedTable },
+  components: { selectTarget,MixedTable,chartSourceEditDia },
   beforeRouteEnter(to, from, next) {
     if(to.query.id){
       to.matched[1].name=`编辑表格`
@@ -120,6 +149,9 @@ export default {
       cancelAutoSave:false,
 
       updating:false,//更新状态
+      sheetSourceFrom:null,
+      isShowSourceDialog:false,
+      showSourceFrom:true
     }
   },
   methods: {
@@ -131,7 +163,16 @@ export default {
 
     /* 获取表格详情 */
     async getDetail(type='init') {
-      if(!this.sheetId) return
+      if(!this.sheetId){
+        const res = await etaBaseConfigInterence.getBaseConfig()
+        if(res.Ret==200){
+          const Data = res.Data||{}
+          this.showSourceFrom = Data.ChartSourceDisplay==='true'?true:false
+        } 
+        this.sheetForm.SourcesFrom = this.setDefaultSource()
+        this.sheetSourceFrom = JSON.parse(this.sheetForm.SourcesFrom)
+        return
+      } 
 
       const res = await sheetInterface.sheetDetail({
 				ExcelInfoId: Number(this.sheetId)
@@ -150,12 +191,14 @@ export default {
         return 
       }
 
-      const { ExcelName,ExcelClassifyId,TableData,ModifyTime,Button } = res.Data;
+      const { ExcelName,ExcelClassifyId,TableData,ModifyTime,Button,SourcesFrom,ExcelSource } = res.Data;
       this.sheetButton=Button
       this.sheetForm = {
         name: ExcelName,
-        classify: ExcelClassifyId
+        classify: ExcelClassifyId,
+        SourcesFrom:SourcesFrom || this.setDefaultSource(ExcelSource)
       }
+      this.sheetSourceFrom = this.sheetForm.SourcesFrom?JSON.parse(this.sheetForm.SourcesFrom):null
       this.$nextTick(()=>{
         this.sheetInit=true
       })
@@ -165,7 +208,14 @@ export default {
       
       type==='refresh' && this.$message.success(this.$t('OnlineExcelPage.table_data_update_msg') )
     },
-
+    setDefaultSource(sourceText){
+      return JSON.stringify({
+        isShow: this.showSourceFrom,
+        text: sourceText,
+        color: "#606266",
+        fontSize: 9
+      })
+    },
     /* 获取分类 */
     getClassify() {
       sheetInterface.excelClassifyOne({Source: 3}).then(res => {
@@ -187,7 +237,8 @@ export default {
         ExcelClassifyId: classify,
         ExcelImage:'',
         Source: 3,
-        TableData: this.$refs.mixedTableRef.getSaveParams()
+        TableData: this.$refs.mixedTableRef.getSaveParams(),
+        SourcesFrom:this.sheetForm.SourcesFrom
       };
       console.log("自动保存");
       const res = await sheetInterface.sheetEdit({ ExcelInfoId: Number(this.sheetId),...params })
@@ -230,8 +281,10 @@ export default {
         ExcelClassifyId: classify,
         ExcelImage: Data.ResourceUrl,
         Source: 3,
-        TableData: this.$refs.mixedTableRef.getSaveParams()
+        TableData: this.$refs.mixedTableRef.getSaveParams(),
+        SourcesFrom:this.sheetForm.SourcesFrom
       };
+
       let isAdd = this.sheetId?false:true
       const res = this.sheetId
       ? await sheetInterface.sheetEdit({ ExcelInfoId: Number(this.sheetId),...params })
@@ -267,6 +320,15 @@ export default {
     //     if(res.Ret != 200) return 
     //   })
     // }
+    updateSheetSource(value){
+      if(value){
+        this.sheetSourceFrom={...this.sheetSourceFrom,...value}
+        this.sheetForm.SourcesFrom=JSON.stringify(this.sheetSourceFrom)
+      }
+    },
+    updateSourceFromTable(){
+      this.sheetForm.SourcesFrom=JSON.stringify(this.sheetSourceFrom)
+    }
   },
   created() {
     this.getClassify();
@@ -285,6 +347,8 @@ export default {
 .customSheet-wrap {
   min-width: 1070px;
   min-height: calc(100vh - 120px);
+  position: relative;
+  padding-bottom: 30px;
   .wrap-top {
     display: flex;
     justify-content: space-between;
@@ -309,5 +373,9 @@ export default {
       }
     }
   }
+  .chart-source{
+    position: absolute;
+    bottom: 0;
+  }
 }
 </style>

+ 119 - 0
src/views/datasheet_manage/mixins/balanceTableMixin.js

@@ -0,0 +1,119 @@
+// 平衡表
+import * as sheetInterface from "@/api/modules/sheetApi.js";
+export default {
+  computed: {
+    downExcelFileUrl() {
+      let url = `${
+        process.env.VUE_APP_API_ROOT
+      }/datamanage/excel_info/table/download?${localStorage.getItem("auth")}`;
+      return url;
+    },
+  },
+  methods: {
+    itemHandle(data, type) {
+      if (type === "edit") {
+        this.handleEdit(data);
+        return;
+      }
+      if (type === "refresh") {
+        this.refreshSheetEdb(data.ExcelInfoId);
+        return;
+      }
+      if (type === "save") {
+        if(this.$route.path==='/sheetBalanceList'){
+            this.$parent.sheetDetailInfo = data;
+            this.$parent.saveOtherHandle();
+        }else{
+            this.saveOtherForm.name = data.ExcelName + "(1)";
+            this.isSaveOther = true;
+        }
+        
+        return;
+      }
+      if (type === "download") {
+        const value = `${this.downExcelFileUrl}&ExcelInfoId=${data.ExcelInfoId}`;
+
+        const a = document.createElement("a");
+        a.href = value;
+        a.target = "_blank";
+        a.download = data.ExcelName;
+        a.style.display = "none";
+        document.body.append(a);
+        a.click();
+        return;
+      }
+      if (type === "del") {
+        if(this.$route.path==='/sheetBalanceList'){
+            this.$emit("delSheetHandle", { cell: data, type: "del-list" });
+        }else{
+            this.$confirm(this.$t('ETable.Msg.is_del_table_msg') , this.$t('Confirm.prompt') , {
+                confirmButtonText:  this.$t('Dialog.confirm_btn'),
+                cancelButtonText: this.$t('Dialog.cancel_btn'),
+                type: "warning",
+              })
+                .then(() => {
+                    this.handleDelExcel(data)
+                })
+                .catch(() => {});
+            
+        }
+        
+        return;
+      }
+    },
+
+    handleDelExcel(data){
+        sheetInterface.classifyDel({
+          ExcelClassifyId:data.ExcelClassifyId,
+          ExcelInfoId:data.ExcelInfoId,
+          Source: 5
+        })
+        .then((res) => {
+          if (res.Ret !== 200) return;
+          this.$message.success(res.Msg);
+            this.$router.back()
+        });
+    },
+
+    // 去编辑
+    async handleEdit(data) {
+      const res = await sheetInterface.markSheetEditStatus({ ExcelInfoId: data.ExcelInfoId, Status: 1 });
+      if (res.Ret !== 200) return;
+      if (res.Data.Status == 0) {
+        this.$router.push({
+          path: "/editBalanceSheet",
+          query: {
+            id: data.ExcelInfoId,
+          },
+        });
+      } else if (res.Data.Status == 1) {
+        //编辑中
+        const text = `${res.Data.Editor}${this.$t("OnlineExcelPage.editing_msg")}`;
+        if(this.$route.path==='/sheetBalanceList'){
+            this.$emit("updateEdit", {
+                ExcelInfoId: data.ExcelInfoId,
+                Editor: res.Data.Editor,
+            });
+        }else{
+            this.excelInfo.Editor=res.Data.Editor
+            this.excelInfo.CanEdit=false
+        }
+        
+        this.$message.warning("当前" + text);
+      }
+    },
+
+    /* 刷新表格 */
+    refreshSheetEdb: _.debounce(async function (id) {
+      if (this.sheetRefreshing) return;
+      this.sheetRefreshing = true;
+      const res = await sheetInterface.refreshCustomSheet({
+        ExcelInfoId: id,
+      });
+      this.sheetRefreshing = false;
+
+      if (res.Ret !== 200) return;
+      this.$message.success(this.$t("ETable.Msg.refresh_success_msg"));
+    }, 300),
+  },
+};

+ 2 - 1
src/views/datasheet_manage/mixins/classifyMixin.js

@@ -353,7 +353,8 @@ export default {
         '/sheetList': 'etaTable_excel',
         '/sheetTimeList': 'etaTable_customize_data',
         '/sheetMixedList': 'etaTable_customize_mix',
-        '/sheetAnalysisList': 'etaTable_analysis'
+        '/sheetAnalysisList': 'etaTable_analysis',
+        '/sheetBalanceList':'etaTable_customize_balance'
       }
       return this.permissionBtn.isShowBtn('etaTablePermission',`${sheetType[this.$route.path]}_${type}`)
     }

+ 206 - 11
src/views/datasheet_manage/sheetList.vue

@@ -16,12 +16,13 @@
           <el-button v-if="permissionBtn.checkPermissionBtn(permissionBtn.etaTablePermission.etaTable_customize_data_sheetAdd)&&sourceMap[$route.path]===2" type="primary" style="margin-right:20px" @click="goAddSheetHandle">{{$t('OnlineExcelPage.add_timeline_table_btn')}}</el-button >
 
           <el-button v-if="permissionBtn.checkPermissionBtn(permissionBtn.etaTablePermission.etaTable_customize_mix_sheetAdd)&&sourceMap[$route.path]===3" type="primary" @click="goAddSheetHandle">{{$t('OnlineExcelPage.add_mixed_table_btn')}}</el-button >
+          <el-button v-if="permissionBtn.checkPermissionBtn(permissionBtn.etaTablePermission.etaTable_customize_balance_sheetAdd)&&sourceMap[$route.path]===5" type="primary" @click="showAddBalanceTable=true">{{$t('OnlineExcelPage.add_balance_table_btn')}}</el-button >
 
           <el-checkbox 
             v-model="isShowMe"
             style="margin-left:20px"
             @change="() => { getTreeData();getPublicList() }"
-          >{{$t('Chart.only_see_mine')}}</el-checkbox>
+          >{{sourceMap[$route.path]===5?$t('BalanceSheet.only_edit'):$t('Chart.only_see_mine')}}</el-checkbox>
 
         </div>
         <div class="search-cont">
@@ -161,10 +162,30 @@
         </span>
       </div>
 
+      <!-- 平衡表列表 -->
       <div
         class="main-right"
         id="right"
         :style="isSlideLeft ? 'width:100%' : 'width:80%'"
+        v-if="sourceMap[$route.path]===5"
+      >
+        <BalanceSheetList 
+          :total="sheet_total" 
+          :list="sheetList"
+          :finished="!publicHaveMove"
+          :loading="sheetLoading"
+          @loadMoreHandle="loadMoreHandle"
+          @delSheetHandle="delSheetHandle"
+          @downloadExcel="downloadExcel"
+          @updateEdit="balanceSheetUpdateEdit"
+        />
+      </div>
+
+      <div
+        v-else
+        class="main-right"
+        id="right"
+        :style="isSlideLeft ? 'width:100%' : 'width:80%'"
       >
         <!-- 表格详情 -->
         <div class="sheet-detail-wrapper" v-if="select_id">
@@ -285,6 +306,15 @@
                 :disabled="true"
                 ref="mixedTableRef"
               />
+              <div class="chart-source">
+                <span
+                  v-if="[2,3].includes(sheetDetailInfo.Source) && sheetDetailInfo.SourcesFrom && JSON.parse(sheetDetailInfo.SourcesFrom).isShow"
+                  :style="`
+                  color: ${JSON.parse(sheetDetailInfo.SourcesFrom).color};
+                  font-size: ${ JSON.parse(sheetDetailInfo.SourcesFrom).fontSize }px;
+                `"
+                ><!-- 数据来源 -->{{$t('ETable.Common.source')}}:{{ JSON.parse(sheetDetailInfo.SourcesFrom).text}}</span>
+              </div>
             </div>
           </template>
 
@@ -345,6 +375,7 @@
                 value: 'ExcelClassifyId',
                 children: 'Children',
                 emitPath: false,
+                checkStrictly: true,
               }"
               style="width: 80%"
               :placeholder="$t('OnlineExcelPage.select_appropriate_category_lable')"
@@ -365,6 +396,58 @@
         >
       </div>
     </m-dialog>
+
+    <!-- 新增平衡表弹窗 -->
+    <m-dialog
+      :show.sync="showAddBalanceTable"
+      width="650px"
+      :title="$t('OnlineExcelPage.add_balance_table_btn')"
+      @close="showAddBalanceTable=false"
+    >
+      <el-form 
+        :model="balanceTableForm" 
+        :rules="balanceTableFormRule" 
+        ref="addBalanceForm" 
+        label-width="140px" 
+        class="add-balance-wrap"
+      >
+        <el-form-item :label="$t('OnlineExcelPage.excel_name_ipt')" prop="name">
+          <el-input 
+            v-model="balanceTableForm.name" 
+            :placeholder="$t('OnlineExcelPage.please_table_name_ipt')"
+            style="width:350px"
+          ></el-input>
+        </el-form-item>
+        <el-form-item :label="$t('SteelChemicalPage.label_edb_classify')" prop="classify">
+          <el-cascader
+            v-model="balanceTableForm.classify"
+            :options="balanceClassifyOpts"
+            :props="{
+              label: 'ExcelClassifyName',
+              value: 'ExcelClassifyId',
+              children: 'Children',
+              emitPath: false,
+              checkStrictly: true,
+            }"
+            clearable
+            :placeholder="$t('OnlineExcelPage.select_table_category')"
+            style="width:350px"
+          />
+        </el-form-item>
+      </el-form>
+
+      <div style="display: flex; justify-content: center; margin-top: 30px">
+        <el-button
+          type="primary"
+          style="margin-right: 60px"
+          @click="handleConfirmAddBalanceTable"
+          >{{$t('Dialog.confirm_save_btn')}}</el-button
+        >
+        <el-button type="primary" plain @click="showAddBalanceTable=false"
+          >{{$t('Dialog.cancel_btn')}}</el-button
+        >
+      </div>
+    </m-dialog>
   </div>
 </template>
 
@@ -378,9 +461,11 @@ import { getSheetImage } from "./common/option";
 import CustomTable from "./components/CustomTable.vue";
 import MixedTable from "./components/MixedTable.vue";
 import sheetListWrap from "./components/sheetListWrap.vue"
+import BalanceSheetList from './components/BalanceSheetList.vue';
+
 export default {
   name: "",
-  components: { mDialog, classifyDia, Sheet, CustomTable, MixedTable,sheetListWrap },
+  components: { mDialog, classifyDia, Sheet, CustomTable, MixedTable,sheetListWrap,BalanceSheetList },
   mixins: [leftMixin],
   beforeRouteLeave(to,from,next){
     if(from.path=='/sheetList'){
@@ -396,11 +481,11 @@ export default {
       return url;
     },
     classifyOptions() {
-      let options = this.treeData.map((_) => ({
-        ExcelClassifyId: _.ExcelClassifyId,
-        ExcelClassifyName: _.ExcelClassifyName,
-      }));
-      return options;
+      // let options = this.treeData.map((_) => ({
+      //   ExcelClassifyId: _.ExcelClassifyId,
+      //   ExcelClassifyName: _.ExcelClassifyName,
+      // }));
+      return this.balanceClassifyOpts;
     },
     saveOtherFormRule(){
       return {
@@ -445,7 +530,8 @@ export default {
       sheetList: [],
       sheet_total: 0,
       sheet_page: 1,
-      sheet_pages_size: 16,
+      sheet_pages_size: this.$route.path==='/sheetBalanceList'?30:16,
+      sheetLoading:false,
 
       /* 另存为 */
       isSaveOther: false,
@@ -458,6 +544,7 @@ export default {
         '/sheetList': 1,
         '/sheetTimeList': 2,
         '/sheetMixedList': 3,
+        '/sheetBalanceList': 5,
       },
       saveTime:"",
       editButtonText:"",
@@ -471,6 +558,18 @@ export default {
       isShowMe: false,//只看我的
 
       sheetRefreshing:false,//表格刷新状态
+
+      showAddBalanceTable:false,//创建平衡表弹窗
+      balanceTableForm:{
+        name:'',
+        classify:''
+      },
+      balanceTableFormRule:{
+        name:[{ required: true, message: '请输入表格名称', trigger: 'blur' },],
+        classify:[{ required: true, message: '请选择分类', trigger: 'change' },]
+      },
+      balanceClassifyOpts:[],//平衡表分类数据
+
     };
   },
   watch: {
@@ -527,6 +626,54 @@ export default {
     }
   },
   methods: {
+    // 获取平衡表分类
+    getBalanceClassifyOpts(){
+      sheetInterface.excelClassifyOne({ Source: this.sourceMap[this.$route.path] }).then(res => {
+        if (res.Ret !== 200) return
+
+        this.balanceClassifyOpts = res.Data.AllNodes || [];
+      })
+    },
+    //确认新增平衡表
+    handleConfirmAddBalanceTable(){
+      this.$refs.addBalanceForm.validate((valid) => {
+          if (valid) {
+
+            let params = {
+              ExcelName: this.balanceTableForm.name,
+              ExcelType: 1,
+              ExcelClassifyId: this.balanceTableForm.classify,
+              ExcelImage: '',
+              Source: 5,
+              TableData: {
+                CellRelation:"[]",
+                Data:[]
+              }
+            };
+            sheetInterface.sheetAdd(params).then(res=>{
+              if(res.Ret===200){
+                this.$router.push({
+                  path:'/editBalanceSheet',
+                  query:{
+                    id:res.Data.ExcelInfoId
+                  }
+                })
+              }
+            })
+          } 
+        });
+    },
+    // 更新平衡表编辑状态
+    balanceSheetUpdateEdit(data){
+      // 找到哪个表格
+      this.sheetList.forEach(item => {
+        if(item.ExcelInfoId===data.ExcelInfoId){
+          item.CanEdit=false
+          item.Editor=data.Editor
+        }
+      });
+    },
+
     /* 添加表格 */
     goAddSheetHandle() {
       if (!this.treeData.length) return this.$message.warning(this.$t('OnlineExcelPage.please_table_classification_msg') );
@@ -562,6 +709,10 @@ export default {
           params && this.selectCurrentNode(params);
         });
       });
+      // 更新一下分类把 新增平衡表时要
+      if([3,5].includes(this.sourceMap[this.$route.path])){
+        this.getBalanceClassifyOpts()
+      }
     },
 
     /* 搜索表格 */
@@ -585,6 +736,18 @@ export default {
     /* 选中分类变化时 */
     nodeChange({ UniqueCode, ExcelInfoId, ExcelClassifyId }, node) {
       console.log(this.select_id,ExcelInfoId,'UniqueCode');
+
+      // 点击的是平衡表模块的表格直接进入预览页
+      if(this.sourceMap[this.$route.path]===5&&ExcelInfoId>0){
+        this.$router.push({
+            path:'/viewBalanceSheet',
+            query:{
+              id:ExcelInfoId
+            }
+        })
+        return
+      }
+
       this.search_txt = "";
       this.select_node = UniqueCode;
       this.select_classify = !ExcelInfoId ? ExcelClassifyId : 0;
@@ -733,7 +896,7 @@ export default {
       if (Source === 1) {
         value = FileUrl;
         this.downLoad(value, ExcelName);
-      } else if ([2, 3].includes(Source)) {
+      } else if ([2, 3,5].includes(Source)) {
         value = `${this.downExcelFileUrl}&ExcelInfoId=${ExcelInfoId}`;
 
         const a = document.createElement("a");
@@ -852,6 +1015,7 @@ export default {
     },1500),
     /* 获取表格列表 */
     getPublicList() {
+      this.sheetLoading=true
       sheetInterface.sheetList({
         CurrentIndex: this.sheet_page,
         PageSize: this.sheet_pages_size,
@@ -859,6 +1023,7 @@ export default {
         Source: this.sourceMap[this.$route.path],
         IsShowMe: this.isShowMe
       }).then((res) => {
+        this.sheetLoading=false
         if (res.Ret !== 200) return;
 
         this.publicHaveMove = res.Data
@@ -870,11 +1035,19 @@ export default {
             : [...this.sheetList, ...res.Data.List]
           : [];
         this.sheet_total = res.Data ? res.Data.Paging.Totals : 0;
+      }).catch(()=>{
+        this.sheetLoading=false
       });
     },
 
     /* 加载更多 */
     loadMoreHandle: _.throttle(function () {
+      // 平衡表加载下一页
+      if(this.sourceMap[this.$route.path]==5){
+        this.sheet_page++;
+        this.getPublicList();
+        return
+      }
       let scrollTop = this.$refs.sheetListWrap.$refs.listRef.scrollTop;
       let clientHeight = this.$refs.sheetListWrap.$refs.listRef.clientHeight;
       let scrollHeight = this.$refs.sheetListWrap.$refs.listRef.scrollHeight;
@@ -898,7 +1071,10 @@ export default {
           this.sheetDetailInfo = res.Data;
           this.saveTime = this.$moment(this.sheetDetailInfo.ModifyTime).format('YYYY-MM-DD HH:mm:ss')||''
           this.editButtonText = this.sheetDetailInfo.CanEdit?'':`${this.sheetDetailInfo.Editor}${this.$t('OnlineExcelPage.editing_msg')}`
-
+          if(!this.sheetDetailInfo.SourcesFrom){
+            this.sheetDetailInfo.SourcesFrom = this.setDefaultSource(this.sheetDetailInfo.ExcelSource)
+          }
+          
           this.$nextTick(() => {
             //sheet组件Mounted已经init一次,再次调用会导致工具栏样式错乱
             //this.sheetDetailInfo.Source === 1 && this.$refs.sheetRef.init();
@@ -911,7 +1087,14 @@ export default {
           });
         });
     },
-
+    setDefaultSource(sourceText){
+      return JSON.stringify({
+        isShow: true,
+        text: sourceText,
+        color: "#606266",
+        fontSize: 9
+      })
+    },
     /* 删除表格 */
     delSheetHandle({cell, type = ""}) {
       const { ExcelClassifyId, ExcelInfoId  } = cell;
@@ -1003,6 +1186,10 @@ export default {
       this.$message.success(this.$t('MsgPrompt.saved_msg') );
       this.cancelSaveOther();
       this.getTreeData();
+      if(this.sourceMap[this.$route.path]==5){
+        this.sheet_page=1
+        this.getPublicList();
+      }
     },
 
     /* 重绘右侧区域宽度 */
@@ -1251,6 +1438,9 @@ $normal-font: 14px;
           box-sizing: border-box;
           padding: 15px;
           overflow-y: auto;
+          display: flex;
+          flex-direction: column;
+          justify-content: space-between;
           /* min-height: 500px; */
         }
       }
@@ -1319,6 +1509,11 @@ $normal-font: 14px;
 </style>
 
 <style lang="scss">
+.add-balance-wrap{
+  .el-input{
+    width: 100%;
+  }
+}
 .dataSheet-container {
   .label-input .el-input__inner {
     height: 25px;

+ 0 - 1
src/views/futures_manage/commodityChartBase.vue

@@ -146,7 +146,6 @@
                 :span="21"
                 style="padding: 20px 0;"
               >
-                <div class="chartEn-mark" v-show="chartInfo.IsEnChart" style="top: 0;left: 0;">En</div>
                 <div class="chart-show-cont"  v-if="!chartInfo.WarnMsg">
                   <div class="chartWrapper" id="chartWrapper">
                     <h2 class="chart-title">{{ currentLang==='en'?(chartInfo.ChartNameEn||chartInfo.ChartName):chartInfo.ChartName }}</h2>

+ 15 - 13
src/views/mychart_manage/components/chartDetailDia.vue

@@ -59,7 +59,7 @@
                 placeholder="年份日期选择"
                 @change="seasonYearChange"
               /> -->
-              <div v-else-if="chartInfo.ChartType === 2" @click="openDateDia" class="date-setting">
+              <div v-else-if="chartInfo.ChartType === 2&&chartInfo.Source!==11" @click="openDateDia" class="date-setting">
                 {{ season_year && season_year.length>0 ? season_year[0]+'~'+season_year[1]:"年份日期选择" }}
               </div>
             </div>
@@ -121,7 +121,7 @@
                 v-permission="permissionBtn.myETAPermission.myChart_edit"
                 class="span-item"
                 style="margin-left: 7px"
-                v-if="chartInfo.Button.IsEdit"
+                v-if="chartInfo.Button.IsEdit&&chartInfo.Source!==11"
                 @click="editChartHandle"
               >
                 <span> <i class="el-icon-edit" />&nbsp;<!-- 编辑 -->{{$t('Chart.chart_edit_btn')}} </span>
@@ -139,7 +139,7 @@
                 v-permission="permissionBtn.myETAPermission.myChart_otherSave"
                 class="span-item"
                 style="margin-left: 7px"
-                v-if="chartInfo.Button.IsCopy"
+                v-if="chartInfo.Button.IsCopy&&chartInfo.Source!==11"
                 @click="saveChartOtherHandle"
               >
                 <span> <i class="el-icon-document-add" />&nbsp;<!-- 另存为 -->{{$t('Chart.chart_copy_btn')}} </span>
@@ -195,6 +195,7 @@
                 class="span-item"
                 style="margin-left: 7px"
                 @click="openLangInfoDia"
+                v-if="chartInfo.Source!==11"
               >
                 <span> <img style="width: 16px;vertical-align: middle" :src="$icons.to_en" />&nbsp;<!-- 编辑信息 -->{{$t('Edb.detail_en_btn')}} </span>
               </span>
@@ -219,7 +220,6 @@
           </div>
           <div class="cont-bottom" v-loading="refreshLoading">
 
-            <div class="chartEn-mark" v-show="chartInfo.IsEnChart" style="top: unset;left:unset;">En</div>
             <div class="chart-show-cont">
               <div class="chartWrapper" id="chartWrapper">
                 <template v-if="!chartInfo.WarnMsg">
@@ -413,6 +413,7 @@
                 </template>
               </el-table-column>
               <el-table-column
+                v-if="chartInfo.Source!==11"
                 :label="$t('Table.column_operations')"
                 key="Copy"
                 align="center"
@@ -485,6 +486,7 @@
 </template>
 
 <script>
+import * as sheetInterface from "@/api/modules/sheetApi.js";
 import { dataBaseInterface,mychartInterface } from '@/api/api.js';
 import futuresInterface from '@/api/modules/futuresBaseApi';
 import chartRelevanceApi from '@/api/modules/chartRelevanceApi';
@@ -590,7 +592,7 @@ export default {
     },
     tableData: {
       handler(newval) {
-        newval.length && !this.chartInfo.WarnMsg && this.chartInfo.Source===1&& this.setChartOptionHandle(newval);
+        newval.length && !this.chartInfo.WarnMsg && [1,11].includes(this.chartInfo.Source)&& this.setChartOptionHandle(newval);
       },
       deep: true,
     },
@@ -640,7 +642,7 @@ export default {
           
           if(!this.chartInfo.HaveOperaAuth) return
 
-          if(this.chartInfo.Source===1) {
+          if([1,11].includes(this.chartInfo.Source)) {
             //处理下历史默认来源
             this.setDefaultSourceFrom();
             
@@ -754,6 +756,7 @@ export default {
    async getPreviewChartInfo() {
       let dateArray=this.chartInfo.ChartType==2?this.season_year:this.select_date
       let params = {
+        ChartSource:this.chartInfo.Source,
         ChartType: this.chartInfo.ChartType,
         DateType: this.year_select,
         StartDate: [5 , 6].includes(this.year_select)
@@ -874,6 +877,8 @@ export default {
         res=await statisticFeatureInterface.refreshChart({ ChartInfoId })
       }else if(Source===10) {
         res=await crossVarietyInterface.refreshChart({ ChartInfoId })
+      }else if(Source===11){
+        res=await sheetInterface.refreshCustomSheet({ChartInfoId});
       }
      
         this.refreshLoading = false;
@@ -1179,12 +1184,9 @@ export default {
     },
 
     /* 删除方法 */
-    delHandle(ChartInfoId) {
-      dataBaseInterface
-        .delChartClassify({
-          ChartInfoId,
-        })
-        .then((res) => {
+    async delHandle(ChartInfoId) {
+      const res=this.chartInfo.Source==11?await sheetInterface.delBalanceChart({ChartInfoId}):await dataBaseInterface.delChartClassify({ChartInfoId})
+
           if (res.Ret !== 200) return;
           this.$message.success(res.Msg);
           sessionStorage.removeItem('myChartbeforeOptions');
@@ -1199,7 +1201,7 @@ export default {
 
           // //只有一个图表且删除了 则展示缺省
           this.isNoChart = !this.allChart.length ? true : false;
-        });
+        
     },
 
     /* 转base64 */

+ 1 - 2
src/views/mychart_manage/index.vue

@@ -198,7 +198,6 @@
             >
               <el-card class="public-chart-item">
                 <div slot="header" class="item-top">
-                  <div class="chartEn-mark" v-show="chart.IsEnChart" style="top: -10px;left: -10px;">En</div>
                   <span class="text_oneLine" :style="{'padding-left':chart.IsEnChart?'24px':''}">{{ chart_lang === 'en' ? (chart.ChartNameEn||chart.ChartName) : chart.ChartName }}</span>
                   <img
                     v-if="ispublic === 0"
@@ -209,7 +208,7 @@
                   />
                 </div>
                 <img
-                  :src="(chart.Source===1&&!chart.HaveOperaAuth) ? $icons.lock_big : chart.ChartImage"
+                  :src="([1,11].includes(chart.Source)&&!chart.HaveOperaAuth) ? $icons.lock_big : chart.ChartImage"
                   alt=""
                   class="chart-img"
                   @click="viewChartDetail(chart)"

+ 3 - 0
src/views/ppt_manage/mixins/layerMixins.js

@@ -31,6 +31,9 @@ export default {
         this.activeLayerEl = {}
       }
       if(this.isEditLayer){
+        //进入图层编辑模式,需要退出其他模式
+        this.isEditTitle = false
+        
         //如果当前活跃图层没有layers,加上
         if(!this.currentItem.layers){
           this.refleshLayerEl([])

+ 73 - 29
src/views/ppt_manage/mixins/mixins.js

@@ -167,7 +167,8 @@ export default {
               return val;
             },
             align: 'center',
-            x: [0,2].includes(item.IsAxis) ? 5 : -5,
+            x: [0,2].includes(item.IsAxis) ? 2 : -2,
+            y: 3,
             style: {
               ...chartTheme&&chartTheme.yAxisOptions.style,
             }
@@ -203,14 +204,20 @@ export default {
         //数据列
         let obj = {
           data: [],
-          type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
-          dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
           yAxis: sameSideIndex,
           name:nameCh,
           nameCh:nameCh,
           nameEn:nameEn,
           color: item.ChartColor,
-          lineWidth: Number(item.ChartWidth)||(chartTheme&&chartTheme.lineOptions.lineWidth),
+          lineWidth: Number(item.ChartWidth)||(chartTheme&&chartTheme.lineOptionList[index].lineWidth),
+          marker: chartTheme && chartTheme.lineOptionList[index].dataMark && chartTheme.lineOptionList[index].dataMark!='none'?{
+            enabled:true,
+            symbol: chartTheme.lineOptionList[index].markType || 'circle',
+            fillColor:chartTheme.lineOptionList[index].markColor,
+            radius: chartTheme.lineOptionList[index].markSize
+          }:{},
           ...predict_params
         };
         item.DataList = item.DataList || [];
@@ -232,6 +239,7 @@ export default {
               ? Highcharts.dateFormat('%m/%d', ctx.value)
               : Highcharts.dateFormat('%y/%m', ctx.value);
           },
+          y: 14,
           style: {
             ...chartTheme&&chartTheme.xAxisOptions.style
           }
@@ -341,7 +349,8 @@ export default {
               return sameSideIndex !== index ? '' : val;
             },
             align: 'center',
-            x: [0,2].includes(item.IsAxis) ? 5 : -5,
+            x: [0,2].includes(item.IsAxis) ? 2 : -2,
+            y: 3,
             style: {
               ...chartTheme&&chartTheme.yAxisOptions.style
             }
@@ -410,6 +419,7 @@ export default {
                ? Highcharts.dateFormat('%m/%d', ctx.value)
                : Highcharts.dateFormat('%y/%m', ctx.value);
            },
+           y: 14,
            style: {
             ...chartTheme&&chartTheme.xAxisOptions.style
           }
@@ -433,12 +443,15 @@ export default {
        /* 主题样式*/
       const chartTheme =  this.chartInfo.ChartThemeStyle ? JSON.parse(this.chartInfo.ChartThemeStyle) : null;
 
-
       // 农历数据需要去除第一项 在ETA1.0.5之后,除了这里 农历和公历处理逻辑一样
       const temChartDataList=chartData.DataList||[]
       const chartDataHandle=this.calendar_type === '农历'?
       temChartDataList.filter((item, index) => index > 0):
       temChartDataList
+
+      // 跟颜色对应
+      chartTheme.lineOptionList=chartTheme.lineOptionList.reverse().slice(-chartDataHandle.length)
+
       let seasonYdata = [],
         seasonData = []
 
@@ -447,17 +460,24 @@ export default {
         minLimit = this.chartLimit.min||0
         maxLimit = this.chartLimit.max||0
       //数据列
-      for (let j of chartDataHandle) {
+      for (let index in chartDataHandle) {
+        let j = chartDataHandle[index]
           //预测指标配置
         let predict_params =  chartData.EdbInfoCategoryType === 1 ? this.getSeasonPredictParams(j.CuttingDataTimestamp) : {};
 
         let serie_item = {
           data: [],
-          type: (chartTheme&&chartTheme.lineOptions.lineType) || chartData.ChartStyle,
-          dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || chartData.ChartStyle,
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
           yAxis: 0,
           name: j.ChartLegend,
-          lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 1,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 1,
+          marker: chartTheme && chartTheme.lineOptionList[index].dataMark && chartTheme.lineOptionList[index].dataMark!='none'?{
+            enabled:true,
+            symbol: chartTheme.lineOptionList[index].markType || 'circle',
+            fillColor:chartTheme.lineOptionList[index].markColor,
+            radius: chartTheme.lineOptionList[index].markSize
+          }:{},
           ...predict_params
         };
         const data_array = _.cloneDeep(j.DataList);
@@ -479,6 +499,8 @@ export default {
             return val;
           },
           align: 'center',
+          x: -2,
+          y: 3,
           style: {
             ...chartTheme&&chartTheme.yAxisOptions.style
           }
@@ -512,6 +534,7 @@ export default {
           formatter: function (ctx) {
             return Highcharts.dateFormat('%m/%d', ctx.value);
           },
+          y: 14,
           style: {
             ...chartTheme&&chartTheme.xAxisOptions.style
           }
@@ -611,7 +634,7 @@ export default {
       //y轴
       const textYZh = chartData[1].ConvertUnit||chartData[1].Unit
       const textYEn = chartData[1].ConvertEnUnit||chartData[1].UnitEn||chartData[1].ConvertUnit||chartData[1].Unit
-      let yAxis = {
+      let yAxis = [{
         title: {
           text:  `${textYZh}`,
           textCh:textYZh,
@@ -628,6 +651,8 @@ export default {
           formatter: function (ctx) {
             return ctx.value;
           },
+          x: -2,
+          y: 3,
           align: 'center',
           style:{
             ...chartTheme&&chartTheme.yAxisOptions.style
@@ -652,7 +677,7 @@ export default {
         tickPixelInterval: 50,
         plotBands: this.setAxisPlotAreas(1),
         plotLines: this.setAxisPlotLines(1)
-      }
+      }]
 
       //数据列
       let series = {
@@ -664,7 +689,7 @@ export default {
         chartType: 'linear',
         color: ChartColor,
         marker: {
-          radius: (chartTheme&&chartTheme.lineOptions.radius)||5,
+          radius: (chartTheme&&chartTheme.lineOptionList[0].radius)||5,
         },
       }
       real_data.forEach(_ => {
@@ -694,6 +719,7 @@ export default {
             offset: 15,
           },
           labels: {
+            y: 14,
             style: {
               ...chartTheme&&chartTheme.xAxisOptions.style
             }
@@ -722,6 +748,7 @@ export default {
         categories: this.barXIdData.map(_ => this.barEdbData.find(edb => edb.EdbInfoId===_).EdbAliasName),
         tickWidth: 1,
         labels: {
+          y: 14,
           style: {
             ...chartTheme&&chartTheme.xAxisOptions.style
           }
@@ -751,6 +778,8 @@ export default {
             let val = ctx.value;
             return val;
           },
+          x: -2,
+          y: 3,
           align: 'center',
           style:{
             ...chartTheme&&chartTheme.yAxisOptions.style
@@ -826,6 +855,7 @@ export default {
         categories: this.commodityXData.map(_ =>_.Name),
         tickWidth: 1,
         labels: {
+          y: 14,
           style: {
             ...chartTheme&&chartTheme.xAxisOptions.style
           }
@@ -854,6 +884,8 @@ export default {
             let val = ctx.value;
             return val;
           },
+          x: -2,
+          y: 3,
           align: 'center',
           style:{
             ...chartTheme&&chartTheme.yAxisOptions.style
@@ -866,21 +898,21 @@ export default {
       }
 
       //数据列
-      data.forEach(item => {
+      data.forEach((item,index) => {
         //处理首或/尾全是无效数据的以null填充
         let filterData = this.filterInvalidData(item)
 
         let serie_item = {
           data: filterData,
-          type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
-          dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
           yAxis: 0,
           name: item.Name,
           nameCh: item.Name,
           nameEn: item.NameEn,
           color: item.Color,
           chartType: 'linear',
-          lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 3,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 3,
           marker: {
             enabled: false
           }
@@ -1040,6 +1072,7 @@ export default {
           }
         },
         labels: {
+          y: 14,
           style: {
             ...chartTheme&&chartTheme.xAxisOptions.style
           }
@@ -1070,6 +1103,8 @@ export default {
             let val = ctx.value;
             return val;
           },
+          x: -2,
+          y: 3,
           align: 'center',
           style:{
             ...chartTheme&&chartTheme.yAxisOptions.style
@@ -1081,18 +1116,18 @@ export default {
 
       //处理series
       let seriesData=[]
-      this.relevanceChartData.YDataList.forEach(item=>{
+      this.relevanceChartData.YDataList.forEach((item,index)=>{
         let serie_item = {
           data: item.Value,
-          type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
-          dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
           yAxis: 0,
           name: item.Name,
           nameCh: item.Name,
           nameEn: item.NameEn,
           color: item.Color,
           chartType: 'linear',
-          lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 3,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 3,
           marker: {
             enabled: false
           }
@@ -1164,6 +1199,8 @@ export default {
           },
         },
         labels: {
+          x: -2,
+          y: 3,
           style:{
             ...chartTheme&&chartTheme.yAxisOptions.style
           },
@@ -1190,6 +1227,7 @@ export default {
           align: 'middle',
         },
         labels: {
+          y: 14,
           style:{
             ...chartTheme&&chartTheme.xAxisOptions.style
           },
@@ -1215,7 +1253,7 @@ export default {
           chartType: 'linear',
           zIndex:1,
           marker: {
-            radius: (chartTheme&&chartTheme.lineOptions.radius)||5,
+            radius: (chartTheme&&chartTheme.lineOptionList.radius)||5,
           },
         }
         item.EdbInfoList.forEach(_ => {
@@ -1342,6 +1380,7 @@ export default {
         ...scatterXAxis,
         tickWidth: 1,
         labels: {
+          y: 14,
           style: {
             ...chartTheme&&chartTheme.xAxisOptions.style
           }
@@ -1366,6 +1405,8 @@ export default {
             },
           },
           labels: {
+            x: 0,
+            y: 3,
             style:{
               ...chartTheme&&chartTheme.yAxisOptions.style
             },
@@ -1378,14 +1419,14 @@ export default {
 
         let series_item = {
           data: item.Value.map(_ =>[_.X,_.Y]),
-          dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
-          type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'spline',
           yAxis: index,
           name: item.Name,
           nameCh: item.Name,
           nameEn: item.NameEn||item.Name,
           color: item.Color,
-          lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth)||3,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth)||3,
           chartType: 'linear',
           zIndex:1
         }
@@ -1443,6 +1484,8 @@ export default {
           }
         },
         labels: {
+          x: -2,
+          y: 3,
           style: {
             ...chartTheme&&chartTheme.xAxisOptions.style
           }
@@ -1467,6 +1510,7 @@ export default {
           }
         },
         labels: {
+          y: 14,
           style: {
             ...chartTheme&&chartTheme.xAxisOptions.style
           }
@@ -1637,18 +1681,18 @@ export default {
 
       //系列
       let series = [];
-      YDataList.forEach(item => {
+      YDataList.forEach((item,index) => {
         let serie_item = {
           data: item.Value,
           pointPlacement: 'on',
-          type: (chartTheme&&chartTheme.lineOptions.lineType) || 'line',
-          dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+          type: (chartTheme&&chartTheme.lineOptionList[index].lineType) || 'line',
+          dashStyle: (chartTheme&&chartTheme.lineOptionList[index].dashStyle)||'Solid',
           yAxis: 0,
           name: item.Name || item.Date,
           nameCh: item.Name || item.Date,
           nameEn: item.Date,
           color: item.Color,
-          lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 1,
+          lineWidth: (chartTheme&&chartTheme.lineOptionList[index].lineWidth) || 1,
           chartType: 'linear'
         };
         series.push(serie_item)

+ 361 - 31
src/views/ppt_manage/mixins/pptEditorMixins.js

@@ -4,8 +4,27 @@
  */
 //lodash
 import _ from "lodash";
+import {dataBaseInterface} from "@/api/api.js"
+import * as sheetInterface from '@/api/modules/sheetApi.js';
 import {createRandomCode,checkPPTpageElemant,getChartInfo} from '../newVersion/utils/untils';
 import {modelInfo,defaultPosition} from '../newVersion/utils/config';
+import {titleDefault} from '../newVersion/utils/tinymceSetting';
+function getAllParentNodes(event) {
+    let parentNodes = [];
+    let currentNode = event;
+
+    while (currentNode) {
+        parentNodes.push(currentNode);
+        currentNode = currentNode.parentNode;
+    }
+
+    return parentNodes;
+}
+function NodeCheck(dom,className){
+    const classList = getAllParentNodes(dom).map(d=>d.className)
+    return classList.includes(className)
+}
+let __click__title__outside = null
 export default{
   data(){
     return {
@@ -20,6 +39,13 @@ export default{
       showLastSaveTime:false,//是否展示自动保存时间
       lastSaveTime:'',//自动保存时间
       isSaved:false,//是否已点击了保存/发布
+
+      refreshLoading:null,//一键刷新的loading
+      refreshBtnLoading:false,//一键刷新的按钮loading
+
+      isEditTitle:false,//是否是标题编辑模式
+      titleSetting:null,//存储应用整个PPT的值
+
     }
   },
   directives: {
@@ -41,8 +67,171 @@ export default{
         document.removeEventListener('click',el.__click__outside)
       }
     },
+    'click-title-outside':{
+        bind(el,binding,vnode){
+            const clickHandle = (e)=>{
+                //点击标题区域和标题设置之外的地方,退出标题编辑模式
+                if(!vnode.context.isEditTitle) return
+                if(NodeCheck(e.target,'title-edit-box')||NodeCheck(e.target,'title-editor')){
+                  return false
+                }
+                if(binding.value && typeof binding.value === 'function'){
+                  binding.value(e)
+                }
+              }
+              __click__title__outside = clickHandle
+              document.addEventListener('click',clickHandle)
+        },
+        unbind(el,binding,vnode){
+            document.removeEventListener('click',__click__title__outside)
+        }
+    }
   },
   methods:{
+    testInput(e,item){
+        const text = e.target.innerHTML
+        item.title = text
+    },
+    exitEditTitle(e){
+        this.isEditTitle = false
+    },
+    //切换标题编辑模式
+    handleEditTitle(item){
+        //判断当前ppt是否添加了页面
+        if(this.pageList.length===0){
+            this.$message.warning(this.$t('Slides.msg_page_at_least_one'))
+            return
+        }
+        //如果点击的页不是当前页,将点击页切换至当前页
+        if(this.currentItem.id!==item.id){
+            //this.changeCurrentItem(item,'change')
+            const {id} = item
+            this.isEditLayer = false
+            this.activeLayerEl = {}
+            this.isEditTitle = false
+            
+            this.pageList.map((item,index)=>{
+                if(item.id===id){
+                    this.currentItem = item
+                    this.currentIndex = index
+                }
+            })
+            let height = $('.ppt-editor-item')[0].offsetHeight
+            const index = this.currentIndex
+            //pptEditor的滚动条动画
+            this.$refs.pptEditor.scrollTo({
+                top:height*index,
+                left:0,
+                behavior: 'smooth'
+            })
+        }
+        //this.isEditTitle = !this.isEditTitle
+        this.isEditTitle = true
+        if(this.isEditTitle){
+            //进入标题编辑模式,需要退出其他模式
+            this.isEditLayer = false
+            this.activeLayerEl = {}
+            
+            //初始化该页标题的数据
+            if(!this.currentItem.titleDetail){
+                this.currentItem.titleDetail = this.titleSetting?_.cloneDeep(this.titleSetting):_.cloneDeep(titleDefault)
+                this.$set(this.pageList,this.currentIndex,this.currentItem) 
+            }
+            
+            this.$nextTick(()=>{
+                this.$refs.titleEditor.initFlag = true
+                this.$refs.titleEditor.initTitleEditor()
+            })
+        }
+    },
+    //获取标题内容
+    handleTextChange({val,richContent}){
+        this.currentItem.title = richContent/* val */
+        this.$set(this.pageList,this.currentIndex,this.currentItem) 
+    },
+    //获取标题样式 需要存一份px单位
+    handleTitelStyleChange({top,left,width,height,color,fontSize,fontFamily}){
+        const baseWidth = 900
+        const baseHeight = 630
+        this.currentItem.titleDetail = {
+            top,left,width,height,
+            baseTop:baseHeight*top/100,//px单位,基准为编辑页的ppt大小
+            baseLeft:baseWidth*left/100,
+            baseWidth:baseWidth*width/100,
+            baseHeight:baseHeight*height/100,
+            fontFamily,fontSize,color
+        }
+        this.$set(this.pageList,this.currentIndex,this.currentItem) 
+
+    },
+    //全局改变标题位置
+    changePositionAll({left,top}){
+        //遍历所有PPT页
+        //替换每一页titleDetail的left top
+        //若width,height没有值,则使用默认的,若有值,则不变
+        const defaultWidth = 900
+        const defaultHeight = 630
+        const defaultWidthPercent = 68
+        const defaultHeightPercent = 7
+        this.pageList.forEach(page=>{
+            const {width='',height='',baseWidth='',baseHeight=''} = page.titleDetail||{}
+            page.titleDetail = {
+                top,left,
+                width:width||defaultWidthPercent,
+                height:height||defaultHeightPercent,
+                baseTop:defaultHeight*top/100,//px单位,基准为编辑页的ppt大小
+                baseLeft:defaultWidth*left/100,
+                baseWidth:baseWidth||defaultWidth*width/100,
+                baseHeight:baseHeight||defaultHeight*height/100
+            }
+        })
+        /* this.$message.success('全局设置成功') */
+    },
+    //全局改变标题宽高
+    changeSizeAll({width,height}){
+        //遍历所有PPT页
+        //替换每一页titleDetail的width height
+        //若left,top没有值,则使用默认的,若有值,则不变
+        const defaultWidth = 900
+        const defaultHeight = 630
+        const defaultLeftPercent = 10
+        const defaultTopPercent = 5.5
+        this.pageList.forEach(page=>{
+            const {top='',left='',baseTop='',baseLeft=''} = page.titleDetail||{}
+            page.titleDetail = {
+                width,height,
+                top:top||defaultTopPercent,
+                left:left||defaultLeftPercent,
+                baseWidth:defaultWidth*width/100,
+                baseHeight:defaultHeight*height/100,
+                baseTop:baseTop||defaultHeight*top/100,
+                baseLeft:baseLeft||defaultWidth*left/100,
+            }
+        })
+        //this.$message.success(this.$t('MsgPrompt.set_success_msg'))
+    },
+    //全局改变标题设置,并存储本次设置
+    changeSettingAll(detail){
+        this.titleSetting = detail
+        this.settingAllPage()
+        this.$message.success(this.$t('MsgPrompt.set_success_msg'))
+    },
+    settingAllPage(){
+        const baseWidth = 900
+        const baseHeight = 630
+        this.pageList.forEach((page,index)=>{
+            const {top=6.6,left=10,width=68,height=5,color='#333',fontFamily='helvetica',fontSize=22} = this.titleSetting
+            page.titleDetail = {
+                top,left,width,height,
+                baseTop:baseHeight*top/100,//px单位,基准为编辑页的ppt大小
+                baseLeft:baseWidth*left/100,
+                baseWidth:baseWidth*width/100,
+                baseHeight:baseHeight*height/100,
+                color,fontFamily,fontSize
+            }
+            this.$set(this.pageList,index,page)
+        })
+    },
     //显示切换模板弹窗
     handleChangeFormat(item){
       this.choosedItem = item
@@ -108,6 +297,7 @@ export default{
         modelId: modelId,
         title:this.choosedItem.title,
         elements: elements,
+        titleDetail:this.titleSetting?this.titleSetting:null
       }
       //把这页删掉,添加新的一页
       const index = this.pageList.findIndex((i) => i.id === this.choosedItem.id); 
@@ -138,6 +328,7 @@ export default{
       list.forEach(page=>{
         page.id = createRandomCode()
         page.elements = checkPPTpageElemant(page)
+        page.titleDetail = this.titleSetting?this.titleSetting:null
         pages.push(page)
       })
       //当前PPT没有页
@@ -253,37 +444,73 @@ export default{
     },
     //更新页面图表
     async updatePage(page){
-      page.isUpdating = true
-      const index = this.pageList.findIndex(i=>i.id===page.id)
-      this.pageList.splice(index,1,page)
-      const chartElements = page.elements.filter((item) => {
-        return item.type === "chart";
-      });
-      //刷新图表
-      //暂停自动保存
-      this.loopTimer&&clearInterval(this.loopTimer)
-      this.loopTimer=null
-      for(let i=0;i<chartElements.length;i++){
-        await this.getRefreshChart(chartElements[i].chartId);
-      }
-      //重新获取图表数据
-      for(let i=0;i<chartElements.length;i++){
-        await this.getchartData(chartElements[i].chartId);
-      }
-      //更新vuex里的图表信息
-      let chartInfoMap = _.cloneDeep(this.$store.state.ppt.chartInfoMap)
-      for(let i=0;i<chartElements.length;i++){     
-        let temp = getChartInfo(this.optionMap[chartElements[i].chartId])
-        chartInfoMap[chartElements[i].chartId] = temp
-      }
-      this.$store.commit('SET_CHART_INFO_MAP',chartInfoMap)
-      //渲染图表
-      await this.initCharts(chartElements, page);
-      page.isUpdating = false
-      this.$message.success(this.$t('MsgPrompt.refresh_success_msg'))
-      this.pageList.splice(index,1,page)
-      //开启自动保存
-      this.autoSave()
+        page.isUpdating = true
+        const index = this.pageList.findIndex(i=>i.id===page.id)
+        this.pageList.splice(index,1,page)
+        const chartElements = page.elements.filter((item) => {
+            return item.type === "chart";
+        });
+        const SheetElements = page.elements.filter((item) => {
+            return item.type === "sheet";
+        });
+        //刷新图表
+        //暂停自动保存
+        this.loopTimer&&clearInterval(this.loopTimer)
+        this.loopTimer=null
+        /* for(let i=0;i<chartElements.length;i++){
+            await this.getRefreshChart(chartElements[i].chartId);
+        }
+        //重新获取图表数据
+        for(let i=0;i<chartElements.length;i++){
+            await this.getchartData(chartElements[i].chartId);
+        }
+        //更新vuex里的图表信息
+        let chartInfoMap = _.cloneDeep(this.$store.state.ppt.chartInfoMap)
+        for(let i=0;i<chartElements.length;i++){     
+            let temp = getChartInfo(this.optionMap[chartElements[i].chartId])
+            chartInfoMap[chartElements[i].chartId] = temp
+        }
+        this.$store.commit('SET_CHART_INFO_MAP',chartInfoMap)
+        //渲染图表
+        await this.initCharts(chartElements, page); */
+
+        chartElements.length&&await this.refreshPageChart(chartElements,page)
+        SheetElements.length&&await this.refreshPageSheet(SheetElements,page)
+        page.isUpdating = false
+        //this.$message.success(this.$t('MsgPrompt.refresh_success_msg'))
+        this.pageList.splice(index,1,page)
+        //开启自动保存
+        this.autoSave()
+    },
+    //更新图表
+    async refreshPageChart(chartElements,page){
+        const codeArr = [...new Set (chartElements.map(i=>i.chartId))]
+        //改成批量刷新图表的接口
+        await this.refreshCharts(codeArr,'',Date.now().toString().slice(-6))
+        //重新获取图表数据
+        for(let i=0;i<chartElements.length;i++){
+            await this.getchartData(chartElements[i].chartId);
+        }
+        //更新vuex里的图表信息
+        let chartInfoMap = _.cloneDeep(this.$store.state.ppt.chartInfoMap)
+        for(let i=0;i<chartElements.length;i++){     
+            let temp = getChartInfo(this.optionMap[chartElements[i].chartId])
+            chartInfoMap[chartElements[i].chartId] = temp
+        }
+        this.$store.commit('SET_CHART_INFO_MAP',chartInfoMap)
+        //渲染图表
+        await this.initCharts(chartElements, page);
+    },
+    //更新表格
+    async refreshPageSheet(sheetElements,page){
+        const codeArr = [...new Set (sheetElements.map(i=>i.sheetId))]
+        await this.refreshSheets(codeArr,'',Date.now().toString().slice(-6))
+        //重新获取表格数据
+        for(let i=0;i<sheetElements.length;i++){
+            await this.getsheetData(sheetElements[i].sheetId);
+        }
+        //渲染表格
+        await this.initSheets(sheetElements,page)
     },
     //设置ctrl按键的状态
     handlePasteKey(e){
@@ -394,6 +621,109 @@ export default{
         this.CoverContent = content
         this.isShowChooseCover = false
     },
+    //一键刷新 图表/表格
+    async refleshFormatEl(){
+        //全局遮罩,按钮禁用
+        this.refreshBtnLoading = true
+        this.refreshLoading = this.$loading({
+            lock: true,
+            text: `${this.$t('Slides.refresh_ppt_el')}...`,
+            spinner: 'el-icon-loading',
+            customClass:'loading',
+            target:document.querySelector('.page-wrap'),
+            background: 'rgba(255, 255, 255, 0.8)'
+        });
+        //刷新图表
+        let chartArr = this.getPPTElIds('chart','chartId')
+        chartArr.length&&await this.refreshCharts(chartArr,this.$route.query.id,Date.now().toString().slice(-6))
+        //刷新表格
+        let sheetArr = this.getPPTElIds('sheet','sheetId')
+        sheetArr.length&&await this.refreshSheets(sheetArr,this.$route.query.id,Date.now().toString().slice(-6))
+        this.refreshLoading&&this.refreshLoading.close()
+        if(!chartArr.length&&!sheetArr.length){
+            this.refreshBtnLoading = false
+            return this.$message.warning(this.$t('Slides.refresh_ppt_hint'))
+        }
+        this.refreshLoading = this.$loading({
+            lock: true,
+            text: `${this.$t('Slides.retrieving_ppt_data')}...`,
+            spinner: 'el-icon-loading',
+            customClass:'loading',
+            target:document.querySelector('.page-wrap'),
+            background: 'rgba(255, 255, 255, 0.8)'
+        });
+        /**
+         * 刷新完成后:
+         * 清空chartInfoMap(store)
+         * 清空optionMap(data)
+         * 清空sheetDataMap(data)
+         */
+        this.$store.commit('SET_CHART_INFO_MAP',{})
+        this.optionMap = {}
+        this.sheetDataMap = {}
+
+        //重新加载所有PPT页
+        //获取数据
+        await this.initPPTAllPage(this.pageList)
+        //渲染元素
+        for(let i=0;i<this.pageList.length;i++){
+            await this.initPageElements(this.pageList[i])
+        }
+        //获取已加载图表的信息
+        let chartInfoMap = {}
+        for(let i=0;i<this.pageList.length;i++){
+            this.pageList[i].elements.forEach(item=>{
+                if(item.type==='chart'){
+                    let temp = getChartInfo(this.optionMap[item.chartId])
+                    chartInfoMap[item.chartId] = temp
+                }
+            })
+        }
+        this.$store.commit('SET_CHART_INFO_MAP',chartInfoMap)
+        //移除遮罩,按钮启用
+        this.refreshLoading&&this.refreshLoading.close()
+        this.refreshBtnLoading = false
+    },
+    getPPTElIds(type,typeKey){
+        let code_arr = []
+        for(let i=0;i<this.pageList.length;i++){
+            this.pageList[i].elements.forEach(item=>{
+                if(item.type===type){
+                    code_arr.push(item[typeKey])
+                }
+            })
+        }
+        return [...new Set(code_arr)]
+    },
+    async refreshCharts(code_arr,id,replaceId){
+        //获取所有图表code
+        let res = await dataBaseInterface.getReportrefreshStatus({
+            Source:this.currentLang==='en'?'en_ppt':'ppt',
+            PrimaryId: Number(id||replaceId),
+        })
+        if(!res.Data.RefreshResult) return this.$message.warning(this.$t('ReportManage.ReportList.chart_refreshed_msg'))
+        const { Ret, Msg } = await dataBaseInterface.reportRefresh({
+            ChartInfoCode: code_arr,
+            Source:this.currentLang==='en'?'en_ppt':'ppt',
+            PrimaryId: Number(id||replaceId)
+        })
+        if(Ret!==200) return 
+        this.$message.success(Msg)
+    },
+    async refreshSheets(code_arr,id,replaceId){
+        let res = await sheetInterface.getRefreshResult({
+            Source:this.currentLang==='en'?'en_ppt':'ppt',
+            PrimaryId: Number(id||replaceId)
+        });
+        if(!res.Data.RefreshResult) return this.$message.warning(this.$t('ReportManage.ReportList.chart_refreshed_msg'))
+        const { Ret,Msg } = await sheetInterface.refreshSheet({
+            ExcelCodes: code_arr,
+            Source:this.currentLang==='en'?'en_ppt':'ppt',
+            PrimaryId: Number(id||replaceId)
+        })
+        if(Ret!==200) return 
+        this.$message.success(Msg)
+    }
   },
   mounted(){
     document.addEventListener("keydown",this.handlePasteKey)

+ 97 - 13
src/views/ppt_manage/mixins/pptMixins.js

@@ -25,6 +25,7 @@ import FormatNine from '../newVersion/components/formatPage/FormatNine.vue';
 import FormatTen from '../newVersion/components/formatPage/FormatTen.vue';
 import FormatEle from '../newVersion/components/formatPage/FormatEle.vue';
 import FormatTwelve from '../newVersion/components/formatPage/FormatTwelve.vue';
+import FormatThirteen from '../newVersion/components/formatPage/FormatThirteen.vue';
 const chunkArray = (array, chunkSize)=>{
     let result = [];
     for (let i = 0; i < array.length; i += chunkSize) {
@@ -34,7 +35,7 @@ const chunkArray = (array, chunkSize)=>{
 }
 export default {
   components:{ FormatOne,FormatTwo,FormatThree,
-    FormatFour,FormatFive,FormatSix,FormatSeven,FormatEight,FormatNine,FormatTen,FormatEle,FormatTwelve},
+    FormatFour,FormatFive,FormatSix,FormatSeven,FormatEight,FormatNine,FormatTen,FormatEle,FormatTwelve,FormatThirteen},
   computed: {
     globalLang() { //全局语言版本 中文ppt可用 英文ppt固定en忽视
       return this.$store.state.lang
@@ -82,6 +83,48 @@ export default {
     }
   },
   methods: {
+    getBasePosition(titleDetail){
+        const {top=6.6,left=10,width=68,height=5} = titleDetail
+        const baseWidth = 900
+        const baseHeight = 630
+        return {
+            baseTop:baseHeight*top/100,
+            baseLeft:baseWidth*left/100,
+            baseWidth:baseWidth*width/100,
+            baseHeight:baseHeight*height/100,
+        }
+    },
+    //配置自定义标题内容
+    setPPTTitle(slide,page){
+        const {titleDetail,title} = page
+        //兼容之前的ppt
+        if(!titleDetail){
+            slide.addText(title, {
+                /* placeholder:"slideTitle", */
+                x:'10%',
+                y:'5.5%',
+                w:'68%',
+                h:'7%',
+                color:'333333'
+              });
+        }else{
+            const {left,top,width,height,color='#333',fontSize=24,fontFamily} = titleDetail
+            const text = toTextProps(toJson(title))
+            const colorObj = color.includes('#')?{color:'333333',transparency:0}:rgbaToHex(color)
+            slide.addText(text,{
+                /* placeholder:"slideTitle", //加上后会走母版slideTitle的设置 */
+                x:left+'%',
+                y:top+'%',
+                w:width+'%',
+                h:height+'%',
+                color:colorObj.color,
+                transparency:colorObj.transparency,
+                fontSize:fontSize*0.7,
+                fontFace:fontFamily,
+            })
+        }
+        return slide
+    },
     //配置自定义封面内容
     setPPTCover(cover,pptCoverContent='',title=''){
         let contentList = []
@@ -172,7 +215,8 @@ export default {
             ModifyTime,
             PublishTime,
             Editor,
-            CoverContent
+            CoverContent,
+            TitleSetting
         } = res.Data
         const pptDate = formatPPTDate(this.currentLang, PptDate)
         let legalContent = JSON.parse(Content)
@@ -180,6 +224,14 @@ export default {
             page.elements = checkPPTpageElemant(page)
             return page
         })
+        let legalTitleSetting = null
+        try{
+            legalTitleSetting = JSON.parse(TitleSetting)
+        }catch(e){
+            console.log(e)
+            legalTitleSetting = null
+        }
+        
         this.pptCoverContent = CoverContent
         this.result = {
             status: 200,
@@ -195,7 +247,8 @@ export default {
             ModifyTime,
             PublishTime,
             Editor,
-            CoverContent
+            CoverContent,
+            TitleSetting:legalTitleSetting
         }
       }else{
         this.result = {status:'',content:'获取ppt数据失败!'}
@@ -225,7 +278,7 @@ export default {
       if(!Data) return 
       this.chartInfo = Data.ChartInfo;
       if(!this.chartInfo) return
-      if(this.chartInfo.Source === 1) { //常规图
+      if([1,11].includes(this.chartInfo.Source)) { //常规图
         //处理下历史默认来源
         this.setDefaultSourceFrom();
         
@@ -484,6 +537,7 @@ export default {
       const sheetElements = page.elements.filter((item)=>{
         return item.type === 'sheet'
       })
+      this.initPageTitle(page)
       if(type==='edit'){
         this.initTexts(textElements,page)
       }
@@ -493,6 +547,16 @@ export default {
       await this.listHandle(chartElements);
       this.initCharts(chartElements, page);
     },
+    //初始化内页标题
+    initPageTitle(page){
+        const index = this.pageList.findIndex((i) => i.id === page.id)
+        this.$nextTick(()=>{
+            const dom = document.getElementById(`page_title__${index}`)
+            if(dom){
+                dom.innerHTML = page.title
+            }
+        })
+    },
     //图表,表格数据统一加载,不按照页
     async initPPTAllPage(pageList){
         let chartElements = []
@@ -554,7 +618,8 @@ export default {
     async sheetListHandle(sheetElements){
       let needGetDataArr = []
       for(let i=0;i<sheetElements.length;i++){
-        if(!this.sheetDataMap[sheetElements[i].sheetId]&&!needGetDataArr.includes(sheetElements[i].sheetId)){
+        if( (!this.sheetDataMap[sheetElements[i].sheetId] || !this.sheetDataMap[sheetElements[i].sheetId].list) 
+          && !needGetDataArr.includes(sheetElements[i].sheetId)){
             needGetDataArr.push(sheetElements[i].sheetId)
         }
       }
@@ -586,13 +651,26 @@ export default {
 				UniqueCode: id
 			})
       if(res.Ret !== 200) return 0
-      const {TableInfo} = res.Data
+      const {TableInfo,SourcesFrom,ExcelSource} = res.Data
       //console.log('get')
-      this.sheetDataMap[id] = _.cloneDeep(TableInfo.TableDataList)
+      this.sheetDataMap[id] ={
+        list:_.cloneDeep(TableInfo.TableDataList),
+        otherParams:{
+          SourcesFrom:SourcesFrom?SourcesFrom:
+                      ExcelSource?this.setDefaultSource(ExcelSource):''
+        }
+      }
       return 1
     },
+    setDefaultSource(sourceText){
+      return JSON.stringify({
+        isShow: true,
+        text: sourceText,
+        color: "#606266",
+        fontSize: 9
+      })
+    },
     initCharts(elements, page) {
-        console.log('initCharts')
       const index = this.pageList.findIndex((i) => i.id === page.id)
       if(index===-1) return
       elements.forEach((item) => {
@@ -662,7 +740,9 @@ export default {
           || ([1,4,6].includes(MyChartType)&&[10,12].includes(modelId))) {
               tickInterval = (Math.max(...maxData)-Math.min(...minData))/6;
           }
-        
+          
+          //y轴也要刻度数量固定...
+          let tickAmount = [3,4,5,10,11,12].includes(modelId)?6:undefined;
 
         //title样式
         let titleHTML = null
@@ -722,7 +802,11 @@ export default {
           xAxis: {
             ...options.xAxis,
             tickInterval: is_linear ? undefined : tickInterval
-          }
+          },
+          yAxis: options.yAxis.map(_ => ({
+            ..._,
+            tickAmount
+          }))
         }
         //奇怪柱不堆叠
         let secialBarOpt = (options.series.some(_ => _.chartType === 'linear') && options.series.some(_ => _.chartType === 'linear')) ? {
@@ -1100,8 +1184,8 @@ export default {
 			this.setEnName = false
 		},
 
-    /* 生成ppt时图表追加底部文字 来源/说明 */
-    transChartBottomInfo(slide,{x,y,width,height},data) {
+    /* 生成ppt时 图表、表格 追加底部文字 来源/说明 */
+    transBottomInfo(slide,{x,y,width,height},data) {
       let chartData = data;
       let yPercent = Number(Math.ceil(height.replace(/%/,''))+Math.ceil(y.replace(/%/,'')))+'%';
       // console.log(yPercent)
@@ -1114,7 +1198,7 @@ export default {
                     ? sourceObj.color.substring(1).length<6 
                     ? '000000':sourceObj.color.substring(1)
                     : '666666'
-        slide.addText(`来源:${sourceObj.text}`,{
+        slide.addText(`${this.$t('ETable.Common.source')}:${sourceObj.text}`,{
           x:x,
           y: yPercent,
           w: width,

+ 1 - 0
src/views/ppt_manage/mixins/virtualScrollMixins.js

@@ -1,3 +1,4 @@
+//已停用 可删除
 /** 图库9.0(智能PPT) 虚拟列表 */
 import Highcharts from "highcharts/highstock"
 export default {

+ 5 - 1
src/views/ppt_manage/newVersion/components/IndexItem.vue

@@ -5,7 +5,7 @@
         <div class="wrap">
             <div class="item-flex">
                 <div class="item-icon-left"></div>
-                <div class="item-name">{{pageItem.title}}</div> 
+                <div class="item-name">{{getPlainText(pageItem.title)}}</div> 
                 <div class="item-icon-right none">
                   <el-dropdown @command="handleOperateCommand" trigger="click" v-if="showCloseBtn" v-show="!ctrlKeyActive">
                     <span class="el-dropdown-link"> 
@@ -48,6 +48,7 @@
 </template>
 
 <script>
+import {getPlainText} from '@/views/ppt_manage/newVersion/utils/untils';
 export default {
   props:{
     pageItem:{//ppt页
@@ -118,6 +119,9 @@ export default {
       },
       handleOperateCommand(command){
         this.$emit('operatePpt',{type:command.key,pageItem:this.pageItem})
+      },
+      getPlainText(str){
+        return getPlainText(str)
       }
   },
 };

+ 1 - 0
src/views/ppt_manage/newVersion/components/TextEditor.vue

@@ -1,4 +1,5 @@
 <template>
+    <!-- 需求199上线后停用,可删除 -->
   <!-- <div style="width:100%;height:100%">{{content}}</div> -->
   <Editor v-model="content" 
           :init="setting" ref="editor"

+ 25 - 2
src/views/ppt_manage/newVersion/components/catalog/pptContent.vue

@@ -15,11 +15,28 @@
             <img :src="pptBackImage" class="pptbg" />
           </div>
           <div class="ppt-item" v-else :key="item.id">
-              <div class="title-wrap" :title="item.title" 
+              <!-- <div class="title-wrap" :title="item.title" 
                 :style="`${getStrCount(item.title)<58?'':'top:0;height:14%;'}`"
                 :class="{'title-ellipsis':getStrCount(item.title)>172}">
                 {{item.title}}
-              </div>
+              </div> -->
+              <!-- 自定义标题 -->
+              <div class="custom-title-wrap editor-content" 
+                    :style="item.titleDetail?{
+                        left:(item.titleDetail.baseLeft||90)*contentScale+'px',
+                        top:(item.titleDetail.baseTop||40.9)*contentScale+'px',
+                        width:(item.titleDetail.baseWidth||612)+'px',
+                        height:(item.titleDetail.baseHeight||30.9)+'px',
+                    }:{
+                        left:90*contentScale+'px',top:40.9*contentScale+'px',width:'612px',height:'30.9px'
+                    }">
+                    <div class="title" v-html="item.title"
+                    :style="item.titleDetail?{
+                        color:item.titleDetail.color||'#333',
+                        fontSize:(item.titleDetail.fontSize||22)+'px',
+                        fontFamily:item.titleDetail.fontFamily||'helvetica'
+                    }:{ color:'#333',fontSize:'22px',fontFamily:'helvetica' }"></div>
+                </div>
               <component  :is="getComponentName(item.modelId)"
                           :ref="`pptPage_${index-1}`"
                           :pageIndex="index-1"
@@ -144,6 +161,12 @@ export default {
       await this.initPPTAllPage(this.pageList)
       for(let i=0;i<this.pageList.length;i++){
         if(this.interruptLoad) return
+        if(this.pageList[i].titleDetail){
+            this.pageList[i].titleDetail = {
+                ...this.pageList[i].titleDetail,
+                ...this.getBasePosition(this.pageList[i].titleDetail)
+            }
+        }
         this.loadArr.push(this.pageList[i])
         await this.initPageElements(this.pageList[i],'show')
       } 

+ 25 - 2
src/views/ppt_manage/newVersion/components/catalog/pptContentEn.vue

@@ -14,11 +14,28 @@
             <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
           </div>
           <div class="ppt-item" v-else :key="item.id">
-              <div class="title-wrap" :title="item.title" 
+              <!-- <div class="title-wrap" :title="item.title" 
                 :style="`${getStrCount(item.title)<52?'top:4.5%;left:8%;width:62%;':'top:0;left:8%;width:62%;height:14%;'}`"
                 :class="{'title-ellipsis':getStrCount(item.title)>150}">
                 {{item.title}}
-              </div>
+              </div> -->
+              <!-- 自定义标题 -->
+              <div class="custom-title-wrap editor-content" 
+                    :style="item.titleDetail?{
+                        left:(item.titleDetail.baseLeft||90)*contentScale+'px',
+                        top:(item.titleDetail.baseTop||40.9)*contentScale+'px',
+                        width:(item.titleDetail.baseWidth||612)+'px',
+                        height:(item.titleDetail.baseHeight||30.9)+'px',
+                    }:{
+                        left:90*contentScale+'px',top:40.9*contentScale+'px',width:'612px',height:'30.9px'
+                    }">
+                    <div class="title" v-html="item.title"
+                    :style="item.titleDetail?{
+                        color:item.titleDetail.color||'#333',
+                        fontSize:(item.titleDetail.fontSize||22)+'px',
+                        fontFamily:item.titleDetail.fontFamily||'helvetica'
+                    }:{ color:'#333',fontSize:'22px',fontFamily:'helvetica' }"></div>
+                </div>
               <component  :is="getComponentName(item.modelId)"
                           :ref="`pptPage_${index-1}`"
                           :pageIndex="index-1"
@@ -139,6 +156,12 @@ export default {
       await this.initPPTAllPage(this.pageList)
       for(let i=0;i<this.pageList.length;i++){
         if(this.interruptLoad) return
+        if(this.pageList[i].titleDetail){
+            this.pageList[i].titleDetail = {
+                ...this.pageList[i].titleDetail,
+                ...this.getBasePosition(this.pageList[i].titleDetail)
+            }
+        }
         this.loadArr.push(this.pageList[i])
         await this.initPageElements(this.pageList[i],'show')
       }

+ 73 - 17
src/views/ppt_manage/newVersion/components/editor/AddFormat.vue

@@ -5,16 +5,20 @@
       class="add_ico"
       @click="addPage(chooseModalId)"
     />
+    <el-button type="text" icon="el-icon-arrow-left" :disabled="clickLeftTime===0" @click="scrollPrev"></el-button>
     <div class="format-wrap">
-      <div class="format-item" :class="{'last-choose':chooseModalId===item.modelId}"
-      v-for="item in formatArr" :key="item.modelId">
-        <component
-          :is="previewComponentName(item.modelId)"
-          @click.native="addPage(item.modelId)"
-        />
-        <!-- <p>{{ item.text }}</p> -->
-      </div>
+        <div class="format-trans-wrap" :style="`transform:translateX(${scrollOffset}px);`">
+            <div class="format-item" :class="{'last-choose':chooseModalId===item.modelId}"
+                :style="`margin:0 ${itemOccupyMargin}px;`"
+                    v-for="item in formatArr" :key="item.modelId">
+                    <component
+                    :is="previewComponentName(item.modelId)"
+                    @click.native="addPage(item.modelId)"
+                    />
+                </div>
+        </div>
     </div>
+    <el-button type="text" icon="el-icon-arrow-right" :disabled="clickRightTime===0" @click="scrollNext"></el-button>
   </div>
 </template>
 
@@ -32,6 +36,7 @@ import FormatPreNine from "@/views/ppt_manage/newVersion/components/formatPrevie
 import FormatPreTen from "@/views/ppt_manage/newVersion/components/formatPreview/FormatPreTen";
 import FormatPreEle from "@/views/ppt_manage/newVersion/components/formatPreview/FormatPreEle";
 import FormatPreTwelve from "@/views/ppt_manage/newVersion/components/formatPreview/FormatPreTwelve";
+import FormatPreThirteen from "@/views/ppt_manage/newVersion/components/formatPreview/FormatPreThirteen";
 import {countComponentName} from '@/views/ppt_manage/newVersion/utils/untils';
 export default {
   name: "AddFormat",
@@ -53,15 +58,44 @@ export default {
     FormatPreNine,
     FormatPreTen,
     FormatPreEle,
-    FormatPreTwelve
+    FormatPreTwelve,
+    FormatPreThirteen
   },
   data() {
     return {
       formatArr: formatPre,
-
+      lineShowNum:9,//一行最多能展示几个
+      clickLeftTime:0,//可以按下左按钮的次数,为0时该按钮禁用
+      clickRightTime:0,//可以按下右按钮的次数,为0时该按钮禁用
+      scrollOffset:0,//当前滚动偏移量
+      itemOccupyMargin:0,//当前一个format占用间距
+      itemWidth:92,//当前一个format所占宽度(固定)
     };
   },
   methods: {
+    init(){
+        //初始化按钮次数
+        this.clickLeftTime = 0
+        this.clickRightTime = this.formatArr.length - this.lineShowNum
+        //获取容器宽度,以确定一个format应占宽度
+        const parentWidth = $('.format-wrap').width()
+        this.itemOccupyMargin = ((parentWidth/this.lineShowNum - this.itemWidth - 0.5)/2).toFixed(2)
+    },
+    scrollPrev(){
+        if(this.clickLeftTime<=0) return 
+        this.clickLeftTime--
+        this.clickRightTime++
+        this.scrollFormat(this.clickLeftTime)
+    },
+    scrollNext(){
+        if(this.clickRightTime===0) return
+        this.clickRightTime--
+        this.clickLeftTime++
+        this.scrollFormat(this.clickLeftTime)
+    },
+    scrollFormat(multiple){
+        this.scrollOffset = -(multiple*this.itemWidth+Number(this.itemOccupyMargin))
+    },
     previewComponentName(modelId) {
       return countComponentName(modelId,'pre')
       //return `formatPre${modelMap[modelId]}`;
@@ -70,10 +104,20 @@ export default {
       this.$emit("addPage", modelId);
     },
   },
+  mounted(){
+    this.init()
+  },
 };
 </script>
 <style lang="scss">
 @import "~@/views/ppt_manage/newVersion/css/formatPre.scss";
+.add-icon-wrap{
+    .el-button{
+        i{
+            font-weight: bold;
+        }
+    }
+}
 </style>
 <style scoped lang="scss">
 .add-icon-wrap {
@@ -81,6 +125,8 @@ export default {
   min-height: 64px;
   position: relative;
   padding: 10px 20px;
+  display: flex;
+  align-items: center;
   .add_ico {
     cursor: pointer;
     position: absolute;
@@ -91,15 +137,25 @@ export default {
     height: 28px;
     display: inline-block;
   }
+  .el-button{
+        font-size: 22px;
+        padding:0;
+        &:first-of-type{
+            margin-left: 40px;
+        }
+    }
   .format-wrap {
-    margin-left: 40px;
-    /* background-color: #eef0f3; */
-    width: calc(100% - 40px);
-    /* height: 120px; */
-    display: flex;
-    /* flex-wrap: wrap; */
-    justify-content: space-between;
+    width: calc(100% - 80px);
+    height:68px;
+    overflow-x: hidden;
+    .format-trans-wrap{
+        width:100%;
+        height: 100%;
+        display: flex;
+        flex-wrap: nowrap;
+    }
     .format-item {
+      flex:0 0 auto;
       width: 80px;
       height: 56px;
       padding: 5px;

+ 3 - 1
src/views/ppt_manage/newVersion/components/editor/ChangeFormatDialog.vue

@@ -48,6 +48,7 @@ import FormatPreNine from "@/views/ppt_manage/newVersion/components/formatPrevie
 import FormatPreTen from "@/views/ppt_manage/newVersion/components/formatPreview/FormatPreTen";
 import FormatPreEle from "@/views/ppt_manage/newVersion/components/formatPreview/FormatPreEle";
 import FormatPreTwelve from "@/views/ppt_manage/newVersion/components/formatPreview/FormatPreTwelve";
+import FormatPreThirteen from "@/views/ppt_manage/newVersion/components/formatPreview/FormatPreThirteen";
 import {countComponentName} from '@/views/ppt_manage/newVersion/utils/untils';
 export default {
   props:{
@@ -71,7 +72,8 @@ export default {
     FormatPreNine,
     FormatPreTen,
     FormatPreEle,
-    FormatPreTwelve
+    FormatPreTwelve,
+    FormatPreThirteen
   },
   data() {
     return {

+ 2 - 1
src/views/ppt_manage/newVersion/components/editor/DeletePageDialog.vue

@@ -105,6 +105,7 @@ import FormatNine from '@/views/ppt_manage/newVersion/components/formatPage/Form
 import FormatTen from '@/views/ppt_manage/newVersion/components/formatPage/FormatTen.vue';
 import FormatEle from '@/views/ppt_manage/newVersion/components/formatPage/FormatEle.vue';
 import FormatTwelve from '@/views/ppt_manage/newVersion/components/formatPage/FormatTwelve.vue';
+import FormatThirteen from '@/views/ppt_manage/newVersion/components/formatPage/FormatThirteen.vue';
 import {countComponentName} from '@/views/ppt_manage/newVersion/utils/untils';
 export default {
   props:{
@@ -120,7 +121,7 @@ export default {
     }
   },
   components:{ FormatOne,FormatTwo,FormatThree,
-    FormatFour,FormatFive,FormatSix,FormatSeven,FormatEight,FormatNine,FormatTen,FormatEle,FormatTwelve},  
+    FormatFour,FormatFive,FormatSix,FormatSeven,FormatEight,FormatNine,FormatTen,FormatEle,FormatTwelve,FormatThirteen},  
   data() {
     return {
       startPageNum:null,//开始的页数

+ 2 - 2
src/views/ppt_manage/newVersion/components/editor/InsertPageDialog.vue

@@ -77,7 +77,7 @@
 <script>
 import {pptInterface } from "@/api/api.js";
 import {pptEnInterface} from '@/api/modules/pptEnApi.js';
-import {changeCatalogArr} from '@/views/ppt_manage/newVersion/utils/untils';
+import {changeCatalogArr,getPlainText} from '@/views/ppt_manage/newVersion/utils/untils';
 export default {
   props:{
     insertPageShow:{
@@ -185,7 +185,7 @@ export default {
       data.forEach((item,index)=>{
         let temp = {}
         temp.key = index
-        temp.label = `${this.$i18n.locale == 'zh' ?`第${index+1}页`:` Slide${index+1}`} ${item.title||this.$t('Slides.untitled_title')}`
+        temp.label = `${this.$i18n.locale == 'zh' ?`第${index+1}页`:` Slide${index+1}`} ${getPlainText(item.title||this.$t('Slides.untitled_title'))}`
         temp.disabled = false
         list.push(temp)
       })

+ 219 - 0
src/views/ppt_manage/newVersion/components/editor/TitleEditorTool.vue

@@ -0,0 +1,219 @@
+<template>
+    <div class="title-editor-tool-wrap">
+        <div class="scroll-box">
+            <el-collapse v-model="activeNames" class="tool-list">
+                <!-- 位置设置 -->
+                <el-collapse-item :title="$t('Slides.title_location_settings')" name="position">
+                    <div>
+                        <!-- 上下 -->
+                        <span class="demonstration">{{$t('Slides.title_location_up_down')}}(%)</span>
+                        <el-slider v-model="detail.top" :max="12" :step="0.1"></el-slider>
+                    </div>
+                    <div>
+                        <!-- 左右 -->
+                        <span class="demonstration">{{$t('Slides.title_location_left_right')}}(%)</span>
+                        <el-slider v-model="detail.left" :step="0.1"></el-slider>
+                    </div>
+                    <!-- <el-button type="text" @click="changePosition">应用至整个PPT</el-button> -->
+                </el-collapse-item>
+                <!-- 大小设置 -->
+                <el-collapse-item :title="$t('Slides.title_size_settings')" name="size">
+                    <div>
+                        <!-- 宽度 -->
+                        <span class="demonstration">{{$t('Slides.title_size_width')}}(%)</span>
+                        <el-slider v-model="detail.width" :max="100 - detail.left" :step="0.1"></el-slider>
+                    </div>
+                    <div>
+                        <!-- 高度 -->
+                        <span class="demonstration">{{$t('Slides.title_size_height')}}(%)</span>
+                        <el-slider v-model="detail.height" :max="14-detail.top" :step="0.1"></el-slider>
+                    </div>
+                </el-collapse-item>
+                <!-- <el-collapse-item :title="$t('Slides.title_content_settings')" name="content">
+                    <div class="editor-tool"></div>
+                    <div class="editor" id="editorDom">
+                        <Editor v-model="content" 
+                            :init="setting" 
+                            ref="editor"/>
+                    </div>
+                </el-collapse-item> -->
+            </el-collapse>
+            <div class="other-setting">
+                <div class="setting-item">
+                    <!-- 字体设置 -->
+                    <span>{{$t('Slides.title_style_fontfamily')}}</span>
+                    <el-select v-model="detail.fontFamily">
+                        <el-option v-for="item in fontFamily" :key="item.value"
+                            :label="item.label"
+                            :value="item.value"
+                        />
+                    </el-select>
+                </div>
+                <div class="setting-item">
+                    <!-- 字号设置 -->
+                    <span>{{$t('Slides.title_style_fontsize')}}</span>
+                    <el-select v-model="detail.fontSize">
+                        <el-option v-for="item in fontSizeList" :key="item.value"
+                            :label="item.label"
+                            :value="item.value"
+                        />
+                    </el-select>
+                </div>
+                <div class="setting-item">
+                    <!-- 字体颜色 -->
+                    <span>{{$t('Slides.title_style_color')}}</span>
+                    <el-color-picker
+                        v-model="detail.color"
+                        size="mini"
+                        show-alpha
+                        :predefine="['#333']"
+                    />
+                    </el-tooltip>
+                </div>
+            </div>
+        </div>
+        <!-- 应用至整个PPT -->
+        <el-button type="primary" @click="applyToAll">{{$t('Slides.apply_to_the_entire')}}</el-button>
+    </div>
+</template>
+
+<script>
+import tinymce from "tinymce";
+import Editor from "@tinymce/tinymce-vue";
+import "tinymce/themes/silver";
+import "tinymce/plugins/lists"; //列表插件
+import "tinymce/plugins/quickbars"; //快速栏插件
+import "tinymce/plugins/fullscreen"; //全屏插件
+import "tinymce/plugins/paste"; //黏贴插件
+import "tinymce/icons/default/icons";
+import {setting,fontSizeList,fontFamily} from '../../utils/tinymceSetting'
+export default {
+    components:{Editor},
+    props:{
+        currentItem:{
+            type:Object,
+        }
+    },
+    data() {
+        return {
+            activeNames:'content',
+            content:'&*^%', //若设置为空,则init时没有标题就不会触发watch,随便设置几个字符即可
+            detail:{
+                left:0,top:0,width:0,height:0,
+                color:'#333',fontSize:22,fontFamily:'helvetica'
+            },
+            initFlag:false,
+            setting:{
+                ...setting,
+                language: "zh_CN",
+                language_url: require("../../utils/zh_CN.js"),
+                select:'#editorDom',//将编辑器渲染至该dom
+                fixed_toolbar_container: ".editor-tool",//将toolbar渲染至该dom
+                toolbar_persist:true,//是否一直显示toolbar
+                placeholder:this.$t('Slides.click_input_text_content'),
+            },
+            fontSizeList:fontSizeList,
+            fontFamily:fontFamily,
+
+        };
+    },
+    watch:{
+        //不用富文本用不到
+        content(con){
+            if(this.initFlag){
+                this.initFlag = false
+                return
+            }
+            const { elementId } = this.$refs.editor;
+            let richContent = tinymce.editors[elementId].getContent();
+            let val = tinymce.editors[elementId].getContent({ format: "text" });
+            this.$emit("textChange", { val, richContent });
+        },
+        detail:{
+            handler(newval){
+                //若init还未执行完成,不派发事件
+                if(this.initFlag){
+                    this.initFlag = false
+                    return 
+                }
+                this.$emit("styleChange",newval)
+            },
+            deep:true
+        },
+    },
+    methods: {
+        initTitleEditor(){
+            const {left,top,width,height,fontFamily='helvetica',fontSize=22,color='#333'} = this.currentItem.titleDetail
+            this.detail = {left,top,width,height,fontFamily,fontSize,color}
+            //this.content = this.currentItem.title
+        },
+        changePosition(){
+            const {left,top} = this.detail
+            this.$emit('changePositionAll',{top,left})
+        },
+        changeSize(){
+            this.changePosition()
+            const {width,height} = this.detail
+            this.$emit('changeSizeAll',{width,height})
+        },
+        applyToAll(){
+            this.$emit('applyToAll',this.detail)
+        }
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.title-editor-tool-wrap{
+    flex:1;
+    display:flex;
+    flex-direction: column;
+    overflow-y:hidden;
+    #editorDom{
+        min-height: 200px;
+        border:1px solid #ccc;
+        border-top: none;
+    }
+    .scroll-box{
+        flex:1;
+        overflow-y:auto;
+        overflow-x:hidden;
+        margin-bottom:20px;
+        padding-right:5px;
+        .el-collapse{
+            .el-slider{
+                padding:0 10px;
+            }
+        }
+        .other-setting{
+            margin-top:15px;
+            .setting-item{
+                display:flex;
+                justify-content:space-between;
+                /* align-items:center; */
+                margin-bottom:10px;
+                font-weight: bold;
+                .el-select{
+                    width:100px;
+                }
+            }
+        }
+    }
+}
+</style>
+<style lang="scss">
+.title-editor-tool-wrap{
+    .el-color-picker {
+      display: block;
+      &.el-color-picker--mini {
+        height: 30px;
+      }
+      .el-color-picker__trigger {
+        width: 60px;
+        height: 30px;
+        padding: 0;
+        border: 0;
+      }
+    }
+}
+</style>

+ 3 - 20
src/views/ppt_manage/newVersion/components/editor/chooseCover/TextEl.vue

@@ -46,6 +46,7 @@
         BaseTextShape
     } from '@/views/ppt_manage/newVersion/utils/config';
     import elMixin from './elMixin';
+    import tinymce from "tinymce";
     import Editor from "@tinymce/tinymce-vue";
     import "tinymce/themes/silver";
     import "tinymce/plugins/lists"; //列表插件
@@ -53,6 +54,7 @@
     import "tinymce/plugins/fullscreen"; //全屏插件
     import "tinymce/plugins/paste"; //黏贴插件
     import "tinymce/icons/default/icons";
+    import {setting} from '@/views/ppt_manage/newVersion/utils/tinymceSetting'
     export default {
         mixins: [elMixin],
         props: {
@@ -77,33 +79,14 @@
         data() {
             return {
                 setting: {
+                    ...setting,
                     language: "zh_CN",
                     language_url: require("../../../utils/zh_CN.js"),
-                    menubar: false,
-                    toolbar: [
-                        "indent outdent alignleft aligncenter alignright alignjustify forecolor",
-                        "bold italic underline strikethrough numlist bullist backcolor",
-                        "fontselect fontsizeselect",
-                    ],
-                    quickbars_selection_toolbar: false,
-                    quickbars_insert_toolbar: false,
-                    plugins: "lists quickbars paste",
                     height: 350,
                     inline: true,
                     selector: `#${this.elementInfo.id}-editorDom`,
                     paste_as_text: true,
-                    fontsize_formats: '12px 14px 16px 18px 20px 22px 24px 36px 48px',
-                    font_formats: `微软雅黑='微软雅黑';宋体='宋体';黑体='黑体';仿宋='仿宋';
-                        楷体='楷体';隶书='隶书';幼圆='幼圆';Andale Mono=andale mono,times;
-                        Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;
-                        Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;
-                        Courier New=courier new,courier;Georgia=georgia,palatino;
-                        Helvetica=helvetica;Impact=impact,chicago;
-                        Webdings=webdings;Wingdings=wingdings`,
                     fixed_toolbar_container: ".cover-text-toolbar", //将toolbar放到指定div上
-                    skin_url: "/static/css",
-                    content_url: "/static/css",
-                    //加placeholder
                     placeholder:this.$t('Slides.click_input_text_content')
                 }
             };

+ 1 - 1
src/views/ppt_manage/newVersion/components/formatEl/ChartEl.vue

@@ -55,7 +55,7 @@
     <!-- 图表说明 -->
     <div 
       class="chart-instruction text_oneLine"
-      v-if="chartInstructions&&chartInstructions.isShow"
+      v-if="chartInstructions&&chartInstructions.isShow&&chartInstructions.text.length"
       v-text="chartInstructions.text"
       :style="`
         color: ${chartInstructions.color};

+ 21 - 2
src/views/ppt_manage/newVersion/components/formatEl/SheetEl.vue

@@ -52,6 +52,15 @@
       @click.stop="delChart(position)"
       v-if="isBtnShow"
     ></div>
+  <div class="chart-source">
+    <span
+      v-if="sheetSourceFrom && sheetSourceFrom.isShow"
+      :style="`
+      color: ${sheetSourceFrom.isShow ? sheetSourceFrom.color : '#999'};
+      font-size: ${ sheetSourceFrom.fontSize }px;
+    `"
+    ><!-- 来源 -->{{$t('ETable.Common.source')}}:{{ sheetSourceFrom.text}}</span>
+  </div>
 </div>
   
 </template>
@@ -69,13 +78,18 @@ export default {
     return {
       tableData:[],
       type:'sheet',
-      tableKey:0
+      tableKey:0,
+      sheetSourceFrom:{}
     };
   },
   methods:{
     getSheetData(id,value){
       this.tableKey++
-      this.tableData = value
+      if(value){
+        this.tableData = value.list
+        this.sheetSourceFrom=(value.otherParams && value.otherParams.SourcesFrom) ? JSON.parse(value.otherParams.SourcesFrom):''
+      }
+
     }
   },
   mounted(){
@@ -104,4 +118,9 @@ export default {
 			}
   }
 }
+.chart-source{
+  width: 95%;
+  position: absolute;
+  left: 2%;
+}
 </style>

+ 2 - 55
src/views/ppt_manage/newVersion/components/formatEl/TextEl.vue

@@ -43,6 +43,7 @@ import "tinymce/plugins/quickbars"; //快速栏插件
 import "tinymce/plugins/fullscreen"; //全屏插件
 import "tinymce/plugins/paste"; //黏贴插件
 import "tinymce/icons/default/icons";
+import {setting} from '@/views/ppt_manage/newVersion/utils/tinymceSetting'
 export default {
   components:{Editor},
   props:{
@@ -56,36 +57,15 @@ export default {
   data() {
     return {
       setting: {
+        ...setting,
         language: "zh_CN",
         language_url: require("../../utils/zh_CN.js"),
-        menubar: false,
-        toolbar: [
-          "indent outdent alignleft aligncenter alignright alignjustify forecolor",
-          "bold italic underline strikethrough numlist bullist backcolor",
-          "fontselect fontsizeselect",
-        ],
-        quickbars_selection_toolbar:false,  
-        quickbars_insert_toolbar: false,
-        plugins: "lists quickbars paste",
         height: 350,
-        inline: true,
         selector: `#text_${this.index}_${this.position}`,
         paste_as_text: true,
        /*  paste_block_drop: true, 开启后阻止drop事件*/
-        fontsize_formats:'12px 14px 16px 18px 20px 22px 24px 36px 48px',
-        font_formats:`微软雅黑='微软雅黑';宋体='宋体';黑体='黑体';仿宋='仿宋';
-                      楷体='楷体';隶书='隶书';幼圆='幼圆';Andale Mono=andale mono,times;
-                      Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;
-                      Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;
-                      Courier New=courier new,courier;Georgia=georgia,palatino;
-                      Helvetica=helvetica;Impact=impact,chicago;
-                      Webdings=webdings;Wingdings=wingdings`,
-        /* toolbar_persist:true,//始终显示toolbar */
         fixed_toolbar_container: ".richtext-tool",//将toolbar放到指定div上
-        skin_url: "/static/css",
-        content_url: "/static/css",
         placeholder:this.$t('Slides.click_input_text_content')
-       
       },
       content:'',
       initFlag: false,
@@ -150,38 +130,5 @@ export default {
     left:-10px;
     top:-10px;
   }
-  .mce-content-body {
-    width: 100%;
-    height: 100%;
-    padding: 10px;
-    box-sizing: border-box;
-    font-size: 16px;
-    &:focus-visible{
-      outline: 0;
-    }
-    ul{
-      margin-left: 1em;
-      list-style-type: disc;
-    }
-    ol{
-      margin-left: 1em;
-      list-style-type: decimal;
-    }
-  }
-  .mce-edit-focus{
-    outline: 0;
-  }
-  .tox .tox-tbtn--bespoke .tox-tbtn__select-label{
-    width:4.5em !important;
-  }
-  .tox .tox-tbtn{
-    width:32px;
-  }
-  .tox-menu.tox-swatches-menu.tox-selected-menu{
-    left:185px !important;
-  }
-  .mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before {
-    left:10px !important;
-  }
 }
 </style>

+ 80 - 0
src/views/ppt_manage/newVersion/components/formatPage/FormatThirteen.vue

@@ -0,0 +1,80 @@
+<template>
+    <div class="total-wrap flex-column format-thirteen" :style="{'pointer-events' :isPreview?'none':'auto'}">
+      <div class="wrap-full-top flex-center" :style="pageItem.layers&&!isLayerShow()?TypeName(1)==='ChartEl'?'z-index:5':'z-index:3':''">
+        <component
+          :data-position="1"
+          :is="TypeName(1)"
+          :ref="RefName(1)"
+          :index="pageIndex"
+          :position="1"
+          :item="Item(1)"
+          @dragstart.native="onDragStart"
+          @dragover.native="onDragOver"
+          @drop.native="onDrop"
+          @getText="getText($event,1)"
+        ></component>
+      </div>
+      <div class="wrap-full-bottom flex-center" :style="pageItem.layers&&!isLayerShow()?TypeName(2)==='ChartEl'?'z-index:5':'z-index:3':''">
+        <component
+          :data-position="2"
+          :is="TypeName(2)"
+          :ref="RefName(2)"
+          :index="pageIndex"
+          :position="2"
+          :item="Item(2)"
+          @dragstart.native="onDragStart"
+          @dragover.native="onDragOver"
+          @drop.native="onDrop"
+          @getText="getText($event,2)"
+        ></component>
+      </div>
+      <!-- 图层编辑模式 -->
+      <div class="layers" :id="`layers_${pageItem.id}`"
+          v-if="isLayerShow()" @click.stop="clickLayer" @contextmenu.stop="showLayerContentMenu">
+        <template v-for="item in pageItem.layers">
+          <component
+            :is="getLayerElName(item)"
+            :key="item.id"
+            :elementInfo="item"
+            :isActive="item.id===activeLayerEl.id&&!isClickLayer"
+            :isLayerEdit="true"
+            @click.stop.native="changeActEl(item)"
+            @chooseThis="changeActEl(item)"
+            v-on="$listeners"
+          ></component>
+          <!-- @deleteLayer="delLayer" -->
+        </template>
+      </div>
+      <!-- 非图层编辑模式 -->
+      <template v-else>
+        <template v-for="item in pageItem.layers">
+          <component
+            :is="getLayerElName(item)"
+            :key="item.id"
+            :elementInfo="item"
+            :isActive="false"
+            :isLayerEdit="false"
+          ></component>
+        </template>
+      </template>
+    </div>
+  </template>
+  
+  <script>
+  import mixin from "./mixins";
+  import {defaultPosition} from "../../utils/config";
+  export default {
+    name: "formatThirteen",
+    mixins: [mixin],
+    data(){
+      return {
+        modelId:13,
+        positionInfo:defaultPosition[13]
+      }
+    },
+  };
+  </script>
+  
+  <style scoped lang="scss">
+  </style>
+  

+ 12 - 4
src/views/ppt_manage/newVersion/components/formatPage/mixins.js

@@ -1,7 +1,7 @@
 import {checkClipboard,checkClipboardItems,getTextContentSize} from '../../utils/untils';
 import {defaultPosition} from "../../utils/config";
 import { copyFit } from '@/utils/svgToblob.js';
-import Ediotr from '../TextEditor.vue';
+/* import Ediotr from '../TextEditor.vue'; */
 import BaseShape from '../layer/Element/BaseShape.vue';
 import LineShape from "../layer/Element/LineShape.vue";
 import TextShape from "../layer/Element/TextShape.vue";
@@ -11,7 +11,7 @@ import ImageEl from "../formatEl/ImageEl.vue";
 import SheetEl from "../formatEl/SheetEl.vue";
 export default {
     components: {
-        Ediotr,BaseShape,LineShape,TextShape,ChartEl,TextEl,ImageEl,SheetEl
+        /* Ediotr, */BaseShape,LineShape,TextShape,ChartEl,TextEl,ImageEl,SheetEl
       },
     props: {
         pageIndex: {//当前是第几页
@@ -45,6 +45,10 @@ export default {
           type:Boolean,
           default:false
         },
+        isEditTitle:{//父组件是否是标题编辑模式
+            type:Boolean,
+            default:false
+          },
         activeLayerEl:{//当前页面在图层编辑模式时,选中的图层元素
           type:Object,
         },
@@ -100,8 +104,8 @@ export default {
         },
         //判断遮罩layers是否显示
         isLayerShow(){
-          //在图层编辑模式+是当前ppt+是编辑模式
-          return this.isEditLayer&&this.type==='edit'&&this.choosedId===this.pageItem.id
+          //在图层编辑模式/标题编辑模式+是当前ppt+是编辑模式
+          return (this.isEditLayer/* ||this.isEditTitle */)&&this.type==='edit'&&this.choosedId===this.pageItem.id
         },
         //判断该渲染哪个图层组件
         getLayerElName(item){
@@ -117,6 +121,7 @@ export default {
         },
         //切换当前选中的图层元素
         changeActEl(item){
+          if(!this.isEditLayer) return
           this.isClickLayer = false
           //如果该元素已被选中,则什么也不做
           const id = this.activeLayerEl.id
@@ -150,6 +155,7 @@ export default {
         },
         //删除这张图表
         delChart(position) {
+            this.$parent.isEditTitle = false
             this.$emit('delChart', position)
         },
         //自主黏贴事件:ctrl+v
@@ -242,6 +248,7 @@ export default {
             return
           } */
           if(this.choosedId!==this.pageItem.id) return
+          this.$parent.isEditTitle = false
           this.dragElement = e.currentTarget
           if(dragInfo.type!=='text'){
             //设置拖拽反馈图像
@@ -293,6 +300,7 @@ export default {
           }catch(err){
             this.$message.error(/*'复制失败'*/this.$t('MsgPrompt.copy_fail_msg'))
           }
+          this.$parent.isEditTitle = false
         },
         addChart(position){
           const {chartId} = this.pageItem.elements.find(i=>i.position===position)

+ 4 - 1
src/views/ppt_manage/newVersion/components/formatPreview/FormatPreEle.vue

@@ -31,8 +31,11 @@
   <style scoped lang="scss">
   .format-pre-wrap{
     .line{
+        width:100%;
+        height: 30%;
         img{
-            width:40%;
+            width: 50%;
+            height: 100%;
         }
     }
   }

+ 26 - 0
src/views/ppt_manage/newVersion/components/formatPreview/FormatPreThirteen.vue

@@ -0,0 +1,26 @@
+<template>
+    <div class="format-pre-wrap flex-center" style="flex-direction: column;">
+      <div class="half-top flex-center">
+        <img class="full" style="object-fit:fill !important;"
+          src="~@/assets/img/ppt_m/format-pic.png" />
+      </div>
+      <div class="half-bottom flex-center">
+        <img class="full" style="object-fit:fill !important;"
+          src="~@/assets/img/ppt_m/format-pic.png" />
+      </div>
+    </div>
+  </template>
+  
+  <script>
+  export default {
+    name: "formatPreThirteen",
+    data() {
+      return {};
+    },
+    methods: {},
+  };
+  </script>
+  
+  <style scoped lang="scss">
+  </style>
+  

+ 3 - 22
src/views/ppt_manage/newVersion/components/layer/Element/TextShape.vue

@@ -50,6 +50,7 @@
 <script>
 import {BaseTextShape} from '../../../utils/config';
 import shapeMixin from './shapeMixin';
+import tinymce from "tinymce";
 import Editor from "@tinymce/tinymce-vue";
 import "tinymce/themes/silver";
 import "tinymce/plugins/lists"; //列表插件
@@ -57,6 +58,7 @@ import "tinymce/plugins/quickbars"; //快速栏插件
 import "tinymce/plugins/fullscreen"; //全屏插件
 import "tinymce/plugins/paste"; //黏贴插件
 import "tinymce/icons/default/icons";
+import {setting} from '@/views/ppt_manage/newVersion/utils/tinymceSetting'
 export default {
   mixins:[shapeMixin],
   props:{
@@ -71,34 +73,13 @@ export default {
   data() {
     return {
       setting: {
+        ...setting,
         language: "zh_CN",
         language_url: require("../../../utils/zh_CN.js"),
-        menubar: false,
-        toolbar: [
-          "indent outdent alignleft aligncenter alignright alignjustify forecolor",
-          "bold italic underline strikethrough numlist bullist backcolor",
-          "fontselect fontsizeselect",
-        ],
-        quickbars_selection_toolbar:false,  
-        quickbars_insert_toolbar: false,
-        plugins: "lists quickbars paste",
         height: 350,
-        inline: true,
         selector: `#${this.elementInfo.id}-editorDom`,
         paste_as_text: true,
-        fontsize_formats:'12px 14px 16px 18px 20px 22px 24px 36px 48px',
-        font_formats:`微软雅黑='微软雅黑';宋体='宋体';黑体='黑体';仿宋='仿宋';
-                      楷体='楷体';隶书='隶书';幼圆='幼圆';Andale Mono=andale mono,times;
-                      Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;
-                      Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;
-                      Courier New=courier new,courier;Georgia=georgia,palatino;
-                      Helvetica=helvetica;Impact=impact,chicago;
-                      Webdings=webdings;Wingdings=wingdings`,
-        /* toolbar_persist:true,//始终显示toolbar */
         fixed_toolbar_container: ".layer-text-toolbar",//将toolbar放到指定div上
-        skin_url: "/static/css",
-        content_url: "/static/css",
-        //加placeholder
         placeholder:this.$t('Slides.click_input_text_content')
       }
     };

+ 111 - 1
src/views/ppt_manage/newVersion/css/common.scss

@@ -5,7 +5,52 @@ $titleColor:#333333;
     * {
         box-sizing: border-box;
     }
+    .el-tabs__nav-wrap::after {
+        height: 0;
+    }
+    .el-tabs__item { font-size: 16px; }
 
+    //富文本编辑器样式
+    .mce-content-body{
+        width: 100%;
+        height: 100%;
+        padding: 10px;
+        box-sizing: border-box;
+        font-size: 16px;
+        &:focus-visible{
+            outline: 0;
+        }
+        ul{
+            margin-left: 1em;
+            list-style-type: disc;
+          }
+          ol{
+            margin-left: 1em;
+            list-style-type: decimal;
+          }
+    }
+    .mce-edit-focus{
+        outline: 0;
+    }
+    .mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before {
+        left:10px !important;
+    }
+    .mce-content-body.placeholder-hidden:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{
+        display: none;
+    }
+    .tox .tox-tbtn--bespoke .tox-tbtn__select-label{
+        width:4.5em !important;
+      }
+    .tox-menu.tox-swatches-menu.tox-selected-menu{
+        left:auto !important;
+        right:0;
+    }
+    .tox{
+        .tox-collection__group{
+            max-height: 200px;
+            overflow-y: auto;
+        }
+    }
     //wrap
     .ppt-page-wrap {
         background-color: #fff;
@@ -29,7 +74,7 @@ $titleColor:#333333;
             align-items: center;
             transform-origin: 0 0;
             word-break: break-word;
-            input{
+            input,textarea{
                 font-size: 24px;
                 color:$titleColor;
                 background: transparent;
@@ -48,6 +93,71 @@ $titleColor:#333333;
         -webkit-box-orient:vertical;
         word-break: break-word;
     }
+    .custom-title-wrap{
+        position: absolute;
+        transform-origin: 0 0;
+        &.editor-model{
+            //background-color: #99999946;
+        }
+        &.ppt-editor-title{
+            border:1px dashed #999;
+        }
+        .title{
+            width:100%;
+            height:100%;
+            font-size: 16px;
+            word-break: break-all;
+            ul{
+                margin-left: 1em;
+                list-style-type: disc;
+              }
+              ol{
+                margin-left: 1em;
+                list-style-type: decimal;
+              }
+        }
+        textarea{
+            font-size: 24px;
+            color:$titleColor;
+            background: transparent;
+            border: none;
+            width:100%;
+            height:auto;
+            /* overflow-y: hidden; */
+            resize: none;
+            &.el-textarea__inner{
+                padding:0;
+                line-height: 1;
+                /* height:auto !important; */
+                color:var(--titleColor);
+                font-size:var(--fontSize);
+                font-family: var(--fontFamily);
+            }
+        }
+        .normal-title{
+            font-size: 16px;
+            word-break: break-all;
+        }
+    }
+    .ppt-tool{
+        .layer-edit-box,.title-edit-box{
+          .tool-list{
+            border:none;
+            .el-collapse-item:first-child{
+                .el-collapse-item__content{
+                    padding-bottom: 5px;
+                }
+            }
+            .el-collapse-item__header{
+              margin-bottom: 0;
+              height: 40px;
+            }
+            .el-collapse-item__wrap{
+              overflow: visible;
+            }
+          }
+        }
+      }
 
     .hint-text {
         text-align: center;

+ 37 - 16
src/views/ppt_manage/newVersion/css/format.scss

@@ -144,7 +144,7 @@ $marginTop:14%;
       width: 100%;
       height: calc(100% - #{$marginTop});
       display: flex;
-      .chart-bottom-insruction-info{
+      .chart-bottom-insruction-info,.chart-source{
             margin-top: 0 !important;
         }
     }
@@ -172,7 +172,7 @@ $marginTop:14%;
             top:0;
             right:calc(5% - 10px);
         }
-        .chart-bottom-insruction-info{
+        .chart-bottom-insruction-info,.chart-source{
             bottom:4%;
         }
     }
@@ -196,7 +196,7 @@ $marginTop:14%;
             top:calc(10% - 10px);
             right:calc(5% - 10px);
         }
-        .chart-bottom-insruction-info{
+        .chart-bottom-insruction-info,.chart-source{
             top:89%;
         }
     }
@@ -217,7 +217,7 @@ $marginTop:14%;
           width: 100%;
           height: 80%;
         }
-        .chart-bottom-insruction-info{
+        .chart-bottom-insruction-info,.chart-source{
             top:89%;
         }
     }
@@ -242,7 +242,7 @@ $marginTop:14%;
                     top:calc(4% - 10px);
                     right:2.5%;
                 }
-                .chart-bottom-insruction-info{
+                .chart-bottom-insruction-info,.chart-source{
                     top:89%;
                 }
             }
@@ -267,7 +267,7 @@ $marginTop:14%;
                     top:0;
                     right:2.5%;
                 }
-                .chart-bottom-insruction-info{
+                .chart-bottom-insruction-info,.chart-source{
                     top:84%;
                 }
             }
@@ -284,7 +284,7 @@ $marginTop:14%;
             top:calc(10% - 10px);
             right:calc(5% - 10px);
         }
-        .chart-bottom-insruction-info{
+        .chart-bottom-insruction-info,.chart-source{
             top:90%;
         }
     }
@@ -308,7 +308,7 @@ $marginTop:14%;
                   top:calc(4% - 10px);
                   right:2.5%;
                 }
-                .chart-bottom-insruction-info{
+                .chart-bottom-insruction-info,.chart-source{
                     top:89%;
                 }
             }
@@ -334,7 +334,7 @@ $marginTop:14%;
                     top:0;
                     right:2.5%;
                 }
-                .chart-bottom-insruction-info{
+                .chart-bottom-insruction-info,.chart-source{
                     top:84%;
                 }
             }
@@ -351,25 +351,28 @@ $marginTop:14%;
             top:calc(10% - 10px);
             right:calc(5% - 10px);
         }
-        .chart-bottom-insruction-info{
+        .chart-bottom-insruction-info,.chart-source{
             top:90%;
         }
     }
 
-    //版式8 9
+    //版式8 9 13
     .wrap-full-top,.wrap-full-bottom{
       width:100%;
       height:50%;
       position:relative;
+      .chart-bottom-insruction-info{
+        top:93%;
+      }
       &.top-70{
         height:70%;
-        .chart-bottom-insruction-info{
+        .chart-bottom-insruction-info,.chart-source{
             top:93%;
         }
       }
       &.bottom-30{
         height: 30%;
-        .chart-bottom-insruction-info{
+        .chart-bottom-insruction-info,.chart-source{
             top:85%;
         }
       }
@@ -422,10 +425,28 @@ $marginTop:14%;
       }
     }
     .format-nine{
-        .chart-bottom-insruction-info{
+        .chart-bottom-insruction-info,.chart-source{
             top:93%;
         }
     }
+    .format-thirteen{
+        .wrap-full-top{
+            .chart-wrap{
+                top: 2%;
+            }
+            .chart-bottom-insruction-info{
+                top:92%;
+            }
+        }
+        .wrap-full-bottom{
+            .chart-wrap{
+                top: 0%;
+            }
+            .chart-bottom-insruction-info{
+                top:90%;
+            }
+        }
+    }
     
     //layer-mask 更改版式345 9布局, ↑原先样式保留不动
     .wrap-full-left-half{
@@ -531,7 +552,7 @@ $marginTop:14%;
                     width:90%;
                     height:90%
                 }
-                .chart-bottom-insruction-info{
+                .chart-bottom-insruction-info,.chart-source{
                     top:92%;
                 }
             }
@@ -543,7 +564,7 @@ $marginTop:14%;
         }
         .bottom-15{
             height: 18%;
-            .chart-bottom-insruction-info{
+            .chart-bottom-insruction-info,.chart-source{
                 top:80%;
             }
         }

+ 14 - 14
src/views/ppt_manage/newVersion/pptCatalog.vue

@@ -227,7 +227,7 @@
               :style="item.BackgroundImg?{background: `no-repeat top/cover url('${item.BackgroundImg}')`}:{}">
                 <span>{{item.Title}}</span>
               </div>
-              <span style="font-size:14px;">{{$t('Slides.creation_time')}}:{{$moment(item.PptCreateTime).format('YYYY-MM-DD')}}</span>
+              <span style="font-size:14px;">{{$t('Slides.creation_time')}}:{{$moment(item.PptModifyTime).format('YYYY-MM-DD')}}</span>
             </div> -->
             <div class="list-item" 
                 v-for="item in catalogPPTList" :key="item.PptId"
@@ -242,12 +242,10 @@
                     </span>
                 </div>
                 <div class="item-foot" style="margin-bottom:0;">
-                    <span style="font-size:14px;">{{$t('Slides.creation_time')}}:{{$moment(item.PptCreateTime).format('YYYY-MM-DD')}}</span>
-                    <img
-                        v-if="treeName==='private'&&selectNode"
-                        src="~@/assets/img/ppt_m/move_ico2.png"
-                        style="width: 14px; height: 14px; margin-right: 8px"
-                    />
+                  <el-tooltip :content="$t('Slides.update_time')" placement='top' :enterable="false">
+                    <span class="item-update-item">{{$moment(item.PptModifyTime).format('YYYY-MM-DD HH:mm:ss')}}</span>
+                  </el-tooltip>
+                  <span>{{ $i18n.locale == 'zh'?`${item.PptPage}页`:`P${item.PptPage}` }}</span>
                 </div>
             </div>
           </draggable>
@@ -274,7 +272,7 @@
           <div class="ppt-info">
             <div> {{$t('Slides.author_info')}}:{{pptItem.AdminRealName}}</div>
             <div>
-              {{pptItem.PptxUrl? $t('Slides.publish_info'):$t('Slides.save_info')}}
+              {{pptItem.PptxUrl? $t('Slides.publish_ab'):$t('Slides.save_info')}}
               {{$t('Slides.time_info')}}:{{$moment(pptItem.PptxUrl?pptItem.PublishTime || undefined:pptItem.PptModifyTime || undefined).format('YYYY-MM-DD')}}
             </div>
           </div>
@@ -571,14 +569,14 @@ export default {
         this.$nextTick(()=>{
            //选中节点
           this.$refs[`${this.treeName}Tree`].setCurrentKey(item.nodeKeyId)
-          //展开该节点的父节点
+          //找到该节点的父节点,展开,获取父节点id
           const node = this.$refs[`${this.treeName}Tree`].getCurrentNode()
           !this[`${this.treeName}ExpandKeys`].includes(node.catalogId)&&this[`${this.treeName}ExpandKeys`].push(node.catalogId)
+          this.pptItem.catalogId = node.catalogId||''
           this.selectNode = item
         })
       }else{
         //获取目录下的ppt列表:getCatalogListByGroupId/getCatalogListByAdminId
-
         const res = this.treeName==='public' 
           ? await pptInterface.getCatalogListByAdminId({ AdminId:item.AdminId||''})
           : this.treeName==='private'
@@ -773,13 +771,13 @@ export default {
             this.$refs[`${this.treeName}Tree`].setCurrentKey(data.catalogId)
             //删除的是公共目录下,某目录的最后一个PPT时,该公共目录会消失
             if(this.treeName==='public'&&catalog.PptList.length>1){
-              this.changeModel('list',catalog)
+              this.changeModel('list',catalog||{})
             }else if(this.treeName==='public'&&catalog.PptList.length===1){
               this.changeModel('list',{})
             }
             //但是私有目录不会
             if(this.treeName==='private'){
-              this.changeModel('list',catalog)
+              this.changeModel('list',catalog||{})
             }
           }
         })
@@ -1596,9 +1594,11 @@ export default {
             margin-bottom: 10px;
             font-size: 16px;
             span{
-              flex:1;
-              overflow: hidden;
+              font-size:14px;
               white-space: nowrap;
+            }
+            .item-update-item{
+              overflow: hidden;
               text-overflow: ellipsis;
             }
             img{

+ 118 - 60
src/views/ppt_manage/newVersion/pptEditor.vue

@@ -46,7 +46,7 @@
         </div>
     </div>
     <div class="ppt-editor-wrap ppt-page-wrap" v-loading="isChartLoading" :element-loading-text="chartLoadingText">
-        <div class="ppt-editor" ref="pptEditor" @paste="handlePasteOutSide">
+        <div class="ppt-editor" id="pptEditor" ref="pptEditor" @paste="handlePasteOutSide">
             <!-- 显示全部ppt -->
             <template v-if="pageList.length">
                 <!-- <transition-group name="flip-list"> -->
@@ -54,10 +54,52 @@
                     <AddFormat @addPage="addPage($event,index)" :chooseModalId="chooseModalId"/>
                     <div class="ppt-item" :class="{'choose':currentItem.id===item.id}" 
                         v-loading="item.isUpdating" :element-loading-text="$t('Slides.updating_chart_loading')"
-                        @click="changeCurrentItem(item)">
+                        @click.stop="changeCurrentItem(item)">
                         <!-- 标题 -->
-                        <div class="title-wrap">
-                            <input type="text" :placeholder="$t('Slides.click_to_input_title')" v-model="item.title"/> 
+                        <!-- <div class="title-wrap" style="background-color: #999999;">
+                            <input type="text" placeholder="单击输入标题" v-model="item.title"/> 
+                        </div> -->
+                        <!-- 自定义标题 -->
+                        <div @click.stop
+                            :class="[
+                                'ppt-editor-title',
+                                'custom-title-wrap',
+                                currentItem.id===item.id&&isEditTitle?'editor-model':''
+                                ]" 
+                            :style="item.titleDetail?{
+                                left:item.titleDetail.left+'%',
+                                top:item.titleDetail.top+'%',
+                                width:item.titleDetail.width+'%',
+                                height:item.titleDetail.height+'%',
+                            }:{
+                                left:'10%',top:'6.6%',width:'68%',height:'5%',
+                            }">
+                            <!-- <div class="title" v-html="item.title"></div> -->
+                            <!-- <el-input type="textarea" placeholder="单击输入标题" v-model="item.title" 
+                                autosize resize="none"
+                                spellcheck="false"
+                                :style="item.titleDetail?{
+                                    color:item.titleDetail.color,
+                                    fontSize:item.titleDetail.fontSize+'px',
+                                    fontFamily:item.titleDetail.fontFamily,
+                                    '--titleColor':item.titleDetail.color,
+                                    '--fontSize':item.titleDetail.fontSize,
+                                    '--fontFamily':item.titleDetail.fontFamily,
+                                }:{ color:'#333',fontSize:'22px',fontFamily:'helvetica' }"
+                                @focus="handleEditTitle(item)"
+                                v-click-title-outside="exitEditTitle"></el-input>  -->
+                                <div contenteditable="true" spellcheck="false" 
+                                :id="`page_title__${index}`"
+                                class="title-editor"
+                                :style="item.titleDetail?{
+                                    color:item.titleDetail.color||'#333',
+                                    fontSize:(item.titleDetail.fontSize||22)+'px',
+                                    fontFamily:(item.titleDetail.fontFamily||'helvetica'),
+                                    outline:0,
+                                }:{ color:'#333',fontSize:'22px',fontFamily:'helvetica',outline:0}"
+                                    v-click-title-outside="exitEditTitle"
+                                    @click.stop="handleEditTitle(item)"
+                                    @input="(e)=>testInput(e,item)"></div>
                         </div>
                         <!-- 内容 -->
                         <component  :is="getComponentName(item.modelId)"
@@ -68,6 +110,7 @@
                                     :isCopy="true"
                                     :isAdd="true"
                                     :isEditLayer="isEditLayer"
+                                    :isEditTitle="isEditTitle"
                                     :choosedId="currentItem.id"
                                     :activeLayerEl="activeLayerEl"
                                     :amendatoryPositionInfo="item.positionInfo"
@@ -94,7 +137,7 @@
                         <!-- 页码 -->
                         <span class="page-num"> {{$i18n.locale == 'zh' ?`第${index+1}页`:` Slide${index+1}`}}</span>
                         <!-- 更新图表 -->
-                        <span class="update-btn" v-show="item.modelId!==6&&item.elements.find((i)=>i.type==='chart')" @click.stop="updatePage(item)"><span class="update-ico"></span> {{$t('Slides.update_chart_btn')}}</span>
+                        <span class="update-btn" v-show="item.modelId!==6&&item.elements.find((i)=>i.type==='chart'||i.type==='sheet')" @click.stop="updatePage(item)"><span class="update-ico"></span> {{$t('Slides.update_chart_btn')}}</span>
                     </div>
                     <AddFormat v-if="index===pageList.length-1" @addPage="addPage($event,index+1)" :chooseModalId="chooseModalId"/>
                 </div> 
@@ -113,6 +156,7 @@
                 style="color: #666; margin-bottom: 15px"
             >{{$t('Slides.last_save_time')}}:{{lastSaveTime}}</div>
             <div class="tool-btn">
+                <el-button type="primary" :loading="refreshBtnLoading" @click="refleshFormatEl">{{$t('Slides.operations_refresh')}}</el-button>
                 <el-button v-permission="permissionBtn.pptPermission.ppt_publish"
                  type="primary" @click="handlePublish">{{$t('Slides.go_to_publish')}}</el-button>
                 <el-button @click="handleSave('save')">{{$t('Slides.operations_save')}}</el-button>
@@ -120,7 +164,7 @@
             </div>
             <div class="richtext-tool"></div>
             <!-- 防止el-tabs未渲染时触发scrollToActiveTab 报错,v-if改为v-show-->
-            <div class="addppt-right-box" v-show="!isEditLayer">
+            <div class="addppt-right-box" v-show="!isEditLayer&&!isEditTitle">
               <el-tabs v-model="tabsactive">
                 <el-tab-pane :label="tab.label" :name="tab.val" v-for="tab in panelTabs" :key="tab.val"></el-tab-pane>
               </el-tabs>
@@ -186,7 +230,7 @@
               </div>
             </div>
             <!-- 图层编辑 -->
-            <div class="layer-edit-box" v-show="isEditLayer">
+            <div class="layer-edit-box" v-if="isEditLayer">
               	<el-collapse v-model="activeNames" class="tool-list">
                   <el-collapse-item :title="$t('Slides.layer_element')" name="el">
                     <div class="el-wrap">
@@ -225,6 +269,20 @@
                   </el-collapse-item>
                 </el-collapse>
             </div>
+            <!-- 标题编辑 -->
+            <div class="title-edit-box" v-if="isEditTitle">
+                <p>
+                    {{$t('Slides.page_title_style_setting')}}
+                </p>
+                <TitleEditorTool 
+                    ref="titleEditor"
+                    :currentItem="currentItem"
+                    @changeSizeAll="changeSizeAll"
+                    @changePositionAll="changePositionAll"
+                    @styleChange="handleTitelStyleChange"
+                    @textChange="handleTextChange"
+                    @applyToAll="changeSettingAll"/>
+            </div>
           </div>
     </div>
 
@@ -279,7 +337,7 @@
 </template>
 
 <script>
-import {countComponentName,checkClipboardItems,createRandomCode,checkPPTpageElemant,getChartInfo} from './utils/untils';
+import {countComponentName,checkClipboardItems,createRandomCode,checkPPTpageElemant,getChartInfo,getPlainText} from './utils/untils';
 import {modelInfo,defaultPosition} from './utils/config'
 import http from '@/api/http.js';
 import { dataBaseInterface ,sandInterface } from "@/api/api.js";
@@ -309,6 +367,7 @@ import InsertCharts from './components/editor/InsertCharts.vue';
 import ContextMenu from './components/ContextMenu.vue';
 import InsertSemantics from './components/editor/InsertSemantics.vue';
 import ChooseCoverNew from './components/editor/ChooseCoverNew.vue';
+import TitleEditorTool from './components/editor/TitleEditorTool';
 export default {
   mixins:[pptmixin,//ppt页面共同逻辑
           mixins,//图表加载逻辑
@@ -318,7 +377,7 @@ export default {
   components: {
     IndexItem, ChooseCover, AddFormat, ShapePreview,
     LayerEditTool, DeletePageDialog, ChangeFormatDialog, InsertPageDialog, addMyClassifyDia, InsertCharts, ContextMenu, InsertSemantics,
-    ChooseCoverNew
+    ChooseCoverNew,TitleEditorTool
 },
   data() {
     return {
@@ -463,7 +522,7 @@ export default {
       //防止自动保存时,有某一页处于更新图表的状态,其isUpdating为true
       this.pageList.forEach(i=>{
         i.isUpdating = false
-      })     
+      })
       this.dataLoading.close();
       $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
       //开启自动保存
@@ -475,13 +534,14 @@ export default {
         await this.getpptDataById(id)
         const {status} = this.result
         if(status===200){
-          const {content,FirstPage,ReportId} = this.result
+          const {content,FirstPage,ReportId,TitleSetting} = this.result
           this.pageList = content
           this.firstPage = FirstPage
           this.firstPage.BackIndex = FirstPage.TemplateType-1
           this.currentItem = this.pageList[0]
           this.ReportId=ReportId
           this.CoverContent = this.result.CoverContent
+          this.titleSetting = TitleSetting||null
           /* //开启自动保存
           this.autoSave() */
         }else{
@@ -518,6 +578,7 @@ export default {
             modelId: modelId,
             title:'',
             elements: [],
+            titleDetail:this.titleSetting?this.titleSetting:null
         }
         //限制取消
         /* if(this.pageList.length>=this.maxPageNum){
@@ -741,6 +802,13 @@ export default {
         if(this.currentItem&&this.currentItem.id!==id){
           this.isEditLayer = false
           this.activeLayerEl = {}
+          
+          this.isEditTitle = false
+        }
+        //点击当前页时,退出标题编辑模式
+        if(this.currentItem&&this.currentItem.id===id){
+            this.isEditTitle = false
+            return 
         }
         this.pageList.map((item,index)=>{
           if(item.id===id){
@@ -750,9 +818,16 @@ export default {
         })
         this.$nextTick(()=>{
           let height = $('.ppt-editor-item')[0].offsetHeight
+          const index = this.currentIndex
           //pptEditor的滚动条动画
-          this.$refs.pptEditor.scrollTo({
-              top:height*this.currentIndex,
+          /* this.$refs.pptEditor.scrollTo({
+              top:height*index,
+              left:0,
+              behavior: 'smooth'
+          }) */
+          const pptEditorDom = document.getElementById('pptEditor')
+          pptEditorDom.scrollTo({
+            top:height*index,
               left:0,
               behavior: 'smooth'
           })
@@ -1048,7 +1123,8 @@ export default {
         FirstPage:FirstPage,
         Content:Content,
         GroupId:this.catalogId,
-        CoverContent:this.CoverContent
+        CoverContent:this.CoverContent,
+        TitleSetting:JSON.stringify(this.titleSetting)
       }).then(res=>{
         this.isSaved = false
         if(res.Ret===200){
@@ -1069,7 +1145,8 @@ export default {
         PptId:parseInt(ppt_id),
         FirstPage:FirstPage,
         Content:Content,
-        CoverContent:this.CoverContent
+        CoverContent:this.CoverContent,
+        TitleSetting:JSON.stringify(this.titleSetting)
       }).then(res=>{
         this.isSaved = false
         if(res.Ret===200){
@@ -1092,6 +1169,8 @@ export default {
       if(this.loopTimer) return 
       if(!this.$route.query.id&&!this.pptId) return
       this.loopTimer = setInterval(()=>{
+        //如果当前在刷新图表,则不进行自动保存
+        if(this.refreshBtnLoading) return
         const ppt_id = this.$route.query.id||this.pptId
         const {Title,ReportType,PptDate,BackgroundImg,BackIndex} = this.firstPage
         const FirstPage = {
@@ -1105,11 +1184,13 @@ export default {
           return i
         })
         let Content = JSON.stringify(pageList) 
+        let TitleSetting = JSON.stringify(this.titleSetting)
         pptInterface.saveLog({
           PptId:parseInt(ppt_id),
           FirstPage:FirstPage,
           Content:Content,
-          CoverContent:this.CoverContent
+          CoverContent:this.CoverContent,
+          TitleSetting,
         }).then((res)=>{
             if(res.Ret!==200) return 
             this.showLastSaveTime = true
@@ -1320,23 +1401,6 @@ export default {
 <style lang="scss">
 @import './css/common.scss';
 @import './css/format.scss';
-.page-wrap{
-  .ppt-editor-wrap{
-    .ppt-tool{
-      .layer-edit-box{
-        .tool-list{
-          .el-collapse-item__header{
-            margin-bottom: 0;
-          }
-          .el-collapse-item__wrap{
-            overflow: visible;
-          }
-        }
-      }
-    }
-  }
-}
-
 </style>
 <style scoped lang="scss">
 $titleColor:#333333;
@@ -1490,17 +1554,19 @@ $titleColor:#333333;
            min-width:320px;
            width: 320px;
            height:100%;
-           .tool-btn{
-               margin-bottom: 12px;
+           overflow-y: hidden;
+           .richtext-tool{
+            margin:10px 0;
            }
             .addppt-right-box{
               flex: 1;
-              height: calc(100% - 182px);
+             /* height: calc(100% - 182px); */
               padding: 0 10px;
-              margin-top: 12px;
               box-sizing: border-box;
-              border:1px solid #B2B9C3;
+              border: 2px solid #EBEBEB;
+              border-radius: 4px;
               min-width: 320px;
+              overflow-y: auto;
               #tabs {
                 padding: 0px 40px;
                 box-sizing: border-box;
@@ -1576,20 +1642,20 @@ $titleColor:#333333;
               }
 
 		        }
-            .layer-edit-box{
+            .layer-edit-box,.title-edit-box{
               flex: 1;
-              height: calc(100% - 182px);
+              /* height: calc(100% - 182px); */
               padding: 0 20px;
-              margin-top: 12px;
               box-sizing: border-box;
               border: 2px solid #EBEBEB;
               border-radius: 4px;
               min-width: 320px;
-              overflow-y: scroll;
+              overflow-y: auto;
               .tool-list{
                 .el-wrap{
                   display: flex;
-                  justify-content: space-between;
+                  /* justify-content: space-between; */
+                  gap: 0 15px;
                   flex-wrap: wrap;
                   .el-item{
                     border: 1px solid #DCDFE6;
@@ -1611,24 +1677,16 @@ $titleColor:#333333;
                 }
               }
             }
+            .title-edit-box{
+                display:flex;
+                flex-direction: column;
+                padding:20px;
+                p{
+                    font-size: 16px;
+                    font-weight: bold;
+                }
+            }
        }
     }
 }
 </style>
-<style lang="scss">
-.page-wrap {
-	.el-tabs__nav-wrap::after {
-		height: 0;
-	}
-	.el-tabs__item { font-size: 16px; }
-	.layer-edit-box{
-		.tool-list{
-			.el-collapse-item:first-child{
-				.el-collapse-item__content{
-					padding-bottom: 5px;
-				}
-			}
-		}
-	}
-}	
-</style>

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác