浏览代码

Merge branch 'master' of http://8.136.199.33:3000/eta_front/eta_front into ETA1.3.6

cxmo 1 年之前
父节点
当前提交
2adb485551
共有 100 个文件被更改,包括 6422 次插入770 次删除
  1. 8 1
      build/webpack.base.conf.js
  2. 1 1
      config/index.js
  3. 3 1
      package.json
  4. 3 1
      src/api/api.js
  5. 46 2
      src/api/modules/sandApi.js
  6. 4 0
      src/api/modules/setApi.js
  7. 35 1
      src/api/modules/thirdBaseApi.js
  8. 二进制
      src/assets/img/sand_new/add_ico.png
  9. 二进制
      src/assets/img/sand_new/add_outline.png
  10. 二进制
      src/assets/img/sand_new/arrow_black_down.png
  11. 二进制
      src/assets/img/sand_new/copy.png
  12. 二进制
      src/assets/img/sand_new/delete_outline.png
  13. 二进制
      src/assets/img/sand_new/delete_outline_1.png
  14. 二进制
      src/assets/img/sand_new/double-arrow-round.png
  15. 二进制
      src/assets/img/sand_new/double-arrow-straight.png
  16. 二进制
      src/assets/img/sand_new/double-arrow.png
  17. 二进制
      src/assets/img/sand_new/edit_outline.png
  18. 二进制
      src/assets/img/sand_new/eye-show-black.png
  19. 二进制
      src/assets/img/sand_new/mindmap-double.png
  20. 二进制
      src/assets/img/sand_new/mindmap-right.png
  21. 二进制
      src/assets/img/sand_new/no-arrow-round.png
  22. 二进制
      src/assets/img/sand_new/no-arrow-straight.png
  23. 二进制
      src/assets/img/sand_new/no-arrow.png
  24. 二进制
      src/assets/img/sand_new/remove.png
  25. 二进制
      src/assets/img/sand_new/save-other.png
  26. 二进制
      src/assets/img/sand_new/single-arrow-round.png
  27. 二进制
      src/assets/img/sand_new/single-arrow-straight.png
  28. 二进制
      src/assets/img/sand_new/single-arrow.png
  29. 二进制
      src/assets/img/sand_new/style-black.png
  30. 二进制
      src/assets/img/sand_new/style-blue-light.png
  31. 二进制
      src/assets/img/sand_new/style-blue.png
  32. 二进制
      src/assets/img/sand_new/style-red.png
  33. 二进制
      src/assets/img/sand_new/tools/arrow-end-disabled.png
  34. 二进制
      src/assets/img/sand_new/tools/arrow-end.png
  35. 二进制
      src/assets/img/sand_new/tools/arrow-start-disabled.png
  36. 二进制
      src/assets/img/sand_new/tools/arrow-start.png
  37. 二进制
      src/assets/img/sand_new/tools/background-color-disabled.png
  38. 二进制
      src/assets/img/sand_new/tools/background-color.png
  39. 二进制
      src/assets/img/sand_new/tools/bold-disabled.png
  40. 二进制
      src/assets/img/sand_new/tools/bold.png
  41. 二进制
      src/assets/img/sand_new/tools/italic-disabled.png
  42. 二进制
      src/assets/img/sand_new/tools/italic.png
  43. 二进制
      src/assets/img/sand_new/tools/line-color-disabled.png
  44. 二进制
      src/assets/img/sand_new/tools/line-color.png
  45. 二进制
      src/assets/img/sand_new/tools/line-height-disabled.png
  46. 二进制
      src/assets/img/sand_new/tools/line-height.png
  47. 二进制
      src/assets/img/sand_new/tools/line-style-bend-round.png
  48. 二进制
      src/assets/img/sand_new/tools/line-style-bend.png
  49. 二进制
      src/assets/img/sand_new/tools/line-style-disabled.png
  50. 二进制
      src/assets/img/sand_new/tools/line-style-straight.png
  51. 二进制
      src/assets/img/sand_new/tools/line-style.png
  52. 二进制
      src/assets/img/sand_new/tools/line-type-disabled.png
  53. 二进制
      src/assets/img/sand_new/tools/line-type.png
  54. 二进制
      src/assets/img/sand_new/tools/line-width-disabled.png
  55. 二进制
      src/assets/img/sand_new/tools/line-width.png
  56. 二进制
      src/assets/img/sand_new/tools/redo-disabled.png
  57. 二进制
      src/assets/img/sand_new/tools/redo.png
  58. 二进制
      src/assets/img/sand_new/tools/select-icon.png
  59. 二进制
      src/assets/img/sand_new/tools/text-align-disabled.png
  60. 二进制
      src/assets/img/sand_new/tools/text-align.png
  61. 二进制
      src/assets/img/sand_new/tools/text-color-disabled.png
  62. 二进制
      src/assets/img/sand_new/tools/text-color.png
  63. 二进制
      src/assets/img/sand_new/tools/underline-disabled.png
  64. 二进制
      src/assets/img/sand_new/tools/underline.png
  65. 二进制
      src/assets/img/sand_new/tools/undo-disabled.png
  66. 二进制
      src/assets/img/sand_new/tools/undo.png
  67. 二进制
      src/assets/img/set_m/down_black.png
  68. 二进制
      src/assets/img/set_m/slide_black.png
  69. 1 6
      src/main.js
  70. 17 12
      src/routes/modules/chartRoutes.js
  71. 9 0
      src/routes/modules/dataRoutes.js
  72. 5 1
      src/utils/buttonConfig.js
  73. 20 3
      src/views/dataEntry_manage/databaseComponents/addTargetDiaBase.vue
  74. 2 1
      src/views/dataEntry_manage/databaseComponents/updateDialog.vue
  75. 2 0
      src/views/dataEntry_manage/databaseComponents/util.js
  76. 203 0
      src/views/dataEntry_manage/thirdBase/DatabankBase.vue
  77. 4 6
      src/views/datasheet_manage/addSheet.vue
  78. 3 3
      src/views/datasheet_manage/components/sheetListWrap.vue
  79. 0 292
      src/views/datasheet_manage/customAnalysis/edit.vue
  80. 49 68
      src/views/datasheet_manage/customAnalysis/list.vue
  81. 1 2
      src/views/datasheet_manage/mixins/classifyMixin.js
  82. 105 19
      src/views/datasheet_manage/sheetList.vue
  83. 2 1
      src/views/ppt_manage/newVersion/components/formatPage/mixins.js
  84. 27 15
      src/views/ppt_manage/newVersion/pptEditor.vue
  85. 16 5
      src/views/ppt_manage/newVersion/pptEnEditor.vue
  86. 20 14
      src/views/report_manage/addreportNew.vue
  87. 20 14
      src/views/report_manage/editreportNew.vue
  88. 19 1
      src/views/report_manage/mixins/messagePush.js
  89. 21 3
      src/views/report_manage/reportdtl.vue
  90. 162 93
      src/views/report_manage/reportlist.vue
  91. 158 0
      src/views/sandbox_manage/common/edge.js
  92. 282 116
      src/views/sandbox_manage/common/events.js
  93. 46 17
      src/views/sandbox_manage/common/gragh.js
  94. 566 0
      src/views/sandbox_manage/common/mindmap.js
  95. 276 64
      src/views/sandbox_manage/common/node.js
  96. 16 2
      src/views/sandbox_manage/common/options.js
  97. 57 5
      src/views/sandbox_manage/common/toolConfig.js
  98. 2 0
      src/views/sandbox_manage/index.vue
  99. 1704 0
      src/views/sandbox_manage/index_new_version.vue
  100. 2507 0
      src/views/sandbox_manage/sandFlowNew/index.vue

+ 8 - 1
build/webpack.base.conf.js

@@ -43,7 +43,8 @@ module.exports = {
     }
   },
   externals:{
-	  "vue":"Vue"
+	  "vue":"Vue",
+    "jQuery": "jQuery"
   },
   plugins: [
     new webpack.DllReferencePlugin({
@@ -57,6 +58,12 @@ module.exports = {
       threshold: 10240, // 对超过10k的数据压缩
       deleteOriginalAssets: false, // 是否删除未压缩的源文件
     }),
+    // new webpack.ProvidePlugin({
+    //   $: "jquery",
+    //   jQuery: "jquery",
+    //   'window.jQuery': 'jquery',
+    //   jQuery: 'jquery'
+    // })
   ],
   module: {
     rules: [

+ 1 - 1
config/index.js

@@ -38,7 +38,7 @@ module.exports = {
     proxyTable:{
 		'/adminapi': {
       target: "http://8.136.199.33:7778",
-      // target: "http://192.168.20.49:8605",
+      // target: "http://192.168.77.7:8606",
 			// secure:false,  // 如果是https接口,需要配置这个参数
 			changeOrigin:true, // 如果接口跨域,需要进行这个参数配置
 			pathRewrite:{

+ 3 - 1
package.json

@@ -13,6 +13,7 @@
     "build.test": "node build/build.test.js"
   },
   "dependencies": {
+    "@antv/hierarchy": "^0.6.11",
     "@antv/x6": "^1.29.1",
     "@fullcalendar/interaction": "^5.10.1",
     "@fullcalendar/timegrid": "^5.10.1",
@@ -38,7 +39,7 @@
     "js-md5": "^0.7.3",
     "less-loader": "^4.1.0",
     "lodash": "^4.17.21",
-    "minio": "^7.0.18",
+    "minio": "7.0.18",
     "pptxgenjs": "^3.10.0",
     "qrcode": "^1.4.4",
     "sortablejs": "^1.15.0",
@@ -52,6 +53,7 @@
     "vue-codemirror": "^4.0.6",
     "vue-count-to": "^1.0.13",
     "vue-froala-wysiwyg": "^3.1.0",
+    "vue-giant-tree": "^1.0.0",
     "vue-masonry": "^0.16.0",
     "vue-pdf": "^4.2.0",
     "vue-qr": "^2.3.0",

+ 3 - 1
src/api/api.js

@@ -9,7 +9,8 @@ import {
   coalDataInterface,
   sciDataInterface,
   baiinfoInterface,
-  nationalInterface
+  nationalInterface,
+  databankInterface
 } from './modules/thirdBaseApi';
 
 //手工指标 手工数据 手工数据权限
@@ -107,6 +108,7 @@ export {
   sciDataInterface,
   baiinfoInterface,
   nationalInterface,
+  databankInterface,
   cloudDiskInterface,
   homeInterface,
   businessTripInterence,

+ 46 - 2
src/api/modules/sandApi.js

@@ -120,6 +120,50 @@ export default {
 	 */
 	sandDelVersion: params => {
 		return http.post('/sandbox/version/delete',params)
-	}
-
+	},
+	// 以下是新版本逻辑图的接口
+	// 获取沙盘图分类
+	getSandboxClassify: params => {
+		return http.get('/sandbox/classify/list',params)
+	},
+	// 获取沙盘图分类-仅有分类
+	getSandboxClassifyOnly: params => {
+		return http.get('/sandbox/classifyList',params)
+	},
+	//新增沙盘图分类
+	addSandboxClassify: params => {
+		return http.post('/sandbox/classify/add',params)
+	},
+	// 编辑沙盘图分类
+	editSandboxClassify: params => {
+		return http.post('/sandbox/classify/edit',params)
+	},
+	//沙盘图/分类移动
+	sandboxClassifyMove: params => {
+		return http.post('/sandbox/classify/move',params)
+	},
+	// 删除沙盘图分类检查
+	deleteSandboxClassifyCheck: params => {
+		return http.post('/sandbox/classify/delete/check',params)
+	},
+	// 删除沙盘图/沙盘图分类
+	deleteSandbox: params => {
+		return http.post('/sandbox/classify/delete',params)
+	},
+	// 沙盘图列表详情
+	getSandboxListV2: params => {
+		return http.get('/sandbox/listV2',params)
+	},
+	//沙盘图详情 SandboxId
+	getSandboxDetail: params => {
+		return http.get('/sandbox/detail',params)
+	},
+	//保存沙盘图V2
+	sandboxSaveV2: params => {
+		return http.post('/sandbox/saveV2',params)
+	},
+	//沙盘图链接检测 {EdbInfoIdList,ChartInfoIdList,ReportIdList}
+	sandboxLinkCheck: params => {
+		return http.post('/sandbox/link/check',params)
+	},
 }

+ 4 - 0
src/api/modules/setApi.js

@@ -2,6 +2,10 @@ import http from "@/api/http.js"
 
 /* 部门管理模块 */
 const departInterence = {
+	//系统用户详情
+	systemUserInfo:params=>{
+		return http.get('/system/sysuser/detail',{})
+	},
 
 	/**
 	 * AdminId

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

@@ -677,6 +677,39 @@ const nationalInterface = {
         return http.get('/datamanage/base_from_national_statistics/index_detail',params)
     }
 }
+/* 数据宝 */
+const databankInterface = {
+    /**
+     * 获取数据源列表
+     * @param {*} params 
+     * @returns 
+     */
+    getSourceList:params=>{
+        return http.get('/datamanage/edb_source/jiayue/list',params)
+    },
+    /**
+     * 获取频度列表
+     * @param {*} params 
+     * @returns 
+     */
+    getFrequencyList:params=>{
+        return http.get('datamanage/edb_source/jiayue/frequency_list',params)
+    },
+    /**
+     * 指标数据列表
+     * @param {Number} PageSize 
+     * @param {Number} CurrentIndex 
+     * @param {Number} Source 数据源的EdbSourceId
+     * @param {String} Frequency 
+     * @param {String} Keyword 
+     * @param {Number} SortField 1-指标开始时间; 2-指标最新时间; 3-更新时间
+     * @param {Number} SortRule 1-正序; 2-倒序
+     * @returns 
+     */
+    getDataList:params=>{
+        return http.get('/datamanage/edb_source/jiayue/index_page_list',params)
+    },
+}
 
 export { 
 	lzDataInterface,
@@ -687,5 +720,6 @@ export {
 	steoInterface,
   sciDataInterface,
   baiinfoInterface,
-  nationalInterface
+  nationalInterface,
+  databankInterface
 }

二进制
src/assets/img/sand_new/add_ico.png


二进制
src/assets/img/sand_new/add_outline.png


二进制
src/assets/img/sand_new/arrow_black_down.png


二进制
src/assets/img/sand_new/copy.png


二进制
src/assets/img/sand_new/delete_outline.png


二进制
src/assets/img/sand_new/delete_outline_1.png


二进制
src/assets/img/sand_new/double-arrow-round.png


二进制
src/assets/img/sand_new/double-arrow-straight.png


二进制
src/assets/img/sand_new/double-arrow.png


二进制
src/assets/img/sand_new/edit_outline.png


二进制
src/assets/img/sand_new/eye-show-black.png


二进制
src/assets/img/sand_new/mindmap-double.png


二进制
src/assets/img/sand_new/mindmap-right.png


二进制
src/assets/img/sand_new/no-arrow-round.png


二进制
src/assets/img/sand_new/no-arrow-straight.png


二进制
src/assets/img/sand_new/no-arrow.png


二进制
src/assets/img/sand_new/remove.png


二进制
src/assets/img/sand_new/save-other.png


二进制
src/assets/img/sand_new/single-arrow-round.png


二进制
src/assets/img/sand_new/single-arrow-straight.png


二进制
src/assets/img/sand_new/single-arrow.png


二进制
src/assets/img/sand_new/style-black.png


二进制
src/assets/img/sand_new/style-blue-light.png


二进制
src/assets/img/sand_new/style-blue.png


二进制
src/assets/img/sand_new/style-red.png


二进制
src/assets/img/sand_new/tools/arrow-end-disabled.png


二进制
src/assets/img/sand_new/tools/arrow-end.png


二进制
src/assets/img/sand_new/tools/arrow-start-disabled.png


二进制
src/assets/img/sand_new/tools/arrow-start.png


二进制
src/assets/img/sand_new/tools/background-color-disabled.png


二进制
src/assets/img/sand_new/tools/background-color.png


二进制
src/assets/img/sand_new/tools/bold-disabled.png


二进制
src/assets/img/sand_new/tools/bold.png


二进制
src/assets/img/sand_new/tools/italic-disabled.png


二进制
src/assets/img/sand_new/tools/italic.png


二进制
src/assets/img/sand_new/tools/line-color-disabled.png


二进制
src/assets/img/sand_new/tools/line-color.png


二进制
src/assets/img/sand_new/tools/line-height-disabled.png


二进制
src/assets/img/sand_new/tools/line-height.png


二进制
src/assets/img/sand_new/tools/line-style-bend-round.png


二进制
src/assets/img/sand_new/tools/line-style-bend.png


二进制
src/assets/img/sand_new/tools/line-style-disabled.png


二进制
src/assets/img/sand_new/tools/line-style-straight.png


二进制
src/assets/img/sand_new/tools/line-style.png


二进制
src/assets/img/sand_new/tools/line-type-disabled.png


二进制
src/assets/img/sand_new/tools/line-type.png


二进制
src/assets/img/sand_new/tools/line-width-disabled.png


二进制
src/assets/img/sand_new/tools/line-width.png


二进制
src/assets/img/sand_new/tools/redo-disabled.png


二进制
src/assets/img/sand_new/tools/redo.png


二进制
src/assets/img/sand_new/tools/select-icon.png


二进制
src/assets/img/sand_new/tools/text-align-disabled.png


二进制
src/assets/img/sand_new/tools/text-align.png


二进制
src/assets/img/sand_new/tools/text-color-disabled.png


二进制
src/assets/img/sand_new/tools/text-color.png


二进制
src/assets/img/sand_new/tools/underline-disabled.png


二进制
src/assets/img/sand_new/tools/underline.png


二进制
src/assets/img/sand_new/tools/undo-disabled.png


二进制
src/assets/img/sand_new/tools/undo.png


二进制
src/assets/img/set_m/down_black.png


二进制
src/assets/img/set_m/slide_black.png


+ 1 - 6
src/main.js

@@ -151,12 +151,7 @@ router.beforeEach(async(to, from, next) => {
 
   /* 沙盘详情name添加 */
   if (to.path === "/sandflow") {
-    to.matched[1].name =
-      to.query.type === "view"
-        ? "查看沙盘"
-        : to.query.id
-        ? "编辑沙盘"
-        : "添加沙盘";
+    to.matched[1].name = to.query.SandboxId? "编辑逻辑": "添加逻辑";
   }
 
   if (to.path === "/analyseVariety") {

+ 17 - 12
src/routes/modules/chartRoutes.js

@@ -142,15 +142,6 @@ export default [
 					pathName: "混合表格",
 				}
 			},
-			{
-				path:"editSheetAnalysis",
-				name:"编辑表格",
-				component:()=>import('@/views/datasheet_manage/customAnalysis/edit.vue'),
-				meta: { 
-					pathFrom: "sheetAnalysisList",
-					pathName: "自定义分析",
-				}
-			},
 			{
 				path:"sheetAnalysisList",
 				name:"自定义分析",
@@ -175,15 +166,29 @@ export default [
 		component: home,
 		name: 'ETA逻辑',
 		hidden: false,
-		children: [{
+		children: [
+			// {
+			// 	path: "sandlist", // 旧版本
+			// 	name: 'ETA逻辑',
+			// 	component: () => import('@/views/sandbox_manage/index.vue'),
+			// 	hidden: false,
+			// },
+			// 改版后的ETA逻辑图
+			{
 				path: "sandlist",
 				name: 'ETA逻辑',
-				component: () => import('@/views/sandbox_manage/index.vue'),
+				component: () => import('@/views/sandbox_manage/index_new_version.vue'),
 				hidden: false,
 			},
+			// {
+			// 	path: "sandflow", // 旧版本
+			// 	component: () => import('@/views/sandbox_manage/sandFlow/index.vue'),
+			// 	hidden: true,
+			// },
 			{
 				path: "sandflow",
-				component: () => import('@/views/sandbox_manage/sandFlow/index.vue'),
+				name: '添加逻辑',
+				component: () => import('@/views/sandbox_manage/sandFlowNew/index.vue'),
 				hidden: true,
 			}
 		]

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

@@ -192,6 +192,15 @@ export default [
         name: "期货数据库",
         component: () => import("@/views/futures_manage/futuresBase.vue"),
       },
+      {
+        path: "databankBase",
+        component: () => import("@/views/dataEntry_manage/thirdBase/DatabankBase.vue"),
+        name: "数据宝",
+        hidden: false,
+        meta: {
+          keepAlive: false,
+        },
+      },
     ],
   },
 ];

+ 5 - 1
src/utils/buttonConfig.js

@@ -425,10 +425,14 @@ export const etaTablePermission = {
  * --------------------------------------------------------------------------ETA逻辑------------------------------------------------
 */
 export const sandboxPermission = {
-    sandbox_variety:'sandbox:variety',//沙盘品种选择,控制筛选项和列表项
+    sandbox_variety:'sandbox:variety',//沙盘品种选择,添加目录的时候控制显示
     sandbox_addMy:'sandbox:addMy',//复制图片
     sandbox_del:'sandbox:del',//删除
     sandbox_saveView:'sandbox:saveView',//添加/编辑/查看
+    sandbox_search:'sandbox:search',//搜索
+    sandbox_classify_move:'sandbox:classify:move',//分类操作:移动
+    sandbox_classify_del:'sandbox:classify:del',//分类操作:删除
+    sandbox_classify_addEdit:'sandbox:classify:addEdit',//分类操作:添加/编辑
 }
 /*
  * --------------------------------------------------------------------------语义分析------------------------------------------------

+ 20 - 3
src/views/dataEntry_manage/databaseComponents/addTargetDiaBase.vue

@@ -69,7 +69,7 @@
 
 <script>
 import { dataBaseInterface } from '@/api/api.js'
-import { fromArr, fromCode } from './util';
+import { fromArr, fromCode ,frequencyArr} from './util';
 export default {
 	name: '',
 	props: {
@@ -110,6 +110,13 @@ export default {
 			search_company_txt: ''
 		};
 	},
+	watch:{
+		isAddTarget(newVal){
+			if(newVal){
+				this.getTargetSource()
+			}
+		}
+	},
 	methods: {
 		init() {
 			this.fromType = 'wind'
@@ -169,12 +176,18 @@ export default {
 							unit: res.Data.SearchItem.Unit,
 							frequency: res.Data.SearchItem.Frequency,
 						} : {}
+						let jy_params = Number(this.fromCode.get(this.fromType))>1000?{
+							edb_name:res.Data.SearchItem.EdbName,
+							unit:res.Data.SearchItem.Unit,
+							frequency:frequencyArr.includes(res.Data.SearchItem.Frequency)?res.Data.SearchItem.Frequency:''
+						}:{}
 						this.add_params = {
 							EdbCode: res.Data.SearchItem.EdbCode,
 							EndDate: res.Data.SearchItem.EndDate,
 							StartDate: res.Data.SearchItem.StartDate,
 							Source: Number(this.fromCode.get(this.fromType)),
-							...opther_params
+							...opther_params,
+							...jy_params
 						}
 						this.status = res.Data.Status;
 						let classify_arr = res.Data.ClassifyList || [];
@@ -223,19 +236,23 @@ export default {
 		},
 		getTargetSource(){
 			this.fromArr = []
+			this.fromCode = []
 			dataBaseInterface.getDataSource({IsBase:1}).then(res=>{
 				if(res.Ret!==200) return
 				if(res.Data){
 					this.fromArr = res.Data.map(i=>{
 						return i.SourceName
 					})
+					this.fromCode = new Map(res.Data.map(i=>{
+						return [i.SourceName,i.EdbSourceId]
+					}))
 				}
 			})
 		}
 	},
 	created() { },
 	mounted() {
-		this.getTargetSource()
+		//this.getTargetSource()
 	},
 }
 </script>

+ 2 - 1
src/views/dataEntry_manage/databaseComponents/updateDialog.vue

@@ -71,6 +71,7 @@ export default {
       if (newval) {
         this.getTotal();
         this.getDataList();
+        this.getTargetSource();
         this.$nextTick(() => {
           this.loadMoveHandler();
         })
@@ -405,7 +406,7 @@ export default {
   },
   created() { },
   mounted() {
-      this.getTargetSource()
+      //this.getTargetSource()
   },
 };
 </script>

+ 2 - 0
src/views/dataEntry_manage/databaseComponents/util.js

@@ -153,6 +153,8 @@ export const computedBatchTypes = [
 	}
 ]
 
+//频度
+export const frequencyArr = ['日度','周度','旬度','月度','季度','年度']
 //添加基础指标来源
 export const fromArr = ['wind','同花顺','彭博','彭博财务','路透','手工指标','隆众指标','SMM','Mysteel','郑商所',
 '大商所','上期所','中金所','上期能源','欧洲天然气','中国煤炭市场网','谷歌出行指数','EIA STEO报告','UN','卓创数据(红桃3)',

+ 203 - 0
src/views/dataEntry_manage/thirdBase/DatabankBase.vue

@@ -0,0 +1,203 @@
+<template>
+    <!-- 数据宝页面 -->
+    <div class="data-bank-base-wrap">
+        <div class="select-box">
+            <!-- <el-radio-group v-model="choosedSource" size="medium" @input="handleCurrentChange(1)">
+                <el-radio-button v-for="source in sourceList" 
+                    :key="source.EdbSourceId" 
+                    :label="source.EdbSourceId">{{source.SourceName}}</el-radio-button>
+            </el-radio-group> -->
+            <el-select v-model="choosedSource">
+                <el-option v-for="source in sourceList" 
+                :key="source.EdbSourceId"
+                :value="source.EdbSourceId"
+                :label="source.SourceName"
+                ></el-option>
+            </el-select>
+            <el-select v-model="selectValue" @change="handleCurrentChange(1)"
+                placeholder="请选择频度"
+                clearable
+                style="width:240px;margin-left: auto;">
+                <el-option v-for="item in frequencyList" 
+                    :key="item" :value="item" :label="item" />
+            </el-select>
+            <el-input v-model="inputValue" @input="handleCurrentChange(1)"
+            placeholder="指标ID/指标名称"
+            clearable
+            prefix-icon="el-icon-search"
+            style="width:240px;margin-left:30px;"></el-input>
+        </div>
+        <div class="table-box">
+            <el-table :data="tableData" border  @sort-change="sortChange" 
+                v-loading="tableLoading" element-loading-text="数据加载中...">
+                <el-table-column v-for="column in tableColumnList" 
+                    align="center"
+                    :key="column.key"
+                    :label="column.label"
+                    :prop="column.key"
+                    :min-width="column.minWidth"
+                    :sortable="column.sortable"></el-table-column>
+                <div class="empty-box" slot="empty">
+                    <tableNoData text="暂无数据"/>
+                </div>
+            </el-table>
+        </div>
+        <div class="page-box">
+          <el-pagination
+                layout="total,prev,pager,next,jumper"
+                background
+                :current-page="pageNo"
+                @current-change="handleCurrentChange"
+                :page-size="pageSize"
+                :total="total"
+            >
+          </el-pagination>
+        </div>
+    </div>
+</template>
+
+<script>
+import { databankInterface } from "@/api/api.js";
+export default {
+    data() {
+        return {
+            sourceList:[],//数据源列表
+            choosedSource:'',//选择的数据源
+
+            frequencyList:[],//频度列表
+            selectValue:'',//选择的频度
+
+            inputValue:'',//搜索框
+
+            tableColumnList:[
+                {
+                    key:'Id',
+                    label:'指标ID'
+                },
+                {
+                    key:'Code',
+                    label:'指标编码'
+                },
+                {
+                    key:'Name',
+                    label:'指标名称',
+                    minWidth:170,
+                },
+                {
+                    key:'Frequency',
+                    label:'频度'
+                },
+                {
+                    key:'Unit',
+                    label:'单位'
+                },
+                {
+                    key:'DateFirst',
+                    label:'指标开始时间',
+                    sortable:true,
+                },
+                {
+                    key:'DateLast',
+                    label:'指标最新时间',
+                    sortable:true
+                },
+                {
+                    key:'TimeLastUpdate',
+                    label:'更新时间',
+                    sortable:true
+                }
+            ],
+            tableData:[],//表格数据
+            pageNo:1,
+            pageSize:15,
+            total:0,
+            SortField:0,
+            SortRule:0,
+            tableLoading:false,
+        };
+    },
+    watch:{
+        choosedSource(newVal){
+            if(newVal){
+                this.handleCurrentChange(1)
+            }
+        }
+    },
+    methods: {
+        getFrequencyList(){
+            databankInterface.getFrequencyList().then(res=>{
+                if(res.Ret!==200) return 
+                this.frequencyList = res.Data||[]
+            })
+        },
+        getSourceList(){
+            databankInterface.getSourceList().then(res=>{
+                if(res.Ret!==200) return
+                this.sourceList = res.Data||[]
+                this.choosedSource = this.sourceList[0].EdbSourceId
+            })
+        },
+        getTableData(){
+            this.tableLoading=true
+            databankInterface.getDataList({
+                Source:Number(this.choosedSource),
+                CurrentIndex:this.pageNo,
+                PageSize:this.pageSize,
+                Frequency:this.selectValue,
+                Keyword:this.inputValue,
+                SortField:this.SortField,
+                SortRule:this.SortRule
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                if(!res.Data) return 
+                this.tableData = res.Data.List
+                this.total = res.Data.Paging.Totals
+                this.tableLoading=false
+            })
+        },
+        handleCurrentChange(page){
+            this.pageNo = page
+            this.getTableData()
+        },
+        sortChange({prop,order}){
+            const propMap = {
+                'DateFirst':1,
+                'DateLast':2,
+                'TimeLastUpdate':3
+            }
+            const orderMap = {
+                'ascending':1,
+                'descending':2
+            }
+            this.SortRule = orderMap[order]||0
+            this.SortField = propMap[prop]||0
+            this.handleCurrentChange(1)
+        }
+
+    },
+    mounted(){
+        this.getSourceList()
+        this.getFrequencyList()
+    }
+};
+</script>
+
+<style scoped lang="scss">
+.data-bank-base-wrap{
+    box-sizing: border-box;
+    background-color: #fff;
+    padding:20px 30px;
+    border-radius: 4px;
+    .select-box{
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+    }
+    .table-box{
+        margin:30px 0;
+    }
+    .page-box{
+        text-align: right;
+    }
+}
+</style>

+ 4 - 6
src/views/datasheet_manage/addSheet.vue

@@ -98,11 +98,7 @@ export default {
   methods: {
 
     backHandle() {
-      // if(this.sheetId){
-      //   this.$router.back()
-      // }else{
-        window.close();
-      // }
+      window.close();
     },
 
     /* 获取分类 */
@@ -135,7 +131,8 @@ export default {
         },1000)
         return 
       }
-      const { ExcelInfoId,ExcelName,ExcelClassifyId,ExcelType,ModifyTime,Content,Source} = res.Data;
+      const { ExcelInfoId,ExcelName,ExcelClassifyId,ExcelType,ModifyTime,Content,Source,Button} = res.Data;
+      this.sheetButton=Button
       this.sheetForm = {
         infoId:ExcelInfoId,
         name: ExcelName,
@@ -159,6 +156,7 @@ export default {
 
     },
     autoSaveFun:_.debounce(async function(){
+      // cancelAutoSave -- 由于是延时自动保存 防止用户在聚焦文本框时点击保存,文本框失焦后又发起自动保存的情况
       if(!this.sheetId && this.sheetInit || this.cancelAutoSave) return
       const { name,classify,infoId } = this.sheetForm;
       luckysheet.exitEditMode()

+ 3 - 3
src/views/datasheet_manage/components/sheetListWrap.vue

@@ -29,12 +29,12 @@
                 @click="$emit('downloadExcel',cell)"
                 >下载</span
               >
-              <span
-                v-if="($parent.sheetDetailInfo.Button && $parent.sheetDetailInfo.Button.DeleteButton && $parent.isSheetBtnShow('del'))"
+              <!-- <span
+                v-if=" $parent.isSheetBtnShow('del')"
                 class="deletesty"
                 @click="$emit('delSheetHandle',{cell, type:'del-list'})"
                 >删除</span
-              >
+              > -->
             </div>
           </div>
         </el-card>

+ 0 - 292
src/views/datasheet_manage/customAnalysis/edit.vue

@@ -1,292 +0,0 @@
-<template>
-  <div class="sheet-detail-wrapper" >
-    <div class="detail-top">
-      <el-input
-        ref="sheetEditTitRef"
-        style="width: 400px"
-        placeholder="请输入表格名称"
-        class="label-input"
-        v-model="sheet_title"
-        v-if="sheetDetailInfo.isEditTit"
-        @blur="changeValue(sheetDetailInfo, 'edit-tit')"
-      />
-      <span
-        class="sheet-name"
-        @click="editNodeLabel(sheetDetailInfo, 'edit-tit')"
-        v-else
-      >
-        {{ sheetDetailInfo.ExcelName }}
-        <i class="el-icon-edit"/>
-      </span>
-      <div class="sheet-anothor-info">
-        <span class="author">作者:{{ sheetDetailInfo.SysUserRealName }}</span>
-        <ul class="action-ul" v-if="sheetDetailInfo.Button">
-          <div v-if="updateTime" style="color:#999999;">最近保存时间:{{ updateTime }}</div>
-          <el-tooltip effect="dark" content="在当前表格选择日期列和数据列生成指标" placement="top-start">
-              <li class="editsty" @click="HandleToPath" v-if="isSheetBtnShow('createedb')&&sheetDetailInfo.Button.OpEdbButton">
-                <img src="~@/assets/img/icons/choose_bluebg_new.png"/>
-                <span>生成指标</span>
-              </li>
-          </el-tooltip>
-
-          <el-tooltip effect="dark" content="根据表格保存的最新内容,更新当前表格生成的所有指标" placement="top-start">
-              <li class="editsty" @click="refreshSheet" v-if="isSheetBtnShow('refresh')&&sheetDetailInfo.Button.RefreshEdbButton">
-                <img src="~@/assets/img/icons/refresh_blue_new.png"/>
-                <span>刷新指标</span>
-              </li>
-          </el-tooltip>
-          <li class="editsty" @click="saveHandle" v-if="isSheetBtnShow('save')&&sheetDetailInfo.Button.OpButton">
-            <img src="~@/assets/img/icons/save_blue_new.png"/>
-            <span>保存</span>
-          </li>
-          <li class="editsty" @click="backHandle">
-            <img src="~@/assets/img/icons/back_arrow_blue_new.png"/>
-            <span>返回</span>
-          </li>
-        </ul>
-      </div>
-    </div>
-
-    <dataLoading :loading="isSheetLoading"/>
-
-    <!-- 表格 -->
-    <div class="sheet-wrap">
-      <Sheet
-        ref="sheetRef"
-        v-if="sheetConfigOpt.data"
-        :option="sheetConfigOpt"
-      />
-    </div>
-  </div>
-</template>
-
-<script>
-import * as sheetInterface from "@/api/modules/sheetApi.js";
-import Sheet from "../components/SheetExcel.vue";
-import leftMixin from "../mixins/classifyMixin";
-import { getSheetImage } from "../common/option";
-
-  export default {
-    components:{Sheet},
-    mixins: [leftMixin],
-    data() {
-      return {
-        sheetDataPage: 2,
-        sheetAllcellData:[],//全部单元格数据 分页push
-        dataToalPage: 0,
-        isSheetLoading: false,
-        code:'',
-        sheetConfigOpt: {
-          showsheetbar: true,
-          data: null
-        },
-        sheet_title: "", //表格标题 双击标题修改时来存储最新值
-        sheetDetailInfo:{},
-        isCanEdit:false,
-        sheetId:'',
-        loading:null,
-        updateTime:''
-      }
-    },
-    beforeRouteLeave(to,from,next){
-      if(to.path!='/editSheetAnalysis'){
-        this.markFinishStatus()
-      }
-      next()
-    },
-    created(){
-      // console.log(this.$route.query.code);
-      if(!this.$route.query.code){
-        this.$message.warning("参数丢失")
-        this.backHandle()
-      }else{
-        this.code = this.$route.query.code
-        this.getDetailHandle()
-      }
-    },
-    mounted() {
-      window.addEventListener('beforeunload',this.markFinishStatus)
-    },
-    beforeDestroy(){
-      window.removeEventListener('beforeunload',this.markFinishStatus)
-    },
-    methods:{
-      /* 获取表格详情 */
-      getDetailHandle() {
-
-        this.isSheetLoading = true;
-        sheetInterface.sheetAnalysisInterface.getExcelDetail({
-          UniqueCode:this.code,
-        }).then((res) => {
-          if (res.Ret !== 200) return;
-          this.isCanEdit = res.Data.ExcelInfo.CanEdit
-          if(!this.isCanEdit){
-            this.$message.warning(`${res.Data.ExcelInfo.Editor}正在编辑中`)
-            setTimeout(()=>{
-              this.backHandle()
-            },1000)
-            return 
-          }
-          this.sheetDetailInfo = res.Data.ExcelInfo;
-          this.updateTime = this.$moment(this.sheetDetailInfo.ModifyTime).format('YYYY-MM-DD HH:mm:ss')||''
-          this.sheetId = this.sheetId || res.Data.ExcelInfo.ExcelInfoId;
-          this.dataToalPage =  Math.max(...res.Data.SheetList.map(_ => _.PageNum));
-          this.sheetAllcellData = res.Data.SheetList.map(_ => _.Data ? JSON.parse(_.Data.Data) : []);
-
-          this.getCellData(res.Data.SheetList)
-        });
-      },
-      //分页获取表格数据
-      async getCellData(sheets) {
-
-        let res = await sheetInterface.sheetAnalysisInterface.getExcelDataByPage({
-          UniqueCode: this.code,
-          Page: this.sheetDataPage
-        })
-
-        if(res.Ret !== 200) return
-        console.log(this.sheetAllcellData)
-
-        for(let i = 0;i<this.sheetAllcellData.length;i++) {
-          if(res.Data[i].Data) {
-            this.sheetAllcellData[i] = [...this.sheetAllcellData[i],...JSON.parse(res.Data[i].Data.Data)]
-          }
-
-          continue
-        }
-        
-        //数据继续加载或渲染表格.
-        if(this.sheetDataPage < this.dataToalPage) {
-          this.sheetDataPage++;
-          this.getCellData(sheets)
-        }else {
-          this.sheetConfigOpt.data = sheets.map((_,index) => ({
-            index: _.Index, //工作表id
-            order: _.Sort, //工作表的下标
-            name: _.SheetName,
-            calcChain: _.CalcChain?JSON.parse(_.CalcChain):[],
-            config: JSON.parse(_.Config),
-            celldata: this.sheetAllcellData[index],
-          }))
-
-          console.log(this.sheetConfigOpt)
-
-          this.isSheetLoading = false;
-        }
-      },
-      backHandle(){
-        let params={
-          code:this.sheetDetailInfo.UniqueCode,
-          id:this.sheetDetailInfo.ExcelInfoId
-        }
-        sessionStorage.setItem('editSheetAnalysisBack',JSON.stringify(params))
-        this.$router.back()
-      },
-      //跳转生成指标
-      HandleToPath() {
-        this.$router.push({ path: '/createTaregtBySheet',query: {
-          code: this.sheetDetailInfo.UniqueCode 
-        }});
-      },
-      /* 刷新表格 */
-      refreshSheet: _.debounce(async function() {
-        let res = await sheetInterface.sheetAnalysisInterface.sheetRefresh({ExcelInfoId: this.sheetDetailInfo.ExcelInfoId})
-
-        if(res.Ret !== 200) return 
-        this.$message.success(res.Msg)
-      },300),
-      /* 保存表格 */
-      saveHandle: _.debounce(async function () {
-        luckysheet.exitEditMode();
-        let data = luckysheet.getAllSheets();
-
-        this.loading = this.$loading({
-          target: ".sheet-detail-wrapper",
-          lock: true,
-          text: "保存中...",
-          spinner: "el-icon-loading",
-          background: "rgba(255, 255, 255, 0.6)",
-        });
-
-        let img = getSheetImage(data[0]);
-        const form = new FormData();
-        form.append("Image", img);
-        const { Data } = await sheetInterface.uploadImg(form);
-
-        data.luckysheet_select_save = [];
-        const { ExcelInfoId, ExcelName, ExcelClassifyId } = this.sheetDetailInfo;
-        const res = await sheetInterface.sheetAnalysisInterface.sheetEdit({
-          ExcelInfoId,
-          ExcelName,
-          ExcelClassifyId,
-          ExcelImage: Data.ResourceUrl,
-          Content: JSON.stringify(data),
-        });
-        this.loading.close();
-        if (res.Ret !== 200) return;
-        this.$message.success("保存成功");
-        this.$router.back()
-      }, 300),
-      markFinishStatus(){
-        if((!this.sheetId) || (!this.isCanEdit)) return
-        sheetInterface.markSheetEditStatus({ExcelInfoId: +this.sheetId,Status:2}).then(res=>{
-          if(res.Ret != 200) return 
-        })
-      }
-    }
-  }
-</script>
-
-<style lang="scss" scoped>
-  .sheet-detail-wrapper {
-    height: 100%;
-    border: 1px solid #ececec;
-    border-radius: 4px;
-    box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.05);
-    overflow: auto;
-    background: #fff;
-    .detail-top {
-      padding: 20px;
-      // display: flex;
-      // justify-content: space-between;
-      // align-items: center;
-      border-bottom: 1px solid #ececec;
-      .sheet-name {
-        font-size: 18px;
-        color: #333333;
-        margin-bottom: 6px;
-        cursor: pointer;
-        max-width: 450px;
-        &:hover {
-          text-decoration: underline;
-        }
-      }
-      .sheet-anothor-info{
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-        .author{
-          color: #666666;
-          font-size: 16px;
-        }
-        .action-ul {
-          display: flex;
-          li {
-            margin: 0 10px;
-            display: flex;
-            align-items: center;
-            img{
-              height: 16px;
-              width: 16px;
-              margin-right: 4px;
-            }
-          }
-        }
-      }
-    }
-    .sheet-wrap {
-      position: relative;
-      height: calc(100vh - 210px);
-    }
-  }
-</style>

+ 49 - 68
src/views/datasheet_manage/customAnalysis/list.vue

@@ -142,7 +142,7 @@
         <!-- 表格详情 -->
         <div class="sheet-detail-wrapper" v-if="select_id" >
           <div class="detail-top">
-            <!-- <el-input
+            <el-input
               ref="sheetEditTitRef"
               style="width: 400px"
               placeholder="请输入表格名称"
@@ -150,10 +150,12 @@
               v-model="sheet_title"
               v-if="sheetDetailInfo.isEditTit"
               @blur="changeValue(sheetDetailInfo, 'edit-tit')"
-            /> -->
-            <div class="sheet-name">
+            />
+            <div class="sheet-name"
+              @click="editNodeLabel(sheetDetailInfo, 'edit-tit')"
+              v-else>
               {{ sheetDetailInfo.ExcelName }}
-              <!-- <i class="el-icon-edit"/> -->
+              <i class="el-icon-edit"/>
             </div>
             <div class="sheet-anothor-info">
               <span class="author">作者:{{ sheetDetailInfo.SysUserRealName }}</span>
@@ -172,15 +174,18 @@
                       <span>刷新指标</span>
                     </li>
                 </el-tooltip>
-                <!-- <li class="editsty" @click="saveHandle" v-if="isSheetBtnShow('save')&&sheetDetailInfo.Button.OpButton">保存</li> -->
-                <li
+                <li class="editsty" @click="saveHandle" v-if="isSheetBtnShow('save')&&sheetDetailInfo.Button.OpButton">
+                  <img src="~@/assets/img/icons/save_blue_new.png"/>
+                  <span>保存</span>
+                </li>
+                <!-- <li
                   class="editsty"
                   @click="goEdit"
                   v-if="(sheetDetailInfo.Button && sheetDetailInfo.Button.OpButton&&isSheetBtnShow('edit'))"
                 >
                   <img src="~@/assets/img/icons/edit_blue_new.png" v-if="!editButtonText"/>
                   <span>{{ editButtonText?editButtonText:'编辑' }}</span> 
-                </li>
+                </li> -->
                 <li
                   class="editsty"
                   @click="saveOtherHandle"
@@ -214,7 +219,6 @@
               ref="sheetRef"
               v-if="sheetConfigOpt.data"
               :option="sheetConfigOpt"
-              :limit="{disabled:true}"
             />
           </div>
         </div>
@@ -389,9 +393,6 @@ export default {
         '/sheetAnalysisList': 4,
       },
       saveTime:"",
-      editButtonText:'',
-      adminId:localStorage.getItem("AdminId") || '0',
-      excelAdminId:""
     };
   },
   watch: {
@@ -612,54 +613,40 @@ export default {
       };
       request.send();
     },
-    goEdit(){
-      sheetInterface.markSheetEditStatus({ExcelInfoId: this.select_id,Status:1}).then(res=>{
-        if(res.Ret != 200) return 
-        if(res.Data.Status==0){
-          this.$router.push({
-            path: '/editSheetAnalysis',
-            query: { code: this.sheetDetailInfo.UniqueCode },
-          });
-
-        }else if(res.Data.Status==1){
-          this.editButtonText = `${res.Data.Editor}编辑中`
-          this.$message.warning('当前'+this.editButtonText)
-        }
-      })
-    },
     /* 保存表格 */
-    // saveHandle: _.debounce(async function () {
-    //   luckysheet.exitEditMode();
-    //   let data = luckysheet.getAllSheets();
-
-    //   this.loading = this.$loading({
-    //     target: ".dataSheet-container",
-    //     lock: true,
-    //     text: "保存中...",
-    //     spinner: "el-icon-loading",
-    //     background: "rgba(255, 255, 255, 0.6)",
-    //   });
-
-    //   let img = getSheetImage(data[0]);
-    //   const form = new FormData();
-    //   form.append("Image", img);
-    //   const { Data } = await sheetInterface.uploadImg(form);
-
-    //   data.luckysheet_select_save = [];
-    //   const { ExcelInfoId, ExcelName, ExcelClassifyId } = this.sheetDetailInfo;
-
-    //   const res = await sheetInterface.sheetAnalysisInterface.sheetEdit({
-    //     ExcelInfoId,
-    //     ExcelName,
-    //     ExcelClassifyId,
-    //     ExcelImage: Data.ResourceUrl,
-    //     Content: JSON.stringify(data),
-    //   });
-    //   this.loading.close();
-    //   if (res.Ret !== 200) return;
-    //   this.$message.success("保存成功");
-    //   this.getTreeData();
-    // }, 300),
+    saveHandle: _.debounce(async function () {
+      luckysheet.exitEditMode();
+      let data = luckysheet.getAllSheets();
+
+      this.loading = this.$loading({
+        target: ".dataSheet-container",
+        lock: true,
+        text: "保存中...",
+        spinner: "el-icon-loading",
+        background: "rgba(255, 255, 255, 0.6)",
+      });
+
+      let img = getSheetImage(data[0]);
+      const form = new FormData();
+      form.append("Image", img);
+      const { Data } = await sheetInterface.uploadImg(form);
+
+      data.luckysheet_select_save = [];
+      const { ExcelInfoId, ExcelName, ExcelClassifyId } = this.sheetDetailInfo;
+
+      const res = await sheetInterface.sheetAnalysisInterface.sheetEdit({
+        ExcelInfoId,
+        ExcelName,
+        ExcelClassifyId,
+        ExcelImage: Data.ResourceUrl,
+        Content: JSON.stringify(data),
+      });
+      this.loading.close();
+      if (res.Ret !== 200) return;
+      this.saveTime = this.$moment().format('YYYY-MM-DD HH:mm:ss')
+      this.$message.success("保存成功");
+      this.getTreeData();
+    }, 300),
 
     /* 获取表格列表 */
     getPublicList() {
@@ -709,9 +696,7 @@ export default {
         if (res.Ret !== 200) return;
 
         this.sheetDetailInfo = res.Data.ExcelInfo;
-        this.saveTime = this.$moment(this.sheetDetailInfo.ModifyTime).format('YYYY-MM-DD HH:mm:ss')||''
-        this.excelAdminId = this.sheetDetailInfo.SysUserId
-        this.editButtonText = this.sheetDetailInfo.CanEdit?'':`${this.sheetDetailInfo.Editor}编辑中`
+        this.saveTime = this.$moment(this.sheetDetailInfo.ModifyTime).format('YYYY-MM-DD HH:mm:ss')
         this.dataToalPage =  Math.max(...res.Data.SheetList.map(_ => _.PageNum));
         this.sheetAllcellData = res.Data.SheetList.map(_ => _.Data ? JSON.parse(_.Data.Data) : []);
 
@@ -846,7 +831,7 @@ export default {
       this.$router.push({ path: '/createTaregtBySheet',query: {
         code: this.sheetDetailInfo.UniqueCode 
       }});
-    }
+    },
 
   },
   mounted() {
@@ -855,10 +840,6 @@ export default {
         code: this.$route.query.code,
         id: Number(this.$route.query.id),
       });
-    } else if(sessionStorage.getItem('editSheetAnalysisBack')){
-      let params=JSON.parse(sessionStorage.getItem('editSheetAnalysisBack'))
-      this.getTreeData(params);
-      sessionStorage.removeItem('editSheetAnalysisBack')
     }else {
       this.getTreeData();
       this.getPublicList();
@@ -1096,8 +1077,8 @@ $normal-font: 14px;
 <style lang="scss">
 .dataSheet-container {
   .label-input .el-input__inner {
-    height: 25px;
-    line-height: 25px;
+    height: 27px;
+    line-height: 27px;
     padding: 0 10px;
   }
 

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

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

+ 105 - 19
src/views/datasheet_manage/sheetList.vue

@@ -136,7 +136,7 @@
         <!-- 表格详情 -->
         <div class="sheet-detail-wrapper" v-if="select_id">
           <div class="detail-top">
-            <!-- <el-input
+            <el-input
               ref="sheetEditTitRef"
               style="width: 400px"
               placeholder="请输入表格名称"
@@ -144,18 +144,18 @@
               v-model="sheet_title"
               v-if="sheetDetailInfo.isEditTit"
               @blur="changeValue(sheetDetailInfo, 'edit-tit')"
-            /> -->
-            <!-- <span
+            />
+            <span
               class="sheet-name"
-              @click="editNodeLabel(sheetDetailInfo, 'edit-tit')"
+              @click="editExcelName(sheetDetailInfo, 'edit-tit')"
               v-else
             >
               {{ sheetDetailInfo.ExcelName }}
-              <i class="el-icon-edit" v-if="sheetDetailInfo.Source === 1" />
-            </span> -->
-            <div class="sheet-name">
+              <i class="el-icon-edit" v-if="sheetDetailInfo.Source === 1 && onlineExcelEditing" />
+            </span>
+            <!-- <div class="sheet-name">
               {{ sheetDetailInfo.ExcelName }}
-            </div>
+            </div> -->
             <div class="sheet-anothor-info">
               <span class="author">作者:{{ sheetDetailInfo.SysUserRealName }}</span>
               <ul class="action-ul">
@@ -163,11 +163,19 @@
                 <li
                   class="editsty"
                   @click="goEditHandle"
-                  v-if="(sheetDetailInfo.Button && sheetDetailInfo.Button.OpButton&&isSheetBtnShow('edit'))"
+                  v-if="(sheetDetailInfo.Button && sheetDetailInfo.Button.OpButton&&isSheetBtnShow('edit') && (!onlineExcelEditing))"
                 >
                   <img src="~@/assets/img/icons/edit_blue_new.png" v-if="!editButtonText"/>
                   <span>{{ editButtonText?editButtonText:'编辑' }}</span> 
                 </li>
+                <li
+                  class="editsty"
+                  @click="saveHandle"
+                  v-if="(sheetDetailInfo.Button && sheetDetailInfo.Button.OpButton&&isSheetBtnShow('save') && onlineExcelEditing)"
+                >
+                  <img src="~@/assets/img/icons/save_blue_new.png"/>
+                  <span>保存</span> 
+                </li>
                 <template v-if="[2, 3].includes(sheetDetailInfo.Source)">
                   <li
                     class="editsty"
@@ -218,7 +226,14 @@
                   scrollLeft: 0
                 }]
               }"
-              :limit="{disabled:true}"
+              :sheetInfo="{
+                ExcelInfoId: sheetDetailInfo.ExcelInfoId,
+                ExcelName: sheetDetailInfo.ExcelName,
+                ExcelClassifyId: sheetDetailInfo.ExcelClassifyId,
+                Source: sheetDetailInfo.Source
+              }"
+              :limit="limit"
+              @updated="autoSaveFun"
             />
 
             <!-- 自定义表格  -->
@@ -328,6 +343,12 @@ export default {
   name: "",
   components: { mDialog, classifyDia, Sheet, CustomTable, MixedTable,sheetListWrap },
   mixins: [leftMixin],
+  beforeRouteLeave(to,from,next){
+    if(from.path=='/sheetList' && to.path!='/sheetList'){
+      this.markFinishStatus()
+    }
+    next()
+  },
   computed: {
     downExcelFileUrl() {
       let url = `${
@@ -398,8 +419,12 @@ export default {
       },
       saveTime:"",
       editButtonText:"",
-      adminId:localStorage.getItem("AdminId") || '0',
-      excelAdminId:""
+      onlineExcelEditing:false,
+      limit:{
+        disabled:true
+      },
+      autoSaveType:'',//自动保存类型,有的自动保存后需要其他操作
+      cancelAutoSave:false, //自动保存时延迟的
     };
   },
   watch: {
@@ -411,8 +436,9 @@ export default {
       });
     },
     /* 表格id */
-    select_id(newval) {
+    select_id(newval,oldVlue) {
       newval && this.getDetailHandle();
+      this.markFinishStatus(oldVlue)
     },
 
     select_classify(newval) {
@@ -441,6 +467,18 @@ export default {
         this.select_id = newval;
       }
     },
+    onlineExcelEditing(value){
+      // console.log(value);
+      this.limit.disabled = !value
+    },
+    'sheetDetailInfo.ExcelName':{
+      handler:function(newValue,oldValue){
+        if(newValue && oldValue){
+          this.autoSaveType = 'nameEdit'
+          this.autoSaveFun()
+        }
+      }
+    }
   },
   methods: {
     /* 添加表格 */
@@ -662,7 +700,6 @@ export default {
         spinner: "el-icon-loading",
         background: "rgba(255, 255, 255, 0.6)",
       });
-
       let img = getSheetImage(data);
       const form = new FormData();
       form.append("Image", img);
@@ -670,6 +707,9 @@ export default {
 
       data.luckysheet_select_save = [];
       const { ExcelInfoId, ExcelName, ExcelClassifyId } = this.sheetDetailInfo;
+      
+      this.cancelAutoSave=true
+
       const res = await sheetInterface.sheetEdit({
         ExcelInfoId,
         ExcelName,
@@ -684,7 +724,34 @@ export default {
 
       this.getDetailHandle();
     }, 300),
+    autoSaveFun:_.debounce(async function(){
+      console.log("自动保存");
+      if(!this.onlineExcelEditing || this.cancelAutoSave){
+        this.cancelAutoSave=false
+        return
+      }
+      luckysheet.exitEditMode();
+      //结构类型乱飘 强制定义下
+      let data = {...luckysheet.getAllSheets()[0],status:Number(luckysheet.getAllSheets()[0].status)}
+      if (!data.celldata.length) return this.$message.warning("请输入表格内容");
+
+      data.luckysheet_select_save = [];
+      const { ExcelInfoId, ExcelName, ExcelClassifyId } = this.sheetDetailInfo;
+      const res = await sheetInterface.sheetEdit({
+        ExcelInfoId,
+        ExcelName,
+        ExcelClassifyId,
+        Content: JSON.stringify(data),
+      });
+      if (res.Ret !== 200) return;
+      if(this.autoSaveType == "nameEdit"){
+        this.getTreeData();
+        this.autoSaveType=''
+      }
+      
+      this.saveTime = this.$moment().format('YYYY-MM-DD HH:mm:ss')
 
+    },1500),
     /* 获取表格列表 */
     getPublicList() {
       sheetInterface.sheetList({
@@ -731,10 +798,7 @@ export default {
 
           this.sheetDetailInfo = res.Data;
           this.saveTime = this.$moment(this.sheetDetailInfo.ModifyTime).format('YYYY-MM-DD HH:mm:ss')||''
-          this.excelAdminId = this.sheetDetailInfo.SysUserId
           this.editButtonText = this.sheetDetailInfo.CanEdit?'':`${this.sheetDetailInfo.Editor}编辑中`
-          //从nextTick里面拉出来 更多功能按钮 显示的出来 但是删除表格,请求下一个表格详情时,表格内容不会更新。
-          // this.sheetDetailInfo.Source === 1 && this.$refs.sheetRef && this.$refs.sheetRef.init();
 
           this.$nextTick(() => {
 
@@ -774,8 +838,7 @@ export default {
             3: "/addMixedSheet",
           };
           if(this.sheetDetailInfo.Source === 1) {
-            const { href } = this.$router.resolve({ path: path[this.sheetDetailInfo.Source],query: { id: this.sheetDetailInfo.ExcelInfoId } });
-            window.open(href, "_blank");
+            this.onlineExcelEditing=true
           }else {
             this.$router.push({
               path: path[this.sheetDetailInfo.Source],
@@ -841,6 +904,23 @@ export default {
       let left = $("#left")[0].offsetWidth;
       let rigtWid = total_wid - left - 20 + "px";
       $("#right")[0].style.width = rigtWid;
+    },
+    editExcelName(sheetDetailInfo, type){
+      if(!this.onlineExcelEditing) return
+      this.editNodeLabel(sheetDetailInfo, type)
+    },
+    // 标记 编辑完成
+    markFinishStatus(select_id){
+      // console.log(select_id,'markFinishStatus',this.select_id);
+      let id = select_id || this.select_id
+      if((!this.onlineExcelEditing) || (!id) || id=='0'){
+        this.onlineExcelEditing=false
+        return
+      }
+      sheetInterface.markSheetEditStatus({ExcelInfoId: +id,Status:2}).then(res=>{
+        if(res.Ret != 200) return 
+      })
+      this.onlineExcelEditing=false
     }
   },
   mounted() {
@@ -855,9 +935,15 @@ export default {
     }
 
     window.addEventListener("resize", this.reloadRightWid);
+    if(this.$route.path == '/sheetList'){
+      window.addEventListener('beforeunload',this.markFinishStatus)
+    }
   },
   destroyed() {
     window.removeEventListener("resize", this.reloadRightWid);
+    if(this.$route.path == '/sheetList'){
+      window.removeEventListener('beforeunload',this.markFinishStatus)
+    }
   },
 };
 </script>

+ 2 - 1
src/views/ppt_manage/newVersion/components/formatPage/mixins.js

@@ -170,7 +170,8 @@ export default {
                 readder.readAsDataURL(bolb);
                 const that = this
                 readder.onload = function (e) {
-                    imgObj.src= e.target.result;
+                    // imgObj.src= e.target.result;
+                    imgObj.src=bolb;
                     imgObj.position = position
                     that.$emit('pasteImg',imgObj)
                 };

+ 27 - 15
src/views/ppt_manage/newVersion/pptEditor.vue

@@ -272,6 +272,7 @@ import futuresInterface from '@/api/modules/futuresBaseApi';
 import chartRelevanceApi from '@/api/modules/chartRelevanceApi';
 import { fittingEquationInterface,statisticFeatureInterface } from '@/api/modules/chartRelevanceApi';
 import pptmixin from '../mixins/pptMixins';
+import {uploadFileDirect} from "@/utils/common.js"
 import mixins from '../mixins/mixins';
 import layerMixins from '../mixins/layerMixins';
 import pptEditorMixins from '../mixins/pptEditorMixins';
@@ -621,21 +622,32 @@ export default {
       if(this.isChartLoading) return
       this.chartLoadingText = "上传图片中..."
       this.isChartLoading = true
-      const params = new FormData();
-			params.append('Image',$event.src)
-      const res = await dataBaseInterface.uploadImg(params);
-      if(!res||res&&res.Ret!==200){
-        this.isChartLoading = false
-        return
-      }
-      const {Data} = res
-      if(!Data){
-        this.$message.warning("上传图片失败")
-        this.isChartLoading = false
-        return
-      }
-      this.imgUrl = Data.ResourceUrl||''
-      /* this.imgUrl = $event.src */
+
+      // const params = new FormData();
+			// params.append('Image',$event.src)
+      // const res = await dataBaseInterface.uploadImg(params);
+      // if(!res||res&&res.Ret!==200){
+      //   this.isChartLoading = false
+      //   return
+      // }
+      // const {Data} = res
+      // if(!Data){
+      //   this.$message.warning("上传图片失败")
+      //   this.isChartLoading = false
+      //   return
+      // }
+      // this.imgUrl = Data.ResourceUrl||''
+
+      //直接走oss不走接口
+      let clientType = this.$setting.dynamicOutLinks.ObjectStorageClient 
+        || this.$store.state.dynamicOutLinks.ObjectStorageClient 
+        || JSON.parse(localStorage.getItem('dynamicOutLinks')).ObjectStorageClient;
+      
+      let temName = `ppt/image/${new Date().getTime()}`
+
+      const res = await uploadFileDirect(clientType,$event.src,temName)
+      this.imgUrl = res;
+      
       //console.log('OK',$event)
       let temp_elements = this.addElement(
             this.currentItem.elements,

+ 16 - 5
src/views/ppt_manage/newVersion/pptEnEditor.vue

@@ -294,6 +294,7 @@ import ChooseCover from './components/editor/ChooseCoverEn.vue';
 import AddFormat from './components/editor/AddFormat.vue';
 import {pptEnInterface} from '@/api/modules/pptEnApi.js';
 import * as sheetInterface from '@/api/modules/sheetApi.js';
+import {uploadFileDirect} from "@/utils/common.js"
 import ShapePreview from './components/layer/shapePreview.vue';
 import LayerEditTool from './components/layer/layerEditTool.vue';
 import DeletePageDialog from './components/editor/DeletePageDialog.vue';
@@ -630,11 +631,21 @@ export default {
       if(this.isChartLoading) return
       this.chartLoadingText = "上传图片中..."
       this.isChartLoading = true
-      const params = new FormData();
-			params.append('Image',$event.src)
-      const { Data } = await dataBaseInterface.uploadImg(params);
-      this.imgUrl = Data.ResourceUrl
-      /* this.imgUrl = $event.src */
+      // const params = new FormData();
+			// params.append('Image',$event.src)
+      // const { Data } = await dataBaseInterface.uploadImg(params);
+      // this.imgUrl = Data.ResourceUrl
+
+      //直接走oss不走接口
+      let clientType = this.$setting.dynamicOutLinks.ObjectStorageClient 
+        || this.$store.state.dynamicOutLinks.ObjectStorageClient 
+        || JSON.parse(localStorage.getItem('dynamicOutLinks')).ObjectStorageClient;
+      
+      let temName = `ppt/image/${new Date().getTime()}`
+
+      const res = await uploadFileDirect(clientType,$event.src,temName)
+      this.imgUrl = res;
+
       //console.log('OK',$event)
       let temp_elements = this.addElement(
             this.currentItem.elements,

+ 20 - 14
src/views/report_manage/addreportNew.vue

@@ -49,19 +49,25 @@
 					@click.native="clickreportadd('cg')"
 					>存草稿</el-button
 				>
-				<el-button v-permission="permissionBtn.reportManageBtn.reportManage_publish"
-					type="primary"
-					size="medium"
-					@click.native="clickreportadd('dsfb')"
-					>定时发布</el-button
-				>
-				<el-button
-					type="primary"
-					size="medium"
-					@click.native="clickreportadd('fb')"
-					:loading="isPublishloading"
-					>发布</el-button
-				>
+				<!--不走审批流-->
+				<template v-if="!isApprove">
+					<el-button v-permission="permissionBtn.reportManageBtn.reportManage_publish"
+						type="primary"
+						size="medium"
+						@click.native="clickreportadd('dsfb')"
+						>定时发布</el-button
+					>
+					<el-button
+						type="primary"
+						size="medium"
+						@click.native="clickreportadd('fb')"
+						:loading="isPublishloading"
+						>发布</el-button
+					>
+				</template>
+				<template v-if="isApprove">
+					<el-button type="primary" size="medium" @click="clickreportadd('fb')">提交</el-button>
+				</template>
 			</div>
 			<div
 				style="
@@ -608,7 +614,7 @@ export default {
 			if (tp == 'fb') {
 				this.isPublishloading = true;
 			}
-			const isPost = this.permissionBtn.checkPermissionBtn(this.permissionBtn.reportManageBtn.reportManage_sendMsg)
+			const isPost = this.permissionBtn.checkPermissionBtn(this.permissionBtn.reportManageBtn.reportManage_sendMsg)&&(!this.isApprove)
 			// 如果已经添加过就修改 否则新增
 			if (this.isAddEnter) {
 				let params2 = {

+ 20 - 14
src/views/report_manage/editreportNew.vue

@@ -49,19 +49,25 @@
 					@click.native="clickreportadd('cg')"
 					>存草稿</el-button
 				>
-				<el-button v-permission="permissionBtn.reportManageBtn.reportManage_publish"
-					type="primary"
-					size="medium"
-					@click.native="clickreportadd('dsfb')"
-					>定时发布</el-button
-				>
-				<el-button
-					type="primary"
-					size="medium"
-					@click.native="clickreportadd('fb')"
-					:loading="isPublishloading"
-					>发布</el-button
-				>
+				<!--不走审批流-->
+				<template v-if="!isApprove">
+					<el-button v-permission="permissionBtn.reportManageBtn.reportManage_publish"
+						type="primary"
+						size="medium"
+						@click.native="clickreportadd('dsfb')"
+						>定时发布</el-button
+					>
+					<el-button
+						type="primary"
+						size="medium"
+						@click.native="clickreportadd('fb')"
+						:loading="isPublishloading"
+						>发布</el-button
+					>
+				</template>
+				<template v-if="isApprove">
+					<el-button type="primary" size="medium" @click="clickreportadd('fb')">提交</el-button>
+				</template>
 			</div>
 			<div
 				style="
@@ -632,7 +638,7 @@ export default {
 				window.open(href, '_blank');
 				return false;
 			}
-			const isPost = this.permissionBtn.checkPermissionBtn(this.permissionBtn.reportManageBtn.reportManage_sendMsg)
+			const isPost = this.permissionBtn.checkPermissionBtn(this.permissionBtn.reportManageBtn.reportManage_sendMsg)&&(!this.isApprove)
 			if (tp == 'fb') {
 				this.isPublishloading = true;
 				// 判断是否要推送客群

+ 19 - 1
src/views/report_manage/mixins/messagePush.js

@@ -4,9 +4,19 @@ export default {
   data() {
     return {
       isMessagePost: false,
+      //isApprove:false,//是否走审批流
       isRightFormShow:true
     };
   },
+  computed:{
+    //是否开启审批流,若开启,发布相关按钮,筛选项改变
+    isApprove(){
+        const type = this.$setting.dynamicOutLinks.ApprovalFlow ||
+                     this.$store.state.dynamicOutLinks.ApprovalFlow ||
+                     JSON.parse(localStorage.getItem('dynamicOutLinks')).ApprovalFlow||''
+        return ['1','3'].includes(type)
+    }
+  },
   methods: {
     reporteditMsg(params2, tp) {
       reportedit(params2).then(async (res) => {
@@ -20,6 +30,10 @@ export default {
             });
             window.open(href, "_blank");
           } else if (tp == "fb") {
+            if(this.isApprove){
+                await this.publishreport(res.Data.ReportId);
+                return 
+            }
             if (this.isMessagePost) {
               await this.publishreport(res.Data.ReportId);
               await reportMessageSend({
@@ -48,6 +62,10 @@ export default {
             });
             window.open(href, "_blank");
           } else if (tp == "fb") {
+            if(this.isApprove){
+                await this.publishreport(res.Data.ReportId);
+                return 
+            }
             if (this.isMessagePost) {
               await this.publishreport(res.Data.ReportId);
               await reportMessageSend({
@@ -100,6 +118,6 @@ export default {
         this.$message.success('刷新成功');
       }
 
-    },1000)
+    },1000),
   },
 };

+ 21 - 3
src/views/report_manage/reportdtl.vue

@@ -66,7 +66,7 @@
 </template>
 
 <script>
-	import { reportdetail } from 'api/api.js';
+	import { reportdetail,departInterence } from 'api/api.js';
 	import http from '@/api/http.js';
 	import * as reportEnInterface from '@/api/modules/reportEnApi';
 	import {strategyReportInterence} from '@/api/api.js'
@@ -77,10 +77,18 @@
 				let str=''
 				const baseUrl= localStorage.getItem('dynamicOutLinks') ? JSON.parse(localStorage.getItem('dynamicOutLinks')).ReportViewUrl : '';
 				if(this.$route.query.code){
+					// 设置水印文案
+					let waterMarkStr=''
+					if(this.systemUserInfo){
+						waterMarkStr=`${this.systemUserInfo.RealName}${this.systemUserInfo.Mobile?this.systemUserInfo.Mobile:this.systemUserInfo.Email}`
+						const base64=new http.Base64()
+						waterMarkStr=base64.encode(waterMarkStr)
+					}
+					
 					if(this.$route.query.fromPage == 'en'){
-						str=`${baseUrl}/reportshare_crm_report_en?code=${this.$route.query.code}`
+						str=`${baseUrl}/reportshare_crm_report_en?code=${this.$route.query.code}&flag=${waterMarkStr}`
 					}else{
-						str=`${baseUrl}/reportshare_crm_report?code=${this.$route.query.code}`
+						str=`${baseUrl}/reportshare_crm_report?code=${this.$route.query.code}&flag=${waterMarkStr}`
 					}
 				}
 				
@@ -93,6 +101,8 @@
 				isshow:false,
 				reportInfo:{},
 				isShowCode:false,
+
+				systemUserInfo:null,
 				// linkUrl:this.$route.query.code?'https://share.hzinsights.com/reportdtl?code='+this.$route.query.code:''
 			}
 		},
@@ -109,6 +119,7 @@
 				console.log(this.reportInfo);
 				this.isshow=true;
 			}
+			this.getSystemUserInfo()
 		},
 		updated(){
 		  $('#resetcss').find('img').css({display:'block',margin:'0 auto'});
@@ -116,6 +127,13 @@
 			$("#resetcss").find("pre").css({display: "block",whiteSpace: "pre-wrap"});
 		},
 		methods: {
+			getSystemUserInfo(){
+				departInterence.systemUserInfo().then(res=>{
+					if(res.Ret===200){
+						this.systemUserInfo=res.Data
+					}
+				})
+			},
 			async getreportdetail(){
 				let res
 				if(this.$route.query.fromPage == 'en'){

+ 162 - 93
src/views/report_manage/reportlist.vue

@@ -11,7 +11,6 @@
               @click="$router.push({ path: '/addreportNew' })"
               >添加研报</el-button
             >
-            <!-- <el-button type="primary" plain size="medium" @click="$router.push({path:'/addreport'})">添加研报(旧版)</el-button> -->
             <el-button
               v-permission="permissionBtn.reportManageBtn.reportManage_dayWeekReportAdd"
               type="primary"
@@ -19,7 +18,6 @@
               @click="$router.push({ path: '/dayorweek' })"
               >添加晨报/周报</el-button
             >
-            <!-- <el-button type="primary" size="medium" @click="publishreport">发 布</el-button> -->
             <template v-if="Role === 'rai_researcher'">
               <el-button
                 type="primary"
@@ -51,7 +49,7 @@
                             style="width:100%;"
                             @change="search"
                         >
-                            <el-option label="发布时间" value="publish_time"></el-option>
+                            <el-option :label="isApprove?'审批时间':'发布时间'" value="publish_time"></el-option>
                             <el-option label="更新时间" value="modify_time"></el-option>
                         </el-select>
                     </div>
@@ -84,8 +82,8 @@
                             style="width:100%;"
                         ></el-cascader>
                     </div>
-                    <div class="select-item">
-                        <el-select
+                    <div class="select-item" v-if="!isApprove">
+                        <el-select 
                             v-model.number="searchform.publishState"
                             placeholder="发布筛选"
                             size="medium"
@@ -97,6 +95,21 @@
                             <el-option label="未发布" :value="1"></el-option>
                         </el-select>
                     </div>
+                    <div class="select-item" v-if="isApprove">
+                        <el-select
+                            v-model.number="searchform.publishState"
+                            placeholder="状态筛选"
+                            size="medium"
+                            clearable
+                            style="width:100%;"
+                            @change="search"
+                        >
+                            <el-option label="待提交" :value="1"></el-option>
+                            <el-option label="待审批" :value="2"></el-option>
+                            <el-option label="已审批" :value="4"></el-option>
+                            <el-option label="已驳回" :value="3"></el-option>
+                        </el-select>
+                    </div>
                     <div class="select-item">
                         <el-select
                             v-permission="permissionBtn.reportManageBtn.reportManage_reportList_sendTime"
@@ -126,7 +139,7 @@
               style="width:110px"
               @change="search"
             >
-              <el-option label="发布时间" value="publish_time"></el-option>
+              <el-option :label="isApprove?'审批时间':'发布时间'" value="publish_time"></el-option>
               <el-option label="更新时间" value="modify_time"></el-option>
             </el-select>
           </el-form-item> -->
@@ -172,6 +185,8 @@
               placeholder="类型筛选"
               size="medium"
             ></el-cascader>
+          </el-form-item>
+          <el-form-item label="" v-if="!isApprove">
           </el-form-item> -->
           <!-- <el-form-item label="">
             <el-select
@@ -185,6 +200,23 @@
               <el-option label="已发布" :value="2"></el-option>
               <el-option label="未发布" :value="1"></el-option>
             </el-select>
+          </el-form-item>
+          <el-form-item label="" v-if="isApprove">
+            <el-select
+              v-model.number="searchform.publishState"
+              placeholder="状态筛选"
+              size="medium"
+              clearable
+              style="width: 140px"
+              @change="search"
+            >
+              <el-option label="待提交" :value="1"></el-option>
+              <el-option label="待审批" :value="2"></el-option>
+              <el-option label="已审批" :value="4"></el-option>
+              <el-option label="已驳回" :value="3"></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="">
           </el-form-item> -->
           <!-- <el-form-item label="">
             <el-select
@@ -281,7 +313,7 @@
             align="center"
             min-width="100"
           ></el-table-column>
-          <el-table-column label="发布状态" align="center">
+          <el-table-column label="发布状态" align="center" v-if="!isApprove">
             <template slot-scope="scope">
               <span v-if="scope.row.State == '2'" style="color: #46c371"
                 >已发布</span
@@ -289,7 +321,17 @@
               <span v-if="scope.row.State == '1'">未发布</span>
             </template>
           </el-table-column>
+          <el-table-column label="状态" align="center" v-if="isApprove">
+            <template slot-scope="scope">
+                <span v-if="scope.row.State == '1'">待提交</span>
+                <span v-if="scope.row.State == '2'">待审批</span>
+                <span v-if="scope.row.State == '4'">已审批</span>
+                <span v-if="scope.row.State == '3'">已驳回</span>
+            </template>
+          </el-table-column>
+
           <el-table-column
+            v-if="!isApprove"
             prop="PublishTime"
             label="发布时间"
             min-width="124"
@@ -303,6 +345,19 @@
               </svg>
             </template>
           </el-table-column>
+          <el-table-column
+            v-if="isApprove"
+            prop="PublishTime"
+            label="审批时间"
+            min-width="124"
+            align="center"
+            :formatter="formatterColumn"
+          >
+            <template slot-scope="scope">
+                <span>{{scope.row.PrePublishTime?scope.row.PrePublishTime:scope.row.PublishTime|formatTime}}</span>
+            </template>
+          </el-table-column>
+
           <el-table-column v-if="permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_reportList_sendTime)"
             prop="MsgSendTime"
             label="报告推送时间"
@@ -345,95 +400,96 @@
           <el-table-column label="操作" align="center" min-width="130" fixed="right">
             <template slot-scope="scope">
               <div class="opt-btns">
-                <template
-                  v-if="scope.row.State == 1"
-                >
-                  <!-- <i class="el-icon-edit-outline" @click="$router.push({name:'编辑研报',query:{id:scope.row.id}})"></i> -->
-                  <span
-                    v-permission="permissionBtn.reportManageBtn.reportManage_publish"
-                    class="editsty"
-                    @click="publishreport(scope.row)"
-                    v-if="scope.row.CanEdit"
-                    >发布</span
-                  >
-                  <span
-                    v-permission="permissionBtn.reportManageBtn.reportManage_reportEdit"
-                    class="editsty"
-                    @click="editreport(scope.row, 'edit')"
-                    v-if="scope.row.CanEdit"
-                    >编辑</span
-                  >
-                  <span
-                    v-permission="permissionBtn.reportManageBtn.reportManage_reportEdit"
-                    class="editsty"
-                    @click="editreport(scope.row, 'editing')"
-                    v-else
-                    >{{ scope.row.Editor || "" }}编辑中...</span
-                  >
-                  <!-- <i class="el-icon-delete" @click="deleteitem(scope.row)"></i> -->
-                  <span
-                    v-permission="permissionBtn.reportManageBtn.reportManage_reportDel"
-                    class="deletesty"
-                    @click="deleteitem(scope.row)"
-                    v-if="scope.row.CanEdit"
-                    >删除</span
-                  >
+                <!--不走审批流的按钮-->
+                <template v-if="!isApprove">
+                    <template v-if="scope.row.State == 1">
+                        <span v-permission="permissionBtn.reportManageBtn.reportManage_publish" class="editsty"
+                            @click="publishreport(scope.row)" v-if="scope.row.CanEdit">发布</span>
+                        <span v-permission="permissionBtn.reportManageBtn.reportManage_reportEdit" class="editsty"
+                            @click="editreport(scope.row, 'edit')" v-if="scope.row.CanEdit">编辑</span>
+                        <span v-permission="permissionBtn.reportManageBtn.reportManage_reportEdit" class="editsty"
+                            @click="editreport(scope.row, 'editing')" v-else>{{ scope.row.Editor || "" }}编辑中...</span>
+                        <span v-permission="permissionBtn.reportManageBtn.reportManage_reportDel" class="deletesty"
+                            @click="deleteitem(scope.row)" v-if="scope.row.CanEdit">删除</span>
+                    </template>
+                    <template v-if="scope.row.State == 2">
+                        <span
+                            v-if="permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_cancelPublish)"
+                            @click="canclepublish(scope.row)" style="color: red; cursor: pointer">取消发布</span>
+                        <span
+                            v-if="scope.row.MsgIsSend == 0 && permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_sendMsg)"
+                            style="color: #4099ef; cursor: pointer" @click="messageSend(scope.row)">推送消息</span>
+                        <span
+                            v-else-if="scope.row.MsgIsSend != 0&&permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_sendMsg)"
+                            style="color: red">已推送消息</span>
+                    </template>
+                    <span style="color: #46c371; cursor: pointer"
+                        v-if="!['晨报', '周报'].includes(scope.row.ClassifyNameFirst)&&permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_audioUpload)"
+                        @click="openupload(scope.row.Id)">音频上传</span>
+                    <a v-permission="permissionBtn.reportManageBtn.reportManage_audioDownload"
+                        :href="hostapi + '?ReportId=' + parseInt(scope.row.Id)" v-if="
+                        scope.row.VideoUrl &&
+                        !['晨报', '周报'].includes(scope.row.ClassifyNameFirst)
+                    " :download="scope.row.VideoName" style="cursor: pointer; color: #4099ef">音频下载</a>
+                    <span v-permission="permissionBtn.reportManageBtn.reportManage_audioDownload"
+                        style="cursor: pointer; color: #4099ef" v-if="
+                        ['晨报', '周报'].includes(scope.row.ClassifyNameFirst) &&
+                        scope.row.ChapterVideoList.length > 0
+                    " @click="handleShowDownloadAudio(scope.row)">音频下载</span>
                 </template>
-                <template v-if="scope.row.State == 2">
-                  <span v-if="permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_cancelPublish)"
-                    @click="canclepublish(scope.row)"
-                    style="color: red; cursor: pointer"
-                    >取消发布</span
-                  >
-                  <!-- <template v-if="scope.row.ClassifyNameFirst!='周报'"> -->
-                  <span
-                    v-if="scope.row.MsgIsSend == 0 && permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_sendMsg)"
-                    style="color: #4099ef; cursor: pointer"
-                    @click="messageSend(scope.row)"
-                    >推送消息</span
-                  >
-                  <span v-else-if="scope.row.MsgIsSend != 0&&permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_sendMsg)"
-                    style="color: red">已推送消息</span>
-                  <!-- </template> -->
-                  <!-- <template v-else>
-										<span v-if="scope.row.MsgIsSend=='0'" @click="gosendTemplateMsg(scope.row)" style="color:#4099ef; cursor:pointer;">推送模版消息</span>
-										<span v-else style="color:red;">已推送模版消息</span>
-									</template> -->
+                <!--走审批流的按钮,权限与原先按钮对应-->
+                <template v-if="isApprove">
+                    <!--待提交-->
+                    <template v-if="scope.row.State===1">
+                        <span v-permission="permissionBtn.reportManageBtn.reportManage_publish"
+                            @click="publishreport(scope.row)"
+                            class="editsty">提交</span>
+                        <span v-permission="permissionBtn.reportManageBtn.reportManage_reportEdit" class="editsty"
+                            @click="editreport(scope.row, 'edit')" v-if="scope.row.CanEdit">编辑</span>
+                        <span v-permission="permissionBtn.reportManageBtn.reportManage_reportEdit" class="editsty"
+                            @click="editreport(scope.row, 'editing')" v-else>{{ scope.row.Editor || "" }}编辑中...</span>
+                        <span v-permission="permissionBtn.reportManageBtn.reportManage_reportDel" class="deletesty"
+                            @click="deleteitem(scope.row)" v-if="scope.row.CanEdit">删除</span>
+                    </template>
+                    <!--已提交(待审批,已审批)-->
+                    <template v-if="[2,4].includes(scope.row.State)">
+                        <span
+                            v-if="permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_cancelPublish)"
+                            @click="canclepublish(scope.row)"
+                            class="editsty">撤销</span>
+                        <template v-if="scope.row.State!==2">
+                            <span
+                                v-if="scope.row.MsgIsSend == 0 && permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_sendMsg)"
+                                style="color: #4099ef; cursor: pointer" @click="messageSend(scope.row)">推送消息</span>
+                            <span
+                                v-else-if="scope.row.MsgIsSend != 0&&permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_sendMsg)"
+                                style="color: red">已推送消息</span>
+                        </template>
+                    </template>
 
-                  <!-- <span v-if="scope.row.MsgIsSend=='0'" @click="gosendTemplateMsg(scope.row)" style="color:#4099ef; cursor:pointer;">推送模版消息</span>
-									<span v-else style="color:red;">已推送模版消息</span>
-									<template v-if="scope.row.NeedThsMsg!=0">
-									<span v-if="scope.row.ThsMsgIsSend == 0" @click="messagePush(scope.row)" style="color:#4099ef; cursor:pointer;">推送客群消息</span>
-									<span v-else style="color:red;">已推送客群消息</span>
-									</template> -->
+                    <!--已驳回则只显示撤销按钮-->
+                    <template v-if="scope.row.State===3">
+                        <span v-permission="permissionBtn.reportManageBtn.reportManage_publish"
+                            @click="canclepublish(scope.row)"
+                            class="editsty">撤销</span>
+                    </template>
+                    <!--音频上传/下载 按原先逻辑-->
+                    <template v-if="scope.row.State!==3">
+                        <span style="color: #46c371; cursor: pointer"
+                            v-if="!['晨报', '周报'].includes(scope.row.ClassifyNameFirst)&&permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_audioUpload)"
+                            @click="openupload(scope.row.Id)">音频上传</span>
+                        <a v-permission="permissionBtn.reportManageBtn.reportManage_audioDownload"
+                            :href="hostapi + '?ReportId=' + parseInt(scope.row.Id)" v-if="
+                            scope.row.VideoUrl &&
+                            !['晨报', '周报'].includes(scope.row.ClassifyNameFirst)
+                        " :download="scope.row.VideoName" style="cursor: pointer; color: #4099ef">音频下载</a>
+                        <span v-permission="permissionBtn.reportManageBtn.reportManage_audioDownload"
+                            style="cursor: pointer; color: #4099ef" v-if="
+                            ['晨报', '周报'].includes(scope.row.ClassifyNameFirst) &&
+                            scope.row.ChapterVideoList.length > 0
+                        " @click="handleShowDownloadAudio(scope.row)">音频下载</span>
+                    </template>
                 </template>
-                <span
-                  style="color: #46c371; cursor: pointer"
-                  v-if="!['晨报', '周报'].includes(scope.row.ClassifyNameFirst)&&permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_audioUpload)"
-                  @click="openupload(scope.row.Id)"
-                  >音频上传</span
-                >
-                <a
-                  v-permission="permissionBtn.reportManageBtn.reportManage_audioDownload"
-                  :href="hostapi + '?ReportId=' + parseInt(scope.row.Id)"
-                  v-if="
-                    scope.row.VideoUrl &&
-                    !['晨报', '周报'].includes(scope.row.ClassifyNameFirst)
-                  "
-                  :download="scope.row.VideoName"
-                  style="cursor: pointer; color: #4099ef"
-                  >音频下载</a
-                >
-                <span
-                  v-permission="permissionBtn.reportManageBtn.reportManage_audioDownload"
-                  style="cursor: pointer; color: #4099ef"
-                  v-if="
-                    ['晨报', '周报'].includes(scope.row.ClassifyNameFirst) &&
-                    scope.row.ChapterVideoList.length > 0
-                  "
-                  @click="handleShowDownloadAudio(scope.row)"
-                  >音频下载</span
-                >
               </div>
             </template>
           </el-table-column>
@@ -701,6 +757,13 @@ export default {
     //是否有UV
     hasUV(){
       return this.permissionBtn.checkPermissionBtn(this.permissionBtn.reportManageBtn.reportManage_reportList_uv)
+    },
+    //是否开启审批流,若开启,发布相关按钮,筛选项改变
+    isApprove(){
+        const type = this.$setting.dynamicOutLinks.ApprovalFlow ||
+                     this.$store.state.dynamicOutLinks.ApprovalFlow ||
+                     JSON.parse(localStorage.getItem('dynamicOutLinks')).ApprovalFlow||''
+        return ['1','3'].includes(type)
     }
   },
   data() {
@@ -748,6 +811,8 @@ export default {
       showPublish: false,
       isDSFB:false,//是否为定时发布
       tableKey:0,
+
+      //isApprove:false,//是否开启审批流,若开启,发布相关按钮,筛选项改变
     };
   },
   mounted() {
@@ -1034,6 +1099,10 @@ export default {
         // this.handlePublic(1)
         return;
       }
+      if(this.isApprove){
+        this.handlePublic(1)
+        return
+      }
       const isPost = this.permissionBtn.checkPermissionBtn(this.permissionBtn.reportManageBtn.reportManage_sendMsg)
       if(isPost){
           this.showPublish = true;

+ 158 - 0
src/views/sandbox_manage/common/edge.js

@@ -0,0 +1,158 @@
+import { configOpt } from './toolConfig';
+
+const { line} = configOpt;
+import store from "@/vuex/index"
+
+const styleConfig=store.state.sand.styleConfig
+// export const myEdges = [
+// 	{
+// 		type: 'noArrowStraight',
+//     ImgUrl:'~@/assets/icons/arrow.svg'
+// 	}
+// ]
+/**type--类型  xP--定位点的横坐标 yP--定位点的纵坐标
+ * 创建的线条
+ * 斜直线无箭头、斜直线单项箭头、斜直线双线箭头
+ * 弯折线无箭头、弯折线单项、弯折线双向箭头
+ * 圆角弯折线无箭头、圆角弯折线单项、圆角弯折线双向箭头
+ */
+export const myEdgeOption = (type,xP=0,yP=0) => {
+  // 斜直线
+  let skewLine={
+    source: { x: xP-40, y: yP-40 },
+    target: { x: xP+40 ,y: yP+40 },
+    router: {
+      name: 'normal',
+      args: {
+        padding: {
+          left: 10,
+        }
+      }
+    },
+    attrs:{
+      line:{
+        strokeDasharray:null,
+        stroke: styleConfig.lineColor,
+        strokeWidth: line.width,
+        sourceMarker: {},//起始箭头 
+        targetMarker: {},//终止箭头
+      }
+    }
+  }
+  //弯折线
+  let bendLine={
+    source: { x: xP-40, y: yP-40 },
+    target: { x: xP+40 ,y: yP+40 },
+    vertices:[{x:xP,y:yP-40},{x:xP,y:yP+40}],
+    attrs:{
+      line:{
+        strokeDasharray:null,
+        stroke: styleConfig.lineColor,
+        strokeWidth: line.width,
+        sourceMarker: {},//起始箭头 
+        targetMarker: {},//终止箭头
+      }
+    }
+  }
+	switch (type) {
+		case 'noArrowStraight': 
+			return skewLine
+		case 'singleArrowStraight': 
+			return {
+				...skewLine,
+        attrs:{
+          line:{
+            strokeDasharray:null,
+            stroke: styleConfig.lineColor,
+            strokeWidth: line.width,
+            sourceMarker: {},//起始箭头 
+            targetMarker: "classic",//终止箭头
+          }
+        },
+			}
+		case 'doubleArrowStraight': 
+			return {
+				...skewLine,
+        attrs:{
+          line:{
+            strokeDasharray:null,
+            stroke: styleConfig.lineColor,
+            strokeWidth: line.width,
+            sourceMarker: "classic",//起始箭头 
+            targetMarker: "classic",//终止箭头
+          }
+        },
+			}
+		case 'noArrowBend': 
+			return bendLine
+		case 'singleArrowBend': 
+			return {
+        ...bendLine,
+        attrs:{
+          line:{
+            strokeDasharray:null,
+            stroke: styleConfig.lineColor,
+            strokeWidth: line.width,
+            sourceMarker: {},//起始箭头 
+            targetMarker: "classic",//终止箭头
+          }
+        },
+			}
+    case 'doubleArrowBend':
+      return {
+        ...bendLine,
+        attrs:{
+          line:{
+            strokeDasharray:null,
+            stroke: styleConfig.lineColor,
+            strokeWidth: line.width,
+            sourceMarker: "classic",//起始箭头 
+            targetMarker: "classic",//终止箭头
+          }
+        },
+      }
+    case 'noArrowRoundBend': 
+			return {
+        ...bendLine,
+        connector: {
+          name: 'rounded',
+          args: { radius: 8 },
+        },
+      }
+    case 'singleArrowRoundBend': 
+			return {
+        ...bendLine,
+        connector: {
+          name: 'rounded',
+          args: { radius: 8 },
+        },
+        attrs:{
+          line:{
+            strokeDasharray:null,
+            stroke: styleConfig.lineColor,
+            strokeWidth: line.width,
+            sourceMarker: {},//起始箭头 
+            targetMarker: "classic",//终止箭头
+          }
+        },
+      }
+    case 'doubleArrowRoundBend': 
+			return {
+        ...bendLine,
+        connector: {
+          name: 'rounded',
+          args: { radius: 8 },
+        },
+        attrs:{
+          line:{
+            strokeDasharray:null,
+            stroke: styleConfig.lineColor,
+            strokeWidth: line.width,
+            sourceMarker: 'classic',//起始箭头 
+            targetMarker: "classic",//终止箭头
+          }
+        },
+      }
+  }
+}
+

+ 282 - 116
src/views/sandbox_manage/common/events.js

@@ -1,14 +1,17 @@
 import { store } from "../../../main";
+import { configOpt } from './toolConfig';
+import _ from "lodash"
+const { line} = configOpt;
 
 /* 节点操作监听事件 */
-export const myEvents = (graph) => {
-
+export const myEvents = (graph,mindmapDataUseFun) => {
+		
 		/* 节点双击编辑 */
 		graph.on('node:dblclick', ({ node, e }) => {
-
 			// 节点当前设置的样式同步到编辑区
-			const { text, rect} = node.attrs;
 
+			const { text, rect} = node.attrs;
+			// console.log(node,'nodenode');
 			const edit_area = document.createElement('div');
 			edit_area.contentEditable = "true";
 			edit_area.id = "editable-wrapper";
@@ -16,20 +19,29 @@ export const myEvents = (graph) => {
 			edit_area.style.outline = "none";
 			edit_area.style.padding = "4px";
 			edit_area.style.boxSizing = "border-box";
-			$('#flow-container')[0].appendChild(edit_area);
+			$('#sand-chart-container')[0].appendChild(edit_area);
 
 			const position = node.position();
       const size = node.size();
+			// console.log(position,size);
       // const pos = graph.localToClient(position);
       const pos = graph.localToGraph(position);
       const zoom = graph.zoom();
-      let width = size.width,
-      height = size.height;
+      let width = size.width,height = size.height;
 
 			// const edit_area =  $('#editable-wrapper')[0];
+			// if(node.shape.indexOf('mindmap')!==-1){
+
+			// 	edit_area.innerText = text.text
+			// 	node.attr('text/text', '');
+			// }else{
+				edit_area.innerText = text.text || text.textWrap.text || ' ';
+				// 开启editText的事务 
+				graph.startBatch('editText')
+				node.attr('text/textWrap/text', '');
+				
+			// }
 
-			edit_area.innerText = text.text || text.textWrap.text || ' ';
-			node.attr('text/textWrap/text', '');
 
 			edit_area.style.left = `${pos.x}px`;
 			edit_area.style.top = `${pos.y}px`;
@@ -63,29 +75,42 @@ export const myEvents = (graph) => {
 			//失焦后设置内容
 			edit_area.onblur = () => {
 				let newval = edit_area.innerText.replace(/(\n[\s\t]*\r*\n)/g,'\n');
+
+				// console.log(node.shape,'edit_area');
+
 				node.attr('text/textWrap/text', newval);
 				node.attr('text/text', newval);
-				
-				const domH = (edit_area.getBoundingClientRect().height) /zoom;
-				node.size(width,domH > 50 ? domH : 50);
-				
-				$('#flow-container')[0].removeChild(edit_area);
+				// 关闭editText的事务
+				graph.stopBatch('editText')
+
+				if(node.shape.indexOf('mindmap')!==-1){
+					const mindmapDataUse=mindmapDataUseFun()
+					let ids = node.id.split('-')
+					let mindmapDataIndex = mindmapDataUse.findIndex(mindmap => mindmap.mindmapData.id == ids[0])
+					let mindMapDataCurrent = mindmapDataUse[mindmapDataIndex]?mindmapDataUse[mindmapDataIndex].mindmapData:{}
+
+					let findId = ids[0]
+					for (let i = 1; i < ids.length; i++) {
+						const element = ids[i];
+						findId = findId+'-'+element
+						mindMapDataCurrent=mindMapDataCurrent.children.find(it => it.id==findId)
+					}
+					mindMapDataCurrent.label = newval
+				}
+				if(node.shape.indexOf('mindmap')==-1){
+					const domH = (edit_area.getBoundingClientRect().height) /zoom;
+					node.size(width,domH > 50 ? domH : 50);
+					// node.size(width,domH);
+				}else{
+					const domH = (edit_area.getBoundingClientRect().height) /zoom;
+					// node.size(width,domH);
+					node.size(width,domH > 50 ? domH : 50);
+					// node.fit({ deep: true })
+				}
+
+				$('#sand-chart-container')[0].removeChild(edit_area);
 			}
-
-
-			// node.addTools({
-			// 	name: 'node-editor',
-			// 	args: {
-			// 		event: e,
-			// 		attrs: {
-			// 			fontSize: text.fontSize,
-			// 			color: text.fill,
-			// 			backgroundColor: rect.fill === 'transparent' ? '#fff' : rect.fill,
-			// 		},
-			// 	},
-			// })
 		})
-
 		/* 鼠标移入移出控制连接桩 */
 		graph.on('node:mouseenter', ({ node, e }) => {
 			// console.log(node)
@@ -102,79 +127,127 @@ export const myEvents = (graph) => {
 
 		/* 节点右键 */
 		graph.on('node:contextmenu',({node,e}) => {
-			graph.select(node);
+			graph.resetSelection(node);
 			const dom = $('#contextMenu-wrapper')[0];
 			dom.style.left = e.clientX-3 + 'px';
 			dom.style.top = e.clientY-3 + 'px';
 		})
 
 		/* 选中事件 */
-		graph.on('cell:selected',({cell,options}) => {
-			// console.log(cell)
-			//节点
-			if(cell.shape === 'rect') {
-				const { key } = cell.data;
-
-				const options = setSelectedOptions(cell.attrs,key);
-				//设置toolbar状态
-				store.commit('sand/SET_SELECT_STATUS',{
-					key,
-					options
-				});
-			}else if(cell.isEdge()) {
-
-				const { line } = cell.attrs;
-				//高亮选中
-				// cell.attr('line', { stroke: '#f00', strokeWidth: 3 });
-				//设置toolbar状态
-				store.commit('sand/SET_SELECT_STATUS',{
-					key: 'line',
-					options: {
-						line: {
-							width: line.strokeWidth,
-							color: line.stroke,
-						}
-					}
-				});
-			}
-		})
+		// graph.on('cell:selected',({cell,options}) => {
+		// 	// console.log(cell)
+		// 	//节点
+		// 	if(cell.shape === 'rect') {
+		// 		const { key } = cell.data;
+
+		// 		const options = setSelectedOptions(cell.attrs,key);
+		// 		//设置toolbar状态
+		// 		store.commit('sand/SET_SELECT_STATUS',{
+		// 			key,
+		// 			options
+		// 		});
+		// 	}else if(cell.isEdge()) {
+
+		// 		const { line } = cell.attrs;
+		// 		//高亮选中
+		// 		// cell.attr('line', { stroke: '#f00', strokeWidth: 3 });
+		// 		//设置toolbar状态
+		// 		store.commit('sand/SET_SELECT_STATUS',{
+		// 			key: 'line',
+		// 			options: {
+		// 				line: {
+		// 					width: line.strokeWidth,
+		// 					color: line.stroke,
+		// 				}
+		// 			}
+		// 		});
+		// 	}
+		// })
 		
 		/* 点击空白区域清空选区 屏蔽工具栏 */
-		graph.on('blank:click',() => {
-			graph.cleanSelection();
-			store.commit('sand/SET_SELECT_STATUS',{key:'default'});
-			store.commit('sand/SET_SELECT_CELL',null);
+		// graph.on('blank:click',() => {
+		// 	graph.cleanSelection();
+		// 	// store.commit('sand/SET_SELECT_STATUS',{key:'default'});
+		// 	store.commit('sand/SET_SELECT_CELLS',[]);
 
-			if($('#editable-wrapper')[0]) $('#editable-wrapper')[0].blur();
-		})
+		// 	if($('#editable-wrapper')[0]) $('#editable-wrapper')[0].blur();
+		// })
+
+		const changeSelection=_.debounce((selected)=> {
+			// console.log(selected,'selected');
+			store.commit('sand/SET_SELECT_CELLS',selected)
+		},50)
 
 		/* 监听选中事件 */
 		graph.on('selection:changed',({selected}) => {
-			
-			selected.length ? store.commit('sand/SET_SELECT_CELL',selected[0]) : store.commit('sand/SET_SELECT_CELL',null);
+			// console.log(selected,'选中修改');
+			// selected.length ? store.commit('sand/SET_SELECT_CELL',selected[0]) : store.commit('sand/SET_SELECT_CELL',null);
+			changeSelection(selected)
+		})
+
+		/* 监听选中事件 */
+		graph.on('edge:mouseenter', ({ cell }) => {
+			// console.log(cell,'myEdgeOption');
+			// console.log(cell.store.data);
+			if(cell.store.data.shape=="mindmap-edge"){
+				// 思维导图的边
+			}else{
+				cell.addTools([
+					{
+						name: 'source-arrowhead',
+						args: {
+							attrs:{
+								d: 'M 8 -6 -8 0 8 6 Z',
+								fill: line.color
+							}
+						}
+					},
+					{
+						name: 'target-arrowhead',
+						args: {
+							attrs:{
+								d: 'M -8 -6 8 0 -8 6 Z',
+								fill: line.color
+							}
+						}
+					},
+					{
+						name:"vertices",
+						args:{
+							addable:false,
+							removable:false
+						}
+					},
+					{
+						name: 'segments'
+					}
+				])
+			}
+
+		})
+		
+		graph.on('edge:mouseleave', ({ cell }) => {
+			if(cell.store.data.shape=="mindmap-edge"){
+				// 思维导图的边
+			}else{
+				cell.removeTools()
+			}
 		})
 }
 
 /* 绑定键盘事件 */
-export const bindKey = (graph) => {
+export const bindKey = (graph,mindmapDataUseFun,mindmapAssistData) => {
 	 // 删除
 	graph.bindKey(['delete', 'backspace'], () => {
-		const select_cell = graph.getSelectedCells();
-			if (select_cell.length) {
-				// 移除工具
-				select_cell.forEach(item => item.removeTools());
-				graph.removeCells(select_cell)
-
-				//重置工具栏
-				store.commit('sand/SET_SELECT_STATUS',{key:'default'});
-				store.commit('sand/SET_SELECT_CELL',null);
-			}
-			return false
+		const mindmapDataUse=mindmapDataUseFun()
+		deleteNodes(graph,mindmapDataUse,mindmapAssistData)
+		return false
 	}, 'keydown');
 
 	/* cv */
 	graph.bindKey('ctrl+c', () => {
-		const select_cell = graph.getSelectedCells();
+		// 去除思维导图的节点
+		const select_cell = graph.getSelectedCells().filter(it => it.shape.indexOf('mindmap')==-1);
 		if (select_cell.length) {
 			graph.copy(select_cell)
 		}
@@ -189,35 +262,37 @@ export const bindKey = (graph) => {
 		}
 		return false
 	});
+
+	graph.bindKey('ctrl+z', () => {
+		if(graph.canUndo()){
+			graph.undo()
+		}
+		return false
+	});
+	graph.bindKey('ctrl+y', () => {
+		if(graph.canRedo()){
+			graph.redo()
+		}
+		return false
+	});
 }
 
 /* 右键事件 */
-export const contextEvent = (graph,key) => {
-	console.log(key)
+export const contextEvent = (graph,key,mindmapDataUse,mindmapAssistData) => {
+	// console.log(key)
 	switch (key) {
 		case 'copy':
 			nodeCopyAndPaste(graph);
 			break;
 		case 'del': 
-			nodeDelete(graph);
+			nodeDelete(graph,mindmapDataUse,mindmapAssistData);
 			break;
 	}
 }
 
 /* 删除节点 清空选区*/
-const nodeDelete = (graph) => {
-	const select_cell = graph.getSelectedCells();
-	console.log(select_cell)
-	if (select_cell.length) {
-
-		// 移除工具
-		select_cell.forEach(item => item.removeTools());
-		graph.removeCells(select_cell);
-
-		//重置工具栏
-		store.commit('sand/SET_SELECT_STATUS',{key:'default'});
-		store.commit('sand/SET_SELECT_CELL',null);
-	}
+const nodeDelete = (graph,mindmapDataUse,mindmapAssistData) => {
+	deleteNodes(graph,mindmapDataUse,mindmapAssistData)
 }
 /* 复制粘贴节点 */
 const nodeCopyAndPaste = (graph) => {
@@ -233,25 +308,116 @@ const nodeCopyAndPaste = (graph) => {
 }
 
 /* 关联三种基础图形选中样式 */
-const setSelectedOptions = ({ rect, text }, key) => {
-	return ['rect','date'].includes(key) ? {
-		text: { //文本设置
-			size: text.fontSize,
-			fontWeight: text.fontWeight, //
-			color: text.fill
-		},
-		border: { //线框设置
-			// isDash: 0, // 0实 1虚线
-			width: rect.strokeWidth,
-			fill: rect.fill,
-			borderColor: rect.stroke,
-		},
-
-	} : key === 'text' ? {
-		text: { //文本设置
-			size: text.fontSize,
-			fontWeight: text.fontWeight,
-			color: text.fill
-		},
-	}: {}
+// const setSelectedOptions = ({ rect, text }, key) => {
+// 	console.log({ rect, text },'{ rect, text }',key);
+// 	return ['rect','date'].includes(key) ? {
+// 		text: { //文本设置
+// 			size: text.fontSize,
+// 			fontWeight: text.fontWeight, //
+// 			color: text.fill
+// 		},
+// 		border: { //线框设置
+// 			// isDash: 0, // 0实 1虚线
+// 			width: rect.strokeWidth,
+// 			fill: rect.fill,
+// 			borderColor: rect.stroke,
+// 		},
+
+// 	} : key === 'text' ? {
+// 		text: { //文本设置
+// 			size: text.fontSize,
+// 			fontWeight: text.fontWeight,
+// 			color: text.fill
+// 		},
+// 	}: {}
+// }
+
+const deleteNodes=(graph,mindmapDataUse,mindmapAssistData)=>{
+	console.log(mindmapDataUse,mindmapAssistData,'最源数据');
+	const select_cell = graph.getSelectedCells();
+	let delete_cells=[]
+	let mindmapCell=[]
+	// return 
+	// console.log(select_cell.length,'select_cell.length');
+	for (let i = 0; i < select_cell.length; i++) {
+		const cell = select_cell[i];
+		if(cell.shape == "mindmap-edge"){
+			continue
+		}else if(cell.shape.indexOf('mindmap')!=-1){
+			mindmapCell.push(cell)
+			// 拿到该节点的所有子节点
+			let Successors = graph.getSuccessors(cell) 
+			// console.log(Successors,'Successors');
+			mindmapCell = [...mindmapCell,...Successors]
+		}
+		delete_cells.push(cell)
+	}
+	// 去重
+	const uniqueArr = mindmapCell.filter((item, index) => mindmapCell.findIndex(i => i.id === item.id) === index);
+	// console.log(uniqueArr,'uniqueArr');
+
+	delete_cells = [...delete_cells,...uniqueArr]
+	// return 
+	if (delete_cells.length) {
+		// 移除工具
+		delete_cells.forEach(item => item.removeTools());
+		graph.removeCells(delete_cells)
+	}
+	let shouldOperations=[]
+	mindmapDataUse.map((item,index)=>{
+		let levelIds = uniqueArr.filter(mindMap => mindMap.id.startsWith(item.mindmapData.id)).map(mindMap => mindMap.id)
+		// console.log(levelIds,'levelIds');
+		if(!(levelIds && levelIds.length>0)) return 
+		// console.log(levelIds,'levelIds');
+		let mindMapIds=[...levelIds]
+		for (let i = 0; i < levelIds.length; i++) {
+			const element = levelIds[i]
+			mindMapIds=mindMapIds.filter( id => id.indexOf(element) !=0 || id==element)
+		}
+		// console.log(mindMapIds,'mindMapIds');
+		shouldOperations.push(mindMapIds)
+	})
+	// 删除前备份
+	console.log(mindmapDataUse,'元数据');
+	mindmapAssistData.mindmapDataRecoverUse=[JSON.stringify(mindmapDataUse)]
+
+	console.log('删除备份',JSON.parse(mindmapAssistData.mindmapDataRecoverUse[0]),mindmapAssistData.mindmapDataRecoverUse.length,mindmapAssistData.mindmapDataRecoverUse);
+	
+	// console.log(shouldOperations,'shouldOperations');
+	shouldOperations.map(it =>{
+		it.map(it1 =>{
+			deleteMindmapData(it1,mindmapDataUse)
+		})
+	})
+	// console.log(mindmapDataUse,'mindmapDataUse',mindmapAssistData,'mindmapAssistData');
+
+}
+
+const deleteMindmapData=(id,data)=>{
+	// console.log(id,data,'id,data');
+	// return 
+	let ids = id.split('-')
+	let mindmapDataIndex = data.findIndex(mindmap => mindmap.mindmapData.id == ids[0])
+	if(ids.length==1){
+		data.splice(mindmapDataIndex,1)
+		return 
+	}
+
+	let mindmapData = data[mindmapDataIndex].mindmapData
+	let findId = ids[0]
+	for (let i = 1; i < ids.length-1; i++) {
+		const element = ids[i];
+		findId = findId+'-'+element
+		if(!(mindmapData && mindmapData.children)){
+			return 
+		}
+		mindmapData=mindmapData.children.find(it => it.id==findId)
+	}
+	let endId = ids[ids.length-1]
+	if(!(mindmapData && mindmapData.children)){
+		return 
+	}
+	let endIndex = mindmapData.children.findIndex(it => it.id == findId+'-'+endId)
+	mindmapData.children.splice(endIndex,1)
+	// console.log(data);
 }

+ 46 - 17
src/views/sandbox_manage/common/gragh.js

@@ -1,15 +1,28 @@
 import { Graph,Shape } from '@antv/x6';
 import { bindKey,myEvents } from './events';
 import { configOpt } from './toolConfig';
+import store from '@/vuex/index'
+console.log(store,'store');
+const styleConfig=store.state.sand.styleConfig
 
 const { line } = configOpt;
-
-export function myGraph (wrapper) {
+// wrapper DOM的Id mindmapDataUseFun 返回思维导图数组函数,传递给事件 type 模式,编辑和查看
+export function myGraph (wrapper,mindmapDataUseFun,mindmapAssistData,type='edit') {
 	const graph = new Graph({
 		container: document.getElementById(wrapper),
 		// width: $(window).width(),
 		// height: $(window).height(),
-		autoResize: true, 
+		history:{
+			enabled:true,
+			beforeAddCommand(event, args){
+				console.log(event, args,'event, args');
+				if(args.key=='tools'){
+					// 工具的改变不加入撤销和重做的队列
+					return false
+				}
+			}
+		},
+		autoResize: false, 
 		background: {
 			color: '#fff',
 		},
@@ -22,7 +35,12 @@ export function myGraph (wrapper) {
 		selecting: {
 			enabled: true,
 			showNodeSelectionBox: false,
-			multiple: false
+			multiple: true,
+			multipleSelectionModifiers:['shift'],
+			rubberband:true,
+			// rubberNode:true,
+			rubberEdge:true,//加上这个才能框选边 官方配置也不写……
+			modifiers:['ctrl']
 		},
 		snapline: true, //对齐线
 		// panning: { //画布拖动
@@ -40,7 +58,7 @@ export function myGraph (wrapper) {
 		}, //滚轮缩放
 		grid: {
 			size: 10,      // 网格大小
-			visible: true,
+			visible: false,
 		},
 		highlighting: {
 			// 当链接桩可以被链接时,在链接桩外围渲染一个 2px 宽的红色矩形框
@@ -66,10 +84,20 @@ export function myGraph (wrapper) {
 					},
 			},
 		},
+		interacting:type=='view'?{
+			nodeMovable:false,
+			magnetConnectable:false,
+			edgeMovable:false,
+			edgeLabelMovable:false,
+			arrowheadMovable:false,
+			vertexMovable:false,
+			vertexMovable:false,
+			vertexDeletable:false
+		}:{},
 		connecting: {
 			snap: true,
-			// 不允许连接到空白位置
-			allowBlank: false,
+			// 允许连接到空白位置
+			allowBlank: true,
 			// 不允许创建循环连线
 			allowLoop: false,
 			// 不允许在相同节点创建多条边
@@ -91,7 +119,7 @@ export function myGraph (wrapper) {
 				return new Shape.Edge({
 					attrs: {
 						line: {
-							stroke: line.color,
+							stroke: styleConfig.lineColor,
 							strokeWidth: line.width,
 							strokeDasharray: "",//虚线间隔
 							sourceMarker: false,//起始箭头 
@@ -103,25 +131,26 @@ export function myGraph (wrapper) {
 			},
 		},//连线
 		resizing: {
-			enabled: true,
+			enabled: type=='view'?false:true,
 			orthogonal: false,
 		},
 		scaling: {
 			min: 0.5,
 			max: 2
 		},
-        //小地图
-        minimap: {
-            enabled: true,
-            container: document.getElementById("minimap"),
-        }
+		//小地图
+		minimap: {
+				enabled: true,
+				container: document.getElementById("minimap"),
+		}
 	})
 
 	/* 节点操作事件 */
-	myEvents(graph);
+	if(type!='view') myEvents(graph,mindmapDataUseFun);
+	
 
 	/* 键盘事件 */
-	bindKey(graph);
+	if(type!='view') bindKey(graph,mindmapDataUseFun,mindmapAssistData);
 
 	return graph;
-}
+}

+ 566 - 0
src/views/sandbox_manage/common/mindmap.js

@@ -0,0 +1,566 @@
+import { Graph, Cell, Node, Path } from '@antv/x6'
+import Hierarchy from '@antv/hierarchy'
+
+export default {
+  data() {
+    return {
+      mindMapDataCurrent:{},
+      positionCurrent:{},
+      addTypeCurrent:'',
+      styleConfig:{}
+    }
+  },
+  mounted() {
+    
+  },
+  created() {
+    this.styleConfig=this.$store.state.sand.styleConfig
+    // console.log(this.styleConfig,'this.styleConfig');
+    // 中心主题
+    Graph.registerNode(
+      'mindmap-topic',          
+      {
+        inherit: 'rect',
+        markup: [
+          {
+            tagName: 'rect',
+            selector: 'body',
+          },
+          {
+            tagName: 'image',
+            selector: 'leftImg',
+          },
+          {
+            tagName: 'image',
+            selector: 'rightImg',
+          },
+          {
+            tagName: 'text',
+            selector: 'text',
+          },
+        ],
+        attrs: {
+          body: {
+            rx: 6,
+            ry: 6,
+            // stroke: this.$store.state.sand.styleConfig.borderColor,
+            // fill: this.$store.state.sand.styleConfig.backgroundColor,
+            strokeWidth: 1,
+            width:100,
+            height:50
+          },
+          leftImg: {
+            ref: 'body',
+            refX: -16,
+            refY: '50%',
+            refY2: -8,
+            width: 16,
+            height: 16,
+            'xlink:href':
+              'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
+            event: 'add:topic:left',
+            class: 'left-topic-image',
+          },
+          rightImg: {
+            ref: 'body',
+            refX: '100%',
+            refY: '50%',
+            refY2: -8,
+            width: 16,
+            height: 16,
+            'xlink:href':
+              'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
+            event: 'add:topic:right',
+            class: 'right-topic-image',
+          },
+          text: {
+            fontSize: 14,
+            fill: this.$store.state.sand.styleConfig.color,
+            textWrap:{
+              width:-10
+            }
+          }
+        },
+      },
+      true,
+    )
+    // 左分支主题
+    Graph.registerNode(
+      'mindmap-topic-left',          
+      {
+        inherit: 'rect',
+        markup: [
+          {
+            tagName: 'rect',
+            selector: 'body',
+          },
+          {
+            tagName: 'image',
+            selector: 'leftImg',
+          },
+          {
+            tagName: 'image',
+            selector: 'rightImg',
+          },
+          {
+            tagName: 'text',
+            selector: 'text',
+          },
+        ],
+        attrs: {
+          body: {
+            rx: 6,
+            ry: 6,
+            // stroke: this.$store.state.sand.styleConfig.borderColor,
+            // fill: this.$store.state.sand.styleConfig.backgroundColor,
+            strokeWidth: 1,
+            width:100,
+            height:50
+          },
+          leftImg: {
+            ref: 'body',
+            refX: -16,
+            refY: '50%',
+            refY2: -8,
+            width: 16,
+            height: 16,
+            'xlink:href':
+              'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
+            event: 'add:topic:left',
+            class: 'left-topic-image',
+          },
+          text: {
+            fontSize: 14,
+            fill: this.$store.state.sand.styleConfig.color,
+            textWrap:{
+              width:-10
+            }
+          }
+        },
+      },
+      true,
+    )    
+    // 右分支主题
+    Graph.registerNode(
+      'mindmap-topic-right',          
+      {
+        inherit: 'rect',
+        markup: [
+          {
+            tagName: 'rect',
+            selector: 'body',
+          },
+          {
+            tagName: 'image',
+            selector: 'leftImg',
+          },
+          {
+            tagName: 'image',
+            selector: 'rightImg',
+          },
+          {
+            tagName: 'text',
+            selector: 'text',
+          },
+        ],
+        attrs: {
+          body: {
+            rx: 6,
+            ry: 6,
+            // stroke: this.$store.state.sand.styleConfig.borderColor,
+            // fill: this.$store.state.sand.styleConfig.backgroundColor,
+            strokeWidth: 1,
+            width:100,
+            height:50
+          },
+          rightImg: {
+            ref: 'body',
+            refX: '100%',
+            refY: '50%',
+            refY2: -8,
+            width: 16,
+            height: 16,
+            'xlink:href':
+              'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
+            event: 'add:topic:right',
+            class: 'right-topic-image',
+          },
+          text: {
+            fontSize: 14,
+            fill:this.$store.state.sand.styleConfig.color,
+            textWrap:{
+              width:-10
+            }
+          }
+        },
+      },
+      true,
+    )
+    // 分支主题
+    // Graph.registerNode(
+    //   'mindmap-topic-child',
+    //   {
+    //     inherit: 'rect',
+    //     markup: [
+    //       {
+    //         tagName: 'rect',
+    //         selector: 'body',
+    //       },
+    //       {
+    //         tagName: 'text',
+    //         selector: 'text',
+    //       },
+    //       {
+    //         tagName: 'path',
+    //         selector: 'line',
+    //       },
+    //     ],
+    //     attrs: {
+    //       body: {
+    //         fill: '#ffffff',
+    //         strokeWidth: 0,
+    //         stroke: '#5F95FF',
+    //       },
+    //       text: {
+    //         fontSize: 14,
+    //         fill: '#262626',
+    //         textVerticalAnchor: 'bottom',
+    //       },
+    //       line: {
+    //         stroke: '#5F95FF',
+    //         strokeWidth: 2,
+    //         d: 'M 0 15 L 60 15',
+    //       },
+    //     },
+    //   },
+    //   true,
+    // )
+
+    // 连接器
+    Graph.registerConnector(
+      'mindmap',
+      (sourcePoint, targetPoint, routerPoints, options) => {
+        // console.log(sourcePoint, targetPoint, routerPoints, options,'sourcePoint, targetPoint, routerPoints, options');
+        const midX = sourcePoint.x + 10
+        const midY = sourcePoint.y
+        const ctrX = (targetPoint.x - midX) / 5 + midX
+        const ctrY = targetPoint.y
+        const pathData = `
+        M ${sourcePoint.x} ${sourcePoint.y}
+        Q ${ctrX} ${ctrY} ${targetPoint.x} ${targetPoint.y}
+        `
+        return options.raw ? Path.parse(pathData) : pathData
+      },
+      true,
+    )
+
+    // 边
+    Graph.registerEdge(
+      'mindmap-edge',
+      {
+        inherit: 'edge',
+        connector: {
+          name: 'mindmap',
+        },
+        attrs: {
+          line: {
+            targetMarker: false,
+            // stroke: this.$store.state.sand.styleConfig.lineColor,
+            strokeWidth: 2,
+          },
+        },
+        zIndex: 0,
+      },
+      true,
+    )
+  },
+  methods: {
+    setGraph(){
+      this.graph.on('add:topic:left', ({ node }) => {
+        if(this.operationType=='view') return 
+        const { id } = node
+        this.setCurrent(id)
+        const type = node.prop('type')
+        if (this.addChildNode(id, type,'left')) {
+          this.mindMapRender()      
+        }
+      })
+
+      this.graph.on('add:topic:right', ({ node }) => {
+        if(this.operationType=='view') return 
+        const { id } = node
+        this.setCurrent(id)
+        const type = node.prop('type')
+        if (this.addChildNode(id, type,'right')) {
+          this.mindMapRender()      
+        }
+      })
+      this.graph.on('node:change:size', (args) => { 
+        if(this.operationType=='view') return 
+        if(args.node.shape.indexOf('mindmap')!==-1){
+          let ids = args.node.id.split('-')
+					let mindmapDataIndex = this.mindmapDataUse.findIndex(mindmap => mindmap.mindmapData.id == ids[0])
+					let mindMapDataCurrent = this.mindmapDataUse[mindmapDataIndex]?this.mindmapDataUse[mindmapDataIndex].mindmapData:{}
+
+					let findId = ids[0]
+
+					for (let i = 1; i < ids.length; i++) {
+						const element = ids[i];
+						findId = findId+'-'+element
+						mindMapDataCurrent=mindMapDataCurrent.children.find(it => it.id==findId)
+					}
+
+					mindMapDataCurrent.width = args.node.size().width
+					mindMapDataCurrent.height = args.node.size().height
+        }
+      })
+      this.graph.on('node:change:position', (args) => { 
+        if(this.operationType=='view') return 
+        if(args.node.shape.indexOf('mindmap')!==-1 && Number(args.node.id)){
+
+          let index = this.mindmapDataUse.findIndex(it =>it.mindmapData.id == args.node.id)
+          // let index = Number(args.node.id)
+          if(index!=-1){
+            this.mindmapDataUse[index].position = args.current
+          // this.setCurrent(args.node.id)
+          }
+        }
+      })
+      // this.graph.on('node:added', ({node}) => { 
+      //   if(node.shape.indexOf('mindmap')!=-1){
+      //     // 思维导图需要处理相对应的数据
+      //     console.log('mindmap',node.id);
+      //   }
+      //   console.log(node,'node:added');
+      // })
+      // this.graph.on('node:removed', (args) => { 
+      //   console.log(args,'node:removed');
+      // })
+      // this.graph.bindKey(['backspace', 'delete'], () => {
+      //   const selectedNodes = this.graph.getSelectedCells().filter((item) => item.isNode())
+      //   if (selectedNodes.length) {
+      //     const { id } = selectedNodes[0]
+      //     if (this.removeNode(id)) {
+      //       this.mindMapRender()
+      //     }
+      //   }
+      // })
+      
+      this.graph.bindKey('tab', (e) => {  
+        if(this.operationType=='view') return 
+        e.preventDefault()
+        const selectedNodes = this.graph.getSelectedCells().filter((item) => {
+          return item.shape.indexOf('mindmap')!=-1 && item.isNode()
+        })
+        if (selectedNodes.length) {
+          const node = selectedNodes[0]
+          this.setCurrent(node.id)
+          let type = node.prop('type')
+          let direction = node.shape.indexOf('left')!=-1?'left':'right'
+          if (this.addChildNode(node.id, type,direction)) {
+            this.mindMapRender()
+          }
+        }
+      })
+    },
+    // 通过id设置当前操作的思维导图
+    setCurrent(id){
+      let rootId = id.split('-')[0]
+      let index = this.mindmapDataUse.findIndex(it =>it.mindmapData.id == rootId)
+      this.mindMapDataCurrent = this.mindmapDataUse[index]?this.mindmapDataUse[index].mindmapData:{}
+      this.positionCurrent = this.mindmapDataUse[index]?this.mindmapDataUse[index].position:{x:0,y:0}
+      this.addTypeCurrent = this.mindmapDataUse[index]?this.mindmapDataUse[index].addType:'singleMindmap'
+    },
+    mindMapRender(i){
+      this.graph.startBatch('renderMindmap')
+      let mindMapType = i || i==0?this.mindmapDataUse[i].addType:this.addTypeCurrent
+      this.mindMapDataCurrent = i || i==0?this.mindmapDataUse[i].mindmapData:this.mindMapDataCurrent
+      this.positionCurrent = i || i==0?this.mindmapDataUse[i].position:this.positionCurrent
+      const result = Hierarchy.mindmap(this.mindMapDataCurrent, {
+        direction: 'H',
+        getHeight(d) {
+          return d.height
+        },
+        getWidth(d) {
+          return d.width
+        },
+        getHGap() {
+          return 40
+        },
+        getVGap() {
+          return 20
+        },
+        getSide: (d) => {
+          return mindMapType.indexOf('double') != -1?d.data.direction || 'left':'right'
+        }
+      })
+      const cells = []
+      let xGap = this.positionCurrent?this.positionCurrent.x-result.x:0
+      let yGap = this.positionCurrent?this.positionCurrent.y-result.y:0
+      // console.log(result,'result');
+      // return 
+      const traverse = (hierarchyItem) => {
+        if (hierarchyItem) {
+          const { data, children } = hierarchyItem
+          // console.log(hierarchyItem,'hierarchyItemhierarchyItemhierarchyItem');
+          let mindmapDirection = mindMapType.indexOf('double') != -1?data.direction:'right'
+          // console.log(mindmapDirection,data.label,data.direction);
+          let currentCell=this.graph.getCellById(data.id)
+
+          if(!currentCell){
+            // 没有 新增
+            cells.push(
+              this.graph.createNode({
+                id: data.id,
+                shape:mindmapDirection=='right'?'mindmap-topic-right':mindmapDirection=='left'?'mindmap-topic-left':'mindmap-topic',
+                x: xGap+hierarchyItem.x,
+                y: yGap+hierarchyItem.y,
+                width: data.width,
+                height: data.height,
+                label: data.label,
+                type: data.type,
+                attrs:{
+                  body: {
+                    stroke: this.$store.state.sand.styleConfig.borderColor,
+                    fill: this.$store.state.sand.styleConfig.backgroundColor
+                  },
+                  text:{
+                    fill:this.$store.state.sand.styleConfig.color
+                  }
+                },
+              }),
+            )
+          }else{
+            // 有,更新下位置信息
+            currentCell.position(xGap+hierarchyItem.x,yGap+hierarchyItem.y)
+          }
+          // return 
+   
+          if (children) {
+            children.forEach((item) => {
+              const { id, data } = item
+              let mindmapChildDirection = mindMapType.indexOf('double') != -1?data.direction:'right'
+              let currentEdge=this.graph.getCellById(data.id)
+              if(!currentEdge){
+                cells.push(
+                  this.graph.createEdge({
+                    shape: 'mindmap-edge',
+                    attrs:{
+                      line:{
+                        stroke:this.$store.state.sand.styleConfig.lineColor
+                      }
+                    },
+                    source: {
+                      cell: hierarchyItem.id,
+                      anchor: {
+                        name: 'center',
+                        args: {
+                          dx: mindmapChildDirection=='right'?'25%':mindmapChildDirection=='left'?'-25%':0,
+                        },
+                      },
+                    },
+                    target: {
+                      cell: id,
+                      anchor: {
+                        name: mindmapChildDirection =='left'?'right':'left',
+                      },
+                    },
+                  }),
+                )
+              }
+
+              traverse(item)
+            })
+          }
+        }
+      }
+      traverse(result)
+      // 排下序,把边放最后面 不然 边 会找不到 节点
+      let sortCells = cells.sort(cell => cell.shape.indexOf('edge'))
+      // console.log(sortCells,'result');
+      // return 
+      // this.graph.removeCells(sortCells)
+      this.graph.addCell(sortCells)
+      this.graph.stopBatch('renderMindmap')
+      // this.graph.resetCells(cells)
+      // this.graph.centerContent()
+    },
+    findItem(obj,id){
+      if (obj.id === id) {
+        return {
+          parent: null,
+          node: obj,
+        }
+      }
+      const { children } = obj
+      if (children) {
+        for (let i = 0, len = children.length; i < len; i++) {
+          const res = this.findItem(children[i], id)
+          if (res) {
+            return {
+              parent: res.parent || obj,
+              node: res.node,
+            }
+          }
+        }
+      }
+      return null
+    },
+    addChildNode (id, type,direction='left'){
+      console.log('添加');
+      // 重做不了 清空重做栈
+      this.mindmapAssistData.mindmapDataRecoverUse = []
+      // console.log(this.mindmapAssistData);
+
+      const res = this.findItem(this.mindMapDataCurrent, id)
+      const dataItem = res && res.node
+      if (dataItem) {
+        let item = null
+        // console.log(dataItem.children);
+        let addId ='1'
+        if(dataItem.children && dataItem.children.length>0){
+          let ids = dataItem.children[dataItem.children.length-1].id.split('-')
+          addId = parseInt(ids[ids.length-1])+1+''
+        }
+        if (type === 'topic') {
+          item = {
+            id: `${id}-${addId}`,
+            type: 'topic-branch',
+            label: `分支主题${addId}`,
+            width: 100,
+            height: 40,
+            direction
+          }
+        } else if (type === 'topic-branch' || type=='topic-child') {
+          item = {
+            id: `${id}-${addId}`,
+            type: 'topic-child',
+            label: `子主题${addId}`,
+            width: 60,
+            height: 30,
+            direction
+          }
+        }
+        if (item) {
+          if (dataItem.children) {
+            dataItem.children.push(item)
+          } else {
+            dataItem.children = [item]
+          }
+          return item
+        }
+      }
+      return null
+    },
+    removeNode (id) {
+      const res = this.findItem(this.mindMapDataCurrent, id)
+      const dataItem = res && res.parent
+      if (dataItem && dataItem.children) {
+        const { children } = dataItem
+        const index = children.findIndex((item) => item.id === id)
+        return children.splice(index, 1)
+      }
+      return null
+    }
+  },
+}

+ 276 - 64
src/views/sandbox_manage/common/node.js

@@ -1,73 +1,93 @@
 import { configOpt } from './toolConfig';
+import store from "@/vuex/index"
 
 const { line,border,text } = configOpt;
 
+console.log(store,'storestorestore');
+const styleConfig=store.state.sand.styleConfig
+
 //定义图形
 const configStyles = {
 	rect: {
-		width: '120px',
-		height: '50px',
-		textAlign: 'center',
-		lineHeight: '50px',
-		border: '1px solid #5b8ffa',
-		backgroundColor: border.fill,
-		borderColor: border.borderColor,
-		borderRadius: '4px',
-		color: '#7D7671',
-		margin: '0 10px 20px 0',
+		width: '30px',
+		height: '18px',
+		border: `2px solid #27292A`
+	},
+	roundRect: {
+		width: '30px',
+		height: '18px',
+		border: `2px solid #27292A`,
+		borderRadius:"8px"
+	},
+	ellipse:{
+		width: '30px',
+		height: '18px',
+		border: `2px solid #27292A`,
+		borderRadius:"100%"
+	},
+	rhomboid:{
+		width: '14px',
+		height: '14px',
+		border: `2px solid #27292A`,
+		transform: 'rotate(-45deg) skew(10deg, 10deg)',
+		position:'relative',
+		left:'4px',
+		marginRight:'6px'
 	},
 	text: {
-		width: '110px',
-		height: '50px',
+		width: '30px',
+		height: '18px',
 		textAlign: 'center',
-		lineHeight: '50px',
-		background: '#fff',
-		color: text.color,
+		lineHeight: '18px',
+		border: `2px solid #27292A`,
+		color: '#333333',
 		fontSize: '14px',
-		fontWeight: 'normal',
-		
+		fontWeight: 'bold',
 	},
-	date: {
-		width: '120px',
-		height: '50px',
-		textAlign: 'center',
-		lineHeight: '50px',
-		backgroundColor: '#5B9BD5',
-		borderRadius: '4px',
-		color: '#fff',
-		fontSize: '14px',
-		fontWeight: 'bold'
-	}
-
 }
 
-/* 图形种类 */
 export const myNodes = [
 	{
 		shape: 'rect',
 		key: 'rect',
-		label: '双击输入文本',
+		label:'',
+		img:'~@/assets/img/chart_m/User_act.png',
 		styles: {
 			...configStyles.rect,
 		}
 	},
 	{
 		shape: 'rect',
-		key: 'text',
-		label: '双击替换文本',
+		key: 'roundRect',
+		label:'',
 		styles: {
-			...configStyles.text,
+			...configStyles.roundRect,
+		}
+	},
+	{
+		shape: 'ellipse',
+		key: 'ellipse',
+		label:'',
+		styles: {
+			...configStyles.ellipse,
+		}
+	},
+	{
+		shape: 'polygon',
+		key: 'rhomboid',
+		label:'',
+		styles: {
+			...configStyles.rhomboid,
 		}
 	},
 	{
 		shape: 'rect',
-		key: 'date',
-		label:'Date:',
+		key: 'text',
+		label: 'T',
 		styles: {
-			...configStyles.date,
+			...configStyles.text,
 		}
 	},
-
 ]
 
 
@@ -84,28 +104,31 @@ export const portStyle = {
 		}
 	}
 }
-// 创建的节点配置 框 文本 日期
+// 创建的节点配置 矩形、圆角矩形、椭圆形、菱形、文本
 export const myNodeOption = (key) => {
 	switch (key) {
 		case 'rect': 
 			return {
-				width: 120,
-				height: 50,
+				width: 60,
+				height: 40,
 				data: {
 					key
 				},
 				attrs: {
-					rect: {
-						stroke: border.borderColor,
+					body: {
+						stroke: styleConfig.borderColor,
 						strokeWidth: border.width,
-						fill: border.fill,
+						fill:styleConfig.backgroundColor,
 						strokeDasharray: null,
 					},
 					text: {
-						fill: text.color,
+						fill: styleConfig.color,
 						fontSize: text.size,
 						lineHeight: text.lineHeight,
 						fontWeight: 'normal',
+						fontStyle:"normal",
+						textDecoration:'none',
+						relativeLineHeight:1.3,
 						textWrap: {
 							width: -10,
 						},
@@ -118,6 +141,66 @@ export const myNodeOption = (key) => {
 							{ 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
+							}
+					}
+				},
+			}
+		case 'roundRect': 
+			return {
+				width: 60,
+				height: 40,
+				data: {
+					key
+				},
+				attrs: {
+					body: {
+						stroke: styleConfig.borderColor,
+						strokeWidth: border.width,
+						fill: styleConfig.backgroundColor,
+						strokeDasharray: null,
+						rx:8,
+						ry:8
+					},
+					text: {
+						fill: styleConfig.color,
+						fontSize: text.size,
+						lineHeight: text.lineHeight,
+						fontWeight: 'normal',
+						fontStyle:"normal",
+						textDecoration:'none',
+						relativeLineHeight:1.3,
+						textWrap: {
+							width: -10,
+						},
+					}
+				},
+				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',
@@ -142,57 +225,186 @@ export const myNodeOption = (key) => {
 					}
 				},
 			}
-		case 'date': 
+		case 'ellipse': 
 			return {
-				width: 120,
-				height: 50,
+				width: 60,
+				height: 40,
 				data: {
-					key,
+					key
 				},
 				attrs: {
-					rect: {
-						stroke: '#5B9BD5',
-						strokeWidth: 1,
-						fill: '#5B9BD5'
+					body: {
+						stroke: styleConfig.borderColor,
+						strokeWidth: border.width,
+						fill: styleConfig.backgroundColor,
+						strokeDasharray: null,
 					},
 					text: {
-						text: 'Date:',
-						fill: '#fff',
-						fontSize: 18,
+						fill: styleConfig.color,
+						fontSize: text.size,
+						lineHeight: text.lineHeight,
 						fontWeight: 'normal',
+						fontStyle:"normal",
+						textDecoration:'none',
+						relativeLineHeight:1.3,
+						textWrap: {
+							width: -10,
+						},
+					}
+				},
+				ports: {
+					items: [
+							{ group: 'port-ellipse', id: 'p_top' },
+							{ group: 'port-ellipse', id: 'p_bottom' },
+							{ group: 'port-ellipse', id: 'p_left' },
+							{ group: 'port-ellipse', id: 'p_right' },
+							{ group: 'port-ellipse', id: 'p_top-1' },
+							{ group: 'port-ellipse', id: 'p_bottom-1' },
+							{ group: 'port-ellipse', id: 'p_left-1' },
+							{ group: 'port-ellipse', id: 'p_right-1' },
+					],
+					groups: {
+							"port-ellipse": {
+									position: 'ellipseSpread',
+									zIndex: 20,
+									...portStyle
+							},
+							// "port-bottom": {
+							// 		position: 'bottom',
+							// 		zIndex: 20,
+							// 		...portStyle
+							// },
+							// "port-left": {
+							// 		position: 'left',
+							// 		zIndex: 20,
+							// 		...portStyle
+							// },
+							// "port-right": {
+							// 		position: 'right',
+							// 		zIndex: 20,
+							// 		...portStyle
+							// },
+					}
+				},
+			}
+		case 'rhomboid': 
+			return {
+				width: 60,
+				height: 60,
+				// angle:-45,
+				data: {
+					key
+				},
+				attrs: {
+					body: {
+						stroke: styleConfig.borderColor,
+						strokeWidth: border.width,
+						fill: styleConfig.backgroundColor,
+						strokeDasharray: null,
+						refPoints: '0,10 10,0 20,10 10,20',
+					},
+					text: {
+						fill: styleConfig.color,
+						fontSize: text.size,
 						lineHeight: text.lineHeight,
+						fontWeight: 'normal',
+						fontStyle:"normal",
+						textDecoration:'none',
+						relativeLineHeight:1.3,
 						textWrap: {
 							width: -10,
 						},
 					}
 				},
-				ports: false
+				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
+							},
+					}
+				},
 			}
 		case 'text': 
 			return {
-				width: 120,
-				height: 50,
+				width: 60,
+				height: 40,
 				data: {
 					key,
 				},
 				attrs: {
-					rect: {
+					body: {
 						stroke: '',
 						strokeWidth: 0,
 						fill: 'transparent',
 					},
 					text: {
-						text: '双击替换文本',
+						text: '文本',
 						fontSize: text.size,
 						lineHeight: text.lineHeight,
 						fontWeight: 'normal',
-						fill: text.color,
+						fontStyle:"normal",
+						textDecoration:'none',
+						relativeLineHeight:1.3,
+						fill: styleConfig.textColor,
 						textWrap: {
 							width: -10,
 						},
 					}
 				},
+				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
+							}
+					}
+				},
 			}
 	}
-	
-}
+}
+

+ 16 - 2
src/views/sandbox_manage/common/options.js

@@ -4,11 +4,25 @@ export const contextMenuOption = [
 	{
 		label: '复制',
 		key: 'copy',
-		icon: 'el-icon-document-copy'
+		icon: 'el-icon-document-copy',
+		show:true
 	},
 	{
 		label: '删除',
 		key: 'del',
-		icon: 'el-icon-delete'
+		icon: 'el-icon-delete',
+		show:true
+	},
+	{
+		label: '添加链接',
+		key: 'addLink',
+		icon: 'el-icon-link',
+		show:true
+	},
+	{
+		label: '清除链接',
+		key: 'deleteLink',
+		icon: 'el-icon-delete',
+		show:true
 	},
 ]

+ 57 - 5
src/views/sandbox_manage/common/toolConfig.js

@@ -8,20 +8,37 @@ export let configOpt = {
 		lineHeight: TEXT_SIZE * 1.3,
 	},
 	line: { //线条设置
-		width: 2,
-		color: '#5B9BD5',
+		width: 1,
+		color: '#0052D9',
 	},
 	border: { //线框设置
-		isDash: 0, // 0实 1虚线
+		isDash: 0, // 0实 1虚线border: 1px solid #0052D9
 		width: 2,
-		fill: '#fff',
-		borderColor: '#5B9BD5',
+		fill: '#DAE8FF',
+		borderColor: '#0052D9',
 	}
 }
 
 /* 定义默认颜色 */
 export const colorsOptions = ['#333','#5B9BD5','#f00','#fff','#00f','#000','#00FFFF','#70DB93','#9F5F9F','#A67D3D','#5F9F9F']
 
+export const familyOptions = [
+	{name:'微软雅黑',value:'微软雅黑'},
+	{name:'宋体',value:'宋体'},
+	{name:'黑体',value:'黑体'}
+]
+export const fontSizeOptions = [
+	{name:'12px',value:12},
+	{name:'14px',value:14},
+	{name:'16px',value:16},
+	{name:'18px',value:18}
+]
+export const lineHeightOptions = [
+	1,
+	1.15,
+	1.5,
+	2
+]
 export const sizeOptions = [
 	30,
 	28,
@@ -34,4 +51,39 @@ export const sizeOptions = [
 	14,
 	12,
 	10,
+]
+
+export const styleSettings=[
+	{
+		id:1,
+		backgroundColor:'#BBCEFF',
+		color:'#1841AA',
+		textColor:'#1841AA',
+		borderColor:'#1841AA',
+		lineColor:'#1841AA'
+	},
+	{
+		id:2,
+		backgroundColor:'#1841AA',
+		color:'#FFFFFF',
+		textColor:'#1841AA',
+		borderColor:'#1841AA',
+		lineColor:'#1841AA'
+	},
+	{
+		id:3,
+		backgroundColor:'#FFFFFF',
+		color:'#333333',
+		textColor:'#333333',
+		borderColor:'#333333',
+		lineColor:'#333333'
+	},
+	{
+		id:4,
+		backgroundColor:'#FFF6F4',
+		color:'#AA3218',
+		textColor:'#AA3218',
+		borderColor:'#AA3218',
+		lineColor:'#AA3218'
+	}
 ]

+ 2 - 0
src/views/sandbox_manage/index.vue

@@ -1,3 +1,5 @@
+<!-- 此沙盘图为老版本,防止后面需求回溯 暂作保留,后续新版沙盘图使用时间增长,使用情况稳定,还请给予删除,防止项目越来越大 开始保留时间 2023-10-9 -->
+<!-- 同目录的sanFlow目录下也一样的情况,属于老版本 -->
 <template>
   <div class="sandList-container">
     <div class="main-top">

+ 1704 - 0
src/views/sandbox_manage/index_new_version.vue

@@ -0,0 +1,1704 @@
+<template>
+  <div id="sandbox-index-container">
+    <span class="slide-icon slide-right" @click="slideHandle" v-show="isSlideLeft">
+      <i class="el-icon-d-arrow-right"></i>
+    </span>
+    <div class="sandbox-content-tree-box" v-show="!isSlideLeft">
+      <div class="sandbox-content-tree-header">
+        <el-button type="primary" style="width: 170px;" @click="addSand" v-permission="permissionBtn.sandboxPermission.sandbox_saveView">添加逻辑</el-button>
+        <el-checkbox v-model="searchParams.IsShowMe" @change="onlyMeHandler">只看我的</el-checkbox>
+      </div>
+      <div class="sandbox-content-tree-body">
+        <div style="padding: 0 20px;" v-permission="permissionBtn.sandboxPermission.sandbox_search">
+          <el-select v-model="searchSandboxId" v-loadMore="searchLoad" :filterable="!searchSandboxId" remote @change="sandboxChange"
+          clearable placeholder="请输入逻辑图名称" style="width: 100%; margin-bottom: 20px;" :remote-method="searchHandle"
+          @click.native="inputFocusHandle">
+            <i slot="prefix" class="el-input__icon el-icon-search"></i>
+            <el-option
+              v-for="item in searchOptions"
+              :key="item.SandboxId"
+              :label="item.Name"
+              :value="item.SandboxId"
+            >
+            </el-option>
+          </el-select>
+        </div>
+        <div class="sandbox-content-tree">
+          <tree :nodes="treeData" :setting="setting" @onCreated="getZTree" @onDrop="zTreeDrop" key="classify" 
+          @onExpand="zTreeExpand"/>
+          <div class="add-classify" v-permission="permissionBtn.sandboxPermission.sandbox_classify_addEdit">
+            <img src="~@/assets/img/sand_new/add_ico.png"/>
+            <span @click="addLevelOneHandle">添加分类</span>
+          </div>
+          <span class="slide-icon slide-left" @click="slideHandle">
+            <i class="el-icon-d-arrow-left"></i>
+          </span>
+        </div>
+      </div>
+    </div>
+    <div class="sandbox-pictures-box" v-show="rightType=='list'" v-permission="permissionBtn.sandboxPermission.sandbox_saveView">
+      <div class="pictures-count">
+        共{{total}}个逻辑图
+      </div>
+      <div class="pictures-box" ref="pictureListRef" @scroll="loadMoreSandbox">
+        <el-col :span="6" style="margin-bottom:20px;padding-right: 20px;min-width: 255px;"
+        v-for="picture in pictureList" :key="picture.SandboxId">
+          <div class="pictures-item">
+            <div class="pictures-item-header">
+              <span class="text_oneLine">{{ picture.Name }}</span>
+            </div>
+            <img :src="picture.PicUrl" class="picture-img" @click="detailShowHandle(picture)"/>
+            <div class="item-bottom">
+              <span>{{ picture.CreateTime.slice(0,10) }}</span>
+              <div class="item-bottom-buttons">
+                <span class="join_txt" @click="copyHandle(picture)" v-permission="permissionBtn.sandboxPermission.sandbox_addMy">复制</span>
+                <span class="join_txt" @click="deleteHandle(picture,'inList')" style="color: #C54322;"
+                v-permission="permissionBtn.sandboxPermission.sandbox_del">删除</span>
+              </div>
+            </div>
+          </div>
+        </el-col>
+      </div>
+    </div>
+    <div class="sandbox-chart-box" 
+    :style="{visibility:rightType=='list'?'hidden':'visible',
+            width:rightType=='list'?'1px':'unset',
+            flexGrow:rightType=='list'?'unset':1}">
+      <div class="sandbox-chart-head">
+        <div class="sandbox-chartHead-author">作者:<span>{{ this.viewSandbox.SysUserName }}</span></div>
+        <div class="sandbox-chartHead-title">{{ this.viewSandbox.Name }}</div>
+        <div class="sandbox-chartHead-options">
+          <div class="chartHead-options-button" @click="editSand" v-permission="permissionBtn.sandboxPermission.sandbox_saveView">
+            <img src="~@/assets/img/sand_new/edit_outline.png" />
+            <span>编辑</span> 
+          </div>
+          <div class="chartHead-options-button" @click="saveOther">
+            <img src="~@/assets/img/sand_new/save-other.png" />
+            <span>另存为</span> 
+          </div>
+          <div class="chartHead-options-button" @click="copySandHandle" v-permission="permissionBtn.sandboxPermission.sandbox_addMy">
+            <img src="~@/assets/img/sand_new/copy.png" />
+            <span>复制</span> 
+          </div>
+          <div class="chartHead-options-button" @click="deleteHandle(viewSandbox,'inchart')">
+            <img src="~@/assets/img/sand_new/remove.png" />
+            <span style="color: red;" v-permission="permissionBtn.sandboxPermission.sandbox_del">删除</span> 
+          </div>
+        </div>
+      </div>
+      <div class="sandbox-body">
+        <div class="sand-chart-body" id="sand-chart-body"></div>
+        <!-- 缩略图 -->
+        <div id="minimap" class="minimap"></div>
+        <el-popover
+        placement="top"
+        trigger="manual"
+        v-model="popoverVisible">
+        <div id="link-popover" :style="{height:popoverFlod?'20px':'unset'}">
+          <div class="link-box">
+            <div v-for="item in checkedLinkList" :key="item.RId" class="link-item" @click="navigateTo(item)">
+              {{ item.Name }}
+            </div>
+          </div>
+          <img src="~@/assets/img/sand_new/arrow_black_down.png" class="link-fold" 
+          :style="{transform:popoverFlod?'':'rotate(180deg)'}" v-show="checkedLinkList.length>1"
+          @click="foldLink"/>
+        </div>
+        <div id="link-reference" slot="reference"></div>
+      </el-popover>
+      </div>
+    </div>
+    <!-- 目录自定义按钮区域 -->
+    <div id="custom-button-zone" class="custom-button-zone">
+      <img src="~@/assets/img/sand_new/add_outline.png" class="add-classify-img" v-permission="permissionBtn.sandboxPermission.sandbox_classify_addEdit"/>
+      <img src="~@/assets/img/sand_new/edit_outline.png" class="edit-classify-img" v-permission="permissionBtn.sandboxPermission.sandbox_classify_addEdit"/>
+      <img src="~@/assets/img/sand_new/delete_outline.png" class="delete-classify-img" v-permission="permissionBtn.sandboxPermission.sandbox_classify_del"/>
+    </div>
+    <!-- 添加分类 -->
+    <el-dialog
+      :title="classifyAddTitle"
+      :visible.sync="classifyAddShow"
+      :append-to-body="true"
+      :close-on-click-modal="false"
+      @closed="classifyAddClosed"
+      width="560px">
+      <div style="padding: 10px 40px 0;">
+        <el-form :model="classifyForm" ref="classifyFormRef" :rules="classifyFormRules" 
+        label-width="80px">
+          <el-form-item label="上级目录" v-if="lastLevelClassifyName">
+            {{ lastLevelClassifyName }}
+          </el-form-item>
+          <el-form-item label="目录名称" prop="SandboxClassifyName">
+            <el-input v-model="classifyForm.SandboxClassifyName" style="width: 317px;" placeholder="请输入目录名称"></el-input>
+          </el-form-item>
+          <el-form-item label="关联品种" prop="ChartPermissionId" v-if="hasVariety && (classifyAddTitle.indexOf('添加')!==-1)">
+            <el-cascader 
+							:options="classifyArr"
+							:props="classifyProps"
+							v-model="classifyForm.ChartPermissionId" 
+							placeholder="请选择对应品种" 
+              id="classifyAddCascader"
+						/>
+          </el-form-item>
+        </el-form>
+        <div style="text-align: center;padding:40px 0 ;">
+          <el-button @click="classifyAddSubmit" type="primary" style="width: 120px;" size="large">保存</el-button>
+          <el-button @click="classifyAddShow=false" style="width: 120px;margin-left: 28px;" size="large">取消</el-button>
+        </div>
+      </div>
+    </el-dialog>
+    <!-- 另存为 -->
+    <el-dialog
+      title="另存为"
+      :visible.sync="saveOtherShow"
+      :append-to-body="true"
+      :close-on-click-modal="false"
+      @closed="saveOtherClosed"
+      width="600px">
+      <div style="padding: 10px 40px 0;" class="save-as-dialog">
+        <el-form :model="saveOtherForm" ref="saveOtherFormRef"
+        label-width="96px">
+          <el-form-item label="逻辑图名称" prop="chartName" :rules="{required:true,message:'请输入逻辑图名称',trigger:'blur'}">
+            <el-input v-model="saveOtherForm.chartName" style="width: 317px;" placeholder="请输入逻辑图名称"></el-input>
+          </el-form-item>
+          <el-form-item label="分类" prop="classifyId" :rules="{required:true,message:'请选择分类',trigger:'change'}" >
+            <el-popover
+              placement="bottom"
+              width="400"
+              popper-class="classify-popper"
+              trigger="click"
+              v-model="selectClassifyShow">
+                <tree :nodes="onlyClassifyTreeData" :setting="selectSetting" key="saveOther" @onCreated="getSelectZTree" @onClick="selectClassify" />
+                <el-cascader 
+                slot="reference"
+                :options="onlyClassifyTreeData"
+                :props="{children: 'Children',
+                  label: 'SandboxClassifyName',
+                   value: 'SandboxClassifyId',emitPath:false,checkStrictly:true}"
+                v-model="saveOtherForm.classifyId" 
+                popper-class="classify-cascader-popper"
+                placeholder="请选择分类">
+                </el-cascader>
+            </el-popover>
+          </el-form-item>
+        </el-form>
+        <div style="text-align: center;padding:40px 0 ;">
+          <el-button @click="saveOtherSubmit" type="primary" style="width: 120px;" size="large">保存</el-button>
+          <el-button @click="saveOtherShow=false" style="width: 120px;margin-left: 28px;" size="large">取消</el-button>
+        </div>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import tree from "vue-giant-tree";
+import { dataBaseInterface,sandInterface,customInterence} from '@/api/api.js';
+import { svgToBase64 } from '@/utils/svgToblob'
+import mindmap from "./common/mindmap"
+
+import { myGraph } from './common/gragh';
+
+  export default {
+    name:"sandbox_manage_index",
+    components:{tree},
+    computed:{
+      hasVariety(){
+        return this.permissionBtn.isShowBtn('sandboxPermission','sandbox_variety')
+      }
+    },
+    mixins:[mindmap],
+    watch: {
+      initData(newval) {
+        console.log(newval);
+        if(!this.graph){
+          this.$nextTick(()=>{
+            this.init()
+            this.graph.fromJSON(newval);
+            this.graph.zoomToFit()
+          })
+        }else{
+          this.graph.fromJSON(newval);
+          this.graph.zoomToFit()
+        }
+      }
+	  },
+    data() {
+      return {
+        SandboxClassifyId:0,
+        searchOptions:[],
+        searchHaveMore:false,
+        rightType:"list",
+        pictureHaveMore:false,
+        searchParams:{
+          SandboxClassifyId:'',
+          PageSize:12,
+          CurrentIndex:1,
+          IsShowMe:false
+        },
+        searchCurrentIndex:1,
+        KeyWord:'',
+        searchSandboxId:'',
+        total:0,
+        pictureList:[],
+        treeData:[],
+        onlyClassifyTreeData:[],
+        setting:{
+          data:{
+            keep:{
+              leaf:true,
+              parent:true
+            },
+            key:{
+              name:"SandboxClassifyName",
+              children:"Children",
+              isParent:"isCatalogue"
+            },
+          },
+          view:{
+            showLine:false,
+            showIcon:false,
+            selectedMulti:false,
+            addDiyDom: this.addDiyDom,
+            // addHoverDom: this.addHoverDom,
+		        // removeHoverDom: this.removeHoverDom
+          },
+          edit:{
+            enable:true,
+            showRemoveBtn:false,
+            showRenameBtn:false,
+            drag:{
+              isCopy:false,
+              isMove:true,
+            }
+          },
+          callback:{
+            beforeDrag:this.zTreeDragBefore,
+            beforeDrop:this.zTreeDropBefore,
+            onDrop:this.zTreeDrop,
+            beforeExpand:this.zTreeExpandBefore,
+            onClick:this.zTreeClick
+          }
+        },
+        zTreeObj:{},
+        selectSetting:{
+          data:{
+            key:{
+              name:"SandboxClassifyName",
+              children:"Children"
+            }
+          },
+          view:{
+            showLine:false,
+            showIcon:false,
+            selectedMulti:false
+          }
+        },
+        selectClassifyShow:false,
+        selectZTreeObj:{},
+        lockLoding:null,
+        viewSandbox:{},
+        activeNode:{},
+        addClassifyNodeTid:'',
+        movingRecoveData:{
+          targetNode:null,
+          treeNode:null,
+          moveType:''
+        },
+        graph:null,
+        initData:{},
+        // ------- 添加分类弹窗
+        classifyAddTitle:"添加分类",
+        classifyAddShow:false,
+        lastLevelClassifyName:'',
+        classifyForm:{
+          SandboxClassifyId:0,
+          SandboxClassifyName:'',
+          ChartPermissionId:null,
+          ParentId:0,
+          Level:0
+        },
+        classifyFormRules:{
+          SandboxClassifyName:{required: true, message:'请输入目录名称', trigger: 'blur'},
+          ChartPermissionId:{required: true, message:'请选择对应品种', trigger: 'change'}
+        },
+        classifyProps: {
+          children: 'Items',
+          label: 'ClassifyName',
+          value: 'ChartPermissionId',
+          emitPath:false
+			  },
+        classifyArr:[],
+        // 另存为弹窗
+        saveOtherShow:false,
+        saveOtherForm:{
+          chartName:"",
+          classifyId:""
+        },
+        saveOtherClassifys:'',
+        locationActiveNode:'',
+        operationType:'view',
+        popoverVisible:false,
+        popoverFlod:true,
+        popoverDom:null,
+        popoverTriggerDom:null,
+        checkedLinkList:[],
+        linkNode:null,
+        popoverTimeout:null,
+        isSlideLeft:false
+      }
+    },
+    created(){
+      this.getClassify()
+      this.getSandboxClassify()
+      this.getSandboxClassifyOnly()
+      this.getSandboxList()
+      // this.setting.async={
+        // enable:false,
+        // type:'head'
+      //   url:(()=>{
+      //     console.log(process.env);
+      //     // console.log(process.env.VUE_APP_API_ROOT,'process.env.VUE_APP_API_ROOT');
+      //     // if(process.env.NODE_ENV === "development"){
+      //     //   return "http://8.136.199.33:7777/adminapi/sandbox/classify/list"
+      //     // }else{
+      //       return process.env.VUE_APP_API_ROOT+'/sandbox/classify/list'
+      //     // }
+      //   })(),
+      //   type:'get',
+      //   autoParam: ["SandboxClassifyId"],
+      //   otherParam:{ "IsShowMe":this.isOnlyMe},
+      //   dataFilter: (treeId,parentNode,responseData)=>{
+      //     console.log(treeId,parentNode,responseData,'responseData');
+      //     return responseData.Data.AllNodes
+      //   },
+      //   headers:{
+      //     Authorization:localStorage.getItem("auth"),
+      //     Uuid:localStorage.getItem("uuid") || "",
+      //     AccessToken:localStorage.getItem("uuid")+"--zheshiyigename",
+      //   }
+      // }
+    },
+    mounted(){
+      // this.init()
+      this.popoverDom = $('#link-popover')[0];
+      this.popoverTriggerDom = $('#link-reference')[0];
+      
+      this.popoverDom.addEventListener('mouseenter',this.clearPopoverTimeout)
+      this.popoverDom.addEventListener('mouseleave',this.closePopover)
+
+    },
+    beforeDestroy(){
+      this.popoverDom.removeEventListener('mouseenter',this.clearPopoverTimeout)
+      this.popoverDom.removeEventListener('mouseleave',this.closePopover)
+
+    },
+    methods:{
+      /* 获取品种 */
+      getClassify() {
+        customInterence.getvariety({
+          CompanyType: 'ficc'
+        }).then(res => {
+          console.log(res);
+          if(res.Ret !== 200)  return
+            this.classifyArr = res.Data.List||[ ]
+        })
+      },
+      // 获取沙盘图分类
+      getSandboxClassify(parentNode,locationNode) {
+        console.log(parentNode,locationNode,'parentNode,locationNode');
+        const sandboxClassifyId = parentNode ? parentNode.SandboxClassifyId:0
+        sandInterface.getSandboxClassify({SandboxClassifyId:sandboxClassifyId,IsShowMe:this.searchParams.IsShowMe}).then(res=>{
+          console.log(res);
+          if (res.Ret === 200) {
+            let nodesData=res.Data.AllNodes || []
+            nodesData.map(item =>{
+              item.isCatalogue = item.SandboxId?false:true
+            })
+            if(parentNode){
+              this.zTreeObj.addNodes(parentNode,nodesData)
+            }else{
+              this.treeData = nodesData
+            }
+            if(locationNode){
+              let searchNode
+              let locationId = locationNode.isCatalogue?locationNode.SandboxClassifyId:locationNode.SandboxId
+              if(parentNode){
+                if(locationNode.isCatalogue){
+                  searchNode=this.zTreeObj.getNodesByParam('SandboxClassifyId',+locationId,parentNode)
+                }else{
+                  searchNode=this.zTreeObj.getNodesByParam('SandboxId',+locationId,parentNode)
+                }
+                console.log(searchNode,'searchNode');
+                if(!(searchNode && searchNode.length>0)) return 
+                this.zTreeClick(null,'',searchNode[0],1)
+                this.zTreeObj.selectNode(searchNode[0])
+              }else{
+                requestAnimationFrame(()=>{
+                  searchNode=this.zTreeObj.getNodesByParam('SandboxClassifyId',+locationId)
+                  console.log(searchNode,'searchNode');
+                  if(!(searchNode && searchNode.length>0)) return 
+                  this.zTreeClick(null,'',searchNode[0],1)
+                  this.zTreeObj.selectNode(searchNode[0])
+                })
+              }
+
+            }
+          }
+        })
+      },
+      getSandboxClassifyOnly(){
+        sandInterface.getSandboxClassifyOnly().then(res=>{
+          if (res.Ret === 200) {
+            this.onlyClassifyTreeData=res.Data.AllNodes || []
+          }
+        })
+      },
+      getSandboxList(type){
+        if(type == 'setCurrentIndex'){
+          this.searchParams.CurrentIndex=1
+        }
+        sandInterface.getSandboxListV2(this.searchParams).then(res=>{
+          console.log(res,'res');
+          if(res.Ret == 200){
+            if(!res.Data){
+              this.pictureList=[]
+              this.total = 0
+              this.pictureHaveMore=false
+            }else{
+              let arr = res.Data.List || []
+              this.pictureList=this.searchParams.CurrentIndex == 1 ?arr:[...this.pictureList,...arr]
+              this.total = res.Data.Paging.Totals || 0
+              this.pictureHaveMore= this.searchParams.CurrentIndex < res.Data.Paging.Pages
+            }
+            this.rightType='list'
+          }
+        })
+      },
+      getZTree(zTree){
+        this.zTreeObj=zTree
+      },
+      getSelectZTree(zTree){
+        this.selectZTreeObj=zTree
+      },
+      selectClassify(event,treeId,treeNode,clickFlag){
+        this.sandSaveParams.SandboxClassifyId = treeNode.SandboxClassifyId
+        this.selectClassifyShow = false
+      },
+      zTreeDragBefore(treeId,treeNodes){
+        return this.permissionBtn.isShowBtn('sandboxPermission','sandbox_classify_move')
+      },
+      zTreeDropBefore(treeId,treeNodes,targetNode,moveType,isCopy){
+        console.log(treeId,treeNodes,targetNode,moveType,isCopy,'zTreeDropBefore');
+        if((!targetNode) && (!moveType)) return false
+        if(((!treeNodes[0].isCatalogue) && targetNode.Level==1 && moveType!='inner')||
+        ((!targetNode.isCatalogue) && moveType=='inner')||
+        (treeNodes[0].isCatalogue && targetNode.Level==5 && moveType=='inner')){
+          return false
+        }
+
+        // 接口失败后的还原
+        // this.movingRecoveData.treeNode=treeNodes[0]
+        // if(treeNodes[0].getPreNode()){
+        //   this.movingRecoveData.targetNode = treeNodes[0].getPreNode()
+        //   this.movingRecoveData.moveType = "next"
+        // }else if(treeNodes[0].getNextNode()){
+        //   this.movingRecoveData.targetNode = treeNodes[0].getNextNode()
+        //   this.movingRecoveData.moveType = "prev"
+        // }else if(treeNodes[0].getParentNode()){
+        //   this.movingRecoveData.targetNode = treeNodes[0].getParentNode()
+        //   this.movingRecoveData.moveType = "inner"
+        // }
+      },
+      zTreeDrop(e,treeId,treeNodes,targetNode,moveType,isCopy){
+        console.log(treeId,treeNodes[0],targetNode,moveType,isCopy,'zTreeDrop');
+        if((!targetNode) && (!moveType)) return
+        console.log(treeNodes[0].getParentNode(),targetNode.getParentNode());
+        let parentNode = treeNodes[0].getParentNode()
+        let prevNode = treeNodes[0].getPreNode()
+        let nextNode = treeNodes[0].getNextNode()
+        //移动分类
+        let params={
+          ClassifyId:treeNodes[0].SandboxClassifyId,
+          SandboxId:treeNodes[0].isCatalogue?0:treeNodes[0].SandboxId,
+          ParentClassifyId:parentNode?parentNode.SandboxClassifyId:0,
+          PrevId:prevNode? (prevNode.isCatalogue?prevNode.SandboxClassifyId:prevNode.SandboxId) :0,
+          NextId:nextNode? (nextNode.isCatalogue?nextNode.SandboxClassifyId:nextNode.SandboxId) :0,
+          PrevType:prevNode?(prevNode.isCatalogue?1:2):0,
+          NextType:nextNode?(nextNode.isCatalogue?1:2):0
+        }
+        sandInterface.sandboxClassifyMove(params).then(res=>{
+          if(res.Ret == 200){
+            this.$message.success('移动分类成功')
+            if(parentNode){
+              this.zTreeObj.removeChildNodes(parentNode)
+            }
+            this.getSandboxClassify(parentNode,treeNodes[0])
+          }
+        })
+        // if((!targetNode) && (!moveType)) return
+        // let parentNode = treeNodes[0].getParentNode()
+        // let prevNode = treeNodes[0].getPreNode()
+        // let nextNode = treeNodes[0].getNextNode()
+        // //移动分类
+        // let params={
+        //   ClassifyId:treeNodes[0].SandboxClassifyId,
+        //   SandboxId:treeNodes[0].isCatalogue?0:treeNodes[0].SandboxId,
+        //   ParentClassifyId:parentNode?parentNode.SandboxClassifyId:0,
+        //   PrevId:prevNode? (prevNode.isCatalogue?prevNode.SandboxClassifyId:prevNode.SandboxId) :0,
+        //   NextId:nextNode? (nextNode.isCatalogue?nextNode.SandboxClassifyId:nextNode.SandboxId) :0,
+        //   PrevType:prevNode?(prevNode.isCatalogue?1:2):0,
+        //   NextType:nextNode?(nextNode.isCatalogue?1:2):0
+        // }
+        // console.log(params);
+        // sandInterface.sandboxClassifyMove(params).then(res=>{
+        //   if(res.Ret == 200){
+        //     this.$message.success('移动分类成功')
+        //   }else{
+        //     // let result=this.zTreeObj.moveNode(this.movingRecoveData.targetNode,this.movingRecoveData.treeNode,this.movingRecoveData.moveType)
+        //     // if(!result){
+        //     //   window.location.reload()
+        //     // }
+        //   }
+        // })
+      },
+      zTreeExpandBefore(treeId, treeNode){
+        // console.log( treeId, treeNode);
+        if(treeNode.Children && treeNode.Children.length>0){
+          return true
+        }else{
+          this.getSandboxClassify(treeNode)
+        }
+      },
+      zTreeExpand(event, treeId, treeNode){
+        // console.log(event, treeId, treeNode);
+      },
+      zTreeClick(event, treeId, treeNode,clickFlag){
+        console.log(event, treeId, treeNode,clickFlag);
+
+        if(clickFlag==1){
+          if(this.activeNode.SandboxClassifyId == treeNode.SandboxClassifyId &&
+          this.activeNode.SandboxId == treeNode.SandboxId){
+            return 
+          }
+          this.activeNode = treeNode
+          if(treeNode.isCatalogue){
+            // 目录
+            this.searchParams.CurrentIndex=1
+            this.searchParams.SandboxClassifyId = treeNode.SandboxClassifyId
+            this.getSandboxList('setCurrentIndex')
+            // this.rightType='list'
+          }else{
+            // 沙盘图
+            sandInterface.getSandboxDetail({SandboxId:this.activeNode.SandboxId}).then(res=>{
+              console.log(res);
+              if(res.Ret == 200){
+                this.viewSandbox=res.Data
+                this.rightType='chart'
+                this.initData = JSON.parse(this.viewSandbox.Content)
+              }
+            })
+          }
+        }
+
+        if(clickFlag==0 && treeNode.isCatalogue){
+          this.activeNode={}
+          this.searchParams.CurrentIndex=1
+          this.searchParams.SandboxClassifyId = ''
+          this.getSandboxList('setCurrentIndex')
+          // this.rightType='list'
+        }
+      },
+      onlyMeHandler(){
+        this.activeNode={}
+        this.getSandboxClassify()
+        this.searchParams.SandboxClassifyId=''
+        this.getSandboxList('setCurrentIndex')
+      },
+      searchHandle(query) {
+        // console.log(query,"搜索");
+        this.searchCurrentIndex = 1;
+        this.KeyWord = query;
+        this.searchSandbox()
+		  },
+      searchSandbox(){
+        sandInterface.getSandboxListV2({...this.searchParams,
+          CurrentIndex:this.searchCurrentIndex,SandboxClassifyId:'',
+          KeyWord:this.KeyWord}).then(res=>{
+            if(res.Ret == 200){
+              if(!res.Data){
+                this.searchOptions=[]
+                this.searchHaveMore=false
+              }else{
+                let arr = res.Data.List || []
+                this.searchOptions=this.searchCurrentIndex==1?arr:[...this.searchOptions,...arr]
+                this.searchHaveMore = this.searchCurrentIndex < res.Data.Paging.Pages
+              }
+            }
+          })
+      },
+      searchLoad() {
+        // 加载更多
+        console.log("加载更多");
+        if(!this.searchHaveMore) return;
+        this.searchCurrentIndex++
+        this.searchSandbox()
+		  },
+      /* 聚焦获取当前检索 */
+      inputFocusHandle(e) {
+        // 选取
+        console.log('选取',e.target.value);
+        this.searchCurrentIndex = 1;
+        this.KeyWord = e.target.value;
+        if(this.KeyWord) {
+          this.searchSandbox()
+        }else {
+          this.searchOptions = [];
+        }
+      },
+      sandboxChange(sandboxId){
+        let sandbox=this.searchOptions.find(it => it.SandboxId == sandboxId)
+        if(sandbox){
+          this.rightType='chart'
+          this.viewSandbox=sandbox
+          this.initData = sandbox.Content?JSON.parse(sandbox.Content):sandbox.Content
+          let ParentClassifys = sandbox.ParentIds.split(',').filter(Boolean)
+          ParentClassifys.push(sandbox.SandboxClassifyId)
+          ParentClassifys.push(sandbox.SandboxId)
+          this.sandboxLocation(ParentClassifys)
+        }
+      },
+      // 添加一级分类
+      addLevelOneHandle(){
+        this.classifyAddTitle="添加分类"
+        this.classifyAddShow=true
+        this.addClassifyNodeTid=''
+      },
+      addClassify(e,node){
+        e.stopPropagation()
+        console.log(node);
+        this.addClassifyNodeTid = node.tId
+        this.lastLevelClassifyName = this.getParentNodeName(node)
+        this.classifyAddTitle="添加分类"
+        this.classifyForm.Level = node.Level
+        this.classifyForm.ParentId = node.SandboxClassifyId
+        this.classifyAddShow=true
+      },
+      getParentNodeName(node){
+        let parentNode = node.getParentNode()
+        if(parentNode){
+          return this.getParentNodeName(parentNode)+'/'+node.SandboxClassifyName
+        }else{
+          return node.SandboxClassifyName
+        }
+      },
+      editClassify(e,node){
+        console.log(node);
+        e.stopPropagation()
+        let pNode = node.getParentNode()
+        this.lastLevelClassifyName = pNode ? pNode.SandboxClassifyName:''
+        this.classifyForm.SandboxClassifyId = node.SandboxClassifyId
+        this.classifyForm.SandboxClassifyName = node.SandboxClassifyName
+        this.classifyAddTitle="重命名"
+        this.classifyAddShow=true
+      },
+      deleteClassify(e,node){
+        e.stopPropagation()
+        sandInterface.deleteSandboxClassifyCheck({SandboxClassifyId:node.SandboxClassifyId}).then(res=>{
+          if (res.Ret === 200) {
+            /**
+             * 0 可删除
+             * 1 关联沙盘图
+             * 2 有子目录无沙盘图
+             */
+            const deleteLabelMap = {
+              1: '该分类下存在沙盘图,不可删除',
+              2: '确认删除当前分类及包含的子分类吗?',
+              4: res.Data.TipsMsg
+            }
+
+            if([1,4].includes(res.Data.DeleteStatus)) this.$confirm(
+                deleteLabelMap[res.Data.DeleteStatus],
+                '删除失败',
+                {
+                confirmButtonText: '知道了',
+                showCancelButton:false,
+                type: 'error'
+              })
+            else if([0,2].includes(res.Data.DeleteStatus)) this.$confirm(
+                res.Data.DeleteStatus === 2 
+                ? deleteLabelMap[res.Data.DeleteStatus]
+                : node.SandboxId?'确认删除该沙盘图吗?':'确定删除当前分类吗?', 
+                '提示',
+                {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'warning'
+              }).then(() => {
+                res.Data.DeleteStatus === 0 && node.SandboxId 
+                ? this.delHandle(node.SandboxClassifyId, node.SandboxId, 1)
+                : this.delHandle(node.SandboxClassifyId, node.SandboxId);
+              }).catch(() => {         
+              });
+          }
+        })
+      },
+      delHandle(SandboxClassifyId,SandboxId,type){
+        let currentNode = this.zTreeObj.getSelectedNodes()[0]
+        sandInterface.deleteSandbox({
+          SandboxClassifyId,
+          SandboxId,
+        }).then((res) => {
+          if (res.Ret === 200) {
+            this.zTreeObj.removeNode(currentNode)
+            this.$message.success(res.Msg);
+            // if(type && res.Data.SandboxId){
+              
+            // }else{
+
+            // }
+          }
+        });
+      },
+      classifyAddSubmit(){
+        console.log(this.classifyForm);
+        //提交
+        this.$refs.classifyFormRef.validate(valid=>{
+          if(valid){
+            if(this.classifyForm.SandboxClassifyId){
+              //编辑
+              let params={
+                SandboxClassifyId:this.classifyForm.SandboxClassifyId,
+                SandboxClassifyName:this.classifyForm.SandboxClassifyName
+              }
+              sandInterface.editSandboxClassify(params).then(res=>{
+                if(res.Ret == 200){
+                  this.classifyAddShow=false
+                  this.$message.success(this.classifyAddTitle+"成功")
+                  let currentNode = this.zTreeObj.getSelectedNodes()[0]
+
+                  currentNode.SandboxClassifyName = this.classifyForm.SandboxClassifyName
+                  this.zTreeObj.updateNode(currentNode)
+                  // this.getSandboxClassify()
+                }
+              })
+            }else{
+              //新增
+              let params={
+                SandboxClassifyName:this.classifyForm.SandboxClassifyName,
+                ParentId:this.classifyForm.ParentId,
+                Level:this.classifyForm.Level,
+                ChartPermissionId:this.classifyForm.ChartPermissionId
+              }
+              sandInterface.addSandboxClassify(params).then(res=>{
+                if(res.Ret == 200){
+                  this.classifyAddShow=false
+                  this.$message.success(this.classifyAddTitle+"成功")
+                  if(!this.addClassifyNodeTid){
+                    this.getSandboxClassify()
+                  }else{
+                    let curNode = this.zTreeObj.getNodeByTId(this.addClassifyNodeTid)
+                    // console.log(curNode,'');
+                    this.zTreeObj.removeChildNodes(curNode)
+                    // this.$nextTick(()=>{
+                      this.zTreeObj.expandNode(curNode,true,false,false,true)
+                    // })
+                  }
+                }
+              })
+            }
+
+          }
+        })
+      },
+      classifyAddClosed(){
+        this.classifyForm={
+          SandboxClassifyId:0,
+          SandboxClassifyName:'',
+          ChartPermissionId:null,
+          ParentId:0,
+          Level:0
+        }
+        this.lastLevelClassifyName=""
+        this.$refs.classifyFormRef.clearValidate()
+      },
+      /* 加载更多 */
+      loadMoreSandbox:_.throttle(function(e) {
+        let scrollTop = this.$refs.pictureListRef.scrollTop;
+        let clientHeight = this.$refs.pictureListRef.clientHeight;
+        let scrollHeight = this.$refs.pictureListRef.scrollHeight;
+        // console.log('scrollTop:',scrollTop)
+        // console.log('clientHeight:',clientHeight)
+        // console.log('scrollHeight:',scrollHeight)
+        if(scrollTop + clientHeight >= scrollHeight-10 && this.pictureHaveMore){
+          this.searchParams.CurrentIndex++
+          this.getSandboxList();
+          console.log("加载更多");
+        }
+      },300),
+      /* 展示详情 */
+      detailShowHandle(item) {
+        this.viewSandbox=item
+        this.rightType='chart' 
+        this.initData = JSON.parse(item.Content)
+        let ParentClassifys = item.ParentIds.split(',').filter(Boolean)
+        ParentClassifys.push(item.SandboxClassifyId)
+        ParentClassifys.push(item.SandboxId)
+        this.sandboxLocation(ParentClassifys)
+      },
+      async sandboxLocation(ParentClassifys){
+        console.log(ParentClassifys,'ParentClassifys');
+        let beActiveNode=''
+        for (let i = 0; i < ParentClassifys.length; i++) {
+          const element = ParentClassifys[i];
+          // if(i == (ParentClassifys.length-1)){
+          //   console.log(+element,beActiveNode,'element');
+          //   let searchNode=this.zTreeObj.getNodesByParam('SandboxId',+element,beActiveNode)
+          //   console.log(searchNode[0]);
+          //   this.zTreeObj.selectNode(searchNode[0],false,false)
+          //   return 
+          // }
+          let searchNode=this.zTreeObj.getNodesByParam('SandboxClassifyId',+element,beActiveNode)
+          console.log(searchNode,'searchNode',i);
+          if(!(searchNode&&searchNode.length>0)){
+            if(!beActiveNode){
+              break
+            }
+            let flag =false
+            if(i == ParentClassifys.length-1){
+              // 最后一层找沙盘的id SandboxId
+              flag = await this.expandNodeAsync(beActiveNode,+element,true)
+            }else{
+              flag = await this.expandNodeAsync(beActiveNode,+element)
+            }
+
+            if(!flag){
+              return 
+            }else{
+              beActiveNode=flag[0]
+            }
+          }else{
+            beActiveNode = searchNode[0]
+          }
+        }
+        this.locationActiveNode=beActiveNode
+        // 选中
+        requestAnimationFrame(()=>{
+          this.zTreeObj.selectNode(beActiveNode)
+          this.activeNode = beActiveNode
+        })
+      },
+      expandNodeAsync(parentNode,activeId,isLast=false){
+        return new Promise((resolve,reject)=>{
+          let resultNode ;
+          if(isLast){
+            resultNode = this.zTreeObj.getNodesByParam('SandboxId',activeId,parentNode)
+          }else{
+            resultNode = this.zTreeObj.getNodesByParam('SandboxClassifyId',activeId,parentNode)
+          }
+          console.log(resultNode,'resolve(resultNode)');
+          if(resultNode.length>0){
+            resolve(resultNode)
+            return 
+          }
+          sandInterface.getSandboxClassify({SandboxClassifyId:parentNode.SandboxClassifyId,IsShowMe:this.searchParams.IsShowMe}).then(res=>{
+            if (res.Ret === 200) {
+              let nodesData=res.Data.AllNodes || []
+              nodesData.map(item =>{
+                item.isCatalogue = item.SandboxId?false:true
+              })
+              this.zTreeObj.addNodes(parentNode,nodesData)
+              if(isLast){
+                resolve(this.zTreeObj.getNodesByParam('SandboxId',activeId,parentNode))
+              }else{
+                resolve(this.zTreeObj.getNodesByParam('SandboxClassifyId',activeId,parentNode))
+              }
+            }else{
+              resolve(null)
+            }
+          })
+        })
+      },
+      copyHandle:_.debounce(function ({ PicUrl }){
+        if(!PicUrl) return this.$message('暂无内容可复制')
+        console.log("复制");
+        this.lockLoding = this.$loading({
+          lock: true,
+          text: '复制图片中...',
+          target: '.sandbox-pictures-box',
+          spinner: 'el-icon-loading',
+          background: 'rgba(255, 255, 255, 0.8)'
+        });
+        const canvas = document.createElement("canvas");
+        const ctx = canvas.getContext("2d");
+        const img = new Image();
+        img.crossOrigin = "Anonymous";
+        img.src = PicUrl;
+        img.onload = ()=>{
+          canvas.width = img.width;
+          canvas.height = img.height;
+          ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+          ctx.fillStyle="#fff";
+          ctx.fillRect(0, 0, img.width, img.height);
+          ctx.drawImage(img, 0, 0);
+          if(window.ClipboardItem) {
+            canvas.toBlob(async (blob) => {
+              const data = [new ClipboardItem({ [blob.type]: blob })]; 
+              await navigator.clipboard.write(data).then(
+                () => {
+                this.$message.success('复制成功!')
+                },
+                () => {
+                  this.$message.warning('浏览器不支持')
+                }
+              ).finally(()=>{
+                this.lockLoding && this.lockLoding.close();
+              });
+            });
+          }else {
+            this.lockLoding && this.lockLoding.close();
+            this.$message.warning('当前协议暂不支持,仅支持https协议')
+          }
+        }
+      },500),
+      deleteHandle(item,type){
+        console.log(item,type);
+        this.$confirm("确定删除该沙盘图吗?", "提示", {
+          type: "warning",
+        })
+        .then(() => {
+          sandInterface.deleteSandbox({
+          SandboxClassifyId:item.SandboxClassifyId,
+          SandboxId:item.SandboxId,
+          }).then((res) => {
+            if (res.Ret === 200) {
+              this.$message.success(res.Msg);
+              let result = this.zTreeObj.getNodesByParam('SandboxId',item.SandboxId)[0]
+              console.log(result);
+              if(type=='inList'){
+                // 在沙盘图列表中删除
+                if(result){
+                  this.zTreeObj.removeNode(result)
+                }
+              }else{
+                // 在沙盘图详情删除
+                this.sandboxLocation([result.SandboxClassifyId])
+                this.zTreeObj.removeNode(result)
+              }
+              this.getSandboxList('setCurrentIndex')
+              
+            }
+          });
+        })
+        .catch(() => {});
+      },
+      addDiyDom(treeId, treeNode) {
+        // console.log(treeNode,'treeId, treeNode');
+        var aObj = $("#" + treeNode.tId + "_a");
+        if ($("#diyBtn_"+treeNode.SandboxClassifyId).length>0) return;
+        if(treeNode.isCatalogue){
+          //目录添加自定义按钮
+          let dom = $('#custom-button-zone')[0].cloneNode(true)
+          let addClassifyDom = $(dom).find('.add-classify-img')[0]
+          let editClassifyDom = $(dom).find('.edit-classify-img')[0]
+          let delClassifyDom = $(dom).find('.delete-classify-img')[0]
+          if(treeNode.Level>4){
+            addClassifyDom && (addClassifyDom.style.display='none')
+          }else{
+            addClassifyDom && addClassifyDom.addEventListener("click",(e)=>this.addClassify(e,treeNode))
+          }
+          editClassifyDom && editClassifyDom.addEventListener("click",(e)=>this.editClassify(e,treeNode))
+          delClassifyDom && delClassifyDom.addEventListener("click",(e)=>this.deleteClassify(e,treeNode))
+
+          aObj.append(dom);
+        }
+
+      },
+      // removeHoverDom(treeId, treeNode) {
+      //   console.log(treeId, treeNode,'treeId, treeNode');
+      //   $("#diyBtn_"+treeNode.SandboxClassifyId).unbind().remove();
+	    //   $("#diyBtn_space_" +treeNode.SandboxClassifyId).unbind().remove();
+      // }
+      addSand(){
+        const { href } = this.$router.resolve({ path: '/sandflow' });
+        window.open(href, '_blank');
+      },
+      editSand(){
+        const { href } = this.$router.resolve({ path: '/sandflow' ,query:{SandboxId:this.viewSandbox.SandboxId}});
+        window.open(href, '_blank');
+      },
+      saveOther(){
+        this.saveOtherForm.chartName = this.viewSandbox.Name+"(1)"
+        this.saveOtherShow=true
+      },
+      saveOtherSubmit: _.debounce( function() {
+        // console.log(this.viewSandbox);
+        // return 
+        if(!this.graph.toJSON().cells.length) return this.$message.warning('画布无内容');
+        this.$refs.saveOtherFormRef.validate(valid=>{
+          if(valid){
+            const { Content,MindmapData} = this.viewSandbox;
+            this.lockLoding = this.$loading({
+              lock: true,
+              text: '保存中...',
+              target: '.save-as-dialog',
+              spinner: 'el-icon-loading',
+              background: 'rgba(255, 255, 255, 0.8)'
+            });
+            const { cells } = this.graph.toJSON();
+            this.graph.toSVG(async (dataUri) => {
+              const params = new FormData();
+              params.append('Img',dataUri)
+              const { Data } = await dataBaseInterface.uploadImgSvg(params);
+
+              // return 
+              const { Ret , Data : sandData} = await sandInterface.sandboxSaveV2({
+                Name:this.saveOtherForm.chartName,
+                SandboxClassifyId: Number(this.saveOtherForm.classifyId),
+                Content,
+                PicUrl: Data?Data.ResourceUrl:'',
+                SvgData: dataUri,
+                MindmapData
+              })
+
+              if(Ret !== 200){
+                this.lockLoding.close();
+                return;
+              }
+              console.log(sandData,'sandData');
+              this.lockLoding.close();
+              this.$message.success("另存为成功")
+              let saveOtherIds = this.saveOtherClassifys.split(',')
+              saveOtherIds.push(sandData.SandboxId)
+              this.sandboxLocation(saveOtherIds)
+              this.saveOtherShow=false
+            },{
+              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}`)
+                // 在图表右下方 加上"来源:弘则研究"字样
+                let gNode = svg.getElementsByClassName('x6-graph-svg-viewport')[0]
+                // 去掉不该截图的添加图标
+                let leftImg = svg.getElementsByClassName('left-topic-image')
+                for (let i = 0; i < leftImg.length; i++) {
+                  const element = leftImg[i];
+                  element.parentElement.removeChild(element)
+                  i--
+                }
+                let rightImg = svg.getElementsByClassName('right-topic-image')
+                for (let i = 0; i < rightImg.length; i++) {
+                  const element = rightImg[i];
+                  element.parentElement.removeChild(element)
+                  i--
+                }
+                let textNode = document.createElement('text')
+                textNode.setAttribute('x',x-tx+width-90)
+                textNode.setAttribute('y',y-ty+height+22)
+                textNode.setAttribute('font-size','16px')
+                textNode.setAttribute('font-style','italic')
+                textNode.innerText = '来源:弘则研究'
+                gNode.appendChild(textNode)
+                  },
+              copyStyles:false,
+              stylesheet: `
+                  svg{
+                      background-color:white;
+                  }
+                .x6-port {
+                    visibility: hidden;
+                }
+                ` 
+            })
+          }
+        })
+
+          
+      },500),
+      saveOtherClosed(){
+        this.saveOtherForm={
+          chartName:"逻辑图名称",
+          classifyId:""
+        }
+        this.selectZTreeObj.cancelSelectedNode()
+        this.$refs.saveOtherFormRef.clearValidate()
+      },
+      copySandHandle: _.debounce(function() {
+        const { cells } = this.graph.toJSON();
+        if(!cells.length) return this.$message.warning('当前画布无可复制内容');
+
+        this.lockLoding = this.$loading({
+          lock: true,
+          text: '复制图片中...',
+          target: '.sandbox-chart-box',
+          spinner: 'el-icon-loading',
+          background: 'rgba(255, 255, 255, 0.8)'
+        });
+        this.graph.toSVG(async(dataUri) => {
+
+        const canvas = document.createElement("canvas");
+        const ctx = canvas.getContext("2d");
+        const img = new Image();
+        img.crossOrigin = "Anonymous";
+        img.src = svgToBase64(dataUri);
+        img.onload = ()=>{
+          canvas.width = img.width;
+          canvas.height = img.height;
+          // console.log('width',img.width)
+          // console.log('height',img.height)
+          ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+          ctx.fillStyle="#fff";
+          ctx.fillRect(0, 0, img.width, img.height);
+          ctx.drawImage(img, 0, 0);
+          if(window.ClipboardItem) {
+            canvas.toBlob(async (blob) => {
+                const data = [new ClipboardItem({ [blob.type]: blob })]; 
+                await navigator.clipboard.write(data).then(
+                () => {
+                    this.$message.success('复制成功!')
+                },
+                () => {
+                    this.$message.warning('浏览器不支持')
+                }
+                ).finally(()=>{
+                    this.lockLoding && this.lockLoding.close();
+                });
+            });
+          }else {
+            this.lockLoding && this.lockLoding.close();
+            this.$message.warning('当前协议暂不支持,仅支持https协议')
+          }	
+        }
+      },{
+        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}`)
+          let gNode = svg.getElementsByClassName('x6-graph-svg-viewport')[0]
+          // 去掉不该截图的添加图标
+          let leftImg = svg.getElementsByClassName('left-topic-image')
+          for (let i = 0; i < leftImg.length; i++) {
+            const element = leftImg[i];
+            element.parentElement.removeChild(element)
+            i--
+          }
+          let rightImg = svg.getElementsByClassName('right-topic-image')
+          for (let i = 0; i < rightImg.length; i++) {
+            const element = rightImg[i];
+            element.parentElement.removeChild(element)
+            i--
+          }
+          let textNode = document.createElement('text')
+          textNode.setAttribute('x',x-tx+width-90)
+          textNode.setAttribute('y',y-ty+height+22)
+          textNode.setAttribute('font-size','16px')
+          textNode.setAttribute('font-style','italic')
+          textNode.innerText = '来源:弘则研究'
+          gNode.appendChild(textNode)
+            },
+        copyStyles:false,
+        stylesheet: `
+            svg{
+                background-color:white;
+            }
+          .x6-port {
+              visibility: hidden;
+          }` 
+        })
+      },500),
+      selectClassify(event,treeId,treeNode,clickFlag){
+        // console.log(treeNode);
+        this.saveOtherForm.classifyId = treeNode.SandboxClassifyId
+        this.saveOtherClassifys=this.getParentClassifyIds(treeNode)
+        this.selectClassifyShow = false
+      },
+      getParentClassifyIds(treeNode){
+        let parentNode = treeNode.getParentNode()
+        if(parentNode){
+          return this.getParentClassifyIds(parentNode)+','+treeNode.SandboxClassifyId
+        }else{
+          return treeNode.SandboxClassifyId+''
+        }
+      },
+      //==============================画布
+      // 初始化画布
+      init() {
+        const graph = new myGraph('sand-chart-body',null,'','view');
+        console.log(graph,'graph');
+        this.graph = graph;
+        graph.on('node:mouseenter', ({ node, e }) => {
+          console.log(node);
+          let data = node.data
+          this.linkNode = node
+          if(data && data.linkData && data.linkData.length>0){
+            this.popoverFlod = data.linkFold
+            this.popoverVisible=false
+            clearTimeout(this.popoverTimeout)
+            this.popoverTimeout=null
+            let currentLinks = data.linkData
+            //指标id
+            let edbInfoIdList = data.linkData.filter(it => it.Type==1).map(it => it.Id)
+            // 图库id
+            let chartInfoIdList = data.linkData.filter(it => it.Type==2).map(it => it.Id)
+            // 报告id
+            let reportIdList = data.linkData.filter(it => it.Type==3).map(it => it.Id)
+            sandInterface.sandboxLinkCheck({EdbInfoIdList:edbInfoIdList,ChartInfoIdList:chartInfoIdList,ReportIdList:reportIdList}).then(res=>{
+              if(res.Ret == 200){
+                let EdbInfoIdList = res.Data.EdbInfoIdList || []
+                let ChartInfoIdList = res.Data.ChartInfoIdList || []
+                let ReportIdList = res.Data.ReportIdList || []
+                this.checkedLinkList = currentLinks.filter(link =>{
+                  return EdbInfoIdList.includes(link.Id) || ChartInfoIdList.includes(link.Id) || ReportIdList.includes(link.Id)
+                })
+                let clinetPositon=graph.localToClient(node.position())
+                let size=node.size()
+                console.log(clinetPositon,'clinetPositon',node.position());
+                // const dom = $('#link-reference')[0];
+                // console.log(this.popoverTriggerDom,'domdomdom');
+                console.log(clinetPositon.x+size.width/2,clinetPositon.y);
+                this.popoverTriggerDom.style.left = clinetPositon.x+size.width/2 + 'px';
+                this.popoverTriggerDom.style.top = clinetPositon.y + 'px';
+                this.popoverVisible=true
+              }
+            })
+          }
+        })
+      
+        graph.on('node:mouseleave', ({ node, e }) => {
+          if(!this.popoverTimeout){
+            this.popoverTimeout= setTimeout(()=>{
+              this.popoverVisible=false
+              this.popoverTriggerDom.style.left = '-99999px';
+              this.popoverTriggerDom.style.top = '-99999px';
+              this.popoverTimeout=null
+            },500)
+          }
+        })
+		  },
+      foldLink(){
+        this.popoverFlod=!this.popoverFlod 
+        if(this.linkNode){
+          this.linkNode.data.linkFold = this.popoverFlod
+        }
+        this.popoverVisible=false
+        this.$nextTick(()=>{
+          this.popoverVisible=true
+        })
+      },
+      navigateTo(item){
+        console.log(item,'item');
+        if(item.Type == 1){
+          if(item.databaseType==0){
+            // 普通指标
+            const { href } = this.$router.resolve({ path: '/database',query:item.detailParams});
+            window.open(href, '_blank');
+          }else{
+            // 预测指标
+            const { href } = this.$router.resolve({ path: '/predictEdb',query:item.detailParams});
+            window.open(href, '_blank');
+          }
+        }else if(item.Type == 2){
+          // 跳转到图库详情
+          const { href } = this.$router.resolve({ path: '/chartsetting',query:item.detailParams});
+          window.open(href, '_blank');
+        }else if(item.Type == 3){
+          // 跳转到研报
+          const { href } = this.$router.resolve({ path: '/reportdtl',query:item.detailParams});
+          window.open(href, '_blank');
+        }
+      },
+      clearPopoverTimeout(){
+        clearTimeout(this.popoverTimeout)
+        this.popoverTimeout=null 
+      },
+      closePopover(){
+        this.popoverVisible=false
+      },
+      /* 向左收起 展开 */
+      slideHandle() {
+        this.isSlideLeft = !this.isSlideLeft;
+      },
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+#sandbox-index-container{
+  height: calc(100vh - 120px);
+  min-height: 600px;
+  display: flex;
+  align-items: flex-start;
+  flex-wrap: nowrap;
+  .sandbox-content-tree-box{
+    background-color: white;
+    min-width: 20vw;
+    width: 20vw;
+    height: 100%;
+    border: solid 1px #DCDFE6;
+    border-radius: 4px;
+    box-sizing: border-box;
+    margin-right: 16px;
+    position: relative;
+    .sandbox-content-tree-header{
+      box-sizing: border-box;
+      padding: 20px;
+      border-bottom: solid 1px #DCDFE6;
+      box-shadow: 0px 2px 12px 0px rgba($color: #000000, $alpha: 0.08);
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+    }
+    .sandbox-content-tree-body{
+      padding: 20px 0;
+      box-sizing: border-box;
+      height: calc(100% - 80px);
+      .sandbox-content-tree{
+        height: calc(100% - 60px);
+        padding: 0 20px;
+        overflow: auto;
+        scroll-behavior: smooth;
+        .add-classify{
+          margin: 30px 0 50px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          img{
+            width: 12px; 
+            height: 12px; 
+            margin-right: 6px;
+            cursor: pointer;
+          }
+          span{
+            font-size: 14px;
+            color: #0052D9;
+            cursor: pointer;
+          }
+        }
+      }
+    }
+  }
+  .sandbox-pictures-box{
+    flex-grow: 1;
+    height: 100%;
+    .pictures-count{
+      font-size: 14px;
+      color: #333333; 
+      margin-bottom: 14px;
+    }
+    .pictures-box{
+      display: flex;
+      flex-wrap: wrap;
+      max-height: calc(100% - 34px);
+      overflow: hidden;
+      overflow-y: auto;
+      .pictures-item{
+        background-color: white;
+        border: 1px solid #DCDFE6;
+        padding: 0 10px 10px;
+        .pictures-item-header{
+          padding: 10px 0;
+          border-bottom: 1px solid #DCDFE6;
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          .text_oneLine{
+            font-size: 16px;
+            color: #333333;
+            font-weight: 500;
+            
+          } 
+        }
+        .picture-img{
+          width: 100%;
+          height: 230px;
+          object-fit: fill !important;
+          cursor: pointer;
+          padding: 10px 0;
+        }
+        .item-bottom{
+          display: flex;
+          align-items: center;
+          justify-content: space-between;
+          span{
+            font-size: 14px;
+            color: #333333;
+          }
+          .item-bottom-buttons{
+            width: 75px;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            span{
+              color: #0052D9;
+              cursor: pointer;
+            }
+          }
+        }
+      }
+    }
+  }
+  .sandbox-chart-box{
+    background-color: white;
+    // flex-grow: 1;
+    height: 100%;
+    border: 1px solid #DCDFE6;
+    border-radius: 4px;
+    overflow: hidden;
+    .sandbox-chart-head{
+      padding: 20px;
+      border-bottom: 1px solid #DCDFE6;
+      box-shadow: 0px 2px 12px 0px rgba($color: #000000, $alpha: 0.08);
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      flex-wrap: nowrap;
+      white-space: nowrap;
+      .sandbox-chartHead-author{
+        font-size: 16px;
+        color: #666666;
+      }
+      .sandbox-chartHead-title{
+        font-size: 16px;
+        color: #333333;
+        padding: 0 12px;
+      }
+      .sandbox-chartHead-options{
+        display: flex;
+        align-items: center;
+        margin-right: -20px;
+        .chartHead-options-button{
+          margin-right: 20px;
+          display: flex;
+          align-items: center;
+          flex-wrap: nowrap;
+          cursor: pointer;
+          img{
+            height: 16px;
+            margin-right: 3px;
+          }
+          span{
+            color: #0052D9;
+          }
+        }
+      }
+    }
+  }
+
+  .slide-icon {
+    padding: 20px 0;
+    /* display: block; */
+    box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.3);
+    border-radius: 5px;
+    cursor: pointer;
+    position: absolute;
+    top: 50%;
+    transform: translateY(-50%);
+    z-index: 99;
+    &:hover {
+      background-color: rgba(0, 0, 0, 0.05);
+    }
+    &.slide-left {
+      right: 0;
+    }
+    &.slide-right {
+      left: 0;
+    }
+  }
+  @media screen and (max-width:1680px) {
+    .sandbox-content-tree-box{
+      min-width: 330px;
+      width: 330px;
+    }
+
+  }
+  .custom-button-zone{
+    // display: flex;
+    flex-wrap: nowrap;
+    align-items: center;
+    justify-content: flex-start;
+    position: relative;
+    display: none;
+    right: 12px;
+    height: 100%;
+    img{
+      cursor: pointer;
+      height: 16px;
+      margin-right: 8px;
+    }
+  }
+}
+#link-popover{
+  display: flex;
+  justify-content: space-between;
+  transition: all 0.3s ease;
+  overflow: hidden;
+  .link-box{
+    .link-item{
+      &:hover{
+        text-decoration: underline;
+        color: #0052D9;
+        cursor: pointer;
+      }
+    }
+  }
+  .link-fold{
+    transition: all 0.3s ease;
+    height: 16px;
+    width: 16px;
+    cursor: pointer;
+  }
+}
+</style>
+<style lang="scss">
+.vue-giant-tree{
+  li{
+    ul{
+      padding: 0 0 0 10px!important;
+    }
+    .button{
+      z-index: 1;
+      height: 30px;
+      width: 20px;
+      &::before{
+        border:none!important;
+        top: 50%!important;
+        left: 50%!important;
+        transform: translate(-50%,-50%)!important;
+        height: 16px!important;
+        width: 16px!important;
+      }
+    }
+    .button.noline_close{
+      &::before{
+        content: url('../../assets/img/set_m/slide_black.png')!important;
+      }
+    }
+    .button.noline_open{
+      &::before{
+        content: url('../../assets/img/set_m/down_black.png')!important;
+      }
+    }
+    a{
+      width: calc(100% - 22px);
+      height: 30px!important;
+      line-height: 30px!important;
+      .node_name{
+        width: calc(100% - 6px);
+        color: #333333!important;
+        border-radius: 0!important;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+      }
+    }
+    .curSelectedNode{
+      position: relative;
+      z-index: 0;
+      display: inline-flex;
+      flex-wrap: nowrap;
+      align-items: center;
+      .node_name{
+        flex: 1;
+        color: unset;
+        background-color: transparent;
+        &::after{
+          content: '';
+          position: absolute;
+          top: 0;
+          left: -22px;
+          height: 30px;
+          width: calc(100% + 22px);
+          background-color: #ECF2FE;
+          z-index: -1;
+        }
+      }
+      .custom-button-zone{
+        display: flex!important;
+      }
+    }
+  }
+
+}
+.ztree.zTreeDragUL{
+  width: 300px;
+	z-index: 10000!important;
+}
+.tmpzTreeMove_arrow{
+  position: absolute;
+	z-index: 10000!important;
+  &::after{
+    content: url('../../assets/img/sand_new/tools/arrow-end.png');
+  }
+}
+.el-cascader{
+  .el-input{
+    width: 317px;
+  }
+}
+.classify-popper{
+  height: 400px;
+  overflow: auto;
+}
+.classify-cascader-popper{
+  display: none;
+}
+.sandbox-body{
+  height: calc(100% - 62px);
+  display: flex;
+  position: relative;
+  #link-reference{
+    position: fixed;
+    z-index: -1;
+    top: -99999px;
+    left: -99999px;
+    background-color: transparent;
+  }
+  .minimap{
+    position:absolute;
+    right:6px;
+    bottom:6px;
+    box-sizing: border-box;
+  }
+  #sand-chart-body{
+    flex: 1;
+  }
+  .x6-graph-scroller {
+    flex: 1;
+  }
+
+  .x6-port-body {
+    display: none;
+  }
+
+  /* reseize 框样式 */
+  .x6-widget-transform {
+    .x6-widget-transform-resize {
+      border-radius: 0;
+    }
+  }
+  .x6-widget-minimap-viewport{
+    border-color: red;
+    .x6-widget-minimap-viewport-zoom{
+      border-color: red;
+    }
+  }
+  .x6-widget-minimap{
+    width: auto !important;
+    height: auto !important;
+  }
+  .left-topic-image,.right-topic-image {
+    display: none;
+    pointer-events:none;
+  }
+}
+</style>

+ 2507 - 0
src/views/sandbox_manage/sandFlowNew/index.vue

@@ -0,0 +1,2507 @@
+<template>
+  <div id="sand-edit-container" class="sand-edit-container">
+    <span class="slide-icon slide-right" @click="slideHandle" v-show="isSlideLeft">
+      <i class="el-icon-d-arrow-right"></i>
+    </span>
+    <div class="sand-toolbar" v-show="!isSlideLeft">
+      <span class="slide-icon slide-left" @click="slideHandle">
+        <i class="el-icon-d-arrow-left"></i>
+      </span>
+      <el-tabs v-model="activeToolTabName" stretch class="sand-toolbar-tabs">
+        <el-tab-pane label="元素库" name="元素库" id="element">
+          <div class="sand-elements-tab">
+            <div class="sand-elements sand-elements-line">
+              <span>线条</span>
+              <div class="elements-row" >
+                <img src="~@/assets/img/sand_new/no-arrow-straight.png" :draggable="true" @dragstart="edgeDragStart('noArrowStraight',$event)" />
+                <img src="~@/assets/img/sand_new/single-arrow-straight.png" :draggable="true" @dragstart="edgeDragStart('singleArrowStraight',$event)" />
+                <img src="~@/assets/img/sand_new/double-arrow-straight.png" :draggable="true" @dragstart="edgeDragStart('doubleArrowStraight',$event)"/>
+                <img src="~@/assets/img/sand_new/no-arrow.png" :draggable="true" @dragstart="edgeDragStart('noArrowBend',$event)"/>
+                <img src="~@/assets/img/sand_new/single-arrow.png" :draggable="true" @dragstart="edgeDragStart('singleArrowBend',$event)"/>
+                <img src="~@/assets/img/sand_new/double-arrow.png" :draggable="true" @dragstart="edgeDragStart('doubleArrowBend',$event)"/>
+                <img src="~@/assets/img/sand_new/no-arrow-round.png" :draggable="true" @dragstart="edgeDragStart('noArrowRoundBend',$event)"/>
+                <img src="~@/assets/img/sand_new/single-arrow-round.png" :draggable="true" @dragstart="edgeDragStart('singleArrowRoundBend',$event)"/>
+                <img src="~@/assets/img/sand_new/double-arrow-round.png" :draggable="true" @dragstart="edgeDragStart('doubleArrowRoundBend',$event)"/>
+              </div>
+            </div>
+            <div class="sand-elements sand-elements-shape">
+              <span>基本形状</span>
+              <div class="elements-row">
+                <div class="elements-shape-item" v-for="shape in myNodes" :key="shape.key">
+                  <div 
+                    :style="shape.styles" 
+                    @mousedown="dragStart(shape,$event)">
+                    {{shape.label}}
+                  </div>
+                </div>
+              </div>
+            </div>
+            <div class="sand-elements sand-elements-mind">
+              <span>思维导图</span>
+              <div class="elements-row-mind">
+                <img src="~@/assets/img/sand_new/mindmap-right.png" :draggable="true" @dragstart="edgeDragStart('singleMindmap',$event)"/>
+                <img src="~@/assets/img/sand_new/mindmap-double.png" :draggable="true" @dragstart="edgeDragStart('doubleMindmap',$event)"/>
+              </div>
+            </div>
+          </div>
+
+        </el-tab-pane>
+        <el-tab-pane label="风格" name="风格" id="style">
+          <div class="sand-style-tab">
+            <div class="sand-style-tab-item" :class="styleActive==1?'active':''" @click="changeStyle(1)" :draggable="false">
+              <img src="~@/assets/img/sand_new/style-blue-light.png" />
+            </div>
+            <div class="sand-style-tab-item" :class="styleActive==2?'active':''" @click="changeStyle(2)" :draggable="false">
+              <img src="~@/assets/img/sand_new/style-blue.png" />
+            </div>
+            <div class="sand-style-tab-item" :class="styleActive==3?'active':''" @click="changeStyle(3)" :draggable="false">
+              <img src="~@/assets/img/sand_new/style-black.png" />
+            </div>
+            <div class="sand-style-tab-item" :class="styleActive==4?'active':''" @click="changeStyle(4)" :draggable="false">
+              <img src="~@/assets/img/sand_new/style-red.png" />
+            </div>
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+    </div>
+    <div class="sand-main">
+      <div class="sand-main-top">
+        <div class="sand-mainTop-form">
+          <el-input
+            v-model="sandSaveParams.Name"
+            style="width: 240px; margin-right: 20px"
+            placeholder="请输入逻辑图名称">
+            <i slot="prefix" class="el-input__icon el-icon-search"></i>
+          </el-input>
+          <el-popover
+            placement="bottom"
+            width="400"
+            popper-class="classify-popper"
+            trigger="click"
+            v-model="selectClassifyShow">
+              <tree :nodes="treeData" :setting="selectSetting" @onCreated="getSelectZTree" @onClick="selectClassify" />
+              <el-cascader 
+                slot="reference"
+                :options="treeData"
+                :props="{children: 'Children',
+                  label: 'SandboxClassifyName',
+                    value: 'SandboxClassifyId',emitPath:false,checkStrictly:true}"
+                v-model="sandSaveParams.SandboxClassifyId" 
+                popper-class="classify-cascader-popper"
+                placeholder="请选择分类">
+              </el-cascader>
+          </el-popover>
+        </div>
+        <div class="sand-mainTop-option">
+          <!-- <div class="sand-option-linkShow">
+            <img src="~@/assets/img/sand_new/eye-show-black.png" />
+            <span>链接展示</span>
+          </div> -->
+          <!-- <el-button size="large" type="primary" @click="backList" style="margin-right: 20px;min-width: 120px;"
+          v-if="$route.query.SandboxId">返回</el-button> -->
+          <el-button size="large" type="primary" plain @click="copySandHandle" style="margin-right: 20px;min-width: 120px;"
+          v-permission="permissionBtn.sandboxPermission.sandbox_addMy">复制图片</el-button>
+          <el-button type="primary" size="large" @click="saveChart(null)" style="min-width: 120px;" v-permission="permissionBtn.sandboxPermission.sandbox_saveView">保存</el-button>
+        </div>
+      </div>
+      <!-- <div class="sand-main-body"> -->
+        <div class="sand-mainBody-chart" id="sand-mainBody-chart">
+          <div class="sand-mainBody-tool" id="sand-mainBody-tool">
+            <el-tooltip content="撤销(Ctrl+Z)" placement="top" :open-delay="250">
+              <img :src="canUndo?require('@/assets/img/sand_new/tools/undo.png'):require('@/assets/img/sand_new/tools/undo-disabled.png')" 
+              class="sand-tool-item"  @click="toolClickOptions('undo',!canUndo)" :class="canUndo?'':'tool-disabled'"/>
+            </el-tooltip>
+            <el-tooltip content="恢复(Ctrl+Y)" placement="top" :open-delay="250">
+              <img :src="canRedo?require('@/assets/img/sand_new/tools/redo.png'):require('@/assets/img/sand_new/tools/redo-disabled.png')" 
+              class="sand-tool-item"  @click="toolClickOptions('redo',!canRedo)" :class="canRedo?'':'tool-disabled'"/>
+            </el-tooltip>
+            <div class="sand-tool-item">
+                <el-dropdown trigger="click" @command="(e)=>toolClickOptions('changeFamily',nodeTextDisable,e)"
+                  placement="bottom">
+                  <div :class="nodeTextDisable?'tool-disabled':''" class="dropdown-box">
+                    <el-tooltip content="字体" placement="top" :open-delay="250">
+                      <div class="dropdown-content"  >
+                        <div class="dropdown-content-text" style="width:28px">{{ styleOptions.fontF }}</div>
+                        <img src="~@/assets/img/sand_new/tools/select-icon.png" style="width: 8px;height: 5px;"/>
+                      </div>
+                    </el-tooltip>
+                    <el-tooltip content="字体" placement="top" :open-delay="250">
+                      <span v-show="nodeTextDisable" class="disabled-item" @click.stop="()=>{}"></span>
+                    </el-tooltip>
+                  </div>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item v-for="f in familyOptions" :command="f.value" :key="f.value"
+                  :class="styleOptions.fontF==f.value?'style-acitve':''">
+                      {{ f.name }}
+                  </el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+            </div>
+            <div class="sand-tool-item">
+              <el-dropdown trigger="click" @command="(e)=>toolClickOptions('changeSize',nodeTextDisable,e)"
+                placement="bottom">
+                <div :class="nodeTextDisable?'tool-disabled':''" class="dropdown-box">
+                  <el-tooltip content="字号" placement="top" :open-delay="250">
+                    <div class="dropdown-content"  >
+                      <div class="dropdown-content-text" >{{ styleOptions.fontS }}px</div>
+                      <img src="~@/assets/img/sand_new/tools/select-icon.png" style="width: 8px;height: 5px;"/>
+                    </div>
+                  </el-tooltip>
+                  <el-tooltip content="字号" placement="top" :open-delay="250">
+                    <span v-show="nodeTextDisable" class="disabled-item" @click.stop="()=>{}"></span>
+                  </el-tooltip>
+                </div>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item v-for="s in fontSizeOptions" :command="s.value" :key="s.value"
+                  :class="styleOptions.fontS==s.value?'style-acitve':''">
+                      {{ s.name }}
+                  </el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+            </div>
+            <el-tooltip content="加粗(Ctrl+B)" placement="top" :open-delay="250">
+              <div class="sand-tool-item img-box" :class="styleOptions.fontW=='bold'?'style-acitve-back':''">
+                <img :class="nodeTextDisable?'tool-disabled':''" :src="nodeTextDisable?
+                  require('@/assets/img/sand_new/tools/bold-disabled.png'):
+                  require('@/assets/img/sand_new/tools/bold.png')"  @click="toolClickOptions('changeWeight',nodeTextDisable)"/>
+              </div>
+
+            </el-tooltip>      
+            <el-tooltip content="斜体" placement="top" :open-delay="250">
+              <div class="sand-tool-item img-box" :class="styleOptions.fontStyle=='italic'?'style-acitve-back':''">
+                <img :class="nodeTextDisable?'tool-disabled':''" :src="nodeTextDisable?
+                  require('@/assets/img/sand_new/tools/italic-disabled.png'):
+                  require('@/assets/img/sand_new/tools/italic.png')"  @click="toolClickOptions('changeFontStyle',nodeTextDisable)"/>
+              </div>
+            </el-tooltip>      
+            <el-tooltip content="下划线" placement="top" :open-delay="250">
+              <div class="sand-tool-item img-box" :class="styleOptions.textDecoration=='underline'?'style-acitve-back':''">
+                <img :class="nodeTextDisable?'tool-disabled':''" :src="nodeTextDisable?
+                  require('@/assets/img/sand_new/tools/underline-disabled.png'):
+                  require('@/assets/img/sand_new/tools/underline.png')" @click="toolClickOptions('changeDecoration',nodeTextDisable)"/>
+              </div>
+            </el-tooltip>      
+            <div class="sand-tool-item sand-tool-img">
+                <img :src="nodeTextDisable?
+                    require('@/assets/img/sand_new/tools/text-color-disabled.png'):
+                    require('@/assets/img/sand_new/tools/text-color.png')" />
+              <el-tooltip content="字体颜色" placement="top" :open-delay="250">
+                <el-color-picker
+                  key="textColor"
+                  v-model="styleOptions.color"
+                  size="mini"
+                  :predefine="colorsOptions"
+                  @change="(e)=>toolClickOptions('changeColor',nodeTextDisable,e)"
+                  style="position: absolute;top: 0;left: 0;width: 16px;height: 16px;opacity: 0;"
+                  :disabled="nodeTextDisable"
+                />
+              </el-tooltip>
+            </div>
+            <div class="sand-tool-item">
+              <el-dropdown trigger="click" @command="(e)=>toolClickOptions('changeLineHeight',nodeTextDisable,e)" 
+                placement="bottom">
+                <div :class="nodeTextDisable?'tool-disabled':''" class="dropdown-box">
+                  <el-tooltip content="文本行高" placement="top" :open-delay="250">
+                    <div class="dropdown-content"  >
+                      <img :src="nodeTextDisable? 
+                        require('@/assets/img/sand_new/tools/line-height-disabled.png'):
+                        require('@/assets/img/sand_new/tools/line-height.png')" 
+                        style="vertical-align: middle;"/>
+                    </div>
+                  </el-tooltip>
+                  <el-tooltip content="文本行高" placement="top" :open-delay="250">
+                    <span v-show="nodeTextDisable" class="disabled-item" @click.stop="()=>{}"></span>
+                  </el-tooltip>
+                </div>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item v-for="s in lineHeightOptions" :command="s" :key="s"
+                  :class="styleOptions.lineHeight==s?'style-acitve':''">
+                      {{ s }}
+                  </el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+            </div>
+            <div class="sand-tool-item">
+              <el-dropdown trigger="click" @command="(e)=>toolClickOptions('changeTextAlign',nodeTextDisable,e)" 
+                placement="bottom">
+                <div :class="nodeTextDisable?'tool-disabled':''" class="dropdown-box">
+                  <el-tooltip content="文本对齐" placement="top" :open-delay="250">
+                    <div class="dropdown-content"  >
+                      <img :src="nodeTextDisable? 
+                        require('@/assets/img/sand_new/tools/text-align-disabled.png'):
+                        require('@/assets/img/sand_new/tools/text-align.png')" 
+                        style="vertical-align: middle;"/>
+                    </div>
+                  </el-tooltip>
+                  <el-tooltip content="文本对齐" placement="top" :open-delay="250">
+                    <span v-show="nodeTextDisable" class="disabled-item" @click.stop="()=>{}"></span>
+                  </el-tooltip>
+                </div>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item command="middle" :class="styleOptions.textAlign=='middle'?'style-acitve':''">
+                    居中
+                  </el-dropdown-item>
+                  <el-dropdown-item command="start" :class="styleOptions.textAlign=='start'?'style-acitve':''">
+                    居左
+                  </el-dropdown-item>
+                  <el-dropdown-item command="end" :class="styleOptions.textAlign=='end'?'style-acitve':''">
+                    居右
+                  </el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+            </div>
+            <div class="sand-tool-item sand-tool-img">
+              <img :src="toolStatus.nodeDisabled?
+                    require('@/assets/img/sand_new/tools/background-color-disabled.png'):
+                    require('@/assets/img/sand_new/tools/background-color.png')" />
+              <el-tooltip content="颜色填充" placement="top" :open-delay="250">
+                <el-color-picker
+                  key="backgroundColor"
+                  v-model="styleOptions.backgroundColor"
+                  size="mini"
+                  :predefine="colorsOptions"
+                  @change="(e)=>toolClickOptions('changeBackgroundColor',toolStatus.nodeDisabled,e)"
+                  style="position: absolute;top: 0;left: 0;width: 16px;height: 16px;opacity: 0;"
+                  :disabled="toolStatus.nodeDisabled"
+                />
+              </el-tooltip>
+            </div>
+            <div class="sand-tool-item sand-tool-img">
+              <img :src="nodeEdgeDisable?
+                    require('@/assets/img/sand_new/tools/line-color-disabled.png'):
+                    require('@/assets/img/sand_new/tools/line-color.png')" />
+              <el-tooltip content="线条颜色" placement="top" :open-delay="250">
+                <el-color-picker
+                  key="lineColor"
+                  v-model="styleOptions.lineColor"
+                  size="mini"
+                  :predefine="colorsOptions"
+                  @change="(e)=>toolClickOptions('changeLineColor',nodeEdgeDisable,e)"
+                  style="position: absolute;top: 0;left: 0;width: 16px;height: 16px;opacity: 0;"
+                  :disabled="nodeEdgeDisable"
+                />
+              </el-tooltip>
+            </div>
+            <div class="sand-tool-item">
+              <el-dropdown trigger="click" @command="(e)=>toolClickOptions('changeLineWidth',nodeEdgeDisable,e)"
+                placement="bottom">
+                <div :class="nodeEdgeDisable?'tool-disabled':''" class="dropdown-box">
+                  <el-tooltip content="线条宽度" placement="top" :open-delay="250">
+                    <div class="dropdown-content"  >
+                      <img :src="nodeEdgeDisable? 
+                        require('@/assets/img/sand_new/tools/line-width-disabled.png'):
+                        require('@/assets/img/sand_new/tools/line-width.png')" 
+                        style="vertical-align: middle;"/>
+                    </div>
+                  </el-tooltip>
+                  <el-tooltip content="线条宽度" placement="top" :open-delay="250">
+                    <span v-show="nodeEdgeDisable" class="disabled-item" @click.stop="()=>{}"></span>
+                  </el-tooltip>
+                </div>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item :command="1" :class="styleOptions.lineWidth==1?'style-acitve':''">
+                    1
+                  </el-dropdown-item>
+                  <el-dropdown-item :command="2" :class="styleOptions.lineWidth==2?'style-acitve':''">
+                    2
+                  </el-dropdown-item>
+                  <el-dropdown-item :command="3" :class="styleOptions.lineWidth==3?'style-acitve':''">
+                    3
+                  </el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+            </div>
+            <div class="sand-tool-item">
+              <el-dropdown trigger="click" @command="(e)=>toolClickOptions('changeStrokeDasharray',nodeEdgeDisable,e)"
+                placement="bottom">
+                <div :class="nodeEdgeDisable?'tool-disabled':''" class="dropdown-box">
+                  <el-tooltip content="线条样式" placement="top" :open-delay="250">
+                    <div class="dropdown-content"  >
+                      <img :src="nodeEdgeDisable? 
+                        require('@/assets/img/sand_new/tools/line-style-disabled.png'):
+                        require('@/assets/img/sand_new/tools/line-style.png')" 
+                        style="vertical-align: middle;"/>
+                    </div>
+                  </el-tooltip>
+                  <el-tooltip content="线条样式" placement="top" :open-delay="250">
+                    <span v-show="nodeEdgeDisable" class="disabled-item" @click.stop="()=>{}"></span>
+                  </el-tooltip>
+                </div>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item command="4 4" :class="styleOptions.lineStyle=='4 4'?'style-acitve':''">
+                    虚线
+                  </el-dropdown-item>
+                  <el-dropdown-item :command="null" :class="styleOptions.lineStyle==null?'style-acitve':''">
+                    实线
+                  </el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+            </div>
+            <div class="sand-tool-item">
+              <el-dropdown trigger="click" @command="(e)=>toolClickOptions('changeRouter',toolStatus.edgeDisabled,e)"
+                placement="bottom">
+                <div :class="toolStatus.edgeDisabled?'tool-disabled':''" class="dropdown-box">
+                  <el-tooltip content="连线类型" placement="top" :open-delay="250">
+                    <div class="dropdown-content"  >
+                      <img :src="toolStatus.edgeDisabled? 
+                        require('@/assets/img/sand_new/tools/line-type-disabled.png'):
+                        require('@/assets/img/sand_new/tools/line-type.png')" 
+                        style="vertical-align: middle;"/>
+                    </div>
+                  </el-tooltip>
+                  <el-tooltip content="连线类型" placement="top" :open-delay="250">
+                    <span v-show="toolStatus.edgeDisabled" class="disabled-item" @click.stop="()=>{}"></span>
+                  </el-tooltip>
+                </div>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item :command="1" :class="styleOptions.connectStyle==1?'style-acitve-back':''">
+                    <img src="~@/assets/img/sand_new/tools/line-style-straight.png" style="width: 17px;height: 16px;"/>
+                  </el-dropdown-item>
+                  <el-dropdown-item :command="2" :class="styleOptions.connectStyle==2?'style-acitve-back':''">
+                    <img src="~@/assets/img/sand_new/tools/line-style-bend.png" style="width: 17px;height: 16px;"/>
+                  </el-dropdown-item>
+                  <el-dropdown-item :command="3" :class="styleOptions.connectStyle==3?'style-acitve-back':''">
+                    <img src="~@/assets/img/sand_new/tools/line-style-bend-round.png" style="width: 17px;height: 16px;"/>
+                  </el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+            </div>
+            <div class="sand-tool-item">
+              <el-dropdown trigger="click" @command="(e)=>toolClickOptions('changeSourceMarker',toolStatus.edgeDisabled,e)"
+                placement="bottom">
+                <div :class="toolStatus.edgeDisabled?'tool-disabled':''" class="dropdown-box">
+                  <el-tooltip content="开始箭头" placement="top" :open-delay="250">
+                    <div class="dropdown-content"  >
+                      <img :src="toolStatus.edgeDisabled? 
+                        require('@/assets/img/sand_new/tools/arrow-start-disabled.png'):
+                        require('@/assets/img/sand_new/tools/arrow-start.png')" 
+                        style="vertical-align: middle;"/>
+                    </div>
+                  </el-tooltip>
+                  <el-tooltip content="开始箭头" placement="top" :open-delay="250">
+                    <span v-show="toolStatus.edgeDisabled" class="disabled-item" @click.stop="()=>{}"></span>
+                  </el-tooltip>
+                </div>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item command="classic" :class="styleOptions.startArrow=='classic'?'style-acitve':''">
+                    有
+                  </el-dropdown-item>
+                  <el-dropdown-item :command="{}" :class="typeof(styleOptions.startArrow)=='string' || styleOptions.startArrow.name?'':'style-acitve'">
+                    无
+                  </el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+            </div>
+            <div class="sand-tool-item">
+              <el-dropdown trigger="click" @command="(e)=>toolClickOptions('changeTargetMarker',toolStatus.edgeDisabled,e)"
+                placement="bottom">
+                <div :class="toolStatus.edgeDisabled?'tool-disabled':''" class="dropdown-box">
+                  <el-tooltip content="结束箭头" placement="top" :open-delay="250">
+                    <div class="dropdown-content"  >
+                      <img :src="toolStatus.edgeDisabled? 
+                        require('@/assets/img/sand_new/tools/arrow-end-disabled.png'):
+                        require('@/assets/img/sand_new/tools/arrow-end.png')" 
+                        style="vertical-align: middle;"/>
+                    </div>
+                  </el-tooltip>
+                  <el-tooltip content="结束箭头" placement="top" :open-delay="250">
+                    <span v-show="toolStatus.edgeDisabled" class="disabled-item" @click.stop="()=>{}"></span>
+                  </el-tooltip>
+                </div>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item command="classic" :class="styleOptions.endArrow=='classic'?'style-acitve':''">
+                    有
+                  </el-dropdown-item>
+                  <el-dropdown-item :command="{}" :class="typeof(styleOptions.endArrow)=='string' || styleOptions.endArrow.name?'':'style-acitve'">
+                    无
+                  </el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+            </div>
+            
+          </div>
+          <div id="sand-chart-container" ></div>
+
+          <!-- 缩略图 -->
+          <div id="minimap" class="minimap"></div>
+
+          <div class="contextMenu-wrapper" id="contextMenu-wrapper" @mouseleave="hideContextMenu">
+            <dropdown-menu size="medium">
+              <el-dropdown-item v-for="menu in contextMenuOption.filter(it => it.show)" :key="menu.key" @click.native="handleContext(menu.key)">
+                <i :class="menu.icon" v-if="menu.icon" /> 
+                {{menu.label}}
+              </el-dropdown-item>
+            </dropdown-menu>
+				  </div>
+          <el-popover
+            placement="top"
+            trigger="manual"
+            v-model="popoverVisible">
+            <div id="link-popover" :style="{height:popoverFlod?'20px':'unset'}">
+              <div class="link-box">
+                <div v-for="item in checkedLinkList" :key="item.RId" class="link-item" @click="navigateTo(item)">
+                  {{ item.Name }}
+                </div>
+              </div>
+              <img src="~@/assets/img/sand_new/arrow_black_down.png" class="link-fold" 
+              :style="{transform:popoverFlod?'':'rotate(180deg)'}" v-show="checkedLinkList.length>1"
+              @click="foldLink"/>
+            </div>
+            <div id="link-reference" slot="reference"></div>
+          </el-popover>
+        </div>
+      <!-- </div> -->
+    </div>
+    <!-- 添加链接 -->
+    <el-dialog :modal-append-to-body='false' title="添加链接" :visible.sync="addLinkShow" 
+    :close-on-click-modal="false" width="872px" top="5vh">
+      <div class="add-link-box">
+        <div class="link-box-option">
+          <el-select v-model="addLinkSearchParams.linkType" placeholder="链接类型" style="width: 240px;" @change="changeLinkType">
+            <el-option :label="item.label" :value="item.value" v-for="item in linkTypeList" :key="item.value"></el-option>
+          </el-select>
+          <el-select v-if="addLinkSearchParams.linkType==1"
+            v-model="search_dataBaseId"
+            v-loadMore="dataBaseSearchLoad"
+            ref="searchRef"
+            :filterable="!search_dataBaseId"
+            remote
+            clearable
+            placeholder="指标ID/指标名称"
+            style="width: 240px"
+            :remote-method="dataBaseSearch"
+            @click.native="dataBaseInputFocus"
+          >
+            <i slot="prefix" class="el-input__icon el-icon-search"></i>
+            <el-option
+              v-for="item in dataBaseOptions"
+              :key="item.EdbInfoId"
+              :label="item.EdbName"
+              :value="item.EdbInfoId"
+            >
+            </el-option>
+          </el-select>
+          <el-select v-else-if="addLinkSearchParams.linkType==2"
+            v-model="search_dataBaseId"
+            v-loadMore="dataBaseSearchLoad"
+            ref="searchRef"
+            :filterable="!search_dataBaseId"
+            remote
+            clearable
+            placeholder="图表名称"
+            style="width: 240px"
+            :remote-method="dataBaseSearch"
+            @click.native="dataBaseInputFocus"
+          >
+            <i slot="prefix" class="el-input__icon el-icon-search"></i>
+            <el-option
+              v-for="item in dataBaseOptions"
+              :key="item.ChartInfoId"
+              :label="item.ChartName"
+              :value="item.ChartInfoId"
+            >
+            </el-option>
+          </el-select>
+          <el-input v-else v-model="reportKeyWord" @input="searchReport"
+          placeholder="标题 / 创建人" style="width: 240px;" clearable >
+            <i slot="prefix" class="el-input__icon el-icon-search"></i>
+          </el-input>
+        </div>
+        <div class="link-box-content">
+          <!-- 指标 -->
+          <div class="link-content-dataIndex" v-if="addLinkSearchParams.linkType==1 && databaseTableData && databaseTableData.length>0">
+            <el-table :data="databaseTableData" border style="box-shadow: rgba(155, 170, 219, 0.2) 0px 3px 6px;">
+              <el-table-column label="指标Id" align="center">
+                <template slot-scope="scope">{{ scope.row.EdbCode }}</template>
+              </el-table-column>
+              <el-table-column label="指标名称" align="center" width="200">
+                <template slot-scope="scope">{{ scope.row.EdbName }}</template>
+              </el-table-column>
+              <el-table-column label="频度" align="center" width="50">
+                <template slot-scope="scope">{{ scope.row.Frequency }}</template>
+              </el-table-column>
+              <el-table-column label="单位" align="center">
+                <template slot-scope="scope">{{ scope.row.Unit }}</template>
+              </el-table-column>
+              <el-table-column label="起始时间" align="center" width="100">
+                <template slot-scope="scope">{{ scope.row.StartDate }}</template>
+              </el-table-column>
+              <el-table-column label="更新时间" align="center" width="160">
+                <template slot-scope="scope">{{ scope.row.ModifyTime }}</template>
+              </el-table-column>
+              <el-table-column label="来源" align="center">
+                <template slot-scope="scope">{{ scope.row.SourceName }}</template>
+              </el-table-column>
+              <el-table-column label="操作" align="center" width="50">
+                <template slot-scope="scope">
+                  <span class="delete-button">删除</span>
+                </template>
+              </el-table-column>
+            </el-table>
+            <ul 
+              class="value-ul" 
+              ref="valueUl" 
+              @scroll="databaseScrollHandle" 
+              v-show="databaseList.length">
+              <li
+                class="value-item"
+                v-for="item in databaseList"
+                :key="item.EdbDataId"
+              >
+                <span class="value-label">
+                  <span style="position: relative;">
+                    <i class="new-tag" v-if="databaseTableData[0].LatestDate===item.DataTime"></i>
+                    {{item.DataTime}}
+                  </span>
+                </span>
+                <span :class="['value-label',{'predict-act': databaseTableData[0].DataInsertConfig.Date===item.DataTime}]" style="min-width:200px;text-align:center;">
+                  <span :class="['value-style',{'predict-act': databaseTableData[0].DataInsertConfig.Date===item.DataTime}]">{{item.Value}}</span>
+                </span>
+              </li>
+              <li class="nodata value-item" v-if="!databaseList.length">暂无数据</li>
+            </ul>
+          </div>
+          <div class="link-content-chartIndex" v-else-if="addLinkSearchParams.linkType==2 && this.chartInfo && this.chartInfo.ChartInfoId">
+            <div class="chart-name">{{ this.chartInfo.ChartName }}</div>
+            <Chart :options="options" ref="chartRef" />
+          </div>
+          <div class="link-content-dataIndex" v-else-if="addLinkSearchParams.linkType==3 && this.reportList.length>0">
+            <el-table :data="this.reportList" border style="margin-bottom: 10px;" ref="reportTable"
+            @select="reportSelect" @select-all="reportSelect"> 
+              <el-table-column type="selection" width="40" align="center"></el-table-column>
+              <el-table-column label="报告标题" align="center" show-overflow-tooltip>
+                <template slot-scope="scope">
+                  <span >{{ scope.row.Title }}</span>
+                  <span  v-if="scope.row.MsgSendTime">
+                    ({{ scope.row.MsgSendTime.substring(5, 7)}}{{ scope.row.MsgSendTime.substring(8, 10) }})
+                  </span>
+                  <span v-else-if="scope.row.PublishTime">
+                    ({{ scope.row.PublishTime.substring(5, 7)}}{{ scope.row.PublishTime.substring(8, 10) }})
+                  </span>
+                  <span v-else-if="scope.row.CreateTime">
+                    ({{ scope.row.CreateTime.substring(5, 7)}}{{ scope.row.CreateTime.substring(8, 10) }})
+                  </span>
+                </template>
+              </el-table-column >
+              <el-table-column label="发布时间" align="center">
+                <template slot-scope="scope">
+                  <span>{{scope.row.PrePublishTime?scope.row.PrePublishTime:scope.row.PublishTime}}</span>
+                </template>
+              </el-table-column>
+            </el-table>
+            <m-page :page_no="reportParams.CurrentIndex" :pageSize="5" :total="reportTotal" @handleCurrentChange="pageChange"/>
+          </div>
+          <tableNoData text="暂无数据" v-else/>
+        </div>
+        <div class="link-box-tags">
+          <div class="link-box-tag" v-for="(item,index) in checkedLinkList" :key="item.RId">
+            <span @dblclick.stop="editLinkName(item)" v-if="!item.editing" @click="linkClick(item)">{{ item.Name }}</span>
+            <el-input v-else @blur="editLinkNameFinish(item)" 
+              v-model.trim="editingLabel" class="label-edit-input" ref="labelEditInput"/>
+            <img src="~@/assets/img/sand_new/delete_outline_1.png" @click="linkDelete(item,index)">
+          </div>
+        </div>
+        <div class="link-box-buttons">
+          <el-button type="info" style="width:120px;color:#333333;background-color:#F4F8FE" @click="addLinkShow=false">取消</el-button>
+          <el-button type="primary" style="width:120px;margin-left: 30px;" @click="saveLink">确定</el-button>
+        </div>
+      </div>
+		</el-dialog>
+  </div>
+</template>
+
+<script>
+// 路由的name 属性在main.js中更改
+// import '@antv/x6-vue-shape'
+import { myGraph } from '../common/gragh';
+import { myNodes,myNodeOption } from '../common/node';
+import { myEdgeOption } from '../common/edge';
+import { Addon } from '@antv/x6'
+import mindmap from "../common/mindmap"
+import {styleSettings,familyOptions,fontSizeOptions,colorsOptions,lineHeightOptions} from "../common/toolConfig"
+import { ElDropdownMenu as DropdownMenu } from 'element-ui';
+import { contextMenuOption } from '../common/options';
+import { contextEvent } from '../common/events';
+import { mapState } from 'vuex'
+import { dataBaseInterface,sandInterface,reportlist} from '@/api/api.js';
+import * as sheetInterface from "@/api/modules/sheetApi.js";
+import tree from "vue-giant-tree";
+import { chartSetMixin } from '../../dataEntry_manage/mixins/chartPublic'
+import Chart from '../../dataEntry_manage/components/chart.vue'
+import mPage from "@/components/mPage.vue";
+import { svgToBase64 } from '@/utils/svgToblob'
+
+  export default {
+    name:"sandFlowIndex",
+    components:{
+      DropdownMenu,tree,Chart,mPage
+    },
+    data() {
+      return {
+        contextMenuOption,
+        graph: null,
+        dnd:null,
+        initData: {},
+        activeToolTabName:"元素库",
+        addType:"",
+        styleActive:1,
+        canUndo:false,
+        canRedo:false,
+        mindmapDataUse:[],
+        mindmapAssistData:{
+          mindmapDataRecoverUse:[],//用于恢复撤销和重做时被删除的思维导图数据
+          // mindmapDataRecoverPtr:-1, //当前索引
+        },
+        sandSaveParams:{
+          Name:'',
+          SandboxClassifyId:'',
+          SandboxId:+this.$route.query.SandboxId || 0,
+        },
+        selectClassifyShow:false,
+        zTreeObj:{},
+        selectSetting:{
+          data:{
+            key:{
+              name:"SandboxClassifyName",
+              children:"Children"
+            }
+          },
+          view:{
+            showLine:false,
+            showIcon:false,
+            selectedMulti:false
+          }
+        },
+        treeData:[],
+        lockLoding: null,
+        loopTimer:null,
+        // 添加链接弹窗
+        addLinkShow:false,
+        addLinkSearchParams:{
+          linkType:1
+        },
+        linkTypeList:[
+          {value:1,label:"ETA指标/预测指标"},
+          {value:2,label:"ETA图库"},
+          {value:3,label:"ETA研报"}
+        ],
+        //添加链接:指标
+        search_dataBaseId:'',
+        dataBaseParams:{
+          pages:1,
+          searchText:'',
+          search_have_more:false
+        },
+        dataBaseOptions:[],
+
+        databaseTableData:[],
+        databaseList:[],
+        databaseHaveMore:false,
+        databasePageNo:1,
+        chartInfo:{},
+        edbData:[],
+        options:{},
+        reportKeyWord:'',
+        reportParams:{
+          CurrentIndex:1,
+          PageSize:5,
+        },
+        reportList:[],
+        selections:[],
+        checkedLinkList:[],
+        reportTotal:0,
+        editingLabel:'',
+        activeItemRId:'',
+        popoverVisible:false,
+        popoverDom:null,
+        popoverTriggerDom:null,
+        popoverTimeout:null,
+        linkNode:null,
+        popoverFlod:true,
+        isSlideLeft:false
+      }
+    },
+    mixins:[mindmap,chartSetMixin],
+    watch: {
+      initData(newval) {
+        // console.log(newval)
+        if(!this.graph){
+          this.init()
+        }
+        this.$nextTick(()=>{
+          this.graph.fromJSON(newval);
+          this.graph.zoomToFit()
+        })
+      },
+      /* 选中搜索指标 展开目录 选中指标 展示数据 */
+      search_dataBaseId(newval) {
+        if (newval) {
+          if(this.addLinkSearchParams.linkType==1){
+            let search_obj = this.dataBaseOptions.find(
+              (item) => item.EdbInfoId === newval
+            );
+            // console.log(search_obj,'search_obj');
+            if(search_obj){
+              this.checkedLinkList.push({
+                RId:this.addLinkSearchParams.linkType+'-'+search_obj.EdbInfoId,
+                Id:search_obj.EdbInfoId,
+                Name:search_obj.EdbName,
+                Type:this.addLinkSearchParams.linkType,
+                editing:false,
+                databaseType:search_obj.EdbInfoType, //0 普通指标 | 1 预测指标
+                detailParams:{
+                  code:search_obj.UniqueCode,
+                  id:search_obj.EdbInfoId,
+                  classifyId:search_obj.ClassifyId
+                }
+              })
+              this.activeItemRId=this.addLinkSearchParams.linkType+'-'+search_obj.EdbInfoId
+              this.initGetData()
+            }
+          }else{
+            let search_obj = this.dataBaseOptions.find(
+              (item) => item.ChartInfoId === newval
+            );
+            if(search_obj){
+              this.checkedLinkList.push({
+                RId:this.addLinkSearchParams.linkType+'-'+search_obj.ChartInfoId,
+                Id:search_obj.ChartInfoId,
+                Name:search_obj.ChartName,
+                Type:this.addLinkSearchParams.linkType,
+                editing:false,
+                detailParams:{
+                  code:search_obj.UniqueCode,
+                  id:search_obj.ChartInfoId
+                }
+              })
+              this.activeItemRId=this.addLinkSearchParams.linkType+'-'+search_obj.ChartInfoId
+              this.getChartDetail(search_obj.ChartInfoId)
+            }
+          }
+        }
+      },
+      edbData: {
+        handler(newval, oldval) {
+          newval.length && !this.chartInfo.WarnMsg && this.setChartOptionHandle(newval);
+        },
+        deep: true,
+    },
+	  },
+    computed:{
+      myNodes(){
+        return myNodes
+      },
+      myEdgeOption(){
+        return myEdgeOption
+      },
+      familyOptions(){
+        return familyOptions
+      },
+      fontSizeOptions(){
+        return fontSizeOptions
+      },
+      colorsOptions(){
+        return colorsOptions
+      },
+      lineHeightOptions(){
+        return lineHeightOptions
+      },
+      ...mapState({
+        selectCells: state => state.sand.selectCells,
+        styleOptions: state => state.sand.styleOptions,
+        toolStatus:state => state.sand.toolStatus,
+      }),
+      nodeTextDisable(){
+        return this.toolStatus.nodeDisabled && this.toolStatus.textDisabled
+      },
+      nodeEdgeDisable(){
+        return this.toolStatus.nodeDisabled && this.toolStatus.edgeDisabled
+      }
+    },
+    created(){
+      this.getSandboxClassify();
+      this.$route.query.SandboxId && this.getGraphData(this.$route.query.SandboxId)
+    },
+    mounted(){
+      this.init()
+      document.getElementById('sand-mainBody-chart').addEventListener("dragover",this.edgeDragover)
+      document.getElementById('sand-mainBody-chart').addEventListener("drop",this.edgeDrop)
+      this.popoverDom = $('#link-popover')[0];
+      this.popoverTriggerDom = $('#link-reference')[0];
+      
+      this.popoverDom.addEventListener('mouseenter',this.clearPopoverTimeout)
+      this.popoverDom.addEventListener('mouseleave',this.closePopover)
+      
+      // Graph.registerNode("link-popover", {
+      //   inherit: "vue-shape",
+      //   component: popover,
+      // });
+    },
+    beforeDestroy(){
+      document.getElementById('sand-mainBody-chart').removeEventListener("dragover",this.edgeDragover)
+      document.getElementById('sand-mainBody-chart').removeEventListener("drop",this.edgeDrop)
+      this.popoverDom.removeEventListener('mouseenter',this.clearPopoverTimeout)
+      this.popoverDom.removeEventListener('mouseleave',this.closePopover)
+    },
+    methods: {
+      getSandboxClassify(){
+        sandInterface.getSandboxClassifyOnly().then(res=>{
+          if (res.Ret === 200) {
+            this.treeData=res.Data.AllNodes || []
+          }
+        })
+      },
+      getSelectZTree(zTree){
+        this.selectZTreeObj=zTree
+      },
+      selectClassify(event,treeId,treeNode,clickFlag){
+        this.sandSaveParams.SandboxClassifyId = treeNode.SandboxClassifyId
+        this.selectClassifyShow = false
+      },
+      getGraphData(Id){
+        let SandboxId=+Id ? +Id : this.sandSaveParams.SandboxId
+        sandInterface.getSandboxDetail({SandboxId}).then(res=>{
+          if(res.Ret == 200 && res.Data){
+            this.sandSaveParams.SandboxId=res.Data.SandboxId
+            this.sandSaveParams.Name=res.Data.Name
+            this.sandSaveParams.SandboxClassifyId=res.Data.SandboxClassifyId
+            this.initData = JSON.parse(res.Data.Content)
+            this.mindmapDataUse = res.Data.MindmapData?JSON.parse(res.Data.MindmapData):[]
+            this.autoSave();
+          }
+        })
+      },
+      /* 编辑页 自动保存 */
+      autoSave() {
+        // return 
+        this.loopTimer = setInterval(() => {
+          if(!this.sandSaveParams.Name || !this.sandSaveParams.SandboxClassifyId) return;
+          const { Name, SandboxClassifyId } = this.sandSaveParams;
+          sandInterface.sandboxSaveV2({
+            SandboxId:this.sandSaveParams.SandboxId,
+            Name,
+            SandboxClassifyId,
+            Content: JSON.stringify(this.graph.toJSON()),
+            PicUrl:'',
+            MindmapData:this.mindmapDataUse.length>0?JSON.stringify(this.mindmapDataUse):''
+          }).then((res) => {
+            if(res.Ret !== 200) return
+          });
+        }, 10000);
+      },
+      // 初始化画布
+      init() {
+        const graph = new myGraph('sand-chart-container',this.getMindmapDataUse,this.mindmapAssistData);
+        this.graph = graph;
+        
+        this.graph.history.on('change', (args) => { 
+          // console.log(args,'change-history');
+          this.canUndo = this.graph.canUndo()
+          this.canRedo = this.graph.canRedo()
+          // console.log(this.canUndo,this.canRedo);
+        })
+        this.graph.history.on('undo', (args) => { 
+          // console.log(args,'undo-history');
+          // let ids=[]
+          let mindmapNodes=args.cmds.filter(it => it.data.props && it.data.props.shape.indexOf('mindmap')!=-1 && it.data.node)
+          if(!(mindmapNodes && mindmapNodes.length>0)) return 
+          console.log(mindmapNodes,'mindmapNodes');
+          let mindmapUndoType=mindmapNodes[0].event
+          if(mindmapUndoType=="cell:added"){
+            this.mindmapRecoverRemove(mindmapNodes)
+          }else if(mindmapUndoType=="cell:removed"){
+            this.mindmapRecoverAdd()
+          }
+          // console.log(this.mindmapDataUse);
+        })
+        this.graph.history.on('redo', (args) => { 
+          // console.log(args,'redo-history');
+          // let ids=[]
+          let mindmapNodes=args.cmds.filter(it => it.data.props && it.data.props.shape.indexOf('mindmap')!=-1 && it.data.node)
+          if(!(mindmapNodes && mindmapNodes.length>0)) return 
+          // console.log(mindmapNodes,'mindmapNodes');
+          let mindmapUndoType=mindmapNodes[0].event
+          if(mindmapUndoType=="cell:added"){
+            this.mindmapRecoverAdd()
+          }else if(mindmapUndoType=="cell:removed"){
+            this.mindmapRecoverRemove(mindmapNodes)
+          }
+          // console.log(this.mindmapDataUse,'mindmapDataUse');
+        })
+        this.graph.on('node:mouseenter', ({ node, e }) => {
+          // console.log(node);
+          let data = node.data
+          this.linkNode = node
+          let isMindmap = node.shape.indexOf('mindmap')!=-1
+          this.contextMenuOption.map(item =>{
+            if(item.key=='copy'){
+              item.show=!isMindmap
+            }
+          })
+          if(data && data.linkData && data.linkData.length>0){
+            this.popoverFlod = data.linkFold
+            this.popoverVisible=false
+            clearTimeout(this.popoverTimeout)
+            this.popoverTimeout=null
+            let currentLinks = data.linkData
+            //指标id
+            let edbInfoIdList = data.linkData.filter(it => it.Type==1).map(it => it.Id)
+            // 图库id
+            let chartInfoIdList = data.linkData.filter(it => it.Type==2).map(it => it.Id)
+            // 报告id
+            let reportIdList = data.linkData.filter(it => it.Type==3).map(it => it.Id)
+            sandInterface.sandboxLinkCheck({EdbInfoIdList:edbInfoIdList,ChartInfoIdList:chartInfoIdList,ReportIdList:reportIdList}).then(res=>{
+              if(res.Ret == 200){
+                let EdbInfoIdList = res.Data.EdbInfoIdList || []
+                let ChartInfoIdList = res.Data.ChartInfoIdList || []
+                let ReportIdList = res.Data.ReportIdList || []
+                this.checkedLinkList = currentLinks.filter(link =>{
+                  return EdbInfoIdList.includes(link.Id) || ChartInfoIdList.includes(link.Id) || ReportIdList.includes(link.Id)
+                })
+                let clinetPositon=this.graph.localToClient(node.position())
+                let size=node.size()
+                // console.log(clinetPositon.y,'clinetPositon');
+                // console.log(this.popoverTriggerDom,'domdomdom');
+                this.popoverTriggerDom.style.left = clinetPositon.x+size.width/2 + 'px';
+                this.popoverTriggerDom.style.top = clinetPositon.y + 'px';
+                this.popoverVisible=true
+                if(!(this.checkedLinkList.length>0)){
+                  if(item.key=='addLink'){
+                    item.label='添加链接'
+                  }else if(item.key=='deleteLink'){
+                    item.show=false
+                  }
+                }
+              }
+              this.contextMenuOption.map(item =>{
+                if(item.key=='addLink'){
+                  item.label='编辑链接'
+                }else if(item.key=='deleteLink'){
+                  item.show=true
+                }
+              })
+            })
+          }else{
+            this.contextMenuOption.map(item =>{
+              if(item.key=='addLink'){
+                item.label='添加链接'
+              }else if(item.key=='deleteLink'){
+                item.show=false
+              }
+            })
+            // console.log(this.contextMenuOption,'contextMenuOption');
+          }
+        })
+      
+        this.graph.on('node:mouseleave', ({ node, e }) => {
+          if(!this.popoverTimeout){
+            this.popoverTimeout= setTimeout(()=>{
+              this.popoverVisible=false
+              this.popoverTriggerDom.style.left = '-99999px';
+              this.popoverTriggerDom.style.top = '-99999px';
+              this.popoverTimeout=null
+            },500)
+          }
+
+        })
+
+        this.graph.on('node:change:position', (args) => { 
+          if(args.node.data && args.node.data.linkData && args.node.data.linkData.length>0
+          &&this.popoverVisible){
+            // console.log(args.node.data.linkData);
+            this.changePopoverPositon(args)
+
+          }
+        })
+
+        this.dnd = new Addon.Dnd({
+          target: this.graph,
+          animation: true,
+          validateNode() {
+            return true;
+          },
+        });
+        this.setGraph()
+		  },
+      getMindmapDataUse(){
+        return this.mindmapDataUse
+      },
+      dragStart(data,e) {
+        // console.log(data,e,"触发了")
+        const { key,shape } = data;
+        
+        const	node = this.graph.createNode({
+          shape,
+          ...myNodeOption(key),
+        });
+        this.dnd.start(node,e);
+      },
+      edgeDragStart(type,e){
+        this.addType = type
+      },
+      edgeDragover(e){
+        e.preventDefault()
+      },
+      edgeDrop(e){
+        if(!this.addType){
+          return 
+        }
+        // console.log(this.addType,e);
+        // console.log(this.graph);
+        let position = this.graph.clientToLocal({x:e.clientX,y:e.clientY})
+        if(this.addType.indexOf("Mindmap")!==-1){
+          //插入思维导图
+          // console.log("插入思维导图");
+          this.generateMindmapData(position,this.addType)
+          this.mindMapRender(this.mindmapDataUse.length-1)
+        }else{
+          this.graph.addEdge({
+            shape:'edge',
+            ...this.myEdgeOption(this.addType,position.x,position.y)
+          });
+        }
+      },
+      generateMindmapData(position,addType){
+        let beId=this.mindmapDataUse.length>0?
+        parseInt(this.mindmapDataUse[this.mindmapDataUse.length-1].mindmapData.id)+1+'':'1'
+        let mindmapData={
+          id: beId,
+          type: 'topic',
+          label: '中心主题',
+          width: 160,
+          height: 50,
+          direction:'double',
+          children: [
+            {
+              id: beId+'-1',
+              type: 'topic-branch',
+              label: '分支主题1',
+              width: 100,
+              height: 40,
+              direction:'left',
+              children: [
+                {
+                  id: beId+'-1-1',
+                  type: 'topic-child',
+                  label: '子主题1',
+                  width: 60,
+                  height: 30,
+                  direction:'left',
+                },
+                {
+                  id: beId+'-1-2',
+                  type: 'topic-child',
+                  label: '子主题2',
+                  width: 60,
+                  height: 30,
+                  direction:'left',
+                },
+              ],
+            },
+            {
+              id: beId+'-2',
+              type: 'topic-branch',
+              label: '分支主题2',
+              width: 100,
+              height: 40,
+              direction:'right',
+            },
+          ],
+        }
+        this.mindmapDataUse.push({mindmapData,position,addType})
+      },
+      changeStyle(activeNum){
+        this.$store.commit("sand/SET_CELL_STYLE",activeNum)
+        let styleData=styleSettings[activeNum-1]
+
+        let cells = this.graph.getCells()
+        // console.log(cells);
+
+        for (let i = 0; i < cells.length; i++) {
+          const element = cells[i];
+          // console.log(element);
+          if(element.shape.indexOf("edge") !=-1){
+            element.setAttrs({
+              line:{
+                stroke:styleData.lineColor
+              }
+            })
+          }if(element.data && element.data.key == 'text'){
+            element.setAttrs({
+              text:{
+                fill:styleData.textColor
+              }
+            })
+          }else{
+            element.setAttrs({
+              body:{
+                fill:styleData.backgroundColor,
+                stroke:styleData.borderColor,
+              },
+              text:{
+                fill:styleData.color
+              }
+            })
+          }
+        }
+        this.styleActive = activeNum
+      },
+      /* 右键事件 */
+      handleContext(key) {
+        if(key=="addLink"){
+          this.addLinkDialogOpen()
+        }else if(key=="deleteLink"){
+          this.deleteLink()
+        }else{
+          contextEvent(this.graph, key,this.mindmapDataUse,this.mindmapAssistData);
+        }
+        this.hideContextMenu();
+      },
+
+      /* 隐藏右键menu */
+      hideContextMenu() {
+        const dom = $('#contextMenu-wrapper')[0];
+        dom.style.left = '-9999px';
+        dom.style.top = '-9999px';
+      },
+      addLinkDialogOpen(){
+        const select_cell = this.graph.getSelectedCells()[0]
+        // console.log(select_cell);
+        if(select_cell){
+          this.checkedLinkList = select_cell.data ? select_cell.data.linkData ||[]:[]
+        }else{
+          this.checkedLinkList=[]
+        }
+        // console.log(this.checkedLinkList);
+        this.addLinkSearchParams.linkType=1
+        this.changeLinkType()
+        this.addLinkShow=true
+      },
+      deleteLink(){
+        const select_cell = this.graph.getSelectedCells()[0]
+        if(select_cell){
+          select_cell.data.linkData=[]
+          this.$message.success('清除链接成功')
+        }
+      },
+      saveLink(){
+        // console.log("保存链接",select_cell);
+        const select_cell = this.graph.getSelectedCells()[0]
+        if(select_cell.data){
+          select_cell.data.linkData = this.checkedLinkList
+          select_cell.data.linkFold = true
+        }else{
+          select_cell.setData({linkData:this.checkedLinkList})
+          if(!select_cell.data.linkFold){
+            select_cell.data.linkFold=true
+          }
+        }
+        this.$message.success("链接保存成功")
+        this.addLinkShow=false
+      },
+      // backList(){
+      //   // this.sandSaveParams.SandboxId this.sandSaveParams.Name
+      //   this.$router.push({path:"/sandlist",query:{SandboxName:'阿巴阿巴A1',SandboxId:142}})
+      // },
+      copySandHandle: _.debounce(function() {
+        const { cells } = this.graph.toJSON();
+        if(!cells.length) return this.$message.warning('当前画布无可复制内容');
+
+        this.lockLoding = this.$loading({
+          lock: true,
+          text: '复制图片中...',
+          target: '.right-wrapper',
+          spinner: 'el-icon-loading',
+          background: 'rgba(255, 255, 255, 0.8)'
+        });
+        this.graph.toSVG(async(dataUri) => {
+          const canvas = document.createElement("canvas");
+          const ctx = canvas.getContext("2d");
+          const img = new Image();
+          img.crossOrigin = "Anonymous";
+          img.src = svgToBase64(dataUri);
+          img.onload = ()=>{
+            canvas.width = img.width;
+            canvas.height = img.height;
+            // console.log('width',img.width)
+            // console.log('height',img.height)
+            ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+            ctx.fillStyle="#fff";
+            ctx.fillRect(0, 0, img.width, img.height);
+            ctx.drawImage(img, 0, 0);
+            if(window.ClipboardItem) {
+              canvas.toBlob(async (blob) => {
+                  const data = [new ClipboardItem({ [blob.type]: blob })]; 
+                  await navigator.clipboard.write(data).then(
+                  () => {
+                      this.$message.success('复制成功!')
+                  },
+                  () => {
+                      this.$message.warning('浏览器不支持')
+                  }
+                  ).finally(()=>{
+                      this.lockLoding && this.lockLoding.close();
+                  });
+              });
+            }else {
+              this.lockLoding && this.lockLoding.close();
+              this.$message.warning('当前协议暂不支持,仅支持https协议')
+            }	
+          }
+        },{
+          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}`)
+            let gNode = svg.getElementsByClassName('x6-graph-svg-viewport')[0]
+            // 去掉不该截图的添加图标
+            let leftImg = svg.getElementsByClassName('left-topic-image')
+            for (let i = 0; i < leftImg.length; i++) {
+              const element = leftImg[i];
+              element.parentElement.removeChild(element)
+              i--
+            }
+            let rightImg = svg.getElementsByClassName('right-topic-image')
+            for (let i = 0; i < rightImg.length; i++) {
+              const element = rightImg[i];
+              element.parentElement.removeChild(element)
+              i--
+            }
+            // console.log(leftImg,rightImg,'rightImg');
+
+            let textNode = document.createElement('text')
+            textNode.setAttribute('x',x-tx+width-90)
+            textNode.setAttribute('y',y-ty+height+22)
+            textNode.setAttribute('font-size','16px')
+            textNode.setAttribute('font-style','italic')
+            textNode.innerText = '来源:弘则研究'
+            gNode.appendChild(textNode)
+              },
+          copyStyles:false,
+          stylesheet: `
+              svg{
+                  background-color:white;
+              }
+            .x6-port {
+                visibility: hidden;
+            }` 
+            
+        })
+      },500),
+      saveChart: _.debounce( function(callback=null) {
+        if(!this.sandSaveParams.Name) 
+          return this.$message.warning('请填写逻辑图名称');
+        if(!this.sandSaveParams.SandboxClassifyId) 
+          return this.$message.warning('请选择所属分类');
+
+        if(!this.graph.toJSON().cells.length) return this.$message.warning('请绘制画布内容');
+
+        const { Name, SandboxClassifyId,SandboxId} = this.sandSaveParams;
+
+        this.lockLoding = this.$loading({
+          lock: true,
+          text: '保存中...',
+          target: '.sand-edit-container',
+          spinner: 'el-icon-loading',
+          background: 'rgba(255, 255, 255, 0.8)'
+        });
+        // return
+        const { cells } = this.graph.toJSON();
+        this.graph.toSVG(async (dataUri) => {
+          const params = new FormData();
+          params.append('Img',dataUri)
+          const { Data } = await dataBaseInterface.uploadImgSvg(params);
+          // if(!Data){
+          //   this.lockLoding.close();
+          //   return;
+          // }
+          let SandboxId = this.sandSaveParams.SandboxId
+          // console.log({
+          //   SandboxId,
+          //   Name,
+          //   SandboxClassifyId: Number(SandboxClassifyId),
+          //   Content: JSON.stringify(this.graph.toJSON()),
+          //   PicUrl: Data?Data.ResourceUrl:'',
+          //   SvgData: dataUri,
+          //   MindmapData:JSON.stringify(this.mindmapDataUse)
+          // });
+          // return 
+          const { Ret , Data : sandData} = await sandInterface.sandboxSaveV2({
+            SandboxId,
+            Name,
+            SandboxClassifyId: Number(SandboxClassifyId),
+            Content: JSON.stringify(this.graph.toJSON()),
+            PicUrl: Data?Data.ResourceUrl:'',
+            SvgData: dataUri,
+            MindmapData:JSON.stringify(this.mindmapDataUse)
+          })
+
+          if(Ret !== 200){
+            this.lockLoding.close();
+            return;
+          }
+          this.$message.success(`${SandboxId ? '编辑成功' : '保存成功'}`);
+          this.lockLoding.close();
+          //如果是新增,直接跳转到编辑页面
+          if(!SandboxId){
+            this.$router.replace({
+              path: '/sandflow',
+              query: {
+                SandboxId:sandData.SandboxId,
+              },
+            });
+          }
+          
+          callback && callback();
+        },{
+          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}`)
+            // 在图表右下方 加上"来源:弘则研究"字样
+            let gNode = svg.getElementsByClassName('x6-graph-svg-viewport')[0]
+            // 去掉不该截图的添加图标
+            let leftImg = svg.getElementsByClassName('left-topic-image')
+            for (let i = 0; i < leftImg.length; i++) {
+              const element = leftImg[i];
+              element.parentElement.removeChild(element)
+              i--
+            }
+            let rightImg = svg.getElementsByClassName('right-topic-image')
+            for (let i = 0; i < rightImg.length; i++) {
+              const element = rightImg[i];
+              element.parentElement.removeChild(element)
+              i--
+            }
+            let textNode = document.createElement('text')
+            textNode.setAttribute('x',x-tx+width-90)
+            textNode.setAttribute('y',y-ty+height+22)
+            textNode.setAttribute('font-size','16px')
+            textNode.setAttribute('font-style','italic')
+            textNode.innerText = '来源:弘则研究'
+            gNode.appendChild(textNode)
+              },
+          copyStyles:false,
+          stylesheet: `
+              svg{
+                  background-color:white;
+              }
+            .x6-port {
+                visibility: hidden;
+            }
+            ` 
+        })
+          
+      },500),
+      toolClickOptions(type,disabled){
+        // 设置元素属性的时候请一起设置,分几步设置,撤销的时候就要分几步。或者使用事务来设置
+        if(disabled) return
+        let value = arguments[2]
+        switch (type) {
+          case 'undo':
+            this.graph.undo()
+            break;
+          case 'redo':
+            this.graph.redo()
+            break;
+          case 'changeFamily':
+            this.styleOptions.fontF = value
+            this.setGraphStyle('text/fontFamily',value)
+            break;
+          case 'changeSize':
+            this.styleOptions.fontS = value
+            this.setGraphStyle('text/fontSize',value)
+            break;
+          case 'changeWeight':
+            this.styleOptions.fontW = this.styleOptions.fontW=='normal'?'bold':'normal'
+            this.setGraphStyle('text/fontWeight')
+            break;
+          case 'changeFontStyle':
+            this.styleOptions.fontStyle = this.styleOptions.fontStyle=='normal'?'italic':'normal'
+            this.setGraphStyle('text/fontStyle')
+            break;
+          case 'changeDecoration':
+            this.styleOptions.textDecoration = this.styleOptions.textDecoration=='none'?'underline':'none'
+            this.setGraphStyle('text/textDecoration')
+            break;
+          case 'changeColor':
+            this.setGraphStyle('text/fill',value)
+            break;
+          case 'changeLineHeight':
+            this.styleOptions.lineHeight = value
+            this.setGraphStyle('text/lineHeight',value)
+            break;
+          case 'changeTextAlign':
+            this.styleOptions.textAlign = value
+            this.setGraphStyle('text/textAnchor',value)
+            break;
+          case 'changeBackgroundColor':
+            this.setGraphStyle('body/fill',value)
+            break;
+          case 'changeLineColor':
+            this.setGraphStyle('body/stroke',value)
+            break;
+          case 'changeLineWidth':
+            this.styleOptions.lineWidth = value
+            this.setGraphStyle('body/strokeWidth',value)
+            break;
+          case 'changeStrokeDasharray':
+            this.styleOptions.lineStyle = value
+            this.setGraphStyle('body/strokeDasharray',value)
+            break;
+          case 'changeRouter':
+            this.styleOptions.connectStyle = value
+            this.setGraphStyle('router/name',value)
+            break;
+          case 'changeSourceMarker':
+            this.styleOptions.startArrow = value
+            this.setGraphStyle('line/sourceMarker',value)
+            break;
+          case 'changeTargetMarker':
+            this.styleOptions.endArrow = value
+            this.setGraphStyle('line/targetMarker',value)
+            break;
+          default:
+            break;
+        }
+      },
+      setGraphStyle(attr,value){
+        // console.log(attr,value);
+        let styleValue = value
+        let attrReal = attr
+        let refXValue;
+        let currentAttr= this.selectCells[0].getAttrs()
+        if(attr.indexOf('fontWeight')!=-1){
+          styleValue = currentAttr.text.fontWeight == "bold"?'normal':'bold'
+        }else if(attr.indexOf('fontStyle')!=-1){
+          styleValue = currentAttr.text.fontStyle == "italic"?'normal':'italic'
+        }else if(attr.indexOf('textDecoration')!=-1){
+          styleValue = currentAttr.text.textDecoration == "underline"?'none':'underline'
+        }else if(attr.indexOf('textAnchor')!=-1){
+          //需要特殊设置
+          if(styleValue=='start'){
+            refXValue='0%'
+          }else if(styleValue=='middle'){
+            refXValue=0.5
+          }else{
+            refXValue='100%'
+          }
+        }
+        // console.log(this.selectCells[0].attr(attr),styleValue,'styleValue');
+
+        if(this.selectCells[0].shape.indexOf('edge')!=-1){
+          // 边的情况
+          attrReal=attrReal.replace('body','line')
+        }
+        // console.log(attrReal,'attrReal');
+        if(this.selectCells[0].attr(attrReal) === styleValue){
+          return 
+        }
+        this.selectCells.map(cell=>{
+          // lineHeight和fontsize 是一个倍数关系,每一个都可能不一样。
+          if(attr.indexOf('lineHeight')!=-1){
+            let fontSizeCurrent = cell.getAttrs().text.fontSize
+            cell.setAttrs({
+              text:{
+                relativeLineHeight:styleValue, //设置相对行高
+                lineHeight:styleValue*fontSizeCurrent //设置行高
+              }
+            })
+          }else if(attr.indexOf('fontSize')!=-1){
+            let relativeLineHeightCurrent = cell.getAttrs().text.relativeLineHeight || 1.3
+            cell.setAttrs({
+              text:{
+                fontSize:styleValue,//设置字号
+                lineHeight:styleValue*relativeLineHeightCurrent //设置行高
+              }
+            })
+          }else if(attr=='body/stroke'){
+            // 线条颜色和边框颜色
+            cell.attr(attrReal,styleValue)
+          }else if(attr=='body/strokeWidth'){
+            // 线条粗细和边框粗细
+            cell.attr(attrReal,styleValue)
+          }else if(attr=='body/strokeDasharray'){
+            // 线条样式和边框样式
+            cell.attr(attrReal,styleValue)
+          }else if(attr=='router/name'){
+            // 1-直线  2-弯折线 3-圆角弯折线
+            let routerName=styleValue==1?'normal':'manhattan'
+            let connectorName=styleValue==3?'rounded':'normal'
+            this.graph.startBatch('setConnetorStyle')
+            if(routerName=='normal'){
+              // 变成直线,清除路径点
+              cell.setVertices([])
+            }else{
+              // 变弯折线 添加路径点
+              let sourcePoint = cell.getSourcePoint() //起始点
+              let targetPoint = cell.getTargetPoint() //终止点
+              let fisrtPoint = {x:(sourcePoint.x+targetPoint.x)/2,y:sourcePoint.y}
+              let secondPoint = {x:(sourcePoint.x+targetPoint.x)/2,y:targetPoint.y}
+              cell.setVertices([fisrtPoint,secondPoint])
+            }
+            cell.setRouter({name:routerName,args: {padding: {left: 10}}})
+            cell.setConnector({name:connectorName,args: { radius: 8 }})
+            this.graph.stopBatch('setConnetorStyle')
+          }else if(attr.indexOf('textAnchor')!=-1){
+            // 居左居中居右设置
+            // cell.attr('text/refX',refXValue)
+            cell.setAttrs({
+              text:{
+                refX:refXValue,//设置相对位置
+                textAnchor:styleValue //设置对齐方式
+              }
+            })
+          }else{
+            cell.attr(attr,styleValue)
+          }
+
+        })
+      },
+      // -------------------------------添加链接
+      changeLinkType(){
+        this.search_dataBaseId=''
+        this.dataBaseOptions=[]
+        this.dataBaseParams={
+          pages:1,
+          searchText:'',
+          search_have_more:false
+        }
+
+        this.databaseTableData=[]
+        this.databaseList=[]
+        this.databaseHaveMore=false
+        this.databasePageNo=1
+        
+        this.chartInfo={}
+        this.edbData=[]
+
+        this.reportKeyWord=''
+        this.reportList=[]
+      },
+      /* 搜索 */
+      dataBaseSearch(query) {
+        this.dataBaseParams.pages = 1;
+        this.dataBaseParams.searchText = query;
+        this.dataBaseSearchApi(this.dataBaseParams.searchText)
+      },
+      // 加载更多
+      dataBaseSearchLoad() {
+        if(!this.dataBaseParams.search_have_more) return;
+        this.dataBaseSearchApi(this.dataBaseParams.searchText,++this.dataBaseParams.pages);
+      },
+      /* 聚焦获取当前检索 */
+      dataBaseInputFocus(e) {
+        this.dataBaseParams.pages = 1;
+        this.dataBaseParams.searchText = e.target.value;
+        if(this.dataBaseParams.searchText) {
+          this.dataBaseSearchApi(this.dataBaseParams.searchText);
+        }else {
+          this.searchOptions = [];
+          this.dataBaseParams.search_have_more=false
+        }
+
+      },
+      dataBaseSearchApi(query,page=1) {
+        if(this.addLinkSearchParams.linkType==1){
+          sheetInterface.searchTarget({
+            KeyWord:query,
+            CurrentIndex: page
+          }).then(res => {
+            if(res.Ret !== 200) return
+            const { List,Paging } = res.Data;
+            this.dataBaseParams.search_have_more = page < Paging.Pages;
+            this.dataBaseOptions = page === 1 ? List : this.dataBaseOptions.concat(List);
+          })
+        }else{
+          dataBaseInterface.chartSearchByEs({
+            Keyword: query,
+            IsShowMe:false,
+            CurrentIndex: page
+          })
+          .then((res) => {
+            if (res.Ret !== 200) return
+            const { List,Paging } = res.Data;
+            this.dataBaseParams.search_have_more = page < Paging.Pages;
+            this.dataBaseOptions = page === 1 ? List : [...this.dataBaseOptions,...List];
+          });
+        }
+
+      },
+      initGetData() {
+        this.databasePageNo = 1;
+        if(this.$refs.edb_detail_data){
+          this.$refs.valueUl.scrollTop=0
+        }
+        this.getDatabaseList();
+      },
+      getDatabaseList(){
+        dataBaseInterface.targetList({
+          PageSize: 20,
+          CurrentIndex: this.databasePageNo,
+          EdbInfoId: this.search_dataBaseId,
+        }).then(res => {
+          if(res.Ret === 200) {
+            if(res.Data) {
+              this.databaseTableData = [res.Data.Item] || [];
+              this.databaseHaveMore =  this.databasePageNo < res.Data.Paging.Pages ? true : false;
+              this.databaseList = this.databasePageNo === 1 ? (res.Data.Item.DataList || []) : this.databaseList.concat(res.Data.Item.DataList);
+            }else {
+              this.databaseTableData = [];
+              this.databaseList = [];  
+            }
+          }
+        })
+      },
+      databaseScrollHandle:_.throttle(function() {
+        let scrollTop = this.$refs.valueUl.scrollTop;
+        let clientHeight = this.$refs.valueUl.clientHeight;
+        let scrollHeight = this.$refs.valueUl.scrollHeight;
+        if(scrollTop===0) return
+        if(scrollTop + clientHeight >= scrollHeight-10 && this.databaseHaveMore){
+          this.databasePageNo++
+          this.getDatabaseList()
+        }
+		  },200),
+      async getChartDetail(ChartInfoId) {
+        // console.log(ChartInfoId);
+        const res = await dataBaseInterface.getChartInfoById({ChartInfoId})
+        if (res.Ret !== 200) return;
+        this.chartInfo = res.Data.ChartInfo || {}
+        this.edbData = res.Data.EdbInfoList|| []
+
+        const chartTypeMap = {
+          7: this.initBarData, //柱形图
+          10: this.initSectionScatterData //截面散点
+        }
+
+        chartTypeMap[this.chartInfo.ChartType] && chartTypeMap[this.chartInfo.ChartType](res.Data);
+
+      },
+      editLinkName(item){
+        this.editingLabel = item.Name
+        item.editing=true
+        this.$nextTick(() => {
+          this.$refs.labelEditInput[0].focus();
+        });
+      },
+      linkClick(item){
+        if(this.activeItemRId == item.RId) return
+        this.activeItemRId = item.RId
+        // console.log(item);
+        if(item.Type==3){
+          this.$message.info('研报类型的暂无回显')
+        }else if(item.Type==1){
+          this.addLinkSearchParams.linkType=item.Type
+          this.changeLinkType()
+          this.initGetData() 
+        }else if(item.Type==2){
+          this.addLinkSearchParams.linkType=item.Type
+          this.changeLinkType()
+          this.getChartDetail(item.Id)
+        }
+
+
+        // console.log('回显');
+      },
+      linkDelete(item,index){
+        if(this.activeItemRId == item.RId){
+          this.activeItemRId=""
+          this.changeLinkType()
+        }
+        if(item.Type==3){
+          let deleteId=this.selections.filter(it=> it.Id==item.Id)
+          // console.log(deleteId);
+          if(deleteId[0]){
+            this.$refs.reportTable && this.$refs.reportTable.toggleRowSelection(deleteId[0],false)
+          }
+        }
+        this.checkedLinkList.splice(index,1)
+      },
+      editLinkNameFinish(item){
+        if (this.editingLabel) {
+          item.editing=false
+          item.Name = this.editingLabel
+        } else {
+          this.$message.warning('不能为空');
+        }
+      },
+      searchReport(){
+        this.reportParams.CurrentIndex=1
+        if(!this.reportKeyWord){
+          this.reportList=[]
+          this.reportTotal=0
+        }else{
+          this.getReportList()
+        }
+      },
+      getReportList(){
+        let params={
+          CurrentIndex: this.reportParams.CurrentIndex,
+          PageSize: this.reportParams.PageSize,
+          KeyWord:this.reportKeyWord,
+          State:2
+        }
+        reportlist(params).then((res) => {
+          if (res.Ret === 200) {
+            this.reportList = res.Data.List || [];
+            this.reportTotal = parseInt(res.Data.Paging.Totals);
+          }
+        });    
+      },
+      pageChange(page_no){
+        this.reportParams.CurrentIndex = page_no;
+        this.getReportList();
+      },
+      reportSelect(selection){
+        this.selections=selection
+        // console.log(selection);
+        let allIds = this.reportList.map(it => {
+          return it.Id
+        })
+        let simpleSelections = selection.map(it => {
+          return {Id:it.Id,Code:it.ReportCode,Name:it.Title}
+        })
+
+        let unselectIds=[]
+
+        if(simpleSelections.length>0){
+          allIds.map(id =>{
+            if(simpleSelections.every(sele => id!=sele.Id )){
+              unselectIds.push(id)
+            }
+          })
+        }else{
+          unselectIds=allIds
+        }
+        // console.log(simpleSelections,unselectIds);
+        //没有就增加
+        simpleSelections.map(item =>{
+          let rId = this.addLinkSearchParams.linkType+'-'+item.Id
+          if(this.checkedLinkList.every(sele => rId!=sele.RId )){
+            this.checkedLinkList.push({
+              RId:rId,
+              Id:item.Id,
+              Name:item.Name,
+              Type:this.addLinkSearchParams.linkType,
+              editing:false,
+              detailParams:{id:item.Id,code:item.Code}
+            })
+          }
+          // else{
+          //   this.$message.warning(`${item.Name}已添加,请勿重复添加`)
+          // }
+        })
+        //有就去掉
+        unselectIds.map(item =>{
+          let rId = this.addLinkSearchParams.linkType+'-'+item
+          let index = this.checkedLinkList.findIndex(link => rId==link.RId)
+          // console.log(index);
+          if(index!=-1){
+            this.checkedLinkList.splice(index,1)
+          }
+        })
+        // console.log(this.checkedLinkList,'this.checkedLinkList');
+      },
+      foldLink(){
+        this.popoverFlod=!this.popoverFlod 
+        if(this.linkNode){
+          this.linkNode.data.linkFold = this.popoverFlod
+        }
+        this.popoverVisible=false
+        this.$nextTick(()=>{
+          this.popoverVisible=true
+        })
+      },
+      clearPopoverTimeout(){
+        clearTimeout(this.popoverTimeout)
+        this.popoverTimeout=null 
+      },
+      closePopover(){
+        this.popoverVisible=false
+      },
+      navigateTo(item){
+        // console.log(item,'item');
+        if(item.Type == 1){
+          if(item.databaseType==0){
+            // 普通指标
+            const { href } = this.$router.resolve({ path: '/database',query:item.detailParams});
+            window.open(href, '_blank');
+          }else{
+            // 预测指标
+            const { href } = this.$router.resolve({ path: '/predictEdb',query:item.detailParams});
+            window.open(href, '_blank');
+          }
+        }else if(item.Type == 2){
+          // 跳转到图库详情
+          const { href } = this.$router.resolve({ path: '/chartsetting',query:item.detailParams});
+          window.open(href, '_blank');
+        }else if(item.Type == 3){
+          // 跳转到研报
+          const { href } = this.$router.resolve({ path: '/reportdtl',query:item.detailParams});
+          window.open(href, '_blank');
+        }
+      },
+      changePopoverPositon:_.throttle(function(args){
+        this.popoverVisible=false
+        let clinetPositon=this.graph.localToClient(args.current)
+        let size=args.node.size()
+        // console.log(this.popoverTriggerDom,'domdomdom');
+        this.popoverTriggerDom.style.left = clinetPositon.x+size.width/2 + 'px';
+        this.popoverTriggerDom.style.top = clinetPositon.y + 'px';
+        this.$nextTick(()=>{
+          this.popoverVisible=true
+        })
+      },200) ,
+      mindmapRecoverRemove(mindmapNodes){
+        let shouldOperations=[]
+        this.mindmapDataUse.map((item,index)=>{
+          let levelIds = mindmapNodes.filter(mindMap => mindMap.data.id.startsWith(item.mindmapData.id)).map(mindMap => mindMap.data.id)
+          // console.log(levelIds,'levelIds');
+          if(!(levelIds && levelIds.length>0)) return 
+          // console.log(levelIds,'levelIds');
+          let mindMapIds=[...levelIds]
+          for (let i = 0; i < levelIds.length; i++) {
+            const element = levelIds[i]
+            mindMapIds=mindMapIds.filter( id => id.indexOf(element) !=0 || id==element)
+          }
+          // console.log(mindMapIds,'mindMapIds');
+          shouldOperations.push(mindMapIds)
+        })
+        // 重做删除时 恢复数据指针前进
+        console.log(this.canRedo,'this.canRedo');
+        if(!this.canRedo){
+          console.log('canredo no');
+          this.mindmapAssistData.mindmapDataRecoverUse=[JSON.stringify(this.mindmapDataUse)]
+        }else{
+          console.log('canredo');
+          this.mindmapAssistData.mindmapDataRecoverUse.push(JSON.stringify(this.mindmapDataUse))
+        }
+
+        console.log(this.mindmapAssistData.mindmapDataRecoverUse,this.mindmapDataUse,this.mindmapAssistData.mindmapDataRecoverUse.length);
+        shouldOperations.map(it =>{
+          it.map(it1 =>{
+            this.deleteMindmapData(it1,this.mindmapDataUse)
+          })
+        })
+      },
+      mindmapRecoverAdd(){
+        // 重做添加时 恢复数据指针前进
+        console.log(this.mindmapAssistData.mindmapDataRecoverUse.length,this.mindmapAssistData.mindmapDataRecoverUse);
+        let recoverData = this.mindmapAssistData.mindmapDataRecoverUse.pop()
+        console.log(JSON.parse(recoverData) ,this.mindmapAssistData.mindmapDataRecoverUse.length,this.mindmapAssistData.mindmapDataRecoverUse,'回复的数据');
+        if(recoverData) this.mindmapDataUse=JSON.parse(recoverData) 
+        console.log(this.mindmapDataUse,'回复后');
+      },
+      deleteMindmapData(id,data){
+        // console.log(id,data,'id,data');
+        // return 
+        let ids = id.split('-')
+        let mindmapDataIndex = data.findIndex(mindmap => mindmap.mindmapData.id == ids[0])
+        if(ids.length==1){
+          data.splice(mindmapDataIndex,1)
+          return 
+        }
+
+        let mindmapData = data[mindmapDataIndex].mindmapData
+        let findId = ids[0]
+        for (let i = 1; i < ids.length-1; i++) {
+          const element = ids[i];
+          findId = findId+'-'+element
+          mindmapData=mindmapData.children.find(it => it.id==findId)
+        }
+        let endId = ids[ids.length-1]
+        // console.log(mindmapData.children,'mindmapData.children');
+        let endIndex = mindmapData.children.findIndex(it => it.id == findId+'-'+endId)
+        mindmapData.children.splice(endIndex,1)
+        // console.log(data);
+      },
+      /* 向左收起 展开 */
+      slideHandle() {
+        this.isSlideLeft = !this.isSlideLeft;
+      },
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  #sand-edit-container{
+    height: calc(100vh - 120px);
+    min-height: 600px;
+    display: flex;
+    flex-wrap: nowrap;
+    .sand-toolbar{
+      min-width: 400px;
+      width: 400px;
+      background-color: white;
+      border-radius: 4px;
+      border: 1px solid #DCDFE6;
+      height: 100%;
+      box-sizing: border-box;
+      margin-right: 20px;
+      padding-bottom: 20px;
+      position: relative;
+      .sand-elements-tab{
+        padding: 0 30px;
+        overflow: auto;
+        height: calc(100vh - 220px);
+        .sand-elements{
+          padding: 30px 0 20px;
+          border-bottom: 1px solid #C8CDD9 ;
+          span{
+            display: inline-block;
+            margin-bottom: 10px;
+            font-size: 16px;
+            color: #999999;
+          }
+          .elements-row{
+            display: flex;
+            flex-wrap: wrap;
+            align-items: center;
+            margin-right: -10px;
+            .elements-shape-item,img{
+              margin-right: 20px;
+              margin-bottom: 8px;
+              cursor: pointer;
+            }
+            img{
+              height: 18px;
+              width: 18px;
+            }
+          }
+        }
+        .sand-elements-mind{
+          border-bottom: none;
+          padding-bottom: 0;
+        }
+
+      }
+      .elements-row-mind{
+        display: flex;
+        flex-wrap: wrap;
+        align-items: center;
+        justify-content: space-between;
+        img{
+          width: 100%;
+          margin-bottom: 20px;
+        }
+      }
+      .sand-style-tab{
+        width: 100%;
+        padding: 20px 30px;
+        display: flex;
+        flex-wrap: wrap;
+        box-sizing: border-box;
+        justify-content: space-between;
+        .sand-style-tab-item{
+          box-sizing: border-box;
+          border: 1px solid #C8CDD9;
+          padding: 10px 0;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          cursor: pointer;
+          width: calc(50% - 7px);
+          margin-bottom: 14px;
+          border-radius: 4px;
+          img{
+            width: 64px;
+            height: 54px;
+          }
+        }
+
+        .active{
+          border: 1px solid #0052D9;
+        }
+      }
+    }
+    .sand-main{
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+      .sand-main-top{
+        padding: 20px 20px 10px;
+        display: flex;
+        // flex-wrap: wrap;
+        align-items: center;
+        justify-content: space-between;
+        background-color: white;
+        box-shadow: 0px 2px 12px 0px rgba($color: #000000, $alpha: 0.08);
+        border: 1px solid #DCDFE6;
+        border-radius: 4px;
+        margin-bottom: 20px;
+        .sand-mainTop-form{
+          margin-bottom: 10px;
+          margin-right: 20px;
+          white-space: nowrap;
+        }
+        .sand-mainTop-option{
+          display: flex;
+          align-items: center;
+          margin-bottom: 10px;
+          .sand-option-linkShow{
+            display: flex;
+            align-items: center;
+            margin-right: 30px;
+            cursor: pointer;
+            img{
+              height: 16px;
+              margin-right: 4px;
+            }
+          }
+        }
+      }
+      .sand-mainBody-chart{
+        .sand-mainBody-tool{
+          position: absolute;
+          height: 50px;
+          width: 100%;
+          background-color: #F5F6F7;
+          box-sizing: border-box;
+          border-radius: 4px;
+          display: flex;
+          align-items: center;
+          padding-right: 10px;
+          z-index: 1;
+          top: 0;
+          left: 0;
+          .sand-tool-item{
+            margin-left: 20px;
+            cursor: pointer;
+            .dropdown-box{
+              position: relative;
+              img{
+                height: 16px;
+                width: 16px;
+              }
+              .dropdown-content{
+                display: flex;
+                align-items: center;
+
+                .dropdown-content-text{
+                  width: 30px;
+                  white-space: nowrap;
+                  overflow: hidden;
+                  margin-right: 5px;
+                }
+              }
+              .disabled-item{
+                background-color: transparent;
+                cursor: not-allowed;
+                position: absolute;
+                top: 0;
+                right: 0;
+                left: 0;
+                bottom: 0;
+                z-index: 1;
+              }
+            }
+          }
+          .img-box{
+            height: 16px;
+            width: 17px;
+            img{
+              height: 16px;
+              width: 17px;
+            }
+          }
+          .sand-tool-img{
+            height: 16px;
+            min-width: 16px;
+            position: relative;
+            img{
+              height: 16px;
+              width: 16px;
+            }
+          }
+          .tool-disabled{
+            color: #C8CDD9;
+            cursor:not-allowed;
+          }
+        }
+      }
+    }
+    .add-link-box{
+      padding: 15px 40px 35px;
+      .link-box-option{
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        margin-bottom: 30px;
+      }
+      .link-box-content{
+        // height:300px;
+        // max-height:300px;
+        margin-bottom: 30px;
+        .link-content-dataIndex{
+          display: flex;
+          flex-direction: column;
+          .value-ul {
+            flex-grow: 1;
+            overflow-y: auto;
+            margin-top: 10px;
+            height: 200px;
+            border-bottom: 1px solid #EBEFF6;
+            //max-height: calc(100vh - 495px);
+            //overflow-y: auto;
+            .value-item {
+              /* width: 100%; */
+              padding: 10px 0;
+              border: 1px solid #dcdfe6;
+              border-bottom: none;
+              display: flex;
+              justify-content: space-around;
+              >span{
+                padding:0 16px;
+                box-sizing: border-box;
+              }
+              .value-label {
+                position: relative;
+                color: #666;
+                .value-style{
+                  /* background-color: #ECF2FE;
+                  color: #0052D9; */
+                  padding:5px;
+                  border-radius: 4px;
+                  &.predict-act {
+                    color: orange;
+                  }
+                }
+                &.date{
+                  &::after{
+                    content: '';
+                    position:absolute;
+                    right:0;
+                    top:-14px;
+                    height:calc(100% + 28px);
+                    width:1px;
+                    background-color: #dcdfe6;
+                  }
+                }
+              }
+              .predict-act {
+                color: orange;
+              }
+              .new-tag {
+                width: 6px;
+                height: 6px;
+                display: inline-block;
+                position: absolute;
+                left: -12px;
+                top: 50%;
+                transform: translateY(-50%);
+                border-radius: 50%;
+                background: #f00;
+              }
+            }
+            .nodata {
+              text-align: center;
+              padding: 40px 0;
+              color: #999;
+            }
+          }
+          .delete-button{
+            color: #AD352F;
+            font-size: 14px;
+            cursor: pointer;
+          }
+        }
+        .link-content-chartIndex{
+          .chart-name{
+            font-size: 16px;
+            text-align: center;
+            color: #333333;
+          }
+        }
+      }
+      .link-box-tags{
+        display: flex;
+        align-items: center;
+        overflow-x: auto;
+        .link-box-tag{
+          display: flex;
+          align-items: center;
+          padding: 0 8px;
+          height: 30px;
+          max-width: 250px;
+          background-color: #F8F8F8;
+          margin-right: 30px;
+          cursor: pointer;
+          &:last-child{
+            margin-right: 0;
+          }
+          span{
+            color: #666666;
+            white-space: nowrap;
+            overflow: hidden;
+            text-overflow: ellipsis;
+          }
+          img{
+            height: 16px;
+            width: 16px;
+            margin-left: 8px;
+          }
+        }
+      }
+      .link-box-buttons{
+        margin-top: 60px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+
+      }
+    }
+  }
+  #link-popover{
+    display: flex;
+    justify-content: space-between;
+    transition: all 0.3s ease;
+    overflow: hidden;
+    .link-box{
+      .link-item{
+        &:hover{
+          text-decoration: underline;
+          color: #0052D9;
+          cursor: pointer;
+        }
+      }
+    }
+    .link-fold{
+      transition: all 0.3s ease;
+      height: 16px;
+      width: 16px;
+      cursor: pointer;
+    }
+  }
+
+  .slide-icon {
+    padding: 20px 0;
+    /* display: block; */
+    box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.3);
+    border-radius: 5px;
+    cursor: pointer;
+    position: absolute;
+    top: 50%;
+    transform: translateY(-50%);
+    z-index: 99;
+    &:hover {
+      background-color: rgba(0, 0, 0, 0.05);
+    }
+    &.slide-left {
+      right: 0;
+    }
+    &.slide-right {
+      left: 0;
+    }
+  }
+  @media screen and (max-width:1680px) {
+    #sand-edit-container{
+      .sand-toolbar{
+        min-width: 320px;
+        width: 320px;
+      }
+    }
+  }
+</style>
+<style lang="scss">
+  .sand-toolbar-tabs{
+    .el-tabs__header{
+      padding-top: 16px;
+      box-shadow: 0px 2px 12px 0px rgba($color: #000000, $alpha: 0.08);
+    }
+  }
+  .el-cascader{
+    .el-input{
+      width: 240px;
+    }
+  }
+  .sand-mainBody-chart{
+    height: calc(100% - 50px);
+    width: 100%;
+    flex: 1;
+    position: relative;
+    overflow: hidden;
+    display: flex;
+    background-color: white;
+    border: 1px solid #DCDFE6;
+    border-radius: 4px;
+    padding-top: 50px;
+    .contextMenu-wrapper {
+      position: fixed;
+      z-index: 99;
+      top: -9999px;
+      left: -9999px;
+      background: #fff;
+      padding: 10px 0;
+      box-shadow: 0 1px 4px #999;
+    }
+    #link-reference{
+      position: fixed;
+      z-index: -1;
+      top: -99999px;
+      left: -99999px;
+      background-color: transparent;
+    }
+    #sand-chart-container{
+      flex: 1;
+    }
+    .x6-graph-scroller {
+      flex: 1;
+    }
+
+    .x6-port-body {
+      display: none;
+    }
+
+    /* reseize 框样式 */
+    .x6-widget-transform {
+      .x6-widget-transform-resize {
+        border-radius: 0;
+      }
+    }
+    .minimap{
+      position:absolute;
+      right:6px;
+      bottom:6px;
+      box-sizing: border-box;
+      .x6-widget-minimap-viewport{
+        border-color: red;
+        .x6-widget-minimap-viewport-zoom{
+          border-color: red;
+        }
+      }
+      .x6-widget-minimap{
+        width: auto !important;
+        height: auto !important;
+      }
+    }
+  }
+  .left-topic-image,.right-topic-image {
+    visibility: hidden;
+    width: 0;
+    cursor: pointer;
+  }
+  .x6-node:hover .left-topic-image {
+    width: unset;
+    visibility: visible;
+  }
+  .x6-node:hover .right-topic-image {
+    width: unset;
+    visibility: visible;
+  }
+  .x6-node-selected rect {
+    stroke-width: 2px;
+  }
+  #sand-mainBody-tool{
+    .el-select{
+      .el-input{
+        .el-input__inner{
+          border: none;
+          background-color: #F5F6F7;
+          padding-left: 0;
+          padding-right: 30px;
+        }
+      }
+    }
+  }
+  .style-acitve{
+    color: #0052D9;
+  }
+  .style-acitve-back{
+    background-color: #C5CBDA;
+  }
+
+.vue-giant-tree{
+  li{
+    ul{
+      padding: 0 0 0 10px!important;
+    }
+    .button{
+      z-index: 1;
+      height: 30px;
+      width: 20px;
+      &::before{
+        border:none!important;
+        top: 50%!important;
+        left: 50%!important;
+        transform: translate(-50%,-50%)!important;
+        height: 16px!important;
+        width: 16px!important;
+      }
+    }
+    .button.noline_close{
+      &::before{
+        content: url('../../../assets/img/set_m/slide_black.png')!important;
+      }
+    }
+    .button.noline_open{
+      &::before{
+        content: url('../../../assets/img/set_m/down_black.png')!important;
+      }
+    }
+    a{
+      width: calc(100% - 22px);
+      height: 30px!important;
+      line-height: 30px!important;
+      .node_name{
+        width: calc(100% - 6px);
+        color: #333333!important;
+        border-radius: 0!important;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+      }
+    }
+    .curSelectedNode{
+      position: relative;
+      z-index: 0;
+      display: inline-flex;
+      flex-wrap: nowrap;
+      align-items: center;
+      .node_name{
+        flex: 1;
+        color: unset;
+        background-color: transparent;
+        &::after{
+          content: '';
+          position: absolute;
+          top: 0;
+          left: -22px;
+          height: 30px;
+          width: calc(100% + 22px);
+          background-color: #ECF2FE;
+          z-index: -1;
+        }
+      }
+      .custom-button-zone{
+        display: flex!important;
+      }
+    }
+  }
+
+}
+  .classify-popper{
+    height: 400px;
+    overflow: auto;
+  }
+  .classify-cascader-popper{
+    display: none;
+  }
+  .label-edit-input{
+    width: 220px!important;
+    .el-input__inner{
+      height: 26px;
+      padding: 10px;
+    }
+  }
+</style>

部分文件因为文件数量过多而无法显示