瀏覽代碼

Merge branch 'master' into eta1.1.6

Karsa 1 年之前
父節點
當前提交
67867cc9b2
共有 100 個文件被更改,包括 4161 次插入936 次删除
  1. 4 0
      build/webpack.base.conf.js
  2. 2 1
      config/dev.env.js
  3. 2 1
      config/prod.env.js
  4. 2 1
      config/prod.test.env.js
  5. 11 0
      index.html
  6. 1 0
      package.json
  7. 2 1
      src/api/api.js
  8. 1 0
      src/api/http.js
  9. 112 1
      src/api/modules/chartApi.js
  10. 9 0
      src/api/modules/futuresBaseApi.js
  11. 6 2
      src/api/modules/oldApi.js
  12. 11 1
      src/api/modules/predictEdbApi.js
  13. 14 0
      src/api/modules/toolBoxApi.js
  14. 3 0
      src/assets/icons/chartFrame/arrow-left.svg
  15. 3 0
      src/assets/icons/chartFrame/arrow-right.svg
  16. 11 0
      src/assets/icons/chartFrame/fillColor.svg
  17. 17 0
      src/assets/icons/chartFrame/fontColor.svg
  18. 12 0
      src/assets/icons/chartFrame/fontStyle.svg
  19. 11 0
      src/assets/icons/chartFrame/fontText.svg
  20. 12 0
      src/assets/icons/chartFrame/fontWeight.svg
  21. 8 0
      src/assets/icons/chartFrame/redo.svg
  22. 5 0
      src/assets/icons/chartFrame/stokeColor.svg
  23. 5 0
      src/assets/icons/chartFrame/stokeStyle.svg
  24. 5 0
      src/assets/icons/chartFrame/textAlign.svg
  25. 8 0
      src/assets/icons/chartFrame/undo.svg
  26. 二進制
      src/assets/img/chart_m/check.png
  27. 二進制
      src/assets/img/icons/tooltip.png
  28. 1 0
      src/components/pwdDlg.vue
  29. 2 1
      src/mixins/theme.js
  30. 65 3
      src/routes/modules/chartRoutes.js
  31. 38 49
      src/utils/TimeOnPage.js
  32. 17 3
      src/utils/buttonConfig.js
  33. 184 0
      src/utils/common.js
  34. 6 2
      src/utils/commonOptions.js
  35. 3 3
      src/utils/svgToblob.js
  36. 2 0
      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 4
      src/views/dataEntry_manage/codecount/index.vue
  59. 51 5
      src/views/dataEntry_manage/components/satterSeriesDia.vue
  60. 11 0
      src/views/dataEntry_manage/components/sectionalScatterOption.vue
  61. 23 8
      src/views/dataEntry_manage/databaseComponents/batchComptedDialog.vue
  62. 6 2
      src/views/dataEntry_manage/databaseComponents/chartTrendRender.vue
  63. 3 2
      src/views/dataEntry_manage/databaseComponents/completeTargetDia.vue
  64. 3 2
      src/views/dataEntry_manage/databaseComponents/computedDialog.vue
  65. 3 7
      src/views/dataEntry_manage/databaseComponents/diffusionIndexDia.vue
  66. 15 14
      src/views/dataEntry_manage/databaseComponents/fittingResidueDia.vue
  67. 6 5
      src/views/dataEntry_manage/databaseComponents/jointTargetDia.vue
  68. 49 72
      src/views/dataEntry_manage/databaseComponents/openDialog.vue
  69. 22 12
      src/views/dataEntry_manage/databaseComponents/operationDialog.vue
  70. 18 1
      src/views/dataEntry_manage/databaseComponents/smoothEdbDialog.vue
  71. 16 1
      src/views/dataEntry_manage/databaseComponents/util.js
  72. 162 256
      src/views/dataEntry_manage/databaseList.vue
  73. 28 3
      src/views/dataEntry_manage/editChart.vue
  74. 3 1
      src/views/dataEntry_manage/mixins/addOreditMixin.js
  75. 1 1
      src/views/dataEntry_manage/mixins/chartPublic.js
  76. 47 11
      src/views/datasheet_manage/customAnalysis/addAnalysisSheet.vue
  77. 0 107
      src/views/datasheet_manage/customAnalysis/components/createTargetDia.vue
  78. 15 3
      src/views/datasheet_manage/customAnalysis/components/createTargetForm.vue
  79. 7 1
      src/views/datasheet_manage/customAnalysis/components/rightSection.vue
  80. 10 8
      src/views/datasheet_manage/customAnalysis/list.vue
  81. 13 1
      src/views/datasheet_manage/sheetList.vue
  82. 5 2
      src/views/mychart_manage/components/chartDetailDia.vue
  83. 80 0
      src/views/mychart_manage/components/classifyDeleteCheck.vue
  84. 57 9
      src/views/mychart_manage/index.vue
  85. 20 0
      src/views/positionAnalysis_manage/components/chartDetail.vue
  86. 19 17
      src/views/positionAnalysis_manage/components/indexContent.vue
  87. 141 23
      src/views/positionAnalysis_manage/detail.vue
  88. 15 0
      src/views/positionAnalysis_manage/list.vue
  89. 3 2
      src/views/ppt_manage/mixins/mixins.js
  90. 4 1
      src/views/ppt_manage/newVersion/pptCatalog.vue
  91. 6 3
      src/views/ppt_manage/newVersion/pptEnCatalog.vue
  92. 38 3
      src/views/ppt_manage/newVersion/pptEnPublish.vue
  93. 36 3
      src/views/ppt_manage/newVersion/pptPublish.vue
  94. 1 0
      src/views/ppt_manage/newVersion/utils/untils.js
  95. 20 7
      src/views/predictEdb_manage/addPredicEdb.vue
  96. 22 12
      src/views/predictEdb_manage/components/classifyDia.vue
  97. 13 0
      src/views/predictEdb_manage/components/computedDialog.vue
  98. 1 1
      src/views/predictEdb_manage/components/edbDetail.vue
  99. 21 8
      src/views/predictEdb_manage/components/operationDialog.vue
  100. 92 132
      src/views/predictEdb_manage/mixins/mixin.js

+ 4 - 0
build/webpack.base.conf.js

@@ -17,6 +17,10 @@ module.exports = {
     // app: './src/main.js',
     app: ['babel-polyfill', './src/main.js']
   },
+  // 防止有依赖关联到fs而报错,浏览器不让用 fs
+  node: {
+    fs: "empty"
+  },
   output: {
     path:process.env.NODE_ENV === 'production'? config.build.assetsRoot:config.test.assetsRoot,
     filename: '[name].js',

+ 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"',
 }

+ 11 - 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 || [];

+ 1 - 0
package.json

@@ -38,6 +38,7 @@
     "js-md5": "^0.7.3",
     "less-loader": "^4.1.0",
     "lodash": "^4.17.21",
+    "minio": "^7.0.18",
     "pptxgenjs": "^3.10.0",
     "qrcode": "^1.4.4",
     "sortablejs": "^1.15.0",

+ 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)
+  }
   
 }

+ 6 - 2
src/api/modules/oldApi.js

@@ -164,8 +164,12 @@ const chapterQRCodeImg=params=>{
 	return http.post('/report/getSunCode',params)
 }
 //上传阿里云 oss获取临时票据
-const getOSSSign=()=>{
-	return http.get('/resource/oss/get_sts_token',{})
+/**
+ * @param {*} params.StorageSource number 1:oss 2:minio
+ * @returns 
+ */
+const getOSSSign=params=>{
+	return http.get('/resource/oss/get_sts_token',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 

+ 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>

二進制
src/assets/img/chart_m/check.png


二進制
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:'',
 }

+ 65 - 3
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,
+			},
 		]
 	},
 
@@ -227,7 +246,7 @@ export default [
 	},
 
 	/* 持仓分析 */
-	{
+	/* {
 		path:'/',
 		component: home,
 		name: '持仓分析',
@@ -244,5 +263,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{

+ 17 - 3
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,6 +332,18 @@ 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表格------------------------------------------------
 */
@@ -585,7 +599,7 @@ const btnMap  = {
     pptPermission,enPPTPermission,
     dataSourcePermission,
     edbDataPermission,predictEdbPermission,chartLibPermission,
-    myETAPermission,etaTablePermission,
+    myETAPermission,chartFramePermission,etaTablePermission,
     sandboxPermission,semanticPermission,
     statisticPermission,stockPlantPermission,
     productPricePermission,sysDepartPermission,

+ 184 - 0
src/utils/common.js

@@ -2,6 +2,11 @@
 // import  getNetworkType from './getNetworkType';
 // import  getSystemInfo from './getSystemInfo';
 
+import {Message} from "element-ui"
+import{getOSSSign} from "@/api/api.js"
+const Minio = require('minio')
+const stream = require('stream')
+
 // 根据字节流下载文件
 /**
  * @param {Blob} data 流数据
@@ -45,4 +50,183 @@ export function getUrlParams(str=window.location.href,key) {
 	str.split('?')[1].split('&').map(i => obj[(i.split('=')[0])] = i.split('=')[1]);
 
   return obj[key]
+}
+
+/**
+ * 
+ * @param {*} objectStorageClient oss-走oss 2-走minio string
+ * @param {*} file 上传文件
+ * @param {*} temName 文件路径/文件名字
+ * @param {*} options 文件路径/文件名字
+ * @param {*} options.OSS 上传至阿里云的配置
+ * @param {*} options.MINIO 上传至MINIO的配置
+ */
+
+// 上传文件 直接走对象存取服务器
+export function uploadFileDirect(objectStorageClient,file,temName,options={}){
+  const objectStorageType= (objectStorageClient || JSON.parse(localStorage.getItem('dynamicOutLinks')).ObjectStorageClient || 'oss')
+  // console.log(objectStorageType,'objectStorageType');
+  // return 
+  if(!objectStorageType){
+    Message.error("ObjectStorageClient参数丢失")
+    return new Promise((resolve,reject) => reject("ObjectStorageClient参数丢失"))
+  }
+  if(!file){
+    Message.error("file参数错误")
+    return new Promise((resolve,reject) => reject("file参数错误"))
+  }
+  if(!temName){
+    Message.error("temName参数错误")
+    return new Promise((resolve,reject) => reject("temName参数错误"))
+  }
+  // console.log(objectStorageType,file,temName,options,'objectStorageType,file,temName,options');
+  switch (objectStorageType) {
+    case "oss":
+      let ossOptions = {}
+      if(options.OSS){
+        ossOptions=options.OSS
+      }
+
+      return handleUploadToOSS(file,temName,ossOptions)
+      // break;
+    case "minio":
+      let minioOptions = {}
+      if(options.MINIO){
+        minioOptions=options.MINIO
+      }
+      return handleUploadToMinIO(file,temName,minioOptions)
+      // break;
+    default:
+      break;
+  }
+}
+
+const handleUploadToOSS= (file,fileName,options={})=>{
+  return new Promise(async (resolve,reject)=>{
+    // 获取oss临时签名
+    const res=await getOSSSign({StorageSource:1})
+    // console.log(res);
+    if(res.Ret!==200) reject("获取阿里云oss临时签名错误,res.Ret="+res.Ret)
+    try {
+
+      let oss_params = {
+        // yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
+        region: res.Data.RegionId,
+        // 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
+        accessKeyId: res.Data.AccessKeyId,
+        accessKeySecret: res.Data.AccessKeySecret,
+        // 从STS服务获取的安全令牌(SecurityToken)。
+        stsToken: res.Data.SecurityToken,
+        // 填写Bucket名称,例如examplebucket。
+        bucket: res.Data.Bucketname,
+        endpoint: res.Data.Endpoint,
+        cname:true,
+        timeout:6000000
+      }
+  
+      let imgHost = res.Data.Imghost;
+  
+      const ALOSSINS=new OSS(oss_params);
+
+      const resp=await ALOSSINS.multipartUpload(fileName,file,{...options})
+      console.log('上传结果',resp);
+      if(resp.res.status===200){
+        let url=imgHost+resp.name
+        resolve(url)
+        console.log('oss文件地址',url);
+      }else{
+        throw new Error('上传到阿里云失败:res.status'+resp.res.status)
+      }
+    } catch (error) {
+      console.error(error);
+      if (error.name !== "cancel") {
+        Message.warning('上传失败,请刷新重试')
+      }
+      reject(error)
+    }
+  })
+}
+
+// minio sdk 文档 https://min.io/docs/minio/linux/developers/javascript/API.html
+const handleUploadToMinIO=(file,fileName,options={})=>{
+  return new Promise(async (resolve,reject)=>{
+
+    const res=await getOSSSign({StorageSource:2})
+    // console.log(res);
+    if(res.Ret!==200) reject("获取minio临时签名错误,res.Ret="+res.Ret)
+    // return
+    const minioClient = new Minio.Client({
+      endPoint: res.Data.Endpoint.split(':')[0],
+      port: Number(res.Data.Port)||undefined,
+      useSSL: res.Data.UseSSL.toLocaleLowerCase()=="false"?false:true,
+      accessKey: res.Data.AccessKeyId,
+      secretKey: res.Data.SecretKeyId,
+    })
+    console.log(minioClient);
+    try {
+      var metaData = {...{
+        'Content-Type': file.type||'application/octet-stream',
+        "Content-Length": file.size,
+      },...options}
+    
+      minioClient.bucketExists(res.Data.Bucketname, function (err, exists) {
+          if (err) {
+              throw "minio 查看桶是否存在失败"+err
+              // return console.log(err);
+          }
+          if (!exists) {
+            // 不存在桶,创建桶
+            console.log("桶不存在,先创建桶",res.Data.Bucketname);
+            minioClient.makeBucket(res.Data.Bucketname, res.Data.RegionId,function (err) {
+              if (err) {
+                throw "minio 创建桶失败"+err
+              }
+            
+              let reader = new FileReader();
+              // console.log(reader);
+              reader.readAsArrayBuffer(file);
+              reader.onloadend = function (e) {
+                const dataurl = e.target.result;
+                let bufferStream = new stream.PassThrough();
+                // 转化成数据流  minio接受数据流格式
+                bufferStream.end(Buffer.from(dataurl))
+                // console.log(bufferStream);
+                minioClient.putObject(res.Data.Bucketname, fileName, bufferStream,file.size, metaData, function (err, etag) {
+                  if (err){
+                    throw "上传到minio失败:"+err
+                  }
+            
+                })
+              }
+            })
+          }
+          if (exists) {
+            // console.log("桶存在",res.Data.Bucketname);
+            let reader = new FileReader();
+            console.log(reader);
+            reader.readAsArrayBuffer(file);
+            reader.onloadend = function (e) {
+              const dataurl = e.target.result;
+              let bufferStream = new stream.PassThrough();
+    
+              bufferStream.end(Buffer.from(dataurl))
+              minioClient.putObject(res.Data.Bucketname, fileName, bufferStream, metaData, function (err, etag) {
+                if (err){
+                  throw "上传到minio失败:"+err
+                }
+                let fileUrl = fileName.startsWith('/')?res.Data.ImgHost+fileName:res.Data.ImgHost+"/"+fileName
+                resolve(fileUrl)
+              })
+            }
+          }
+      })
+    } catch (error) {
+      console.error(error);
+      if (error.name !== "cancel") {
+        //不是取消上传的则给错误提示
+        this.$message.warning("上传失败,请刷新重试");
+      }
+      reject(error)
+    }
+  })
 }

+ 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}/

+ 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协议')
       }
     }	
  

+ 2 - 0
src/views/Home.vue

@@ -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 - 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`]
 ])

+ 162 - 256
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,6 +1177,7 @@ export default {
 		},
 		/* 编辑节点 */
 		editNode(node,data) {
+			// console.log(node);
 			this.dialog_title = '编辑';
 			if(data.EdbCode) {
 				/* 编辑指标 基础弹窗 */
@@ -1187,17 +1186,19 @@ export default {
 					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,

+ 3 - 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)
 
 		},
@@ -617,7 +618,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协议')
         }
       };
     },

+ 47 - 11
src/views/datasheet_manage/customAnalysis/addAnalysisSheet.vue

@@ -1,7 +1,11 @@
 <template>
   <div class="addSheet-wrap">
     
-    <createTargetForm ref="createTargetRef" @save="handleCreateTarget" v-if="$route.path==='/createTaregtBySheet'"/>
+    <createTargetForm 
+      v-if="$route.path==='/createTaregtBySheet'"
+      ref="createTargetRef" 
+      @save="handleCreateTarget" 
+    />
 
 
     <div class="main">
@@ -23,7 +27,6 @@
           <dataLoading :loading="isLoading"/>
         </div>
 
-        <!-- <tableNoData text="暂无数据" v-else/> -->
       </div>
 
       <!-- 指标列表 -->
@@ -65,10 +68,10 @@ export default {
       return this.$route.path==='/createTaregtBySheet' 
         ? {
             showsheetbar: true,
-            allowCopy:false,
-            allowEdit:false,
-            allowUpdate:false,
-            enableAddRow:false,
+            // allowCopy:false,
+            // allowEdit:false,
+            // allowUpdate:false,
+            // enableAddRow:false,
             data: null,
             hook: {
               //选区时
@@ -104,8 +107,21 @@ export default {
   },
   methods: {
 
-    backHandle() {
-      this.$router.go(-1);
+    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);
+      }
+
     },
 
     /* 切换表格 */
@@ -252,7 +268,7 @@ export default {
 
         this.sheetDetailInfo = res.Data.ExcelInfo;
         this.dataToalPage =  Math.max(...res.Data.SheetList.map(_ => _.PageNum));
-        this.sheetAllcellData = res.Data.SheetList.map(_ => JSON.parse(_.Data.Data));
+        this.sheetAllcellData = res.Data.SheetList.map(_ => _.Data ? JSON.parse(_.Data.Data): []);
 
         this.getCellData(res.Data.SheetList)
       });
@@ -281,7 +297,7 @@ export default {
         this.getCellData(sheets)
       }else {
         this.sheetConfig.data = sheets.map((_,index) => ({
-          // index: _.Sort, //工作表索引
+          index: _.Index, //工作表id
           order: _.Sort, //工作表的下标
           name: _.SheetName,
           calcChain: JSON.parse(_.CalcChain),
@@ -344,6 +360,25 @@ export default {
     /* 生成指标 */
     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,
@@ -355,7 +390,7 @@ export default {
 				unit } = this.$refs.createTargetRef.formData;
       let params = {
         EdbName: edbName,
-        ExcelInfoId: this.sheetDetailInfo.ExcelInfoId,
+        ExcelInfoId: ExcelInfoId,
         ClassifyId: classify,
         Frequency: frequency,
         Unit: unit,
@@ -368,6 +403,7 @@ export default {
         ? 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)

+ 0 - 107
src/views/datasheet_manage/customAnalysis/components/createTargetDia.vue

@@ -1,107 +0,0 @@
-<template>
-  <div v-dialogDrag v-show="isShow" >
-    <div class="create-target-wrapper">
-      <div class="header el-dialog__header">
-        <span>编辑指标区域</span>
-        <i class="el-icon-close" @click="cancelHandle"/>
-      </div>
-
-      <div class="main">
-        <el-form
-          ref="diaForm"
-          label-position="left"
-          hide-required-asterisk
-          label-width="80px"
-          :model="formData"
-        >
-          <el-form-item label="分类名称" prop="dateSeries">
-            <el-input v-model="formData.dateSeries"></el-input>
-          </el-form-item>
-          <el-form-item label="数值序列" prop="valueSeries">
-            <el-input v-model="formData.valueSeries"></el-input>
-          </el-form-item>
-        </el-form>
-      </div>
-
-      <div class="dia-bot">
-        <el-button type="primary">保存</el-button>
-        <el-button>取消</el-button>
-      </div>
-    </div>
-  </div>
-</template>
-<script>
-export default {
-  data() {
-    return {
-      formData: {
-        dateSeries: '',
-        valueSeries: '',
-				edbName:'',
-				menu:'',
-				frequency: '',
-				unit:''
-			}
-    }
-  },
-  mounted(){
-
-  },
-  methods:{
-
-  },
-}
-</script>
-<style scoped lang='scss'>
-@import "~@/styles/theme-vars.scss";
-.create-target-wrapper {
-  background: #fff;
-  position: fixed;
-  top: 20%;
-  left: 55%;
-  width: 500px;
-  border-radius: 2px;
-  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
-  z-index: 999;
-  .header { 
-    height: 50px;
-    font-size: 16px;
-    background: $theme-color;
-    color: #fff;
-    padding: 0 15px;
-    display: flex;
-    align-content: center;
-    justify-content: space-between;
-    span {
-      line-height: 50px;
-    }
-    .el-icon-close {
-      font-size: 20px;
-      line-height: 50px;
-      cursor: pointer;
-    }
-  }
-  .main {
-    padding: 20px 15px;
-    .data-cont {
-      margin: 15px 0;
-      border: 1px solid #DCDFE6;
-      /* padding: 20px; */
-      .data-li {
-        display: flex;
-        padding: 15px;
-        text-align: center;
-        justify-content: space-around;
-        &.choose {
-          background: #ECF5FF;
-        }
-      }
-    }
-    .dia-bot {
-      margin-top: 20px; 
-      display: flex;
-      justify-content: center;
-    }
-  }
-}
-</style>

+ 15 - 3
src/views/datasheet_manage/customAnalysis/components/createTargetForm.vue

@@ -30,6 +30,7 @@
             value: 'ClassifyId',
             children: 'Children',
             emitPath: false,
+            checkStrictly: true
           }"
           clearable
           placeholder="请选择所属目录"
@@ -58,6 +59,7 @@
       
       <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>
@@ -115,10 +117,20 @@ export default {
 		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) {
@@ -199,14 +211,14 @@ export default {
     },
 
     /* 保存 */
-    async handleSaveTarget() {
+    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() {

+ 7 - 1
src/views/datasheet_manage/customAnalysis/components/rightSection.vue

@@ -6,7 +6,7 @@
           <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" alt="" @click.stop="linkToEdbBase(item)">
+            <img :src="$icons.jupm_icon" class="jump-icon" @click.stop="linkToEdbBase(item)">
           </div>
         </li>
       </ul>
@@ -89,6 +89,12 @@ export default {
         .item-right {
           display: flex;
           align-items: center;
+          .jump-icon {
+            cursor: pointer;
+            &:hover {
+              opacity: 0.8;
+            }
+          }
         }
         .el-icon-edit {
           font-size: 16px;

+ 10 - 8
src/views/datasheet_manage/customAnalysis/list.vue

@@ -163,8 +163,14 @@
               <i class="el-icon-edit"/>
             </span>
             <ul class="action-ul" v-if="sheetDetailInfo.Button">
-              <li class="editsty" @click="HandleToPath" v-if="isSheetBtnShow('createedb')&&sheetDetailInfo.Button.OpEdbButton">生成指标</li>
-              <li class="editsty" @click="refreshSheet" v-if="isSheetBtnShow('refresh')&&sheetDetailInfo.Button.RefreshEdbButton">刷新指标</li>
+
+              <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"
@@ -626,8 +632,6 @@ export default {
       if (res.Ret !== 200) return;
       this.$message.success("保存成功");
       this.getTreeData();
-
-      // this.getDetailHandle();
     }, 300),
 
     /* 获取表格列表 */
@@ -704,18 +708,16 @@ export default {
         continue
       }
       
-      //数据继续加载或渲染表格
+      //数据继续加载或渲染表格.
       if(this.sheetDataPage < this.dataToalPage) {
         this.sheetDataPage++;
         this.getCellData(sheets)
       }else {
-        console.log(this.sheetAllcellData)
         this.sheetConfigOpt.data = sheets.map((_,index) => ({
-          index: _.Sort, //工作表索引
+          index: _.Index, //工作表id
           order: _.Sort, //工作表的下标
           name: _.SheetName,
           calcChain: _.CalcChain?JSON.parse(_.CalcChain):[],
-          // calcChain: _.CalcChain?[{r:27,c:4,index:1}]:[],
           config: JSON.parse(_.Config),
           celldata: this.sheetAllcellData[index],
         }))

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

@@ -346,9 +346,21 @@ export default {
         ExcelClassifyId: _.ExcelClassifyId,
         ExcelClassifyName: _.ExcelClassifyName,
       }));
-
       return options;
     },
+
+     //数据表格是否展示
+    isShowDataSheet(){
+        const cell = {Source:2}
+        return this.isSheetBtnShow(cell,'edit')||this.isSheetBtnShow(cell,'refresh')||this.isSheetBtnShow(cell,'otherSave')
+            || this.isSheetBtnShow(cell,'download')||this.isSheetBtnShow(cell,'del')
+    },
+    //混合表格是否展示
+    isShowMixSheet(){
+        const cell = {Source:3}
+        return this.isSheetBtnShow(cell,'edit')||this.isSheetBtnShow(cell,'refresh')||this.isSheetBtnShow(cell,'otherSave')
+            || this.isSheetBtnShow(cell,'download')||this.isSheetBtnShow(cell,'del')
+    }
   },
   data() {
     return {

+ 5 - 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
@@ -1063,9 +1065,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 = {

+ 4 - 1
src/views/ppt_manage/newVersion/pptCatalog.vue

@@ -249,7 +249,10 @@
         <div class="tool-side ppt-page-wrap">
           <div class="ppt-info">
             <div>作者:{{pptItem.AdminRealName}}</div>
-            <div>{{pptItem.PptxUrl?'发布':'保存'}}时间:{{$moment(pptTime).format('YYYY-MM-DD')}}</div>
+            <div>
+              {{pptItem.PptxUrl?'发布':'保存'}}
+              时间:{{$moment(pptItem.PptxUrl?pptItem.PublishTime || undefined:pptItem.PptModifyTime || undefined).format('YYYY-MM-DD')}}
+            </div>
           </div>
           <div class="tool-list-operation">
             <span>操作</span>

+ 6 - 3
src/views/ppt_manage/newVersion/pptEnCatalog.vue

@@ -239,7 +239,10 @@
         <div class="tool-side ppt-page-wrap">
           <div class="ppt-info">
             <div>作者:{{pptItem.AdminRealName}}</div>
-            <div>{{pptItem.PptxUrl?'发布':'保存'}}时间:{{$moment(pptTime).format('YYYY-MM-DD')}}</div>
+            <div>
+              {{pptItem.PptxUrl?'发布':'保存'}}
+              时间:{{$moment(pptItem.PptxUrl?pptItem.PublishTime || undefined:pptItem.PptModifyTime || undefined).format('YYYY-MM-DD')}}
+            </div>
           </div>
           <div class="tool-list-operation">
             <span>操作</span>
@@ -1022,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=>{

+ 38 - 3
src/views/ppt_manage/newVersion/pptEnPublish.vue

@@ -60,6 +60,8 @@ import {pptEnInterface} from '@/api/modules/pptEnApi.js';
 import Highcharts from "highcharts/highstock";
 import HighchartszhCN  from '@/utils/highcahrts-zh_CN'
 import HightchartsExport from 'highcharts/modules/exporting';
+import {uploadFileDirect} from "@/utils/common.js"
+
 HightchartsExport(Highcharts)
 HighchartszhCN(Highcharts)
 export default {
@@ -430,10 +432,43 @@ export default {
         text:"发布中..."
       })
       //console.log('pptx',pptx)
+      // pptx2.write('blob').then((data)=>{
+      //   // 上传到阿里云oss
+      //   // this.handleUploadToOSS(data)
+      // })
+      // 生成文件名
+      let t=new Date()
+      let month=moment(t).format('YYYYMM')
+      let day=moment(t).format('YYYYMMDD')
+      const temName=`ppt/${month}/${day}/${createRandomCode(32)}.pptx`
+
+      const options = {
+        OSS:{
+          // 获取分片上传进度、断点和返回值。
+          progress: (p, cpt, res) => {
+            console.log(p);
+              // this.percentage=parseInt(p*100)
+          },
+          // 设置并发上传的分片数量。
+          parallel: 10,
+          // 设置分片大小。默认值为1 MB,最小值为100 KB。
+          partSize: 1024 * 1024 * 10, // 10MB
+        }
+      };
+
       pptx2.write('blob').then((data)=>{
-        // 上传到阿里云oss
-        this.handleUploadToOSS(data)
+        let clientType = this.$setting.dynamicOutLinks.ObjectStorageClient ||
+                        this.$store.state.dynamicOutLinks.ObjectStorageClient ||
+                        JSON.parse(localStorage.getItem('dynamicOutLinks')).ObjectStorageClient
+        // 上传到 对象存储器 阿里云、mino
+        uploadFileDirect(clientType,data,temName,options).then(url=>{
+          console.log('文件地址',url);
+          this.publishPPT(url)
+        }).catch(err=>{
+          console.error(err);
+        })
       })
+
     },
     //计算各版式下,对应position在ppt中的位置
     getPosition(modelId, position) {
@@ -487,7 +522,7 @@ export default {
     async handleUploadToOSS(file){
       console.log(file);
       // 获取oss临时签名
-      const res=await getOSSSign()
+      const res=await getOSSSign({StorageSource:1})
       if(res.Ret!==200) return
 
       let oss_params = {

+ 36 - 3
src/views/ppt_manage/newVersion/pptPublish.vue

@@ -120,6 +120,8 @@ import{pptInterface,dataBaseInterface,getOSSSign} from "@/api/api.js"
 import Highcharts from "highcharts/highstock";
 import HighchartszhCN  from '@/utils/highcahrts-zh_CN'
 import HightchartsExport from 'highcharts/modules/exporting';
+import {uploadFileDirect} from "@/utils/common.js"
+
 HightchartsExport(Highcharts)
 HighchartszhCN(Highcharts)
 export default {
@@ -508,6 +510,28 @@ export default {
         fullscreen:true,
         text:"发布中..."
       })
+
+      // 生成文件名
+      let t=new Date()
+      let month=moment(t).format('YYYYMM')
+      let day=moment(t).format('YYYYMMDD')
+      /* const temName=`ppt/${month}/${day}/${this.coverInfo.page.Title}.pptx` */
+      const temName=`ppt/${month}/${day}/${createRandomCode(32)}.pptx`
+
+      const options = {
+        OSS:{
+          // 获取分片上传进度、断点和返回值。
+          progress: (p, cpt, res) => {
+            console.log(p);
+              // this.percentage=parseInt(p*100)
+          },
+          // 设置并发上传的分片数量。
+          parallel: 10,
+          // 设置分片大小。默认值为1 MB,最小值为100 KB。
+          partSize: 1024 * 1024 * 10, // 10MB
+        }
+      };
+
       //console.log('pptx',pptx)
       pptx2.write('blob').then((data)=>{
         // let form = new FormData()
@@ -519,7 +543,17 @@ export default {
         //   }
         // })
         // 上传到阿里云oss
-        this.handleUploadToOSS(data)
+        // this.handleUploadToOSS(data)
+        let clientType = this.$setting.dynamicOutLinks.ObjectStorageClient ||
+                        this.$store.state.dynamicOutLinks.ObjectStorageClient ||
+                        JSON.parse(localStorage.getItem('dynamicOutLinks')).ObjectStorageClient
+        // 上传到 对象存储器
+        uploadFileDirect(clientType,data,temName,options).then(url=>{
+          console.log('文件地址',url);
+          this.publishPPT(url)
+        }).catch(err=>{
+          console.error(err);
+        })
       })
     },
     //计算各版式下,对应position在ppt中的位置
@@ -592,7 +626,7 @@ export default {
     async handleUploadToOSS(file){
       console.log(file);
       // 获取oss临时签名
-      const res=await getOSSSign()
+      const res=await getOSSSign({StorageSource:1})
       if(res.Ret!==200) return
       
       let oss_params = {
@@ -617,7 +651,6 @@ export default {
       let t=new Date()
       let month=moment(t).format('YYYYMM')
       let day=moment(t).format('YYYYMMDD')
-      /* const temName=`ppt/${month}/${day}/${this.coverInfo.page.Title}.pptx` */
       const temName=`ppt/${month}/${day}/${createRandomCode(32)}.pptx`
       console.log('文件名',temName);
 

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

@@ -500,6 +500,7 @@ export const caclShapeRealSize = (layer,shape)=>{
 //将rgba转为hex+透明度的格式
 //rgba(91,155,213,0.44) -> {color: "#5b9bd5",transparency: 56}
 const parseRgbaColor = (color) => {
+  if(!color) color='rgba(51, 51, 51, 1)'
   const arr = color.match(/(\d(\.\d+)?)+/g) || [];
   const res = arr.map((s) => parseInt(s, 10));
   return {

+ 20 - 7
src/views/predictEdb_manage/addPredicEdb.vue

@@ -36,6 +36,7 @@
                         label: 'ClassifyName',
                         value: 'ClassifyId',
                         children: 'Children',
+                        checkStrictly: true
                     }"
                     style="width: 90%"
                     placeholder="请选择所属分类"
@@ -379,6 +380,7 @@
         <div class="top-title">{{ formData.edbName }}</div>
         <chartInfo
           :edbData="edbData"
+          :isAllowEditLimit="true"
           @refreshData="refreshData"
           ref="chartInfo"
         />
@@ -590,6 +592,7 @@ export default {
           if (res.Ret !== 200) return;
           const {
             ClassifyId,
+            ClassifyList,
             EdbName,
             Frequency,
             LatestValue,
@@ -598,9 +601,10 @@ export default {
             LatestDate,
             DataDateType
           } = res.Data;
+          const classifyArr = ClassifyList.length&&ClassifyList.map(item=>item.ClassifyId).reverse()
           this.formData = {
             edb_id: EdbInfoId,
-            classify: ClassifyId,
+            classify: classifyArr||[],
             oldEdb: res.Data.CalculateList[0].FromEdbInfoId,
             oldEdbName: res.Data.CalculateList[0].FromEdbName,
             edbName: EdbName,
@@ -652,17 +656,26 @@ export default {
           };
         });
     },
-
+    // 递归改变目录结构
+		filterNodes(arr) {
+			arr.length &&
+				arr.forEach((item) => {
+					item.Children.length && this.filterNodes(item.Children);
+					if (!item.Children.length) {
+						delete item.Children;
+					}
+				});
+		},
     getClassifyOne() {
       preDictEdbInterface.classifyListV2().then((res) => {
         if (res.Ret !== 200) return;
-
+        this.filterNodes(res.Data.AllNodes || [])
         this.classifyArr = res.Data.AllNodes || [];
 
-        if (this.$route.path == "/editpredictEdb") {
-          //将formData.classify转为数组的格式
-          this.formData.classify = this.findParentNodeHandle(this.classifyArr,this.formData.classify).reverse()
-        } 
+        // if (this.$route.path == "/editpredictEdb") {
+        //   //将formData.classify转为数组的格式
+        //   this.formData.classify = this.findParentNodeHandle(this.classifyArr,this.formData.classify).reverse()
+        // } 
 
       });
     },

+ 22 - 12
src/views/predictEdb_manage/components/classifyDia.vue

@@ -19,18 +19,11 @@
 				:model="formData"
 				:rules="formRules">
 				
-				<!-- 添加一级目录的子分类/编辑二级目录时显示 -->
-				<template v-if="(title=='添加'&&formData.Level >= 1)||(title=='编辑'&&formData.Level >= 2)">
-					<el-form-item label="一级目录" prop="level_1_Name">
-						<span>{{formData.level_1_Name}}</span>
-					</el-form-item>
-				</template>
-				<!-- 添加二级目录的子分类/编辑三级目录时显示 -->
-				<template v-if="(title=='添加'&&formData.Level === 2)||(title=='编辑'&&formData.Level === 3)">
-					<el-form-item label="二级目录" prop="level_2_Name">
-						<span>{{formData.level_2_Name}}</span>
-					</el-form-item>
-				</template>
+				<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>
 
 				<el-form-item label="目录名称" prop="classify_name">
 					<el-input
@@ -73,6 +66,16 @@ export default {
 			}
 		}
 	},
+	computed:{
+		getParentName(){
+			const arr=this.formData.parentArr||[]
+			let strArr=arr.reverse().map(item=>{
+				return item.classifyName
+			})
+			
+			return strArr.join('/')
+		}
+	},
 	data () {
 		return {			
 			formData: {},
@@ -113,6 +116,13 @@ export default {
 </script>
 <style lang='scss'>
 .predict-classify-dialog {
+	.parentStr{
+		display: block;
+		width: 304px;
+		overflow: hidden;
+		white-space: nowrap;
+		text-overflow: ellipsis;
+	}
 	.dialog-main {
 		padding-left: 50px;
 	}

+ 13 - 0
src/views/predictEdb_manage/components/computedDialog.vue

@@ -121,6 +121,7 @@
 							label: 'ClassifyName',
 							value: 'ClassifyId',
 							children: 'Children',
+							checkStrictly: true
 						}"
 						style="width: 90%"
 						placeholder="请选择所属分类"
@@ -266,11 +267,23 @@ export default {
 		};
 	},
 	methods: {
+		// 递归改变目录结构
+		filterNodes(arr) {
+			arr.length &&
+				arr.forEach((item) => {
+					item.Children.length && this.filterNodes(item.Children);
+					if (!item.Children.length) {
+						delete item.Children;
+					}
+				});
+		},
+
 		/* 获取目录结构 */
 		getMenu() {
 			preDictEdbInterface.classifyListV2().then(res => {
 				if(res.Ret !== 200) return
 
+				this.filterNodes(res.Data.AllNodes||[]);
 				this.options = res.Data.AllNodes || [];
 			}) 
 		},

+ 1 - 1
src/views/predictEdb_manage/components/edbDetail.vue

@@ -139,7 +139,7 @@ export default {
                 })
                 this.$emit('setOpera',res.Data.Button)
 
-                this.$emit('setCurrentClassify',res.Data.EdbInfo.ClassifyId)
+                this.$emit('setCurrentClassify',res.Data.ClassifyList||[])
                 //更新图片
                 if(type==='updateImg' || !res.Data.EdbInfo.ChartImage) {
                     console.log(type);

+ 21 - 8
src/views/predictEdb_manage/components/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">
 			
@@ -191,6 +191,7 @@
 									label: 'ClassifyName',
 									value: 'ClassifyId',
 									children: 'Children',
+									checkStrictly: true
 								}"
 								style="width: 90%"
 								placeholder="请选择所属分类"
@@ -263,7 +264,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>
@@ -371,7 +372,7 @@ export default {
 					key: 'SourceName',
 				},
 			],
-			switchType: new Map([
+			titleMap: new Map([
 				[42,'累计值转月/季值'],
 				[32,'同比值'],
 				[33,'同差值'],
@@ -389,7 +390,7 @@ export default {
 				[69,'标准差'],
 				[70,'百分比'],
 			]),//标题
-			save_txts: new Map([
+			saveBtnMap: new Map([
 				[42,'转月值计算'],
 				[32,'同比值计算'],
 				[33,'同差值计算'],
@@ -490,13 +491,25 @@ export default {
 			this.searchApi(this.current_search,++this.search_page)
 		},
 
+		// 递归改变目录结构
+		filterNodes(arr) {
+			arr.length &&
+				arr.forEach((item) => {
+					item.Children.length && this.filterNodes(item.Children);
+					if (!item.Children.length) {
+						delete item.Children;
+					}
+				});
+		},
+
 		/* 获取目录结构 */
 		getMenu() {
-      preDictEdbInterface.classifyListV2().then(res => {
-        if(res.Ret !== 200) return
+			preDictEdbInterface.classifyListV2().then(res => {
+				if(res.Ret !== 200) return
 
-        this.options = res.Data.AllNodes || [];
-      }) 
+				this.filterNodes(res.Data.AllNodes||[]);
+				this.options = res.Data.AllNodes || [];
+			}) 
 		},
 
 		/* 获取指标数据 */

+ 92 - 132
src/views/predictEdb_manage/mixins/mixin.js

@@ -75,7 +75,7 @@ export default {
 					? 'auto'
 					: width <= 260
 					? 80
-					: 0.5 * width;
+					: 0.35 * width;
 			this.$set(node, 'Nodewidth', label_wid + 'px');
 		},200),
 
@@ -108,121 +108,93 @@ export default {
 
     /* 拖拽完成 */
     dropOverHandle(b, a, i, e) {
-      // console.log(i, a);
+      console.log(b,a,i);
       // 被拖拽节点对应的 Node、结束拖拽时最后进入的节点、被拖拽节点的放置位置
-      // 一/二/三级目录
-      if ([1,2,3].includes(b.level)) this.handleMoveCatalogue(b, a, i, e);
-
-      // 指标层
-      if (b.level === 4) this.handleMoveSheet(b, a, i, e);
-    },
-
-    // 移动的为一/二/三级目录
-    handleMoveCatalogue(b, a, i, e) {
-      let list = a.parent.childNodes,
-        targetIndex = 0,
-        PrevClassifyId = 0,
-        NextClassifyId = 0,
-        ParentClassifyId = 0;
-
-      list.forEach((item, index) => {
-        if (item.data.ClassifyId === b.data.ClassifyId) {
-          targetIndex = index;
-          return;
-        }
-      });
-
-      if (targetIndex === 0) {
-        PrevClassifyId = 0;
-        NextClassifyId = list.length>1?list[targetIndex + 1].data.ClassifyId:0;
-      } 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;
+      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
+
+			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
+						}
+					}
+					
+				})
+
+				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
+
+					PrevEdbInfoId=pData.EdbCode?pData.EdbInfoId:0
+
+					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===2||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
-        }
-      }
-
-      preDictEdbInterface
-        .classifyMove({
-          ClassifyId: b.data.ClassifyId,
-          ParentClassifyId: ParentClassifyId,
-          PrevClassifyId: PrevClassifyId,
-          NextClassifyId: NextClassifyId,
-        })
-        .then((res) => {
-          if (res.Ret !== 200) return;
-          this.$message.success("移动成功!");
-          this.getTreeData();
-        });
-    },
 
-    // 移动的为指标
-    handleMoveSheet(b, a, i, e) {
-      let PrevEdbInfoId = 0,
-        NextEdbInfoId = 0,
-        targetIndex = 0,
-        list = a.parent.data.Children;
-      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;
+			const params={
+				ClassifyId,
+				ParentClassifyId,
+				EdbInfoId,
+				PrevClassifyId,
+				NextClassifyId,
+				PrevEdbInfoId,
+				NextEdbInfoId
+			}
+			console.log(params);
+			preDictEdbInterface.classifyMoveSort(params).then(res=>{
+				if(res.Ret===200){
+					this.$message.success('移动成功!')
+				}
+				this.getTreeData()
+        if(this.select_id&&!this.showAssociateChart&&!this.showAssociateComputeData){
+          this.$refs.detailComponentRef.getDetail()
         }
-      }
-
-      preDictEdbInterface
-        .ebdMove({
-          ClassifyId: a.data.ClassifyId,
-          EdbInfoId: b.data.EdbInfoId,
-          PrevEdbInfoId,
-          NextEdbInfoId,
-        })
-        .then((res) => {
-          if (res.Ret !== 200) return;
-          this.$message.success("移动成功!");
-          this.getTreeData();
-        });
-
+			})
     },
 
     /* 拖拽覆盖添加背景色 */
     dropMouseOver(node1, node2, e) {
-      if (
-        (node1.level === 2 && node2.level === 1) &&
-        (e.target.childNodes[0].className.includes("el-tree-node__content") ||
-          e.target.className.includes("el-tree-node__content"))
-      ) {
-        e.target.childNodes[0].className.includes("el-tree-node__content")
-          ? (e.target.childNodes[0].style.backgroundColor = "#409eff")
-          : (e.target.style.backgroundColor = "#409eff");
-      }
+      // 被拖拽节点对应的 Node、所进入节点对应的 Node、event
+			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){
+				setTimeout(() => {
+					dropLine.style.top=e.layerY+'px'
+				}, 100);
+			}
     },
 
     /* 拖拽离开/拖拽完成重置背景色 */
@@ -263,30 +235,18 @@ export default {
     /* 判断节点是否能被拖入 */
     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')){
-                canDrop=true
-            }
-        }
-        //四级指标层
-        if(draggingNode.level===4){
-            if((dropNode.level===3&&type==='inner')||(dropNode.level===4&&type!=='inner')){
-                canDrop=true
-            }
-        }
+      // 如果拖动的是指标
+			if(draggingNode.data.EdbCode){
+				if(!(dropNode.level===1&&type!=='inner')){
+					canDrop=true
+				}
+			}else{//拖动的是目录
+				// console.log(dropNode.level,draggingNode.level);
+				//目录只能拖动到层级比他大的里面去
+				if(dropNode.level<draggingNode.level||(dropNode.level===draggingNode.level&&type!=='inner')){
+					canDrop=true
+				}
+			}
 
       return canDrop;
     },

部分文件因文件數量過多而無法顯示