Преглед изворни кода

Merge branch 'master' of http://8.136.199.33:3000/eta_front/eta_front into ETA_1.1.5

hbchen пре 1 година
родитељ
комит
b1c85b6a4f
100 измењених фајлова са 6181 додато и 925 уклоњено
  1. 2 1
      config/dev.env.js
  2. 2 1
      config/prod.env.js
  3. 2 1
      config/prod.test.env.js
  4. 12 0
      index.html
  5. 2 1
      src/api/api.js
  6. 1 0
      src/api/http.js
  7. 112 1
      src/api/modules/chartApi.js
  8. 9 0
      src/api/modules/futuresBaseApi.js
  9. 11 1
      src/api/modules/predictEdbApi.js
  10. 97 0
      src/api/modules/sheetApi.js
  11. 14 0
      src/api/modules/toolBoxApi.js
  12. 3 0
      src/assets/icons/chartFrame/arrow-left.svg
  13. 3 0
      src/assets/icons/chartFrame/arrow-right.svg
  14. 11 0
      src/assets/icons/chartFrame/fillColor.svg
  15. 17 0
      src/assets/icons/chartFrame/fontColor.svg
  16. 12 0
      src/assets/icons/chartFrame/fontStyle.svg
  17. 11 0
      src/assets/icons/chartFrame/fontText.svg
  18. 12 0
      src/assets/icons/chartFrame/fontWeight.svg
  19. 8 0
      src/assets/icons/chartFrame/redo.svg
  20. 5 0
      src/assets/icons/chartFrame/stokeColor.svg
  21. 5 0
      src/assets/icons/chartFrame/stokeStyle.svg
  22. 5 0
      src/assets/icons/chartFrame/textAlign.svg
  23. 8 0
      src/assets/icons/chartFrame/undo.svg
  24. BIN
      src/assets/img/chart_m/check.png
  25. BIN
      src/assets/img/home/loading.gif
  26. BIN
      src/assets/img/icons/jump_ico.png
  27. BIN
      src/assets/img/icons/tooltip.png
  28. 1 0
      src/components/pwdDlg.vue
  29. 2 1
      src/mixins/theme.js
  30. 94 7
      src/routes/modules/chartRoutes.js
  31. 38 49
      src/utils/TimeOnPage.js
  32. 45 11
      src/utils/buttonConfig.js
  33. 6 2
      src/utils/commonOptions.js
  34. 2 0
      src/utils/icon.js
  35. 3 3
      src/utils/svgToblob.js
  36. 3 1
      src/views/Home.vue
  37. 5 0
      src/views/Login.vue
  38. 140 0
      src/views/chartFrame_manage/common/config.js
  39. 115 0
      src/views/chartFrame_manage/common/event.js
  40. 135 0
      src/views/chartFrame_manage/common/graph.js
  41. 267 0
      src/views/chartFrame_manage/components/frameContainer.vue
  42. 402 0
      src/views/chartFrame_manage/components/frameToolBar.vue
  43. 36 0
      src/views/chartFrame_manage/components/toolItem.vue
  44. 149 0
      src/views/chartFrame_manage/css/basePage.scss
  45. 69 0
      src/views/chartFrame_manage/css/customTree.scss
  46. 221 0
      src/views/chartFrame_manage/frameEditor.vue
  47. 601 0
      src/views/chartFrame_manage/index.vue
  48. 73 0
      src/views/chartRelevance_manage/components/explainDialog.vue
  49. 38 0
      src/views/chartRelevance_manage/components/explainText.js
  50. 4 3
      src/views/chartRelevance_manage/components/saveEdbToBaseDia.vue
  51. 20 4
      src/views/chartRelevance_manage/fittingEquationChartEditor.vue
  52. 2 2
      src/views/chartRelevance_manage/fittingEquationList.vue
  53. 21 6
      src/views/chartRelevance_manage/relevanceChartEditor.vue
  54. 24 8
      src/views/chartRelevance_manage/statisticFeatureChartEditor.vue
  55. 106 88
      src/views/classify_manage/classifyEnlist.vue
  56. 23 3
      src/views/dataEntry_manage/addChart.vue
  57. 4 3
      src/views/dataEntry_manage/adjustdata/adjustData.vue
  58. 5 92
      src/views/dataEntry_manage/chartSetting.vue
  59. 5 4
      src/views/dataEntry_manage/codecount/index.vue
  60. 51 5
      src/views/dataEntry_manage/components/satterSeriesDia.vue
  61. 11 0
      src/views/dataEntry_manage/components/sectionalScatterOption.vue
  62. 23 8
      src/views/dataEntry_manage/databaseComponents/batchComptedDialog.vue
  63. 6 2
      src/views/dataEntry_manage/databaseComponents/chartTrendRender.vue
  64. 3 2
      src/views/dataEntry_manage/databaseComponents/completeTargetDia.vue
  65. 3 2
      src/views/dataEntry_manage/databaseComponents/computedDialog.vue
  66. 3 7
      src/views/dataEntry_manage/databaseComponents/diffusionIndexDia.vue
  67. 15 14
      src/views/dataEntry_manage/databaseComponents/fittingResidueDia.vue
  68. 6 5
      src/views/dataEntry_manage/databaseComponents/jointTargetDia.vue
  69. 49 72
      src/views/dataEntry_manage/databaseComponents/openDialog.vue
  70. 22 12
      src/views/dataEntry_manage/databaseComponents/operationDialog.vue
  71. 18 1
      src/views/dataEntry_manage/databaseComponents/smoothEdbDialog.vue
  72. 16 1
      src/views/dataEntry_manage/databaseComponents/util.js
  73. 164 258
      src/views/dataEntry_manage/databaseList.vue
  74. 28 3
      src/views/dataEntry_manage/editChart.vue
  75. 7 1
      src/views/dataEntry_manage/mixins/addOreditMixin.js
  76. 1 1
      src/views/dataEntry_manage/mixins/chartPublic.js
  77. 2 1
      src/views/datasheet_manage/addSheet.vue
  78. 33 23
      src/views/datasheet_manage/common/option.js
  79. 3 13
      src/views/datasheet_manage/components/SheetExcel.vue
  80. 1 1
      src/views/datasheet_manage/components/selectTargetValueDia.vue
  81. 6 2
      src/views/datasheet_manage/components/sheetClassifyDia.vue
  82. 119 0
      src/views/datasheet_manage/components/sheetListWrap.vue
  83. 505 0
      src/views/datasheet_manage/customAnalysis/addAnalysisSheet.vue
  84. 130 0
      src/views/datasheet_manage/customAnalysis/components/bottomSection.vue
  85. 261 0
      src/views/datasheet_manage/customAnalysis/components/createTargetForm.vue
  86. 118 0
      src/views/datasheet_manage/customAnalysis/components/rightSection.vue
  87. 1092 0
      src/views/datasheet_manage/customAnalysis/list.vue
  88. 1 1
      src/views/datasheet_manage/customSheetEdit.vue
  89. 1 1
      src/views/datasheet_manage/mixedSheetEdit.vue
  90. 38 2
      src/views/datasheet_manage/mixins/classifyMixin.js
  91. 76 139
      src/views/datasheet_manage/sheetList.vue
  92. 9 2
      src/views/mychart_manage/components/chartDetailDia.vue
  93. 80 0
      src/views/mychart_manage/components/classifyDeleteCheck.vue
  94. 57 9
      src/views/mychart_manage/index.vue
  95. 20 0
      src/views/positionAnalysis_manage/components/chartDetail.vue
  96. 19 17
      src/views/positionAnalysis_manage/components/indexContent.vue
  97. 141 23
      src/views/positionAnalysis_manage/detail.vue
  98. 15 0
      src/views/positionAnalysis_manage/list.vue
  99. 3 2
      src/views/ppt_manage/mixins/mixins.js
  100. 2 2
      src/views/ppt_manage/newVersion/pptEnCatalog.vue

+ 2 - 1
config/dev.env.js

@@ -13,5 +13,6 @@ module.exports = merge(prodEnv, {
   VUE_APP_FINANCIAL_MANAGEMENT_SYSTEM:'"http://8.136.199.33:8618/login"',
   VUE_APP_CRM_SYSTEM:'"http://8.136.199.33:7777/temppage"',
   VUE_APP_ETA_DOCS:'"http://8.136.199.33:8622/update/index"',
-	VUE_APP_ETA_HELP_DOCS:'"http://8.136.199.33:8622/help/index"'
+	VUE_APP_ETA_HELP_DOCS:'"http://8.136.199.33:8622/help/index"',
+    VUE_APP_ETA_VIDEO:'"http://8.136.199.33:8622/video/list"',
 });

+ 2 - 1
config/prod.env.js

@@ -10,6 +10,7 @@ module.exports = {
 	VUE_APP_FINANCIAL_MANAGEMENT_SYSTEM:'"https://fms.hzinsights.com/login"',
 	VUE_APP_CRM_SYSTEM:'"https://admin.hzinsights.com/temppage"',
 	VUE_APP_ETA_DOCS:'"https://etadocs.hzinsights.com/update/index"',
-	VUE_APP_ETA_HELP_DOCS:'"https://etadocs.hzinsights.com/help/index"'
+	VUE_APP_ETA_HELP_DOCS:'"https://etadocs.hzinsights.com/help/index"',
+	VUE_APP_ETA_VIDEO:'"https://etadocs.hzinsights.com/video/list"',
 		
 }

+ 2 - 1
config/prod.test.env.js

@@ -10,5 +10,6 @@ module.exports = {
   VUE_APP_FINANCIAL_MANAGEMENT_SYSTEM:'"http://8.136.199.33:8618/login"',
 	VUE_APP_CRM_SYSTEM:'"http://8.136.199.33:7777/temppage"',
 	VUE_APP_ETA_DOCS:'"http://8.136.199.33:8622/update/index"',
-	VUE_APP_ETA_HELP_DOCS:'"http://8.136.199.33:8622/help/index"'
+	VUE_APP_ETA_HELP_DOCS:'"http://8.136.199.33:8622/help/index"',
+	VUE_APP_ETA_VIDEO:'"http://8.136.199.33:8622/video/list"',
 }

+ 12 - 0
index.html

@@ -36,6 +36,17 @@
         input[type="password"]::-o-reveal{
             display: none;
         }
+    </style>
+    <!-- 字蛛压缩字体 -->
+    <style>
+        @font-face {
+            font-family: '思源黑体';
+            src: url(./static/css/fonts/SourceHanSansSC-Regular.ttf);
+        }
+        @font-face {
+            font-family: '思源宋体';
+            src: url(./static/css/fonts/SourceHanSerifCN-Regular.ttf);
+        }
     </style>
 	<script>
 		var _hmt = _hmt || [];
@@ -64,6 +75,7 @@
 	<script type="text/javascript" src="./static/js/jquery.min.js"></script>
 	<script src="https://hzstatic.hzinsights.com/static/cdn/Luckysheet@2.1.13/dist/plugins/js/plugin.js"></script>
 	<script src="https://hzstatic.hzinsights.com/static/cdn/Luckysheet@2.1.13/dist/luckysheet.umd.js"></script>
+	<script src="https://hzstatic.hzinsights.com/static/cdn/luckyexcel.umd.js"></script>
 	<script type="text/javascript" src="./static/js/jquery.dataTables.js"></script>
 </body>
 </html>

+ 2 - 1
src/api/api.js

@@ -1,5 +1,5 @@
 // eta图表 我的图库 数据指标库
-import { dataBaseInterface, mychartInterface } from './modules/chartApi';
+import { dataBaseInterface, mychartInterface,chartFrameInterface } from './modules/chartApi';
 
 //接入的第三方的数据库
 import {
@@ -75,6 +75,7 @@ import {reportVarietyENInterence} from './modules/reportVariety'
 export {
   dataBaseInterface,
   mychartInterface,
+  chartFrameInterface,
   lzDataInterface,
   glDataInterface,
   smmDataInterface,

+ 1 - 0
src/api/http.js

@@ -52,6 +52,7 @@ function checkStatus(response) {
       bus.$message.error(res.Msg);
     } else if (res.Ret === 408) {
       localStorage.setItem("auth", "")
+      localStorage.setItem("loginTime", "")
       bus
         .$alert(res.Msg, "提示", {
           showClose: false,

+ 112 - 1
src/api/modules/chartApi.js

@@ -2,6 +2,19 @@ import http from "@/api/http.js"
 
 /* 数据库管理模块  */
 const dataBaseInterface = {
+	/**
+	 * 指标库目录
+	 */
+	targetCatalog:params=>{
+		return http.get('/datamanage/classify/simple',params)
+	},
+	/**
+	 * 指标和目录拖动排序
+	 */
+	classifyMoveSort:params=>{
+		return http.post('/datamanage/edb_classify/move',params)
+	},
+
 	/**
 	 * 新增分类
 	 * @param {ClassifyName} params 
@@ -58,7 +71,8 @@ const dataBaseInterface = {
 		return http.get('/datamanage/classify/items/v2',params)
 	},
 	menuListV3: params => {
-		return http.get('/datamanage/classify/items/v3',params)
+		// return http.get('/datamanage/classify/items/v3',params)
+		return http.get('/datamanage/classify/tree',params)
 	},
 	/**
 	 * 通过分类查找指标列表数据
@@ -929,6 +943,13 @@ const mychartInterface = {
 	addClassify: params => {
 		return http.post('/my_chart/classify/add',params)
 	},
+	/**
+	 * 获取图表关联的节点列表
+	 * @param {MyChartClassifyId} params 
+	 */
+	getFrameNode:params =>{
+		return http.get('/my_chart/classify/framework_node_list',params)
+	},
 	/**
 	 * 删除分类
 	 * @param {MyChartClassifyId} params 
@@ -1092,8 +1113,98 @@ const mychartInterface = {
 		return http.get('/my_chart/search_by_es',params)
 	}
 }
+/* 图库框架 */
+const chartFrameInterface = {
+    /**
+     * 添加框架
+     * @param {Object} params 
+     * @param {String} params.FrameworkName 框架名称
+     * @param {String} params.FrameworkImg 框架图片地址
+     * @param {String} params.FrameworkContent 框架内容
+     * @param {Array} params.Nodes 框架所包含的节点数组
+     * @param {String} Nodes.NodeName 节点名称
+     * @param {Number} Nodes.MyChartClassifyId 节点对应图库分类id
+     * @returns 
+     */
+    addFrame: params => {
+        return http.post('/chart_framework/add',params)
+    },
+    /**
+     * 编辑框架
+     * @param {Object} params 
+     * @param {Number} params.ChartFrameworkId 框架id
+     * 其他参数同上
+     * @returns 
+     */
+    editFrame: params => {
+        return http.post('/chart_framework/edit',params)
+    },
+    getFrameDetail:params=>{
+        return http.get('/chart_framework/detail',params)
+    },
+    /**
+     * 重命名框架
+     * @param {Object} params 
+     * @param {Number} params.ChartFrameworkId
+     * @param {String} params.FrameworkName
+     * @returns 
+     */
+    reNameFrame: params => {
+        return http.post('/chart_framework/rename',params)
+    },
+    /**
+     * 删除框架
+     * @param {Object} params 
+     * @param {Number} params.ChartFrameworkId
+     * @returns 
+     */
+    deleteFrame: params => {
+        return http.post('/chart_framework/remove',params)
+    },
+    /**
+     * 公开/隐藏框架
+     * @param {Object} params 
+     * @param {Number} params.ChartFrameworkId
+     * @param {Number} params.IsPublic 0隐藏 1公开
+     * @returns 
+     */
+    changePublicFrame: params => {
+        return http.post('/chart_framework/edit_public',params)
+    },
+    /**
+     * 框架移动排序
+     * @param {Object} params 
+     * @param {Number} params.ChartFrameworkId
+     * @param {Number} params.PrevChartFrameworkId
+     * @param {Number} params.NextChartFrameworkId
+     * @returns 
+     */
+    moveFrame: params => {
+        return http.post('/chart_framework/move',params)
+    },
+    /**
+     * 获取公开框架目录
+     * @returns 
+     */
+    getPublicFrameList:params=>{
+        return http.get('/chart_framework/public_menu',params)
+    },
+    /**
+     * 获取我的框架列表
+     * @param {Object} params 
+     * @param {Number} params.AdminId
+     * @param {String} params.Keyword 筛选关键词
+     * @param {Number} params.Visibility 0所有用户 1自己用户
+     * @returns 
+     */
+    getMyFrameList:params=>{
+        return http.get('/chart_framework/list',params)
+    },
+
+}
 
 export {
 	dataBaseInterface,
 	mychartInterface,
+	chartFrameInterface
 }

+ 9 - 0
src/api/modules/futuresBaseApi.js

@@ -306,5 +306,14 @@ export default {
   profitChartEdit: params => {
     return http.post('/future_good/chart_info/profit/edit',params)
   },
+
+  /**
+   * 获取图表基本信息 价格曲线遍历指标找数据太慢 这个用来获取基本信息不包含数据
+   * @param {*} params 
+   * @returns 
+  */
+  getChartBasicInfo: params => {
+    return http.get('/future_good/chart_info/base_detail/from_unique_code',params)
+  }
   
 }

+ 11 - 1
src/api/modules/predictEdbApi.js

@@ -12,8 +12,18 @@ export const classifyList = params => {
  * @returns 
  */
 export const classifyListV2 = params => {
-    return http.get('/datamanage/predict_classify/list/v2',params)
+    return http.get('/datamanage/predict_classify/tree',params)
 }
+//分类数据
+export const predictEdbCatalog=params=>{
+	return http.get('/datamanage/predict_classify/simple',params)
+}
+//目录指标移动
+export const classifyMoveSort=params=>{
+	return http.post('/datamanage/predict_classify/move',params)
+}
+
+
 /**
  * 分类的图表列表 IsOnlyMe ClassifyId
  * @param {*} params 

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

@@ -254,4 +254,101 @@ export const insertData = params => {
  */
 export const getDateLatelyData = params => {
 	return http.get('/datamanage/edb_info/date_data/before_after',params)
+}
+
+
+/* =====自定义分析==== */
+
+export const sheetAnalysisInterface = {
+
+	/**
+	 * 移动表格
+	 * @param {*} params ExcelClassifyId ExcelInfoId PrevExcelInfoId NextExcelInfoId
+	 * @returns 
+	 */
+	sheetMove: params => {
+		return http.post('/datamanage/excel_info/move',params)
+	},
+	
+	/**
+	 * 新增表格
+	 * @param {*} params ExcelName ExcelClassifyId ExcelImage Content
+	 * @returns 
+	 */
+	excelSheetAdd: params => {
+		return http.post('/custom_analysis/add',params)
+	},
+
+	/**
+	 * 获取详情
+	 * @param {*} params UniqueCode
+	 * @returns 
+	 */
+	getExcelDetail: params => {
+		return http.get('/custom_analysis/excel/base',params)
+	},
+
+	/**
+	 * 分页加载celldata
+	 * @param {*} params  UniqueCode Page
+	 * @returns 
+	 */
+	getExcelDataByPage: params => {
+		return http.get('/custom_analysis/excel/data',params)
+	},
+
+	/**
+	 * 表格保存
+	 * @param {*} params ExcelName ExcelInfoId ExcelClassifyId ExcelImage Content
+	 */
+	sheetEdit: params => {
+		return http.post('/custom_analysis/save',params)
+	},
+
+	/**
+	 * 生成指标
+	 * @param {*} params  
+	 * EdbName ExcelInfoId ClassifyId Frequency Unit DateSequenceVal DataSequenceVal DateSequenceStr DataSequenceStr
+	 * @returns 
+	 */
+	edbAddBysheet: params => {
+		return http.post('/custom_analysis/edb/add',params)
+	},
+
+	/**
+	 * 指标编辑
+	 * @param {*} params 
+	 * EdbName ExcelInfoId EdbInfoId ClassifyId Frequency Unit DateSequenceVal DataSequenceVal
+	 * @returns 
+	 */
+	edbEditBysheet: params => {
+		return http.post('/custom_analysis/edb/edit',params)
+	},
+
+	/**
+	 * 获取表格生成的指标列表
+	 * @param {*} params ExcelInfoId
+	 * @returns 
+	 */
+	edbListBySheet: params => {
+		return http.get('/custom_analysis/edb/list',params)
+	},
+
+	/**
+	 * 刷新
+	 * @param {*} params ExcelInfoId
+	 * @returns 
+	 */
+	sheetRefresh: params => {
+		return http.get('/custom_analysis/edb/refresh',params)
+	},
+
+	/**
+	 * 检查是否有同名表格
+	 * @param {*} params  ExcelName
+	 * @returns 
+	 */
+	checkSheetRepeat: params => {
+		return http.get('/custom_analysis/excel_by_name',params)
+	}
 }

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

@@ -0,0 +1,14 @@
+import http from "@/api/http.js"
+
+//工具箱
+export const ToolBoxInterface = {
+    /**
+     * 获取联储观察的数据
+     * @param {Object} params 
+     * @param {String} DateTime //时间 yyyy-MM-dd
+     * @returns 
+     */
+    getSheetDetail:(params)=>{
+        return http.get('/meeting_probabilities/detail',params)
+    }
+}

+ 3 - 0
src/assets/icons/chartFrame/arrow-left.svg

@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M3.91423 8.49963L7.56053 12.1459L6.85342 12.853L2.21213 8.21174C2.09497 8.09458 2.09497 7.90463 2.21213 7.78748L6.85342 3.14619L7.56053 3.8533L3.91419 7.49963L13.9999 7.4998L13.9999 8.4998L3.91423 8.49963Z" fill="#C8CDD9" stroke="#C8CDD9" stroke-width="0.5"/>
+</svg>

+ 3 - 0
src/assets/icons/chartFrame/arrow-right.svg

@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12.0857 7.50013L8.43938 3.85384L9.14649 3.14673L13.7878 7.78802C13.9049 7.90517 13.9049 8.09512 13.7878 8.21228L9.14649 12.8536L8.43938 12.1465L12.0857 8.50013L2 8.49996L2.00002 7.49996L12.0857 7.50013Z" fill="#C8CDD9" stroke="#C8CDD9" stroke-width="0.5"/>
+</svg>

+ 11 - 0
src/assets/icons/chartFrame/fillColor.svg

@@ -0,0 +1,11 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_1428_2103)">
+<path d="M6.30152 0.666687L5.35886 1.60935L6.77286 3.02335L1.58752 8.20935C1.46254 8.33437 1.39233 8.50391 1.39233 8.68069C1.39233 8.85746 1.46254 9.027 1.58752 9.15202L7.24419 14.8087C7.36921 14.9337 7.53875 15.0039 7.71552 15.0039C7.8923 15.0039 8.06184 14.9337 8.18686 14.8087L13.8442 9.15202C13.9692 9.027 14.0394 8.85746 14.0394 8.68069C14.0394 8.50391 13.9692 8.33437 13.8442 8.20935L6.30152 0.666687ZM3.00152 8.68002L7.71552 3.96669L12.4295 8.68002L7.71619 13.3947L3.00152 8.68069V8.68002Z" fill="#C8CDD9"/>
+<path d="M14.392 10.6667L15.5707 11.8454C15.8037 12.0785 15.9624 12.3754 16.0267 12.6987C16.091 13.022 16.0579 13.3571 15.9318 13.6616C15.8056 13.9661 15.592 14.2264 15.3179 14.4095C15.0438 14.5926 14.7216 14.6904 14.392 14.6904C14.0624 14.6904 13.7402 14.5926 13.4661 14.4095C13.192 14.2264 12.9784 13.9661 12.8523 13.6616C12.7261 13.3571 12.6931 13.022 12.7573 12.6987C12.8216 12.3754 12.9803 12.0785 13.2133 11.8454L14.392 10.6667Z" fill="#C8CDD9"/>
+</g>
+<defs>
+<clipPath id="clip0_1428_2103">
+<rect width="16" height="16" fill="white" transform="translate(0.39209)"/>
+</clipPath>
+</defs>
+</svg>

+ 17 - 0
src/assets/icons/chartFrame/fontColor.svg

@@ -0,0 +1,17 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_1428_2042)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M3.39209 14.9999H13.3921V13.2599H3.39209V14.9999Z" fill="#C8CDD9"/>
+<g clip-path="url(#clip1_1428_2042)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.44209 2H7.29209L3.39209 11H5.29209L6.29209 8.45H10.3821L11.3721 11H13.3421L9.44209 2Z" fill="#C8CDD9"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.93218 7.31999L9.47218 6.12C9.09218 5.14 8.73218 4.14 8.37218 3.12H8.30218C7.95218 4.15 7.58218 5.14 7.20218 6.12L6.73218 7.31999H9.93218Z" fill="white"/>
+</g>
+</g>
+<defs>
+<clipPath id="clip0_1428_2042">
+<rect width="10" height="13" fill="white" transform="translate(3.39209 2)"/>
+</clipPath>
+<clipPath id="clip1_1428_2042">
+<rect width="9.952" height="9" fill="white" transform="translate(3.39209 2)"/>
+</clipPath>
+</defs>
+</svg>

+ 12 - 0
src/assets/icons/chartFrame/fontStyle.svg

@@ -0,0 +1,12 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_1428_2031)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M3.39209 3C3.39209 2.44772 3.83981 2 4.39209 2H10.3921C10.9444 2 11.3921 2.44772 11.3921 3C11.3921 3.55228 10.9444 4 10.3921 4H4.39209C3.83981 4 3.39209 3.55228 3.39209 3Z" fill="#C8CDD9"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.89209 12.5L8.89209 3H6.89209L5.89209 12.5H7.89209Z" fill="#C8CDD9"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M3.39209 13C3.39209 12.4477 3.83981 12 4.39209 12H10.3921C10.9444 12 11.3921 12.4477 11.3921 13C11.3921 13.5523 10.9444 14 10.3921 14H4.39209C3.83981 14 3.39209 13.5523 3.39209 13Z" fill="#C8CDD9"/>
+</g>
+<defs>
+<clipPath id="clip0_1428_2031">
+<rect width="8" height="12" fill="white" transform="translate(3.39209 2)"/>
+</clipPath>
+</defs>
+</svg>

+ 11 - 0
src/assets/icons/chartFrame/fontText.svg

@@ -0,0 +1,11 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_1428_2000)">
+<path d="M4.39209 1V6C4.39209 7.06 4.81209 8.08 5.56209 8.83C6.31209 9.58 7.33209 10 8.39209 10C9.45209 10 10.4721 9.58 11.2221 8.83C11.9721 8.08 12.3921 7.06 12.3921 6V1" stroke="#C8CDD9" stroke-width="2" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M3.39209 14C3.39209 13.4477 3.83981 13 4.39209 13H12.3921C12.9444 13 13.3921 13.4477 13.3921 14C13.3921 14.5523 12.9444 15 12.3921 15H4.39209C3.83981 15 3.39209 14.5523 3.39209 14Z" fill="#C8CDD9"/>
+</g>
+<defs>
+<clipPath id="clip0_1428_2000">
+<rect width="10" height="14" fill="white" transform="translate(3.39209 1)"/>
+</clipPath>
+</defs>
+</svg>

+ 12 - 0
src/assets/icons/chartFrame/fontWeight.svg

@@ -0,0 +1,12 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_1428_2021)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4.39209 13.79H8.33209C10.9521 13.79 12.8421 12.67 12.8421 10.34C12.8421 8.74 11.8621 7.81 10.5221 7.54V7.46C11.5921 7.1 12.2021 6.03 12.2021 4.9C12.2021 2.78 10.4521 2 8.05209 2H4.39209V13.79Z" fill="#C8CDD9"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.8822 3.46002H6.2522V6.93002H7.8322C9.6222 6.93002 10.3722 6.26002 10.3722 5.15002C10.3722 3.94002 9.5422 3.46002 7.8822 3.46002Z" fill="white"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6.2522 8.34003V12.34H8.1222C9.9622 12.34 11.0122 11.68 11.0122 10.24C11.0122 8.93003 9.9922 8.34003 8.1222 8.34003H6.2522Z" fill="white"/>
+</g>
+<defs>
+<clipPath id="clip0_1428_2021">
+<rect width="8.448" height="11.792" fill="white" transform="translate(4.39209 2)"/>
+</clipPath>
+</defs>
+</svg>

+ 8 - 0
src/assets/icons/chartFrame/redo.svg

@@ -0,0 +1,8 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<mask id="mask0_1428_2007" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="16" height="16">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0H16V16H0V0Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_1428_2007)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M14.841 7.96784C15.051 7.74784 15.031 7.40784 14.801 7.20784L9.37097 2.54784C9.27097 2.45784 9.13097 2.40784 8.99097 2.40784C8.68097 2.40784 8.42097 2.64784 8.42097 2.94784V6.04784C6.08097 6.13784 4.13097 6.35784 2.82097 7.59784C0.880971 9.44784 1.01097 11.7778 1.01097 12.3678C1.01097 12.6778 1.01097 13.2378 1.01097 13.5878H1.17097C1.41097 13.5878 1.63097 13.4478 1.71097 13.2378C2.46097 11.2878 3.53097 10.1078 4.92097 9.69784C5.88097 9.40784 6.94097 9.31784 8.42097 9.27784V12.3578C8.42097 12.4878 8.47097 12.6278 8.57097 12.7278C8.79097 12.9378 9.15097 12.9578 9.38097 12.7578L14.811 7.99784C14.821 7.98784 14.831 7.97784 14.841 7.96784Z" fill="#C8CDD9"/>
+</g>
+</svg>

+ 5 - 0
src/assets/icons/chartFrame/stokeColor.svg

@@ -0,0 +1,5 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M9.21239 3.66195L9.7372 2.79734L12.0681 5.10705L11.5442 5.97156L9.21239 3.66195Z" fill="#C8CDD9"/>
+<path d="M10.9596 2.5202L4.98385 8.49595L4.47785 10.5227L6.50405 10.0162L12.4798 4.0404L10.9596 2.5202ZM14 4.0404L7.0535 10.9869L3 12L4.01365 7.9465L10.9596 1L14 4.0404Z" fill="#C8CDD9"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M3 15H14V13H3V15Z" fill="#C8CDD9"/>
+</svg>

+ 5 - 0
src/assets/icons/chartFrame/stokeStyle.svg

@@ -0,0 +1,5 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<line x1="2.39209" y1="3" x2="14.3921" y2="3" stroke="#C8CDD9" stroke-width="2"/>
+<line x1="2.39209" y1="8" x2="14.3921" y2="8" stroke="#C8CDD9" stroke-width="2" stroke-dasharray="2 2"/>
+<line x1="2.39209" y1="13" x2="14.3921" y2="13" stroke="#C8CDD9" stroke-width="2" stroke-dasharray="1 1"/>
+</svg>

+ 5 - 0
src/assets/icons/chartFrame/textAlign.svg

@@ -0,0 +1,5 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M14.3921 2H2.39209V4H14.3921V2Z" fill="#C8CDD9"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.39209 7H2.39209V9H9.39209V7Z" fill="#C8CDD9"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M14.3921 12H2.39209V14H14.3921V12Z" fill="#C8CDD9"/>
+</svg>

+ 8 - 0
src/assets/icons/chartFrame/undo.svg

@@ -0,0 +1,8 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<mask id="mask0_1428_2013" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="16" height="16">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0H16V16H0V0Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_1428_2013)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6.62965 2.54784L1.19965 7.20784C0.959647 7.40784 0.949647 7.74784 1.15965 7.96784C1.16965 7.97784 1.17965 7.98784 1.18965 7.99784L6.61965 12.7578C6.84965 12.9578 7.20965 12.9378 7.42965 12.7278C7.52965 12.6278 7.57965 12.4878 7.57965 12.3578V9.27784C9.05965 9.31784 10.1196 9.40784 11.0796 9.69784C12.4696 10.1078 13.5296 11.2878 14.2896 13.2378C14.3696 13.4478 14.5796 13.5878 14.8296 13.5878H14.9896C14.9896 13.2378 14.9896 12.6778 14.9896 12.3678C14.9896 11.7778 15.1196 9.44784 13.1796 7.59784C11.8696 6.35784 9.91965 6.13784 7.57965 6.04784V2.94784C7.57965 2.64784 7.31965 2.40784 7.00965 2.40784C6.86965 2.40784 6.72965 2.45784 6.62965 2.54784Z" fill="#C8CDD9"/>
+</g>
+</svg>

BIN
src/assets/img/chart_m/check.png


BIN
src/assets/img/home/loading.gif


BIN
src/assets/img/icons/jump_ico.png


BIN
src/assets/img/icons/tooltip.png


+ 1 - 0
src/components/pwdDlg.vue

@@ -117,6 +117,7 @@ export default {
                 localStorage.setItem('AdminName',"");
                 localStorage.setItem("RoleIdentity", "");
                 localStorage.setItem("ManageType", "");
+                localStorage.setItem("loginTime", "");
                 this.$router.push({ path: "/login" });
               }, 1000);
             }

+ 2 - 1
src/mixins/theme.js

@@ -30,5 +30,6 @@ export default {
   login_logo: require('@/assets/img/login_logo.png'),
   g_logo: require('@/assets/img/home/logo.png'),
   g_mini_logo: require('@/assets/img/home/eta_mini.png'),
-  dynamicOutLinks:{}//动态的外部link链接
+  dynamicOutLinks:{},//动态的外部link链接
+  bus_code:'',
 }

+ 94 - 7
src/routes/modules/chartRoutes.js

@@ -65,12 +65,31 @@ export default [
 		name: 'My ETA',
 		hidden: false,
 		icon_path: require('@/assets/img/home/data_ic.png'),
-		children: [{
+		children: [
+			{
 				path: 'mychart',
 				name: 'My ETA',
 				component: () => import('@/views/mychart_manage/index.vue'),
 				hidden: false,
-			}
+			},
+			{
+				path: 'chartframe',
+				name: '图库框架',
+				component: () => import('@/views/chartFrame_manage/index.vue'),
+				hidden: false,
+			},
+			{
+				path: 'addframe',
+				name: '添加框架',
+				component: () => import('@/views/chartFrame_manage/frameEditor.vue'),
+				hidden: false,
+			},
+			{
+				path: 'editframe',
+				name: '编辑框架',
+				component: () => import('@/views/chartFrame_manage/frameEditor.vue'),
+				hidden: false,
+			},
 		]
 	},
 
@@ -83,7 +102,17 @@ export default [
 		children:[
 			{
 				path:"sheetList",
-				name:"ETA表格",
+				name:"在线Excel",
+				component:()=>import('@/views/datasheet_manage/sheetList.vue')
+			},
+			{
+				path:"sheetTimeList",
+				name:"时间序列表格",
+				component:()=>import('@/views/datasheet_manage/sheetList.vue')
+			},
+			{
+				path:"sheetMixedList",
+				name:"混合表格",
 				component:()=>import('@/views/datasheet_manage/sheetList.vue')
 			},
 			{
@@ -93,14 +122,29 @@ export default [
 			},
 			{
 				path:"addCustomSheet",
-				name:"添加表格",
+				name:"添加数据表格",
 				component:()=>import('@/views/datasheet_manage/customSheetEdit.vue')
 			},
 			{
 				path:"addMixedSheet",
-				name:"添加表格",
+				name:"添加混合表格",
 				component:()=>import('@/views/datasheet_manage/mixedSheetEdit.vue')
-			}
+			},
+			{
+				path:"sheetAnalysisList",
+				name:"自定义分析",
+				component:()=>import('@/views/datasheet_manage/customAnalysis/list.vue')
+			},
+			{
+				path:"addAnalysisSheet",
+				name:"上传文件",
+				component:()=>import('@/views/datasheet_manage/customAnalysis/addAnalysisSheet.vue')
+			},
+			{
+				path:"createTaregtBySheet",
+				name:"生成指标",
+				component:()=>import('@/views/datasheet_manage/customAnalysis/addAnalysisSheet.vue')
+			},
 		]
 	},
 
@@ -215,7 +259,7 @@ export default [
 	},
 
 	/* 持仓分析 */
-	{
+	/* {
 		path:'/',
 		component: home,
 		name: '持仓分析',
@@ -232,5 +276,48 @@ export default [
 				component:()=>import('@/views/positionAnalysis_manage/detail.vue'),
 			}
 		]
+	}, */
+	/* 工具箱 */
+	//ETA1.1.3:将持仓分析,商品价格曲线合并至工具箱
+	{
+		path:'/',
+		component:home,
+		name:'工具箱',
+		hidden:false,
+		children:[
+			/* {
+				path: 'positionAnalysisList',
+				name: '持仓列表',
+				component:()=>import('@/views/positionAnalysis_manage/list.vue')
+			}, */
+			{//不要列表页了,但是改path需要动ETA菜单很麻烦,先这样
+				path: 'positionAnalysisList',
+				name: '持仓详情',
+				component:()=>import('@/views/positionAnalysis_manage/detail.vue')
+			},
+			{
+				path: 'positionAnalysisDetail',
+				name: '持仓详情',
+				component:()=>import('@/views/positionAnalysis_manage/detail.vue'),
+			},
+			{
+				path:'federalReserveWatch',
+				name:'联储观察',
+				component:()=>import('@/views/toolBox_manage/FederalReserveWatch.vue')
+			},{
+				path: "commordityChartBase",
+				name: "商品价格曲线",
+				component: () => import('@/views/futures_manage/commodityChartBase.vue')
+			},
+			{
+				path: "addCommodityChart",
+				name: "编辑图表",
+				component: () => import('@/views/futures_manage/chartEditor.vue'),
+				meta: { 
+					pathFrom: "commordityChartBase",
+					pathName: "商品价格曲线",
+				}
+			},
+		]
 	}
 ]

+ 38 - 49
src/utils/TimeOnPage.js

@@ -11,16 +11,13 @@ let stayTime = 0
 let intervalTimer=null
 
 export const openLoginTimer=()=>{
-  // 登录时间
-  localStorage.setItem("loginTime",new Date())
 
   clearInterval(intervalTimer)
   intervalTimer = setInterval(()=>{
-    // let inactiveTime = time || new Date()
     let ActiveTime=0
     if(localStorage.getItem('loginTime')){
       ActiveTime = (new Date()-new Date(localStorage.getItem('loginTime')))/1000
-      console.log("1分钟间隔记录时长",ActiveTime+'s');
+      console.log("间隔记录时长",ActiveTime+'s');
       recordActiveLogin({ActiveTime:Math.round(ActiveTime)}).then(res=>{
         if(res.Ret!==200) return
       })
@@ -39,7 +36,7 @@ export const recordActiveLoginFun=(time)=>{
     }).finally(()=>{
       // 清除工作
       clearInterval(intervalTimer)
-      localStorage.removeItem('loginTime')
+      // localStorage.removeItem('loginTime')
     })
   }
 }
@@ -49,6 +46,7 @@ let timer = null
 //打开计时器
 export const optionTimeCalc = ()=>{
   const IsActive = sessionStorage.getItem('IsActive')
+  // console.log(IsActive,'IsActive');
   if(Number(IsActive)===0){
     //console.log('打开计时器')
     sessionStorage.setItem('IsActive',1)
@@ -62,7 +60,6 @@ export const startCalc = ()=>{
   sessionStorage.setItem('preTitle',document.title)
   timer = setInterval(()=>{
     stayTime++
-    
     if(stayTime>=TimeInterval){
       endCalc('timeup',0)
     }
@@ -137,24 +134,25 @@ let rewriteHis = function(type){
 }
 
 export function init(){
-  const unloadT = sessionStorage.getItem('unloadT')
-  const IsActive = sessionStorage.getItem('IsActive')
-  if(unloadT){
-    //console.log('刷新该页呆了时长',unloadT)
-    sessionStorage.removeItem('unloadT')
-    sessionStorage.setItem('preTitle',document.title)
-    if(Number(IsActive)){
-      endCalc('unload',unloadT)
-    }
-  }
-  timeStr = new Date().getTime()
+  // const unloadT = sessionStorage.getItem('unloadT')
+  // console.log("init",unloadT,IsActive);
+  // if(unloadT){
+  //   //console.log('刷新该页呆了时长',unloadT)
+  //   sessionStorage.removeItem('unloadT')
+  //   sessionStorage.setItem('preTitle',document.title)
+  //   if(Number(IsActive)){
+  //     endCalc('unload',unloadT)
+  //   }
+  // }
+  // timeStr = new Date().getTime()
+  sessionStorage.setItem('IsActive',0)
   optionTimeCalc()
+  // const IsActive = sessionStorage.getItem('IsActive')
 
-  if((!localStorage.getItem("loginTime")) && localStorage.getItem('auth')){
-    // 初始化的时候 先重置最近登录时长
-    recordActiveLogin({ActiveTime:0}).then(res=>{
-      if(res.Ret!==200) return
-    })
+  // if(Number(IsActive)){
+  //   sessionStorage.setItem('unloadT',t)
+  // }
+  if(localStorage.getItem("loginTime") && localStorage.getItem('auth')){
     openLoginTimer()
   }
 }
@@ -195,10 +193,23 @@ export const doPageEventListener=function(){
   window.addEventListener('beforeunload',(e)=>{
     console.log('beforeunload')
     let t = new Date().getTime() - timeStr
+    // const unloadT = sessionStorage.getItem('unloadT')
     const IsActive = sessionStorage.getItem('IsActive')
-    if(Number(IsActive)){
-      sessionStorage.setItem('unloadT',t)
-    }
+    console.log("init",IsActive);
+    // if(unloadT){
+      //console.log('刷新该页呆了时长',unloadT)
+      // sessionStorage.removeItem('unloadT')
+      // sessionStorage.setItem('preTitle',document.title)
+      if(Number(IsActive)){
+        endCalc('unload',t)
+      }
+    // }
+    // timeStr = new Date().getTime()
+    // optionTimeCalc()
+    // const IsActive = sessionStorage.getItem('IsActive')
+    // if(Number(IsActive)){
+      // sessionStorage.setItem('unloadT',t)
+    // }
   })
 
   //刷新离开页面
@@ -207,7 +218,7 @@ export const doPageEventListener=function(){
     recordActiveLoginFun()
     // 猜测在unload这里 浏览器不会等待异步返回 清除工作在这进行
     clearInterval(intervalTimer)
-    localStorage.removeItem('loginTime')
+    // localStorage.removeItem('loginTime')
   })
 
   //popstate会在router.before/afterEach 之前触发,所以这里不对计时操作,操作放到before/afterEach
@@ -242,29 +253,6 @@ export const doPageEventListener=function(){
     optionTimeCalc()
   })
   
-  //页面监听
-  /* document.addEventListener('visibilitychange', function () {
-    // 用户离开了当前页面
-    if (document.visibilityState === 'hidden') {
-      console.log('hidden')
-      const IsActive = sessionStorage.getItem('IsActive')
-      if(Number(IsActive)){
-        let t = new Date().getTime() - timeStr
-        timeStr = new Date().getTime()
-        endCalc('hidden',t)
-      }
-    }
-  
-    // 用户打开或回到页面
-    if (document.visibilityState === 'visible') {
-      console.log('visible')
-      const IsActive = sessionStorage.getItem('IsActive')
-      if(IsActive==='0'){
-        timeStr = new Date().getTime()
-        optionTimeCalc()
-      }
-    }
-  }); */
   document.addEventListener('click',(e)=>{
 
     //console.log('click',e,e.composedPath())
@@ -274,6 +262,7 @@ export const doPageEventListener=function(){
     if(contentIndex===-1) return 
     //console.log('合法的click')
     const IsActive = sessionStorage.getItem('IsActive')
+    console.log(IsActive,'IsActive');
     if(Number(IsActive)===0){
       optionTimeCalc()
     }else{

+ 45 - 11
src/utils/buttonConfig.js

@@ -72,11 +72,11 @@ export const classifyBtn={
     classifyList_cnClassify_childMenu:'classifyList:cnClassify:childMenu',//表单项:子目录
 }
 /*
-*--------英文分类----------- 
+*--------英文分类-----------   ETA_1.1.7 不区分英文研报和线上路演 统一使用英文研报的标识
 */
 export const enClassifyBtn = {
     classifyList_enClassify:'classifyList:enClassify',//英文分类这个选项卡是否展示
-    /* -------------线上路演------------- */
+    /* -------------线上路演------------- */ 
     classifyList_enClassify_roadshow:'classifyList:enClassify:roadshow',//线上路演这个选项卡是否展示
     classifyList_enClassify_rsDel:'classifyList:enClassify:rsDel',//线上路演一二级分类删除
     classifyList_enClassify_rsAuthSetting:'classifyList:enClassify:rsAuthSetting',//线上路演二级分类权限设置
@@ -245,6 +245,7 @@ export const edbDataPermission = {
     edbData_switchEn:'edbData:switchEn',//切换英文版
     edbData_classifyOpt_add:'edbData:classifyOpt:add',//添加/编辑分类
     edbData_classifyOpt_delete:'edbData:classifyOpt:delete',//删除分类
+    edbData_classifyOpt_move:'edbData:classifyOpt:move',//移动分类
     edbData_checkRelatedChart:'edbData:checkRelatedChart',//查看关联图表
     edbData_checkRelatedEdb:'edbData:checkRelatedEdb',//查看关联指标
     edbData_checkCalcChart:'edbData:checkCalcChart',//查看计算指标
@@ -272,6 +273,7 @@ export const predictEdbPermission = {
     edbPreData_isOnlyMine:'edbPreData:isOnlyMine',//只看我的
     edbPreData_classifyOpt_add:'edbPreData:classifyOpt:add',//添加/编辑分类
     edbPreData_classifyOpt_delete:'edbPreData:classifyOpt:delete',//删除分类
+    edbPreData_classifyOpt_move:'edbPreData:classifyOpt:move',//移动分类
     edbPreData_checkRelatedChart:'edbPreData:checkRelatedChart',//查看关联图表
     edbPreData_checkRelatedEdb:'edbPreData:checkRelatedEdb',//查看关联指标
     edbPreData_checkPreRule:'edbPreData:checkPreRule',//查看预测规则
@@ -330,15 +332,23 @@ export const myETAPermission = {
     myChart_classifyOpt_rename:'myChart:classifyOpt:rename',//重命名
     myChart_classifyOpt_delete:'myChart:classifyOpt:delete',//删除
 }
+//图库框架
+export const chartFramePermission={
+    chartframe_public_copyImg:'chartframe:public:copyImg',//公共框架-复制图片
+    chartframe_my_editNode:'chartframe:my:editNode',//我的框架-添加/编辑节点
+    chartframe_my_saveFrame:'chartframe:my:saveFrame',//我的框架-保存框架
+    chartframe_my_editFrame:'chartframe:my:editFrame',//我的框架-添加/编辑框架
+    chartframe_my_delFrame:'chartframe:my:delFrame',//我的框架-删除框架
+    chartframe_my_show:'chartframe:my:show',//我的框架-设置可见权限
+    chartframe_my_rename:'chartframe:my:rename',//我的框架-重命名
+    chartframe_my_copyImg:'chartframe:my:copyImg',//我的框架-复制图片
+    chartframe_my_move:'chartframe:my:move',//我的框架-移动排序
+}
 /*
  * --------------------------------------------------------------------------ETA表格------------------------------------------------
 */
 export const etaTablePermission = {
     /*-----------页面按钮--------- */
-    etaTable_customize:'etaTable:customize',//自定义表格这个按钮显示不显示
-    etaTable_excel:'etaTable:excel',//添加Excel表格这个按钮显示不显示
-    etaTable_classifyOpt_edit:'etaTable:classifyOpt:edit',//添加编辑表格
-    etaTable_classifyOpt_delete:'etaTable:classifyOpt:delete',//删除表格
 
     /*-----------自定义表格--------- */
     /* etaTable_customize_del:'etaTable:customize:del',
@@ -346,22 +356,46 @@ export const etaTablePermission = {
     etaTable_customize_otherSave:'etaTable:customize:otherSave',
     etaTable_customize_refresh:'etaTable:customize:refresh',
     etaTable_customize_edit:'etaTable:customize:edit', */
-    //混合表格
+
+    //混合表格页面
+    etaTable_customize_mix_sheetAdd: 'etaTable:customize:mix:sheetAdd',//添加混合表格按钮
+    etaTable_customize_mix_classifyOpt_edit: 'etaTable:customize:mix:classifyOpt:edit',//混合表格分类操作
+    etaTable_customize_mix_classifyOpt_delete: 'etaTable:customize:mix:classifyOpt:delete',//混合表格分类删除
     etaTable_customize_mix_edit:'etaTable:customize:mix:edit',//编辑
     etaTable_customize_mix_refresh:'etaTable:customize:mix:refresh',//刷新
     etaTable_customize_mix_otherSave:'etaTable:customize:mix:otherSave',//另存为
     etaTable_customize_mix_download:'etaTable:customize:mix:download',//下载
     etaTable_customize_mix_del:'etaTable:customize:mix:del',//删除
-    //数据表格
+
+    //数据表格页面
+    etaTable_customize_data_sheetAdd: 'etaTable:customize:data:sheetAdd',//添加数据表格按钮
+    etaTable_customize_data_classifyOpt_edit: 'etaTable:customize:data:classifyOpt:edit',//数据表格分类操作
+    etaTable_customize_data_classifyOpt_delete: 'etaTable:customize:data:classifyOpt:delete',//数据表格分类删除
     etaTable_customize_data_edit:'etaTable:customize:data:edit',//编辑
     etaTable_customize_data_refresh:'etaTable:customize:data:refresh',//刷新
     etaTable_customize_data_otherSave:'etaTable:customize:data:otherSave',//另存为
     etaTable_customize_data_download:'etaTable:customize:data:download',//下载
     etaTable_customize_data_del:'etaTable:customize:data:del',//删除
-    /*-----------常规表格--------- */
+
+    /*-----------excel表格页面--------- */
+    etaTable_excel:'etaTable:excel',//添加Excel表格这个按钮显示不显示
+    etaTable_excel_classifyOpt_edit:'etaTable:excel:classifyOpt:edit',//添加编辑表格
+    etaTable_excel_classifyOpt_delete:'etaTable:excel:classifyOpt:delete',//删除表格
     etaTable_excel_del:'etaTable:excel:del',
     etaTable_excel_download:'etaTable:excel:download',
-    etaTable_excel_save:'etaTable:excel:save'
+    etaTable_excel_save:'etaTable:excel:save',
+
+    //自定义分析表格页面
+    // etaTable_analysis_sheetAdd: 'etaTable:analysis:sheetAdd',//添加数据表格按钮
+    etaTable_analysis_classifyOpt_edit: 'etaTable:analysis:classifyOpt:edit',//数据表格分类操作
+    etaTable_analysis_classifyOpt_delete: 'etaTable:analysis:classifyOpt:delete',//数据表格分类删除
+    etaTable_analysis_upload:'etaTable:analysis:upload',//上传文件
+    etaTable_analysis_createedb:'etaTable:analysis:createedb',//生成指标
+    etaTable_analysis_refresh:'etaTable:analysis:refresh',//刷新
+    etaTable_analysis_otherSave:'etaTable:analysis:otherSave',//另存为
+    etaTable_analysis_download:'etaTable:analysis:download',//下载
+    etaTable_analysis_del:'etaTable:analysis:del',//删除
+    etaTable_analysis_save:'etaTable:analysis:save',//保存
 }
 /*
  * --------------------------------------------------------------------------ETA逻辑------------------------------------------------
@@ -565,7 +599,7 @@ const btnMap  = {
     pptPermission,enPPTPermission,
     dataSourcePermission,
     edbDataPermission,predictEdbPermission,chartLibPermission,
-    myETAPermission,etaTablePermission,
+    myETAPermission,chartFramePermission,etaTablePermission,
     sandboxPermission,semanticPermission,
     statisticPermission,stockPlantPermission,
     productPricePermission,sysDepartPermission,

+ 6 - 2
src/utils/commonOptions.js

@@ -22,7 +22,7 @@ export function checkPassWord(pwd){
 //验证手机号的正则 仅支持国内大陆的
 export const patternPhone = /0?(13|14|15|18|17)[0-9]{9}/
 export function isMobileNo(account) {
-    // 手机号正则
+    /* // 手机号正则
     var isChinaMobile = new RegExp(
       "(^1(3[4-9]|4[78]|5[0-27-9]|7[28]|8[2-478]|98)\\d{8}$)"
     ); // 中国移动
@@ -41,7 +41,11 @@ export function isMobileNo(account) {
       return true;
     } else if (isChinaTelcom.test(account)) {
       return true;
-    } else return isOtherTelphone.test(account);
+    } else return isOtherTelphone.test(account); */
+    
+    //改成和后端一样的正则
+    const phonePatter = new RegExp("(^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0-9])|(17[0-9])|(16[0-9])|(19[0-9]))\\d{8}$)")
+    return phonePatter.test(account)
   }
 //验证邮箱的正则
 export const patternEmail = /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/

+ 2 - 0
src/utils/icon.js

@@ -65,4 +65,6 @@ export default {
 	no_view: require('@/assets/img/icons/no_view.png'),
 	/* 中英文切换 */
 	to_en: require('@/assets/img/icons/toEn.png'),
+	/* 跳转icon */
+	jupm_icon: require('@/assets/img/icons/jump_ico.png')
 }

+ 3 - 3
src/utils/svgToblob.js

@@ -1,10 +1,10 @@
 /* 针对系统中众多svg的图表/沙盘想要复制粘到微信中 */		
   import bus from '@/api/bus.js';
 
-  export const copyBlob = (url,callback=null,ratio=1) => {
+  export const copyBlob = (url,callback=null,ratio=1,urlType='svg') => {
     const copyImg = new Image()
     copyImg.crossOrigin = 'anonymous';
-    copyImg.src = svgToBase64(url);
+    copyImg.src = urlType==='svg'?svgToBase64(url):url;
 
     copyImg.onload = ()=> {
       const canvas = document.createElement('canvas');
@@ -30,7 +30,7 @@
           );
         })
       }else {
-        bus.$message.warning('浏览器暂不支持')
+        bus.$message.warning('当前协议暂不支持,仅支持https协议')
       }
     }	
  

+ 3 - 1
src/views/Home.vue

@@ -286,7 +286,7 @@
               :style="!isHaveAside ? 'padding: 0 30px 0 0;' : ''"
             >
               <transition name="fade" mode="out-in">
-                <router-view></router-view>
+                <router-view :key="$route.fullPath"></router-view>
               </transition>
             </el-col>
           </el-row>
@@ -497,6 +497,7 @@ export default {
       getBusinessCode().then(res=>{
         if(res.Ret!==200) return 
         this.bus_code = res.Data||''
+        this.$setting.bus_code = this.bus_code
       })
     },
     //判断是否为初始密码
@@ -798,6 +799,7 @@ export default {
             localStorage.setItem("AdminName", "");
             localStorage.setItem("ManageType", "");
             localStorage.setItem("RoleIdentity", "");
+            localStorage.setItem("loginTime", "");
 
             that.$router.push("/login");
           }, 10);

+ 5 - 0
src/views/Login.vue

@@ -443,6 +443,11 @@ export default {
             localStorage.setItem("ManageType", res.Data.Authority);
             localStorage.setItem("AdminId", res.Data.AdminId);
             localStorage.setItem("AdminName", res.Data.AdminName);
+            localStorage.setItem("loginTime",new Date())
+            // 清除最近登录时长
+            recordActiveLogin({ActiveTime:0}).then(res=>{
+                if(res.Ret!==200) return
+            })
         },
         //根据角色判断应该进入系统的哪个页面,进入系统
         async loginSys(res){

+ 140 - 0
src/views/chartFrame_manage/common/config.js

@@ -0,0 +1,140 @@
+/* ports 样式 */
+const portStyle = {
+    attrs: {
+        circle: {
+            r: 5,
+            magnet: true,
+            stroke: '#333',
+            strokeWidth: 1,
+            fill: '#fff'
+        }
+    }
+    }
+//基础节点
+export const baseNode = {
+    shape:'rect',
+    width: 120,
+    height: 50,
+    attrs:{
+        text:{ //文字换行
+            textWrap: {
+                width: -10,
+                ellipsis: true,
+            }
+        },
+        body:{
+            fill:'#ECF2FE',//背景色
+            stroke:'#0052D9',//边框色
+            strokeWidth:1,//边框宽度
+            strokeDasharray:'',//虚线,如果赋值为0保存缩略图时会省略掉边框
+        },
+        label:{ //与svg text属性相同
+            fill:'#0052D9',//文字颜色
+            fontSize:14,//文字大小
+            fontWeight:'normal',//文字粗细
+            fontStyle:'normal',//斜体
+            textDecoration:'normal',//下划线
+        }
+    },
+    ports: { //基础连接桩
+        items: [
+            { group: 'port-top', id: 'p_top' },
+            { group: 'port-bottom', id: 'p_bottom' },
+            { group: 'port-left', id: 'p_left' },
+            { group: 'port-right', id: 'p_right' },
+        ],
+        groups: {
+            "port-top": {
+                    position: 'top',
+                    zIndex: 20,
+                    ...portStyle
+            },
+            "port-bottom": {
+                    position: 'bottom',
+                    zIndex: 20,
+                    ...portStyle
+            },
+            "port-left": {
+                    position: 'left',
+                    zIndex: 20,
+                    ...portStyle
+            },
+            "port-right": {
+                    position: 'right',
+                    zIndex: 20,
+                    ...portStyle
+            },
+        }
+    },
+}
+//基础线条
+export const baseEdge = {
+    attrs:{
+        line:{
+            stroke:'#333',//线条颜色
+            strokeWidth:2,//线条宽
+            strokeDasharray:0,//虚线
+        }
+    }
+}
+
+//字号
+export const sizeOptions = [
+    30,
+    28,
+    26,
+    24,
+    22,
+    20,
+    18,
+    16,
+    14,
+    12,
+    10,
+]
+//线框宽度
+export const stokeWidthOptions = [1,2,3,4,5]
+//行高
+export const lineHeightOptions = [ //倍数 设置的值为 value*fontSize
+    {
+        label:'默认',
+        value:''
+    },
+    {
+        label:'1',
+        value:1,
+    },
+    {
+        label:'1.5',
+        value:1.5
+    },
+    {
+        label:'2',
+        value:2
+    }]
+//对齐方式
+export const textAnchorOptions = [
+    {
+        label:'居左',
+        options:{
+            refX:0,
+            refY:0.5,
+            textAnchor:'start',
+        }
+    },
+    {
+        label:'居中',
+        options:{
+            refX:0.5,
+            refY:0.5,
+            textAnchor:'middle',
+        }
+    },
+    {
+        label:'居右',
+        options:{
+            refX:0.99,
+            refY:0.5,
+            textAnchor:'end',
+        }
+    }]

+ 115 - 0
src/views/chartFrame_manage/common/event.js

@@ -0,0 +1,115 @@
+import { baseNode } from './config';
+//监听画布事件 tempThis是一个vue实例
+export const myEvents = (graph,tempThis=null)=>{
+    //右键节点/边
+    graph.on('cell:contextmenu',({cell,e})=>{
+        if(window.location.pathname.startsWith('/chartframe')) return 
+        graph.select(cell)
+        const dom = $('#context-menu-wrapper')[0];
+        dom.style.left = e.clientX-3 + 'px';
+        dom.style.top = e.clientY-3 + 'px';
+    })
+
+    graph.on('node:click',({node,e})=>{
+        if(!window.location.pathname.startsWith('/chartframe')) return 
+        console.log('node.data',node.data)
+        if(node.data&&node.data.id){
+            tempThis&&tempThis.$emit('showDialog',node.data)
+        }
+    })
+
+    /* 鼠标移入移出控制连接桩 */
+    graph.on('node:mouseenter', ({ node, e }) => {
+        if(window.location.pathname.startsWith('/chartframe')) return 
+        for(let i of document.querySelectorAll(`g[data-cell-id="${node.id}"] .x6-port-body`)) {
+            i.style.display = 'block'
+        }
+    })
+
+    graph.on('node:mouseleave', ({ node, e }) => {
+        if(window.location.pathname.startsWith('/chartframe')) return 
+        for(let i of document.querySelectorAll(`g[data-cell-id="${node.id}"] .x6-port-body`)) {
+            i.style.display = 'none'
+        }
+    })
+
+    /* 鼠标移入移出边 */
+    graph.on('edge:mouseenter', ({ edge }) => {
+        edge.addTools([
+          'source-arrowhead',
+          'target-arrowhead',
+          {
+            name: 'button-remove',
+            args: {
+              distance: -30,
+            },
+          },
+        ])
+      })
+      
+    graph.on('edge:mouseleave', ({ edge }) => {
+        edge.removeTools()
+    })
+
+    /* 元素选中事件 */
+    graph.on('cell:selected',({cell})=>{
+        const selects = graph.getSelectedCells()
+        if(cell.isNode()){
+            tempThis.isSelectEdge = false
+            tempThis.isSelectNode = true
+        }else if(cell.isEdge()){
+            tempThis.isSelectNode = false
+            tempThis.isSelectEdge = true
+        }
+        tempThis.cleanSelect = false
+        selects&&selects.length&&(tempThis.currentCell = selects[0])
+    })
+    /* 点击空白区域清空选区 屏蔽工具栏 */
+    graph.on('blank:click',() => {
+        graph.cleanSelection();
+        tempThis.isSelectEdge = false
+        tempThis.isSelectNode = false
+        tempThis.cleanSelect = true
+        tempThis.currentCell = baseNode
+    })
+
+    /* 历史记录改变 */
+    graph.history.on('change',()=>{
+        tempThis.canRedo = graph.history.canRedo()
+        tempThis.canUndo = graph.history.canUndo()
+    })
+
+}
+//监听键盘绑定事件
+export const bindKey = (graph,tempThis=null)=>{
+    //delete 删除选中元素
+    graph.bindKey(['delete'],()=>{
+        const selectCells = graph.getSelectedCells()
+        if(selectCells.length){
+            // 移除工具
+            selectCells.forEach(item => item.removeTools());
+            graph.removeCells(selectCells)
+            //重置工具栏
+            tempThis.isSelectEdge = false
+            tempThis.isSelectNode = false
+            tempThis.cleanSelect = true
+            tempThis.currentCell = baseNode
+        }
+    },'keydown')
+    //ctrl+c复制选择元素
+    graph.bindKey('ctrl+c',()=>{
+        const selectCells = graph.getSelectedCells()
+        if(selectCells.length){
+            graph.copy(selectCells)
+        }
+    })
+    //ctrl+v粘贴元素
+    graph.bindKey('ctrl+v', () => {
+        if (!graph.isClipboardEmpty()) {
+            const selectCell = graph.paste({ offset: 30 })
+            graph.cleanSelection()
+            graph.select(selectCell)
+        }
+        return false
+    });
+}

+ 135 - 0
src/views/chartFrame_manage/common/graph.js

@@ -0,0 +1,135 @@
+import {
+    Graph,Shape
+} from '@antv/x6';
+import { myEvents,bindKey } from './event';
+//非编辑页的配置
+const viewConfig = {
+    resizing:false,//不允许节点缩放
+    translating:{
+        restrict:true,//节点移动时无法超出画布
+    },
+    interacting:function (cellView){ //禁止节点移动
+        /* if(cellView.cell.getData().disableMove){
+            return false
+        } */
+        return false
+    },
+    highlighting:{},
+    /* connecting:{}, */
+    history:false,//关闭画布撤销/重做能力。
+    keyboard:false,
+    clipboard: false,
+}
+export function myGraph(wrapper,tempThis) {
+    const otherConfig = window.location.pathname.startsWith('/chartframe')?viewConfig:{}
+    const graph = new Graph({...{
+        container: document.getElementById(wrapper),
+        background: {
+            color: '#fff',
+        },
+        history:true,
+        keyboard:{
+            enabled:true,
+            global:true
+        },
+        clipboard: true,
+        selecting:{
+            enabled: true,
+            showNodeSelectionBox: false,
+            multiple: false
+        },
+        snapline: true,
+        scroller: {
+            enabled: true,
+            pannable: true,
+            minVisibleWidth: 50,
+            minVisibleHeight: 50,
+        },
+        //节点是否允许缩放
+        resizing: {
+            enabled: true,
+            orthogonal: false,
+        },
+        scaling: {
+            min: 0.5,
+            max: 2
+        },
+        mousewheel:{
+            enabled: true,
+            modifiers:['ctrl','meta']
+        },
+        highlighting: {
+            //当链接桩可以被链接时,在链接桩外围渲染一个 2px 宽的红色矩形框
+            magnetAvailable: {
+                name: "stroke",
+                args: {
+                    padding: 0.8,
+                    attrs: {
+                            "stroke-width": 2,
+                            stroke: "skyblue",
+                    },
+                },
+            },
+            //连线过程中,自动吸附到链接桩时被使用
+            magnetAdsorbed: {
+                name: "stroke",
+                args: {
+                    padding: 0.8,
+                    attrs: {
+                            "stroke-width": 4,
+                            stroke: "skyblue",
+                    },
+                },
+            },
+        },
+        connecting: {
+            snap: true,
+            highlight: true,
+            allowLoop:false,
+            allowNode:false,
+            connector: {
+                name: 'normal',
+                args: {
+                    padding:1
+                }
+            },
+            connectionPoint: 'anchor',
+            router:{
+                name:'manhattan',
+                args:{
+                }
+            },
+            /*
+            router: {
+                name: 'er',
+                args: {
+                    direction: 'V',
+                },
+            },
+             */
+            // 定义边样式
+            createEdge() {
+                return new Shape.Edge({
+                    attrs: {
+                        line: {
+                            stroke: '#0052D9',
+                            strokeWidth: 1,
+                            strokeDasharray: "",//虚线间隔
+                            sourceMarker: false,//起始箭头 
+                            targetMarker: 'classic',//终止箭头
+                        },
+                    },
+                    zIndex: 0,
+                })
+            },
+        },//连线
+        minimap: {
+            enabled: true,
+            container: document.getElementById("frameMinimap"),
+        }
+    },...otherConfig})
+    myEvents(graph,tempThis)
+
+    bindKey(graph,tempThis)
+    return graph
+}

+ 267 - 0
src/views/chartFrame_manage/components/frameContainer.vue

@@ -0,0 +1,267 @@
+<template>
+    <!-- 沙盘图区域 -->
+    <div class="frame-container-wrap">
+        <!-- 工具栏 -->
+        <FrameToolBar v-if="$route.path!=='/chartframe'&&graph"
+            :is-select-edge="isSelectEdge"
+            :is-select-node="isSelectNode"
+            :canUndo="canUndo"
+            :canRedo="canRedo"
+            :graph="graph"
+            :current-cell="currentCell||baseNode"
+        ></FrameToolBar>
+        <div class="frame-container" id="frameContainer"></div>
+        <!-- 缩略图 -->
+        <div class="minimap" id="frameMinimap"></div>
+        <!-- 右键菜单 -->
+        <div id="context-menu-wrapper" @mouseleave="hideContextMenu">
+            <el-dropdown-menu size="medium">
+                <el-dropdown-item v-for="menu in contextMenu" :key="menu.key" @click.native="handleContext(menu.key)">
+                    <i :class="menu.icon" v-if="menu.icon"/> 
+                    {{menu.label}}
+                </el-dropdown-item>
+            </el-dropdown-menu>
+        </div>
+        <!-- 内容空提示 -->
+        <div class="empty" v-if="!FrameworkContent.length&&$route.path==='/chartframe'">
+            <tableNoData text="框架内无节点"/>
+        </div>
+    </div>
+</template>
+
+<script>
+import { ElDropdownMenu } from 'element-ui';
+import { myGraph } from '../common/graph';
+import { baseNode } from '../common/config';
+import FrameToolBar from './frameToolBar.vue';
+export default {
+    components:{ElDropdownMenu,FrameToolBar},
+    props:{
+        FrameworkContent:{ //框架内容
+            type:String,
+            default:''
+        }
+    },
+    data() {
+        this.baseNode = baseNode //默认节点样式
+        return {
+            graph:null,//画布对象
+            /* contextMenu:[{
+                label: '编辑',
+                key: 'edit',
+                icon: 'el-icon-edit'
+            },
+            {
+                label: '删除',
+                key: 'del',
+                icon: 'el-icon-delete'
+            }], *///右键菜单
+            isSelectEdge:false,//是否选择了边
+            isSelectNode:false,//是否选择了节点
+            currentCell:null,//当前选中的元素
+            canRedo:false,//是否能前进
+            canUndo:false,//是否能后退
+            cleanSelect:false,//是否清除选区
+        };
+    },
+    watch:{
+        cleanSelect(newVal){
+            if(newVal){
+                this.currentCell = null
+            }
+        },
+        FrameworkContent(newVal){//当框架内容发生改变时,画布内容也发生改变
+            newVal.length&&this.gragh&&this.graph.fromJSON(JSON.parse(newVal))
+        }
+    },
+    computed:{
+        contextMenu(){//右键菜单,根据权限配置
+            const editOption = {label: '编辑',key: 'edit',icon: 'el-icon-edit'}
+            const deleteOption = {label: '删除',key: 'del',icon: 'el-icon-delete'}
+            let MenuArr = []
+            if(this.permissionBtn.isShowBtn('chartFramePermission','chartframe_my_editNode')){
+                MenuArr.push(editOption)
+            }
+            MenuArr.push(deleteOption)
+            return MenuArr
+        }
+    },
+    methods: {
+        //初始化画布
+        init(){
+            //如果需要在内部调用vue实例,则初始化时就将this传入
+            this.graph = new myGraph('frameContainer',this)
+            //如果有内容,初始化画布内容
+            this.FrameworkContent.length&&this.graph.fromJSON(JSON.parse(this.FrameworkContent))
+            //如果有内容,将画布内容居中
+            this.FrameworkContent.length&&this.graph.scrollToContent({ animation: { duration: 600 }})
+            //如果是非编辑页,加载完成画布内容后冻结画布
+            window.location.pathname.startsWith('/chartframe')&&this.graph.freeze()
+            //如果是编辑页,加载完成后清除历史数据
+            !window.location.pathname.startsWith('/chartframe')&&this.graph.cleanHistory()
+        },
+        //销毁画布
+        dispose(){
+            this.graph&&this.graph.dispose()
+        },
+        //添加/编辑节点
+        editNode(node){
+            //获取视口范围
+            const position = this.graph.getContentArea()
+            const nodes = this.graph.getNodes()
+            const currentNode = nodes.find(item=>item.id===node.nodeId)
+            if(currentNode){
+                currentNode.data.id=node.nodeLink.MyChartClassifyId
+                currentNode.label=node.nodeName
+                currentNode.data.nodeLink = node.nodeLink
+            }else{
+                //在视口范围内添加节点
+                this.graph.addNode({
+                    ...baseNode,
+                    ...{
+                    x:position.x+position.width/2+20,
+                    y:position.y+position.height/2+20,
+                    width:120,
+                    height:50,
+                    data:{
+                        id:node.nodeLink.MyChartClassifyId,//存储节点对应的myETA分类id
+                        nodeLink:node.nodeLink
+                    },
+                    label:node.nodeName||''
+                }})
+            }
+        },
+        //点击右键菜单事件
+        handleContext(key){
+            const select_cell = this.graph.getSelectedCells()
+            if(!select_cell.length) return 
+
+            if(key==='edit'){
+                const {id} = select_cell[0]
+                const node = this.graph.getNodes().find(item=>item.id===id)
+                this.$emit('editNode',{
+                    nodeId:node.id,
+                    nodeName:node.label,
+                    nodeLink:node.data.nodeLink
+                })
+            }
+            if(key==='del'){
+                this.graph.removeCells(select_cell)
+                this.hideContextMenu()
+            }
+            //清除选区
+            this.graph.cleanSelection()
+        },
+        hideContextMenu(){
+            const dom = $('#context-menu-wrapper')[0];
+            dom.style.left = '-9999px';
+            dom.style.top = '-9999px';
+        },
+        //获取画布内容的svg数据
+        getContentPic(){
+            const { cells } = this.graph.toJSON();
+            let svgData = ''
+            this.graph.toSVG((dataUri) => {
+                svgData = dataUri 
+                
+            },{
+                preserveDimensions:true,//让svg为实际图片大小
+                beforeSerialize:(svg)=>{
+                    const {x,y,width,height} = this.graph.getContentBBox(cells)
+                    let {tx,ty} = this.graph.translate() // 画布偏移量
+                    //给导出的svg增加一点宽高
+                    svg.setAttribute('width',width+50)
+                    svg.setAttribute('height',height+50) 
+                    //设置viewBox使图像居中
+                    svg.setAttribute('viewBox',`${x-25} ${y-25} ${width+50} ${height+50}`)
+                },
+                copyStyles:false,
+                stylesheet: `
+                    svg{
+                        background-color:white;
+                    }
+                    .x6-port {
+                        visibility: hidden;
+                    }
+                    ` 
+            })
+            return svgData
+        },
+        //获取画布节点并转换成对应格式
+        getContentNodes(){
+            return this.graph.getNodes().map(node=>{
+                return {
+                    NodeName:node.label,
+                    MyChartClassifyId:Number(node.data.id)
+                }
+            })
+        }
+    },
+    mounted(){
+        //this.init()
+    }
+};
+</script>
+
+<style lang="scss">
+.frame-container-wrap {
+    width:100%;
+    height:100%;
+    display: flex;
+    overflow: hidden;
+    position: relative;
+    padding-top: 26px;
+    .minimap {
+        position: absolute;
+        right: 16px;
+        bottom: 16px;
+        box-sizing: border-box;
+
+        .x6-widget-minimap-viewport {
+            border-color: #0052D9;
+
+            .x6-widget-minimap-viewport-zoom {
+                border-color: #0052D9;
+            }
+        }
+
+        .x6-widget-minimap {
+            width: auto !important;
+            height: auto !important;
+            overflow: visible !important;
+            padding:0 !important;
+        }
+    }
+    #context-menu-wrapper{
+        position: fixed;
+        z-index: 99;
+        top: -9999px;
+        left: -9999px;
+        background: #fff;
+        padding: 10px 0;
+        box-shadow: 0 1px 4px #999;
+
+    }
+    #frameContainer{
+        flex: 1;
+    }
+    .x6-graph-scroller {
+        flex: 1;
+        width:auto !important;
+        height:auto !important;
+    }
+
+    .x6-port-body {
+        display: none;
+    }
+    .empty{
+        position:absolute;
+        left:50%;
+        top:0;
+        transform: translateX(-50%);
+    }
+}
+</style>
+<style scoped lang="scss">
+
+</style>

+ 402 - 0
src/views/chartFrame_manage/components/frameToolBar.vue

@@ -0,0 +1,402 @@
+<template>
+    <!-- 框架工具栏 -->
+    <div class="frame-tool-bar-wrap">
+        <div class="cell-style">
+            <!-- 撤销 -->
+            <ToolItem tooltip="撤销" toolkey="undo">
+                <div class="tool-item" @click="handleGraphHistory('undo')">
+                    <img :src="require(`@/assets/icons/chartFrame/undo.svg`)"
+                        :class="{'img-disabled':!canUndo,'actived':canUndo}">
+                    <span class="disabled" v-if="!canUndo"></span>
+                </div>
+                
+            </ToolItem>
+            <!-- 恢复 -->
+            <ToolItem tooltip="恢复" toolkey="undo">
+                <div class="tool-item" @click="handleGraphHistory('redo')">
+                    <img :src="require(`@/assets/icons/chartFrame/redo.svg`)"
+                        :class="{'img-disabled':!canRedo,'actived':canRedo}">
+                    <span class="disabled" v-if="!canRedo"></span>
+                </div>
+            </ToolItem>
+            <!-- 字体 暂定-->
+            <!-- 字号 -->
+            <ToolItem tooltip="字号" toolkey="fontSize">
+                <el-dropdown @command="changeStyle" trigger="click" class="tool-item">
+                    <span class="el-dropdown-link tool-item"> 
+                        <span>{{nodeStyle.fontSize}}px</span>
+                        <i class="el-icon-caret-bottom"></i>
+                    </span>
+                    <el-dropdown-menu slot="dropdown">
+                        <el-dropdown-item v-for="item in sizeOptions" 
+                            :key="item" :command="{attr:'label/fontSize',value:item}">{{item}}</el-dropdown-item>
+                    </el-dropdown-menu>
+                    <span class="disabled" v-if="!isSelectNode"></span>
+                </el-dropdown>
+            </ToolItem>
+            <!-- 加粗 -->
+            <ToolItem tooltip="加粗" toolkey="fontWeight">
+                <span class="tool-item">
+                    <span class="item-text" :class="{'text-disabled':!isSelectNode,'text-actived':isSelectNode}"
+                        :style="'font-size: 16px;font-weight: bold;'"
+                        @click="changeStyleToggle('label/fontWeight')">B</span>
+                    <span class="disabled" v-if="!isSelectNode"></span>
+                </span>
+            </ToolItem>
+            <!-- 斜体 -->
+            <ToolItem tooltip="斜体" toolkey="fontstyle">
+                <span class="tool-item">
+                    <span style="font-style: italic;" class="item-text"
+                        @click="changeStyleToggle('label/fontStyle')">
+                        <img :src="require(`@/assets/icons/chartFrame/fontStyle.svg`)"
+                            :class="{'img-disabled':!isSelectNode,'actived':isSelectNode}">
+                    </span>
+                    <span class="disabled" v-if="!isSelectNode"></span>
+                </span>
+            </ToolItem>
+            <!-- 下划线 -->
+            <ToolItem tooltip="下划线" toolkey="textDecoration">
+                <span class="tool-item">
+                    <span style="text-decoration: underline;" class="item-text"
+                        @click="changeStyleToggle('label/textDecoration')">
+                        <img :src="require(`@/assets/icons/chartFrame/fontText.svg`)"
+                            :class="{'img-disabled':!isSelectNode,'actived':isSelectNode}">
+                    </span>
+                    <span class="disabled" v-if="!isSelectNode"></span>
+                </span>
+            </ToolItem>
+            <!-- 字体颜色 -->
+            <ToolItem tooltip="字体颜色" toolkey="textDecoration">
+                <span class="tool-item">
+                    <label for="label/fill" :style="`color:${color}`">
+                        <img :src="require(`@/assets/icons/chartFrame/fontColor.svg`)"
+                            :class="{'img-disabled':!isSelectNode,'actived':isSelectNode}">
+                    </label>
+                    <input type="color" id="label/fill" style="width: 0;height: 0;visibility: hidden;" 
+                        :value="nodeStyle.color"
+                        @input="valueChange"/>
+                    <span class="disabled" v-if="!isSelectNode"></span>
+                </span>
+            </ToolItem>
+            <!-- 文本行高 暂定-->
+            <!-- 文本对齐 -->
+            <ToolItem tooltip="文本对齐" toolkey="textAligh">
+                <el-dropdown @command="changeTextStyle" trigger="click" class="tool-item">
+                    <span class="el-dropdown-link tool-item"> 
+                        <img :src="require(`@/assets/icons/chartFrame/textAlign.svg`)"
+                            :class="{'img-disabled':!isSelectNode,'actived':isSelectNode}">
+                        <i class="el-icon-caret-bottom"></i>
+                    </span>
+                    <el-dropdown-menu slot="dropdown">
+                        <el-dropdown-item v-for="item in textAnchorOptions" 
+                            :key="item.label" :command="{attr:'label/textAligh',value:item.options}">{{item.label}}</el-dropdown-item>
+                    </el-dropdown-menu>
+                    <span class="disabled" v-if="!isSelectNode"></span>
+                </el-dropdown>
+            </ToolItem>
+            <!-- 节点颜色填充 -->
+            <ToolItem tooltip="填充颜色" toolkey="fillColor">
+                <span class="tool-item">
+                    <label for="body/fill" :style="`color:${fillColor}`">
+                        <img :src="require(`@/assets/icons/chartFrame/fillColor.svg`)"
+                            :class="{'img-disabled':!isSelectNode,'actived':isSelectNode}">
+                    </label>
+                    <input type="color" id="body/fill" style="width: 0;height: 0;visibility: hidden;"
+                        :value="nodeStyle.fill"
+                        @input="valueChange"/>
+                    <span class="disabled" v-if="!isSelectNode"></span>
+                </span>
+            </ToolItem>
+            <!-- 节点/线条边框颜色 -->
+            <ToolItem tooltip="边框颜色" toolkey="borderColor">
+                <span class="tool-item">
+                    <label for="storke" :style="`color:${borderColor}`">
+                        <img :src="require(`@/assets/icons/chartFrame/stokeColor.svg`)"
+                            :class="{'img-disabled':!isSelectNode&&!isSelectEdge,'actived':isSelectNode||isSelectEdge}">
+                    </label>
+                    <input type="color" id="storke" style="width: 0;height: 0;visibility: hidden;" 
+                        :value="cellStyle.stroke"
+                        @input="valueChange"/>
+                    <span class="disabled" v-if="!isSelectNode&&!isSelectEdge"></span>
+                </span>
+            </ToolItem>
+            <!-- 节点/线条边框宽度 -->
+            <ToolItem tooltip="线框宽度" toolkey="stokeWidth">
+                <el-dropdown @command="changeCellStyle" trigger="click" class="tool-item">
+                    <span class="el-dropdown-link tool-item"> 
+                        <i class="el-icon-minus"></i>
+                        <i class="el-icon-caret-bottom"></i>
+                    </span>
+                    <el-dropdown-menu slot="dropdown">
+                        <el-dropdown-item v-for="item in stokeWidthOptions" 
+                            :key="item" :command="{attr:'width',value:item}">{{item}}</el-dropdown-item>
+                    </el-dropdown-menu>
+                    <span class="disabled" v-if="!isSelectNode&&!isSelectEdge"></span>
+                </el-dropdown>
+            </ToolItem>
+            <!-- 节点/线条边框样式 -->
+            <ToolItem tooltip="边框样式" toolkey="stokeWidth">
+                <el-dropdown @command="changeCellStyle" trigger="click" class="tool-item">
+                    <span class="el-dropdown-link tool-item"> 
+                        <img :src="require(`@/assets/icons/chartFrame/stokeStyle.svg`)"
+                            :class="{'img-disabled':!isSelectNode&&!isSelectEdge,'actived':isSelectNode||isSelectEdge}">
+                        <i class="el-icon-caret-bottom"></i>
+                    </span>
+                    <el-dropdown-menu slot="dropdown">
+                        <el-dropdown-item :command="{attr:'dash',value:5}">
+                            <i class="iconfont icon--xuxian" style="color:'#000';fontSize:30px"></i>
+                        </el-dropdown-item>
+                        <el-dropdown-item :command="{attr:'dash',value:0}">
+                            <i class="iconfont icon--shixian" style="color:'#000';fontSize:30px"></i>
+                        </el-dropdown-item>
+                    </el-dropdown-menu>
+                    <span class="disabled" v-if="!isSelectNode&&!isSelectEdge"></span>
+                </el-dropdown>
+            </ToolItem>
+            <!-- 开始箭头 -->
+            <ToolItem tooltip="开始箭头" toolkey="stokeWidth">
+                <el-dropdown trigger="click" @command="changeStyle" class="tool-item">
+                    <div class="el-dropdown-link">
+                        <img :src="require(`@/assets/icons/chartFrame/arrow-left.svg`)"
+                            :class="{'img-disabled':!isSelectEdge,'actived':isSelectEdge}">
+                            <i class="el-icon-caret-bottom"></i>
+                    </div>
+                    <el-dropdown-menu slot="dropdown">
+                        <el-dropdown-item :command="{attr:'line/sourceMarker',value: 'classic'}">
+                            <i class="iconfont icon-arrow-left" style="color:'#000';fontSize:24px"></i>
+                        </el-dropdown-item>
+                        <el-dropdown-item :command="{attr:'line/sourceMarker',value: ''}">
+                            <i class="iconfont icon--shixian" style="color:'#000';fontSize:32px"></i>
+                        </el-dropdown-item>
+                    </el-dropdown-menu>
+                    <span class="disabled" v-if="!isSelectEdge"></span>
+                </el-dropdown>
+            </ToolItem>
+            <!-- 结束箭头 -->
+            <ToolItem tooltip="结束箭头" toolkey="stokeWidth">
+                <el-dropdown trigger="click" @command="changeStyle" class="tool-item">
+                    <div class="el-dropdown-link">
+                        <img :src="require(`@/assets/icons/chartFrame/arrow-right.svg`)"
+                            :class="{'img-disabled':!isSelectEdge,'actived':isSelectEdge}">
+                            <i class="el-icon-caret-bottom"></i>
+                    </div>
+                    <el-dropdown-menu slot="dropdown">
+                        <el-dropdown-item :command="{attr:'line/targetMarker',value: 'classic'}">
+                            <i class="iconfont icon-arrow-right" style="color:'#000';fontSize:24px"></i>
+                        </el-dropdown-item>
+                        <el-dropdown-item :command="{attr:'line/targetMarker',value: ''}">
+                            <i class="iconfont icon--shixian" style="color:'#000';fontSize:32px"></i>
+                        </el-dropdown-item>
+                    </el-dropdown-menu>
+                    <span class="disabled" v-if="!isSelectNode&&!isSelectEdge"></span>
+                </el-dropdown>
+            </ToolItem>
+        </div>
+        
+    </div>
+</template>
+
+<script>
+import '@/assets/icons/iconfont.css';
+import ToolItem from './toolItem.vue';
+import {sizeOptions,stokeWidthOptions,lineHeightOptions,textAnchorOptions} from '../common/config';
+export default {
+    components: { ToolItem },
+    props:{
+        isSelectNode:{//当前选中的元素是否是节点
+            type:Boolean,
+            default:false
+        },
+        isSelectEdge:{//当前选中的元素是否是边
+            type:Boolean,
+            default:false
+        },
+        currentCell:{//当前传入的元素,Node/Edge
+            type:Object,
+        },
+        graph:{ //当前画布
+            type:Object,
+        },
+        canRedo:{
+            type:Boolean
+        },
+        canUndo:{
+            type:Boolean
+        }
+    },
+    data() {
+        this.sizeOptions=sizeOptions
+        this.stokeWidthOptions=stokeWidthOptions
+        this.textAnchorOptions=textAnchorOptions
+        return {
+            nodeStyle:{ //回显用的
+                fontSize:14,
+                fill:'#333',
+                color:'#333',
+            },
+            cellStyle:{
+                stroke:'#333',
+            },
+            color:'#333',
+            fillColor:'#333',
+            borderColor:'#333',
+        };
+    },
+    watch:{
+        isSelectNode(newVal){
+            if(!newVal){
+                //重置 node相关样式
+                this.nodeStyle = {
+                    fontSize:14,
+                    fill:'#333',
+                    color:'#333',
+                    stroke:'#333'
+                }
+            }
+        },
+        currentCell(newVal){
+            if(newVal){
+                if(newVal.isNode&&newVal.isNode()){
+                    this.nodeStyle = {
+                        fontSize:newVal.attrs.label.fontSize,
+                        fill:newVal.attrs.body.fill,
+                        color:newVal.attrs.label.fill,
+                        stroke:newVal.attrs.body.stroke,
+                    }
+                    this.cellStyle = {
+                        store:newVal.attrs.body.stroke,
+                    }
+                }
+                if(newVal.isEdge&&newVal.isEdge()){
+                    this.cellStyle = {
+                        store:newVal.attrs.line.stroke
+                    }
+                }
+
+            }
+        },
+    },
+    methods: {
+        //加粗,斜体,下划线样式
+        changeStyleToggle(attr){
+            const value = this.currentCell.attr(attr)
+            const valueMap = {
+                'label/fontWeight':['normal','bold'],
+                'label/fontStyle':['normal','italic'],
+                'label/textDecoration':['normal','underline'],
+            }
+            this.changeStyle({attr,
+                value:value===valueMap[attr][0]
+                ?valueMap[attr][1]
+                :valueMap[attr][0]})
+        },
+        changeStyle({attr,value}){
+            this.currentCell.attr(attr,value)
+            if(attr==='label/fontSize'){
+                this.nodeStyle.fontSize = value
+            }
+            
+        },
+        //边框和线条通用样式:线条颜色,宽度,虚线
+        valueChange(e){
+            //t.target.value: "#9c3535"
+            if(e.target){
+                const styleMap = {
+                    'storke':['body/stroke','line/stroke'],
+                    'width':['body/strokeWidth','line/strokeWidth'],
+                    'dash':['body/strokeDasharray','line/strokeDasharray']
+                }
+                const {id,value} = e.target
+                let attr = id
+                if(styleMap[id]){
+                    attr = this.isSelectNode?styleMap[id][0]:styleMap[id][1]
+                } 
+                this.currentCell.attr(attr,value)
+            }
+        },
+        changeCellStyle({attr,value}){
+            this.valueChange({target:{id:attr,value}})
+        },
+        changeTextStyle({attr,value}){
+            for(const key in value){
+                this.currentCell.attr('label/'+key,value[key])
+            }
+        },
+        //撤销/恢复
+        handleGraphHistory(type){
+            this.graph.history[type]()
+        }
+    },
+    mounted(){
+    },
+    
+};
+</script>
+
+<style lang="scss">
+.frame-tool-bar-wrap{
+    .tool-item{
+        .el-input{
+            .el-input__inner {
+                padding:0;
+                height:100%;
+            }
+        }
+    }
+    .el-button{
+        padding:0;
+    }
+}
+</style>
+<style scoped lang="scss">
+.frame-tool-bar-wrap{
+    background-color:#F6F7F8;
+    padding: 5px;
+    position: absolute;
+    height: 26px;
+    left: 0;
+    right:0;
+    top:0;
+    z-index: 100;
+    box-sizing: border-box;
+    .cell-style{
+        display: flex;
+        gap:0 20px;
+        overflow:hidden;
+        align-items:center;
+        .tool-item{
+            cursor: pointer;
+            position: relative;
+            .img-disabled{
+                transform:translateY(50px);
+                filter:drop-shadow(#C8CDD9 0px -50px 0px);
+            }
+            .actived{
+                transform:translateY(50px);
+                filter:drop-shadow(#333 0px -50px 0px);
+            }
+            .item-text{
+                padding:0 2px;
+                &.text-disabled{
+                    color:#C8CDD9;
+                }
+                &.text-actived{
+                    color:#333;
+                }
+            }
+            .disabled {
+                color: #bbb;
+                /* background: rgba(0, 0, 0, 0.08); */
+                background-color: transparent;
+                cursor: not-allowed;
+                position: absolute;
+                top: 0;
+                right: 0;
+                left: 0;
+                bottom: 0;
+                z-index: 1;
+            }
+        }
+    }
+}
+</style>

+ 36 - 0
src/views/chartFrame_manage/components/toolItem.vue

@@ -0,0 +1,36 @@
+<template>
+    <div class="tool-item-wrap">
+        <el-tooltip class="item" effect="dark" :content="tooltip" placement="top">
+            <slot></slot>
+        </el-tooltip>
+    </div>
+</template>
+
+<script>
+export default {
+    props:{
+        tooltip:{
+            type:String,
+            default:''
+        },
+        toolkey:{
+            type:String,
+            default:''
+        },
+        disabled:{
+            type:Boolean,
+            default:false,
+        }
+    },
+    data() {
+        return {};
+    },
+    methods: {
+
+    },
+};
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 149 - 0
src/views/chartFrame_manage/css/basePage.scss

@@ -0,0 +1,149 @@
+.chart-frame-wrap{
+    display: flex;
+    width:100%;
+    position:relative;
+    *{box-sizing: border-box;}
+    .slide-icon {
+        padding: 20px 0;
+        box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.3);
+        border-radius: 5px;
+        cursor: pointer;
+        position: absolute;
+        top: 50%;
+        transform: translateY(-50%);
+        z-index: 99;
+        &:hover {
+          background-color: rgba(0, 0, 0, 0.05);
+        }
+        &.slide-left {
+          right: 0;
+        }
+        &.slide-right {
+          left: 0;
+        }
+    }
+    .page-block-wrap{
+        padding:20px;
+        background-color: #fff;
+        border-radius: 4px;
+        height: calc(100vh - 120px);
+    }
+    .catalog-wrap{
+        width:300px;
+        min-width: 300px;
+        margin-right: 30px;
+        padding:20px;
+        position: relative;
+        display: flex;
+        flex-direction: column;
+        gap:20px 0;
+        .move-btn {
+            height: 100%;
+            width: 4px;
+            position: absolute;
+            right: 0px;
+            top: 0;
+            &:hover {
+              cursor: col-resize;
+            }
+          }
+        .catalog-list{
+            display: flex;
+            flex-direction: column;
+            flex: 1;
+            overflow-y: auto;
+            /* .public-catalog,.my-list{
+                height: 50%;
+                overflow-y: auto;
+            } */
+            .public-catalog{
+                .catalog-tree{
+                    margin: 20px 0;
+                    min-height: 100px;
+                }
+            }
+            .my-list{
+                .classify-item{
+                    display: flex;
+                    align-items: center;
+                    padding:10px;
+                    cursor: pointer;
+                    &.active{
+                        background: #e0eefd;
+                        color: #409eff;
+                    }
+                    .item-label{
+                        flex: 1;
+                        margin: 0 5px;
+                    }
+                    .icon{
+                        width: 18px;
+                    }
+                }
+            }
+        }
+    }
+    .detail-wrap{
+        padding:0;
+        flex:1;
+        background-color: transparent;
+        overflow-y: auto;
+        .list{
+            display: flex;
+            flex-wrap: wrap;
+            gap:20px;
+            .item-title{
+                padding-bottom: 10px;
+            }
+            .list-item{
+                width: 22%;
+                min-width:270px;
+               /*  max-width:300px; */
+                padding:10px;
+                background-color: #fff;
+                cursor: pointer;
+                .item-image{
+                    margin-top:10px;
+                    width:100%;
+                    height: 0;
+                    padding-bottom: 70%;
+                    background-color: pink;
+                    background: no-repeat center/contain url('~@/assets/img/document_m/default-img.png');
+                }
+            }
+        }
+        .detail{
+            background-color: #fff;
+            width:100%;
+            height:100%;
+            display: flex;
+            flex-direction: column;
+            .top-info{
+                width:100%;
+                padding:20px;
+                display: flex;
+                .title{
+                    flex: 1;
+                    text-align: center;
+                    margin: 0 20px;
+                }
+                .tool{
+                    .el-button{
+                        padding: 0;
+                    }
+                }
+                border-bottom: 1px solid #ECECEC;
+            }
+            .frame-wrap{
+                flex:1;
+                overflow: hidden;
+            }
+        }
+    }
+    .dialog-container,.dialog-footer{
+        text-align: center;
+    }
+    .dialog-footer{
+        padding:25px 0;
+    }
+}

+ 69 - 0
src/views/chartFrame_manage/css/customTree.scss

@@ -0,0 +1,69 @@
+.chart-frame-wrap{
+    .catalog-tree{
+        .custom-tree-node {
+            display: flex !important;
+            justify-content: space-between;
+            align-items: center;
+            display: block;
+            flex: 1;
+            width: calc(100% - 28px);
+            .node_label {
+                margin-right: 2px;
+            }
+            .tree-label {
+                flex: 1;
+                overflow: hidden;
+                white-space: nowrap;
+                text-overflow: ellipsis;
+            }
+        }
+        .el-tree-node__content {
+            margin-bottom: 7px !important;
+            &:hover {
+                background-color: #f0f4ff !important;
+              }
+        }
+        .el-tree-node__children {
+            .el-tree-node {
+              margin-bottom: 0px !important;
+              padding-left: 18px;
+            }
+        
+            .el-tree-node__content {
+              margin-bottom: 5px !important;
+              padding-left: 0 !important;
+        
+              &:hover {
+                background-color: #f0f4ff !important;
+              }
+            }
+        }
+        .el-tree-node.is-current>.el-tree-node__content {
+            background-color: #f0f4ff !important;
+            color: #409eff;
+        }
+        .expanded.el-icon-caret-right:before {
+            content: url('~@/assets/img/set_m/down.png') !important;
+        }
+        .el-icon-caret-right:before {
+            content: url('~@/assets/img/set_m/slide.png') !important;
+        }
+        .el-tree-node__expand-icon.is-leaf.el-icon-caret-right:before {
+            content: '' !important;
+        }
+        .el-tree-node__expand-icon.expanded {
+            -webkit-transform: rotate(0deg);
+            transform: rotate(0deg);
+        }
+    }
+    .el-dropdown-menu-item{
+        &:hover {
+            background-color: #F5F7FA  !important;
+            color: #606266 !important;
+        }
+    }
+    .el-dropdown-menu .el-dropdown-menu-item-chat {
+        background-color: #ecf5ff !important;
+        color: #66b1ff !important;
+    }
+}

+ 221 - 0
src/views/chartFrame_manage/frameEditor.vue

@@ -0,0 +1,221 @@
+<template>
+    <!-- 添加编辑框架 -->
+    <div class="frame-editor-wrap">
+        <div class="option-wrap">
+            <el-input style="width:240px;" placeholder="请输入框架名称" v-model.trim="frameDetail.FrameworkName"></el-input>
+            <el-button type="primary" style="margin-left:auto;" @click="handleEditNode({})"
+                v-if="permissionBtn.isShowBtn('chartFramePermission','chartframe_my_editNode')">添加节点</el-button>
+            <el-button type="primary" style="margin-left:20px;" @click="saveFrame"
+                v-if="permissionBtn.isShowBtn('chartFramePermission','chartframe_my_saveFrame')">保存</el-button>
+        </div>
+        <div class="editor-wrap">
+            <!-- 沙盘图组件 -->
+            <FrameContainer ref="container"
+                :FrameworkContent="frameDetail.FrameworkContent"
+                @editNode="handleEditNode"
+                @framePic="getFramePic"
+            />
+        </div>
+        <!-- 添加/编辑节点弹窗 -->
+        <el-dialog
+            :title="modifyNode.nodeId?'编辑节点':'添加节点'"
+            :visible.sync="isModifyNodeDialogShow"
+            :close-on-click-modal="false"
+            :modal-append-to-body="false"
+            @close="isModifyNodeDialogShow=false"
+            width="589px"
+            v-dialogDrag
+            center
+        >
+            <div class="dialog-container">
+                <el-form
+                    ref="refForm"
+                    :model="modifyNode"
+                    :rules="rules"
+                >
+                    <el-form-item label="节点名称" prop="nodeName">
+                        <el-input v-model.trim="modifyNode.nodeName" placeholder="请输入节点名称" style="width:217px;"></el-input>
+                    </el-form-item>
+                    <el-form-item label="节点链接" prop="nodeLink">
+                        <el-select v-model="modifyNode.nodeLink" value-key="MyChartClassifyId" placeholder="请选择节点链接" style="width:217px;">
+                            <el-option v-for="item in myList" 
+                                :key="item.MyChartClassifyId"
+                                :label="item.MyChartClassifyName"
+                                :value="item">
+                                <span style="float:left;">{{item.MyChartClassifyName}}</span>
+                                <span style="float:right;color: #8492a6; font-size: 13px"
+                                @click="goToList(item)"><img src="~@/assets/img/chart_m/check.png"></span>
+                            </el-option>
+                        </el-select>
+                    </el-form-item>
+                </el-form>
+            </div>
+            <div class="dialog-footer">
+                <el-button @click="isModifyNodeDialogShow=false">取消</el-button>
+                <el-button type="primary" @click="editNode">确定</el-button>
+            </div>
+
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+import FrameContainer from './components/frameContainer.vue';
+import { mychartInterface,chartFrameInterface,dataBaseInterface } from '@/api/api.js';
+export default {
+    components: { FrameContainer },
+    data() {
+        return {
+            frameId:this.$route.query.frameId||0,
+            frameDetail:{
+                FrameworkName:'',
+                FrameworkContent:'',
+            },
+            lockLoding:null,
+            modifyNode: {},//正在编辑的节点
+            isModifyNodeDialogShow: false,//编辑节点弹窗
+            rules: {
+                nodeName: [{ required: true, message: "请输入节点名称", trigger: "blur" }],
+                nodeLink: [{ required: true, message: "请选择节点链接", trigger: "blur" }]
+            },
+            myList:[],//我的图库列表
+        };
+    },
+    methods: {
+        //获取正在编辑的节点,弹出弹窗
+        handleEditNode(node = {}) {
+            this.$refs.refForm && this.$refs.refForm.resetFields();
+            this.modifyNode = _.cloneDeep(node);
+            this.isModifyNodeDialogShow = true;
+        },
+        //编辑节点,更改子组件节点信息,隐藏弹窗
+        async editNode() {
+            await this.$refs.refForm.validate();
+            if(!this.$refs.container) return
+            this.$refs.container.editNode(this.modifyNode)
+            this.$message.success(`${this.modifyNode.nodeId ? '编辑' : '添加'}节点成功`);
+            this.isModifyNodeDialogShow = false;
+        },
+        //跳转至my eta
+        goToList(item) {
+            window.open(`/mychart?frameId=${item.MyChartClassifyId}`);
+        },
+        //保存框架:内容验证->生成缩略图->获取节点信息,内容信息->编辑/添加框架
+        async saveFrame(){
+            if(!this.frameDetail.FrameworkName.length){
+                return this.$message.warning("请输入框架名称")
+            }
+            if(!this.$refs.container.graph.toJSON().cells.length){
+                return this.$message.warning('请绘制画布内容');
+            }
+
+            this.lockLoding = this.$loading({
+                lock: true,
+                text: '保存中...',
+                target: '.frame-editor-wrap',
+                spinner: 'el-icon-loading',
+                background: 'rgba(255, 255, 255, 0.8)'
+            });
+
+            //获取框架内容图片
+            const svgData = this.$refs.container.getContentPic()
+            if(svgData){
+                const params = new FormData();
+                params.append('Img',svgData)
+                const { Data,Ret } = await dataBaseInterface.uploadImgSvg(params);
+                if(Ret !== 200) return;
+                if(!Data){
+                    return this.$message.warning("上传图片失败")
+                }
+                this.frameDetail.FrameworkImg = Data.ResourceUrl||''
+            }
+            //获取框架节点和内容
+            this.frameDetail.Nodes = this.$refs.container.getContentNodes()
+            this.frameDetail.FrameworkContent = JSON.stringify(this.$refs.container.graph.toJSON())
+            if(this.frameId){
+                //edit
+                chartFrameInterface.editFrame({...this.frameDetail,...{ChartFrameworkId:Number(this.frameId)}}).then(res=>{
+                    this.lockLoding.close();
+                    if(res.Ret!==200) return 
+                    this.$message.success("编辑成功")
+                })
+            }else{
+                //add 
+                chartFrameInterface.addFrame(this.frameDetail).then(res=>{
+                    this.lockLoding.close();
+                    if(res.Ret!==200) return 
+                    this.frameId = res.Data?res.Data.ChartFrameworkId:0
+                    this.frameDetail = res.Data||{FrameworkName:'',FrameworkContent:''}
+                    this.$message.success("新增成功")
+                    //切换至编辑页
+                    this.$router.replace({path:'/editframe',query:{frameId:this.frameId}})
+                })
+            }
+        },
+        getMyList(){
+            mychartInterface.classifyList().then((res)=>{
+                if(res.Ret!==200) return
+                if(!res.Data) return 
+                this.myList = res.Data.List||[]
+            })
+        },
+        async getFrameDetail(){
+            if(this.frameId){
+                const res = await chartFrameInterface.getFrameDetail({ChartFrameworkId:Number(this.frameId)})
+                if(res.Ret!==200) return 
+                this.frameDetail = res.Data||{FrameworkName:'',FrameworkContent:''}
+            }
+            //获取到框架内容后再加载graph
+            this.$nextTick(()=>{
+                this.$refs.container.init()
+            })
+            
+        },
+    },
+    mounted(){
+        this.getMyList()
+        this.getFrameDetail()
+    }
+};
+</script>
+
+<style scoped lang="scss">
+.frame-editor-wrap{
+    display: flex;
+    flex-direction: column;
+    height: calc(100vh - 120px);
+    *{box-sizing: border-box;}
+    .option-wrap{
+        background-color:#fff;
+        padding:20px;
+        display: flex;
+        justify-content: space-between;
+    }
+    .editor-wrap{
+        margin-top: 15px;
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        background-color: #fff;
+        overflow: hidden;
+        .frame-wrap{
+            flex:1;
+            background-color: #F2F6FA;
+        }
+    }
+    .el-dialog{
+        .dialog-container{
+           .el-form{
+               .el-form-item{
+                   display: flex;
+                   justify-content: center;
+               }
+           }
+        }
+        .dialog-footer{
+            text-align: center;
+            padding-bottom:25px;
+        }
+    }
+}
+</style>

+ 601 - 0
src/views/chartFrame_manage/index.vue

@@ -0,0 +1,601 @@
+<template>
+    <!-- 图库框架 列表页 -->
+    <div class="chart-frame-wrap">
+        <!-- 控制目录栏展开收起-->
+        <span class="slide-icon slide-right" @click="slideHandle" v-show="isSlideLeft">
+            <i class="el-icon-d-arrow-right"></i>
+        </span>
+        <div class="catalog-wrap page-block-wrap" id="catalog-left" v-show="!isSlideLeft">
+            <span class="slide-icon slide-left" @click="slideHandle">
+                <i class="el-icon-d-arrow-left"></i>
+            </span>
+            <span class="move-btn resize" v-drag id="resize"></span>
+            <div class="btn-wrap">
+                <el-button type="primary" @click="$router.push('/addframe')" 
+                v-permission="permissionBtn.chartFramePermission.chartframe_my_editFrame">添加框架</el-button>
+            </div>
+            <div class="search-wrap">
+                <el-select style="width:100%"
+                    filterable remote
+                    placeholder="请输入框架名称"
+                    v-model.trim="searchText"
+                    :remote-method="searchHandle"
+                    value-key="ChartFrameworkId"
+                    clearable
+                    >
+                    <i slot="prefix" class="el-input__icon el-icon-search"></i>
+                    <el-option
+                        v-for="item in searchOptions"
+                        :key="item.ChartFrameworkId"
+                        :label="item.FrameworkName"
+                        :value="item"
+                    />
+                </el-select>
+            </div>
+            <div class="catalog-list">
+                <div class="public-catalog">
+                    <p>公共框架</p>
+                    <div class="catalog-tree">
+                        <el-tree
+                            ref="catalogTree"
+                            class="catalog-tree other-tree"
+                            empty-text="暂无分类"
+                            :data="publicFrameList"
+                            node-key="nodeKeyId"
+                            :expand-on-click-node="false"
+                            @current-change="(data,node)=>{nodeChange(data,node)}"
+                            >
+                            <span class="custom-tree-node" slot-scope="{ data,node }"
+                            >
+                                <span class="tree-label">{{ data.name }}</span>
+                            </span>
+                        </el-tree>
+                    </div>
+                </div>
+                <div class="my-list">
+                    <p>我的框架</p>
+                    <draggable
+                        v-model="myFrameList"
+                        class="classify-ul"
+                        animation="300"
+                        tag="ul"
+                        :disabled="!permissionBtn.isShowBtn('chartFramePermission','chartframe_my_move')"
+                        @start="menuDragStart"
+                        @update="menuDragenter"
+                        @end="menuDragOver"
+                    >
+                        <li class="classify-item" :class="{'active':currentFrame.ChartFrameworkId===item.ChartFrameworkId&&frameType==='my'}"
+                            v-for="item in myFrameList" :key="item.ChartFrameworkId"
+                            @click="chooseFrame(item)"
+                            >
+                            <span v-if="permissionBtn.isShowBtn('chartFramePermission','chartframe_my_move')">
+                                <img src="~@/assets/img/data_m/move_ico.png"
+                                    alt="" class="move"
+                                    style="width: 14px; height: 14px;"
+                                />
+                            </span>
+                            <span class="item-label text_oneLine">{{ item.FrameworkName }}</span>
+                            <el-dropdown style="margin-right: 10px" @command="handleCommand" trigger="click"
+                                v-if="permissionBtn.isShowBtn('chartFramePermission','chartframe_my_show')">
+                                <span class="el-dropdown-link  el-dropdown-link-img">
+                                    <img class="icon" src="~@/assets/img/chart_m/Group.png" v-if="item.IsPublic === 0">
+                                    <img class="icon" src="~@/assets/img/chart_m/User.png" v-else>
+                                </span>
+                                <el-dropdown-menu slot="dropdown">
+                                    <el-dropdown-item 
+                                        :command="{key:'own',value:item}" 
+                                        class="el-dropdown-menu-item-chat"
+                                        >
+                                        <div style="display: flex;align-items: center;">
+                                            <img src="~@/assets/img/chart_m/Group.png">
+                                            <span style="margin-left:5px">仅自己可见</span>
+                                        </div>
+                                    </el-dropdown-item>
+                                    <el-dropdown-item 
+                                        :command="{key:'public',value:item}" 
+                                        class="el-dropdown-menu-item-chat"
+                                        >
+                                        <div style="display: flex;align-items: center;">
+                                            <img src="~@/assets/img/chart_m/User.png">
+                                            <span style="margin-left:5px">所有人可见</span>
+                                        </div>
+                                        
+                                    </el-dropdown-item>
+                                </el-dropdown-menu>
+                            </el-dropdown>
+                            <el-dropdown @command="handleCommand" trigger="click"
+                                v-if="isDropDownShow"
+                            >
+                                <span class="el-dropdown-link"> 
+                                    <i class="el-icon-more" style="font-size: 16px;transform: rotate(90deg);cursor: pointer"/>
+                                </span>
+                                <el-dropdown-menu slot="dropdown">
+                                    <el-dropdown-item v-if="permissionBtn.isShowBtn('chartFramePermission','chartframe_my_rename')"
+                                        :command="{key:'edit'}">重命名</el-dropdown-item>
+                                    <el-dropdown-item v-if="permissionBtn.isShowBtn('chartFramePermission','chartframe_my_delFrame')"
+                                        :command="{key:'del'}">删除</el-dropdown-item>
+                                </el-dropdown-menu>
+                            </el-dropdown>
+                           
+                        </li>
+                    </draggable>
+                </div>
+            </div>
+        </div>
+        <div class="detail-wrap page-block-wrap" id="detail-right">
+            <div class="empty" v-if="!currentFrame.ChartFrameworkId&&currentList.length===0">
+                <tableNoData text="暂无数据"/>
+            </div>
+            <template v-else>
+                <div class="list" v-if="model==='list'">
+                    <div class="list-item" 
+                        v-for="item in currentList" :key="item.nodeKeyId"
+                        @click="nodeChange(item,{level:2})"
+                        >
+                        <div class="item-title text_oneLine">
+                            <span>{{item.name}}</span>
+                        </div>
+                        <div style="height:1px;background:#ECECEC;margin:0 -10px;"></div>
+                        <div class="item-image" 
+                            :style="`background-image:url(${item.FrameworkImg?item.FrameworkImg:require('@/assets/img/document_m/default-img.png')})`"></div>
+                        <div style="height:1px;background:#ECECEC;margin:10px -10px;"></div>
+                        <div class="item-time">
+                            创建时间:{{item.CreateTime}}
+                        </div>
+                    </div>
+                    <div class="empty" v-if="currentList.length===0">
+                        <tableNoData text="暂无数据"/>
+                    </div>
+                </div>
+                <div class="detail" v-else>
+                    <div class="top-info">
+                        <span>更新时间:{{currentFrame.ModifyTime}}</span>
+                        <span class="title text_oneLine">{{currentFrame.FrameworkName}}</span>
+                        <div class="tool">
+                            <el-button type="text" @click="handleOption('edit',currentFrame)" 
+                                v-if="frameType==='my'&&permissionBtn.isShowBtn('chartFramePermission','chartframe_my_editFrame')">编辑</el-button>
+
+                            <el-button type="text" @click="handleOption('copy',currentFrame)" :disabled="!currentFrame.FrameworkContent"
+                                v-if="frameType==='my'&&permissionBtn.isShowBtn('chartFramePermission','chartframe_my_copyImg')">复制图片</el-button>
+                            <el-button type="text" @click="handleOption('copy',currentFrame)" :disabled="!currentFrame.FrameworkContent"
+                                v-if="frameType==='public'&&permissionBtn.isShowBtn('chartFramePermission','chartframe_public_copyImg')">复制图片</el-button>
+
+                            <el-button type="text" @click="handleOption('del',currentFrame)" style="color:red;"
+                                v-if="frameType==='my'&&permissionBtn.isShowBtn('chartFramePermission','chartframe_my_delFrame')">删除</el-button>
+                        </div>
+                    </div>
+                    <div class="frame-wrap">
+                        <!--沙盘图组件-->
+                        <FrameContainer ref="container"
+                            :FrameworkContent="currentFrame.FrameworkContent"
+                            @showDialog="handleShowDialog"/>
+                    </div>
+                </div>
+            </template>
+        </div>
+        <!-- 重命名弹窗 -->
+        <el-dialog
+            title="重命名框架"
+            :visible.sync="isRenameDialogShow"
+            :close-on-click-modal="false"
+            :modal-append-to-body="false"
+            @close="isRenameDialogShow=false"
+            width="589px"
+            v-dialogDrag
+            center
+        >
+            <div class="dialog-container">
+                <div>
+                    <span style="margin-right:5px;">框架名称</span>
+                    <el-input v-model.trim="modifyFrame.FrameworkName" placeholder="请输入框架名称"></el-input>
+                </div>
+            </div>
+            <div class="dialog-footer">
+                <el-button @click="isRenameDialogShow=false">取消</el-button>
+                <el-button type="primary" @click="renameFrame">确定</el-button>
+            </div>
+        </el-dialog>
+        <!-- my eta图表详情弹窗 -->
+        <chartDetail 
+            :isOpenDetail="myETADetailDialogShow"
+            :select_classify="chartClassify"
+            :chart_code="chartCode"
+            :allChart="chartArr"
+            :classifyUserId="classifyUserId"
+            @close="myETADetailDialogShow=false"
+            @remove="removeChart"
+        />
+        <!-- my eta图表复制到弹窗 -->
+        <el-dialog
+            title="复制到我的图库"
+            :visible.sync="isCopyDialogShow"
+            :close-on-click-modal="false"
+            :modal-append-to-body="false"
+            @close="isCopyDialogShow=false"
+            width="589px"
+            v-dialogDrag
+            center
+        >
+            <div class="dialog-container" v-loading="copyDialogLoading">
+                <div>
+                    <span style="margin-right:5px;">复制到</span>
+                    <el-select
+                        v-model="copyToClassify"
+                        placeholder="请选择目录"
+                        style="width: 80%;"
+                        multiple clearable
+                    >
+                        <el-option v-for="item in myETAClassArr"
+                            :key="item.value"
+                            :label="item.name"
+                            :value="item.value"
+                        />
+                    </el-select>
+                </div>
+            </div>
+            <div class="dialog-footer">
+                <el-button @click="isCopyDialogShow=false">取消</el-button>
+                <el-button type="primary" @click="copyToClass">确定</el-button>
+            </div>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+import draggable from 'vuedraggable';
+import FrameContainer from './components/frameContainer.vue';
+import chartDetail from '@/views/mychart_manage/components/chartDetailDia.vue';
+import { mychartInterface,chartFrameInterface } from '@/api/api.js';
+import {copyBlob} from '@/utils/svgToblob.js';
+export default {
+    components:{ draggable, FrameContainer,chartDetail},
+    directives: {//自定义指令调整目录栏宽度
+        drag(el, bindings) {
+            el.onmousedown = function (e) {
+                let init = e.clientX;
+                let left = $('#catalog-left')[0];
+                let initWidth = left.offsetWidth;
+                document.onmousemove = function (e) {
+                let end = e.clientX;
+                let newWidth = end - init + initWidth;
+                left.style.width = newWidth+'px';
+                //reloadFrame()
+                };
+                document.onmouseup = function () {
+                document.onmousemove = document.onmouseup = null;
+                e.releaseCapture && e.releaseCapture();
+                };
+                e.setCapture && e.setCapture();
+                return false;
+            };
+        },
+    },
+    data() {
+        return {
+            isSlideLeft:false,//控制左侧目录栏是否显示
+
+            /* drag 我的框架相关 */
+            dragStartIndex:0,
+            dragFrame:null,
+            prevFrame:null,
+            nextFrame:null,
+
+            /* search */
+            searchText:'',
+            searchOptions:[],
+            
+            /* select frame*/
+            model:'frame',
+            frameType:'my',
+            publicFrameList:[],//公共框架列表
+            currentList:[],//选择公共框架时,框架列表
+            myFrameList:[],//我的框架列表
+            currentFrame:{},//选择的框架
+            /* frame node */
+            myETADetailDialogShow:false,//点击节点时,弹出myeta图表详情弹框
+            modifyFrame:{},//正在修改的框架
+            isRenameDialogShow:false,//重命名弹窗
+            /*my eta 图表详情操作相关 */
+            chartClassify:0,
+            classifyUserId:0,
+            chartCode:'',
+            chartArr:[],
+            isCopyDialogShow:false,
+            myETAClassArr:[],
+            copyToClassify:[],
+            modeId:0,
+            /* 页面loading */
+            lockLoding:null,
+        };
+    },
+    watch:{
+        searchText(newVal){
+            newVal&&this.chooseFrame(newVal)
+        }
+    },
+    computed:{
+        adminId(){
+            return Number(localStorage.getItem('AdminId'))
+        },
+        isDropDownShow(){
+            return this.permissionBtn.isShowBtn('chartFramePermission','chartframe_my_rename')
+                || this.permissionBtn.isShowBtn('chartFramePermission','chartframe_my_delFrame')
+        }
+    },
+    methods: {
+        slideHandle(){
+            this.isSlideLeft = !this.isSlideLeft;
+        },
+        getPublicList(){
+            chartFrameInterface.getPublicFrameList().then(res=>{
+                if(res.Ret!==200) return 
+                this.publicFrameList = res.Data||[]
+                this.publicFrameList = this.publicFrameList.map(list=>{
+                    list.name = list.MenuName
+                    list.nodeKeyId = 'list'+list.AdminId
+                    if(list.Frameworks){
+                        list.children = list.Frameworks.map(item=>{
+                            return {
+                                ...item,
+                                ...{
+                                    nodeKeyId:'item'+item.ChartFrameworkId,
+                                    name:item.FrameworkName
+                                }
+                            }
+                        })
+                    }
+                    return list
+                })
+            })
+        },
+        async getMyList(type){
+            const res = await chartFrameInterface.getMyFrameList({AdminId:this.adminId})
+            if(res.Ret!==200) return 
+            this.myFrameList = res.Data||[]
+            if(type!=='init') return 
+            //如果是其他页面跳转来的
+            if(this.$route.query.frameId){
+                this.currentFrame = this.myFrameList.find(i=>i.ChartFrameworkId===Number(this.$route.query.frameId))||{}
+            }else{
+                //否则选择myFrameList的第一个
+                this.currentFrame = this.myFrameList[0]||{}
+            }
+            this.handleInitGraph()
+        },
+        searchHandle(keyword){
+            chartFrameInterface.getMyFrameList({
+                AdminId:this.adminId,
+                Keyword:keyword,
+            }).then(res=>{
+                if(res.Ret!==200) return
+                this.searchOptions = res.Data||[]
+            })
+        },
+        nodeChange(data,node){
+            this.frameType = 'public'
+            this.changeModel(node.level===2?'frame':'list',data)
+            this.$nextTick(()=>{
+                this.$refs.catalogTree.setCurrentKey(data.nodeKeyId)
+            })
+        },
+        changeModel(type,data){
+            if(type==='frame'&&data.ChartFrameworkId===this.currentFrame.ChartFrameworkId) return 
+            this.model = type
+            //销毁画布
+            this.$refs.container&&this.$refs.container.dispose()
+            if(type==='frame'){
+                this.currentFrame = data
+                this.handleInitGraph()
+            }else{
+                this.currentList = data.children||[]
+                this.currentFrame={}
+            }
+        },
+        handleInitGraph(){
+            //判断一下框架内容是否是合法的JSON,否则置为空
+            try{
+                JSON.parse(this.currentFrame.FrameworkContent)
+            }catch(e){
+                this.currentFrame.FrameworkContent = ''
+            }
+            this.$nextTick(()=>{
+                //若框架有内容,才加载画布
+                this.currentFrame.FrameworkContent&&this.$refs.container.init()
+            })
+        },
+        /* 拖动相关 */
+        menuDragStart({oldIndex}){
+            this.dragStartIndex = oldIndex
+            this.dragFrame = this.myFrameList[oldIndex]
+        },
+        menuDragenter({newIndex}){
+            //置顶
+            if(newIndex===0){
+                this.prevFrame=null
+                this.nextFrame=this.myFrameList[newIndex+1]
+            }
+            //置底
+            if(newIndex===this.myFrameList.length-1){
+                this.prevFrame = this.myFrameList[newIndex-1]
+                this.nextFrame = null
+            }
+            if(newIndex!==0&&newIndex!==this.myFrameList.length-1){
+                this.prevFrame = this.myFrameList[newIndex-1]
+                this.nextFrame = this.myFrameList[newIndex+1]
+            }
+        },
+        menuDragOver({newIndex}){
+            if(newIndex===this.drageStartIndex) return
+            if(!this.dragFrame) return
+            chartFrameInterface.moveFrame({
+                ChartFrameworkId:this.dragFrame.ChartFrameworkId,
+                PrevChartFrameworkId:this.prevFrame?this.prevFrame.ChartFrameworkId:0,
+                NextChartFrameworkId:this.nextFrame?this.nextFrame.ChartFrameworkId:0,
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                this.$message.success("移动成功")
+                this.getMyList()
+            })
+        },
+        /*下拉框 */
+        handleCommand(command){
+            if(command.key==='edit'){
+                this.modifyFrame = _.cloneDeep(this.currentFrame)
+                this.isRenameDialogShow = true
+            }
+            if(command.key==='del'){
+                this.deleteFrame(this.currentFrame)
+            }
+            if(['own','public'].includes(command.key)){
+                chartFrameInterface.changePublicFrame({
+                    ChartFrameworkId:command.value.ChartFrameworkId,
+                    IsPublic:command.key==='own'?0:1
+                }).then(res=>{
+                    if(res.Ret!==200) return
+                    this.getPublicList()
+                    this.getMyList()
+                    this.$message.success(`操作成功`)
+                })
+            }
+        },
+        //选择我的框架
+        chooseFrame(item){
+            this.frameType = 'my'
+            this.changeModel('frame',item)
+            this.$nextTick(()=>{
+                this.$refs.catalogTree.setCurrentKey(null)
+            })
+        },
+        /* 框架操作相关 */
+        handleOption(type,data){
+            const optionMap = {
+                'edit':this.handleEditFrame,
+                'copy':this.copyFrameImg,
+                'del':this.deleteFrame,
+            }
+            optionMap[type](data)
+        },
+        handleEditFrame(data){
+            this.$router.push({path:'/editframe',query:{frameId:data.ChartFrameworkId}})
+        },
+        copyFrameImg(data){
+            this.lockLoding = this.$loading({
+                lock: true,
+                text: '复制图片中...',
+                target: '.frame-container-wrap',
+                spinner: 'el-icon-loading',
+                background: 'rgba(255, 255, 255, 0.8)'
+            });
+            const svgData = this.$refs.container.getContentPic()
+            copyBlob(svgData,()=>{
+                this.lockLoding && this.lockLoding.close();
+            },1,'svg')
+        },
+        deleteFrame(data){
+            this.$confirm("删除后不可恢复,确认删除吗?","提示",{
+                confirmButtonText:"确定",
+                cancelButtonText:"取消",
+                type:"warning"
+            }).then(()=>{
+                chartFrameInterface.deleteFrame({
+                    ChartFrameworkId:data.ChartFrameworkId
+                }).then(res=>{
+                    if(res.Ret!==200) return
+                    this.$message.success("删除成功")
+                    this.getPublicList()
+                    this.getMyList()
+                    this.currentFrame = {}
+                })
+            }).catch(()=>{})
+        },
+        renameFrame(){
+            if(!this.modifyFrame.FrameworkName.length){
+                this.$message.warning("请输入框架名称")
+                return
+            }
+            chartFrameInterface.reNameFrame({
+                ChartFrameworkId:this.modifyFrame.ChartFrameworkId,
+                FrameworkName:this.modifyFrame.FrameworkName
+            }).then(async res=>{
+                if(res.Ret!==200) return
+                this.getPublicList()
+                await this.getMyList()
+                this.currentFrame = this.myFrameList.find(item=>item.ChartFrameworkId===this.modifyFrame.ChartFrameworkId)||{}
+                this.$message.success("编辑成功")
+                this.isRenameDialogShow = false
+            })
+            
+        },
+        //点击框架内节点
+        handleShowDialog({id,nodeLink}){
+            //请求接口看有没有数据
+            mychartInterface.myList({
+                PageSize:1200,
+                CurrentIndex:1,
+                MyChartClassifyId: Number(id),
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                if(res.Data&&res.Data.List){
+                    if(res.Data.List.length){
+                        this.chartClassify = id
+                        this.classifyUserId = nodeLink.AdminId||0
+                        this.chartCode = res.Data.List[0].UniqueCode
+                        this.chartArr = res.Data.List.map(item => item.UniqueCode)
+                        this.myETADetailDialogShow = true
+                    }
+                }else{
+                    this.$message.warning('该节点链接的图库没有图表')
+                }
+            })
+        },
+        //打开复制到弹窗
+        async moveMychart(id) {
+            this.isCopyDialogShow = true
+            this.copyDialogLoading = true
+            this.modeId = id
+            //获取当前图表所属分类
+            const { Data : chartClassifyList=[]} = await mychartInterface.getChartInClassify({ChartInfoId: id })
+            //获取myETA全部分类
+            const {Data} = await mychartInterface.classifyList()
+            const classifyListData = Data?Data.List.map(item=>{
+                return {...item,fromPublic: 0}
+            }):[]
+            //过滤掉所属分类
+            this.myETAClassArr = classifyListData
+                .map((item) => ({
+                name: item.MyChartClassifyName,
+                value: item.MyChartClassifyId,
+                }))
+                .filter((x) => !chartClassifyList.includes(x.value))
+            this.copyDialogLoading = false
+        },
+        //将图表复制到其他目录
+        copyToClass(){
+            mychartInterface.copyMyChart({
+                ChartInfoId: this.modeId,
+                MyChartClassifyId: this.copyToClassify,
+            })
+            .then((res) => {
+                if (res.Ret !== 200) return;
+                this.$message.success('复制成功');
+                this.isCopyDialogShow = false;
+            });
+        },
+        //弹窗中移除了图表,对chartArr做对应改动
+        removeChart(UniqueCode){
+            this.chartArr.splice(this.chartArr.findIndex(item => item === UniqueCode), 1)
+        }
+    },
+    mounted(){
+        this.getPublicList()
+        this.getMyList('init')
+    }
+};
+</script>
+
+<style lang="scss">
+@import "./css/customTree.scss";
+</style>
+<style scoped lang="scss">
+@import "./css/basePage.scss";
+</style>

+ 73 - 0
src/views/chartRelevance_manage/components/explainDialog.vue

@@ -0,0 +1,73 @@
+<template>
+    <el-dialog custom-class="explain-dialog-wrap"
+        :visible.sync="showExplain"
+        :close-on-click-modal="false"
+        :append-to-body="true"
+        center
+        width="976px"
+        v-dialogDrag
+        top="8vh"
+        title="操作说明"
+        @close="$emit('close')"
+    >
+        <div class="dialog-container">
+            <div class="explain-text" v-for="text,index in textArray" :key="index" v-html="text">
+            </div>
+        </div>
+        <div class="dialog-btn">
+            <el-button type="primary" @click="$emit('close')">知道了</el-button>
+        </div>
+        
+    </el-dialog>
+</template>
+
+<script>
+import * as explainText from './explainText'
+export default {
+    props:{
+        showExplain:{
+            type:Boolean,
+            default:false
+        },
+        textArrName:{
+            type:String,
+            default:'chartrelevanceTextArr'
+        }
+    },
+    computed:{
+        textArray(){
+            return explainText[this.textArrName]
+        }
+    },
+    data() {
+        return {
+
+        };
+    },
+    methods: {
+
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.explain-dialog-wrap{
+    .dialog-container{
+        .explain-text{
+            font-size: 16px;
+            padding-bottom: 20px;
+            &:not(:last-child){
+                border-bottom:1px solid #D9D9D9;
+            }
+            &:not(:first-child){
+                padding-top: 20px;
+            }
+        }
+    }
+    .dialog-btn{
+        margin-top: 25px;
+        padding-bottom: 25px;
+        text-align: center;
+    }
+}
+</style>

+ 38 - 0
src/views/chartRelevance_manage/components/explainText.js

@@ -0,0 +1,38 @@
+//相关性分析
+export const chartrelevanceTextArr = [
+    `<p style='font-weight:bold;'>相关性计算处理逻辑:</p>
+    <p>1、取数:取计算窗口的时间长度,从当前时间往前推移对应的时间长度,取该日期区间,指标A序列值和指标B序列值;</p>
+    <p>2、变频:根据指标A和指标B的频度对取出的数据序列做如下处理</p>
+    <p>①指标A高频,对指标B升频(线性方程插值法补全数据);</p>
+    <p>②指标B高频,对指标A升频(线性方程插值法补全数据);</p>
+    <p>③指标A,指标B同频,不作处理;</p>
+    <p>3、计算:按照分析周期,以指标A为基准,对指标B作对应期数的位移,根据公式相关系数R = SUM[(Xi-Mx)*(Yi-My)]/[(N-1)(SDx*SDy)],计算每个期数对应的相关性;</p>
+    <p style='height:20px;'></p>
+    <p>注:指标B作位移时,若以指标A的日期序列未找到指标B的值,则往前找最近值进行计算(往前找的范围为当前日期往前推移计算窗口的时间范围)</p>`,
+    `<p style='font-weight:bold;'>相关性配置:</p>
+    <p>1、计算窗口:参与计算的历史数据时间段;</p>
+    <p>2、分析周期:指标B领先A的期数,如配置参数10个月,表示B领先A -10月、B领先A -9月,...,B领先A 9月、B领先A 10月,每期分别计算相关性值;</p>`,
+    `<p style='font-weight:bold;'>滚动相关性配置:</p>
+    <p>1、计算窗口:参与计算的时间段长度,从两个指标都有值的日期开始滚动的取计算窗口长度的值进行计算,如配置计算窗口1个月,则2023.7.28的值取2023.6.28~2023.7.28时间段,2023.7.27的值取2023.6.27~2023.7.27时间段;</p>
+    <p>2、B领先A:B指标领先A指标的参数,为0时不领先;</p>`
+]
+
+//拟合方程曲线
+export const fittingEquationListTextArr = [
+    `<p style='font-weight:bold;'>拟合方程曲线处理逻辑:</p>
+    <p>1、选择两组有相关性的指标</p>
+    <p>2、对两组在选定时间范围内的每一个时间节点,生成拟合方程Y=aX+b以及相关系数R²</p>
+    <p>3、分别画出弹性系数a,截距b,相关系数R²,在选定时间范围内的曲线图</p>`,
+]
+
+export const statisticFeatureListTextArr = [
+    `<p style='font-weight:bold;'>标准差处理逻辑:</p>
+    <p>计算所选时间范围内数据的样本标准差s,s=sqrt(((x1-x)^2 (x2-x)^2 ......(xn-x)^2)/(n-1)),n表示数据个数</p>`,
+    `<p style='font-weight:bold;'>百分位处理逻辑:</p>
+    <p>对所选时间范围内的数据,取最大值Max,最小值Min,计算Max-Min,百分位=(现值-Min)/(Max-Min),Max=Min时不计算</p>`,
+    `<p style='font-weight:bold;'>频率分布处理逻辑:</p>
+    <p>1、在所选时间范围内,取最大值和最小值;</p>
+    <p>2、根据频段数划分多个间距相同的区间(左闭右开,最后一个区间为左闭右闭),统计数据值落在每个区间的数据个数;</p>
+    <p>3、频率=落在某区间数据个数/所选时间段内数据总个数;</p>
+    <p>4、累计频率为从最小值所在区间对应的频率开始累加;</p>`
+]

+ 4 - 3
src/views/chartRelevance_manage/components/saveEdbToBaseDia.vue

@@ -125,7 +125,8 @@ export default {
 				label: 'ClassifyName',
 				value: 'ClassifyId',
 				children: 'Children',
-				emitPath: false
+				emitPath: false,
+				checkStrictly: true
 			},
 			frequencyArr:['日度','周度','旬度','月度','季度','年度'],
 		};
@@ -144,13 +145,13 @@ export default {
 				if(res.Ret !== 200) return
 				//this.filterNodes(res.Data.AllNodes,2);
 			}
-
+			this.filterNodes(res.Data.AllNodes||[]);
 			this.options = res.Data.AllNodes || [];
 		},
 		filterNodes(arr,n) {
 			arr.length && arr.forEach(item => {
 				item.Children && item.Children.length && this.filterNodes(item.Children,n)
-				if(item.Level === n) {
+				if(!item.Children.length) {
 					delete item.Children
 				}
 			})

+ 20 - 4
src/views/chartRelevance_manage/fittingEquationChartEditor.vue

@@ -14,7 +14,7 @@
 					path: '/fittingEquationList',
 					query: $route.query
 				})">取消</el-button>
-				<span style="color: #666;">
+				<!-- <span style="color: #666;">
 						使用说明
 					<el-tooltip
 						effect="dark"
@@ -26,7 +26,11 @@
 						></div>
 						<i class="el-icon-question" />
 					</el-tooltip>
-				</span>
+				</span> -->
+				<div style="color:#409EFF;font-size: 16px;cursor: pointer;" @click="showExplain = true">
+					<i class="el-icon-document" style="font-size:22px;"></i>
+					操作说明
+				</div>
       </div>
 			<div class="left-min">
 				<div class="section-item">
@@ -155,6 +159,12 @@
       :isShow.sync="isSaveDialog"
 			:initData="leftOption.ChartMappingList"
 			@saveBack="editChartBackHandle"
+    />
+	<!-- 操作说明 -->
+    <ExplainDialog 
+        textArrName="fittingEquationListTextArr"
+        :show-explain="showExplain"
+        @close="showExplain = false"
     />
 
   </div>
@@ -167,8 +177,9 @@ import Chart from '@/views/dataEntry_manage/components/chart';
 import selectTarget from './components/selectTarget.vue';
 import fittingEquationSaveDia from './components/fittingEquationSaveDia.vue';
 import chartCard from './components/chartCard.vue';
+import ExplainDialog from './components/explainDialog.vue';
 export default {
-  components: { Chart,selectTarget,fittingEquationSaveDia,chartCard },
+  components: { Chart,selectTarget,fittingEquationSaveDia,chartCard,ExplainDialog },
 	directives: {
     drag(el, bindings) {
       el.onmousedown = function (e) {
@@ -236,7 +247,9 @@ export default {
 
 			useTip:`1、选择两组有相关性的指标<br>
 					2、对两组在选定时间范围内的每一个时间节点,生成拟合方程Y=aX+b以及相关系数R²<br>
-					3、分别画出弹性系数a,截距b,相关系数R²,在选定时间范围内的曲线图`
+					3、分别画出弹性系数a,截距b,相关系数R²,在选定时间范围内的曲线图`,
+			//操作说明弹窗
+			showExplain:false
 
     };
   },
@@ -417,6 +430,9 @@ export default {
       padding: 15px 20px;
       border: 1px solid #ececec;
       box-shadow: 0px 3px 6px rgba(167, 167, 167, 0.09);
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
     }
 		.left-min {
 			padding: 30px 20px;

+ 2 - 2
src/views/chartRelevance_manage/fittingEquationList.vue

@@ -13,7 +13,7 @@
 				<div class="datasheet_top">
 						<el-button v-permission="permissionBtn.statisticPermission.fittingEq_addChart"
 							type="primary" @click="goAddChart">添加图表</el-button>
-						<div style="color: #666">
+						<!-- <div style="color: #666">
 							 使用说明
 							<el-tooltip
 								effect="dark"
@@ -25,7 +25,7 @@
 								></div>
 								<i class="el-icon-question" />
 							</el-tooltip>
-						</div>
+						</div> -->
 				</div>
 
 				<div class="search-cont">

+ 21 - 6
src/views/chartRelevance_manage/relevanceChartEditor.vue

@@ -10,6 +10,10 @@
     <div class="left-cont" v-show="!isSlideLeft" id="left">
       <div class="left-top">
         <el-button type="primary" plain @click="$router.back()">取消</el-button>
+        <div style="color:#409EFF;font-size: 16px;cursor: pointer;" @click="showExplain = true">
+            <i class="el-icon-document" style="font-size:22px;"></i>
+            操作说明
+        </div>
       </div>
       <div class="left-min">
         <el-form
@@ -148,7 +152,7 @@
 
         <div class="section">
           <div>相关性
-            <el-tooltip
+            <!-- <el-tooltip
               effect="dark"
             >
               <div
@@ -157,7 +161,7 @@
                 style="line-height: 20px;width:350px"
               ></div>
               <i class="el-icon-question" style="color:#666"/>
-            </el-tooltip>
+            </el-tooltip> -->
           </div>
           <div class="section-item">
             <div style="flex-shrink:0;min-width:70px"><span style="color:red;font-size:18px;">*</span>计算窗口</div>
@@ -208,7 +212,7 @@
 
       <div class="section" v-for="(item,index) in chartInfo.RollingCorrelation" :key="index">
         <div>滚动相关性{{index+1}}
-          <el-tooltip
+          <!-- <el-tooltip
             effect="dark"
           >
             <div
@@ -217,7 +221,7 @@
               style="line-height: 20px;width:350px"
             ></div>
             <i class="el-icon-question" style="color:#666"/>
-          </el-tooltip>
+          </el-tooltip> -->
         </div>
         <div class="section-item">
           <span style="flex-shrink:0;min-width:70px">计算窗口</span>
@@ -357,6 +361,11 @@
       :chartData="chartData"
       @saveBack="saveEdbBack"
     />
+    <!-- 操作说明 -->
+    <ExplainDialog 
+        :show-explain="showExplain"
+        @close="showExplain = false"
+    />
   </div>
 </template>
 
@@ -370,8 +379,9 @@ import chartCard from './components/chartCard.vue';
 import SaveChartOther from '@/views/dataEntry_manage/components/SaveChartOther';
 import saveChartToBase from './components/saveChartTobaseDia.vue';
 import saveEdbToBase from './components/saveEdbToBaseDia.vue'
+import ExplainDialog from './components/explainDialog.vue';
 export default {
-  components: { selectTarget,chartCard,SaveChartOther,saveChartToBase,saveEdbToBase },
+  components: { selectTarget, chartCard, SaveChartOther, saveChartToBase, saveEdbToBase, ExplainDialog },
   directives: {
     drag(el, bindings) {
       el.onmousedown = function (e) {
@@ -506,7 +516,9 @@ export default {
           分析周期:指标B领先A的期数,如配置参数10个月,表示B领先A -10月、B领先A -9月,...,B领先A 9月、B领先A 10月,每期分别计算相关性值;`,
         rollingCorrelation:`计算窗口:参与计算的时间段长度,从两个指标都有值的日期开始滚动的取计算窗口长度的值进行计算,如配置计算窗口1个月,则2023.7.28的值取2023.6.28~2023.7.28时间段,2023.7.27的值取2023.6.27~2023.7.27时间段;<br>
         B领先A:B指标领先A指标的参数,为0时不领先;`
-      }
+      },
+      /* 操作说明弹窗 */
+      showExplain:false
 
     };
   },
@@ -813,6 +825,9 @@ export default {
       padding: 15px 20px;
       border-bottom: 1px solid #ececec;
       box-shadow: 0px 3px 6px rgba(167, 167, 167, 0.09);
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
     }
     .left-min {
       padding: 20px;

+ 24 - 8
src/views/chartRelevance_manage/statisticFeatureChartEditor.vue

@@ -10,6 +10,10 @@
     <div class="left-cont" v-show="!isSlideLeft" id="left">
       <div class="left-top">
         <el-button type="primary" plain @click="$router.back()">取消</el-button>
+        <div style="color:#409EFF;font-size: 16px;cursor: pointer;" @click="showExplain = true">
+            <i class="el-icon-document" style="font-size:22px;"></i>
+            操作说明
+        </div>
       </div>
       <div class="left-min">
         <div class="search-cont">
@@ -72,14 +76,14 @@
 
         <div class="section">
           <div>标准差
-            <el-tooltip effect="dark" placement="right">
+            <!-- <el-tooltip effect="dark" placement="right">
               <div
                 slot="content"
                 v-html="ruleTips.StandardDeviation"
                 style="line-height: 20px;width:300px"
               ></div>
               <i class="el-icon-question" style="color: #666" />
-            </el-tooltip>
+            </el-tooltip> -->
           </div>
           <div class="section-item">
             <div>滚动期数:</div>
@@ -95,14 +99,14 @@
 
         <div class="section">
           <div>百分位
-            <el-tooltip effect="dark" placement="right">
+            <!-- <el-tooltip effect="dark" placement="right">
               <div
                 slot="content"
                 v-html="ruleTips.Percentile"
                 style="line-height: 20px;width:300px"
               ></div>
               <i class="el-icon-question" style="color: #666" />
-            </el-tooltip>
+            </el-tooltip> -->
           </div>
           <div class="section-item">
             <span style="flex-shrink:0;min-width:70px">时间长度:</span>
@@ -130,14 +134,14 @@
 
         <div class="section">
           <div>频率分布
-            <el-tooltip effect="dark" placement="right">
+            <!-- <el-tooltip effect="dark" placement="right">
               <div
                 slot="content"
                 v-html="ruleTips.FrequencyDistribution"
                 style="line-height: 20px;width:300px"
               ></div>
               <i class="el-icon-question" style="color: #666" />
-            </el-tooltip>
+            </el-tooltip> -->
           </div>
           <div class="section-item">
             <span style="flex-shrink:0;min-width:70px">时间段:</span>
@@ -271,6 +275,12 @@
       :chartData="chartData"
       @saveBack="saveEdbBack"
     />
+    <!-- 操作说明 -->
+    <ExplainDialog 
+        textArrName="statisticFeatureListTextArr"
+        :show-explain="showExplain"
+        @close="showExplain = false"
+    />
   </div>
 </template>
 
@@ -283,9 +293,10 @@ import selectTarget from './components/selectTarget.vue'
 import chartCard from './components/chartCard.vue';
 import SaveChartOther from '@/views/dataEntry_manage/components/SaveChartOther';
 import saveChartToBase from './components/saveChartTobaseDia.vue';
-import saveEdbToBase from './components/saveEdbToBaseDia.vue'
+import saveEdbToBase from './components/saveEdbToBaseDia.vue';
+import ExplainDialog from './components/explainDialog.vue';
 export default {
-  components: { selectTarget,chartCard,SaveChartOther,saveChartToBase,saveEdbToBase },
+  components: { selectTarget,chartCard,SaveChartOther,saveChartToBase,saveEdbToBase,ExplainDialog },
   directives: {
     drag(el, bindings) {
       el.onmousedown = function (e) {
@@ -393,6 +404,8 @@ export default {
       isSaveEdbToBase: false,
 
       oldEdbInfoType: 0,//原指标来源
+      //操作说明弹窗
+      showExplain:false
     };
   },
   methods: {
@@ -672,6 +685,9 @@ export default {
       padding: 15px 20px;
       border-bottom: 1px solid #ececec;
       box-shadow: 0px 3px 6px rgba(167, 167, 167, 0.09);
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
     }
     .left-min {
       padding: 20px;

+ 106 - 88
src/views/classify_manage/classifyEnlist.vue

@@ -23,7 +23,7 @@
         </el-input>
         </div>
       </div>
-      <div class="tabs-box" :style="authTabsOpt.length>1?'':'border:none'"
+      <!-- <div class="tabs-box" :style="authTabsOpt.length>1?'':'border:none'"
         v-if="authTabsOpt.length">
         <span 
           v-for="item in authTabsOpt" 
@@ -31,10 +31,10 @@
           :class="item.val==aTab?'active':''"
           @click="handleTabChange(item)"
         >{{item.name}}</span>
-      </div>
+      </div> -->
 
+      <!-- v-if="authTabsOpt.length" -->
       <el-table
-        v-if="authTabsOpt.length"
         :data="tableData"
         v-loading="dataLoading"
         row-class-name="tableRowClassName"
@@ -42,7 +42,7 @@
         :default-expand-all="isexpand"
         row-key="Id"
         style="border: 1px solid #dcdfe6"
-        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+        :tree-props="{ children: 'Child', hasChildren: 'hasChildren' }"
       >
         <el-table-column
           v-for="item in tableColums"
@@ -54,21 +54,24 @@
           :align="item.align || 'left'"
           :default-expand-all="isexpand"
           row-key="Id"
-          :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+          :tree-props="{ children: 'Child', hasChildren: 'hasChildren' }"
         >
           <template slot-scope="{ row }">
             <span v-if="item.prop === 'ClassifyOne'">{{
-              row.ischild ? "" : row.ClassifyName
+              row.level==1 ? row.ClassifyName : "" 
             }}</span>
             <span v-else-if="item.prop === 'ClassifyTwo'">{{
-              row.ischild ? row.ClassifyName : ""
+              row.level==2 ? row.ClassifyName : ""
+            }}</span>
+           <span v-else-if="item.prop === 'ClassifyThree'">{{
+              row.level==3 ? row.ClassifyName : ""
             }}</span>
 
             <div v-else-if="item.prop === 'handle'">
               <span 
                 
                 class="editsty"
-                v-if="row.ischild&&isAuthSetBtnShow" 
+                v-if="row.level==3&&isAuthSetBtnShow" 
                 @click="handleShowSetVariety(row)"
               >权限配置</span>
               <span class="editsty" v-if="isEditBtnShow"
@@ -107,7 +110,7 @@
           label-position="left"
           hide-required-asterisk
           label-width="80px">
-          <el-form-item prop="type" label="所属模块">
+          <!-- <el-form-item prop="type" label="所属模块">
             <el-select 
               v-model="classifyForm.type"
               placeholder="请选择所属模块"
@@ -119,7 +122,7 @@
             <el-option v-for="item in authTabsOpt" :key="item.val" :label="item.name" :value="item.val"/>
             </el-select>
 
-          </el-form-item>
+          </el-form-item> -->
           <el-form-item prop="classify_name" label="分类名称">
             <el-input 
               type="text" 
@@ -130,7 +133,7 @@
             />
           </el-form-item>
           <el-form-item prop="parent_id" label="上级分类">
-            <el-select 
+            <!-- <el-select 
               v-model="classifyForm.parent_id"
               placeholder="请选择"
               size="small"
@@ -138,7 +141,9 @@
             >
               <el-option label="无" :value="0"/>
               <el-option v-for="item in classifyparentArr" :key="item.ClassifyName" :label="item.ClassifyName" :value="item.Id"/>
-            </el-select>
+            </el-select> -->
+            <el-cascader :options="classifyparentArr" v-model="classifyForm.parent_id" placeholder="请选择"
+            :props="{value:'Id',label:'ClassifyName',children:'Child',checkStrictly:true,emitPath:false}" style="min-width:400px;"></el-cascader>
           </el-form-item>
           <el-form-item label="后台排序" prop="sort">
             <el-input 
@@ -200,72 +205,71 @@ export default {
   computed:{
       //添加分类是否展示
       isAddClassifyBtnShow(){
-          if(this.aTab===0&&this.authTabsOpt.length){
+          // if(this.aTab===0&&this.authTabsOpt.length){
               return this.permissionBtn.checkPermissionBtn(
                   this.permissionBtn.enClassifyBtn.classifyList_enClassify_rpAddClassify
                 )
-          }
-          if(this.aTab===1&&this.authTabsOpt.length){
-            return this.permissionBtn.checkPermissionBtn(
-                  this.permissionBtn.enClassifyBtn.classifyList_enClassify_rsAddClassify
-                )
-          }
-        return false
+          // }
+          // if(this.aTab===1&&this.authTabsOpt.length){
+          //   return this.permissionBtn.checkPermissionBtn(
+          //         this.permissionBtn.enClassifyBtn.classifyList_enClassify_rsAddClassify
+          //       )
+          // }
       },
       //编辑是否展示
       isEditBtnShow(){
-        if(this.aTab===0){
+        // if(this.aTab===0){
                 return this.permissionBtn.checkPermissionBtn(
                     this.permissionBtn.enClassifyBtn.classifyList_enClassify_rpEdit
                 )
-            }else{
-            return this.permissionBtn.checkPermissionBtn(
-                    this.permissionBtn.enClassifyBtn.classifyList_enClassify_rsEdit
-                )
-            }
+            // }else{
+            // return this.permissionBtn.checkPermissionBtn(
+            //         this.permissionBtn.enClassifyBtn.classifyList_enClassify_rsEdit
+            //     )
+            // }
       },
       //删除是否展示
       isDeleteBtnShow(){
-        if(this.aTab===0){
+        // if(this.aTab===0){
                 return this.permissionBtn.checkPermissionBtn(
                     this.permissionBtn.enClassifyBtn.classifyList_enClassify_rpDel
                 )
-            }else{
-            return this.permissionBtn.checkPermissionBtn(
-                    this.permissionBtn.enClassifyBtn.classifyList_enClassify_rsDel
-                )
-            }
+            // }else{
+            // return this.permissionBtn.checkPermissionBtn(
+            //         this.permissionBtn.enClassifyBtn.classifyList_enClassify_rsDel
+            //     )
+            // }
       },
       //权限设置是否展示
       isAuthSetBtnShow(){
-        if(this.aTab===0){
+        // if(this.aTab===0){
                 return this.permissionBtn.checkPermissionBtn(
                     this.permissionBtn.enClassifyBtn.classifyList_enClassify_rpAuthSetting
                 )
-            }else{
-            return this.permissionBtn.checkPermissionBtn(
-                    this.permissionBtn.enClassifyBtn.classifyList_enClassify_rsAuthSetting
-                )
-            }
-      },
-      //英文研报、线上路演选项卡
-      authTabsOpt(){
-        const isShowTabRoadshow = this.permissionBtn.checkPermissionBtn(
-            this.permissionBtn.enClassifyBtn.classifyList_enClassify_roadshow
-        )
-        const isShowTabReport = this.permissionBtn.checkPermissionBtn(
-            this.permissionBtn.enClassifyBtn.classifyList_enClassify_report
-        )
-        //没时间写更好的写法了,有空再优化
-        let authTabs = []
-        if(isShowTabReport){
-            authTabs.push(this.tabsOpt[0])
-        }
-        if(isShowTabRoadshow){
-            authTabs.push(this.tabsOpt[1])
-        }
-        return authTabs
+            // }else{
+            // return this.permissionBtn.checkPermissionBtn(
+            //         this.permissionBtn.enClassifyBtn.classifyList_enClassify_rsAuthSetting
+            //     )
+            // }
       },
+      //英文研报、线上路演选项卡 - ETA1.1.7 不区分英文研报和线上路演,统一用英文研报的 按钮标识
+      // authTabsOpt(){
+      //   const isShowTabRoadshow = this.permissionBtn.checkPermissionBtn(
+      //       this.permissionBtn.enClassifyBtn.classifyList_enClassify_roadshow
+      //   )
+      //   const isShowTabReport = this.permissionBtn.checkPermissionBtn(
+      //       this.permissionBtn.enClassifyBtn.classifyList_enClassify_report
+      //   )
+      //   //没时间写更好的写法了,有空再优化
+      //   let authTabs = []
+      //   if(isShowTabReport){
+      //       authTabs.push(this.tabsOpt[0])
+      //   }
+      //   if(isShowTabRoadshow){
+      //       authTabs.push(this.tabsOpt[1])
+      //   }
+      //   return authTabs
+      // },
       //添加分类时的选项框
   },
   data() {
@@ -287,6 +291,10 @@ export default {
           label: "二级分类",
           prop: "ClassifyTwo",
         },
+        {
+          label: "三级分类",
+          prop: "ClassifyThree",
+        },
         {
           label: "操作",
           prop: "handle",
@@ -299,7 +307,7 @@ export default {
         title: '',
         show: false,
         classify_name: '',
-        parent_id: 0,
+        parent_id: "0", // 数字的0,级联选择器不回显
         sort: 1,
         classify_id: '',
 
@@ -309,7 +317,7 @@ export default {
         classify_name: [{ required:true,message:'请输入分类名称',trigger:'blur'}],
         parent_id: [{ required:true,message:'请输入',trigger:'blur'}],
         sort: [{ required:true,message:'请输入数字',trigger:'blur'}],
-        type: [{ required:true,message:'请选择',trigger:'change'}]
+        // type: [{ required:true,message:'请选择',trigger:'change'}]
       },
 
       tabsOpt:[
@@ -362,7 +370,7 @@ export default {
         CurrentIndex: this.page_no,
         PageSize: 15,
         KeyWord: this.searchform.key_word,
-        ClassifyType:this.aTab
+        // ClassifyType:this.aTab
       };
       classifyEnInterface.classifyList(params).then(res => {
         this.dataLoading = false;
@@ -370,25 +378,30 @@ export default {
           this.tableData = res.Data.List || [];
           this.total = parseInt(res.Data.Paging.Totals);
           this.tableData.forEach((item, index) => {
+            item.level = 1
             if (item.Child) {
               // item.hasChildren=true;
-              let childnode = JSON.parse(JSON.stringify(item.Child));
-              childnode.forEach((itemchild, i) => {
-                itemchild.ischild = true;
+              // let childnode = JSON.parse(JSON.stringify(item.Child));
+              item.Child.forEach((itemchild, i) => {
+                itemchild.level = 2;
+                itemchild.Child && itemchild.Child.forEach((itemChildTwo,i)=>{
+                  itemChildTwo.level=3
+                })
               });
-              item.children = childnode;
+              // item.children = childnode;
             }
           });
+          console.log(this.tableData,'this.tableData');
         }
       });
     },
 
-    addClassify() {
+    addClassify() {      
       this.classifyForm = {
         title: '新增英文分类',
         show: true,
         classify_name: '',
-        parent_id: 0,
+        parent_id: "0",
         sort: 1,
         type:0
       }
@@ -396,16 +409,13 @@ export default {
 
     /* 获取一级分类 */
     getClassifyOne() {
-      classifyEnInterface.classifyOne({ CurrentIndex: 1, PageSize: 9999,ClassifyType:this.classifyForm.type })
+      classifyEnInterface.classifyOne({ CurrentIndex: 1, PageSize: 9999 /**,ClassifyType:this.classifyForm.type */ })
         .then(res => {
           if(res.Ret !== 200) return
 
-          this.classifyparentArr=[];
-					res.Data.List && res.Data.List.forEach((item,i)=>{
-							item.Id=parseInt(item.Id);
+          this.classifyparentArr=res.Data.List || [];
 
-							if(!item.Child) this.classifyparentArr.push(item);
-					});
+          this.classifyparentArr.unshift({Id:"0",ClassifyName:'无',Child:null})
         })
     },
 
@@ -424,7 +434,7 @@ export default {
         title: '编辑分类',
         show: true,
         classify_name: ClassifyName,
-        parent_id: ParentId,
+        parent_id: ParentId==0?0+'':ParentId,//数字的0,'无'不回显
         sort: Sort,
         classify_id: Id,
         type:ClassifyType
@@ -453,17 +463,19 @@ export default {
     /* 保存分类 */
     async setClassifyHandle() {
       await this.$refs.formRef.validate();
-
+      console.log(this.classifyForm);
+      // return 
       const { classify_name,parent_id,sort,classify_id } = this.classifyForm;
       let params = {
         ClassifyName: classify_name,
-        ParentId: parent_id,
+        ParentId: parseInt(parent_id),
         Sort: sort
       }
 
       const { Ret,Msg } = classify_id 
         ? await classifyEnInterface.classifyEdit({...params,ClassifyId: classify_id}) 
-        : await classifyEnInterface.classifyAdd({...params,ClassifyType:this.classifyForm.type})
+        : await classifyEnInterface.classifyAdd(params)
+        // : await classifyEnInterface.classifyAdd({...params,ClassifyType:this.classifyForm.type})
 
       if(Ret !== 200) return
       this.$message.success(Msg)
@@ -478,25 +490,25 @@ export default {
     },
 
     //切换分类
-    handleTabChange(item){
-      this.aTab=item.val
-      this.page_no=1
-      this.searchform.key_word=''
-      this.getList()
-    },
+    // handleTabChange(item){
+    //   this.aTab=item.val
+    //   this.page_no=1
+    //   this.searchform.key_word=''
+    //   this.getList()
+    // },
 
     //新增分类时切换分类
-    FormClassifyChange(){
-      this.classifyForm.parent_id=0
-      this.getClassifyOne()
-    }
+    // FormClassifyChange(){
+    //   this.classifyForm.parent_id=0
+    //   this.getClassifyOne()
+    // }
   },
 
   mounted() {
-      if(this.authTabsOpt.length){
-        this.aTab = this.authTabsOpt[0].val
+      // if(this.authTabsOpt.length){
+      //   this.aTab = this.authTabsOpt[0].val
         this.getList();
-      }
+      // }
   },
 };
 </script>
@@ -542,3 +554,9 @@ export default {
   }
 }
 </style>
+<style lang="scss">
+.el-cascader .el-input{
+  width: 100%;
+}
+
+</style>

+ 23 - 3
src/views/dataEntry_manage/addChart.vue

@@ -57,13 +57,28 @@
 						/>
 					</el-form-item>
 					<el-form-item label="图表单位" prop="Unit" v-if="chartInfo.ChartType===7">
-						<el-input
+						<!-- <el-input
 							v-model="chartInfo.Unit"
 							style="width: 90%"
 							placeholder="请输入图表单位"
 							clearable
 							@change="changeUnit"
-						/>
+						/> -->
+						<el-select
+							v-model="chartInfo.Unit"
+							filterable
+							allow-create
+							default-first-option
+							clearable
+							@change="changeUnit"
+							placeholder="请输入图表单位">
+							<el-option
+								v-for="item in UnitOptions"
+								:key="item"
+								:label="item"
+								:value="item">
+							</el-option>
+						</el-select>
 					</el-form-item>
 				</el-form>
 
@@ -315,6 +330,7 @@
 						v-if="chartInfo.ChartType===10"
 						ref="SectionScatterOptRef"
 						@getData="getSectionScatterData"
+						@modifySeriesName="IsNameDefault = false"
 					/>
         </div>
 			</div>
@@ -551,6 +567,7 @@
 <script>
 import { dataBaseInterface } from '@/api/api.js';
 import { chartSetMixin } from './mixins/chartPublic';
+import {unitArr} from '@/utils/defaultOptions.js';
 import addOrEditMixn from './mixins/addOreditMixin';
 import Chart from './components/chart';
 import DateChooseDia from './components/DateChooseDia';
@@ -626,7 +643,10 @@ export default {
 			season_year:'',//季节图时间段
 			activeNames:'',
 
-			needWatch: true
+			needWatch: true,
+			IsNameDefault:true,
+
+			UnitOptions:unitArr
 
     };
   },

+ 4 - 3
src/views/dataEntry_manage/adjustdata/adjustData.vue

@@ -68,7 +68,8 @@
                 label: 'ClassifyName',
                 value: 'ClassifyId',
                 children: 'Children',
-                emitPath: false
+                emitPath: false,
+                checkStrictly: true
               }"
               clearable
               placeholder="请选择指标目录"
@@ -351,7 +352,7 @@ export default {
 		getMenu() {
 			dataBaseInterface.menuListV3().then((res) => {
 				if (res.Ret === 200) {
-					//this.filterNodes(res.Data.AllNodes)
+					this.filterNodes(res.Data.AllNodes||[])
 					this.classifyOptions = res.Data.AllNodes || [];
 				}
 			});
@@ -361,7 +362,7 @@ export default {
 			arr.length &&
 				arr.forEach((item) => {
 					item.Children.length && this.filterNodes(item.Children);
-					if (item.Level === 2) {
+					if (!item.Children.length) {
 						delete item.Children;
 					}
 				});

+ 5 - 92
src/views/dataEntry_manage/chartSetting.vue

@@ -1671,90 +1671,12 @@ export default {
       this.tableData.forEach((item) => {
         let edbData = EdbInfoList.find(_ => _.EdbInfoId===item.EdbInfoId);
         item.DataList = edbData.DataList;
+        //更新起始时间和最近更新时间
+        item.StartDate = edbData.StartDate;
+        item.ModifyTime = edbData.ModifyTime;
+
         if(edbData.EdbInfoCategoryType===1) item.MoveLatestDate = edbData.MoveLatestDate;
       });
-
-
-
-      // // 判断图标类型 设置参数
-      // let params =
-      //   this.sameOptionType.includes(this.selected_chartType)
-      //     ? {
-      //         ChartInfoId: this.selected_chartid,
-      //         DateType: this.year_select,
-      //         StartDate:
-      //           this.year_select === 5 || this.year_select === 6
-      //             ? this.select_date[0]
-      //             : '',
-      //         EndDate: this.year_select === 5 ? this.select_date[1] : '',
-      //       }
-      //     : {
-      //         ChartInfoId: this.selected_chartid,
-      //         Calendar: this.calendar_type,
-      //         SeasonStartDate: this.season_year ? this.season_year[0] : '',
-      //         SeasonEndDate: this.season_year ? this.season_year[1] : '',
-      //       };
-      // dataBaseInterface.chartInfo(params).then((res) => {
-      //   if (res.Ret === 200) {
-      //     this.chartInfo = res.Data.ChartInfo;
-      //     let beforeOptions = sessionStorage.getItem('beforeOptions')
-      //       ? JSON.parse(sessionStorage.getItem('beforeOptions'))
-      //       : '';
-      //     //合并缓存配置和新的数据
-      //     let newarr = res.Data.EdbInfoList.map((item, index) => {
-      //       if (beforeOptions && type === 'refresh') {
-      //         const DataList = item.DataList;
-      //         return {
-      //           ...beforeOptions[index],
-      //           DataList,
-      //         };
-      //       } else {
-      //         return item;
-      //       }
-      //     });
-      //     this.tableData = newarr;
-      //     //  刷新最新的指标数据 防止领先配置已保存 指标数据确实原数据的情况 针对正常图
-      //     if (
-      //       type === 'refresh' &&
-      //       beforeOptions &&
-      //       (this.sameOptionType.includes(this.chartInfo.ChartType) && this.chartInfo.ChartType!==5)
-      //     )
-      //       this.refreshTarget();
-      //     sessionStorage.setItem(
-      //       'defaultArr',
-      //       JSON.stringify(res.Data.EdbInfoList)
-      //     );
-      //     if (!type) {
-      //       this.year_select = this.chartInfo.DateType;
-      //       this.select_date = [
-      //         this.chartInfo.StartDate,
-      //         this.chartInfo.EndDate,
-      //       ];
-      //       this.calendar_type = this.chartInfo.Calendar; //日历类型
-      //       // this.season_year = [ this.chartInfo.SeasonStartDate, this.chartInfo.SeasonEndDate ];
-      //       this.dateTip =
-      //         this.chartInfo.DateType === 5
-      //           ? `${this.chartInfo.StartDate}~${this.chartInfo.EndDate}`
-      //           : this.chartInfo.DateType === 6
-      //           ? `${this.chartInfo.StartDate}~至今`
-      //           : '请选择时间段';
-
-      //       //新图表类型 依赖数据不同单独init 数据
-      //       const typeInitMap = {
-      //         7: this.initBarData,
-      //         10: this.initSectionScatterData
-      //       }
-      //       typeInitMap[this.chartInfo.ChartType] && typeInitMap[this.chartInfo.ChartType](res.Data);
-            
-      //     }
-      //     //将指标添加进标签列表中
-      //       const {ChartNameEn,ChartName,ChartInfoId,UniqueCode,ChartClassifyId}=res.Data.ChartInfo
-      //       this.addLabel({code:UniqueCode,id:ChartInfoId,classifyId:ChartClassifyId,EdbName:ChartName,EdbNameEn:ChartNameEn,chartData:res.Data.ChartInfo})
-      //       this.defaultShowNodes=this.findParentNodeHandle(this.treeData,ChartClassifyId)
-      //       this.changeTreeNode()
-      //   }
-        
-      // });
     },
 
     /* 搜索 */
@@ -2243,16 +2165,7 @@ export default {
     slideHandle() {
       this.isSlideLeft = !this.isSlideLeft;
     },
-    /* 保存图表当前配置项 上下限 */
-    saveNowOptions() {
-      // const dataArr = _.cloneDeep(this.tableData);
-      // dataArr.forEach((item) => {
-      //   item.MaxData = Number(item.MaxData);
-      //   item.MinData = Number(item.MinData);
-      //   delete item.DataList;
-      // });
-      // sessionStorage.setItem('beforeOptions', JSON.stringify(dataArr));
-    },
+
     /* 季节图切换年份  保持当前配置 */
     seasonYearChange() {
       // this.saveNowOptions();

+ 5 - 4
src/views/dataEntry_manage/codecount/index.vue

@@ -67,6 +67,7 @@
 									label: 'ClassifyName',
 									value: 'ClassifyId',
 									children: 'Children',
+									checkStrictly: true
 								}"
 								@change="menuChange"
 								clearable
@@ -341,7 +342,7 @@ export default {
 				EdbName: edb_name,
 				Frequency: frequency,
 				Unit: unit,
-				ClassifyId: menu
+				ClassifyId: menu&&menu[menu.length-1]
 			}
 			
 			const { Ret,Data } = this.$route.query.edbid ? await dataBaseInterface.editCountCode({ ...params,EdbInfoId: Number(this.$route.query.edbid) }) : await dataBaseInterface.addCountCode(params);
@@ -362,7 +363,7 @@ export default {
 		getMenu() {
 			dataBaseInterface.menuListV3().then((res) => {
 				if (res.Ret !== 200) return
-					//this.filterNodes(res.Data.AllNodes);
+					this.filterNodes(res.Data.AllNodes||[]);
 					this.menuOptions = res.Data.AllNodes || [];
 			});
 		},
@@ -371,7 +372,7 @@ export default {
 			arr.length &&
 				arr.forEach((item) => {
 					item.Children.length && this.filterNodes(item.Children);
-					if (item.Level === 2) {
+					if (!item.Children.length) {
 						delete item.Children;
 					}
 				});
@@ -379,7 +380,7 @@ export default {
 
 		/* 选择目录 */
 		menuChange(val) {
-			this.formData.menu = val.length ? val[val.length - 1] : '';
+			// this.formData.menu = val.length ? val[val.length - 1] : '';
 		},
 
 		/* 搜索 */

+ 51 - 5
src/views/dataEntry_manage/components/satterSeriesDia.vue

@@ -351,6 +351,13 @@ export default {
     },
     serieInfo: {
       type: Object
+    },
+    edbInfoData:{
+        type:Array,
+        default:[]
+    },
+    IsNameDefault:{
+        type:Boolean
     }
   },
   components: { mDialog },
@@ -392,8 +399,10 @@ export default {
             date: '',
             value: '',
           })).filter(_ =>_.target_id)
-        }     
-
+        }
+        //遍历请求xEdbs yEdbs的指标详情,获取最新日期和值
+        this.getEdbData()
+        this.getEdbNewInfo()
       }
     }
   },
@@ -414,6 +423,7 @@ export default {
         xEdbs: [],
         yEdbs: []
       },
+      edbData:{},
 
       form: {
         x_title:'',
@@ -515,7 +525,7 @@ export default {
             name: item.EdbName,
           })
 
-          this.form.series_name = this.form.series_name || this.targetInfo.xEdbs[0].date;
+          this.form.series_name = this.IsNameDefault?this.targetInfo.xEdbs[0].date:this.form.series_name;
           this.form.x_unit = this.form.x_unit || item.Unit;
         }else {
           this.targetInfo.yEdbs.push({
@@ -534,6 +544,9 @@ export default {
     /* 删除指标 */
     removeTarget(type,index) {
       type === 'x' ? this.targetInfo.xEdbs.splice(index,1) : this.targetInfo.yEdbs.splice(index,1);
+      if(type === 'x'&&this.IsNameDefault){
+        this.form.series_name = this.targetInfo.xEdbs.length?this.targetInfo.xEdbs[0].date:''
+      }
     },
 
     /* 保存 */
@@ -595,6 +608,10 @@ export default {
         edbs: arr
       }
       this.$emit('saveCallback',params)
+      //如果没修改过,且保存时值不相等,则此次保存视为修改
+      if(params.series_name!==xEdbs[0].date&&this.IsNameDefault){
+        this.$emit('modifySeriesName')
+      }
       this.cancelHandle()
     },
 
@@ -640,13 +657,13 @@ export default {
           target_id: item.EdbInfoId,
           target_name: item.EdbName,
           date: item.LatestDate,
-          value: '',
+          value: item.LatestValue,
           name: item.EdbName,
         } : {
           target_id: item.EdbInfoId,
           target_name: item.EdbName,
           date: item.LatestDate,
-          value: '',
+          value: item.LatestValue,
         }
       }else {
         this.replaceForm.item = { date: '' }
@@ -659,6 +676,9 @@ export default {
       const { index,type,item } = this.replaceForm;
 
       type==='x' ? this.targetInfo.xEdbs.splice(index,1,item) : this.targetInfo.yEdbs.splice(index,1,item);
+      if(type==='x'&&index===0&&this.IsNameDefault){
+        this.form.series_name = this.targetInfo.xEdbs[0].date;
+      }
       this.cancelReplace()
     },
 
@@ -678,6 +698,32 @@ export default {
       
       this.$emit("update:show", false);
     },
+    getEdbData(){
+        this.edbInfoData.forEach(e=>{
+            if(!this.edbData[e.EdbInfoId]){
+                this.edbData[e.EdbInfoId] = {
+                    date:e.LatestDate,
+                    value:e.LatestValue
+                }
+            }
+        })
+    },
+    //获取指标的最新日期和值
+    getEdbNewInfo(){
+        const {xEdbs,yEdbs} = this.targetInfo
+        xEdbs.forEach(x=>{
+            if(this.edbData[x.target_id]){
+                x.date = this.edbData[x.target_id].date
+                x.value = this.edbData[x.target_id].value
+            }
+        })
+        yEdbs.forEach(y=>{
+            if(this.edbData[y.target_id]){
+                y.date = this.edbData[y.target_id].date
+                y.value = this.edbData[y.target_id].value
+            }
+        })
+    }
   }
 }
 </script>

+ 11 - 0
src/views/dataEntry_manage/components/sectionalScatterOption.vue

@@ -54,7 +54,10 @@
     <satterSeriesDia
       :show.sync="isOpenSeriesDialog"
       :serieInfo="seriesArr[0]"
+      :edbInfoData="edbInfoData"
+      :IsNameDefault="IsNameDefault"
       @saveCallback="saveSeriesOpt"
+      @modifySeriesName="$emit('modifySeriesName')"
     />
 
     <!-- 添加其他系列 -->
@@ -166,6 +169,14 @@ export default {
   props: {
     initData: {
       default: null
+    },
+    edbInfoData:{
+        type:Array,
+        default:[]
+    },
+    IsNameDefault:{
+        type:Boolean,
+        default:true
     }
   },
   data() {

+ 23 - 8
src/views/dataEntry_manage/databaseComponents/batchComptedDialog.vue

@@ -15,7 +15,7 @@
 				:src="$icons.computed"
 				style="color: #fff; width: 16px; height: 16px; margin-right: 5px"
 			/>
-			<span style="font-size: 16px">{{ switchType.get(type) }}</span>
+			<span style="font-size: 16px">{{ titleMap.get(type) }}</span>
 		</div>
 
     <div class="cont">
@@ -84,7 +84,7 @@
 					<selectUnit 
 						v-model="list.unit" 
 						style="width: 15%;margin: 0 10px" 
-						:disabled="[6,7,32,33].includes(type)"
+						:disabled="[6,7,32,33,75].includes(type)"
 					/>
           <el-input
             v-if="[8,12,13,39,43,44].includes(type)"
@@ -99,7 +99,7 @@
 						placeholder="请选择频率"
 						style="width: 20%"
 						clearable
-            :disabled="[6,7,32,33,5,42,61,64,63,66].includes(type)"
+            :disabled="[6,7,32,33,5,42,61,64,63,66,75].includes(type)"
 					>
 						<el-option
 							v-for="item in frequencyArr"
@@ -119,7 +119,7 @@
 				style="margin-right: 20px"
 				@click="saveHandle"
 				:loading="loading"
-				>{{loading ? '计算中...' : save_txts.get(type)}}</el-button
+				>{{loading ? '计算中...' : saveBtnMap.get(type)}}</el-button
 			>
 			<el-button type="primary" plain @click="cancelHandle('cancel')">取消</el-button>
 		</div>
@@ -199,7 +199,7 @@ export default {
 				},
       ],
 
-			switchType: new Map([
+			titleMap: new Map([
 				[6,'同比值'],
 				[7,'同差值'],
 				[8,'N数值移动平均计算'],
@@ -220,8 +220,9 @@ export default {
 				[64,'累计值转月/季值'],
 				[65,'累计值'],
 				[66,'累计值'],
+				[75,'日均值']
 			]),//标题
-			save_txts: new Map([
+			saveBtnMap: new Map([
 				[6,'同比值计算'],
 				[7,'同差值计算'],
 				[8,'移动平均计算'],
@@ -242,6 +243,7 @@ export default {
 				[64,'转季值计算'],
 				[65,'累计值计算'],
 				[66,'年初至今计算'],
+				[75,'日均值计算']
 			]),//保存文案
 			unitArr,
 			options: [],
@@ -249,6 +251,7 @@ export default {
 				label: 'ClassifyName',
 				value: 'ClassifyId',
 				children: 'Children',
+				checkStrictly: true
 			},
 			frequencyArr: ['日度', '周度','旬度', '月度', '季度', '年度'],
 			fre_options: ['天','周','月','季','年'],
@@ -326,6 +329,7 @@ export default {
             list.targetName = default_opt.targetName;
             list.unit = default_opt.unit;
             list.frequency = default_opt.frequency;
+						list.menu = default_opt.menu||0
 					}
 				});
 
@@ -374,14 +378,18 @@ export default {
 				: await dataBaseInterface.menuListV3()
 				if (res.Ret !== 200) return
 				//this.edbSource !== 'predict' && this.filterNodes(res.Data.AllNodes);
+				// this.options = res.Data.AllNodes || [];
+				
+				this.filterNodes(res.Data.AllNodes||[]);
 				this.options = res.Data.AllNodes || [];
+				
 		},
 		// 递归改变第三级目录结构
 		filterNodes(arr) {
 			arr.length &&
 				arr.forEach((item) => {
 					item.Children.length && this.filterNodes(item.Children);
-					if (item.Level === 2) {
+					if (!item.Children.length) {
 						delete item.Children;
 					}
 				});
@@ -431,7 +439,7 @@ export default {
       let params = filterArr.map(item => ({
         CalculateId: item.tag,
         CalculateInfo: {
-          ClassifyId: item.menu[item.menu.length - 1],
+          ClassifyId: Array.isArray(item.menu)?item.menu[item.menu.length - 1]:item.menu,
           EdbName: item.targetName,
           Formula: String(item.n_num),
           Frequency:item.frequency,
@@ -578,6 +586,13 @@ export default {
 						unit: '无',
 						frequency: obj.Frequency
 					}
+				case 75: 
+					return {
+						targetName: `${obj.EdbName}日均值`,
+						unit: obj.Unit,
+						frequency: obj.Frequency,
+						menu: obj.ClassifyId,
+					}
 			}
     }  
 	},

+ 6 - 2
src/views/dataEntry_manage/databaseComponents/chartTrendRender.vue

@@ -144,8 +144,10 @@ export default {
 	computed: {
 
 		// 同比,环比,环差,超季节性、 残差展示基础图
+		//ETA1.1.1 所有的计算指标都能展示季节性图
 		isOnlyShowBaseChart() {
-			return [6,12,13,35,37].includes(this.chartInfo.Source)
+			/* return [6,12,13,35,37].includes(this.chartInfo.Source) */
+			return false
 		}
 	},
 	watch: {
@@ -269,7 +271,9 @@ export default {
 			});
 			let form = new FormData();
 			form.append("Img", svg);
-			let { Data } = await dataBaseInterface.uploadImgSvg(form);
+			let { Data,Ret } = await dataBaseInterface.uploadImgSvg(form);
+
+			if(Ret!==200 || !Data) return 
 			await dataBaseInterface.saveEdbChartImg({
 				EdbInfoId: EdbInfo.EdbInfoId,
 				ImageUrl: Data.ResourceUrl,

+ 3 - 2
src/views/dataEntry_manage/databaseComponents/completeTargetDia.vue

@@ -117,6 +117,7 @@ export default {
 				label: 'ClassifyName',
 				value: 'ClassifyId',
 				children: 'Children',
+				checkStrictly: true
 			},
 			frequencyArr:['日度','周度','旬度','月度','季度','年度']
 		};
@@ -126,7 +127,7 @@ export default {
 		getMenu() {
 			dataBaseInterface.menuListV3().then(res => {
 				if(res.Ret === 200) {
-					//this.filterNodes(res.Data.AllNodes);
+					this.filterNodes(res.Data.AllNodes||[]);
 					this.options = res.Data.AllNodes || [];
 				}
 			})
@@ -135,7 +136,7 @@ export default {
 		filterNodes(arr) {
 			arr.length && arr.forEach(item => {
 				item.Children.length && this.filterNodes(item.Children)
-				if(item.Level === 2) {
+				if(!item.Children.length) {
 					delete item.Children
 				}
 			})

+ 3 - 2
src/views/dataEntry_manage/databaseComponents/computedDialog.vue

@@ -209,6 +209,7 @@ export default {
 				label: 'ClassifyName',
 				value: 'ClassifyId',
 				children: 'Children',
+				checkStrictly: true
 			},
 			frequencyArr: ['日度', '周度','旬度','月度', '季度', '年度'],
 			formRules,
@@ -260,7 +261,7 @@ export default {
 		getMenu() {
 			dataBaseInterface.menuListV3().then((res) => {
 				if (res.Ret === 200) {
-					//this.filterNodes(res.Data.AllNodes);
+					this.filterNodes(res.Data.AllNodes||[]);
 					this.options = res.Data.AllNodes || [];
 				}
 			});
@@ -270,7 +271,7 @@ export default {
 			arr.length &&
 				arr.forEach((item) => {
 					item.Children.length && this.filterNodes(item.Children);
-					if (item.Level === 2) {
+					if (!item.Children.length) {
 						delete item.Children;
 					}
 				});

+ 3 - 7
src/views/dataEntry_manage/databaseComponents/diffusionIndexDia.vue

@@ -225,6 +225,7 @@ export default {
 				label: 'ClassifyName',
 				value: 'ClassifyId',
 				children: 'Children',
+				checkStrictly: true
 			},
 			frequencyArr: ['日度', '周度','旬度', '月度', '季度', '年度'],
 			fre_options: ['天','周','月','季','年'],
@@ -328,12 +329,7 @@ export default {
       ? await preDictEdbInterface.classifyListV2()
       : await dataBaseInterface.menuListV3()
 				if (res.Ret === 200) {
-					/* if(!this.isPredict){
-						this.filterNodes(res.Data.AllNodes);
-						this.options = res.Data.AllNodes || [];
-					}else{
-						this.options = res.Data.AllNodes || [];
-					} */
+					this.filterNodes(res.Data.AllNodes||[]);
 					this.options = res.Data.AllNodes || [];
 				}
 		},
@@ -342,7 +338,7 @@ export default {
 			arr.length &&
 				arr.forEach((item) => {
 					item.Children.length && this.filterNodes(item.Children);
-					if (item.Level === 2) {
+					if (!item.Children.length) {
 						delete item.Children;
 					}
 				});

+ 15 - 14
src/views/dataEntry_manage/databaseComponents/fittingResidueDia.vue

@@ -28,7 +28,7 @@
         :disabled="operationForm.view"
       >
 			
-        <el-form-item label="自变量" prop="self_variate">
+        <el-form-item label="自变量(x)" prop="self_variate">
           <el-select
             v-model="formData.self_variate"
             v-loadMore="searchLoad"
@@ -72,7 +72,7 @@
           </template>  
         </el-form-item>
 
-        <el-form-item label="因变量" prop="depend_variate">
+        <el-form-item label="因变量(y)" prop="depend_variate">
           <el-select
             v-model="formData.depend_variate"
             v-loadMore="searchLoad"
@@ -117,7 +117,7 @@
             @change="changeDate"
             :picker-options="endDateOptions"
           />
-					<span v-if="correlationIndex" class="editsty" style="margin-left: 20px">相关系数:{{correlationIndex}}</span>
+					<span v-if="correlationStr" class="editsty" style="margin-left: 20px">{{correlationStr}}</span>
         </el-form-item>
         <el-form-item label="指标名称" prop="edb_name" class="target-form-cont">
           <el-input
@@ -225,6 +225,8 @@ export default {
 					StartDate: item.StartDate,
 					EndDate: item.EndDate,
 				}))
+
+				this.correlationStr = backData.correlationStr;
 				
 			}
 		}
@@ -276,6 +278,7 @@ export default {
 				label: 'ClassifyName',
 				value: 'ClassifyId',
 				children: 'Children',
+				checkStrictly: true
 			},
 			frequencyArr: ['日度', '周度','旬度', '月度', '季度', '年度'],
 			fre_options: ['天','周','月','季','年'],
@@ -298,7 +301,7 @@ export default {
 			depend_edb_name: '',
 			self_edb_name: '',
 
-			correlationIndex: '',//相关系数
+			correlationStr: '',//相关系数
 
 		};
 	},
@@ -350,13 +353,10 @@ export default {
 			const res=this.isPredict?await preDictEdbInterface.classifyListV2():await dataBaseInterface.menuListV3()
 			// dataBaseInterface.menuList().then((res) => {
 				if (res.Ret === 200) {
-					/* if(!this.isPredict){
-						this.filterNodes(res.Data.AllNodes);
-						this.options = res.Data.AllNodes || [];
-					}else{
-						this.options = res.Data.AllNodes || [];
-					} */
+					
+					this.filterNodes(res.Data.AllNodes);
 					this.options = res.Data.AllNodes || [];
+					
 				}
 			// });
 		},
@@ -365,7 +365,7 @@ export default {
 			arr.length &&
 				arr.forEach((item) => {
 					item.Children.length && this.filterNodes(item.Children);
-					if (item.Level === 2) {
+					if (!item.Children.length) {
 						delete item.Children;
 					}
 				});
@@ -397,9 +397,9 @@ export default {
 		/* 获取相关系数 */
 		async getCorrelationIndex() {
 
-			if(!this.formData.self_variate || !this.formData.depend_variate || !this.formData.date[0] || !this.formData.date[1]) return this.correlationIndex = '';
+			if(!this.formData.self_variate || !this.formData.depend_variate || !this.formData.date[0] || !this.formData.date[1]) return this.correlationStr = '';
 			
-			if(this.formData.self_move_type===1 && !this.formData.self_move_val) return this.correlationIndex = '';
+			if(this.formData.self_move_type===1 && !this.formData.self_move_val) return this.correlationStr = '';
 
 			const { date,self_variate,self_move_type,self_move_val,depend_variate } = this.formData;
 			let params = {
@@ -423,7 +423,7 @@ export default {
 
 			if(res.Ret !==200) return
 			
-			this.correlationIndex = res.Data;
+			this.correlationStr = res.Data;
 		},
 
     /* 选择日期 */
@@ -445,6 +445,7 @@ export default {
 
 		init() {
 			this.searchOptions = [];
+			this.correlationStr = '';
 			this.formData = {
 				self_variate: '',
         self_move_type: 0,

+ 6 - 5
src/views/dataEntry_manage/databaseComponents/jointTargetDia.vue

@@ -157,6 +157,7 @@
 					label: 'ClassifyName',
 					value: 'ClassifyId',
 					children: 'Children',
+					checkStrictly: true
 				}"
 				style="width: 70%"
 				clearable
@@ -424,13 +425,13 @@ export default {
 			const res=this.isPredict?await preDictEdbInterface.classifyListV2():await dataBaseInterface.menuListV3()
 			// dataBaseInterface.menuList().then(res => {
 				if(res.Ret === 200) {
-					/* if(!this.isPredict){
-						this.filterNodes(res.Data.AllNodes);
+					if(!this.isPredict){
+						this.filterNodes(res.Data.AllNodes||[]);
 						this.menuOptions = res.Data.AllNodes || [];
 					}else{
 						this.menuOptions = res.Data.AllNodes || [];
-					} */
-					this.menuOptions = res.Data.AllNodes || [];
+					} 
+					// this.menuOptions = res.Data.AllNodes || [];
 				}
 			// })
 		},
@@ -438,7 +439,7 @@ export default {
 		filterNodes(arr) {
 			arr.length && arr.forEach(item => {
 				item.Children.length && this.filterNodes(item.Children)
-				if(item.Level === 2) {
+				if(!item.Children.length) {
 					delete item.Children
 				}
 			})

+ 49 - 72
src/views/dataEntry_manage/databaseComponents/openDialog.vue

@@ -1,4 +1,4 @@
-<template>
+ <template>
 	<div class="Dialog-box">
 		<el-dialog
 		:visible.sync="isOpenDialog"
@@ -21,53 +21,24 @@
 				label-width="80px"
 				:model="formData"
 				:rules="formRules">
-					<!-- 添加/编辑1级目录 -->
-					<template 
-					v-if="(title=='添加'&&formData.level === 0)
-					|| (title=='编辑'&&formData.level === 1)">
-						<el-form-item label="目录名称" prop="level_1">
-							<el-input
-							v-model="formData.level_1"
-							style="width: 80%"
-							placeholder="必填项"></el-input>
+					<template v-if="!formData.isEDB">
+						<el-form-item label="上级目录" v-if="formData.level>0">
+							<el-tooltip class="item" effect="dark" :content="getParentName" placement="top">
+      							<span class="parentStr">{{getParentName}}</span>
+    						</el-tooltip>
 						</el-form-item>
-					</template>
-					<!-- 添加/编辑2级目录 -->
-					<template 
-					v-else-if="(title=='添加'&&formData.level === 1)
-					|| (title=='编辑'&&formData.level === 2)">
-						<el-form-item label="一级目录" prop="level_1">
-							<span>{{formData.level_1}}</span>
-						</el-form-item>
-						<el-form-item label="目录名称" prop="level_2">
+						<el-form-item label="目录名称" prop="levelVal">
 							<el-input
-							v-model="formData.level_2"
-							style="width: 80%"
-							placeholder="必填项"></el-input>
-						</el-form-item>
-					</template>
-					<!-- 添加/编辑3级目录 -->
-					<template 
-					v-else-if="(title=='添加'&&formData.level === 2)
-					|| (title=='编辑'&&formData.level === 3)">
-						<el-form-item label="一级目录" prop="level_1">
-							<span>{{formData.level_1}}</span>
-						</el-form-item>
-						<el-form-item label="二级目录" prop="level_2">
-							<span>{{formData.level_2}}</span>
-						</el-form-item>
-						<el-form-item label="目录名称" prop="level_3">
-							<el-input
-							v-model="formData.level_3"
+							v-model="formData.levelVal"
 							style="width: 80%"
 							placeholder="必填项"></el-input>
 						</el-form-item>
 					</template>
 					<!-- 编辑具体指标 -->
-					<template v-else-if="title=='编辑' && formData.level === 4">
-						<el-form-item label="指标名称" prop="level_4">
+					<template v-if="title=='编辑' && formData.isEDB">
+						<el-form-item label="指标名称" prop="levelVal">
 							<el-input
-							v-model="formData.level_4"
+							v-model="formData.levelVal"
 							style="width: 80%"
 							placeholder="指标名称"></el-input>
 						</el-form-item>
@@ -124,34 +95,44 @@ export default {
 			default: '添加'
 		},
 		formData: {
-			type: Object,
+			type: Object,//{parentArr父级数据,isEDB:true 是否为指标}
 		}
 	},
 	watch: {
 		'isOpenDialog': {
 			handler(newval) {
-				if(newval && this.formData.level === 4) {
+				if(newval && this.formData.isEDB) {
 					this.getMenu();
 				}
 				// console.log(this.formData);
 			}
 		}
 	},
+	computed:{
+		getParentName(){
+			const arr=this.formData.parentArr||[]
+			let strArr=arr.reverse().map(item=>{
+				return item.classifyName
+			})
+			
+			return strArr.join('/')
+		}
+	},
 	data () {
 		return {
 			formRules: {
-				level_1:[
-					{ required: true, message: '目录名称不能为空', trigger: 'blur' },
-				],
-				level_2:[
-					{ required: true, message: '目录名称不能为空', trigger: 'blur' },
-				],
-				level_3:[
+				levelVal:[
 					{ required: true, message: '目录名称不能为空', trigger: 'blur' },
 				],
-				level_4:[
-					{ required: true, message: '指标名称不能为空', trigger: 'blur' },
-				],
+				// level_2:[
+				// 	{ required: true, message: '目录名称不能为空', trigger: 'blur' },
+				// ],
+				// level_3:[
+				// 	{ required: true, message: '目录名称不能为空', trigger: 'blur' },
+				// ],
+				// level_4:[
+				// 	{ required: true, message: '指标名称不能为空', trigger: 'blur' },
+				// ],
 				level_menu:[
 					{ required: true, message: '所属目录不能为空', trigger: 'blur' },
 				],
@@ -168,6 +149,7 @@ export default {
 				label: 'ClassifyName',
 				value: 'ClassifyId',
 				children: 'Children',
+				checkStrictly: true
 			},
 			frequencyArr:['日度','周度','旬度','月度','季度','年度'],
 
@@ -180,33 +162,21 @@ export default {
 
 			if(this.title==='添加') {
 				res = await dataBaseInterface.nodeAdd({
-						ClassifyName: this.formData.level === 0 
-							? this.formData.level_1
-							: this.formData.level === 1
-							? this.formData.level_2
-							: this.formData.level === 2
-							? this.formData.level_3
-							:'',
+						ClassifyName: this.formData.levelVal||'',
 						ParentId:this.formData.parent_id || 0,
 						Level: this.formData.level
 					})
 			}else if(this.title==='编辑') {
-				res = this.formData.level===4
+				res = this.formData.isEDB
 					? await dataBaseInterface.targetEdit({
 							ClassifyId: this.formData.level_menu[this.formData.level_menu.length - 1],
 							EdbInfoId: this.formData.edbinfo_id,
-							EdbName: this.formData.level_4,
+							EdbName: this.formData.levelVal,
 							Frequency: this.formData.frequency,
 							Unit: this.formData.unit
 						})
 					: await dataBaseInterface.nodeEdit({
-							ClassifyName: this.formData.level === 1
-								? this.formData.level_1
-								: this.formData.level === 2
-								? this.formData.level_2
-								: this.formData.level === 3
-								?this.formData.level_3
-								:'',
+							ClassifyName: this.formData.levelVal||'',
 							ClassifyId:this.formData.classify_id || 0
 						})
 			}
@@ -214,8 +184,8 @@ export default {
 			this.$message.success(res.Msg);
 
 		 if(this.title==='添加') this.callbackHandle('add');
-		 else if(this.title==='编辑' && this.formData.level===4) this.callbackHandle('update');
-		 else if(this.title==='编辑' && this.formData.level!==4) this.callbackHandle();
+		 else if(this.title==='编辑' && this.formData.isEDB) this.callbackHandle('update');
+		 else if(this.title==='编辑' && !this.formData.isEDB) this.callbackHandle();
 
 				
 		},
@@ -234,7 +204,7 @@ export default {
 		getMenu() {
 			dataBaseInterface.menuListV3().then(res => {
 				if(res.Ret === 200) {
-					//this.filterNodes(res.Data.AllNodes);
+					this.filterNodes(res.Data.AllNodes||[]);
 					this.options = res.Data.AllNodes || [];
 				}
 			})
@@ -243,7 +213,7 @@ export default {
 		filterNodes(arr) {
 			arr.length && arr.forEach(item => {
 				item.Children.length && this.filterNodes(item.Children)
-				if(item.Level === 2) {
+				if(!item.Children.length) {
 					delete item.Children
 				}
 			})
@@ -255,6 +225,13 @@ export default {
 </script>
 <style lang='scss'>
 .Dialog-box {
+	.parentStr{
+		display: block;
+		width: 304px;
+		overflow: hidden;
+		white-space: nowrap;
+		text-overflow: ellipsis;
+	}
 	.dialog-main {
 		padding-left: 50px;
 	}

+ 22 - 12
src/views/dataEntry_manage/databaseComponents/operationDialog.vue

@@ -15,7 +15,7 @@
 				:src="$icons.computed"
 				style="color: #fff; width: 16px; height: 16px; margin-right: 5px"
 			/>
-			<span style="font-size: 16px">{{ (operationForm.edb_id ? (operationForm.view ? '查看' : '编辑') : '') + switchType.get(type) }}</span>
+			<span style="font-size: 16px">{{ (operationForm.edb_id ? (operationForm.view ? '查看' : '编辑') : '') + titleMap.get(type) }}</span>
 		</div>
 		<div class="dialog-main">
 
@@ -163,7 +163,7 @@
 							<selectUnit 
 								v-model="formData.unit" 
 								style="width: 340px" 
-								:disabled="!operationForm.edb_id&&[6,7].includes(type)"
+								:disabled="!operationForm.edb_id&&[6,7,75].includes(type)"
 							/>
 						</el-form-item>
 						<el-form-item label="指标目录" prop="menu">
@@ -181,7 +181,7 @@
 								placeholder="请选择频度"
 								style="width: 340px"
 								clearable
-								:disabled="[5,14,61,63].includes(type)||(!operationForm.edb_id&&[6,7].includes(type))"
+								:disabled="[5,14,61,63].includes(type)||(!operationForm.edb_id&&[6,7,75].includes(type))"
 							>
 								<el-option
 									v-for="item in frequencyArr"
@@ -237,7 +237,7 @@
 				style="margin-right: 20px"
 				@click="saveHandle"
 				:loading="loading"
-				>{{loading ? '计算中...' : operationForm.edb_id ? '保存' : save_txts.get(type)}}</el-button
+				>{{loading ? '计算中...' : operationForm.edb_id ? '保存' : saveBtnMap.get(type)}}</el-button
 			>
 			<el-button type="primary" plain @click="cancelHandle('cancel')">取消</el-button>
 		</div>
@@ -359,7 +359,7 @@ export default {
 					key: 'SourceName',
 				},
 			],
-			switchType: new Map([
+			titleMap: new Map([
 				[5,'累计值转月/季值'],
 				[6,'同比值'],
 				[7,'同差值'],
@@ -375,8 +375,9 @@ export default {
 				[61,'累计值转月/季值'],
 				[62,'累计值'],
 				[63,'累计值'],
+				[75,'日均值']
 			]),//标题
-			save_txts: new Map([
+			saveBtnMap: new Map([
 				[5,'转月值计算'],
 				[6,'同比值计算'],
 				[7,'同差值计算'],
@@ -391,6 +392,7 @@ export default {
 				[61,'转季值计算'],
 				[62,'累计值计算'],
 				[63,'年初至今计算'],
+				[75,'日均值计算'],
 			]),//保存文案
 			formData: {
 				targetName:'',
@@ -411,6 +413,7 @@ export default {
 				label: 'ClassifyName',
 				value: 'ClassifyId',
 				children: 'Children',
+				checkStrictly: true
 			},
 			frequencyArr: ['日度', '周度','旬度', '月度', '季度', '年度'],
 			fre_options: ['天','周','月','季','年'],
@@ -488,7 +491,7 @@ export default {
 		getMenu() {
 			dataBaseInterface.menuListV3().then((res) => {
 				if (res.Ret === 200) {
-					//this.filterNodes(res.Data.AllNodes);
+					this.filterNodes(res.Data.AllNodes||[]);
 					this.options = res.Data.AllNodes || [];
 				}
 			});
@@ -498,7 +501,7 @@ export default {
 			arr.length &&
 				arr.forEach((item) => {
 					item.Children.length && this.filterNodes(item.Children);
-					if (item.Level === 2) {
+					if (!item.Children.length) {
 						delete item.Children;
 					}
 				});
@@ -604,7 +607,7 @@ export default {
 					Source: this.type,
 					EdbName: this.formData.targetName,
 					Unit: this.formData.unit,
-					ClassifyId: this.formData.menu[this.formData.menu.length - 1],
+					ClassifyId: Array.isArray(this.formData.menu)?this.formData.menu[this.formData.menu.length - 1]:this.formData.menu,
 					Frequency: this.formData.frequency,
 					Formula: valueMap[this.type] ? String(this.formData[valueMap[this.type]]) : String(this.formData.n_num),
 					FromEdbInfoId: this.select_target,
@@ -687,13 +690,20 @@ export default {
 				61:  obj.EdbName,
 				62:  obj.EdbName,
 				63:  obj.EdbName,
+				75: `${obj.EdbName}日均值`
+			}
+			
+			let frequerncyMap = {
+				14: '日度',
+				61: '季度',
+				62: ''
 			}
 
 			this.formData = {
 				targetName: name_map[this.type] || '',
-				frequency: this.type === 14 ? '日度' : this.type === 61 ? '季度' : this.type === 62 ? '' : obj.Frequency,
-				unit: [5,8,14,7,35].includes(this.type) ? obj.Unit : '无',
-				menu:'',
+				frequency: frequerncyMap[this.type] || obj.Frequency,
+				unit: [5,8,14,7,35,75].includes(this.type) ? obj.Unit : '无',
+				menu: this.type===75 ? obj.ClassifyId : '',
 				n_num: 1,
 				moveType: 1,
 				moveUnit: '天',

+ 18 - 1
src/views/dataEntry_manage/databaseComponents/smoothEdbDialog.vue

@@ -312,6 +312,7 @@ export default {
                 value: 'ClassifyId',
                 children: 'Children',
                 emitPath: false,
+                checkStrictly: true
             },
 
             select_target:'',
@@ -432,8 +433,24 @@ export default {
                 ? await preDictEdbInterface.classifyListV2()
                 : await dataBaseInterface.menuListV3()
             if(res.Ret!==200) return 
-            this.catalogArr = res.Data.AllNodes || [];
+            // this.catalogArr = res.Data.AllNodes || [];
+            if(!this.isPredict){
+				this.filterNodes(res.Data.AllNodes||[]);
+				this.catalogArr = res.Data.AllNodes || [];
+			}else{
+				this.catalogArr = res.Data.AllNodes || [];
+			} 
         },
+        // 递归改变第三级目录结构
+		filterNodes(arr) {
+			arr.length &&
+				arr.forEach((item) => {
+					item.Children.length && this.filterNodes(item.Children);
+					if (!item.Children.length) {
+						delete item.Children;
+					}
+				});
+		},
         /* 选择指标 */
         chooseTarget(val) {
             if(val) {

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

@@ -102,6 +102,10 @@ export const computedTypes = [
 	{
 		name:'指数修匀',
 		type:'alpha'
+	},
+	{
+		name:'日均值',
+		type: 75
 	}
 ]
 
@@ -142,6 +146,10 @@ export const computedBatchTypes = [
 	{
 		name:'指数修匀',
 		type:'alpha'
+	},
+	{
+		name:'日均值',
+		type: 75
 	}
 ]
 
@@ -418,5 +426,12 @@ export const formulaTip = new Map([
 	['alpha',`指数修匀计算公式:<br>
 	1、设定指数修匀值序列的初始值=原来时间序列的初始值 <br>
 	2、选择平滑系数alpha值:在0-1之间,开区间 <br>
-	3、本期指数修匀值=alpha*本期实际值+(1-alpha)*上期指数修匀值`]
+	3、本期指数修匀值=alpha*本期实际值+(1-alpha)*上期指数修匀值`],
+	[75,`日均值计算公式:<br>
+	1、年度值转日均值=年度值/对应年份天数 <br>
+	2、半年度值转日均值=半年度值/对应半年度天数 <br>
+	3、季度值转日均值=季度值/对应季度天数 <br>
+	4、月度值转日均值=月度值/对应月度天数 <br>
+	5、旬度值转日均值=旬度值/对应旬度天数 <br>
+	6、周度值转日均值=周度值/7`]
 ])

+ 164 - 258
src/views/dataEntry_manage/databaseList.vue

@@ -12,8 +12,8 @@
 					type="primary" @click="$router.push({path: '/codecount'})">代码运算</el-button>
 				<el-button v-permission="permissionBtn.edbDataPermission.edbData_dataAdjust"
 					type="primary" @click="$router.push({path: '/adjustdata'})">数据调整</el-button>
-				<el-button v-permission="permissionBtn.edbDataPermission.edbData_batchUpdate"
-					type="primary" plain @click="updateHandler">一键刷新</el-button>
+				<!-- <el-button v-permission="permissionBtn.edbDataPermission.edbData_batchUpdate"
+					type="primary" plain @click="updateHandler">一键刷新</el-button> -->
 			</div>
 			<div class="top-right">
 
@@ -54,6 +54,7 @@
 				/>
 		</div>
 		<div class="database_main box" id="box" v-if="showData">
+			<!-- <target-tree /> -->
 			<div class="main-left left" id="left">
 				<div class="tree-cont">
 					<el-tree
@@ -66,7 +67,7 @@
 						:allow-drop="canDropHandle"
 						:current-node-key="select_node"
 						:default-expanded-keys="defaultShowNodes"
-						draggable
+						:draggable="isEdbBtnShow('moveCatalog')"
 						:expand-on-click-node="false"
 						check-strictly
 						empty-text="暂无目录"
@@ -79,6 +80,7 @@
 						@node-drag-end="dropMouseLeave"
 						@node-drag-leave="dropMouseLeave"
 						@node-drag-enter="dropMouseOver"
+						@node-drag-over="dropMouseOver"
 					>
 						<span
 							class="custom-tree-node"
@@ -110,7 +112,7 @@
 									src="~@/assets/img/data_m/move_ico.png"
 									alt=""
 									style="width: 14px; height: 14px; margin-right: 8px"
-									v-if="data.Button.MoveButton"
+									v-if="data.Button.MoveButton&&isEdbBtnShow('moveCatalog')"
 								/>
 								<!-- 添加子项 -->
 								<img
@@ -118,9 +120,9 @@
 									alt=""
 									style="width: 14px; height: 14px; margin-right: 8px"
 									@click.stop="addNode(node,data)"
-									v-if="data.Button.AddButton&&isEdbBtnShow('editCatalog')"
+									v-if="data.Button.AddButton&&isEdbBtnShow('editCatalog')&&node.level<6"
 								/>
-								<!--编辑节点 如果是分类,判断data.Button.OpButton不变;如果是指标,不显示(ETA1.0.3)-->
+								<!-- 编辑节点 如果是分类,判断data.Button.OpButton不变;如果是指标,不显示(ETA1.0.3) -->
 								<img
 									src="~@/assets/img/set_m/edit.png"
 									alt=""
@@ -128,7 +130,7 @@
 									@click.stop="editNode(node,data)"
 									v-if="!data.EdbCode&&(data.Button.OpButton)&&isEdbBtnShow('editCatalog')"
 								/>
-								<!-- 删除节点 如果是分类,判断data.Button.DeleteButton不变;如果是指标,不显示(ETA1.0.3)-->
+								<!-- 删除节点 如果是分类,判断data.Button.DeleteButton不变;如果是指标,不显示(ETA1.0.3) -->
 								<img
 									slot="reference"
 									src="~@/assets/img/set_m/del.png"
@@ -139,7 +141,7 @@
 								/>
 								<!-- 查看计算指标 -->
 								<i class="el-icon-view" 
-									v-if="data.EdbType===2&&![58,59,67,68].includes(data.Source)&&isEdbBtnShow('checkCalcChart')" 
+									v-if="data.EdbType===2&&![58,59,67,68,74].includes(data.Source)&&isEdbBtnShow('checkCalcChart')" 
 									@click.stop="viewNode(node,data)"></i>
 								<!-- 查看关联图表 -->
 								<img 
@@ -215,18 +217,7 @@
 							type="text" @click="refreshTargetHandle" >刷新</el-button>
 						<el-button v-if="isEdbBtnShow('edit')"
 								type="text" :disabled="!(EdbData.Button.OpButton)"
-								@click="editNode({
-									level: 4,
-									parent: {
-										data: { ClassifyId:edb_levels[2].ClassifyId },
-										parent:{
-											data: { ClassifyId:edb_levels[1].ClassifyId },
-											parent:{
-												data: { ClassifyId:edb_levels[0].ClassifyId },
-											}
-										},
-									}
-								},EdbData)"
+								@click="editNode({},EdbData)"
 							>编辑</el-button>
 						<!-- 指保存指标的上下限,在走势图才显示 -->
 						<el-button v-if="activeTab==='Chart'&&isEdbBtnShow('saveEdb')"
@@ -373,7 +364,7 @@
 		</el-dialog>
 		<!-- 转月值 同比 同差 平均值弹窗 -->
 		<operationDialog
-			:isOperation="([5,6,7,8,12,13,14,22,35,51,52,61,62,63].includes(computed_type) || (computed_type===40&&operationForm.view)) && computed_source===1"
+			:isOperation="([5,6,7,8,12,13,14,22,35,51,52,61,62,63,75].includes(computed_type) || (computed_type===40&&operationForm.view)) && computed_source===1"
 			:type="computed_type"
 			:operationForm="operationForm"
 			@cancel="computed_type=0"
@@ -425,7 +416,7 @@
 
 		<!-- 批量计算弹窗 -->
 		<batchComputedDialog
-			:isBatchComputed="[6,7,8,12,13,14,5,61,62,63].includes(computed_type) && computed_source===2"
+			:isBatchComputed="[6,7,8,12,13,14,5,61,62,63,75].includes(computed_type) && computed_source===2"
 			:type="computed_type"
 			@cancel="computed_type=0"
 			@addCallBack="addComputedCallBack"
@@ -518,7 +509,7 @@ export default {
 		EdbLabelList,
 		chartTrendRender,
 		edbDetailData,
-		SmoothEdbDialog
+		SmoothEdbDialog,
 	},
 	directives: {
     drag(el, bindings) {
@@ -799,6 +790,7 @@ export default {
 
 				'editCatalog':edbDataPermission.edbData_classifyOpt_add,//添加编辑目录
 				'deleteCatalog':edbDataPermission.edbData_classifyOpt_delete,//删除目录
+				'moveCatalog':edbDataPermission.edbData_classifyOpt_move,//删除目录
 				'checkRelatedChart':edbDataPermission.edbData_checkRelatedChart,//查看关联图表
 				'checkRelatedEdb':edbDataPermission.edbData_checkRelatedEdb,//查看关联指标
 				'checkCalcChart':edbDataPermission.edbData_checkCalcChart,//查看计算指标
@@ -808,13 +800,13 @@ export default {
 		/* 获取树分类数据 */
 		getTreeData(params) {
 			
-			dataBaseInterface.menuListV3().then(res=>{
+			dataBaseInterface.targetCatalog({ParentId:0}).then(res=>{
 				if(res.Ret===200){
 					const arr=res.Data.AllNodes || []
 					this.treeData=arr.map(item=>{
 						return {
 							...item,
-							isLeaf:item.Children.length?false:true
+							// isLeaf:item.Children.length?false:true
 						}
 					})
 					this.CanOpClassify = res.Data.CanOpClassify;
@@ -863,10 +855,15 @@ export default {
 						//将指标添加进标签列表中
 						const {EdbNameEn,EdbName,EdbInfoId,UniqueCode,ClassifyId}=res.Data.Item
 						this.addLabel({code:UniqueCode,id:EdbInfoId,classifyId:ClassifyId,EdbName,EdbNameEn})
-						let deep_arr = _.cloneDeep(this.treeData);
-						this.defaultShowNodes=this.findParentNodeHandle(deep_arr,ClassifyId).reverse()||[]
+						// 展开目录
+						this.defaultShowNodes=classify_arr.map(item=>item.UniqueCode)
 						//设置tree高亮
-						this.$refs.menuTree.setCurrentKey(UniqueCode);
+						this.$nextTick(()=>{
+							setTimeout(() => {
+								this.$refs.menuTree.setCurrentKey(UniqueCode);
+							}, 1000);
+						})
+						
 
 					}else {
 						this.tableData = [];
@@ -902,7 +899,7 @@ export default {
 							if(overBottom){
 								parent.scrollTop =  node.offsetTop - parent.offsetHeight/2
 							}
-						},400)
+						},1500)
 					})
 					
 				}
@@ -1111,7 +1108,7 @@ export default {
 					? 'auto'
 					: width <= 260
 					? 80
-					: 0.5 * width;
+					: 0.4 * width;
 			this.$set(node, 'Nodewidth', label_wid + 'px');
 		},200),
 		/* 双击label出现input修改框 */
@@ -1151,27 +1148,28 @@ export default {
 			}
 			this.isOpenDialog = true;
 		},
+		// 递归节点
+		getNodeParentData(data,arr){
+			if(data.level===0) return
+			arr.push({classifyName:data.data.ClassifyName,classifyId:data.data.ClassifyId})
+			this.getNodeParentData(data.parent,arr)
+			return arr
+		},
 		/* 添加节点 */
 		addNode(node,data) {
-			// console.log(node,data);
+			console.log(node);
 			this.dialog_title = '添加';
+			let arr=[]
+			arr=this.getNodeParentData(node,arr)
+			// console.log(arr);
+			
 				/* 添加目录 */
 			this.dialogForm = {
-				level_1: node.level === 1 
-				? data.ClassifyName
-				:node.level === 2
-				? node.parent.data.ClassifyName
-				: node.parent.parent.data.ClassifyName,
-				level_2: node.level === 1 
-				? ''
-				:node.level === 2
-				? data.ClassifyName
-				: node.parent.data.ClassifyName,
-				// level_3: node.level === 3
-				// ? data.ClassifyName
-				// : '',
+				parentArr:arr,
 				parent_id: data.ClassifyId,
-				level: node.level
+				level: node.level,
+				levelVal:'',
+				isEDB:false
 			}
 			//存储当前要新增子级的目录code
 			sessionStorage.setItem('expandCode', data.UniqueCode);
@@ -1179,25 +1177,28 @@ export default {
 		},
 		/* 编辑节点 */
 		editNode(node,data) {
+			// console.log(node);
 			this.dialog_title = '编辑';
 			if(data.EdbCode) {
-				/* 编辑指标 */
+				/* 编辑指标 基础弹窗 */
 				
-				(data.EdbType===1 || [58,59,67,68].includes(data.Source)) && dataBaseInterface.targetDetail({
+				(data.EdbType===1 || [58,59,67,68,74].includes(data.Source)) && dataBaseInterface.targetDetail({
 					EdbInfoId: data.EdbInfoId
 				}).then(res => {
 					if(res.Ret === 200) {
+						// 处理所在目录
+						let menuArrId=res.Data.ClassifyList&&res.Data.ClassifyList.map(item=>{
+							return item.ClassifyId
+						}).reverse()
 						this.dialogForm = {
-							level: node.level,
-							level_4: res.Data.EdbName,
-							level_menu:[
-								node.parent.parent.parent.data.ClassifyId,
-								node.parent.parent.data.ClassifyId,
-								node.parent.data.ClassifyId
-							],
+							parentArr:[],
+							level: 0,
+							levelVal: res.Data.EdbName,
+							level_menu:menuArrId||[],
 							edbinfo_id: res.Data.EdbInfoId,
 							frequency:res.Data.Frequency,
-							unit:res.Data.Unit
+							unit:res.Data.Unit,
+							isEDB:true
 						}
 						this.isOpenDialog = true;
 					}
@@ -1232,23 +1233,15 @@ export default {
 
 
 			}else {
+				let arr=[]
+				arr=this.getNodeParentData(node.parent,arr)
 				/* 编辑目录 */
 				this.dialogForm = {
-					level_1: node.level === 1 
-					? data.ClassifyName
-					:node.level === 2
-					? node.parent.data.ClassifyName
-					: node.parent.parent.data.ClassifyName,
-					level_2: node.level === 1 
-					? ''
-					:node.level === 2
-					? data.ClassifyName
-					: node.parent.data.ClassifyName,
-					level_3: node.level === 3
-					? data.ClassifyName
-					: '',
+					isEDB:false,
+					parentArr:arr,
+					levelVal: data.ClassifyName||'',
 					classify_id: data.ClassifyId,
-					level: node.level
+					level: node.level-1
 				}
 				this.isOpenDialog = true;
 			}
@@ -1355,155 +1348,122 @@ export default {
 		},
 		/* 判断节点是否能被拖拽 */
 		canDragHandle({data}) {
-      return data.Button.MoveButton;
+      		return data.Button.MoveButton;
 		},
 		/* 判断节点是否能被拖入 */
 		canDropHandle(draggingNode, dropNode, type) {
 			let canDrop=false
-			// 移动的是一级目录
-			if(draggingNode.level===1&&dropNode.level===1&&type!=='inner') {
-				canDrop=true
-			} 
-
-			// 二级目录
-			if(draggingNode.level===2){
-				if((dropNode.level===1&&type==='inner')||(dropNode.level===2&&type!=='inner')){
-					canDrop=true
-				}
-			}
-
-			//三级目录
-			if(draggingNode.level===3){
-				if((dropNode.level===2&&type==='inner')||(dropNode.level===3&&type!=='inner')){
+			
+			// 如果拖动的是指标
+			if(draggingNode.data.EdbCode){
+				if(!(dropNode.level===1&&type!=='inner')){
 					canDrop=true
 				}
-			}
-			//四级指标
-			if(draggingNode.level===4){
-				if((dropNode.level===3&&type==='inner')||(dropNode.level===4&&type!=='inner')){
+			}else{//拖动的是目录
+				// console.log(dropNode.level,draggingNode.level);
+				//目录只能拖动到层级比他大的里面去
+				if(dropNode.level<draggingNode.level||(dropNode.level===draggingNode.level&&type!=='inner')){
 					canDrop=true
 				}
 			}
-			
 			return canDrop
 		},
 		/* 拖拽完成 */
 		dropOverHandle(b,a,i,e) {
 			// 被拖拽节点对应的 Node、结束拖拽时最后进入的节点、被拖拽节点的放置位置
-			if(b.level===1||b.level===2||b.level===3){
-				this.handleMoveCatalogue(b,a,i,e)
-			}
-
-			// 指标层
-			if(b.level===4){
-				this.handleMoveEdb(b,a,i,e)
-			}
-		},
+			console.log(b,a,i);
+			const isEDB=b.data.EdbCode?true:false
+			let list=a.parent.childNodes;
+			let targetIndex=0,PrevClassifyId=0,NextClassifyId=0,ParentClassifyId=0;
+			let ClassifyId=0,EdbInfoId=0,PrevEdbInfoId=0,NextEdbInfoId=0;
+
+			ClassifyId=isEDB?0:b.data.ClassifyId
+			EdbInfoId=isEDB?b.data.EdbInfoId:0
+			
 
-		// 移动的为一、二、三级目录
-		handleMoveCatalogue(b,a,i,e){
-			let list=a.parent.childNodes,targetIndex=0,PrevClassifyId=0,NextClassifyId=0,ParentClassifyId=0;
+			if(i!=='inner'){
+				ParentClassifyId=a.parent.data.ClassifyId||0
+				list.forEach((item,index)=>{
+					if(isEDB){
+						if(item.data.EdbInfoId===b.data.EdbInfoId){
+							targetIndex=index
+						}
+					}else{
+						if(item.data.ClassifyId===b.data.ClassifyId){
+							targetIndex=index
+						}
+					}
+					
+				})
 
-			list.forEach((item,index)=>{
-				if(item.data.ClassifyId===b.data.ClassifyId){
-					targetIndex=index
-					return
-				}
-			})
+				console.log(targetIndex);
+				
+				
+				if(targetIndex===0){
+					const data=list[targetIndex+1].data
+					NextClassifyId=data.EdbCode?0:data.ClassifyId
+					NextEdbInfoId=data.EdbCode?data.EdbInfoId:0
+				}else if(targetIndex===list.length-1){
+					const data=list[targetIndex-1].data
+					PrevClassifyId=data.EdbCode?0:data.ClassifyId
+					PrevEdbInfoId=data.EdbCode?data.EdbInfoId:0
+				}else{
+					const pData=list[targetIndex-1].data
+					PrevClassifyId=pData.EdbCode?0:pData.ClassifyId
 
-			if(targetIndex===0){
-				PrevClassifyId=0
-				NextClassifyId=list[targetIndex+1].data.ClassifyId
-			}else if(targetIndex===list.length-1){
-				PrevClassifyId=list[targetIndex-1].data.ClassifyId
-				NextClassifyId=0
-			}else{
-				PrevClassifyId=list[targetIndex-1].data.ClassifyId
-				NextClassifyId=list[targetIndex+1].data.ClassifyId
-			}
+					PrevEdbInfoId=pData.EdbCode?pData.EdbInfoId:0
 
-			if(b.level===2){
-				if(i==='inner'){
-					ParentClassifyId=a.data.ClassifyId
-					PrevClassifyId=0
-					NextClassifyId=a.data.Children.length>1?a.data.Children[1].ClassifyId:0
-				}else{
-					ParentClassifyId=a.data.ParentId
+					const nData=list[targetIndex+1].data
+					NextClassifyId=nData.EdbCode?0:nData.ClassifyId
+					NextEdbInfoId=nData.EdbCode?nData.EdbInfoId:0
 				}
+			}else{
+				ParentClassifyId=a.data.ClassifyId||0
 			}
 
-			if(b.level===3){
-				if(i==='inner'){
-					ParentClassifyId=a.data.ClassifyId
-					PrevClassifyId=0
-					NextClassifyId=a.data.Children.length>1?a.data.Children[1].ClassifyId:0
-				}else{
-					ParentClassifyId=a.data.ParentId
-				}
+			const params={
+				ClassifyId,
+				ParentClassifyId,
+				EdbInfoId,
+				PrevClassifyId,
+				NextClassifyId,
+				PrevEdbInfoId,
+				NextEdbInfoId
 			}
-
-			dataBaseInterface.classifyMove({
-				ClassifyId:b.data.ClassifyId,
-				ParentClassifyId:ParentClassifyId,
-				PrevClassifyId:PrevClassifyId,
-				NextClassifyId:NextClassifyId
-			}).then(res=>{
+			console.log(params);
+			dataBaseInterface.classifyMoveSort(params).then(res=>{
 				if(res.Ret===200){
 					this.$message.success('移动成功!')
 				}
-				this.getTreeData();
-			})
-		},
-
-		// 移动的为指标层 四级
-		handleMoveEdb(b,a,i,e){
-			let PrevEdbInfoId=0,NextEdbInfoId=0,targetIndex=0,list=a.parent.childNodes.map(_ => _.data)
-			if(i==='inner'){
-				PrevEdbInfoId=0
-				NextEdbInfoId=a.data.Children.length>1?a.data.Children[1].EdbInfoId:0
-			}else{
-				list.forEach((item,index)=>{
-					if(item.EdbInfoId===b.data.EdbInfoId){
-						targetIndex=index
-						return
-					}
-				})
-
-				if(targetIndex===0){
-					PrevEdbInfoId=0
-					NextEdbInfoId=list[targetIndex+1].EdbInfoId
-				}else if(targetIndex===list.length-1){
-					PrevEdbInfoId=list[targetIndex-1].EdbInfoId
-					NextEdbInfoId=0
-				}else{
-					PrevEdbInfoId=list[targetIndex-1].EdbInfoId
-					NextEdbInfoId=list[targetIndex+1].EdbInfoId
+				this.getTreeData()
+				if(this.selected_edbid){
+					this.getDataList();
 				}
-			}	
-			
-			dataBaseInterface.targetMove({
-				ClassifyId: a.data.ClassifyId,
-				EdbInfoId: b.data.EdbInfoId,
-				PrevEdbInfoId:PrevEdbInfoId,
-				NextEdbInfoId:NextEdbInfoId
-			}).then(res => {
-				if(res.Ret === 200) {
-					this.$message.success('移动成功!')
-				}
-				this.getTreeData();
+				
 			})
 		},
 
 		/* 拖拽覆盖添加背景色 */
 		dropMouseOver(node1,node2,e) {
+			// console.log(e.layerY);
+			
 			// 被拖拽节点对应的 Node、所进入节点对应的 Node、event
-			if(((node1.level===2&&node2.level === 1)||(node1.level===3&&node2.level === 2)) && (e.target.childNodes[0].className.includes('el-tree-node__content') 
+			if((node1.level>node2.level||(node1.data.EdbInfoId>0&&!node2.data.EdbInfoId)) && (e.target.childNodes[0].className.includes('el-tree-node__content') 
 			|| e.target.className.includes('el-tree-node__content'))) {
 				// console.log(e.target.childNodes[0])
 				e.target.childNodes[0].className.includes('el-tree-node__content') 
 				? e.target.childNodes[0].style.backgroundColor = '#409eff' 
 				: e.target.style.backgroundColor = '#409eff';
 			}
+			const dropLine=$('.el-tree__drop-indicator')[0]
+			if(dropLine){
+				// console.log(dropLine);
+				setTimeout(() => {
+					dropLine.style.top=e.layerY+'px'
+					// console.log(e.layerY,dropLine);
+				}, 100);
+			}
+			
 		},
 		/* 拖拽离开/拖拽完成重置背景色 */
 		dropMouseLeave(node1,node2,e) {
@@ -1515,13 +1475,7 @@ export default {
 		// 树节点展开
 		handleNodeExpand (data) {
 			// 保存当前展开的节点
-			let flag = false
-			this.defaultShowNodes.some(item => {
-				if (item === data.UniqueCode) { // 判断当前节点是否存在, 存在不做处理
-					flag = true
-					return true
-				}
-			})
+			let flag = this.defaultShowNodes.some((item) => item === data.UniqueCode);
 			if (!flag) { // 不存在则存到数组里
 				this.defaultShowNodes.push(data.UniqueCode)
 			}
@@ -1586,41 +1540,6 @@ export default {
 			})
 			return [...arr,code]
 		},
-		// 懒加载tree
-		handleTreeLoad(node,resolve){
-			if(node.level===0){
-				resolve(this.treeData)
-			}
-			if(node.level===1){
-				let arr=[]
-				this.treeData.forEach(item=>{
-					if(item.UniqueCode===node.data.UniqueCode){
-						arr=item.Children
-					}
-				})
-				resolve(arr)
-			}
-			if(node.level===2){
-				dataBaseInterface.getEdbListForClassify({ClassifyId:node.data.ClassifyId}).then(res=>{
-					if(res.Ret===200){
-						let arr=res.Data.EdbInfoList||[]
-						arr=arr.map(item=>{
-							return {
-								...item,
-								isLeaf:true
-							}
-						})
-						resolve(arr)
-					}else{
-						resolve([])
-					}
-					this.changeTreeNode()
-				})
-			}
-			if(node.level>2){
-				resolve([])
-			}
-		},
 		/* 添加计算指标 */
 		addComputedHandler() {
 			this.computedTit = '计算指标';
@@ -1699,6 +1618,12 @@ export default {
 		/* 设置回显计算指标的表单 */
 		setComputedDialogForm(type,node,data,res,view=false) {
 			//指标运算 or 其他计算类型指标
+
+			// 处理所在目录
+			let menuArrId=res.EdbInfoDetail.ClassifyList&&res.EdbInfoDetail.ClassifyList.map(item=>{
+				return item.ClassifyId
+			}).reverse()
+
 			if( type === 4 ) {
 				/* 回显指标和表单 */
 				const list = res.CalculateList;
@@ -1717,11 +1642,7 @@ export default {
 				this.calulateForm =  {
 					edb_id:res.EdbInfoDetail.EdbInfoId,
 					formula: res.EdbInfoDetail.CalculateFormula,
-					menu: [
-						node.parent.parent.parent.data.ClassifyId,
-						node.parent.parent.data.ClassifyId,
-						data.ClassifyId
-					],
+					menu: menuArrId||[],
 					targetName: res.EdbInfoDetail.EdbName,
 					unit: res.EdbInfoDetail.Unit,
 					frequency: res.EdbInfoDetail.Frequency,
@@ -1736,11 +1657,7 @@ export default {
 					targetName: dataInfo.EdbName,
 					frequency: dataInfo.Frequency,
 					unit: dataInfo.Unit,
-					menu: [
-						node.parent.parent.parent.data.ClassifyId,
-						node.parent.parent.data.ClassifyId,
-						data.ClassifyId
-					],
+					menu: menuArrId||[],
 					view
 				}
 
@@ -1754,6 +1671,7 @@ export default {
 							old_stay_edb: type === 24 ? old_edb.find(item => item.FromTag === 'A').FromEdbInfoId : '',
 							concat_edb: type === 24 ? old_edb.find(item => item.FromTag === 'B').FromEdbInfoId : '',
 							from_arr: old_edb,
+							correlationStr: dataInfo.CorrelationStr
 						} 
 					: {
 							...public_params,
@@ -1916,34 +1834,22 @@ export default {
 			})
 		},
 		//绑定el-tree的load属性
-		getLazyTreeData (node,resolve,maxLevel=3){
+		async getLazyTreeData (node,resolve){
 			if(node.level===0){
 				resolve(this.treeData)
-			}
-			if(node.level>0&&node.level<=maxLevel){
-				//获取对应层级的Child
-				resolve(node.data.Children||[])
-			}
-			if(node.level===maxLevel){
-				//调接口获取该分类下指标的数据
-				dataBaseInterface.getEdbListForClassify({ClassifyId:node.data.ClassifyId}).then(res=>{
-					if(res.Ret===200){
-						let arr=res.Data.EdbInfoList||[]
-						arr=arr.map(item=>{
-							return {
-								...item,
-								isLeaf:true
-							}
-						})
-						resolve(arr)
-					}else{
-						resolve([])
-					}
-					this.changeTreeNode()
-				})
-			}
-			if(node.level>maxLevel){
-				resolve([])
+			}else{
+				let arr=[]
+				const res=await dataBaseInterface.targetCatalog({ParentId:node.data.ClassifyId})
+				if (res.Ret === 200) {
+					const temarr = res.Data.AllNodes || [];
+					arr=temarr.map(item=>{
+						return {
+							...item,
+							isLeaf:item.EdbInfoId?true:false
+						}
+					})
+				}
+				resolve(arr)
 			}
 		},
 		//保存指标上下限

+ 28 - 3
src/views/dataEntry_manage/editChart.vue

@@ -66,13 +66,28 @@
 						/>
 					</el-form-item>
 					<el-form-item label="图表单位" prop="Unit" v-if="chartInfo.ChartType===7">
-						<el-input
+						<!-- <el-input
 							v-model="chartInfo.Unit"
 							style="width: 90%"
 							placeholder="请输入图表单位"
 							clearable
 							@change="changeUnit"
-						/>
+						/> -->
+						<el-select
+							v-model="chartInfo.Unit"
+							filterable
+							allow-create
+							default-first-option
+							clearable
+							@change="changeUnit"
+							placeholder="请输入图表单位">
+							<el-option
+								v-for="item in UnitOptions"
+								:key="item"
+								:label="item"
+								:value="item">
+							</el-option>
+						</el-select>
 					</el-form-item>
 				</el-form>
 
@@ -313,7 +328,10 @@
 						v-if="chartInfo.ChartType===10"
 						ref="SectionScatterOptRef"
 						:initData="chartInfo.ExtraConfig?JSON.parse(chartInfo.ExtraConfig):null"
+						:edbInfoData="tableData"
+						:IsNameDefault="IsNameDefault"
 						@getData="getSectionScatterData"
+						@modifySeriesName="IsNameDefault = false"
 					/>
         </div>
 			</div>
@@ -561,6 +579,7 @@
 <script>
 import { dataBaseInterface } from '@/api/api.js';
 import { chartSetMixin } from './mixins/chartPublic';
+import {unitArr} from '@/utils/defaultOptions.js'
 import addOrEditMixn from './mixins/addOreditMixin';
 
 import Chart from './components/chart';
@@ -629,6 +648,9 @@ export default {
 
 			initBarOptions: null,//编辑时回显的barOptions数据
 			needWatch: false,
+			IsNameDefault:true,
+
+			UnitOptions:unitArr
     };
   },
   methods: {
@@ -641,7 +663,10 @@ export default {
         })
         .then((res) => {
           if (res.Ret !== 200) return;
-					const { ChartInfo,EdbInfoList,BarChartInfo } = res.Data;
+					const { ChartInfo,EdbInfoList,BarChartInfo} = res.Data;
+					const {SeriesList=[]} = ChartInfo.ExtraConfig?JSON.parse(ChartInfo.ExtraConfig):{} 
+					const {IsNameDefault=true} = SeriesList.length?SeriesList[0]:[]
+					this.IsNameDefault = IsNameDefault
 
            this.chartInfo = {
 						...ChartInfo,

+ 7 - 1
src/views/dataEntry_manage/mixins/addOreditMixin.js

@@ -224,6 +224,7 @@ export default {
 			this.$set(edb,'EdbAliasName',edb.EdbName)
 			if(have_bol) return this.$message.warning('录入指标已存在');
 			this.search_txt = '';
+			this.chartInfo.Unit = this.chartInfo.Unit||edb.Unit
 			this.tableData.push(edb)
 
 		},
@@ -312,6 +313,10 @@ export default {
       this.tableData.forEach((item) => {
         let edbData = EdbInfoList.find(_ => _.EdbInfoId===item.EdbInfoId);
         item.DataList = edbData.DataList;
+				//更新起始时间和最近更新时间
+        item.StartDate = edbData.StartDate;
+        item.ModifyTime = edbData.ModifyTime;
+				
         if(edbData.EdbInfoCategoryType===1) item.MoveLatestDate = edbData.MoveLatestDate;
       });
 		},
@@ -617,7 +622,8 @@ export default {
 									YDate: edb.y_date,
 									YDateValue: edb.y_date_value,
 									IsShow: edb.is_show
-								}))
+								})),
+								IsNameDefault:this.IsNameDefault
 							}))
 						})
 					}	

+ 1 - 1
src/views/dataEntry_manage/mixins/chartPublic.js

@@ -1934,7 +1934,7 @@ export const chartSetMixin = {
             );
           });
         }else {
-          this.$message.warning('浏览器暂不支持')
+          this.$message.warning('当前协议暂不支持,仅支持https协议')
         }
       };
     },

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

@@ -72,7 +72,8 @@ export default {
     saveSheetHandle: _.debounce(async function() {
       const { name,classify } = this.sheetForm;
       luckysheet.exitEditMode()
-      let data = luckysheet.getAllSheets()[0]
+      //结构类型乱飘 强制定义下
+      let data = {...luckysheet.getAllSheets()[0],status:Number(luckysheet.getAllSheets()[0].status)}
       if(!name || !classify) return this.$message.warning(name ? '请选择表格分类' : '请输入表格名称')
       if(!data.celldata.length) return this.$message.warning('请输入表格内容');
 

+ 33 - 23
src/views/datasheet_manage/common/option.js

@@ -1,11 +1,10 @@
 
 /*  初始化  
-  options 用来初始化数据用 
-  data 初始化数据 [{celldata}]
+  options 其他配置 包括初始化数据 data:[{ celldata:[] }]
   sheetInfo 表格id相关信息 用来内容hooks变化时保存草稿
 */
 import * as sheetInterface from '@/api/modules/sheetApi.js';
-export const initSheet = (container,options={},sheetInfo={}) =>  {
+export function initSheet(container,options={},sheetInfo={}) {
   const configOpt = {
     container,
     lang: 'zh', // 设定表格语言
@@ -22,24 +21,23 @@ export const initSheet = (container,options={},sheetInfo={}) =>  {
       image: false, // 插入图片
       link: false, // 插入链接
     },
-    data: [{
-      ...options,
-      scrollTop: 0,
-      scrollLeft: 0
-    }],
     hook: {
       updated: (a,b,c,d,e)=> {
-        let data = luckysheet.getAllSheets()[0];
-        data.luckysheet_select_save = [];
-        const { ExcelInfoId,ExcelName,ExcelClassifyId } = sheetInfo;
-        ExcelInfoId && sheetInterface.sheetDrafSave({
-          ExcelInfoId,
-          ExcelName,
-          ExcelClassifyId,
-          Content: JSON.stringify(data)
-        })
+
+        if(sheetInfo.Source&&sheetInfo.Source===1) {
+          let data = luckysheet.getAllSheets()[0];
+          data.luckysheet_select_save = [];
+          const { ExcelInfoId,ExcelName,ExcelClassifyId } = sheetInfo;
+          ExcelInfoId && sheetInterface.sheetDrafSave({
+            ExcelInfoId,
+            ExcelName,
+            ExcelClassifyId,
+            Content: JSON.stringify(data)
+          })
+        }
       }
-    }
+    },
+    ...options
   }
 
   luckysheet.create(configOpt)
@@ -49,12 +47,24 @@ export const initSheet = (container,options={},sheetInfo={}) =>  {
 /* 保存表格关联截图 手动选区截图再清空选区 */
 export const getSheetImage = (data) => {
   const { celldata } = data;
-  
-  const r_arr = celldata.map(_ => _.c);
-  let r_start = celldata[0].r,
-    r_end = celldata[celldata.length-1].r,
-    c_start = Math.min(...r_arr),
+
+  //超过1000个就不遍历了
+  let r_start,r_end,c_start,c_end;
+  if(celldata.length > 1000) {
+    const splitData = celldata.slice(0,1000);
+    const r_arr = splitData.map(_ => _.c);
+    r_start = splitData[0].r;
+    r_end = splitData[splitData.length-1].r;
+    c_start = Math.min(...r_arr);
     c_end = Math.max(...r_arr);
+
+  }else {
+    const r_arr = celldata.map(_ => _.c);
+    r_start = celldata[0].r;
+    r_end = celldata[celldata.length-1].r;
+    c_start = Math.min(...r_arr);
+    c_end = Math.max(...r_arr);
+  }
   
   luckysheet.setRangeShow({row:[r_start,r_end],column:[c_start,c_end]},{show: false})
   let img = luckysheet.getScreenshot()

+ 3 - 13
src/views/datasheet_manage/components/SheetExcel.vue

@@ -8,7 +8,7 @@ import { initSheet } from '../common/option';
 export default {
   props: {
     option: {
-      type: String,
+      type: Object,
       default: ''
     },
     sheetInfo: {
@@ -16,25 +16,15 @@ export default {
       default: ()=>{}
     }
   },
-  // watch: {
-  //   option: {
-  //     handler(newval) {
-  //       console.log(newval)
-  //       this.optionData = newval ? JSON.parse(newval) : {}
-  //       this.init();
-  //     },
-  //     deep:true
-  //   }
-  // },
   data() {
     return {
-      // optionData: {},
       sheetObj: {}
     }
   },
   methods: {
     init() {
-      let optionData = this.option ? JSON.parse(this.option) : {};
+      let optionData = this.option ? this.option : {};
+
       initSheet('sheet-container',optionData,this.sheetInfo)
     }
   },

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

@@ -107,7 +107,7 @@ export default {
 }
 </script>
 <style scoped lang='scss'>
-@import "../../../styles/theme-vars.scss";
+@import "~@/styles/theme-vars.scss";
 .select-target-value-dia {
   background: #fff;
   position: fixed;

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

@@ -1,3 +1,4 @@
+<!-- 通用二级分类的弹窗 -->
 <template>
 	<div class="sheet-classify-dialog">
 		<el-dialog
@@ -81,6 +82,9 @@ export default {
       
 			const handleMap = {
 				'/sheetList': this.sheetClassifyApi,
+				'/sheetTimeList': this.sheetClassifyApi,
+				'/sheetMixedList': this.sheetClassifyApi,
+				'/sheetAnalysisList': this.sheetClassifyApi,
 				'/commordityChartBase': this.commodityClassifyApi,
 				'/chartrelevance':this.relevanceClassifyApi,
 				'/fittingEquationList': this.fittingEquationClassifyApi,
@@ -92,8 +96,8 @@ export default {
 		/* 表格分类接口 */
 		async sheetClassifyApi(classify_name,classify_id) {
 			const { Ret,Msg } = !classify_id
-        ? await sheetInterface.classifyAdd({ ExcelClassifyName:classify_name })
-        : await sheetInterface.classifyEdit({ ExcelClassifyName:classify_name, ExcelClassifyId:classify_id  })
+        ? await sheetInterface.classifyAdd({ ExcelClassifyName:classify_name,Source: this.$parent.sourceMap[this.$route.path] })
+        : await sheetInterface.classifyEdit({ ExcelClassifyName:classify_name, ExcelClassifyId:classify_id,Source: this.$parent.sourceMap[this.$route.path] })
         
       if( Ret !== 200) return
       this.$message.success(Msg);

+ 119 - 0
src/views/datasheet_manage/components/sheetListWrap.vue

@@ -0,0 +1,119 @@
+<template>
+  <div class="sheet-list-cont">
+    <span>共{{ total }}张表格</span>
+    <div class="sheetlist-wrapper" ref="listRef" @scroll="$emit('loadMoreHandle')">
+      <el-col
+        :span="6"
+        style="margin-bottom: 20px; padding-right: 20px"
+        v-for="cell in list"
+        :key="cell.ExcelInfoId"
+      >
+        <el-card class="sheet-item">
+          <div slot="header" class="item-top">
+            <span class="text_oneLine">{{ cell.ExcelName }}</span>
+          </div>
+          <img
+            :src="cell.ExcelImage"
+            alt=""
+            class="chart-img"
+            :height="imgHeight"
+            @click="$emit('detailShowHandle',cell)"
+          />
+          <div class="item-bottom">
+            <span>创建时间: {{ cell.CreateTime.slice(0, 10) }}</span>
+            <div>
+              <span
+                v-if="$parent.isSheetBtnShow('download')"
+                class="editsty"
+                style="margin-right: 10px"
+                @click="$emit('downloadExcel',cell)"
+                >下载</span
+              >
+              <span
+                v-if="$parent.isSheetBtnShow('del')"
+                class="deletesty"
+                @click="$emit('delSheetHandle',{cell, type:'del-list'})"
+                >删除</span
+              >
+            </div>
+          </div>
+        </el-card>
+      </el-col>
+    </div>
+    <div v-if="!total" class="nodata">
+      <tableNoData text="暂无表格"/>
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  props: ['total','list'],
+  data() {
+    return {
+    }
+  },
+  mounted(){
+
+  },
+}
+</script>
+<style scoped lang='scss'>
+  .sheet-list-cont {
+    color: #333;
+    .el-card .el-card__header,
+    .el-card__body {
+      padding: 10px;
+    }
+
+    .sheetlist-wrapper {
+      margin-top: 10px;
+      display: flex;
+      flex-wrap: wrap;
+      max-height: calc(100vh - 143px);
+      overflow: hidden;
+      overflow-y: auto;
+      .drag-cont {
+        width: 100%;
+        display: flex;
+        flex-wrap: wrap;
+      }
+      .dragShdow {
+        box-shadow: 0 1px 8px rgba(64, 158, 255, 0.8);
+        opacity: 0.5;
+      }
+      .sheet-item {
+        .item-top {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          font-size: 16px;
+          font-weight: 600;
+        }
+        .chart-img {
+          width: 100%;
+          height: 196px;
+          object-fit: contain !important;
+          cursor: pointer;
+        }
+        .item-bottom {
+          margin-top: 10px;
+          display: flex;
+          justify-content: space-between;
+          font-size: 12px;
+          color: #666;
+          .collected {
+            color: #f00;
+            cursor: pointer;
+          }
+          .join_txt {
+            color: #409eff;
+            cursor: pointer;
+          }
+        }
+      }
+    }
+    .nodata {
+      text-align: center;
+    }
+  }
+</style>

+ 505 - 0
src/views/datasheet_manage/customAnalysis/addAnalysisSheet.vue

@@ -0,0 +1,505 @@
+<template>
+  <div class="addSheet-wrap">
+    
+    <createTargetForm 
+      v-if="$route.path==='/createTaregtBySheet'"
+      ref="createTargetRef" 
+      @save="handleCreateTarget" 
+    />
+
+
+    <div class="main">
+      <div class="left-section">
+        <el-tabs 
+          v-model="selectIndex" 
+          type="card"
+        >
+          <el-tab-pane
+            :key="item.name"
+            v-for="(item,index) in uploadSheetsList"
+            :label="item.name"
+            :name="String(index)"
+          />
+        </el-tabs>
+        <div class="sheet-wrapper">
+          <Sheet ref="sheetRef" :option="sheetConfig" v-if="sheetConfig.data"/>
+
+          <dataLoading :loading="isLoading"/>
+        </div>
+
+      </div>
+
+      <!-- 指标列表 -->
+      <rightSection 
+        ref="edbWrapRef"
+        v-if="$route.path==='/createTaregtBySheet'"
+        :list="edbList"
+        @choose="chooseEdbHandle"
+      />
+    </div>
+
+
+    <!-- 上传文件 -->
+    <bottomSection
+      ref="bottomSecRef"
+      v-if="$route.path==='/addAnalysisSheet'" 
+      :sheetList="sheetConfig.data||[]"
+      :classifyArr="classifyArr"
+      @save="handleAddSheet"
+    />
+
+  </div>
+</template>
+
+<script>
+import * as sheetInterface from '@/api/modules/sheetApi.js';
+import Sheet from '../components/SheetExcel.vue';
+import { getSheetImage } from '../common/option';
+import bottomSection from './components/bottomSection.vue'
+import rightSection from './components/rightSection.vue';
+import createTargetForm from './components/createTargetForm.vue';
+export default {
+  components: { Sheet,bottomSection,rightSection,createTargetForm },
+  computed: {
+    files() {
+      return this.$store.state.sheet.files;
+    },
+    sheetConfig() {
+      return this.$route.path==='/createTaregtBySheet' 
+        ? {
+            showsheetbar: true,
+            // allowCopy:false,
+            // allowEdit:false,
+            // allowUpdate:false,
+            // enableAddRow:false,
+            data: null,
+            hook: {
+              //选区时
+              rangeSelect: (sheet,range) => {
+                if(this.$refs.createTargetRef && this.$refs.createTargetRef.selectArea && !this.$refs.createTargetRef.isLockUpdate) this.getRangeCell()
+              },
+            }
+          } 
+        : {
+            showsheetbar: true,
+            data: null
+          }
+    },
+  },
+  data() {
+    return {
+      isLoading: false,
+      uploadSheetsList: [],
+      pageSize: 2000,
+      currentPage: 0,
+      maxPage:0,
+
+      selectIndex: '0',
+      classifyArr: [],
+
+      sheetDetailInfo: {},
+      sheetDataPage: 2,
+      sheetAllcellData:[],//全部单元格数据 分页push
+      dataToalPage: 0,
+
+      edbList: [],//生成的指标列表
+    }
+  },
+  methods: {
+
+    backHandle(scence=null) {
+      if(scence === 'into-detail') {
+        const { ExcelInfoId, UniqueCode } = this.sheetDetailInfo;
+        
+        this.$router.replace({
+          path: '/sheetAnalysisList',
+          query: {
+            code: UniqueCode,
+            id: ExcelInfoId
+          }
+        })
+      }else {
+        this.$router.go(-1);
+      }
+
+    },
+
+    /* 切换表格 */
+    handleSwitchSheet() {
+      this.sheetConfig.data = null;
+      this.handelTranslateData(); 
+    },
+
+    /* 获取分类 */
+    getClassify() {
+      sheetInterface.excelClassifyOne({Source: 4}).then(res => {
+        if(res.Ret !==200) return
+        
+        this.classifyArr = res.Data.AllNodes || [];
+      })
+    },
+
+    loadDataSync() {
+      let len = this.sheetConfig.data.length;
+      for(let i =0;i<len;i++) {
+        if(this.allSheetData[i].celldata[this.currentPage*this.pageSize]) {
+          let concatData = this.allSheetData[i].celldata.slice(this.currentPage*this.pageSize, (this.currentPage+1)*this.pageSize);
+
+          // this.sheetConfig.data[i].celldata = this.sheetConfig.data[i].celldata.concat(concatData) 
+          // this.$refs.sheetRef.init()
+        }
+        continue
+
+      }
+
+      if (this.currentPage<this.maxPage) {
+        this.currentPage++
+        requestAnimationFrame(this.loadDataSync());
+      }
+    },
+
+    /* 分割数据 */
+    splitSheetData(sheets) {
+      // this.allSheetData = sheets.map(_ => ({
+      //   index: _.index, //工作表索引
+      //   order: _.order, //工作表的下标
+      //   name: _.name,
+      //   calcChain: _.calcChain,
+      //   celldata: _.celldata,
+      //   config: _.config
+      // }));
+      // this.maxPage = Math.max(...sheets.map(_ =>  Math.ceil(_.celldata.length / this.pageSize)))
+      console.log(sheets)
+
+      this.sheetConfig.data = sheets.map(_ => ({
+        index: _.index, //工作表索引
+        order: Number(_.order), //工作表的下标
+        name: _.name,
+        calcChain: _.calcChain,
+        config: _.config,
+        celldata: _.celldata,
+      }));
+      
+      //辣鸡插件连更新数据的api都没有
+       //  this.loadDataSync();
+      
+      this.isLoading = false;
+    },
+
+    handelTranslateData() {
+        this.isLoading = true;
+        LuckyExcel.transformExcelToLucky(this.uploadSheetsList[Number(this.selectIndex)], (exportJson, luckysheetfile) =>{
+                                  
+          if(exportJson.sheets==null || exportJson.sheets.length==0){
+              this.$message.warning('解析文件失败')
+              return;
+          }
+
+            this.splitSheetData(exportJson.sheets);
+
+        });
+
+    },
+
+    /* 移除表格 */
+    handleRemoveSheet(index) {
+      if(this.uploadSheetsList.length === 1) {
+        this.backHandle()
+        return
+      }
+
+      this.uploadSheetsList.splice(Number(index),1)
+      if(this.selectIndex === index) {
+        this.selectIndex = '0';
+        this.handleSwitchSheet()
+      }
+
+    },
+
+
+    /* 保存表格 */
+    handleAddSheet: _.debounce(async function() {
+      luckysheet.exitEditMode()
+      let data = luckysheet.getAllSheets().filter(_ => this.$refs.bottomSecRef.sheetChecked.includes(_.name));
+      console.log(data)
+
+      this.loading = this.$loading({
+				target:'.addSheet-wrap',
+				lock: true,
+				text: '保存中...',
+				spinner: 'el-icon-loading',
+				background: 'rgba(255, 255, 255, 0.6)'
+			});
+      let img = getSheetImage(data[0]);
+			const form  = new FormData();
+			form.append('Image', img);
+			const { Data } = await sheetInterface.uploadImg(form)
+
+      data.luckysheet_select_save = [];
+      const res = await sheetInterface.sheetAnalysisInterface.excelSheetAdd({
+        ExcelName: this.uploadSheetsList[0].name,
+        ExcelClassifyId: this.$refs.bottomSecRef.select_classify,
+        ExcelImage: Data.ResourceUrl,
+        Content: JSON.stringify(data)
+      })
+      this.loading.close()
+      if(res.Ret !== 200) return
+
+      this.$message.success(res.Msg);
+
+      // const { ExcelInfoId, UniqueCode } = res.Data;
+      
+      this.$router.replace({
+        path: '/sheetAnalysisList',
+        // query: {
+        //   code: UniqueCode,
+        //   id: ExcelInfoId
+        // }
+      })
+    },300),
+
+     /* 获取表格详情 */
+    getDetailHandle() {
+      this.isLoading = true;
+      sheetInterface.sheetAnalysisInterface.getExcelDetail({
+        UniqueCode: this.$route.query.code,
+      }).then((res) => {
+        if (res.Ret !== 200) return;
+
+        this.sheetDetailInfo = res.Data.ExcelInfo;
+        this.dataToalPage =  Math.max(...res.Data.SheetList.map(_ => _.PageNum));
+        this.sheetAllcellData = res.Data.SheetList.map(_ => _.Data ? JSON.parse(_.Data.Data): []);
+
+        this.getCellData(res.Data.SheetList)
+      });
+    },
+
+    //分页获取表格数据
+    async getCellData(sheets) {
+
+      let res = await sheetInterface.sheetAnalysisInterface.getExcelDataByPage({
+        UniqueCode: this.$route.query.code,
+        Page: this.sheetDataPage
+      })
+
+      if(res.Ret !== 200) return
+
+      for(let i = 0;i<this.sheetAllcellData.length;i++) {
+        if(res.Data[i].Data) {
+          this.sheetAllcellData[i] = [...this.sheetAllcellData[i],...JSON.parse(res.Data[i].Data.Data)]
+        }
+        continue
+      }
+      
+      //数据继续加载或渲染表格
+      if(this.sheetDataPage < this.dataToalPage) {
+        this.sheetDataPage++;
+        this.getCellData(sheets)
+      }else {
+        this.sheetConfig.data = sheets.map((_,index) => ({
+          index: _.Index, //工作表id
+          order: _.Sort, //工作表的下标
+          name: _.SheetName,
+          calcChain: JSON.parse(_.CalcChain),
+          config: JSON.parse(_.Config),
+          celldata: this.sheetAllcellData[index],
+        }))
+
+        this.isLoading = false;
+        this.getTargetList()
+      }
+    },
+
+
+    /* 获取选取对应单元格数组和拼接选取的公式 
+      Sheet1!$A$1:$A$25
+      Sheet1!$E:$E
+    */
+    getRangeCell: _.debounce(function() {
+      let sheet = luckysheet.getSheet();
+      let rangeArr = luckysheet.getRangeAxis();
+
+      if(rangeArr.length > 1) return this.$message.warning('同时只允许选择一块区域');
+      //检查选取是否满足同行/同列
+      if(!this.checkRangeVaild(rangeArr[0])) return this.$message.warning('序列只允许选择同行或同列');
+
+      let rangeCells = luckysheet.getRangeValue().flat().map(_=>_?_.m:'');
+
+      let format = `${sheet.name}!${this.formatStr(rangeArr[0])}`;
+
+      console.log(format)
+      this.$refs.createTargetRef.setFormula(format,rangeCells)
+    },300),
+
+    //检验同行同列
+    checkRangeVaild(range) {
+      let reg = /^([A-Z]+)(\d+)$/;
+      let arr = range.split(':').map(_ => [_.match(reg)[1],_.match(reg)[2]]);
+      
+      if(arr.length ===1) return true;
+
+      if(arr[0][0] === arr[1][0] || arr[0][1] === arr[1][1]) {
+        return true
+      }else {
+        return false
+      }
+    },
+
+    formatStr(inputRange) {
+      // 将字母和数字前面都拼接"$"
+      const parts = inputRange.split(':');
+      if (parts.length === 2) {
+          const start = parts[0].replace(/(^[A-Z]+)(\d+)$/, '$$$1$$$2');
+          const end = parts[1].replace(/(^[A-Z]+)(\d+)$/, '$$$1$$$2');
+          return start + ':' + end;
+      }
+      return inputRange;
+      
+    },
+    
+    /* 生成指标 */
+    async handleCreateTarget() {
+      console.log(this.$refs.createTargetRef.formData)
+      this.loading = this.$loading({
+				target:'.addSheet-wrap',
+				lock: true,
+				text: '保存中...',
+				spinner: 'el-icon-loading',
+				background: 'rgba(255, 255, 255, 0.6)'
+			});
+
+      let data = luckysheet.getAllSheets();
+      data.luckysheet_select_save = [];
+      const { ExcelInfoId, ExcelName, ExcelClassifyId } = this.sheetDetailInfo;
+      await sheetInterface.sheetAnalysisInterface.sheetEdit({
+        ExcelInfoId,
+        ExcelName,
+        ExcelClassifyId,
+        // ExcelImage: Data.ResourceUrl,
+        Content: JSON.stringify(data)
+      });
+      
+      const { edbInfoId,
+        dateSeries,
+        valueSeries,
+        dateArr,
+        valueArr,
+				edbName,
+				classify,
+				frequency,
+				unit } = this.$refs.createTargetRef.formData;
+      let params = {
+        EdbName: edbName,
+        ExcelInfoId: ExcelInfoId,
+        ClassifyId: classify,
+        Frequency: frequency,
+        Unit: unit,
+        DateSequenceVal: dateArr,
+        DataSequenceVal: valueArr,
+        DateSequenceStr: dateSeries,
+        DataSequenceStr: valueSeries
+      }
+      const res = edbInfoId 
+        ? await sheetInterface.sheetAnalysisInterface.edbEditBysheet({...params,EdbInfoId: edbInfoId})
+        : await sheetInterface.sheetAnalysisInterface.edbAddBysheet(params)
+
+      this.loading.close();
+      if(res.Ret !== 200) return
+
+      this.$message.success(res.Msg)
+
+      if(!edbInfoId) this.$refs.createTargetRef.initData();
+
+      this.getTargetList()
+    },
+
+    /* 获取生成指标列表 */
+    async getTargetList() {
+      const res = await sheetInterface.sheetAnalysisInterface.edbListBySheet({
+        ExcelInfoId: this.sheetDetailInfo.ExcelInfoId
+      })
+
+      if(res.Ret !== 200) return
+      
+      this.edbList = res.Data || [];
+    },
+
+    /* 选择指标列表更新表单信息和区域选中 */
+    chooseEdbHandle() {
+
+      if(this.$refs.edbWrapRef.selectEdb.EdbInfoId) {
+        this.$refs.createTargetRef.initData(this.$refs.edbWrapRef.selectEdb)
+      } else {
+        this.$refs.createTargetRef.initData()
+      }
+    }
+    
+  },
+  mounted() {
+    this.getClassify();
+    //上传文件的解析渲染
+    if(this.files) {
+      this.uploadSheetsList =  Object.values(this.files);
+      this.handelTranslateData()
+      this.$store.commit('sheet/SET_UPLOADFIlES',null)
+    }
+
+    //详情的渲染
+    if(this.$route.query.code) this.getDetailHandle();
+  }
+}
+</script>
+<style scoped lang="scss">
+*{ box-sizing: border-box; }
+.addSheet-wrap {
+  min-height: calc(100vh - 120px);
+  .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;
+      li {
+        margin-right: 30px;
+      }
+    }
+  }
+  .main {
+    display: flex;
+    position: relative;
+    min-height: 700px;
+    .left-section {
+      flex:1;
+      .sheet-wrapper {
+        position: relative;
+        background: #fff;
+        min-height: 700px;
+      }
+    
+    }
+    &.full-height {
+      min-height: calc(100vh - 120px);
+    }
+  }
+}
+</style>
+<style lang="scss">
+.addSheet-wrap {
+  .el-tabs__nav {
+    background: #fff;
+  }
+  .el-tabs__header {
+    margin-bottom: 0;
+    // border-bottom: none;
+  }
+}
+</style>

+ 130 - 0
src/views/datasheet_manage/customAnalysis/components/bottomSection.vue

@@ -0,0 +1,130 @@
+<template>
+  <div class="bottom-section">
+
+    <!-- 无同名 -->
+    <div>
+      <div class="page-list" v-if="sheetPages.length">
+        <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange" style="margin-right:30px">全部</el-checkbox>
+        <el-checkbox-group v-model="sheetChecked" @change="handleCheckedChange">
+          <el-checkbox v-for="item in sheetPages" :label="item" :key="item">{{item}}</el-checkbox>
+        </el-checkbox-group>
+      </div>
+
+      <div>
+        <el-select 
+          v-model="select_classify"
+          placeholder="请选择表格目录"
+          clearable
+          style="width:350px;"
+        >
+          <el-option
+            v-for="item in classifyArr"
+            :key="item.ExcelClassifyId"
+            :label="item.ExcelClassifyName"
+            :value="item.ExcelClassifyId"
+          />
+        </el-select>
+        <el-button type="primary" style="margin-left:30px" @click="saveSheetHandle">保存</el-button>
+          <el-tooltip class="item" effect="dark" content="根据用户选择的sheet页上传文件" placement="top-start">
+          <i class="el-icon-warning"/>
+        </el-tooltip>
+      </div>
+    </div>
+
+    <!-- 有同名文件 -->
+    <!-- <div>
+      <div class="same-page-item">
+        <label>
+          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
+            <path d="M14.7136 12.8013L9.22087 2.90725C8.54904 1.69758 7.45106 1.69758 6.77941 2.90725L1.28669 12.8013C0.615035 14.0122 1.16452 15 2.5069 15H13.4933C14.8357 15 15.3846 14.0121 14.7136 12.8013ZM7.2457 5.71459C7.44308 5.49263 7.69402 5.38164 8.00006 5.38164C8.30627 5.38164 8.55698 5.49146 8.75456 5.71015C8.95086 5.92933 9.04898 6.20343 9.04898 6.53305C9.04898 6.81664 8.63924 8.902 8.50257 10.4191H7.51565C7.39579 8.90199 6.95119 6.81664 6.95119 6.53305C6.95122 6.20844 7.0495 5.93546 7.2457 5.71459ZM8.74074 12.9285C8.53313 13.1387 8.28608 13.2435 8.00013 13.2435C7.71426 13.2435 7.46714 13.1387 7.25956 12.9285C7.05256 12.7186 6.94967 12.4645 6.94967 12.166C6.94967 11.8691 7.05256 11.6123 7.25956 11.397C7.46714 11.1816 7.71426 11.0739 8.00013 11.0739C8.28608 11.0739 8.53313 11.1816 8.74074 11.397C8.94761 11.6123 9.05074 11.8691 9.05074 12.166C9.05074 12.4645 8.94761 12.7186 8.74074 12.9285Z" fill="#E37318"/>
+          </svg>
+          下列sheet页同名,勾选可替换页面内容
+          <span style="color:#999">(不勾选则拼接原内容+上传内容,不去重)</span>
+        </label>
+        <div class="page-list">
+          <el-radio v-model="item.checked" v-for="item in sheetPages" :key="item">{{item}}</el-radio>
+        </div>
+      </div>
+      <div class="same-page-item">
+        <label>
+          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
+            <path d="M14.7136 12.8013L9.22087 2.90725C8.54904 1.69758 7.45106 1.69758 6.77941 2.90725L1.28669 12.8013C0.615035 14.0122 1.16452 15 2.5069 15H13.4933C14.8357 15 15.3846 14.0121 14.7136 12.8013ZM7.2457 5.71459C7.44308 5.49263 7.69402 5.38164 8.00006 5.38164C8.30627 5.38164 8.55698 5.49146 8.75456 5.71015C8.95086 5.92933 9.04898 6.20343 9.04898 6.53305C9.04898 6.81664 8.63924 8.902 8.50257 10.4191H7.51565C7.39579 8.90199 6.95119 6.81664 6.95119 6.53305C6.95122 6.20844 7.0495 5.93546 7.2457 5.71459ZM8.74074 12.9285C8.53313 13.1387 8.28608 13.2435 8.00013 13.2435C7.71426 13.2435 7.46714 13.1387 7.25956 12.9285C7.05256 12.7186 6.94967 12.4645 6.94967 12.166C6.94967 11.8691 7.05256 11.6123 7.25956 11.397C7.46714 11.1816 7.71426 11.0739 8.00013 11.0739C8.28608 11.0739 8.53313 11.1816 8.74074 11.397C8.94761 11.6123 9.05074 11.8691 9.05074 12.166C9.05074 12.4645 8.94761 12.7186 8.74074 12.9285Z" fill="#E37318"/>
+          </svg>
+          下列sheet页不同名,勾选可新增sheet页
+          <span style="color:#999">(不勾选则不新增)</span>
+        </label>
+        <div class="page-list">
+          <el-radio v-model="item.checked" v-for="item in sheetPages" :key="item">{{item}}</el-radio>
+          
+        </div>
+      </div>
+
+      <el-button type="primary">保存</el-button>
+    </div> -->
+
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    sheetList: {
+      type: Array
+    },
+    classifyArr: {
+      type: Array
+    }
+  },
+  watch: {
+    sheetList(nval) {
+      this.sheetPages = nval.map(_ => _.name)
+      this.sheetChecked = this.sheetPages;
+    }
+  },
+  data() {
+    return {
+      isIndeterminate: false,
+      checkAll: true,
+      sheetPages: [],
+      sheetChecked: [],
+
+      select_classify: '',
+      classifyArr: this.classifyArr,
+    }
+  },
+  methods:{
+    saveSheetHandle() {
+      if(!this.sheetChecked.length) return this.$message.warning('请选择要保存的sheet页')
+      if(!this.select_classify) return this.$message.warning('请选择分类')
+
+      this.$emit('save')
+    },
+
+    handleCheckedChange(val){
+      this.checkAll = val.length === this.sheetPages.length;
+      this.isIndeterminate = val.length > 0 && val.length < this.sheetPages.length;
+      console.log(this.sheetChecked)
+    },
+    handleCheckAllChange(val){
+      this.sheetChecked = val ? this.sheetPages : [];
+      this.isIndeterminate = false;
+    },
+  },
+}
+</script>
+<style scoped lang='scss'>
+.bottom-section {
+  background: #fff;
+  padding: 20px 20px 50px;
+  border-radius: 4px;
+  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
+  .page-list  {
+    display: flex;
+    align-items: center;
+    margin: 10px 0;
+    margin-bottom: 30px;
+  }
+  .btn-bottom {
+    margin-top: 20px;
+  }
+}
+</style>

+ 261 - 0
src/views/datasheet_manage/customAnalysis/components/createTargetForm.vue

@@ -0,0 +1,261 @@
+<template>
+  <div class="create-form-cont">
+    <el-form
+      ref="formRef"
+      label-position="left"
+      hide-required-asterisk
+      inline
+      label-width="0"
+      :model="formData"
+      :rules="formRules"
+    >
+      <el-form-item prop="dateSeries">
+        <el-input v-model="formData.dateSeries" placeholder="请选择日期序列" @focus="selectArea='date'" @change="changeFormat('date')" @keyup.native="e => { e.keyCode===13 && initSelect()}" :class="{'select': selectArea==='date'}"></el-input>
+      </el-form-item>
+      <el-form-item prop="valueSeries">
+        <el-input v-model="formData.valueSeries" placeholder="请选择数值序列" @focus="selectArea='value'" @change="changeFormat('value')" @keyup.native="e => { e.keyCode===13 && initSelect()}" :class="{'select': selectArea==='value'}"></el-input>
+      </el-form-item>
+
+      <el-form-item prop="edbName">
+        <el-input v-model="formData.edbName" placeholder="指标名称" @focus="initSelect"></el-input>
+      </el-form-item>
+      <el-form-item prop="classify">
+        <el-cascader
+          v-model="formData.classify"
+          :options="classifyOption"
+          style="width: 100%"
+          @focus="initSelect"
+          :props="{
+            label: 'ClassifyName',
+            value: 'ClassifyId',
+            children: 'Children',
+            emitPath: false,
+            checkStrictly: true
+          }"
+          clearable
+          placeholder="请选择所属目录"
+        />
+      </el-form-item>
+      <el-form-item prop="frequency">
+        <el-select
+          v-model="formData.frequency"
+          placeholder="请选择频率"
+          style="width: 100%"
+          @focus="initSelect"
+          clearable
+        >
+          <el-option
+            v-for="item in frequencyArr"
+            :key="item"
+            :label="item"
+            :value="item"
+          >
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item prop="unit">
+        <selectUnit v-model="formData.unit" @click.native="initSelect"/>
+      </el-form-item>
+      
+      <el-form-item>
+        <el-button type="primary" @click="handleSaveTarget">保存</el-button>
+        <el-button type="primary" plain @click="$parent.backHandle('into-detail')">返回</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+<script>
+import {dataBaseInterface} from '@/api/api.js'
+export default {
+  data() {
+    return {
+      selectArea: '',
+      formData: {
+        edbInfoId: 0,
+        dateSeries: '',
+        valueSeries: '',
+        dateArr:[],
+        valueArr: [],
+				edbName:'',
+				classify:'',
+				frequency: '',
+				unit:'',
+      },
+      formRules: {
+        // dateSeries: [{ required: true, message: '日期序列不能为空', trigger: 'blur' }],
+        // valueSeries: [{ required: true, message: '数值序列不能为空', trigger: 'blur' }],
+        edbName: [{ required: true, message: '指标名称不能为空', trigger: 'blur' }],
+        classify: [{ required: true, message: '目录不能为空', trigger: 'blur' }],
+        frequency: [{ required: true, message: '频率不能为空', trigger: 'blur' }],
+        unit: [{ required: true, message: '单位不能为空', trigger: 'blur' }],
+      },
+      frequencyArr:['日度','周度','旬度','月度','季度','年度'],
+      classifyOption: [],
+
+      isLockUpdate: false,//防止手动改变公式设置选区出发hook事件又更新公式和值 手动设置值即可
+    };
+  },
+  methods: {
+
+    /* 选区时更新公式 */
+    setFormula(formula,arr) {
+      if(!this.selectArea) return
+      //更新日期序列公式
+      if(this.selectArea === 'date') {
+        this.formData.dateArr = arr;
+        this.formData.dateSeries = formula
+      }else if(this.selectArea === 'value') {
+        //更新数值序列公式
+        this.formData.valueArr = arr;
+         this.formData.valueSeries = formula
+      }
+
+      console.log(this.formData)
+    },
+
+    /* 获取分类 */
+		getMenu() {
+			dataBaseInterface.menuListV3().then((res) => {
+				if (res.Ret !== 200) return
+        this.filterNodes(res.Data.AllNodes||[]);
+				this.classifyOption = res.Data.AllNodes || [];
+			});
+		},
+    
+    filterNodes(arr) {
+			arr.length &&
+				arr.forEach((item) => {
+					item.Children.length && this.filterNodes(item.Children);
+					if (!item.Children.length) {
+						delete item.Children;
+					}
+				});
+		},
+
+    /* 改变公式 */
+    changeFormat(type) {
+      this.isLockUpdate = true;
+      this.setRangeShow(type==='date'?this.formData.dateSeries:this.formData.valueSeries)
+      
+      let rangeArr = luckysheet.getRangeAxis();
+
+      //检查选取是否满足同行/同列
+      if(!this.$parent.checkRangeVaild(rangeArr[0])){
+        type==='date'?this.formData.dateSeries = '':this.formData.valueSeries ='';
+        return this.$message.warning('序列只允许选择同行或同列');
+      } 
+
+      let rangeCells = luckysheet.getRangeValue().flat().map(_=>_?_.m:'');
+      //更新公式关联的数据数组
+      type==='date' ? this.formData.dateArr = rangeCells : this.formData.valueArr = rangeCells;
+      console.log(this.formData)
+      this.isLockUpdate = false;
+    },
+
+    initSelect() {
+      this.selectArea = ''
+    },
+
+    initData(data=null) {
+      this.initSelect()
+      if(data) {
+        this.formData = {
+          edbInfoId: data.EdbInfoId,
+          dateSeries: data.DateSequenceStr,
+          valueSeries: data.DataSequenceStr,
+          dateArr:[],
+          valueArr: [],
+          edbName: data.EdbName,
+          classify: data.ClassifyId,
+          frequency: data.Frequency,
+          unit: data.Unit,
+        }
+
+        this.setRangeShow([data.DateSequenceStr,data.DataSequenceStr]);
+      }else {
+        this.formData = {
+          edbInfoId: 0,
+          dateSeries: '',
+          valueSeries: '',
+          dateArr:[],
+          valueArr: [],
+          edbName:'',
+          classify:'',
+          frequency: '',
+          unit:'',
+        }
+        
+        this.setRangeShow(['A1','A1'])
+      }
+    },
+
+    /* 解析公式显示选区 */
+    setRangeShow(range) {
+      
+      //初始化多选区
+      let rangeArr = [];
+      if(Array.isArray(range)) {
+        range.forEach(_ => {
+          rangeArr.push(this.splitFormula(_))
+        })
+      }else {
+        rangeArr = [this.splitFormula(range)]
+      }
+      luckysheet.setRangeShow(rangeArr)
+    },
+
+    /* 解析公式 */
+    splitFormula(formula) {
+      let str = formula.substr(formula.indexOf('!')+1).replace(/\$/g,'')
+      return str
+    },
+
+    /* 保存 */
+    handleSaveTarget: _.debounce(async function() {
+      if(!this.formData.dateSeries) return this.$message.warning('日期序列不能为空')
+      if(!this.formData.valueSeries) return this.$message.warning('数值序列不能为空')
+
+      await this.$refs.formRef.validate();
+      this.initSelect();
+      this.$emit('save')
+    },300),
+  },
+  
+  mounted() {
+    this.getMenu()
+  },
+};
+</script>
+<style scoped lang="scss">
+.create-form-cont {
+  background: #fff;
+  margin-bottom: 20px;
+  display: flex;
+  flex-wrap: wrap;
+  padding: 20px;
+  .el-form-item {
+    margin-bottom: 20px;
+    /* .select {
+      &::before {
+        content: '';
+        position: absolute;
+        left: 0;
+        right: 0;
+        top: 0;
+        bottom: 0;
+        border: 2px dashed #18ad18;
+        border-radius: 4px;
+      }
+    } */
+  }
+}
+</style>
+
+<style lang="scss">
+  .create-form-cont {
+    .select .el-input__inner {
+       border: 2px dashed #18ad18;
+      border-radius: 4px;
+    }
+  }
+</style>

+ 118 - 0
src/views/datasheet_manage/customAnalysis/components/rightSection.vue

@@ -0,0 +1,118 @@
+<template>
+  <div class="right-section-wrapper">
+    <div class="create-cont">
+      <ul class="edb-list" v-if="edbList.length">
+        <li :class="['edb-item',{'selected':selectEdb.EdbInfoId===item.EdbInfoId}]" v-for="(item,index) in edbList" :key="index" @click="chooseEdb(item)">
+          <span>{{item.EdbName}}</span>
+          <div class="item-right">
+            <!-- <i class="el-icon-edit" style="margin-right:10px" @click.stop="editEdbSettingHandle"/> -->
+            <img :src="$icons.jupm_icon" class="jump-icon" @click.stop="linkToEdbBase(item)">
+          </div>
+        </li>
+      </ul>
+      <div style="padding-top: 50px;" v-else>
+        <tableNoData text="暂无指标"/>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    list: {
+      type: Array
+    }
+  },
+  watch: {
+    list(nval) {
+      this.edbList = nval;
+    }
+  },
+  data() {
+    return {
+      edbList:[],
+      selectEdb: {},
+    }
+  },
+  mounted(){
+
+  },
+  methods:{
+
+    chooseEdb(item) {
+      if(item.EdbInfoId === this.selectEdb.EdbInfoId) {
+        this.selectEdb = {};
+      }else {
+        this.selectEdb = item;
+      }
+
+      this.$emit('choose')
+    },
+
+    //跳转指标库
+    linkToEdbBase({UniqueCode,EdbInfoId,ClassifyId}) {
+      let {href} = this.$router.resolve({path:'/database', query: {
+        code: UniqueCode,
+        id: EdbInfoId,
+        classifyId:ClassifyId
+      }});
+			window.open(href,'_blank');
+    }
+  },
+}
+</script>
+<style scoped lang='scss'>
+@import"~@/styles/theme-vars.scss";
+.right-section-wrapper {
+  width: 360px;
+  flex-shrink: 0;
+  border-radius: 4px;
+  border: 1px solid #C8CDD9;
+  background: #FFF;
+  margin-left: 20px;
+  .create-cont {
+    .edb-list {
+      padding: 30px;
+      overflow-y: auto;
+      .edb-item {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        padding: 14px 20px;
+        margin: 10px 0;
+        border-radius: 4px;
+        border: 1px solid #C8CDD9;
+        background: #FFF;
+        &.selected { 
+          border-color: $theme-color; background: #ECF2FE;
+        }
+        .item-right {
+          display: flex;
+          align-items: center;
+          .jump-icon {
+            cursor: pointer;
+            &:hover {
+              opacity: 0.8;
+            }
+          }
+        }
+        .el-icon-edit {
+          font-size: 16px;
+          &:hover {
+            color: $theme-color;
+            cursor: pointer;
+          }
+        }
+      }
+    }
+  }
+}
+</style>
+<style lang="scss">
+.right-section-wrapper {
+  .el-form--label-top .el-form-item__label {
+    height: 20px;
+    line-height: 20px;
+  }
+} 
+</style>

+ 1092 - 0
src/views/datasheet_manage/customAnalysis/list.vue

@@ -0,0 +1,1092 @@
+<template>
+  <div class="dataSheet-container" v-if="showData">
+    <span
+      class="slide-icon slide-right"
+      @click="isSlideLeft = !isSlideLeft"
+      v-show="isSlideLeft"
+    >
+      <i class="el-icon-d-arrow-right"></i>
+    </span>
+    <div class="data-sheet-main" id="box">
+      <div class="main-left left" id="left" v-show="!isSlideLeft">
+        <div class="datasheet_top">
+          
+          <el-button
+            type="primary" 
+            style="margin-right:20px"
+            :loading="isUploadLoading"
+            @click="clickUpload"
+            v-if="permissionBtn.checkPermissionBtn(permissionBtn.etaTablePermission.etaTable_analysis_upload)"
+          >上传文件</el-button>
+          <input type="file" @change="fileSelected" id="file"  style="display: none;">
+          
+          <el-checkbox v-model="isShowMe"  @change="() => { getTreeData();getPublicList() }">只看我的</el-checkbox>
+        </div>
+        <div class="search-cont">
+          <el-select
+            v-model="search_txt"
+            ref="searchRef"
+            :filterable="!search_txt"
+            remote
+            clearable
+            placeholder="表格名称"
+            style="width: 100%"
+            :remote-method="searchHandle"
+            @focus="searchHandle('')"
+          >
+            <i slot="prefix" class="el-input__icon el-icon-search"></i>
+            <el-option
+              v-for="item in searchOptions"
+              :key="item.ExcelInfoId"
+              :label="item.ExcelName"
+              :value="item.ExcelInfoId"
+            >
+            </el-option>
+          </el-select>
+        </div>
+        <div class="tree-cont">
+          <el-tree
+            ref="treeRef"
+            class="target_tree"
+            :data="treeData"
+            node-key="UniqueCode"
+            :props="defaultProp"
+            :allow-drag="canDragHandle"
+            :allow-drop="canDropHandle"
+            :current-node-key="select_node"
+            :default-expanded-keys="defaultShowNodes"
+            draggable
+            :expand-on-click-node="false"
+            check-strictly
+            empty-text="暂无分类"
+            @node-expand="handleNodeExpand"
+            @node-collapse="handleNodeCollapse"
+            @current-change="nodeChange"
+            @node-drop="dropOverHandle"
+            @node-drag-end="dropMouseLeave"
+            @node-drag-leave="dropMouseLeave"
+            @node-drag-enter="dropMouseOver"
+          >
+            <span class="custom-tree-node" slot-scope="{ node, data }">
+              <el-input
+                ref="editVal"
+                style="width: 90px"
+                placeholder="请输入值"
+                class="label-input"
+                v-model="new_label"
+                v-if="data.isEdit&&isSheetBtnShow('classifyOpt_edit')"
+                @blur="changeValue(data)"
+              />
+              <span
+                @dblclick.stop="editNodeLabel(data)"
+                v-else
+                class="text_oneLine node_label"
+                :style="`width:${
+                  (select_node === data.UniqueCode && node.Nodewidth) || ''
+                }`"
+              >
+                <span>{{ data.ExcelClassifyName }}</span>
+              </span>
+              <span
+                style="display: flex; align-items: center"
+                v-if="select_node === data.UniqueCode"
+              >
+                <img
+                  src="~@/assets/img/data_m/move_ico.png"
+                  alt=""
+                  style="width: 14px; height: 14px; margin-right: 8px"
+                />
+                <img
+                  src="~@/assets/img/set_m/edit.png"
+                  alt=""
+                  style="width: 15px; height: 14px; margin-right: 8px"
+                  @click.stop="editNode(node, data)"
+                  v-if="!data.ExcelInfoId&&isSheetBtnShow('classifyOpt_edit')"
+                />
+                <img
+                  slot="reference"
+                  src="~@/assets/img/set_m/del.png"
+                  alt=""
+                  style="width: 14px; height: 14px"
+                  @click.stop="removeNode(node, data)"
+                  v-if="!data.ExcelInfoId&&isSheetBtnShow('classifyOpt_delete')"
+                />
+              </span>
+            </span>
+          </el-tree>
+          <div class="noDepart" @click="addLevelOneHandle" v-if="isSheetBtnShow('classifyOpt_edit')">
+            <img
+              src="~@/assets/img/set_m/add_ico.png"
+              alt=""
+              style="width: 16px; height: 16px; margin-right: 10px"
+            />
+            <span>添加表格分类</span>
+          </div>
+        </div>
+        <span
+          class="move-btn resize"
+          v-drag
+          id="resize"
+          @mousemove="dynamicNode && resetNodeStyle(dynamicNode)"
+        ></span>
+        <span class="slide-icon slide-left" @click="isSlideLeft = !isSlideLeft">
+          <i class="el-icon-d-arrow-left"></i>
+        </span>
+      </div>
+
+      <div
+        class="main-right"
+        id="right"
+        :style="isSlideLeft ? 'width:100%' : 'width:80%'"
+      >
+        <!-- 表格详情 -->
+        <div class="sheet-detail-wrapper" v-if="select_id" >
+          <div class="detail-top">
+            <span class="author"
+              >作者:{{ sheetDetailInfo.SysUserRealName }}</span
+            >
+            <el-input
+              ref="sheetEditTitRef"
+              style="width: 400px"
+              placeholder="请输入表格名称"
+              class="label-input"
+              v-model="sheet_title"
+              v-if="sheetDetailInfo.isEditTit"
+              @blur="changeValue(sheetDetailInfo, 'edit-tit')"
+            />
+            <span
+              class="sheet-name"
+              @click="editNodeLabel(sheetDetailInfo, 'edit-tit')"
+              v-else
+            >
+              {{ sheetDetailInfo.ExcelName }}
+              <i class="el-icon-edit"/>
+            </span>
+            <ul class="action-ul" v-if="sheetDetailInfo.Button">
+
+              <el-tooltip effect="dark" content="在当前表格选择日期列和数据列生成指标" placement="top-start">
+                  <li class="editsty" @click="HandleToPath" v-if="isSheetBtnShow('createedb')&&sheetDetailInfo.Button.OpEdbButton">生成指标</li>
+              </el-tooltip>
+
+              <el-tooltip effect="dark" content="根据表格保存的最新内容,更新当前表格生成的所有指标" placement="top-start">
+                  <li class="editsty" @click="refreshSheet" v-if="isSheetBtnShow('refresh')&&sheetDetailInfo.Button.RefreshEdbButton">刷新指标</li>
+              </el-tooltip>
+              <li class="editsty" @click="saveHandle" v-if="isSheetBtnShow('save')&&sheetDetailInfo.Button.OpButton">保存</li>
+              <li
+                class="editsty"
+                @click="saveOtherHandle"
+                v-if="isSheetBtnShow('otherSave')&&sheetDetailInfo.Button.CopyButton"
+              >
+                另存为
+              </li>
+              <li class="editsty" @click="downloadExcel
+              (sheetDetailInfo)" v-if="isSheetBtnShow('download')&&sheetDetailInfo.Button.DownloadButton">
+                下载
+              </li>
+              <li
+                class="deletesty"
+                v-if="isSheetBtnShow('del')&&sheetDetailInfo.Button.DeleteButton"
+                @click="delSheetHandle({cell:sheetDetailInfo, type:'del'})"
+              >
+                删除
+              </li>
+            </ul>
+          </div>
+
+          <!-- <dataLoading :loading="isSheetLoading"/> -->
+
+          <!-- 表格 -->
+          <div class="sheet-wrap">
+            <Sheet
+              ref="sheetRef"
+              v-if="sheetConfigOpt.data"
+              :option="sheetConfigOpt"
+              :sheetInfo="{
+                ExcelInfoId: sheetDetailInfo.ExcelInfoId,
+                ExcelName: sheetDetailInfo.ExcelName,
+                ExcelClassifyId: sheetDetailInfo.ExcelClassifyId,
+                Source: sheetDetailInfo.Source
+              }"
+            />
+          </div>
+        </div>
+
+         <!-- 列表 -->
+        <sheetListWrap
+          v-else
+          :total="sheet_total" 
+          :list="sheetList" 
+          @loadMoreHandle="loadMoreHandle"
+          @detailShowHandle="detailShowHandle"
+          @delSheetHandle="delSheetHandle"
+          @downloadExcel="downloadExcel"
+          ref="sheetListWrap"
+        />
+      </div>
+
+      <dataLoading :loading="isSheetLoading"/>
+    </div>
+
+    <!-- 分类弹窗 -->
+    <classify-dia
+      :isOpenDialog.sync="classifyDia"
+      :title="dialog_title"
+      :form="classifyForm"
+      @successCallback="getTreeData"
+    />
+
+    <!-- 表格另存 -->
+    <m-dialog
+      :show.sync="isSaveOther"
+      width="650px"
+      title="另存为"
+      @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="表格名称" prop="name">
+            <el-input
+              v-model="saveOtherForm.name"
+              style="width: 80%"
+              placeholder="请输入表格名称"
+            />
+          </el-form-item>
+          <el-form-item label="表格分类" prop="classify">
+            <el-cascader
+              v-model="saveOtherForm.classify"
+              :options="classifyOptions"
+              :props="{
+                label: 'ExcelClassifyName',
+                value: 'ExcelClassifyId',
+                children: 'Children',
+                emitPath: false,
+              }"
+              style="width: 80%"
+              placeholder="请选择所属分类"
+              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"
+          >保存</el-button
+        >
+        <el-button type="primary" plain @click="cancelSaveOther"
+          >取消</el-button
+        >
+      </div>
+    </m-dialog>
+  </div>
+</template>
+
+<script>
+import * as sheetInterface from "@/api/modules/sheetApi.js";
+import leftMixin from "../mixins/classifyMixin";
+import mDialog from "@/components/mDialog.vue";
+import classifyDia from "../components/sheetClassifyDia.vue";
+import Sheet from "../components/SheetExcel.vue";
+import { getSheetImage } from "../common/option";
+import sheetListWrap from "../components/sheetListWrap.vue"
+export default {
+  name: "",
+  components: { mDialog, classifyDia, Sheet, sheetListWrap },
+  mixins: [leftMixin],
+  computed: {
+    downExcelFileUrl() {
+      let url = `${
+        process.env.VUE_APP_API_ROOT
+      }/datamanage/excel_info/table/download?${localStorage.getItem("auth")}`;
+      return url;
+    },
+    classifyOptions() {
+      let options = this.treeData.map((_) => ({
+        ExcelClassifyId: _.ExcelClassifyId,
+        ExcelClassifyName: _.ExcelClassifyName,
+      }));
+
+      return options;
+    },
+  },
+  data() {
+    return {
+      showData: false,
+      search_txt: "",
+      searchOptions: [],
+      isSlideLeft: false, //左侧分类收起
+
+      select_node: "", //节点唯一标识code
+      select_classify: "",
+      new_label: "", //双击修改的value
+      treeData: [], //分类数据
+      defaultShowNodes: [], //展开节点
+      defaultProp: {
+        label: "ExcelClassifyName",
+        children: "Children",
+      }, //树结构配置项
+      dynamicNode: null,
+
+      /* 分类弹窗 */
+      dialog_title: "",
+      classifyDia: false, //
+      classifyForm: {},
+
+      select_id: "", //选中的表格id
+      sheetDetailInfo: {},
+      sheet_title: "", //表格标题 双击标题修改时来存储最新值
+      sheetConfigOpt: {
+        showsheetbar: true,
+        data: null
+      },
+      sheetDataPage: 2,
+      sheetAllcellData:[],//全部单元格数据 分页push
+      dataToalPage: 0,
+      isSheetLoading: false,
+
+      /* 表格列表 */
+      publicHaveMove: true, //是否还有列表数据
+      sheetList: [],
+      sheet_total: 0,
+      sheet_page: 1,
+      sheet_pages_size: 16,
+
+      /* 另存为 */
+      isSaveOther: false,
+      saveOtherForm: {
+        name: '',
+				classify: ''
+      },
+      saveOtherFormRule: {
+        name: [
+          { required: true, message: "表格名称不能为空", trigger: "blur" },
+        ],
+        classify: [
+          { required: true, message: "表格分类不能为空", trigger: "blur" },
+        ],
+      },
+
+      isShowMe: false,
+
+      sourceMap: {
+        '/sheetAnalysisList': 4,
+      },
+    };
+  },
+  watch: {
+    /* 设置动态右侧区域宽度 */
+    isSlideLeft(newval) {
+      this.select_id && this.$refs.sheetRef && this.$refs.sheetRef.init();
+      this.$nextTick(() => {
+        this.reloadRightWid();
+      });
+    },
+    /* 表格id */
+    select_id(newval) {
+      this.sheetDataPage = 2,
+      this.sheetAllcellData = [],//全部单元格数据 分页push
+      this.dataToalPage = 0;
+      this.sheetConfigOpt.data = null;
+      newval && this.getDetailHandle();
+    },
+
+    select_classify(newval) {
+      if (this.$refs.sheetListWrap) this.$refs.sheetListWrap.$refs.listRef.scrollTop = 0;
+      if (newval) {
+        this.sheet_page = 1;
+        this.getPublicList();
+      }
+    },
+
+    /* 搜索关键词 */
+    search_txt(newval) {
+      if (newval) {
+        let search_obj = this.searchOptions.find(
+          (_) => _.ExcelInfoId === newval
+        );
+        let deep_arr = _.cloneDeep(this.treeData);
+        // 查找图表的分类父级id
+        let arr = this.findParentNodeHandle(deep_arr, search_obj.UniqueCode)
+          .slice(1)
+          .reverse(); // 父的父的父-父的父-父
+        this.defaultShowNodes = arr;
+        this.select_node = search_obj.UniqueCode;
+        this.$refs.treeRef.setCurrentKey(this.select_node);
+        // 重置筛选状态
+        this.select_id = newval;
+      }
+    },
+  },
+  methods: {
+
+    /* 获取表格分类 */
+    getTreeData(params = null) {
+      sheetInterface.classifyList({Source: this.sourceMap[this.$route.path],IsShowMe: this.isShowMe}).then((res) => {
+        const { Ret, Data } = res;
+        if (Ret !== 200) return;
+
+        this.showData = true;
+        this.treeData = Data.AllNodes || [];
+        this.$nextTick(() => {
+          /* 新增完成后 处理树展开和选中 */
+          params && this.selectCurrentNode(params);
+        });
+      });
+    },
+
+    /* 搜索表格 */
+    searchHandle(query) {
+      if (query) {
+        /* 查找列表 */
+        sheetInterface
+          .sheetList({
+            Keyword: query,
+            CurrentIndex: 1,
+            PageSize: 10000,
+            Source: this.sourceMap[this.$route.path]
+          })
+          .then((res) => {
+            if (res.Ret !== 200) return;
+            this.searchOptions = res.Data.List || [];
+          });
+      } else {
+        this.searchOptions = [];
+      }
+    },
+
+    /* 选中分类变化时 */
+    nodeChange({ UniqueCode, ExcelInfoId, ExcelClassifyId }, node) {
+      this.search_txt = "";
+      this.select_node = UniqueCode;
+      this.select_classify = !ExcelInfoId ? ExcelClassifyId : 0;
+      if (this.select_id !== ExcelInfoId) {
+        this.select_id = ExcelInfoId || 0;
+        this.sheetDetailInfo = {};
+      }
+      this.resetNodeStyle(node);
+      this.dynamicNode = node;
+    },
+
+    /* 添加一级目录 */
+    addLevelOneHandle() {
+      this.dialog_title = "添加";
+      this.classifyForm = {
+        classify_name: "",
+      };
+      this.classifyDia = true;
+    },
+
+    /* 编辑节点 */
+    editNode(node, { ExcelClassifyName, ExcelClassifyId }) {
+      this.dialog_title = "编辑";
+      /* 编辑目录 */
+      this.classifyForm = {
+        classify_name: ExcelClassifyName,
+        classify_id: ExcelClassifyId,
+      };
+      this.classifyDia = true;
+    },
+
+    /* 删除节点校验 */
+    async removeNode(node, { ExcelClassifyId, ExcelInfoId }) {
+      const { Data } = await sheetInterface.classifyDelCheck({
+        ExcelClassifyId,
+        ExcelInfoId,
+      });
+
+      const { DeleteStatus } = Data;
+
+      DeleteStatus === 1
+        ? this.$confirm("该分类下关联表格不可删除", "删除失败", {
+            confirmButtonText: "知道了",
+            showCancelButton: false,
+            type: "error",
+          })
+        : DeleteStatus === 0 && !ExcelInfoId
+        ? this.$confirm("确定删除当前分类吗?", "提示", {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning",
+          }).then(() => {
+            this.delApi(ExcelClassifyId, ExcelInfoId);
+          })
+        : null;
+    },
+
+    /* 删除方法 */
+    delApi(ExcelClassifyId, ExcelInfoId, type = "") {
+      sheetInterface
+        .classifyDel({
+          ExcelClassifyId,
+          ExcelInfoId,
+          Source: this.sourceMap[this.$route.path]
+        })
+        .then((res) => {
+          if (res.Ret !== 200) return;
+          this.$message.success(res.Msg);
+
+          if (!res.Data.ExcelInfoId) this.select_id = "";
+
+          //删除表格后自动显示下一张表格
+          type == "del" && res.Data.ExcelInfoId
+            ? this.getTreeData({
+                code: res.Data.UniqueCode,
+                id: res.Data.ExcelInfoId,
+              })
+            : this.getTreeData();
+
+          //删除封面
+          if (type === "del-list") {
+            let index = this.sheetList.findIndex(
+              (_) => _.ExcelInfoId === ExcelInfoId
+            );
+            this.sheetList.splice(index, 1);
+          }
+        });
+    },
+
+    /* 分类成功回调 */
+    classifyCallback(type) {
+      this.getTreeData();
+
+      if (type === "add") {
+        //新增分类完成之后,展开父节点显示刚新增的分类,若已展开节点则不做处理
+        let code = this.add_parent_id;
+        let flag = this.defaultShowNodes.some((item) => item === code);
+        // console.log(flag)
+        !flag && this.defaultShowNodes.push(code);
+        this.add_parent_id = "";
+      }
+    },
+
+    /* 展开对应菜单 显示详情 */
+    detailShowHandle({ UniqueCode, ExcelInfoId }) {
+      let params = {
+        code: UniqueCode,
+        id: ExcelInfoId,
+      };
+      this.selectCurrentNode(params);
+      this.select_classify = 0;
+    },
+
+    /* 下载数据 */
+    downloadExcel(cell) {
+      const { FileUrl, ExcelName } = cell;
+      this.downLoad(FileUrl, ExcelName);
+    },
+
+    downLoad(url, filename) {
+      const request = new window.XMLHttpRequest();
+      request.open("GET", url, true);
+      request.responseType = "blob";
+      request.onload = () => {
+        const url = window.URL.createObjectURL(request.response);
+        const a = document.createElement("a");
+        a.href = url;
+        a.target = "_blank";
+        a.download = filename;
+        a.style.display = "none";
+        document.body.append(a);
+        a.click();
+      };
+      request.send();
+    },
+
+    /* 保存表格 */
+    saveHandle: _.debounce(async function () {
+      luckysheet.exitEditMode();
+      let data = luckysheet.getAllSheets();
+
+      this.loading = this.$loading({
+        target: ".dataSheet-container",
+        lock: true,
+        text: "保存中...",
+        spinner: "el-icon-loading",
+        background: "rgba(255, 255, 255, 0.6)",
+      });
+
+      let img = getSheetImage(data[0]);
+      const form = new FormData();
+      form.append("Image", img);
+      const { Data } = await sheetInterface.uploadImg(form);
+
+      data.luckysheet_select_save = [];
+      const { ExcelInfoId, ExcelName, ExcelClassifyId } = this.sheetDetailInfo;
+      const res = await sheetInterface.sheetAnalysisInterface.sheetEdit({
+        ExcelInfoId,
+        ExcelName,
+        ExcelClassifyId,
+        ExcelImage: Data.ResourceUrl,
+        Content: JSON.stringify(data),
+      });
+      this.loading.close();
+      if (res.Ret !== 200) return;
+      this.$message.success("保存成功");
+      this.getTreeData();
+    }, 300),
+
+    /* 获取表格列表 */
+    getPublicList() {
+      sheetInterface
+        .sheetList({
+          CurrentIndex: this.sheet_page,
+          PageSize: this.sheet_pages_size,
+          ExcelClassifyId: this.select_classify || 0,
+          Source: this.sourceMap[this.$route.path],
+          IsShowMe: this.isShowMe 
+        })
+        .then((res) => {
+          if (res.Ret !== 200) return;
+
+          this.publicHaveMove = res.Data
+            ? this.sheet_page < res.Data.Paging.Pages
+            : false;
+          this.sheetList = res.Data
+            ? this.sheet_page === 1
+              ? res.Data.List
+              : [...this.sheetList, ...res.Data.List]
+            : [];
+          this.sheet_total = res.Data ? res.Data.Paging.Totals : 0;
+        });
+    },
+
+    /* 加载更多 */
+    loadMoreHandle: _.throttle(function () {
+      let scrollTop = this.$refs.sheetListWrap.$refs.listRef.scrollTop;
+      let clientHeight = this.$refs.sheetListWrap.$refs.listRef.clientHeight;
+      let scrollHeight = this.$refs.sheetListWrap.$refs.listRef.scrollHeight;
+      if (
+        scrollTop + clientHeight >= scrollHeight - 10 &&
+        this.publicHaveMove
+      ) {
+        this.sheet_page++;
+        this.getPublicList();
+      }
+    }, 300),
+
+    /* 获取表格详情 */
+    getDetailHandle() {
+      this.isSheetLoading = true;
+      sheetInterface.sheetAnalysisInterface.getExcelDetail({
+        UniqueCode: this.select_node,
+      }).then((res) => {
+        if (res.Ret !== 200) return;
+
+        this.sheetDetailInfo = res.Data.ExcelInfo;
+        this.dataToalPage =  Math.max(...res.Data.SheetList.map(_ => _.PageNum));
+        this.sheetAllcellData = res.Data.SheetList.map(_ => _.Data ? JSON.parse(_.Data.Data) : []);
+
+        this.getCellData(res.Data.SheetList)
+      });
+    },
+
+    //分页获取表格数据
+    async getCellData(sheets) {
+
+      let res = await sheetInterface.sheetAnalysisInterface.getExcelDataByPage({
+        UniqueCode: this.select_node,
+        Page: this.sheetDataPage
+      })
+
+      if(res.Ret !== 200) return
+      console.log(this.sheetAllcellData)
+
+      for(let i = 0;i<this.sheetAllcellData.length;i++) {
+        if(res.Data[i].Data) {
+          this.sheetAllcellData[i] = [...this.sheetAllcellData[i],...JSON.parse(res.Data[i].Data.Data)]
+        }
+
+        continue
+      }
+      
+      //数据继续加载或渲染表格.
+      if(this.sheetDataPage < this.dataToalPage) {
+        this.sheetDataPage++;
+        this.getCellData(sheets)
+      }else {
+        this.sheetConfigOpt.data = sheets.map((_,index) => ({
+          index: _.Index, //工作表id
+          order: _.Sort, //工作表的下标
+          name: _.SheetName,
+          calcChain: _.CalcChain?JSON.parse(_.CalcChain):[],
+          config: JSON.parse(_.Config),
+          celldata: this.sheetAllcellData[index],
+        }))
+
+        console.log(this.sheetConfigOpt)
+
+        this.isSheetLoading = false;
+      }
+    },
+
+    /* 删除表格 */
+    delSheetHandle({cell, type = ""}) {
+      const { ExcelClassifyId, ExcelInfoId  } = cell;
+      this.$confirm("删除后该表格将不能再引用,确认删除吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          this.delApi(ExcelClassifyId, ExcelInfoId, type);
+        })
+        .catch(() => {});
+    },
+
+    /* 表格另存为 */
+    saveOtherHandle() {
+      this.saveOtherForm.name = this.sheetDetailInfo.ExcelName + "(1)";
+      this.isSaveOther = true;
+    },
+
+    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.sheetDetailInfo.ExcelInfoId,
+        ExcelName: name,
+        ExcelClassifyId: classify
+      });
+
+      if (res.Ret !== 200) return;
+
+      this.$message.success("保存成功");
+      this.cancelSaveOther();
+      this.getTreeData();
+    },
+
+    /* 刷新表格 */
+    refreshSheet: _.debounce(async function() {
+      let res = await sheetInterface.sheetAnalysisInterface.sheetRefresh({ExcelInfoId: this.sheetDetailInfo.ExcelInfoId})
+
+      if(res.Ret !== 200) return 
+      this.$message.success(res.Msg)
+    },300),
+
+    /* 重绘右侧区域宽度 */
+    reloadRightWid() {
+      let total_wid = $(".data-sheet-main")[0].offsetWidth;
+      let left = $("#left")[0].offsetWidth;
+      let rigtWid = total_wid - left - 20 + "px";
+      $("#right")[0].style.width = rigtWid;
+    },
+
+    clickUpload() {
+      $(`#file`).click()
+    },
+
+    //选择文件上传
+    async fileSelected(){ 
+      let file = document.getElementById('file').files[0];
+      if(file){
+        if(!file.name.includes('.xlsx')) return this.$message.warning("上传失败,格式不符合xlsx");
+        if(file.size > 5.1*1024*1024) return this.$message.warning("上传文件最大不能超过5M");
+
+
+        const res = await sheetInterface.sheetAnalysisInterface.checkSheetRepeat({ExcelName: file.name})
+        if(res.Data.IsFind) return this.$message.warning('已有同名文件,请上传新文件')
+
+        this.$store.commit('sheet/SET_UPLOADFIlES',[file])
+        this.$router.push({ path: '/addAnalysisSheet' });
+      } 
+		},
+
+    //跳转生成指标
+    HandleToPath() {
+      this.$router.push({ path: '/createTaregtBySheet',query: {
+        code: this.sheetDetailInfo.UniqueCode 
+      }});
+    }
+
+  },
+  mounted() {
+    if (this.$route.query.code) {
+      this.getTreeData({
+        code: this.$route.query.code,
+        id: Number(this.$route.query.id),
+      });
+    } else {
+      this.getTreeData();
+      this.getPublicList();
+    }
+
+    window.addEventListener("resize", this.reloadRightWid);
+  },
+  destroyed() {
+    window.removeEventListener("resize", this.reloadRightWid);
+  },
+};
+</script>
+<style lang="scss" scoped>
+* {
+  box-sizing: border-box;
+}
+$mini-font: 12px;
+$normal-font: 14px;
+.dataSheet-container {
+  .slide-icon {
+    padding: 20px 0;
+    /* display: block; */
+    box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.3);
+    border-radius: 5px;
+    cursor: pointer;
+    position: absolute;
+    top: 50%;
+    transform: translateY(-50%);
+    z-index: 99;
+    &:hover {
+      background-color: rgba(0, 0, 0, 0.05);
+    }
+    &.slide-left {
+      right: 0;
+    }
+    &.slide-right {
+      left: 0;
+    }
+  }
+  .data-sheet-main {
+    display: flex;
+    position: relative;
+
+    .main-left {
+      width: 400px;
+      min-width: 350px;
+      background: #fff;
+      margin-right: 20px;
+      border: 1px solid #ececec;
+      border-radius: 4px;
+      box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.05);
+      height: calc(100vh - 120px);
+      overflow: hidden;
+      position: relative;
+      box-sizing: border-box;
+
+      .datasheet_top {
+        padding: 20px;
+        background: #fff;
+        border: 1px solid #ececec;
+        box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
+        margin-bottom: 20px;
+      }
+      .search-cont {
+        padding: 0 20px;
+      }
+
+      .tree-cont {
+        padding: 30px 20px;
+        max-height: calc(100vh - 280px);
+        overflow: auto;
+      }
+      .target_tree {
+        color: #333;
+        .custom-tree-node {
+          display: flex !important;
+          justify-content: space-between;
+          align-items: center;
+          display: block;
+          flex: 1;
+          .node_label {
+            margin-right: 2px;
+          }
+          .el-icon-view {
+            color: #409eff;
+            font-size: 18px;
+            margin-left: 5px;
+          }
+        }
+      }
+      .noDepart {
+        margin: 60px 0;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        color: #409eff;
+        font-size: 16px;
+        cursor: pointer;
+      }
+      .move-btn {
+        height: 100%;
+        width: 4px;
+        /* opacity: 0; */
+        position: absolute;
+        right: 0px;
+        top: 0;
+        &:hover {
+          cursor: col-resize;
+          /* background-color: orange */
+        }
+      }
+    }
+
+    .main-right {
+      width: 80%;
+      position: relative;
+      .sheet-detail-wrapper {
+        height: 100%;
+        border: 1px solid #ececec;
+        border-radius: 4px;
+        box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.05);
+        overflow: auto;
+        background: #fff;
+        .detail-top {
+          padding: 20px;
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          border-bottom: 1px solid #ececec;
+          .sheet-name {
+            font-size: 17px;
+            cursor: pointer;
+            max-width: 450px;
+            &:hover {
+              text-decoration: underline;
+            }
+          }
+          .action-ul {
+            display: flex;
+            li {
+              margin: 0 10px;
+            }
+          }
+        }
+        .sheet-wrap {
+          position: relative;
+          height: calc(100vh - 190px);
+          padding: 15px;
+          /* min-height: 500px; */
+        }
+      }
+
+      .sheet-list-cont {
+        color: #333;
+        .el-card .el-card__header,
+        .el-card__body {
+          padding: 10px;
+        }
+
+        .sheetlist-wrapper {
+          margin-top: 10px;
+          display: flex;
+          flex-wrap: wrap;
+          max-height: calc(100vh - 143px);
+          overflow: hidden;
+          overflow-y: auto;
+          .drag-cont {
+            width: 100%;
+            display: flex;
+            flex-wrap: wrap;
+          }
+          .dragShdow {
+            box-shadow: 0 1px 8px rgba(64, 158, 255, 0.8);
+            opacity: 0.5;
+          }
+          .sheet-item {
+            .item-top {
+              display: flex;
+              justify-content: space-between;
+              align-items: center;
+              font-size: 16px;
+              font-weight: 600;
+            }
+            .chart-img {
+              width: 100%;
+              /* height: 230px; */
+              object-fit: contain !important;
+              cursor: pointer;
+            }
+            .item-bottom {
+              margin-top: 10px;
+              display: flex;
+              justify-content: space-between;
+              font-size: 12px;
+              color: #666;
+              .collected {
+                color: #f00;
+                cursor: pointer;
+              }
+              .join_txt {
+                color: #409eff;
+                cursor: pointer;
+              }
+            }
+          }
+        }
+        .nodata {
+          text-align: center;
+        }
+      }
+    }
+  }
+}
+</style>
+
+<style lang="scss">
+.dataSheet-container {
+  .label-input .el-input__inner {
+    height: 25px;
+    line-height: 25px;
+    padding: 0 10px;
+  }
+
+  .el-tree__drop-indicator {
+    height: 3px;
+    background-color: #409eff;
+  }
+  .el-tree-node__content {
+    margin-bottom: 14px !important;
+  }
+  .el-tree-node__children {
+    .el-tree-node {
+      /* margin-bottom: 8px !important; */
+      margin-bottom: 0px !important;
+      padding-left: 18px;
+    }
+    .el-tree-node__content {
+      margin-bottom: 5px !important;
+      padding-left: 0 !important;
+    }
+  }
+  .expanded.el-icon-caret-right:before {
+    content: url("~@/assets/img/set_m/down.png") !important;
+  }
+  .el-icon-caret-right:before {
+    content: url("~@/assets/img/set_m/slide.png") !important;
+  }
+  .el-tree-node__expand-icon.is-leaf.el-icon-caret-right:before {
+    content: "" !important;
+  }
+  .el-tree-node__expand-icon.expanded {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  .el-tree-node.is-current > .el-tree-node__content {
+    background-color: #f0f4ff !important;
+  }
+  .el-tree-node__content {
+    padding-right: 10px !important;
+  }
+}
+.sheet-classify-cascader .el-input {
+	width: 100%;
+}
+</style>

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

@@ -165,7 +165,7 @@ export default {
 
     /* 获取分类 */
     getClassify() {
-      sheetInterface.excelClassifyOne().then(res => {
+      sheetInterface.excelClassifyOne({Source: 2}).then(res => {
         if(res.Ret !==200) return
         
         this.classifyArr = res.Data.AllNodes || [];

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

@@ -117,7 +117,7 @@ export default {
 
     /* 获取分类 */
     getClassify() {
-      sheetInterface.excelClassifyOne().then(res => {
+      sheetInterface.excelClassifyOne({Source: 3}).then(res => {
         if(res.Ret !==200) return
         
         this.classifyArr = res.Data.AllNodes || [];

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

@@ -85,7 +85,9 @@ export default {
 		editNodeLabel(data,type='') {
       if(type === 'edit-tit') {
         if([2,3].includes(this.sheetDetailInfo.Source)) return
-        if(!this.permissionBtn.isShowBtn('etaTablePermission','etaTable_classifyOpt_edit')) return
+        // if(!this.permissionBtn.isShowBtn('etaTablePermission','etaTable_classifyOpt_edit')) return
+
+        if(!this.isSheetBtnShow('classifyOpt_edit')) return
         this.$set(data,'isEditTit',true)
         this.sheet_title = data.ExcelName;
         this.$nextTick(() => {
@@ -114,7 +116,8 @@ export default {
   
         this.new_label !== data.ClassifyName && sheetInterface.classifyEdit({
           ExcelClassifyId: data.ExcelClassifyId,
-          ExcelClassifyName: this.new_label
+          ExcelClassifyName: this.new_label,
+          Source: this.sourceMap[this.$route.path]
         }).then(res => {
           if(res.Ret !== 200) return
   
@@ -286,5 +289,38 @@ export default {
 
       return canDrop;
     },
+
+    //判断右侧列表的下载按钮是否显示
+    isDownLoadShow(cell){
+        const {checkPermissionBtn,etaTablePermission} = this.permissionBtn
+        const checkMap = {
+            1:etaTablePermission.etaTable_excel_download,
+            2:etaTablePermission.etaTable_customize_data_download,
+            3:etaTablePermission.etaTable_customize_mix_download,
+            4:etaTablePermission.etaTable_analysis_download
+        }
+        return checkPermissionBtn(checkMap[cell.Source])
+    },
+    //判断右侧列表的删除按钮是否显示
+    isDeleteShow(cell){
+        const {checkPermissionBtn,etaTablePermission} = this.permissionBtn
+        const checkMap = {
+            1:etaTablePermission.etaTable_excel_del,
+            2:etaTablePermission.etaTable_customize_data_del,
+            3:etaTablePermission.etaTable_customize_mix_del,
+            4:etaTablePermission.etaTable_analysis_del,
+        }
+        return checkPermissionBtn(checkMap[cell.Source])
+    },
+    //判断自定义表格-编辑,另存为,刷新按钮是否显示
+    isSheetBtnShow(type){
+      const sheetType = {
+        '/sheetList': 'etaTable_excel',
+        '/sheetTimeList': 'etaTable_customize_data',
+        '/sheetMixedList': 'etaTable_customize_mix',
+        '/sheetAnalysisList': 'etaTable_analysis'
+      }
+      return this.permissionBtn.isShowBtn('etaTablePermission',`${sheetType[this.$route.path]}_${type}`)
+    }
   },
 };

+ 76 - 139
src/views/datasheet_manage/sheetList.vue

@@ -10,20 +10,11 @@
     <div class="data-sheet-main" id="box">
       <div class="main-left left" id="left" v-show="!isSlideLeft">
         <div class="datasheet_top">
-          <el-button v-permission="permissionBtn.etaTablePermission.etaTable_excel"
-            type="primary" style="margin-right:20px" @click="goAddSheetHandle(1)"
+          <el-button v-if="permissionBtn.checkPermissionBtn(permissionBtn.etaTablePermission.etaTable_excel)&&sourceMap[$route.path]===1" type="primary" style="margin-right:20px" @click="goAddSheetHandle"
           >添加Excel表格</el-button >
+          <el-button v-if="permissionBtn.checkPermissionBtn(permissionBtn.etaTablePermission.etaTable_customize_data_sheetAdd)&&sourceMap[$route.path]===2" type="primary" style="margin-right:20px" @click="goAddSheetHandle">添加时间序列表格</el-button >
+          <el-button v-if="permissionBtn.checkPermissionBtn(permissionBtn.etaTablePermission.etaTable_customize_mix_sheetAdd)&&sourceMap[$route.path]===3" type="primary" @click="goAddSheetHandle">添加混合表格</el-button >
 
-          <el-dropdown v-if="isShowDataSheet||isShowMixSheet"
-            @command="goAddSheetHandle">
-            <el-button type="primary">
-              自定义表格<i class="el-icon-arrow-down el-icon--right"></i>
-            </el-button>
-            <el-dropdown-menu slot="dropdown">
-              <el-dropdown-item :command="2" v-if="isShowDataSheet">数据表格</el-dropdown-item>
-              <el-dropdown-item :command="3" v-if="isShowMixSheet">混合表格</el-dropdown-item>
-            </el-dropdown-menu>
-          </el-dropdown>
         </div>
         <div class="search-cont">
           <el-select
@@ -77,7 +68,7 @@
                 placeholder="请输入值"
                 class="label-input"
                 v-model="new_label"
-                v-if="data.isEdit&&permissionBtn.isShowBtn('etaTablePermission','etaTable_classifyOpt_edit')"
+                v-if="data.isEdit&&isSheetBtnShow('classifyOpt_edit')"
                 @blur="changeValue(data)"
               />
               <span
@@ -104,7 +95,7 @@
                   alt=""
                   style="width: 15px; height: 14px; margin-right: 8px"
                   @click.stop="editNode(node, data)"
-                  v-if="!data.ExcelInfoId&&permissionBtn.isShowBtn('etaTablePermission','etaTable_classifyOpt_edit')"
+                  v-if="!data.ExcelInfoId&&isSheetBtnShow('classifyOpt_edit')"
                 />
                 <img
                   slot="reference"
@@ -112,12 +103,12 @@
                   alt=""
                   style="width: 14px; height: 14px"
                   @click.stop="removeNode(node, data)"
-                  v-if="!data.ExcelInfoId&&permissionBtn.isShowBtn('etaTablePermission','etaTable_classifyOpt_delete')"
+                  v-if="!data.ExcelInfoId&&isSheetBtnShow('classifyOpt_delete')"
                 />
               </span>
             </span>
           </el-tree>
-          <div class="noDepart" @click="addLevelOneHandle" v-if="permissionBtn.isShowBtn('etaTablePermission','etaTable_classifyOpt_edit')">
+          <div class="noDepart" @click="addLevelOneHandle" v-if="isSheetBtnShow('classifyOpt_edit')">
             <img
               src="~@/assets/img/set_m/add_ico.png"
               alt=""
@@ -171,7 +162,7 @@
                 @click="saveHandle"
                 v-if="
                   sheetDetailInfo.Source === 1 &&
-                  sheetDetailInfo.Button.OpButton&&permissionBtn.isShowBtn('etaTablePermission','etaTable_excel_save')
+                  sheetDetailInfo.Button.OpButton&&isSheetBtnShow('save')
                 "
               >
                 保存
@@ -180,21 +171,21 @@
                 <li
                   class="editsty"
                   @click="goEditHandle"
-                  v-if="sheetDetailInfo.Button.OpButton&&isSheetBtnShow(sheetDetailInfo,'edit')"
+                  v-if="sheetDetailInfo.Button.OpButton&&isSheetBtnShow('edit')"
                 >
                   编辑
                 </li>
                 <li
                   class="editsty"
-                  @click="refreshSheet"
-                  v-if="sheetDetailInfo.Button.RefreshButton&&isSheetBtnShow(sheetDetailInfo,'refresh')"
+                  @click="refreshSheetEdb"
+                  v-if="sheetDetailInfo.Button.RefreshButton&&isSheetBtnShow('refresh')"
                 >
                   刷新
                 </li>
                 <li
                   class="editsty"
                   @click="saveOtherHandle"
-                  v-if="sheetDetailInfo.Button.CopyButton&&isSheetBtnShow(sheetDetailInfo,'otherSave')"
+                  v-if="sheetDetailInfo.Button.CopyButton&&isSheetBtnShow('otherSave')"
                 >
                   另存为
                 </li>
@@ -209,7 +200,7 @@
                   sheetDetailInfo.Button && sheetDetailInfo.Button.DeleteButton
                   &&isDeleteShow(sheetDetailInfo)
                 "
-                @click="delSheetHandle(sheetDetailInfo, 'del')"
+                @click="delSheetHandle({cell:sheetDetailInfo, type:'del'})"
               >
                 删除
               </li>
@@ -221,11 +212,18 @@
             <Sheet
               ref="sheetRef"
               v-if="sheetDetailInfo.Source === 1"
-              :option="sheetDetailInfo.Content"
+              :option="{
+                data: [{
+                  ...JSON.parse(sheetDetailInfo.Content),
+                  scrollTop: 0,
+                  scrollLeft: 0
+                }]
+              }"
               :sheetInfo="{
                 ExcelInfoId: sheetDetailInfo.ExcelInfoId,
                 ExcelName: sheetDetailInfo.ExcelName,
                 ExcelClassifyId: sheetDetailInfo.ExcelClassifyId,
+                Source: sheetDetailInfo.Source
               }"
             />
 
@@ -245,52 +243,17 @@
           </div>
         </div>
 
-        <!-- 列表 -->
-        <div class="sheet-list-cont" v-else>
-          <span>共{{ sheet_total }}张表格</span>
-          <div class="sheetlist-wrapper" ref="listRef" @scroll="loadMoreHandle">
-            <el-col
-              :span="6"
-              style="margin-bottom: 20px; padding-right: 20px"
-              v-for="cell in sheetList"
-              :key="cell.ExcelInfoId"
-            >
-              <el-card class="sheet-item">
-                <div slot="header" class="item-top">
-                  <span class="text_oneLine">{{ cell.ExcelName }}</span>
-                </div>
-                <img
-                  :src="cell.ExcelImage"
-                  alt=""
-                  class="chart-img"
-                  :height="imgHeight"
-                  @click="detailShowHandle(cell)"
-                />
-                <div class="item-bottom">
-                  <span>创建时间: {{ cell.CreateTime.slice(0, 10) }}</span>
-                  <div>
-                    <span
-                      v-if="isDownLoadShow(cell)"
-                      class="editsty"
-                      style="margin-right: 10px"
-                      @click="downloadExcel(cell)"
-                      >下载</span
-                    >
-                    <span
-                      v-if="isDeleteShow(cell)"
-                      class="deletesty"
-                      @click="delSheetHandle(cell, 'del-list')"
-                      >删除</span
-                    >
-                  </div>
-                </div>
-              </el-card>
-            </el-col>
-          </div>
-          <div v-if="!sheet_total" class="nodata">
-            <tableNoData text="暂无表格"/>
-          </div>
-        </div>
+         <!-- 列表 -->
+        <sheetListWrap
+          v-else
+          :total="sheet_total" 
+          :list="sheetList" 
+          @loadMoreHandle="loadMoreHandle"
+          @detailShowHandle="detailShowHandle"
+          @delSheetHandle="delSheetHandle"
+          @downloadExcel="downloadExcel"
+          ref="sheetListWrap"
+        />
       </div>
     </div>
 
@@ -366,9 +329,10 @@ import Sheet from "./components/SheetExcel.vue";
 import { getSheetImage } from "./common/option";
 import CustomTable from "./components/CustomTable.vue";
 import MixedTable from "./components/MixedTable.vue";
+import sheetListWrap from "./components/sheetListWrap.vue"
 export default {
   name: "",
-  components: { mDialog, classifyDia, Sheet, CustomTable, MixedTable },
+  components: { mDialog, classifyDia, Sheet, CustomTable, MixedTable,sheetListWrap },
   mixins: [leftMixin],
   computed: {
     downExcelFileUrl() {
@@ -431,7 +395,6 @@ export default {
       sheet_total: 0,
       sheet_page: 1,
       sheet_pages_size: 16,
-      imgHeight: 196,
 
       /* 另存为 */
       isSaveOther: false,
@@ -447,6 +410,12 @@ export default {
           { required: true, message: "表格分类不能为空", trigger: "blur" },
         ],
       },
+
+      sourceMap: {
+        '/sheetList': 1,
+        '/sheetTimeList': 2,
+        '/sheetMixedList': 3,
+      }
     };
   },
   watch: {
@@ -463,7 +432,7 @@ export default {
     },
 
     select_classify(newval) {
-      if (this.$refs.listRef) this.$refs.listRef.scrollTop = 0;
+      if (this.$refs.sheetListWrap) this.$refs.sheetListWrap.$refs.listRef.scrollTop = 0;
       if (newval) {
         this.sheet_page = 1;
         this.getPublicList();
@@ -491,9 +460,10 @@ export default {
   },
   methods: {
     /* 添加表格 */
-    goAddSheetHandle(type) {
-      if (!this.treeData.length)
-        return this.$message.warning("请先添加表格分类");
+    goAddSheetHandle() {
+      if (!this.treeData.length) return this.$message.warning("请先添加表格分类");
+      let type = this.sourceMap[this.$route.path];
+
       let path = {
         1: "/addsheet",
         2: "/addCustomSheet",
@@ -510,7 +480,7 @@ export default {
 
     /* 获取表格分类 */
     getTreeData(params = null) {
-      sheetInterface.classifyList().then((res) => {
+      sheetInterface.classifyList({Source: this.sourceMap[this.$route.path]}).then((res) => {
         const { Ret, Data } = res;
         if (Ret !== 200) return;
 
@@ -527,13 +497,12 @@ export default {
     searchHandle(query) {
       if (query) {
         /* 查找列表 */
-        sheetInterface
-          .sheetList({
+        sheetInterface.sheetList({
             Keyword: query,
             CurrentIndex: 1,
             PageSize: 10000,
-          })
-          .then((res) => {
+            Source: this.sourceMap[this.$route.path]
+          }).then((res) => {
             if (res.Ret !== 200) return;
             this.searchOptions = res.Data.List || [];
           });
@@ -607,6 +576,7 @@ export default {
         .classifyDel({
           ExcelClassifyId,
           ExcelInfoId,
+          Source: this.sourceMap[this.$route.path]
         })
         .then((res) => {
           if (res.Ret !== 200) return;
@@ -696,7 +666,8 @@ export default {
     /* 保存表格 */
     saveHandle: _.debounce(async function () {
       luckysheet.exitEditMode();
-      let data = luckysheet.getAllSheets()[0];
+      //结构类型乱飘 强制定义下
+      let data = {...luckysheet.getAllSheets()[0],status:Number(luckysheet.getAllSheets()[0].status)}
       if (!data.celldata.length) return this.$message.warning("请输入表格内容");
 
       this.loading = this.$loading({
@@ -731,32 +702,31 @@ export default {
 
     /* 获取表格列表 */
     getPublicList() {
-      sheetInterface
-        .sheetList({
-          CurrentIndex: this.sheet_page,
-          PageSize: this.sheet_pages_size,
-          ExcelClassifyId: this.select_classify || 0,
-        })
-        .then((res) => {
-          if (res.Ret !== 200) return;
-
-          this.publicHaveMove = res.Data
-            ? this.sheet_page < res.Data.Paging.Pages
-            : false;
-          this.sheetList = res.Data
-            ? this.sheet_page === 1
-              ? res.Data.List
-              : [...this.sheetList, ...res.Data.List]
-            : [];
-          this.sheet_total = res.Data ? res.Data.Paging.Totals : 0;
-        });
+      sheetInterface.sheetList({
+        CurrentIndex: this.sheet_page,
+        PageSize: this.sheet_pages_size,
+        ExcelClassifyId: this.select_classify || 0,
+        Source: this.sourceMap[this.$route.path]
+      }).then((res) => {
+        if (res.Ret !== 200) return;
+
+        this.publicHaveMove = res.Data
+          ? this.sheet_page < res.Data.Paging.Pages
+          : false;
+        this.sheetList = res.Data
+          ? this.sheet_page === 1
+            ? res.Data.List
+            : [...this.sheetList, ...res.Data.List]
+          : [];
+        this.sheet_total = res.Data ? res.Data.Paging.Totals : 0;
+      });
     },
 
     /* 加载更多 */
     loadMoreHandle: _.throttle(function () {
-      let scrollTop = this.$refs.listRef.scrollTop;
-      let clientHeight = this.$refs.listRef.clientHeight;
-      let scrollHeight = this.$refs.listRef.scrollHeight;
+      let scrollTop = this.$refs.sheetListWrap.$refs.listRef.scrollTop;
+      let clientHeight = this.$refs.sheetListWrap.$refs.listRef.clientHeight;
+      let scrollHeight = this.$refs.sheetListWrap.$refs.listRef.scrollHeight;
       if (
         scrollTop + clientHeight >= scrollHeight - 10 &&
         this.publicHaveMove
@@ -790,7 +760,8 @@ export default {
     },
 
     /* 删除表格 */
-    delSheetHandle({ ExcelClassifyId, ExcelInfoId }, type = "") {
+    delSheetHandle({cell, type = ""}) {
+      const { ExcelClassifyId, ExcelInfoId  } = cell;
       this.$confirm("删除后该表格将不能再引用,确认删除吗?", "提示", {
         confirmButtonText: "确定",
         cancelButtonText: "取消",
@@ -815,7 +786,7 @@ export default {
     },
 
     /* 刷新表格 */
-    refreshSheet: _.debounce(async function () {
+    refreshSheetEdb: _.debounce(async function () {
       const res = await sheetInterface.refreshCustomSheet({
         ExcelInfoId: this.sheetDetailInfo.ExcelInfoId,
       });
@@ -864,40 +835,6 @@ export default {
       let left = $("#left")[0].offsetWidth;
       let rigtWid = total_wid - left - 20 + "px";
       $("#right")[0].style.width = rigtWid;
-
-      !this.select_id &&
-        this.$nextTick(() => {
-          this.imgHeight =
-            $(".chart-img")[0].offsetWidth / 1.64 > 150
-              ? $(".chart-img")[0].offsetWidth / 1.64
-              : 150;
-        });
-    },
-    //判断右侧列表的下载按钮是否显示
-    isDownLoadShow(cell){
-        const {checkPermissionBtn,etaTablePermission} = this.permissionBtn
-        const checkMap = {
-            1:etaTablePermission.etaTable_excel_download,
-            2:etaTablePermission.etaTable_customize_data_download,
-            3:etaTablePermission.etaTable_customize_mix_download
-        }
-        return checkPermissionBtn(checkMap[cell.Source])
-    },
-    //判断右侧列表的删除按钮是否显示
-    isDeleteShow(cell){
-        const {checkPermissionBtn,etaTablePermission} = this.permissionBtn
-        const checkMap = {
-            1:etaTablePermission.etaTable_excel_del,
-            2:etaTablePermission.etaTable_customize_data_del,
-            3:etaTablePermission.etaTable_customize_mix_del
-        }
-        return checkPermissionBtn(checkMap[cell.Source])
-    },
-    //判断自定义表格-编辑,另存为,刷新按钮是否显示
-    isSheetBtnShow(cell,type){
-        console.log('cell',cell.Source)
-        const sheetType = cell.Source===2?'data':'mix'
-        return this.permissionBtn.isShowBtn('etaTablePermission',`etaTable_customize_${sheetType}_${type}`)
     }
   },
   mounted() {

+ 9 - 2
src/views/mychart_manage/components/chartDetailDia.vue

@@ -571,6 +571,8 @@ export default {
       bind(el, binding) {
         const clickHandle = (e)=>{
           //console.log(e.target.className)
+          //如果弹窗没打开就没必要执行了
+          if(!(this&&this.isOpenDetail)) return
           const isCurrentTarget = el.contains(e.target)||e.target.className==='el-popover el-popper'||['shareLink','copy'].some(str => e.target.className.includes(str))
           if(isCurrentTarget){
             return false
@@ -814,6 +816,10 @@ export default {
       this.tableData.forEach((item) => {
         let edbData = EdbInfoList.find(_ => _.EdbInfoId===item.EdbInfoId);
         item.DataList = edbData.DataList;
+        //更新起始时间和最近更新时间
+        item.StartDate = edbData.StartDate;
+        item.ModifyTime = edbData.ModifyTime;
+        
         if(edbData.EdbInfoCategoryType===1) item.MoveLatestDate = edbData.MoveLatestDate;
       });
     },
@@ -1063,9 +1069,10 @@ export default {
     saveChartMapHandle() {
       const sourceMap = {
         1: this.saveChartHandle,
-        2: this.saveCommodityChart
+        2: this.saveCommodityChart,
+        5: this.saveCommodityChart,//利润曲线
       }
-      sourceMap[this.chartInfo.Source]();
+      sourceMap[this.chartInfo.Source]&&sourceMap[this.chartInfo.Source]();
     },
 
     /* 商品价格图保存 */

+ 80 - 0
src/views/mychart_manage/components/classifyDeleteCheck.vue

@@ -0,0 +1,80 @@
+<template>
+    <el-dialog custom-class="classify-delete-wrap"
+        :visible.sync="hintDialogShow"
+        :close-on-click-modal="false"
+        :modal-append-to-body="false"
+        :append-to-body="false"
+        @close="$emit('close')"
+        center
+        width="400px"
+        v-dialogDrag
+    >
+        <div slot="title" style="display: flex; align-items: center;">
+            <i style="color:#FF8A00;font-size: 16px;" class="el-icon-warning"></i>
+            <span style="font-size: 16px;color:#333;margin-left: 5px;">提示</span>
+        </div>
+        <div class="dialog-container">
+            <p>该图分类已添加节点链接,不允许删除!</p>
+            <div class="frame-list">
+                <p class="frame-item" v-for="(item,index) in detailArr" :key="index" @click="goToFrameList(item)">
+                    {{index+1}}、{{item.FrameworkName}}({{item.NodeName}})
+                </p>
+            </div>
+        </div>
+        <div class="dialog-footer">
+            <el-button @click="$emit('close')">取消</el-button>
+            <el-button type="primary" @click="$emit('close')">确定</el-button>
+        </div>
+    </el-dialog>
+</template>
+
+<script>
+export default {
+    props:{
+        hintDialogShow:{
+            type:Boolean,
+            default:false
+        },
+        detailArr:{
+            type:Array,
+            default:[]
+        }
+    },
+    data() {
+        return {
+
+        };
+    },
+    methods: {
+        goToFrameList(item){
+            window.open(`/chartframe?frameId=${item.ChartFrameworkId}`);
+        }
+    },
+};
+</script>
+
+<style lang="scss">
+.classify-delete-wrap{
+    .el-dialog__header{
+        background-color: transparent;
+        border-bottom:1px solid #ECECEC;
+        .el-dialog__headerbtn>i{
+            color: #C0C4CC;
+        }
+
+    }
+    .dialog-container{
+        .frame-item{
+            cursor: pointer;
+            text-decoration: underline;
+            &:hover{
+                color:#0052D9;
+            }
+        }
+    }
+    .dialog-footer{
+        padding:25px 0;
+        text-align: right;
+    }
+}
+</style>

+ 57 - 9
src/views/mychart_manage/index.vue

@@ -261,6 +261,13 @@
       @close="chartCallBack"
       @remove="removeCallBack"
     />
+
+    <!-- 删除确认弹窗 -->
+    <ClassifyDeleteCheck 
+        :hintDialogShow="hintDialogShow"
+        :detailArr="detailArr"
+        @close="hintDialogShow=false"
+    />
   </div>
 </template>
 
@@ -270,14 +277,16 @@ import { mychartInterface } from '@/api/api.js';
 import pubDialog from '@/components/pubDialog.vue';
 import chooseChart from './components/chooseChart.vue';
 import chartDetail from './components/chartDetailDia.vue';
+import ClassifyDeleteCheck from './components/classifyDeleteCheck.vue';
 export default {
   name: '',
   components: {
     chooseChart,
     pubDialog,
     draggable,
-    chartDetail
-  },
+    chartDetail,
+    ClassifyDeleteCheck
+},
   directives: {
     drag(el, bindings) {
       el.onmousedown = function (e) {
@@ -374,6 +383,9 @@ export default {
       haveMove: false,
 
       chart_lang: 'ch',
+
+      hintDialogShow:false,
+      detailArr:[]
     };
   },
   computed: {
@@ -434,7 +446,7 @@ export default {
     getClassify() {
       mychartInterface.classifyList().then((res) => {
         if (res.Ret !== 200) return;
-        this.chart_lang = res.Data.Language === 'EN' ? 'en' : 'ch';
+        this.chart_lang = res.Data&&res.Data.Language === 'EN' ? 'en' : 'ch';
 
         this.classifyList = res.Data ? res.Data.List.map(item => ({
           ...item,
@@ -690,8 +702,8 @@ export default {
     /* 编辑 删除*/
     dealAction(key) {
       // this.isRightClick = false;
-      key === 'del' &&
-        this.$confirm(
+      key === 'del' && this.handleDeleteClassify()
+        /* this.$confirm(
           '若删除该分类,则分类下关联的所有图表将被全部删除, 是否继续?',
           '提示',
           {
@@ -710,17 +722,48 @@ export default {
                 this.$message.success('删除成功');
                 this.getClassify();
                 this.getPublicClassify();
-                // if (this.rightClick_classify === this.select_classify)
-                //   this.select_classify = '';
               });
           })
-          .catch(() => {});
-
+          .catch(() => {}); */
       const obj = this.classifyList.find(
         (x) => x.MyChartClassifyId === this.select_classify
       );
       key === 'edit' && this.editClassify(obj);
     },
+    async handleDeleteClassify(){
+        const res = await mychartInterface.getFrameNode({
+            MyChartClassifyId:this.select_classify
+        })
+        if(res.Ret!==200) return
+        this.detailArr = res.Data||[]
+        if(this.detailArr.length){
+            this.hintDialogShow = true
+            return
+        }
+        this.$confirm(
+          '若删除该分类,则分类下关联的所有图表将被全部删除, 是否继续?',
+          '提示',
+          {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning',
+          }
+        )
+          .then(() => {
+            mychartInterface
+              .delClassify({
+                MyChartClassifyId: this.select_classify,
+              })
+              .then((res) => {
+                if (res.Ret !== 200) return;
+                this.$message.success('删除成功');
+                this.getClassify();
+                this.getPublicClassify();
+              });
+          })
+          .catch(() => {});
+      
+    },
 
     /* 右键菜单打开 */
     // rightClickHandle({ MyChartClassifyId }, e) {
@@ -882,6 +925,11 @@ export default {
       : 0;
     this.ispublic=sessionStorage.getItem('myChartIspublic')? Number(sessionStorage.getItem('myChartIspublic')): '';
     }
+    //从图库框架跳转来的
+    if(this.$route.query.frameId){
+        this.select_classify = Number(this.$route.query.frameId)
+        this.ispublic = ''
+    }
     this.getClassify();
     this.getPublicClassify();
   },

+ 20 - 0
src/views/positionAnalysis_manage/components/chartDetail.vue

@@ -23,12 +23,26 @@
             >
           </el-radio-group>
         </div>
+        <div>
+            <el-date-picker
+                v-model="selectDate"
+                type="date"
+                placeholder="请选择日期"
+                value-format="yyyy-MM-dd"
+                :picker-options="pickerOption"
+                @change="$emit('handleOpt','date')"
+                style="margin-right: 10px"
+            />
+            <el-button type="primary" plain @click="$emit('handleOpt','beforeDate')">查看前一天</el-button>
+            <el-button type="primary" plain @click="$emit('handleOpt','nextDate')" :disabled="disabledNextBtn">查看后一天</el-button>
+        </div>
       </div>
       <div
         class="chart-wrap"
         v-if="chartItemInfo&&chartItemInfo.List && chartListState.BuyList.List"
       >
         <div class="top-info-box">
+          <span>{{$route.query.classify_type}}</span>
           <span>{{ chartItemInfo.name }}</span>
           <span
             ><span style="color: #999; margin-right: 2px">总计 </span
@@ -66,6 +80,11 @@ export default {
       },
     },
   },
+  props:{
+    disabledNextBtn:Boolean,
+    selectDate:String,
+    pickerOption:Object
+  },
   data() {
     return {
       isPcShow: true,
@@ -198,6 +217,7 @@ export default {
     },
 
     async getInfo() {
+      if(!this.$route.query.classify_name||!this.$route.query.classify_type) return
       this.pageLoading = true;
       const res = await apiPositionAnalysisInfo({
         DataTime: this.selectDate || "",

+ 19 - 17
src/views/positionAnalysis_manage/components/indexContent.vue

@@ -4,19 +4,12 @@
             <span style="margin-right:20px">{{num}}品种</span>
             <span>{{time}}</span>
         </div>
-        <div style="margin:30px 0">
-            <el-switch
-                v-model="isHistory"
-                size="large"
-                active-text="历史合约"
-            />
-        </div>
         <div class="list-wrap">
             <div class="item" v-for="item in clist" :key="item.ClassifyName">
                 <div class="label">{{item.ClassifyName}}</div>
-                <div style="flex:1">
+                <div style="margin-top:20px;">
                     <div 
-                        class="opt" 
+                        class="opt" :class="{'active':$route.query.classify_type===_item.ClassifyType}"
                         v-for="_item in item.Items" 
                         :key="_item.ClassifyType"
                         @click="goDetail(_item,item)"
@@ -34,12 +27,13 @@ export default {
     time:String,
     exchange:String,
     now:String,
-    list:null
+    list:null,
+    isHistory:Boolean
   },
   computed: {
     clist() {
       if(this.isHistory){
-          console.log('看历史');
+          /* console.log('看历史'); */
           return this.list
       }
 
@@ -74,8 +68,6 @@ export default {
   },
   data() {
     return {
-      isHistory: false,
-
     }
   },
 
@@ -86,7 +78,8 @@ export default {
           query:{
               classify_name:item.ClassifyName,
               classify_type:_item.ClassifyType,
-              exchange:this.exchange
+              exchange:this.exchange,
+              isHistory:this.isHistory
           }
       })      
     }
@@ -102,6 +95,8 @@ export default {
 <style lang="scss" scoped>
 @import '~@/styles/theme-vars.scss';
 .index-content-wrap{
+    display: flex;
+    flex-direction: column;
     .top-box{
         background: #e6eefb;
         padding: 15px 30px;
@@ -110,10 +105,13 @@ export default {
         }
     }
     .list-wrap{
-        padding: 30px 0;
+        padding: 30px;
+        height: 958px;
+        box-sizing: border-box;
+        overflow-y: auto;
         .item{
-            margin-bottom: 40px;
-            display: flex;
+            margin-bottom: 30px;
+            /* display: flex; */
 
             .label{
                 color: #666;
@@ -132,6 +130,10 @@ export default {
                 border: 1px solid $theme-color;
                 border-radius: 4px;
                 cursor: pointer;
+                &:hover,&.active{
+                    background-color: #0052D9;
+                    color: #FFFFFF;
+                }
             }
         }
     }

+ 141 - 23
src/views/positionAnalysis_manage/detail.vue

@@ -1,39 +1,76 @@
 <template>
   <div class="hasrightaside-box position-analysis-detail-page">
-    <div class="detail-top">
-      <div>
-          <el-date-picker
-            v-model="selectDate"
-            type="date"
-            placeholder="请选择日期"
-            value-format="yyyy-MM-dd"
-            :picker-options="pickerOption"
-            @change="handleOpt('date')"
-            style="margin-right: 10px"
-          />
-          <el-button type="primary" plain @click="handleOpt('beforeDate')">查看前一天</el-button>
-          <el-button type="primary" plain @click="handleOpt('nextDate')" :disabled="disabledNextBtn">查看后一天</el-button>
+    <div class="detail">
+        <div class="detail-top">
+            <div>
+                <!-- <el-button type="primary" @click="refreshData" plain>一键刷新</el-button> -->
+                <el-button type="primary" @click="handleOpt('beforeClassifyType')">上一个合约</el-button>
+                <el-button type="primary" @click="handleOpt('nextClassifyType')">下一个合约</el-button>
+            </div>
+        </div>
+        <div class="content-box detail-content">
+            <chartDetail ref="chartDetailRef" 
+                :disabledNextBtn="disabledNextBtn"
+                :selectDate="selectDate"
+                :pickerOption="pickerOption"
+                @setInfo="e => { selectDate=e.date;}"
+                @handleOpt="handleOpt"
+            />
         </div>
-      <div>
-        <!-- <el-button type="primary" @click="refreshData" plain>一键刷新</el-button> -->
-        <el-button type="primary" @click="handleOpt('beforeClassifyType')">上一个合约</el-button>
-        <el-button type="primary" @click="handleOpt('nextClassifyType')">下一个合约</el-button>
-      </div>
     </div>
-    <div class="content-box detail-content">
-        <chartDetail ref="chartDetailRef" @setInfo="e => { selectDate=e.date; }"/>
+    <div class="list" :class="{'expand-list':isSlide}">
+        <div class="header">
+            <span>持仓列表</span>
+            <div>历史合约
+                <el-switch
+                    v-model="isHistory"
+                    size="large"
+                />
+            </div>
+        </div>
+        <el-tabs 
+            class="tabs-wrap"
+            v-model="activeType"
+        >
+            <el-tab-pane 
+                v-for="item in list"
+                :key="item.Exchange"
+                :label="item.Exchange" 
+                :name="item.Exchange"
+            >
+                <indexContent 
+                  :list="item.Items" 
+                  :num="item.Num" 
+                  :time="item.DataTime" 
+                  :exchange="item.Exchange"
+                  :now="item.CurrDate"
+                  :isHistory="isHistory"
+                />
+            </el-tab-pane>
+        </el-tabs>
+        <span class="slide-icon" @click="isSlide = !isSlide">
+            <i :class="{'el-icon-d-arrow-left':!isSlide,'el-icon-d-arrow-right':isSlide}"></i>
+        </span>
     </div>
-   
   </div>
 </template>
 
 <script>
 import chartDetail from './components/chartDetail.vue'
+import indexContent from './components/indexContent.vue'
+import {apiPositionAnalysisList} from '@/api/modules/positionAnalysis'
 export default {
-  components: { chartDetail },
+  components: { chartDetail , indexContent },
   data() {
     return {
-      selectDate: ''
+      selectDate: '',
+
+      /* list */
+      activeType: '',
+      list: [],
+      loading: false,
+      isHistory:false,
+      isSlide:false,
     }
   },
   computed: {
@@ -65,6 +102,7 @@ export default {
     handleOpt(type){
         let obj={}
         if(type==='date'){
+            this.selectDate = this.$refs.chartDetailRef.selectDate
             obj={
                 opt:type,
                 val:this.selectDate
@@ -94,10 +132,22 @@ export default {
         this.$refs.chartDetailRef.selectDate=''
         this.$refs.chartDetailRef.getInfo()  
       }
+    },
+
+    getList(){
+      this.loading=true
+      apiPositionAnalysisList().then(res=>{
+          this.loading=false
+          if(res.Ret!==200) return
+          this.list=res.Data||[]
+          this.activeType= this.$route.query.exchange||res.Data[0]&&res.Data[0].Exchange
+          this.isHistory = Boolean(this.$route.query.isHistory)
+      })
     }
   },
 
   mounted() {
+    this.getList()
   }
 }
 
@@ -121,12 +171,79 @@ export default {
         }
 
     }
+    .position-analysis-detail-page{
+        .list{
+            .tabs-wrap{
+                .el-tabs__nav{
+                    display: flex;
+                    width: 100%;
+                }
+                .el-tabs__item{
+                    text-align: center;
+                    flex: 1;
+                    padding:0;
+                }
+                .el-tabs__header{
+                    margin-bottom: 0;
+                }
+            }
+            
+        }
+    }
 </style>
 
 <style lang="scss" scoped>
 @import '~@/styles/theme-vars.scss';
 .position-analysis-detail-page{
   min-height: calc(100vh - 410px);
+  display: flex;
+  position: relative;
+  .list{
+      width:379px;
+      margin-left:20px;
+      position: relative;
+      background: #fff;
+      border: 1px solid #F2F2F2;
+      border-radius: 4px;
+      /* box-shadow: 0 3px 6px rgba(0,0,0,.05); */
+      .header{
+          padding:30px;
+          display: flex;
+          justify-content: space-between;
+          box-sizing: border-box;
+          span{
+              font-size: 16px;
+              font-weight: 500;
+          }
+      }
+      .tabs-wrap{
+          flex: 1;
+          border-top: 1px solid #DCDFE6;
+      }
+      .slide-icon{
+        position:absolute;
+        left: -10px;
+        padding: 20px 0;
+        box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.3);
+        border-radius: 5px;
+        cursor: pointer;
+        top: 50%;
+        transform: translateY(-50%);
+        z-index: 99;
+        background-color: #fff;
+      }
+  }
+  .expand-list{
+      position:absolute;
+      right:0;
+      width:50%;
+  }
+  .detail{
+      flex:1;
+      display: flex;
+      flex-direction: column;
+      max-width: calc(100% - 379px - 20px);
+  }
   .detail-top {
     padding: 20px;
     margin-bottom: 20px;
@@ -138,6 +255,7 @@ export default {
     justify-content: space-between;
   }
   .detail-content {
+      flex: 1;
     padding: 20px;
     background: #fff;
     border-right: 2px solid #F2F2F2;

+ 15 - 0
src/views/positionAnalysis_manage/list.vue

@@ -16,9 +16,17 @@
                   :time="item.DataTime" 
                   :exchange="item.Exchange"
                   :now="item.CurrDate"
+                  :isHistory="isHistory"
                 />
             </el-tab-pane>
         </el-tabs>
+        <div class="switch-wrap">
+            <el-switch
+                v-model="isHistory"
+                size="large"
+                active-text="历史合约"
+            />
+        </div>
     </div>
 </template>
 
@@ -32,6 +40,7 @@ export default {
       activeType: '',
       list: [],
       loading: false,
+      isHistory:false
 
     }
   },
@@ -59,6 +68,7 @@ export default {
 
 <style lang="scss" scoped>
 .position-analysis-index-page{
+    position: relative;
     min-height: 60vh;
     padding: 20px;
     background: #fff;
@@ -73,6 +83,11 @@ export default {
             font-size: 16px;
         }
     }
+    .switch-wrap{
+        position:absolute;
+        right:20px;
+        top:20px;
+    }
 }
 </style>
 <style lang="scss">

+ 3 - 2
src/views/ppt_manage/mixins/mixins.js

@@ -337,9 +337,10 @@ export default {
 
 
       // 农历数据需要去除第一项 在ETA1.0.5之后,除了这里 农历和公历处理逻辑一样
+      const temChartDataList=chartData.DataList||[]
       const chartDataHandle=this.calendar_type === '农历'?
-      chartData.DataList.filter((item, index) => index > 0):
-      chartData.DataList
+      temChartDataList.filter((item, index) => index > 0):
+      temChartDataList
       let seasonYdata = [],
         seasonData = [],
         chart = {

+ 2 - 2
src/views/ppt_manage/newVersion/pptEnCatalog.vue

@@ -1025,8 +1025,8 @@ export default {
     getTransSet(data){
       pptEnInterface.transPPTtoReport({
         PptId:this.pptItem.PptId,
-        ClassifyIdFirst:data.type[0],
-        ClassifyIdSecond:data.type[1]?data.type[1]:0,
+        ClassifyIdFirst:data.type[1]?data.type[1]:0,
+        ClassifyIdSecond:data.type[2]?data.type[2]:0,
         Title:data.title,
         Abstract:data.abstract
       }).then(res=>{

Неке датотеке нису приказане због велике количине промена