Browse Source

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

cxmo 1 year ago
parent
commit
509356d152
100 changed files with 6662 additions and 545 deletions
  1. 1 0
      index.html
  2. 2 1
      src/api/api.js
  3. 97 0
      src/api/modules/chartApi.js
  4. 107 0
      src/api/modules/sheetApi.js
  5. 85 0
      src/api/modules/smartReport.js
  6. 3 0
      src/assets/icons/chartFrame/arrow-left.svg
  7. 3 0
      src/assets/icons/chartFrame/arrow-right.svg
  8. 11 0
      src/assets/icons/chartFrame/fillColor.svg
  9. 17 0
      src/assets/icons/chartFrame/fontColor.svg
  10. 12 0
      src/assets/icons/chartFrame/fontStyle.svg
  11. 11 0
      src/assets/icons/chartFrame/fontText.svg
  12. 12 0
      src/assets/icons/chartFrame/fontWeight.svg
  13. 8 0
      src/assets/icons/chartFrame/redo.svg
  14. 5 0
      src/assets/icons/chartFrame/stokeColor.svg
  15. 5 0
      src/assets/icons/chartFrame/stokeStyle.svg
  16. 5 0
      src/assets/icons/chartFrame/textAlign.svg
  17. 8 0
      src/assets/icons/chartFrame/undo.svg
  18. BIN
      src/assets/img/chart_m/check.png
  19. BIN
      src/assets/img/home/loading.gif
  20. BIN
      src/assets/img/icons/back_arrow_blue_new.png
  21. BIN
      src/assets/img/icons/choose_bluebg_new.png
  22. BIN
      src/assets/img/icons/download_blue.png
  23. BIN
      src/assets/img/icons/edit_blue_new.png
  24. BIN
      src/assets/img/icons/jump_ico.png
  25. BIN
      src/assets/img/icons/refresh_blue_new.png
  26. BIN
      src/assets/img/icons/save_as_blue_new.png
  27. BIN
      src/assets/img/icons/save_blue_new.png
  28. BIN
      src/assets/img/ppt_m/add_first.png
  29. BIN
      src/assets/img/smartReport/bg01.png
  30. BIN
      src/assets/img/smartReport/icon01.png
  31. BIN
      src/assets/img/smartReport/icon02.png
  32. BIN
      src/assets/img/smartReport/icon03.png
  33. BIN
      src/assets/img/smartReport/icon04.png
  34. BIN
      src/assets/img/smartReport/icon05.png
  35. BIN
      src/assets/img/smartReport/icon06.png
  36. BIN
      src/assets/img/smartReport/icon07.png
  37. BIN
      src/assets/img/smartReport/icon08.png
  38. BIN
      src/assets/img/smartReport/icon09.png
  39. BIN
      src/assets/img/smartReport/icon10.png
  40. BIN
      src/assets/img/smartReport/icon11.png
  41. BIN
      src/assets/img/smartReport/icon12.png
  42. BIN
      src/assets/img/smartReport/icon13.png
  43. BIN
      src/assets/img/smartReport/icon14.png
  44. BIN
      src/assets/img/smartReport/icon15.png
  45. BIN
      src/assets/img/smartReport/icon16.png
  46. 80 10
      src/routes/modules/chartRoutes.js
  47. 17 0
      src/routes/modules/oldRoutes.js
  48. 65 9
      src/utils/buttonConfig.js
  49. 2 0
      src/utils/icon.js
  50. 2 2
      src/utils/svgToblob.js
  51. 1 1
      src/views/Home.vue
  52. 140 0
      src/views/chartFrame_manage/common/config.js
  53. 115 0
      src/views/chartFrame_manage/common/event.js
  54. 135 0
      src/views/chartFrame_manage/common/graph.js
  55. 267 0
      src/views/chartFrame_manage/components/frameContainer.vue
  56. 402 0
      src/views/chartFrame_manage/components/frameToolBar.vue
  57. 36 0
      src/views/chartFrame_manage/components/toolItem.vue
  58. 149 0
      src/views/chartFrame_manage/css/basePage.scss
  59. 69 0
      src/views/chartFrame_manage/css/customTree.scss
  60. 221 0
      src/views/chartFrame_manage/frameEditor.vue
  61. 601 0
      src/views/chartFrame_manage/index.vue
  62. 1 1
      src/views/chartRelevance_manage/components/selectTarget.vue
  63. 5 92
      src/views/dataEntry_manage/chartSetting.vue
  64. 11 13
      src/views/dataEntry_manage/databaseList.vue
  65. 4 0
      src/views/dataEntry_manage/mixins/addOreditMixin.js
  66. 158 24
      src/views/datasheet_manage/addSheet.vue
  67. 70 24
      src/views/datasheet_manage/common/option.js
  68. 57 3
      src/views/datasheet_manage/components/CustomTable.vue
  69. 25 1
      src/views/datasheet_manage/components/MixedTable.vue
  70. 31 15
      src/views/datasheet_manage/components/SheetExcel.vue
  71. 1 1
      src/views/datasheet_manage/components/selectTargetValueDia.vue
  72. 6 2
      src/views/datasheet_manage/components/sheetClassifyDia.vue
  73. 119 0
      src/views/datasheet_manage/components/sheetListWrap.vue
  74. 505 0
      src/views/datasheet_manage/customAnalysis/addAnalysisSheet.vue
  75. 130 0
      src/views/datasheet_manage/customAnalysis/components/bottomSection.vue
  76. 261 0
      src/views/datasheet_manage/customAnalysis/components/createTargetForm.vue
  77. 118 0
      src/views/datasheet_manage/customAnalysis/components/rightSection.vue
  78. 292 0
      src/views/datasheet_manage/customAnalysis/edit.vue
  79. 1149 0
      src/views/datasheet_manage/customAnalysis/list.vue
  80. 197 82
      src/views/datasheet_manage/customSheetEdit.vue
  81. 89 17
      src/views/datasheet_manage/mixedSheetEdit.vue
  82. 40 2
      src/views/datasheet_manage/mixins/classifyMixin.js
  83. 191 209
      src/views/datasheet_manage/sheetList.vue
  84. 4 0
      src/views/mychart_manage/components/chartDetailDia.vue
  85. 80 0
      src/views/mychart_manage/components/classifyDeleteCheck.vue
  86. 56 8
      src/views/mychart_manage/index.vue
  87. 1 0
      src/views/positionAnalysis_manage/components/chartDetail.vue
  88. 2 2
      src/views/ppt_manage/newVersion/components/Cover.vue
  89. 2 2
      src/views/ppt_manage/newVersion/components/CoverEn.vue
  90. 1 1
      src/views/ppt_manage/newVersion/components/catalog/pptContent.vue
  91. 2 2
      src/views/ppt_manage/newVersion/pptEditor.vue
  92. 2 2
      src/views/ppt_manage/newVersion/pptEnEditor.vue
  93. 6 4
      src/views/ppt_manage/newVersion/pptEnPresent.vue
  94. 4 4
      src/views/ppt_manage/newVersion/pptEnPublish.vue
  95. 6 4
      src/views/ppt_manage/newVersion/pptPresent.vue
  96. 4 4
      src/views/ppt_manage/newVersion/pptPublish.vue
  97. 4 2
      src/views/predictEdb_manage/mixins/mixin.js
  98. 2 1
      src/views/sandbox_manage/index.vue
  99. 312 0
      src/views/smartReport/components/BaseInfo.vue
  100. 20 0
      src/views/smartReport/components/ChartComp.vue

+ 1 - 0
index.html

@@ -75,6 +75,7 @@
 	<script type="text/javascript" src="./static/js/jquery.min.js"></script>
 	<script src="https://hzstatic.hzinsights.com/static/cdn/Luckysheet@2.1.13/dist/plugins/js/plugin.js"></script>
 	<script src="https://hzstatic.hzinsights.com/static/cdn/Luckysheet@2.1.13/dist/luckysheet.umd.js"></script>
+	<script src="https://hzstatic.hzinsights.com/static/cdn/luckyexcel.umd.js"></script>
 	<script type="text/javascript" src="./static/js/jquery.dataTables.js"></script>
 </body>
 </html>

+ 2 - 1
src/api/api.js

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

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

@@ -943,6 +943,13 @@ const mychartInterface = {
 	addClassify: params => {
 		return http.post('/my_chart/classify/add',params)
 	},
+	/**
+	 * 获取图表关联的节点列表
+	 * @param {MyChartClassifyId} params 
+	 */
+	getFrameNode:params =>{
+		return http.get('/my_chart/classify/framework_node_list',params)
+	},
 	/**
 	 * 删除分类
 	 * @param {MyChartClassifyId} params 
@@ -1106,8 +1113,98 @@ const mychartInterface = {
 		return http.get('/my_chart/search_by_es',params)
 	}
 }
+/* 图库框架 */
+const chartFrameInterface = {
+    /**
+     * 添加框架
+     * @param {Object} params 
+     * @param {String} params.FrameworkName 框架名称
+     * @param {String} params.FrameworkImg 框架图片地址
+     * @param {String} params.FrameworkContent 框架内容
+     * @param {Array} params.Nodes 框架所包含的节点数组
+     * @param {String} Nodes.NodeName 节点名称
+     * @param {Number} Nodes.MyChartClassifyId 节点对应图库分类id
+     * @returns 
+     */
+    addFrame: params => {
+        return http.post('/chart_framework/add',params)
+    },
+    /**
+     * 编辑框架
+     * @param {Object} params 
+     * @param {Number} params.ChartFrameworkId 框架id
+     * 其他参数同上
+     * @returns 
+     */
+    editFrame: params => {
+        return http.post('/chart_framework/edit',params)
+    },
+    getFrameDetail:params=>{
+        return http.get('/chart_framework/detail',params)
+    },
+    /**
+     * 重命名框架
+     * @param {Object} params 
+     * @param {Number} params.ChartFrameworkId
+     * @param {String} params.FrameworkName
+     * @returns 
+     */
+    reNameFrame: params => {
+        return http.post('/chart_framework/rename',params)
+    },
+    /**
+     * 删除框架
+     * @param {Object} params 
+     * @param {Number} params.ChartFrameworkId
+     * @returns 
+     */
+    deleteFrame: params => {
+        return http.post('/chart_framework/remove',params)
+    },
+    /**
+     * 公开/隐藏框架
+     * @param {Object} params 
+     * @param {Number} params.ChartFrameworkId
+     * @param {Number} params.IsPublic 0隐藏 1公开
+     * @returns 
+     */
+    changePublicFrame: params => {
+        return http.post('/chart_framework/edit_public',params)
+    },
+    /**
+     * 框架移动排序
+     * @param {Object} params 
+     * @param {Number} params.ChartFrameworkId
+     * @param {Number} params.PrevChartFrameworkId
+     * @param {Number} params.NextChartFrameworkId
+     * @returns 
+     */
+    moveFrame: params => {
+        return http.post('/chart_framework/move',params)
+    },
+    /**
+     * 获取公开框架目录
+     * @returns 
+     */
+    getPublicFrameList:params=>{
+        return http.get('/chart_framework/public_menu',params)
+    },
+    /**
+     * 获取我的框架列表
+     * @param {Object} params 
+     * @param {Number} params.AdminId
+     * @param {String} params.Keyword 筛选关键词
+     * @param {Number} params.Visibility 0所有用户 1自己用户
+     * @returns 
+     */
+    getMyFrameList:params=>{
+        return http.get('/chart_framework/list',params)
+    },
+
+}
 
 export {
 	dataBaseInterface,
 	mychartInterface,
+	chartFrameInterface
 }

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

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

+ 85 - 0
src/api/modules/smartReport.js

@@ -0,0 +1,85 @@
+import http from "@/api/http.js"
+
+//智能研报模块
+
+const apiSmartReport={
+    //报告列表
+    reportList:params=>{
+        return http.get('/smart_report/list',params)
+    },
+
+    //分类数据
+    classifyList:params=>{
+        return http.get('/classify/list',params)
+    },
+
+    //删除报告
+    delReport:params=>{
+        return http.post('/smart_report/remove',params)
+    },
+
+    //报告推送
+    reportMsgSend:params=>{
+        return http.post('/smart_report/send_msg',params)
+    },
+
+    // 作者
+    reportAuthor:params=>{
+        return http.get('/report/author',params)
+    },
+
+    //新增报告
+    reportAdd:params=>{
+        return http.post('/smart_report/add',params)
+    },
+
+    //编辑报告
+    reportEdit:params=>{
+        return http.post('/smart_report/edit',params)
+    },
+
+    //报告详情
+    reportDetail:params=>{
+        return http.get('/smart_report/detail',params)
+    },
+
+    //保存报告内容
+    saveReportContent:params=>{
+        return http.post('/smart_report/save_content',params)
+    },
+
+    //定时发布报告
+    prePublishReport:params=>{
+        return http.post('/smart_report/pre_publish',params)
+    },
+
+    //发布/取消发布报告
+    publishReport:params=>{
+        return http.post('/smart_report/publish',params)
+    },
+
+    //编辑状态
+    markReport:params=>{
+        return http.post('/smart_report/mark_edit',params)
+    },
+
+    //音频上传
+    voiceupload:params=>{
+        return http.post('/smart_report/voice_upload',params)
+    },
+
+    //报告导出图片
+    getReportImg:params=>{
+        return http.get('/smart_report/detail_img',params)
+    },
+
+    //获取上期已发布报告
+    getLastReport:params=>{
+        return http.get('/smart_report/last_published_report',params)
+    }
+
+}
+
+export {
+	apiSmartReport
+}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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


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


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


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


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


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


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


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


BIN
src/assets/img/ppt_m/add_first.png


BIN
src/assets/img/smartReport/bg01.png


BIN
src/assets/img/smartReport/icon01.png


BIN
src/assets/img/smartReport/icon02.png


BIN
src/assets/img/smartReport/icon03.png


BIN
src/assets/img/smartReport/icon04.png


BIN
src/assets/img/smartReport/icon05.png


BIN
src/assets/img/smartReport/icon06.png


BIN
src/assets/img/smartReport/icon07.png


BIN
src/assets/img/smartReport/icon08.png


BIN
src/assets/img/smartReport/icon09.png


BIN
src/assets/img/smartReport/icon10.png


BIN
src/assets/img/smartReport/icon11.png


BIN
src/assets/img/smartReport/icon12.png


BIN
src/assets/img/smartReport/icon13.png


BIN
src/assets/img/smartReport/icon14.png


BIN
src/assets/img/smartReport/icon15.png


BIN
src/assets/img/smartReport/icon16.png


+ 80 - 10
src/routes/modules/chartRoutes.js

@@ -65,12 +65,31 @@ export default [
 		name: 'My ETA',
 		hidden: false,
 		icon_path: require('@/assets/img/home/data_ic.png'),
-		children: [{
+		children: [
+			{
 				path: 'mychart',
 				name: 'My ETA',
 				component: () => import('@/views/mychart_manage/index.vue'),
 				hidden: false,
-			}
+			},
+			{
+				path: 'chartframe',
+				name: '图库框架',
+				component: () => import('@/views/chartFrame_manage/index.vue'),
+				hidden: false,
+			},
+			{
+				path: 'addframe',
+				name: '添加框架',
+				component: () => import('@/views/chartFrame_manage/frameEditor.vue'),
+				hidden: false,
+			},
+			{
+				path: 'editframe',
+				name: '编辑框架',
+				component: () => import('@/views/chartFrame_manage/frameEditor.vue'),
+				hidden: false,
+			},
 		]
 	},
 
@@ -83,24 +102,70 @@ export default [
 		children:[
 			{
 				path:"sheetList",
-				name:"ETA表格",
+				name:"在线Excel",
+				component:()=>import('@/views/datasheet_manage/sheetList.vue')
+			},
+			{
+				path:"sheetTimeList",
+				name:"时间序列表格",
+				component:()=>import('@/views/datasheet_manage/sheetList.vue')
+			},
+			{
+				path:"sheetMixedList",
+				name:"混合表格",
 				component:()=>import('@/views/datasheet_manage/sheetList.vue')
 			},
 			{
 				path:"addSheet",
 				name:"添加表格",
-				component:()=>import('@/views/datasheet_manage/addSheet.vue')
+				component:()=>import('@/views/datasheet_manage/addSheet.vue'),
+				meta: { 
+					pathFrom: "sheetList",
+					pathName: "在线Excel",
+				}
 			},
 			{
 				path:"addCustomSheet",
-				name:"添加表格",
-				component:()=>import('@/views/datasheet_manage/customSheetEdit.vue')
+				name:"添加数据表格",
+				component:()=>import('@/views/datasheet_manage/customSheetEdit.vue'),
+				meta: { 
+					pathFrom: "sheetTimeList",
+					pathName: "时间序列表格",
+				}
 			},
 			{
 				path:"addMixedSheet",
-				name:"添加表格",
-				component:()=>import('@/views/datasheet_manage/mixedSheetEdit.vue')
-			}
+				name:"添加混合表格",
+				component:()=>import('@/views/datasheet_manage/mixedSheetEdit.vue'),
+				meta: { 
+					pathFrom: "sheetMixedList",
+					pathName: "混合表格",
+				}
+			},
+			{
+				path:"editSheetAnalysis",
+				name:"编辑表格",
+				component:()=>import('@/views/datasheet_manage/customAnalysis/edit.vue'),
+				meta: { 
+					pathFrom: "sheetAnalysisList",
+					pathName: "自定义分析",
+				}
+			},
+			{
+				path:"sheetAnalysisList",
+				name:"自定义分析",
+				component:()=>import('@/views/datasheet_manage/customAnalysis/list.vue')
+			},
+			{
+				path:"addAnalysisSheet",
+				name:"上传文件",
+				component:()=>import('@/views/datasheet_manage/customAnalysis/addAnalysisSheet.vue')
+			},
+			{
+				path:"createTaregtBySheet",
+				name:"生成指标",
+				component:()=>import('@/views/datasheet_manage/customAnalysis/addAnalysisSheet.vue')
+			},
 		]
 	},
 
@@ -228,10 +293,15 @@ export default [
 		name:'工具箱',
 		hidden:false,
 		children:[
-			{
+			/* {
 				path: 'positionAnalysisList',
 				name: '持仓列表',
 				component:()=>import('@/views/positionAnalysis_manage/list.vue')
+			}, */
+			{//不要列表页了,但是改path需要动ETA菜单很麻烦,先这样
+				path: 'positionAnalysisList',
+				name: '持仓详情',
+				component:()=>import('@/views/positionAnalysis_manage/detail.vue')
 			},
 			{
 				path: 'positionAnalysisDetail',

+ 17 - 0
src/routes/modules/oldRoutes.js

@@ -52,6 +52,18 @@ export default [
   	name:'AI问答',
   	hidden:false
   },
+  // 智能研报编辑页
+  {
+    path: "/smartReportEdit",
+    name: "智能报告",
+    component: () => import("@/views/smartReport/editReport.vue"),
+  },
+  // 智能研报详情页
+  {
+    path: "/smartReportDetail",
+    name: "智能报告",
+    component: () => import("@/views/smartReport/reportDetail.vue"),
+  },
 
   // 主页
   {
@@ -235,6 +247,11 @@ export default [
         name: "英文品种配置",
         component: () => import("@/views/report_manage/reportVariety.vue"),
       },
+      {
+        path: "smartReportList",
+        name: "智能研报",
+        component: () => import("@/views/smartReport/reportList.vue"),
+      },
     ],
   },
 

+ 65 - 9
src/utils/buttonConfig.js

@@ -34,6 +34,26 @@ export const reportManageBtn={
     reportManage_dayWeekReportAdd:'reportManage:dayWeekReportAdd',//添加晨报周报
     reportManage_reportAdd:'reportManage:reportAdd',//添加研报
 }
+/*
+ *--------智能研报列表----------- 
+ */
+ export const smartReportManageBtn={
+    reportManage_sendMsg:'smartReportManage:sendMsg',//推送消息/已推送消息
+    reportManage_reportView:'smartReportManage:reportView',//研报预览:即是否能点击研报名称跳转预览页面
+    reportManage_reportView_wechartShare:'smartReportManage:reportView:wechartShare',//研报预览页面-微信分享
+    reportManage_reportView_copyWechat:'smartReportManage:reportView:copyWechat',//研报预览页面-复制链接
+    reportManage_reportView_exportImg:'smartReportManage:reportView:exportImg',//研报预览页面-导出图片
+    reportManage_audioDownload:'smartReportManage:audioDownload',//音频下载
+    reportManage_audioUpload:'smartReportManage:audioUpload',//音频上传
+    reportManage_reportDel:'smartReportManage:reportDel',//删除研报
+    reportManage_reportEdit:'smartReportManage:reportEdit',//编辑研报
+    reportManage_cancelPublish:'smartReportManage:cancelPublish',//取消发布
+    reportManage_publish:'smartReportManage:publish',//发布研报
+    reportManage_reportList:'smartReportManage:reportList',//研报列表的选项
+    reportManage_reportList_uv:'smartReportManage:reportList:uv',//研报列表-PV/UV
+    reportManage_reportList_sendTime:'smartReportManage:reportList:sendTime',//研报列表-报告推送时间
+    reportManage_reportAdd:'smartReportManage:reportAdd',//添加研报
+}
 /*
 *--------英文研报列表----------- 
 */
@@ -332,15 +352,23 @@ export const myETAPermission = {
     myChart_classifyOpt_rename:'myChart:classifyOpt:rename',//重命名
     myChart_classifyOpt_delete:'myChart:classifyOpt:delete',//删除
 }
+//图库框架
+export const chartFramePermission={
+    chartframe_public_copyImg:'chartframe:public:copyImg',//公共框架-复制图片
+    chartframe_my_editNode:'chartframe:my:editNode',//我的框架-添加/编辑节点
+    chartframe_my_saveFrame:'chartframe:my:saveFrame',//我的框架-保存框架
+    chartframe_my_editFrame:'chartframe:my:editFrame',//我的框架-添加/编辑框架
+    chartframe_my_delFrame:'chartframe:my:delFrame',//我的框架-删除框架
+    chartframe_my_show:'chartframe:my:show',//我的框架-设置可见权限
+    chartframe_my_rename:'chartframe:my:rename',//我的框架-重命名
+    chartframe_my_copyImg:'chartframe:my:copyImg',//我的框架-复制图片
+    chartframe_my_move:'chartframe:my:move',//我的框架-移动排序
+}
 /*
  * --------------------------------------------------------------------------ETA表格------------------------------------------------
 */
 export const etaTablePermission = {
     /*-----------页面按钮--------- */
-    etaTable_customize:'etaTable:customize',//自定义表格这个按钮显示不显示
-    etaTable_excel:'etaTable:excel',//添加Excel表格这个按钮显示不显示
-    etaTable_classifyOpt_edit:'etaTable:classifyOpt:edit',//添加编辑表格
-    etaTable_classifyOpt_delete:'etaTable:classifyOpt:delete',//删除表格
 
     /*-----------自定义表格--------- */
     /* etaTable_customize_del:'etaTable:customize:del',
@@ -348,22 +376,50 @@ export const etaTablePermission = {
     etaTable_customize_otherSave:'etaTable:customize:otherSave',
     etaTable_customize_refresh:'etaTable:customize:refresh',
     etaTable_customize_edit:'etaTable:customize:edit', */
-    //混合表格
+
+    //混合表格页面
+    etaTable_customize_mix_sheetAdd: 'etaTable:customize:mix:sheetAdd',//添加混合表格按钮
+    etaTable_customize_mix_classifyOpt_edit: 'etaTable:customize:mix:classifyOpt:edit',//混合表格分类操作
+    etaTable_customize_mix_classifyOpt_delete: 'etaTable:customize:mix:classifyOpt:delete',//混合表格分类删除
     etaTable_customize_mix_edit:'etaTable:customize:mix:edit',//编辑
     etaTable_customize_mix_refresh:'etaTable:customize:mix:refresh',//刷新
     etaTable_customize_mix_otherSave:'etaTable:customize:mix:otherSave',//另存为
     etaTable_customize_mix_download:'etaTable:customize:mix:download',//下载
+    etaTable_customize_mix_save:'etaTable:customize:mix:save',//保存
     etaTable_customize_mix_del:'etaTable:customize:mix:del',//删除
-    //数据表格
+
+    //数据表格页面
+    etaTable_customize_data_sheetAdd: 'etaTable:customize:data:sheetAdd',//添加数据表格按钮
+    etaTable_customize_data_classifyOpt_edit: 'etaTable:customize:data:classifyOpt:edit',//数据表格分类操作
+    etaTable_customize_data_classifyOpt_delete: 'etaTable:customize:data:classifyOpt:delete',//数据表格分类删除
     etaTable_customize_data_edit:'etaTable:customize:data:edit',//编辑
     etaTable_customize_data_refresh:'etaTable:customize:data:refresh',//刷新
     etaTable_customize_data_otherSave:'etaTable:customize:data:otherSave',//另存为
     etaTable_customize_data_download:'etaTable:customize:data:download',//下载
     etaTable_customize_data_del:'etaTable:customize:data:del',//删除
-    /*-----------常规表格--------- */
+    etaTable_customize_data_save:'etaTable:customize:data:save',//保存
+
+    /*-----------excel表格页面--------- */
+    etaTable_excel:'etaTable:excel',//添加Excel表格这个按钮显示不显示
+    etaTable_excel_classifyOpt_edit:'etaTable:excel:classifyOpt:edit',//添加编辑表格
+    etaTable_excel_classifyOpt_delete:'etaTable:excel:classifyOpt:delete',//删除表格
     etaTable_excel_del:'etaTable:excel:del',
     etaTable_excel_download:'etaTable:excel:download',
-    etaTable_excel_save:'etaTable:excel:save'
+    etaTable_excel_save:'etaTable:excel:save',//保存
+    etaTable_excel_edit:'etaTable:excel:edit',
+
+    //自定义分析表格页面
+    // etaTable_analysis_sheetAdd: 'etaTable:analysis:sheetAdd',//添加数据表格按钮
+    etaTable_analysis_classifyOpt_edit: 'etaTable:analysis:classifyOpt:edit',//数据表格分类操作
+    etaTable_analysis_classifyOpt_delete: 'etaTable:analysis:classifyOpt:delete',//数据表格分类删除
+    etaTable_analysis_upload:'etaTable:analysis:upload',//上传文件
+    etaTable_analysis_createedb:'etaTable:analysis:createedb',//生成指标
+    etaTable_analysis_refresh:'etaTable:analysis:refresh',//刷新
+    etaTable_analysis_otherSave:'etaTable:analysis:otherSave',//另存为
+    etaTable_analysis_download:'etaTable:analysis:download',//下载
+    etaTable_analysis_del:'etaTable:analysis:del',//删除
+    etaTable_analysis_save:'etaTable:analysis:save',//保存
+    etaTable_analysis_edit:'etaTable:analysis:edit',//编辑
 }
 /*
  * --------------------------------------------------------------------------ETA逻辑------------------------------------------------
@@ -567,7 +623,7 @@ const btnMap  = {
     pptPermission,enPPTPermission,
     dataSourcePermission,
     edbDataPermission,predictEdbPermission,chartLibPermission,
-    myETAPermission,etaTablePermission,
+    myETAPermission,chartFramePermission,etaTablePermission,
     sandboxPermission,semanticPermission,
     statisticPermission,stockPlantPermission,
     productPricePermission,sysDepartPermission,

+ 2 - 0
src/utils/icon.js

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

+ 2 - 2
src/utils/svgToblob.js

@@ -1,10 +1,10 @@
 /* 针对系统中众多svg的图表/沙盘想要复制粘到微信中 */		
   import bus from '@/api/bus.js';
 
-  export const copyBlob = (url,callback=null,ratio=1) => {
+  export const copyBlob = (url,callback=null,ratio=1,urlType='svg') => {
     const copyImg = new Image()
     copyImg.crossOrigin = 'anonymous';
-    copyImg.src = svgToBase64(url);
+    copyImg.src = urlType==='svg'?svgToBase64(url):url;
 
     copyImg.onload = ()=> {
       const canvas = document.createElement('canvas');

+ 1 - 1
src/views/Home.vue

@@ -286,7 +286,7 @@
               :style="!isHaveAside ? 'padding: 0 30px 0 0;' : ''"
             >
               <transition name="fade" mode="out-in">
-                <router-view></router-view>
+                <router-view :key="$route.fullPath"></router-view>
               </transition>
             </el-col>
           </el-row>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -15,7 +15,7 @@
       />
     </el-select>
 
-    <div v-else-if="selectStyleType===2">
+    <div v-else-if="selectStyleType===2" class="database-choose">
       <label>选择指标:</label>
       <el-radio-group v-model="targetType" @change="targetTypeChange">
         <el-radio  

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

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

+ 11 - 13
src/views/dataEntry_manage/databaseList.vue

@@ -141,7 +141,7 @@
 								/>
 								<!-- 查看计算指标 -->
 								<i class="el-icon-view" 
-									v-if="data.EdbType===2&&![58,59,67,68].includes(data.Source)&&isEdbBtnShow('checkCalcChart')" 
+									v-if="data.EdbType===2&&![58,59,67,68,74].includes(data.Source)&&isEdbBtnShow('checkCalcChart')" 
 									@click.stop="viewNode(node,data)"></i>
 								<!-- 查看关联图表 -->
 								<img 
@@ -856,7 +856,7 @@ export default {
 						const {EdbNameEn,EdbName,EdbInfoId,UniqueCode,ClassifyId}=res.Data.Item
 						this.addLabel({code:UniqueCode,id:EdbInfoId,classifyId:ClassifyId,EdbName,EdbNameEn})
 						// 展开目录
-						this.defaultShowNodes=classify_arr.reverse().map(item=>item.UniqueCode)
+						this.defaultShowNodes=classify_arr.map(item=>item.UniqueCode)
 						//设置tree高亮
 						this.$nextTick(()=>{
 							setTimeout(() => {
@@ -1180,8 +1180,9 @@ export default {
 			// console.log(node);
 			this.dialog_title = '编辑';
 			if(data.EdbCode) {
-				/* 编辑指标 */
-				(data.EdbType===1 || [58,59,67,68].includes(data.Source)) && dataBaseInterface.targetDetail({
+				/* 编辑指标 基础弹窗 */
+				
+				(data.EdbType===1 || [58,59,67,68,74].includes(data.Source)) && dataBaseInterface.targetDetail({
 					EdbInfoId: data.EdbInfoId
 				}).then(res => {
 					if(res.Ret === 200) {
@@ -1435,7 +1436,10 @@ export default {
 					this.$message.success('移动成功!')
 				}
 				this.getTreeData()
-				this.getDataList();
+				if(this.selected_edbid){
+					this.getDataList();
+				}
+				
 			})
 		},
 
@@ -1457,7 +1461,7 @@ export default {
 				setTimeout(() => {
 					dropLine.style.top=e.layerY+'px'
 					// console.log(e.layerY,dropLine);
-				}, 10);
+				}, 100);
 			}
 			
 		},
@@ -1471,13 +1475,7 @@ export default {
 		// 树节点展开
 		handleNodeExpand (data) {
 			// 保存当前展开的节点
-			let flag = false
-			this.defaultShowNodes.some(item => {
-				if (item === data.UniqueCode) { // 判断当前节点是否存在, 存在不做处理
-					flag = true
-					return true
-				}
-			})
+			let flag = this.defaultShowNodes.some((item) => item === data.UniqueCode);
 			if (!flag) { // 不存在则存到数组里
 				this.defaultShowNodes.push(data.UniqueCode)
 			}

+ 4 - 0
src/views/dataEntry_manage/mixins/addOreditMixin.js

@@ -313,6 +313,10 @@ export default {
       this.tableData.forEach((item) => {
         let edbData = EdbInfoList.find(_ => _.EdbInfoId===item.EdbInfoId);
         item.DataList = edbData.DataList;
+				//更新起始时间和最近更新时间
+        item.StartDate = edbData.StartDate;
+        item.ModifyTime = edbData.ModifyTime;
+				
         if(edbData.EdbInfoCategoryType===1) item.MoveLatestDate = edbData.MoveLatestDate;
       });
 		},

+ 158 - 24
src/views/datasheet_manage/addSheet.vue

@@ -3,20 +3,18 @@
     <div class="wrap-top">
       <ul class="form-ul">
         <li style="margin-right:30px;">
-          表格名称:
           <el-input
             v-model="sheetForm.name"
             placeholder="请输入表格名称"
             clearable
-            style="width:300px">
+            style="width:240px">
           </el-input>
         </li>
-        <li>
-          表格分类
-          
+        <li>          
           <el-select 
             v-model="sheetForm.classify" 
             placeholder="请选择表格分类"
+            style="width:240px"
             clearable
           >
 							<el-option
@@ -28,14 +26,21 @@
 						</el-select>
         </li>
       </ul>
+      <div v-if="updateTime" style="color:#999999;margin-right: 30px;">最近保存时间:{{ updateTime }}</div>
       <div>
-        <el-button type="primary" size="medium" @click="saveSheetHandle">保存</el-button>
+        <el-button type="primary" size="medium" @click="saveSheetHandle" v-if="hasPermission">保存</el-button>
         <el-button type="primary" size="medium" plain @click="backHandle">返回</el-button>
       </div>
     </div>
     
     <div class="main">
-      <Sheet ref="sheetRef"/>
+      <Sheet ref="sheetRef" :limit="{disabled:false}" :option="this.option" v-if="sheetInit" @updated="autoSaveFun"
+      :sheetInfo="{
+        ExcelInfoId: sheetForm.infoId,
+        ExcelName: sheetForm.name,
+        ExcelClassifyId: sheetForm.classify,
+        Source: sheetForm.source
+      }" />
     </div>
   </div>
 </template>
@@ -48,14 +53,56 @@ export default {
   components: { Sheet },
   data() {
     return {
+      sheetId: this.$route.query.id || '',
+      isCanEdit:false,
       sheetForm: {},
-      classifyArr: []
+      classifyArr: [],
+      sheetInit:false,
+      option:{},
+      updateTime:'',
+      sheetButton:'',
+      cancelAutoSave:false
+    }
+  },
+  beforeRouteEnter(to, from, next) {
+    if(to.query.id){
+      to.matched[1].name=`编辑表格`
+    }else{
+      to.matched[1].name='添加表格'
+    }
+    next()
+  },
+  beforeRouteLeave(to,from,next){
+    if(to.path!='/addsheet'){
+      this.markFinishStatus()
+    }
+    next()
+  },
+  watch:{
+    sheetForm:{
+      handler(newVal){
+        console.log(this.sheetInit,this.sheetId);
+        if(this.sheetId && this.sheetInit) this.autoSaveFun()
+      },
+      deep:true
+    }
+  },
+  computed:{
+    hasPermission(){
+      // console.log(this.sheetButton,'sheetButton');
+      return this.sheetButton?
+            this.permissionBtn.isShowBtn('etaTablePermission','etaTable_excel_save')&&this.sheetButton.OpButton:
+            this.permissionBtn.isShowBtn('etaTablePermission','etaTable_excel_save')
     }
   },
   methods: {
 
     backHandle() {
-      window.close();
+      // if(this.sheetId){
+      //   this.$router.back()
+      // }else{
+        window.close();
+      // }
     },
 
     /* 获取分类 */
@@ -67,12 +114,76 @@ export default {
       })
     },
 
+    /* 获取表格详情 */
+    async getDetail() {
+      if(!this.sheetId){
+        this.sheetInit=true
+        return
+      }
+
+      const res = await sheetInterface.sheetDetail({
+				ExcelInfoId: Number(this.sheetId)
+			})
+
+      if(res.Ret !== 200)  return
+
+      this.isCanEdit = res.Data.CanEdit
+      if(!res.Data.CanEdit){
+        this.$message.warning(`${res.Data.Editor}正在编辑中`)
+        setTimeout(()=>{
+          this.backHandle()
+        },1000)
+        return 
+      }
+      const { ExcelInfoId,ExcelName,ExcelClassifyId,ExcelType,ModifyTime,Content,Source} = res.Data;
+      this.sheetForm = {
+        infoId:ExcelInfoId,
+        name: ExcelName,
+        classify: ExcelClassifyId,
+        sheetType: ExcelType,
+        source:Source
+      }
+      this.updateTime =  this.$moment(ModifyTime).format('YYYY-MM-DD HH:mm:ss')
+
+      this.option={
+        data: [{
+          ...JSON.parse(Content),
+          scrollTop: 0,
+          scrollLeft: 0
+        }]
+      }
+
+      this.$nextTick(()=>{
+        this.sheetInit=true
+      })
+
+    },
+    autoSaveFun:_.debounce(async function(){
+      if(!this.sheetId && this.sheetInit || this.cancelAutoSave) return
+      const { name,classify,infoId } = this.sheetForm;
+      luckysheet.exitEditMode()
+      let data = luckysheet.getAllSheets()[0];
+      if(!name || !classify) return this.$message.warning(name ? '请选择表格分类' : '请输入表格名称')
+      if(!data.celldata.length) return this.$message.warning('请输入表格内容');
+      let params={
+        ExcelInfoId:infoId,
+        ExcelName: name,
+        ExcelClassifyId: classify,
+        ExcelImage: "",
+        Content: JSON.stringify(data)
+      }
+      const res = await sheetInterface.sheetEdit(params)
+      if(res.Ret !==200) return
+      this.updateTime = this.$moment().format('YYYY-MM-DD HH:mm:ss')
 
+      // console.log("自动保存");
+    },1500),
     /* 保存表格 */
     saveSheetHandle: _.debounce(async function() {
-      const { name,classify } = this.sheetForm;
+      const { name,classify} = this.sheetForm;
       luckysheet.exitEditMode()
-      let data = luckysheet.getAllSheets()[0]
+      //结构类型乱飘 强制定义下
+      let data = {...luckysheet.getAllSheets()[0],status:Number(luckysheet.getAllSheets()[0].status)}
       if(!name || !classify) return this.$message.warning(name ? '请选择表格分类' : '请输入表格名称')
       if(!data.celldata.length) return this.$message.warning('请输入表格内容');
 
@@ -89,31 +200,53 @@ export default {
 			const { Data } = await sheetInterface.uploadImg(form)
 
       data.luckysheet_select_save = [];
-      const res = await sheetInterface.sheetAdd({
+      let params={
         ExcelName: name,
         ExcelClassifyId: classify,
         ExcelImage: Data.ResourceUrl,
         Content: JSON.stringify(data)
-      })
-      this.loading.close()
-      if(res.Ret !== 200) return
+      }
+      let isAdd = this.sheetId?false:true
+      const res = this.sheetId
+      ? await sheetInterface.sheetEdit({ ExcelInfoId: Number(this.sheetId),...params })
+      : await sheetInterface.sheetAdd(params)
 
+      this.loading.close()
+      if(res.Ret !==200) return
+      this.updateTime = this.$moment().format('YYYY-MM-DD HH:mm:ss')
+      
+      this.sheetId = this.sheetId || res.Data.ExcelInfoId;
       this.$message.success(res.Msg);
+      if(isAdd){
+        this.$router.replace({path:'/addsheet',query:{id:this.sheetId}})
+        this.cancelAutoSave=true
+      }
 
-      const { ExcelInfoId, UniqueCode } = res.Data;
+
+      // const { ExcelInfoId, UniqueCode } = res.Data;
       
-      this.$router.replace({
-        path: '/sheetList',
-        query: {
-          code: UniqueCode,
-          id: ExcelInfoId
-        }
-      })
+      // this.$router.replace({
+      //   path: '/sheetList',
+      //   query: {
+      //     code: UniqueCode,
+      //     id: ExcelInfoId
+      //   }
+      // })
     },300),
-    
+    markFinishStatus(){
+      if((!this.sheetId) || (!this.isCanEdit)) return
+      sheetInterface.markSheetEditStatus({ExcelInfoId: +this.sheetId,Status:2}).then(res=>{
+        if(res.Ret != 200) return 
+      })
+    }
   },
   mounted() {
+    this.getDetail()
     this.getClassify();
+    window.addEventListener('beforeunload',this.markFinishStatus)
+  },
+  beforeDestroy(){
+    window.removeEventListener('beforeunload',this.markFinishStatus)
   }
 }
 </script>
@@ -121,6 +254,7 @@ export default {
 *{ box-sizing: border-box; }
 .addSheet-wrap {
   min-height: calc(100vh - 120px);
+  min-width: 1000px;
   .wrap-top {
     display: flex;
     justify-content: space-between;

+ 70 - 24
src/views/datasheet_manage/common/option.js

@@ -1,11 +1,14 @@
 
 /*  初始化  
-  options 用来初始化数据用 
-  data 初始化数据 [{celldata}]
+  options 其他配置 包括初始化数据 data:[{ celldata:[] }]
   sheetInfo 表格id相关信息 用来内容hooks变化时保存草稿
+  limit 限制性数据
+  callbackItems 回调函数组成的对象
 */
 import * as sheetInterface from '@/api/modules/sheetApi.js';
-export const initSheet = (container,options={},sheetInfo={}) =>  {
+import { Message } from 'element-ui';
+
+export function initSheet(container,options={},sheetInfo={},limit,callbackItems) {
   const configOpt = {
     container,
     lang: 'zh', // 设定表格语言
@@ -18,28 +21,59 @@ export const initSheet = (container,options={},sheetInfo={}) =>  {
       postil:  false, //'批注'
 		},
     cellRightClickConfig: {
+      copy:!limit.disabled,
+      copyAs:!limit.disabled,
       chart: false, // 图表生成
       image: false, // 插入图片
       link: false, // 插入链接
     },
-    data: [{
-      ...options,
-      scrollTop: 0,
-      scrollLeft: 0
-    }],
+    allowCopy:!limit.disabled,//没效果
     hook: {
+      cellEditBefore:(range)=>{
+        if(limit.disabled){
+          Message.warning("当前不可编辑")
+          setTimeout(()=>{
+            luckysheet.exitEditMode();
+          },0)
+        }
+      },
+      cellUpdateBefore:()=>{
+        if(limit.disabled){
+          // 不可编辑
+          return false
+        }
+      },
+      // rangeCopyBefore:(range,data)=>{
+      //   // 不触发
+      //   console.log(range,data,'range,data','rangeCopyBefore');
+      // },
+      // rangeCopyAfter:(range,data)=>{
+      //   // 不触发
+      //   console.log(range,data,'range,data','rangeCopyAfter');
+      // },
       updated: (a,b,c,d,e)=> {
-        let data = luckysheet.getAllSheets()[0];
-        data.luckysheet_select_save = [];
-        const { ExcelInfoId,ExcelName,ExcelClassifyId } = sheetInfo;
-        ExcelInfoId && sheetInterface.sheetDrafSave({
-          ExcelInfoId,
-          ExcelName,
-          ExcelClassifyId,
-          Content: JSON.stringify(data)
-        })
-      }
-    }
+        if(limit.disabled){
+          Message.warning("当前不可编辑")
+          luckysheet.undo()
+          return 
+        }
+        // console.log(callbackItems);
+        callbackItems.updated()
+        //草稿
+        if(sheetInfo.Source&&sheetInfo.Source===1) {
+          let data = luckysheet.getAllSheets()[0];
+          data.luckysheet_select_save = [];
+          const { ExcelInfoId,ExcelName,ExcelClassifyId } = sheetInfo;
+          ExcelInfoId && sheetInterface.sheetDrafSave({
+            ExcelInfoId,
+            ExcelName,
+            ExcelClassifyId,
+            Content: JSON.stringify(data)
+          })
+        }
+      },
+    },
+    ...options,
   }
 
   luckysheet.create(configOpt)
@@ -49,12 +83,24 @@ export const initSheet = (container,options={},sheetInfo={}) =>  {
 /* 保存表格关联截图 手动选区截图再清空选区 */
 export const getSheetImage = (data) => {
   const { celldata } = data;
-  
-  const r_arr = celldata.map(_ => _.c);
-  let r_start = celldata[0].r,
-    r_end = celldata[celldata.length-1].r,
-    c_start = Math.min(...r_arr),
+
+  //超过1000个就不遍历了
+  let r_start,r_end,c_start,c_end;
+  if(celldata.length > 1000) {
+    const splitData = celldata.slice(0,1000);
+    const r_arr = splitData.map(_ => _.c);
+    r_start = splitData[0].r;
+    r_end = splitData[splitData.length-1].r;
+    c_start = Math.min(...r_arr);
     c_end = Math.max(...r_arr);
+
+  }else {
+    const r_arr = celldata.map(_ => _.c);
+    r_start = celldata[0].r;
+    r_end = celldata[celldata.length-1].r;
+    c_start = Math.min(...r_arr);
+    c_end = Math.max(...r_arr);
+  }
   
   luckysheet.setRangeShow({row:[r_start,r_end],column:[c_start,c_end]},{show: false})
   let img = luckysheet.getScreenshot()

+ 57 - 3
src/views/datasheet_manage/components/CustomTable.vue

@@ -418,6 +418,31 @@ export default {
       this.$nextTick(() => {
         resetStyle();
       })
+    },
+    // 'config.data':{
+    //   handler(value){
+    //     console.log(value,'valuevaluevalue');
+    //     if(!this.disabled && this.hasInit){
+    //       this.$emit("autoSave")
+    //     }
+    //   },
+    //   deep:true
+    // },
+    'config.textRowData':{
+      handler(value){
+        if(!this.disabled && this.hasInit){
+          this.$emit("autoSave")
+        }
+
+      },
+      deep:true
+    },
+    'config.order':{
+      handler(value){
+        if(!this.disabled && this.hasInit){
+          this.$emit("autoSave")
+        }
+      }
     }
   },
   components: {addDateCellDia,mDialog},
@@ -467,7 +492,9 @@ export default {
 
       //指标别名弹窗
       isEditEdbAliasDialog: false,
-      editEdb: {}
+      editEdb: {},
+
+      hasInit:false
     };
   },
   methods: {
@@ -493,6 +520,9 @@ export default {
             
         })
       }
+      if(!this.disabled && this.hasInit){
+        this.$emit("autoSave")
+      }
     },
 
     /* 改变排序 */
@@ -505,6 +535,9 @@ export default {
           ? edb.Data.sort((x,y) => new Date(y.DataTime)-new Date(x.DataTime))
           : edb.Data.sort((x,y) => new Date(x.DataTime)-new Date(y.DataTime))
       })
+      if(!this.disabled && this.hasInit){
+        this.$emit("autoSave")
+      }
     },
 
     // 单击指标名称修改别名
@@ -522,6 +555,9 @@ export default {
     /* 保存别名 */
     saveEdbAlias() {
       this.config.data.find(_ =>_.EdbInfoId === this.editEdb.EdbInfoId).EdbAliasName = this.editEdb.EdbAliasName;
+      if(!this.disabled && this.hasInit){
+        this.$emit("autoSave")
+      }
       this.isEditEdbAliasDialog = false;
     },
 
@@ -578,6 +614,9 @@ export default {
           ? [...edb.Data,...edb_concat_data].sort((x,y) => new Date(y.DataTime)-new Date(x.DataTime))
           : [...edb.Data,...edb_concat_data].sort((x,y) => new Date(x.DataTime)-new Date(y.DataTime))
       })
+      if(!this.disabled && this.hasInit){
+        this.$emit("autoSave")
+      }
     },
 
     /* 输入框失焦 存值或公式计算 val,行标 列标 指标信息 */
@@ -588,6 +627,9 @@ export default {
       if(!value){
         cell.DataType = 3;
         cell.ShowValue = '';
+        if(!this.disabled && this.hasInit){
+          this.$emit("autoSave")
+        }
         return
       }
 
@@ -601,7 +643,10 @@ export default {
         cell.ShowValue = value
       }
       this.$set(cell,'CanEdit',false)
-      
+
+      if(!this.disabled && this.hasInit){
+        this.$emit("autoSave")
+      }
     },
 
     /* 输入公式的计算值 */
@@ -694,7 +739,9 @@ export default {
 
         
       }
-
+      if(!this.disabled && this.hasInit){
+        this.$emit("autoSave")
+      }
       this.hideContextMenu()
     },
 
@@ -745,6 +792,7 @@ export default {
 
     /* 详情initData */
     initSheetData(initData) {
+      this.hasInit=false
       if(initData.Data) {
         const { Data,Sort,TextRowData } = initData;
 
@@ -752,6 +800,9 @@ export default {
         this.config.data = Data;
         this.config.textRowData = TextRowData;
       }
+      this.$nextTick(()=>{
+        this.hasInit=true
+      })
     },
 
     /* 跳转到指标库 */
@@ -774,6 +825,9 @@ export default {
     /* 清空所有数据 */
     reset() {
       this.config.data = [];
+      if(!this.disabled && this.hasInit){
+        this.$emit("autoSave")
+      }
       this.config.textRowData = [];
     },
 

+ 25 - 1
src/views/datasheet_manage/components/MixedTable.vue

@@ -171,6 +171,24 @@ export default {
       return getRowHeaderCode(total_length);
     },
   },
+  watch:{
+    'config.data':{
+      handler(newVal){
+        if(!this.disabled && this.hasInit){
+          this.$emit("autoSave")
+        }
+      },
+      deep:true
+    },
+    insertRelationArr:{
+      handler(newVal){
+        if(!this.disabled && this.hasInit){
+          this.$emit("autoSave")
+        }
+      },
+      deep:true
+    },
+  },
   data() {
     return {
       config: {
@@ -188,7 +206,8 @@ export default {
 
       isSelectTargetValueDialog: false,
 
-      cellrelationEdbInfo: {}
+      cellrelationEdbInfo: {},
+      hasInit:false,
     };
   },
   mounted() {
@@ -685,6 +704,8 @@ export default {
 
     /* 初始化8行5列 */
     initData(initData=null) {
+      console.log('initData');
+      this.hasInit=false
       if(initData) {
         const { CellRelation,Data } = initData;
         this.config.data = Data;
@@ -702,6 +723,9 @@ export default {
           }));
         });
       }
+      this.$nextTick(()=>{
+        this.hasInit=true
+      })
     },
   },
 };

+ 31 - 15
src/views/datasheet_manage/components/SheetExcel.vue

@@ -8,34 +8,42 @@ import { initSheet } from '../common/option';
 export default {
   props: {
     option: {
-      type: String,
+      type: Object,
       default: ''
     },
     sheetInfo: {
       type: Object,
       default: ()=>{}
-    }
+    },
+    limit: {
+      type: Boolean,
+      default: ()=>{
+        return {disabled:false}
+      }
+    },
   },
-  // watch: {
-  //   option: {
-  //     handler(newval) {
-  //       console.log(newval)
-  //       this.optionData = newval ? JSON.parse(newval) : {}
-  //       this.init();
-  //     },
-  //     deep:true
-  //   }
-  // },
   data() {
     return {
-      // optionData: {},
       sheetObj: {}
     }
   },
   methods: {
     init() {
-      let optionData = this.option ? JSON.parse(this.option) : {};
-      initSheet('sheet-container',optionData,this.sheetInfo)
+      let optionData = this.option ? this.option : {};
+      let callbackItems={updated:this.updateEmit}
+      initSheet('sheet-container',optionData,this.sheetInfo,this.limit,callbackItems)
+    },
+    copyDisable(e){
+      // 变向的禁止复制
+      // console.log(e.target.value && e.target.value.indexOf('lucksheet'));
+      if(e.target.value && e.target.value.indexOf('lucksheet')){
+        luckysheet.enterEditMode();
+        // luckysheet.exitEditMode();
+        return false
+      }
+    },
+    updateEmit(){
+      this.$emit("updated")
     }
   },
   destroyed() {
@@ -43,7 +51,15 @@ export default {
   },
   mounted() {
     this.init();
+    if(this.limit.disabled){
+      document.addEventListener('copy',this.copyDisable)
+    }
   },
+  beforeDestroy(){
+    if(this.limit.disabled){
+      document.removeEventListener('copy',this.copyDisable)
+    }
+  }
 }
 </script>
 <style scoped lang="scss">

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -0,0 +1,292 @@
+<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>

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

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

+ 197 - 82
src/views/datasheet_manage/customSheetEdit.vue

@@ -1,75 +1,79 @@
 <template>
   <div class="customSheet-wrap">
     <div class="wrap-top">
-      <ul class="form-ul">
-        <li>
-          <selectTarget
-            ref="selectRef"
-            @select="handleSelectTarget"
-            :selectStyleType="2"
-          />
-        </li>
-        <li>
-          表格名称
-          <el-input
-            v-model="sheetForm.name"
-            placeholder="请输入表格名称"
-            style="width:200px"
-            clearable>
-          </el-input>
-        </li>
-        <li>
-          表格分类
-          <el-select 
-            v-model="sheetForm.classify" 
-            placeholder="请选择表格分类"
-            clearable
-          >
-							<el-option
-								v-for="item in classifyArr"
-								:key="item.ExcelClassifyId"
-								:label="item.ExcelClassifyName"
-								:value="item.ExcelClassifyId"
-              />
-						</el-select>
-        </li>
-        <li>
-          表格类型
-          <el-select 
-            v-model="sheetForm.sheetType"
-            style="width:150px;"
-          >
-							<el-option
-								v-for="item in sheetTypeOption"
-								:key="item.key"
-								:label="item.label"
-								:value="item.key"
-              />
-						</el-select>
-        </li>
-        <li>
-          表格说明
-          <el-tooltip
-            effect="dark"
-          >
-            <div
-              slot="content"
-              v-html="rules"
-              style="line-height: 20px;width:350px"
-            ></div>
-            <i class="el-icon-question" />
-          </el-tooltip>
-        </li>
-      </ul>
-      <div>
-        <el-button type="primary" size="medium" @click="saveSheetHandle">保存</el-button>
-        <el-button type="primary" size="medium" plain @click="backHandle">返回</el-button>
+      <div class="database-select">
+        <selectTarget
+          ref="selectRef"
+          @select="handleSelectTarget"
+          :selectStyleType="2"
+        />
+        <div>
+          <div v-if="saveTime" style="color:#999999;margin-right:30px ;">
+            最近保存时间:{{ saveTime }}
+          </div>
+          <el-button type="primary" size="medium" @click="saveSheetHandle" v-if="hasPermission">保存</el-button>
+          <el-button type="primary" size="medium" plain @click="backHandle">返回</el-button>
+        </div>
+      </div>
+      <div class="wrap-top-bottom">
+        <ul class="form-ul">
+          <li>
+            <el-input
+              v-model="sheetForm.name"
+              placeholder="请输入表格名称"
+              style="width:240px"
+              clearable>
+            </el-input>
+          </li>
+          <li>
+            <el-select 
+              v-model="sheetForm.classify" 
+              placeholder="请选择表格分类"
+              style="width:240px;"
+              clearable
+            >
+                <el-option
+                  v-for="item in classifyArr"
+                  :key="item.ExcelClassifyId"
+                  :label="item.ExcelClassifyName"
+                  :value="item.ExcelClassifyId"
+                />
+              </el-select>
+          </li>
+          <li>
+            <el-select 
+              v-model="sheetForm.sheetType"
+              style="width:240px;"
+            >
+                <el-option
+                  v-for="item in sheetTypeOption"
+                  :key="item.key"
+                  :label="item.label"
+                  :value="item.key"
+                />
+              </el-select>
+          </li>
+          <li>
+            表格说明
+            <el-tooltip
+              effect="dark"
+            >
+              <div
+                slot="content"
+                v-html="rules"
+                style="line-height: 20px;width:350px"
+              ></div>
+              <i class="el-icon-question" />
+            </el-tooltip>
+          </li>
+        </ul>
       </div>
     </div>
     
     <CustomTable
       :sheetType="sheetForm.sheetType"
       ref="customTableRef"
+      @autoSave="autoSaveFun"
     />
   </div>
 </template>
@@ -90,6 +94,30 @@ export default {
     }
     next()
   },
+  watch:{
+    sheetForm:{
+      handler(newVal){
+        console.log(newVal,'newVal','newVal');
+        if(this.sheetInit && this.sheetId) this.autoSaveFun()
+        
+      },
+      deep:true
+    }
+  },
+  computed:{
+    hasPermission(){
+      // console.log(this.sheetButton,'sheetButton');
+      return this.sheetButton?
+            this.permissionBtn.isShowBtn('etaTablePermission','etaTable_customize_data_save')&&this.sheetButton.OpButton:
+            this.permissionBtn.isShowBtn('etaTablePermission','etaTable_customize_data_save')
+    }
+  },
+  beforeRouteLeave(to,from,next){
+    if(to.path!='/addMixedSheet'){
+      this.markFinishStatus()
+    }
+    next()
+  },
   data() {
     return {
       sheetId: this.$route.query.id || '',
@@ -103,13 +131,19 @@ export default {
         { key: 1,label: '指标列+日期行' },
         { key: 2,label: '指标行+日期列' },
       ],
-
+      saveTime:"",
+      sheetInit:false,
+      isCanEdit:false,
+      sheetButton:'',
+      // 取消自动保存,比如返回的时候
+      cancelAutoSave:false
     }
   },
   methods: {
 
     backHandle() {
-      this.$router.go(-1)
+      this.$router.back()
+      this.cancelAutoSave=true
     },
 
     /* 获取表格详情 */
@@ -121,14 +155,26 @@ export default {
 			})
 
       if(res.Ret !== 200)  return
-      const { ExcelName,ExcelClassifyId,ExcelType,TableData } = res.Data;
-      
+      this.isCanEdit = res.Data.CanEdit
+      if(!res.Data.CanEdit){
+        this.$message.warning(`${res.Data.Editor}正在编辑中`)
+        setTimeout(()=>{
+          this.backHandle()
+        },1000)
+        return 
+      }
+      const { ExcelName,ExcelClassifyId,ExcelType,TableData,ModifyTime,Button} = res.Data;
+      this.sheetButton=Button
       this.sheetForm = {
         name: ExcelName,
         classify: ExcelClassifyId,
         sheetType: ExcelType
       }
+      this.saveTime =  this.$moment(ModifyTime).format('YYYY-MM-DD HH:mm:ss')
 
+      this.$nextTick(()=>{
+        this.sheetInit=true
+      })
       this.$refs.customTableRef.initSheetData(TableData);
     },
 
@@ -165,14 +211,32 @@ export default {
 
     /* 获取分类 */
     getClassify() {
-      sheetInterface.excelClassifyOne().then(res => {
+      sheetInterface.excelClassifyOne({Source: 2}).then(res => {
         if(res.Ret !==200) return
         
         this.classifyArr = res.Data.AllNodes || [];
       })
     },
 
-
+    autoSaveFun:_.debounce(async function(){
+      // console.log("触发自动",this.cancelAutoSave);
+      if(!this.sheetId || this.cancelAutoSave) return 
+      const { name,classify,sheetType } = this.sheetForm;
+      if(!name || !classify) return this.$message.warning(name ? '请选择表格分类' : '请输入表格名称')
+      if(!document.getElementsByClassName('table')[0]) return this.$message.warning('请添加表格')
+      let params = {
+        ExcelName: name,
+        ExcelType: sheetType,
+        ExcelClassifyId: classify,
+        ExcelImage:'',
+        Source: 3,
+        TableData: this.$refs.customTableRef.getSaveParams()
+      };
+      console.log("自动保存");
+      const res = await sheetInterface.sheetEdit({ ExcelInfoId: Number(this.sheetId),...params })
+      if(res.Ret !==200) return
+      this.saveTime = this.$moment().format('YYYY-MM-DD HH:mm:ss')
+    },1500),
     /* 保存表格 */
     saveSheetHandle: _.debounce(async function() {
       const { name,classify,sheetType } = this.sheetForm;
@@ -203,15 +267,20 @@ export default {
         TableData: this.$refs.customTableRef.getSaveParams()
       };
 
+      let isAdd = this.sheetId?false:true
+
       const res = this.sheetId
       ? await sheetInterface.sheetEdit({ ExcelInfoId: Number(this.sheetId),...params })
       : await sheetInterface.sheetAdd(params)
 
       if(res.Ret !==200) return
-      
+
       this.sheetId = this.sheetId || res.Data.ExcelInfoId;
       this.$message.success('保存成功')
+      this.saveTime =  this.$moment().format('YYYY-MM-DD HH:mm:ss')
       
+      isAdd && this.$router.replace({path:'/addCustomSheet',query:{id:this.sheetId}})
+
       // this.$router.replace({
       //   path: '/sheetList',
       //   query: {
@@ -220,11 +289,22 @@ export default {
       //   }
       // })
     },300),
-    
+    markFinishStatus(){
+      if((!this.sheetId) || (!this.isCanEdit)) return
+      sheetInterface.markSheetEditStatus({ExcelInfoId: +this.sheetId,Status:2}).then(res=>{
+        if(res.Ret != 200) return 
+      })
+    }
   },
   created() {
     this.getClassify();
     this.getDetail();
+  },
+  mounted(){
+    window.addEventListener('beforeunload',this.markFinishStatus)
+  },
+  beforeDestroy(){
+    window.removeEventListener('beforeunload',this.markFinishStatus)
   }
 }
 </script>
@@ -232,30 +312,65 @@ export default {
 *{ box-sizing: border-box; }
 .customSheet-wrap {
   min-height: calc(100vh - 120px);
+  min-width: 1020px;
   .wrap-top {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
+    // display: flex;
+    // justify-content: space-between;
+    // align-items: center;
     margin-bottom: 20px;
     padding: 20px;
     background: #fff;
     border: 1px solid #ececec;
     border-radius: 4px;
     box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
-    display: flex;
+    // display: flex;
     z-index: 1;
-    .form-ul {
-      flex: 1;
+    .database-select{
       display: flex;
       align-items: center;
-      li {
-        margin: 0 10px;
-        padding-top: 40px;
-        &:first-child {
-          padding-top: 0;
+      margin-bottom: 16px;
+      div{
+        display: flex;
+        align-items: center;
+      }
+    }
+    .wrap-top-bottom{
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      .form-ul {
+        flex: 1;
+        display: flex;
+        align-items: center;
+        li {
+          margin: 0 10px;
+          // padding-top: 40px;
+          &:first-child {
+            padding-top: 0;
+            margin:0
+          }
         }
       }
     }
+
   }
 }
+</style>
+<style lang="scss">
+  .database-select{
+    .el-select{
+      margin-top: 0!important;
+      margin-left: 20px;
+      .el-input{
+        width: 240px;
+      }
+    }
+    .database-choose{
+      display: flex;
+      align-items: center;
+      label,div{
+        white-space: nowrap;
+      }
+    }
+  }
 </style>

+ 89 - 17
src/views/datasheet_manage/mixedSheetEdit.vue

@@ -3,20 +3,19 @@
     <div class="wrap-top">
       <ul class="form-ul">
         <li>
-          表格名称
           <el-input
             v-model="sheetForm.name"
             placeholder="请输入表格名称"
-            style="width:200px"
+            style="width:240px"
             clearable>
           </el-input>
         </li>
         <li>
-          表格分类
           <el-select 
             v-model="sheetForm.classify" 
             placeholder="请选择表格分类"
             clearable
+            style="min-width:240px"
           >
 							<el-option
 								v-for="item in classifyArr"
@@ -41,13 +40,13 @@
         </li>
       </ul>
       <div>
-        <span v-if="updateTime">上次保存时间:{{updateTime}}</span>
-        <el-button type="primary" size="medium" @click="saveSheetHandle" style="margin-left:10px">保存</el-button>
+        <span v-if="updateTime" style="color:#999999 ;">最近保存时间:{{updateTime}}</span>
+        <el-button type="primary" size="medium" @click="saveSheetHandle" style="margin-left:10px" v-if="hasPermission">保存</el-button>
         <el-button type="primary" size="medium" plain @click="backHandle">返回</el-button>
       </div>
     </div>
     
-    <MixedTable
+    <MixedTable @autoSave="autoSaveFun"
       ref="mixedTableRef"
     />
   </div>
@@ -69,6 +68,30 @@ export default {
     }
     next()
   },
+  watch:{
+    sheetForm:{
+      handler(newVal){
+        // console.log(newVal,'newVal','newVal');
+        if(this.sheetInit && this.sheetId) this.autoSaveFun()
+        
+      },
+      deep:true
+    }
+  },
+  computed:{
+    hasPermission(){
+      // console.log(this.sheetButton,'sheetButton');
+      return this.sheetButton?
+              this.permissionBtn.isShowBtn('etaTablePermission','etaTable_customize_mix_save')&&this.sheetButton.OpButton:
+              this.permissionBtn.isShowBtn('etaTablePermission','etaTable_customize_mix_save')
+    }
+  },
+  beforeRouteLeave(to,from,next){
+    if(to.path!='/addMixedSheet'){
+      this.markFinishStatus()
+    }
+    next()
+  },
   data() {
     return {
       sheetId: this.$route.query.id || '',
@@ -80,19 +103,24 @@ export default {
       sheetForm: {
         sheetType: 1
       },
+      sheetButton:'',
+      sheetInit:false,
       sheetTypeOption: [
         { key: 1,label: '指标列+日期行' },
         { key: 2,label: '指标行+日期列' },
       ],
 
-      updateTime: ''
-
+      updateTime: '',
+      isCanEdit:false,
+      // 取消自动保存,比如返回的时候
+      cancelAutoSave:false
     }
   },
   methods: {
 
     backHandle() {
-      this.$router.go(-1)
+      this.cancelAutoSave=true
+      this.$router.back()
     },
 
     /* 获取表格详情 */
@@ -104,12 +132,24 @@ export default {
 			})
 
       if(res.Ret !== 200)  return
-      const { ExcelName,ExcelClassifyId,TableData,ModifyTime } = res.Data;
-      
+      this.isCanEdit = res.Data.CanEdit
+      if(!res.Data.CanEdit){
+        this.$message.warning(`${res.Data.Editor}正在编辑中`)
+        setTimeout(()=>{
+          this.backHandle()
+        },2000)
+        return 
+      }
+
+      const { ExcelName,ExcelClassifyId,TableData,ModifyTime,Button } = res.Data;
+      this.sheetButton=Button
       this.sheetForm = {
         name: ExcelName,
         classify: ExcelClassifyId
       }
+      this.$nextTick(()=>{
+        this.sheetInit=true
+      })
       this.updateTime =  this.$moment(ModifyTime).format('YYYY-MM-DD HH:mm:ss')
 
       this.$refs.mixedTableRef.initData(TableData);
@@ -117,14 +157,34 @@ export default {
 
     /* 获取分类 */
     getClassify() {
-      sheetInterface.excelClassifyOne().then(res => {
+      sheetInterface.excelClassifyOne({Source: 3}).then(res => {
         if(res.Ret !==200) return
         
         this.classifyArr = res.Data.AllNodes || [];
       })
     },
-
-
+    autoSaveFun:_.debounce(async function(){
+      if(!this.sheetId || this.cancelAutoSave) return 
+      const { name,classify,sheetType } = this.sheetForm;
+      if(!name || !classify) return this.$message.warning(name ? '请选择表格分类' : '请输入表格名称')
+      let checkAllEmpty = this.$refs.mixedTableRef.config.data.flat(1).some(_ => _.ShowValue);
+      if(!checkAllEmpty) return this.$message.warning('请输入表格内容')
+      let params = {
+        ExcelName: name,
+        ExcelType: 1,
+        ExcelClassifyId: classify,
+        ExcelImage:'',
+        Source: 3,
+        TableData: {
+          CellRelation: JSON.stringify(this.$refs.mixedTableRef.insertRelationArr),
+          Data: this.$refs.mixedTableRef.config.data
+        }
+      };
+      console.log("自动保存");
+      const res = await sheetInterface.sheetEdit({ ExcelInfoId: Number(this.sheetId),...params })
+      if(res.Ret !==200) return
+      this.updateTime = this.$moment().format('YYYY-MM-DD HH:mm:ss')
+    },1500),
     /* 保存表格 */
     saveSheetHandle: _.debounce(async function() {
 
@@ -158,7 +218,7 @@ export default {
           Data: this.$refs.mixedTableRef.config.data
         }
       };
-
+      let isAdd = this.sheetId?false:true
       const res = this.sheetId
       ? await sheetInterface.sheetEdit({ ExcelInfoId: Number(this.sheetId),...params })
       : await sheetInterface.sheetAdd(params)
@@ -168,19 +228,31 @@ export default {
       
       this.sheetId = this.sheetId || res.Data.ExcelInfoId;
       this.$message.success('保存成功')
-
+      isAdd && this.$router.replace({path:'/addMixedSheet',query:{id:this.sheetId}})
     },300),
-    
+    markFinishStatus(){
+      if((!this.sheetId) || (!this.isCanEdit)) return
+      sheetInterface.markSheetEditStatus({ExcelInfoId: +this.sheetId,Status:2}).then(res=>{
+        if(res.Ret != 200) return 
+      })
+    }
   },
   created() {
     this.getClassify();
     this.getDetail();
+  },
+  mounted(){
+    window.addEventListener('beforeunload',this.markFinishStatus)
+  },
+  beforeDestroy(){
+    window.removeEventListener('beforeunload',this.markFinishStatus)
   }
 }
 </script>
 <style scoped lang="scss">
 *{ box-sizing: border-box; }
 .customSheet-wrap {
+  min-width: 1070px;
   min-height: calc(100vh - 120px);
   .wrap-top {
     display: flex;

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

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

+ 191 - 209
src/views/datasheet_manage/sheetList.vue

@@ -10,20 +10,11 @@
     <div class="data-sheet-main" id="box">
       <div class="main-left left" id="left" v-show="!isSlideLeft">
         <div class="datasheet_top">
-          <el-button v-permission="permissionBtn.etaTablePermission.etaTable_excel"
-            type="primary" style="margin-right:20px" @click="goAddSheetHandle(1)"
+          <el-button v-if="permissionBtn.checkPermissionBtn(permissionBtn.etaTablePermission.etaTable_excel)&&sourceMap[$route.path]===1" type="primary" style="margin-right:20px" @click="goAddSheetHandle"
           >添加Excel表格</el-button >
+          <el-button v-if="permissionBtn.checkPermissionBtn(permissionBtn.etaTablePermission.etaTable_customize_data_sheetAdd)&&sourceMap[$route.path]===2" type="primary" style="margin-right:20px" @click="goAddSheetHandle">添加时间序列表格</el-button >
+          <el-button v-if="permissionBtn.checkPermissionBtn(permissionBtn.etaTablePermission.etaTable_customize_mix_sheetAdd)&&sourceMap[$route.path]===3" type="primary" @click="goAddSheetHandle">添加混合表格</el-button >
 
-          <el-dropdown v-if="isShowDataSheet||isShowMixSheet"
-            @command="goAddSheetHandle">
-            <el-button type="primary">
-              自定义表格<i class="el-icon-arrow-down el-icon--right"></i>
-            </el-button>
-            <el-dropdown-menu slot="dropdown">
-              <el-dropdown-item :command="2" v-if="isShowDataSheet">数据表格</el-dropdown-item>
-              <el-dropdown-item :command="3" v-if="isShowMixSheet">混合表格</el-dropdown-item>
-            </el-dropdown-menu>
-          </el-dropdown>
         </div>
         <div class="search-cont">
           <el-select
@@ -77,7 +68,7 @@
                 placeholder="请输入值"
                 class="label-input"
                 v-model="new_label"
-                v-if="data.isEdit&&permissionBtn.isShowBtn('etaTablePermission','etaTable_classifyOpt_edit')"
+                v-if="data.isEdit&&isSheetBtnShow('classifyOpt_edit')"
                 @blur="changeValue(data)"
               />
               <span
@@ -104,7 +95,7 @@
                   alt=""
                   style="width: 15px; height: 14px; margin-right: 8px"
                   @click.stop="editNode(node, data)"
-                  v-if="!data.ExcelInfoId&&permissionBtn.isShowBtn('etaTablePermission','etaTable_classifyOpt_edit')"
+                  v-if="!data.ExcelInfoId&&isSheetBtnShow('classifyOpt_edit')"
                 />
                 <img
                   slot="reference"
@@ -112,12 +103,12 @@
                   alt=""
                   style="width: 14px; height: 14px"
                   @click.stop="removeNode(node, data)"
-                  v-if="!data.ExcelInfoId&&permissionBtn.isShowBtn('etaTablePermission','etaTable_classifyOpt_delete')"
+                  v-if="!data.ExcelInfoId&&isSheetBtnShow('classifyOpt_delete')"
                 />
               </span>
             </span>
           </el-tree>
-          <div class="noDepart" @click="addLevelOneHandle" v-if="permissionBtn.isShowBtn('etaTablePermission','etaTable_classifyOpt_edit')">
+          <div class="noDepart" @click="addLevelOneHandle" v-if="isSheetBtnShow('classifyOpt_edit')">
             <img
               src="~@/assets/img/set_m/add_ico.png"
               alt=""
@@ -145,10 +136,7 @@
         <!-- 表格详情 -->
         <div class="sheet-detail-wrapper" v-if="select_id">
           <div class="detail-top">
-            <span class="author"
-              >作者:{{ sheetDetailInfo.SysUserRealName }}</span
-            >
-            <el-input
+            <!-- <el-input
               ref="sheetEditTitRef"
               style="width: 400px"
               placeholder="请输入表格名称"
@@ -156,64 +144,68 @@
               v-model="sheet_title"
               v-if="sheetDetailInfo.isEditTit"
               @blur="changeValue(sheetDetailInfo, 'edit-tit')"
-            />
-            <span
+            /> -->
+            <!-- <span
               class="sheet-name"
               @click="editNodeLabel(sheetDetailInfo, 'edit-tit')"
               v-else
             >
               {{ sheetDetailInfo.ExcelName }}
               <i class="el-icon-edit" v-if="sheetDetailInfo.Source === 1" />
-            </span>
-            <ul class="action-ul">
-              <li
-                class="editsty"
-                @click="saveHandle"
-                v-if="
-                  sheetDetailInfo.Source === 1 &&
-                  sheetDetailInfo.Button.OpButton&&permissionBtn.isShowBtn('etaTablePermission','etaTable_excel_save')
-                "
-              >
-                保存
-              </li>
-              <template v-if="[2, 3].includes(sheetDetailInfo.Source)">
+            </span> -->
+            <div class="sheet-name">
+              {{ sheetDetailInfo.ExcelName }}
+            </div>
+            <div class="sheet-anothor-info">
+              <span class="author">作者:{{ sheetDetailInfo.SysUserRealName }}</span>
+              <ul class="action-ul">
+                <li style="color:#999999 ;">最近保存时间:{{ saveTime }}</li>
                 <li
                   class="editsty"
                   @click="goEditHandle"
-                  v-if="sheetDetailInfo.Button.OpButton&&isSheetBtnShow(sheetDetailInfo,'edit')"
+                  v-if="isCreator || 
+                  (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
-                  class="editsty"
-                  @click="refreshSheet"
-                  v-if="sheetDetailInfo.Button.RefreshButton&&isSheetBtnShow(sheetDetailInfo,'refresh')"
-                >
-                  刷新
+                <template v-if="[2, 3].includes(sheetDetailInfo.Source)">
+                  <li
+                    class="editsty"
+                    @click="refreshSheetEdb"
+                    v-if="sheetDetailInfo.Button.RefreshButton&&isSheetBtnShow('refresh')"
+                  >
+                  <img src="~@/assets/img/icons/refresh_blue_new.png"/>
+                    <span>刷新</span>
+                  </li>
+                  <li
+                    class="editsty"
+                    @click="saveOtherHandle"
+                    v-if="sheetDetailInfo.Button.CopyButton&&isSheetBtnShow('otherSave')"
+                  >
+                    <img src="~@/assets/img/icons/save_as_blue_new.png"/>
+                    <span>另存为</span>
+                  </li>
+                </template>
+                <li v-if="isDownLoadShow(sheetDetailInfo)"
+                  class="editsty" @click="downloadExcel(sheetDetailInfo)">
+                  <img src="~@/assets/img/icons/download_blue.png"/>
+                  <span>下载</span>
                 </li>
                 <li
-                  class="editsty"
-                  @click="saveOtherHandle"
-                  v-if="sheetDetailInfo.Button.CopyButton&&isSheetBtnShow(sheetDetailInfo,'otherSave')"
+                  class="deletesty"
+                  v-if="
+                    isCreator || (sheetDetailInfo.Button && sheetDetailInfo.Button.DeleteButton
+                    &&isDeleteShow(sheetDetailInfo))
+                  "
+                  @click="delSheetHandle({cell:sheetDetailInfo, type:'del'})"
                 >
-                  另存为
+                  <img src="~@/assets/img/icons/delete-red.png"/>
+                  <span>删除</span>
                 </li>
-              </template>
-              <li v-if="isDownLoadShow(sheetDetailInfo)"
-                class="editsty" @click="downloadExcel(sheetDetailInfo)">
-                下载
-              </li>
-              <li
-                class="deletesty"
-                v-if="
-                  sheetDetailInfo.Button && sheetDetailInfo.Button.DeleteButton
-                  &&isDeleteShow(sheetDetailInfo)
-                "
-                @click="delSheetHandle(sheetDetailInfo, 'del')"
-              >
-                删除
-              </li>
-            </ul>
+              </ul>
+            </div>
+
           </div>
 
           <!-- 表格 -->
@@ -221,12 +213,14 @@
             <Sheet
               ref="sheetRef"
               v-if="sheetDetailInfo.Source === 1"
-              :option="sheetDetailInfo.Content"
-              :sheetInfo="{
-                ExcelInfoId: sheetDetailInfo.ExcelInfoId,
-                ExcelName: sheetDetailInfo.ExcelName,
-                ExcelClassifyId: sheetDetailInfo.ExcelClassifyId,
+              :option="{
+                data: [{
+                  ...JSON.parse(sheetDetailInfo.Content),
+                  scrollTop: 0,
+                  scrollLeft: 0
+                }]
               }"
+              :limit="{disabled:true}"
             />
 
             <!-- 自定义表格  -->
@@ -245,52 +239,17 @@
           </div>
         </div>
 
-        <!-- 列表 -->
-        <div class="sheet-list-cont" v-else>
-          <span>共{{ sheet_total }}张表格</span>
-          <div class="sheetlist-wrapper" ref="listRef" @scroll="loadMoreHandle">
-            <el-col
-              :span="6"
-              style="margin-bottom: 20px; padding-right: 20px"
-              v-for="cell in sheetList"
-              :key="cell.ExcelInfoId"
-            >
-              <el-card class="sheet-item">
-                <div slot="header" class="item-top">
-                  <span class="text_oneLine">{{ cell.ExcelName }}</span>
-                </div>
-                <img
-                  :src="cell.ExcelImage"
-                  alt=""
-                  class="chart-img"
-                  :height="imgHeight"
-                  @click="detailShowHandle(cell)"
-                />
-                <div class="item-bottom">
-                  <span>创建时间: {{ cell.CreateTime.slice(0, 10) }}</span>
-                  <div>
-                    <span
-                      v-if="isDownLoadShow(cell)"
-                      class="editsty"
-                      style="margin-right: 10px"
-                      @click="downloadExcel(cell)"
-                      >下载</span
-                    >
-                    <span
-                      v-if="isDeleteShow(cell)"
-                      class="deletesty"
-                      @click="delSheetHandle(cell, 'del-list')"
-                      >删除</span
-                    >
-                  </div>
-                </div>
-              </el-card>
-            </el-col>
-          </div>
-          <div v-if="!sheet_total" class="nodata">
-            <tableNoData text="暂无表格"/>
-          </div>
-        </div>
+         <!-- 列表 -->
+        <sheetListWrap
+          v-else
+          :total="sheet_total" 
+          :list="sheetList" 
+          @loadMoreHandle="loadMoreHandle"
+          @detailShowHandle="detailShowHandle"
+          @delSheetHandle="delSheetHandle"
+          @downloadExcel="downloadExcel"
+          ref="sheetListWrap"
+        />
       </div>
     </div>
 
@@ -366,9 +325,10 @@ import Sheet from "./components/SheetExcel.vue";
 import { getSheetImage } from "./common/option";
 import CustomTable from "./components/CustomTable.vue";
 import MixedTable from "./components/MixedTable.vue";
+import sheetListWrap from "./components/sheetListWrap.vue"
 export default {
   name: "",
-  components: { mDialog, classifyDia, Sheet, CustomTable, MixedTable },
+  components: { mDialog, classifyDia, Sheet, CustomTable, MixedTable,sheetListWrap },
   mixins: [leftMixin],
   computed: {
     downExcelFileUrl() {
@@ -396,6 +356,10 @@ export default {
         const cell = {Source:3}
         return this.isSheetBtnShow(cell,'edit')||this.isSheetBtnShow(cell,'refresh')||this.isSheetBtnShow(cell,'otherSave')
             || this.isSheetBtnShow(cell,'download')||this.isSheetBtnShow(cell,'del')
+    },
+
+    isCreator(){
+      return this.adminId==this.excelAdminId
     }
   },
   data() {
@@ -431,7 +395,6 @@ export default {
       sheet_total: 0,
       sheet_page: 1,
       sheet_pages_size: 16,
-      imgHeight: 196,
 
       /* 另存为 */
       isSaveOther: false,
@@ -447,6 +410,15 @@ export default {
           { required: true, message: "表格分类不能为空", trigger: "blur" },
         ],
       },
+      sourceMap: {
+        '/sheetList': 1,
+        '/sheetTimeList': 2,
+        '/sheetMixedList': 3,
+      },
+      saveTime:"",
+      editButtonText:"",
+      adminId:localStorage.getItem("AdminId") || '0',
+      excelAdminId:""
     };
   },
   watch: {
@@ -463,7 +435,7 @@ export default {
     },
 
     select_classify(newval) {
-      if (this.$refs.listRef) this.$refs.listRef.scrollTop = 0;
+      if (this.$refs.sheetListWrap) this.$refs.sheetListWrap.$refs.listRef.scrollTop = 0;
       if (newval) {
         this.sheet_page = 1;
         this.getPublicList();
@@ -491,9 +463,10 @@ export default {
   },
   methods: {
     /* 添加表格 */
-    goAddSheetHandle(type) {
-      if (!this.treeData.length)
-        return this.$message.warning("请先添加表格分类");
+    goAddSheetHandle() {
+      if (!this.treeData.length) return this.$message.warning("请先添加表格分类");
+      let type = this.sourceMap[this.$route.path];
+
       let path = {
         1: "/addsheet",
         2: "/addCustomSheet",
@@ -510,7 +483,7 @@ export default {
 
     /* 获取表格分类 */
     getTreeData(params = null) {
-      sheetInterface.classifyList().then((res) => {
+      sheetInterface.classifyList({Source: this.sourceMap[this.$route.path]}).then((res) => {
         const { Ret, Data } = res;
         if (Ret !== 200) return;
 
@@ -527,13 +500,12 @@ export default {
     searchHandle(query) {
       if (query) {
         /* 查找列表 */
-        sheetInterface
-          .sheetList({
+        sheetInterface.sheetList({
             Keyword: query,
             CurrentIndex: 1,
             PageSize: 10000,
-          })
-          .then((res) => {
+            Source: this.sourceMap[this.$route.path]
+          }).then((res) => {
             if (res.Ret !== 200) return;
             this.searchOptions = res.Data.List || [];
           });
@@ -544,6 +516,7 @@ export default {
 
     /* 选中分类变化时 */
     nodeChange({ UniqueCode, ExcelInfoId, ExcelClassifyId }, node) {
+      console.log(this.select_id,ExcelInfoId,'UniqueCode');
       this.search_txt = "";
       this.select_node = UniqueCode;
       this.select_classify = !ExcelInfoId ? ExcelClassifyId : 0;
@@ -607,6 +580,7 @@ export default {
         .classifyDel({
           ExcelClassifyId,
           ExcelInfoId,
+          Source: this.sourceMap[this.$route.path]
         })
         .then((res) => {
           if (res.Ret !== 200) return;
@@ -696,7 +670,8 @@ export default {
     /* 保存表格 */
     saveHandle: _.debounce(async function () {
       luckysheet.exitEditMode();
-      let data = luckysheet.getAllSheets()[0];
+      //结构类型乱飘 强制定义下
+      let data = {...luckysheet.getAllSheets()[0],status:Number(luckysheet.getAllSheets()[0].status)}
       if (!data.celldata.length) return this.$message.warning("请输入表格内容");
 
       this.loading = this.$loading({
@@ -731,32 +706,31 @@ export default {
 
     /* 获取表格列表 */
     getPublicList() {
-      sheetInterface
-        .sheetList({
-          CurrentIndex: this.sheet_page,
-          PageSize: this.sheet_pages_size,
-          ExcelClassifyId: this.select_classify || 0,
-        })
-        .then((res) => {
-          if (res.Ret !== 200) return;
-
-          this.publicHaveMove = res.Data
-            ? this.sheet_page < res.Data.Paging.Pages
-            : false;
-          this.sheetList = res.Data
-            ? this.sheet_page === 1
-              ? res.Data.List
-              : [...this.sheetList, ...res.Data.List]
-            : [];
-          this.sheet_total = res.Data ? res.Data.Paging.Totals : 0;
-        });
+      sheetInterface.sheetList({
+        CurrentIndex: this.sheet_page,
+        PageSize: this.sheet_pages_size,
+        ExcelClassifyId: this.select_classify || 0,
+        Source: this.sourceMap[this.$route.path]
+      }).then((res) => {
+        if (res.Ret !== 200) return;
+
+        this.publicHaveMove = res.Data
+          ? this.sheet_page < res.Data.Paging.Pages
+          : false;
+        this.sheetList = res.Data
+          ? this.sheet_page === 1
+            ? res.Data.List
+            : [...this.sheetList, ...res.Data.List]
+          : [];
+        this.sheet_total = res.Data ? res.Data.Paging.Totals : 0;
+      });
     },
 
     /* 加载更多 */
     loadMoreHandle: _.throttle(function () {
-      let scrollTop = this.$refs.listRef.scrollTop;
-      let clientHeight = this.$refs.listRef.clientHeight;
-      let scrollHeight = this.$refs.listRef.scrollHeight;
+      let scrollTop = this.$refs.sheetListWrap.$refs.listRef.scrollTop;
+      let clientHeight = this.$refs.sheetListWrap.$refs.listRef.clientHeight;
+      let scrollHeight = this.$refs.sheetListWrap.$refs.listRef.scrollHeight;
       if (
         scrollTop + clientHeight >= scrollHeight - 10 &&
         this.publicHaveMove
@@ -768,16 +742,21 @@ export default {
 
     /* 获取表格详情 */
     getDetailHandle() {
-      sheetInterface
-        .sheetDetail({
+      sheetInterface.sheetDetail({
           ExcelInfoId: this.select_id,
         })
         .then((res) => {
           if (res.Ret !== 200) return;
 
           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(() => {
+
             this.sheetDetailInfo.Source === 1 && this.$refs.sheetRef.init();
 
             this.sheetDetailInfo.Source === 2 &&
@@ -790,7 +769,8 @@ export default {
     },
 
     /* 删除表格 */
-    delSheetHandle({ ExcelClassifyId, ExcelInfoId }, type = "") {
+    delSheetHandle({cell, type = ""}) {
+      const { ExcelClassifyId, ExcelInfoId  } = cell;
       this.$confirm("删除后该表格将不能再引用,确认删除吗?", "提示", {
         confirmButtonText: "确定",
         cancelButtonText: "取消",
@@ -801,21 +781,37 @@ export default {
         })
         .catch(() => {});
     },
-
     /* 编辑 */
     goEditHandle() {
-      let path = {
-        2: "/addCustomSheet",
-        3: "addMixedSheet",
-      };
-      this.$router.push({
-        path: path[this.sheetDetailInfo.Source],
-        query: { id: this.sheetDetailInfo.ExcelInfoId },
-      });
+      // 标记
+      sheetInterface.markSheetEditStatus({ExcelInfoId: this.select_id,Status:1}).then(res=>{
+        if(res.Ret != 200) return 
+        if(res.Data.Status==0){
+          let path = {
+            1:"/addsheet",
+            2: "/addCustomSheet",
+            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");
+          }else {
+            this.$router.push({
+              path: path[this.sheetDetailInfo.Source],
+              query: { id: this.sheetDetailInfo.ExcelInfoId },
+            });
+          }
+
+        }else if(res.Data.Status==1){
+          this.editButtonText = `${res.Data.Editor}编辑中`
+          this.$message.warning('当前'+this.editButtonText)
+        }
+      })
+
     },
 
     /* 刷新表格 */
-    refreshSheet: _.debounce(async function () {
+    refreshSheetEdb: _.debounce(async function () {
       const res = await sheetInterface.refreshCustomSheet({
         ExcelInfoId: this.sheetDetailInfo.ExcelInfoId,
       });
@@ -864,40 +860,6 @@ export default {
       let left = $("#left")[0].offsetWidth;
       let rigtWid = total_wid - left - 20 + "px";
       $("#right")[0].style.width = rigtWid;
-
-      !this.select_id &&
-        this.$nextTick(() => {
-          this.imgHeight =
-            $(".chart-img")[0].offsetWidth / 1.64 > 150
-              ? $(".chart-img")[0].offsetWidth / 1.64
-              : 150;
-        });
-    },
-    //判断右侧列表的下载按钮是否显示
-    isDownLoadShow(cell){
-        const {checkPermissionBtn,etaTablePermission} = this.permissionBtn
-        const checkMap = {
-            1:etaTablePermission.etaTable_excel_download,
-            2:etaTablePermission.etaTable_customize_data_download,
-            3:etaTablePermission.etaTable_customize_mix_download
-        }
-        return checkPermissionBtn(checkMap[cell.Source])
-    },
-    //判断右侧列表的删除按钮是否显示
-    isDeleteShow(cell){
-        const {checkPermissionBtn,etaTablePermission} = this.permissionBtn
-        const checkMap = {
-            1:etaTablePermission.etaTable_excel_del,
-            2:etaTablePermission.etaTable_customize_data_del,
-            3:etaTablePermission.etaTable_customize_mix_del
-        }
-        return checkPermissionBtn(checkMap[cell.Source])
-    },
-    //判断自定义表格-编辑,另存为,刷新按钮是否显示
-    isSheetBtnShow(cell,type){
-        console.log('cell',cell.Source)
-        const sheetType = cell.Source===2?'data':'mix'
-        return this.permissionBtn.isShowBtn('etaTablePermission',`etaTable_customize_${sheetType}_${type}`)
     }
   },
   mounted() {
@@ -950,7 +912,7 @@ $normal-font: 14px;
 
     .main-left {
       width: 400px;
-      min-width: 350px;
+      min-width: 300px;
       background: #fff;
       margin-right: 20px;
       border: 1px solid #ececec;
@@ -1020,6 +982,7 @@ $normal-font: 14px;
 
     .main-right {
       width: 80%;
+      min-width: 800px;
       .sheet-detail-wrapper {
         height: 100%;
         border: 1px solid #ececec;
@@ -1029,28 +992,47 @@ $normal-font: 14px;
         background: #fff;
         .detail-top {
           padding: 20px;
-          display: flex;
-          justify-content: space-between;
-          align-items: center;
+          // display: flex;
+          // justify-content: space-between;
+          // align-items: center;
           border-bottom: 1px solid #ececec;
           .sheet-name {
-            font-size: 17px;
-            cursor: pointer;
-            max-width: 450px;
-            &:hover {
-              text-decoration: underline;
-            }
+            font-size: 18px;
+            color: #333333;
+            margin-bottom: 6px;
+            // cursor: pointer;
+            // max-width: 450px;
+            // &:hover {
+            //   text-decoration: underline;
+            // }
           }
-          .action-ul {
+          .sheet-anothor-info{
             display: flex;
-            li {
-              margin: 0 10px;
+            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 - 190px);
+          height: calc(100vh - 210px);
           padding: 15px;
           /* min-height: 500px; */
         }

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

@@ -816,6 +816,10 @@ export default {
       this.tableData.forEach((item) => {
         let edbData = EdbInfoList.find(_ => _.EdbInfoId===item.EdbInfoId);
         item.DataList = edbData.DataList;
+        //更新起始时间和最近更新时间
+        item.StartDate = edbData.StartDate;
+        item.ModifyTime = edbData.ModifyTime;
+        
         if(edbData.EdbInfoCategoryType===1) item.MoveLatestDate = edbData.MoveLatestDate;
       });
     },

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

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

+ 56 - 8
src/views/mychart_manage/index.vue

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

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

@@ -217,6 +217,7 @@ export default {
     },
 
     async getInfo() {
+      if(!this.$route.query.classify_name||!this.$route.query.classify_type) return
       this.pageLoading = true;
       const res = await apiPositionAnalysisInfo({
         DataTime: this.selectDate || "",

+ 2 - 2
src/views/ppt_manage/newVersion/components/Cover.vue

@@ -1,8 +1,8 @@
 <template>
-    <div class="flex-column cover" :style="`width:100%;color: ${$parent.pptCoverTextColor||'#fff'};`" v-if="pageInfo">
+    <div class="flex-column cover" :style="`width:100%;height:100%;color: ${$parent.pptCoverTextColor||'#fff'};`" v-if="pageInfo">
         <!-- <img :src="pageInfo.BackgroundImg" class="pptbg" /> -->
         <!-- <img :src="base64Url" class="pptbg" /> -->
-        <img :src="pageInfo.BackgroundImg" class="pptbg"  style="width:100%"/>
+        <img :src="pageInfo.BackgroundImg" class="pptbg"  style="width:100%;height:100%;object-fit: fill !important;"/>
         <div
         style="width:62%; font-size:16px; text-align:center; line-height:1.6;  position:absolute; right:20px; top:50%;zIndex:20;">
         <p :style="`height:5px; marginBottom:21px;`"></p>

+ 2 - 2
src/views/ppt_manage/newVersion/components/CoverEn.vue

@@ -1,6 +1,6 @@
 <template>
-    <div class="flex-column cover" style="width:100%;" v-if="pageInfo">
-        <img :src="pageInfo.BackgroundImg" class="pptbg"  style="width:100%"/>
+    <div class="flex-column cover" style="width:100%;height:100%;" v-if="pageInfo">
+        <img :src="pageInfo.BackgroundImg" class="pptbg"  style="width:100%;height:100%;object-fit: fill !important;"/>
         <div
         :style="`width:62%; font-size:16px; text-align:center; line-height:1.6; color:${$parent.pptCoverTextColor||'#fff'}; position:absolute; right:20px; top:50%;zIndex:20;`">
         <p :style="`height:5px;marginBottom:21px;`"></p>

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

@@ -320,7 +320,7 @@ export default {
       position:relative;
       width:100%;
       background: url('~@/assets/img/pptnextimg.png') no-repeat center;
-      background-size: cover;
+      background-size: 100%;
       margin-bottom: 20px;
       border: 4px solid transparent;
       .ppt-info{

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

@@ -2,7 +2,7 @@
   <div class="page-wrap">
     <div class="index-wrap ppt-page-wrap flex-column">
         <div class="cover-wrap" @click="openChooseCover">
-            <div class="cover" :style="'background: no-repeat center/cover url('+firstPage.BackgroundImg+')'">
+            <div class="cover" :style="'background: no-repeat center/cover url('+firstPage.BackgroundImg+');background-color:#F2F6FA;'">
                 <img src="~@/assets/img/ppt_m/add_first.png" />
             </div>
             <p class="hint-text">选择封面页</p>
@@ -313,7 +313,7 @@ export default {
         firstPage:{
             Title:'',
             ReportType:'',
-            BackgroundImg:'https://hzstatic.hzinsights.com/ppt/bg3.jpg',
+            BackgroundImg:'',
             PptDate:(new Date().getFullYear())+'年'+(new Date().getMonth()+1)+'月',
             BackIndex:0,
             TemplateType:1

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

@@ -2,7 +2,7 @@
   <div class="page-wrap">
     <div class="index-wrap ppt-page-wrap flex-column">
         <div class="cover-wrap" @click="openChooseCover">
-            <div class="cover" :style="'background: no-repeat center/cover url('+firstPage.BackgroundImg+')'">
+            <div class="cover" :style="'background: no-repeat center/cover url('+firstPage.BackgroundImg+');background-color:#F2F6FA;'">
                 <img src="~@/assets/img/ppt_m/add_first.png" />
             </div>
             <p class="hint-text">选择封面页</p>
@@ -336,7 +336,7 @@ export default {
         firstPage:{
             Title:'',
             ReportType:'',
-            BackgroundImg:'https://hzstatic.hzinsights.com/ppt/bg3.jpg',
+            BackgroundImg:'',
             PptDate:(new Date().getFullYear())+'.'+(new Date().getMonth()+1),
             BackIndex:0,
             TemplateType:1

+ 6 - 4
src/views/ppt_manage/newVersion/pptEnPresent.vue

@@ -39,11 +39,11 @@
           <!-- <div class="image-move" v-if="dragShow" @mousedown.stop="handleMoveStart" ></div> -->
           <div class="ppt-wrap" @wheel.stop="normalMouseWheel">
             <!-- 封面 -->
-            <div class="ppt-item" id="cover" v-if="currentIndex===0">
+            <div class="ppt-item" id="cover" v-if="currentIndex===0" style="background-size:20%;">
               <Cover :pageInfo="coverInfo.page" v-show="coverInfo.page"></Cover>
             </div>
             <!-- 封底 -->
-            <div class="ppt-item" id="back" v-else-if="currentIndex===pageList.length+1">
+            <div class="ppt-item" id="back" v-else-if="currentIndex===pageList.length+1" style="background-size:20%;">
               <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
             </div>
             <!-- PPT内容 -->
@@ -97,11 +97,11 @@
         @mousedown.stop="(e)=>{handleMouse('down',e)}" @mouseup="(e)=>{handleMouse('up',e)}" @wheel.stop="normalMouseWheel" @contextmenu="handleContextMenu">
           <div class="ppt-wrap">
             <!-- 封面 -->
-            <div class="ppt-item" id="cover" v-if="currentIndex===0">
+            <div class="ppt-item" id="cover" v-if="currentIndex===0" style="background-size:20%;">
               <Cover :pageInfo="coverInfo.page" v-show="coverInfo.page"></Cover>
             </div>
             <!-- 封底 -->
-            <div class="ppt-item" id="back" v-else-if="currentIndex===pageList.length+1">
+            <div class="ppt-item" id="back" v-else-if="currentIndex===pageList.length+1" style="background-size:20%;">
               <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
             </div>
             <!-- PPT内容 -->
@@ -302,6 +302,7 @@ export default {
         this.sheetListHandle(sheetElements);
       }
       this.currentKey = 1
+      this.pptBgImage&&$('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
       this.dataLoading.close();
     },
     //根据id获取ppt数据
@@ -559,6 +560,7 @@ export default {
           $('.fullscreen .ppt-wrap').css('width','1100px')
           $('.ppt-item').css('transform',`scale(1)`)
           this.changeCurrentItem(this.currentItem)
+          $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
         })
       }else{
         this.$nextTick(()=>{

+ 4 - 4
src/views/ppt_manage/newVersion/pptEnPublish.vue

@@ -19,7 +19,7 @@
       <template v-if="loadingAll">
         <div class="ppt-wrap flex-center">
           <!-- 封面 -->
-          <div class="ppt-item" id="cover">
+          <div class="ppt-item" id="cover" style="background-size:20%;">
             <Cover :pageInfo="coverInfo.page"></Cover>
           </div>
           <!-- 内容 -->
@@ -37,7 +37,7 @@
             </component>
           </div>
           <!-- 封底 -->
-          <div class="ppt-item" id="back" v-if="pptBackImage.length">
+          <div class="ppt-item" id="back" v-if="pptBackImage.length" style="background-size:20%;">
             <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
           </div>
         </div>
@@ -394,14 +394,14 @@ export default {
       })
       //生成的ppt需要可以在封面页更改标题和类型,所以封面信息手动写入
       const coverInfo = [
-        {text:'—————————————————————————————————\n',options:{fontSize:16*0.75,breakLine:true}},
+        //{text:'—————————————————————————————————\n',options:{fontSize:16*0.75,breakLine:true}},
         {text:this.coverInfo.page.Title,options:{fontSize:28*0.75,breakLine:true}},
         {text:`\n${this.pptCoverCompenyName||'ETA'}`,
          options:{fontSize:16*0.75,breakLine:true}},
         {text:`\n — ${this.coverInfo.page.ReportType} —`,options:{fontSize:16*0.75,breakLine:true}}, 
         {text:`\n${this.pptCoverDepartName||'Research Department'}`,options:{fontSize:16*0.75,breakLine:true}},
         {text:this.coverInfo.page.PptDate,options:{fontSize:16*0.75,breakLine:true}},
-        {text:'\n—————————————————————————',options:{fontSize:16*0.75,breakLine:true}}
+        //{text:'\n—————————————————————————',options:{fontSize:16*0.75,breakLine:true}}
       ]
       cover.addText(coverInfo,{
         x:'38%',

+ 6 - 4
src/views/ppt_manage/newVersion/pptPresent.vue

@@ -39,11 +39,11 @@
           <!-- <div class="image-move" v-if="dragShow" @mousedown.stop="handleMoveStart" ></div> -->
           <div class="ppt-wrap" @wheel.stop="normalMouseWheel">
             <!-- 封面 -->
-            <div class="ppt-item" id="cover" v-if="currentIndex===0">
+            <div class="ppt-item" id="cover" v-if="currentIndex===0" style="background-size:20%;">
               <Cover :pageInfo="coverInfo.page" v-show="coverInfo.page"></Cover>
             </div>
             <!-- 封底 -->
-            <div class="ppt-item" id="back" v-else-if="currentIndex===pageList.length+1">
+            <div class="ppt-item" id="back" v-else-if="currentIndex===pageList.length+1" style="background-size:20%;">
               <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
             </div>
             <!-- PPT内容 -->
@@ -97,11 +97,11 @@
         @mousedown.stop="(e)=>{handleMouse('down',e)}" @mouseup="(e)=>{handleMouse('up',e)}" @wheel.stop="normalMouseWheel" @contextmenu="handleContextMenu" >
           <div class="ppt-wrap">
             <!-- 封面 -->
-            <div class="ppt-item" id="cover" v-if="currentIndex===0">
+            <div class="ppt-item" id="cover" v-if="currentIndex===0" style="background-size:20%;">
               <Cover :pageInfo="coverInfo.page" v-show="coverInfo.page"></Cover>
             </div>
             <!-- 封底 -->
-            <div class="ppt-item" id="back" v-else-if="currentIndex===pageList.length+1">
+            <div class="ppt-item" id="back" v-else-if="currentIndex===pageList.length+1" style="background-size:20%;">
               <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
             </div>
             <!-- PPT内容 -->
@@ -300,6 +300,7 @@ export default {
         this.sheetListHandle(sheetElements);
       }
       this.currentKey = 1
+      this.pptBgImage&&$('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
       this.dataLoading.close();
     },
     //根据id获取ppt数据
@@ -557,6 +558,7 @@ export default {
           $('.fullscreen .ppt-wrap').css('width','1100px')
           $('.ppt-item').css('transform',`scale(1)`)
           this.changeCurrentItem(this.currentItem)
+          $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
         })
       }else{
         this.$nextTick(()=>{

+ 4 - 4
src/views/ppt_manage/newVersion/pptPublish.vue

@@ -20,7 +20,7 @@
       <template v-if="loadingAll">
         <div class="ppt-wrap flex-center">
           <!-- 封面 -->
-          <div class="ppt-item" id="cover">
+          <div class="ppt-item" id="cover" style="background-size:20%;">
             <Cover :pageInfo="coverInfo.page"></Cover>
           </div>
           <!-- 内容 -->
@@ -38,7 +38,7 @@
             </component>
           </div>
           <!-- 封底 -->
-          <div class="ppt-item" id="back" v-if="pptBackImage.length">
+          <div class="ppt-item" id="back" v-if="pptBackImage.length" style="background-size:20%;">
             <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
           </div>
         </div>
@@ -474,13 +474,13 @@ export default {
       })
       //生成的ppt需要可以在封面页更改标题和类型,所以封面信息手动写入
       const coverInfo = [
-        {text:'—————————————————————————————————\n',options:{fontSize:16*0.75,breakLine:true}},
+        //{text:'—————————————————————————————————\n',options:{fontSize:16*0.75,breakLine:true}},
         {text:this.coverInfo.page.Title,options:{fontSize:28*0.75,breakLine:true}},
         {text:`\n— ${this.pptCoverCompenyName||'ETA'} ● ${this.coverInfo.page.ReportType} —`,
          options:{fontSize:16*0.75,breakLine:false}},
         {text:`\n${this.pptCoverDepartName||'投研部'}`,options:{fontSize:16*0.75,breakLine:true}},
         {text:this.coverInfo.page.PptDate,options:{fontSize:16*0.75,breakLine:true}},
-        {text:'\n—————————————————————————',options:{fontSize:16*0.75,breakLine:true}}
+        //{text:'\n—————————————————————————',options:{fontSize:16*0.75,breakLine:true}}
       ]
       cover.addText(coverInfo,{
         x:'38%',

+ 4 - 2
src/views/predictEdb_manage/mixins/mixin.js

@@ -173,7 +173,9 @@ export default {
 					this.$message.success('移动成功!')
 				}
 				this.getTreeData()
-        this.$refs.detailComponentRef.getDetail()
+        if(this.select_id&&!this.showAssociateChart&&!this.showAssociateComputeData){
+          this.$refs.detailComponentRef.getDetail()
+        }
 			})
     },
 
@@ -191,7 +193,7 @@ export default {
 			if(dropLine){
 				setTimeout(() => {
 					dropLine.style.top=e.layerY+'px'
-				}, 10);
+				}, 100);
 			}
     },
 

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

@@ -404,7 +404,8 @@ export default {
     },
 
     editChildSand(item) {
-      ({SandboxId,VersionCode,type} = item)
+      // ({SandboxId,VersionCode,type} = item)
+      let {SandboxId,VersionCode,type} = item
        // 编辑前校验
       sandInterface
         .mark({

+ 312 - 0
src/views/smartReport/components/BaseInfo.vue

@@ -0,0 +1,312 @@
+<template>
+    <el-dialog
+        title="基础信息"
+        :visible.sync="show"
+        :modal-append-to-body="false"
+        :close-on-click-modal="false"
+        :center="true"
+        v-dialogDrag
+        custom-class="dialogclass"
+        width="440px"
+        @close="handleClose"
+    >
+        <el-form 
+            :model="formData" 
+            :rules="rules" 
+            ref="baseinfoForm"
+            class="baseinfo-form-wrap"
+        >  
+            <el-form-item prop="type">
+                <el-radio-group v-model="formData.type" :disabled="id" @change="handleUpdateBaseInfo">
+                    <el-radio :label="1">新增报告</el-radio>
+                    <el-radio :label="2">继承报告</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item prop="classify">
+                <el-cascader
+					ref="cascader"
+					:options="classifyArr"
+					v-model="formData.classify"
+					placeholder="请选择分类"
+					size="medium"
+                    style="width:340px"
+                    @change="handleUpdateBaseInfo"
+				/>
+            </el-form-item>
+            <el-form-item prop="title">
+                <el-input placeholder="请输入标题" v-model="formData.title" style="width:340px"></el-input>
+            </el-form-item>
+            <el-form-item prop="abstract">
+                <el-input type="textarea" placeholder="请输入摘要" v-model="formData.abstract" style="width:340px"></el-input>
+            </el-form-item>
+            <el-form-item prop="author">
+				<el-select
+					v-model="formData.author"
+					multiple
+					placeholder="请选择作者"
+					size="medium"
+					style="width: 340px"
+				>
+					<el-option
+						v-for="(item, i) in authorlist"
+						:key="i"
+						:label="item.ReportAuthor"
+						:value="item.ReportAuthor"
+					></el-option>
+				</el-select>
+			</el-form-item>
+            <el-form-item prop="frequency">
+                <el-select
+					v-model="formData.frequency"
+					placeholder="请选择频度"
+					size="medium"
+					style="width: 340px"
+				>
+                    <el-option label="年度" value="年度"></el-option>
+                    <el-option label="半年度" value="半年度"></el-option>
+                    <el-option label="季度" value="季度"></el-option>
+                    <el-option label="月度" value="月度"></el-option>
+                    <el-option label="双周度" value="双周度"></el-option>
+                    <el-option label="周度" value="周度"></el-option>
+                    <el-option label="日度" value="日度"></el-option>
+                    <el-option label="不定时" value="不定时"></el-option>
+                </el-select>
+            </el-form-item>
+            <el-form-item prop="time">
+                <el-date-picker
+					v-model="formData.time"
+					type="date"
+					value-format="yyyy-MM-dd"
+					placeholder="选择日期"
+					size="medium"
+					:clearable="false"
+					style="width: 340px"
+				></el-date-picker>
+            </el-form-item>
+        </el-form>
+        <div style="text-align:center;margin-top:60px;margin-bottom:40px">
+            <el-button type="primary" plain style="width:120px" @click="handleClose">取消</el-button>
+            <el-button type="primary" style="width:120px" @click="handleConfirm">确定</el-button>
+        </div>
+    </el-dialog>
+</template>
+
+<script>
+import {apiSmartReport}  from '@/api/modules/smartReport'
+export default {
+    name:"BaseInfo",
+    model:{
+        prop:'show',
+        event:'showChange'
+    },
+    props:{
+        show:{
+            type:Boolean,
+            default:false
+        },
+        id:{
+            type:Number,
+            default:0
+        }
+    },
+    watch: {
+        show(n){
+            if(!n){
+                this.formData.type=1
+                this.formData.classify=[]
+                this.formData.title=''
+                this.formData.abstract=''
+                this.formData.author=['FICC团队']
+                this.formData.frequency='日度'
+                this.formData.time=this.$moment().format('YYYY-MM-DD')
+            }else{
+                if(this.id){
+                    apiSmartReport.reportDetail({
+                        SmartReportId:Number(this.id)
+                    }).then(res=>{
+                        if(res.Ret===200){
+                            this.formData.type=res.Data.AddType
+                            this.formData.classify=[res.Data.ClassifyIdFirst,res.Data.ClassifyIdSecond]
+                            this.formData.title=res.Data.Title
+                            this.formData.abstract=res.Data.Abstract
+                            this.formData.author=res.Data.Author ? res.Data.Author.split(',') : []
+                            this.formData.frequency=res.Data.Frequency
+                            this.formData.time=res.Data.CreateTime
+                        }
+                    })
+                }
+            }
+        }  
+    },
+    data() {
+        return {
+            rules:{
+                type:[{ required: true, message: '请选择报告类型', trigger: 'change' }],
+                classify:[{ required: true, message: '请选择报告分类', trigger: 'change' }],
+                title:[{ required: true, message: '请填写报告标题', trigger: 'blur' }],
+            },
+            formData:{
+                type:1,
+                classify:[],
+                title:'',
+                abstract:'',
+                author:['FICC团队'],
+                frequency:'日度',
+                time:this.$moment().format('YYYY-MM-DD')||''
+            },
+            classifyArr:[],
+            authorlist:[]
+        }
+    },
+   
+    methods: {
+        handleClose(){
+            this.$emit('showChange', false)
+        },
+
+        handleConfirm(){
+            this.$refs.baseinfoForm.validate((valid)=>{
+                if(valid){
+
+                    const params={
+                        AddType: this.formData.type,
+                        ClassifyIdFirst: this.formData.classify[0]?this.formData.classify[0]:0,
+                        ClassifyNameFirst: '',
+                        ClassifyIdSecond:this.formData.classify[1]?this.formData.classify[1]:0,
+                        ClassifyNameSecond:'',
+                        Title: this.formData.title,
+                        Abstract: this.formData.abstract,
+                        Author:
+                            this.formData.author.length > 0
+                                ? this.formData.author.join(',')
+                                : '',
+                        Frequency: this.formData.frequency,
+                        CreateTime: this.formData.time,
+                    }
+                    this.classifyArr.forEach(item=>{
+                        if(item.value===params.ClassifyIdFirst){
+                            params.ClassifyNameFirst=item.label
+                            const arr=item.children||[]
+                            arr.forEach(_item=>{
+                                if(_item.value===params.ClassifyIdSecond){
+                                    params.ClassifyNameSecond=_item.label
+                                }
+                            })
+                        }
+                    })
+                    // 编辑
+                    if(this.id){
+                        this.$emit('save',params)
+                        return
+                    }
+                    apiSmartReport.reportAdd(params).then(res=>{
+                        if(res.Ret===200){
+                            this.handleClose()
+                            let { href } = this.$router.resolve({
+                                path: "/smartReportEdit",
+                                query: { id: res.Data.SmartReportId },
+                            });
+                            window.open(href, "_blank");
+                        }
+                    })
+
+                }
+            })
+        },
+
+        handleUpdateBaseInfo(){
+            if(this.formData.type===1){
+                if(this.formData.classify.length===2){
+                    this.formData.title=this.getSelectClassifyName()[1]
+                }
+                return
+            }
+            //获取上次报告
+            apiSmartReport.getLastReport({
+                ClassifyIdFirst:this.formData.classify[0],
+                ClassifyIdSecond:this.formData.classify[1]
+            }).then(res=>{
+                if(res.Ret!==200) return
+                if (res.Data == null) {
+					this.$message.warning('此分类暂无报告');
+					return false;
+				}
+                this.formData.title=res.Data.Title
+                this.formData.abstract=res.Data.Abstract
+                this.formData.author=res.Data.Author ? res.Data.Author.split(',') : ''
+                this.formData.frequency=res.Data.Frequency
+            })
+        },
+
+        // 获取选择的分类名称
+        getSelectClassifyName(){
+            let arr=[]
+            this.classifyArr.forEach(item=>{
+                if(this.formData.classify[0]&&item.value===this.formData.classify[0]){
+                    arr.push(item.label)
+                    if(item.children&&item.children.length>0){
+                        item.children.forEach(_item=>{
+                            if(this.formData.classify[1]&&_item.value===this.formData.classify[1]){
+                                arr.push(_item.label)
+                            }
+                        })
+                    }
+                }
+            })
+            return arr
+        },
+
+        // 获取分类
+        getclassifylist() {
+            let params = { CurrentIndex: 0, PageSize: 1000, KeyWord: "",HideDayWeek:1,/*不显示晨报/周报*/ };
+            apiSmartReport.classifyList(params).then((res) => {
+                if (res.Ret == 200 && Array.isArray(res.Data.List)) {
+                    this.classifyArr = [];
+                    res.Data.List.forEach((item, index) => {
+                        let newitem = {
+                            label: item.ClassifyName,
+                            value: item.Id,
+                        };
+                        if (item.Child) {
+                            let childnode = [];
+                            item.Child.forEach((itemchild, i) => {
+                                childnode.push({
+                                    label: itemchild.ClassifyName,
+                                    value: itemchild.Id,
+                                });
+                            });
+                            newitem.children = childnode;
+                        }
+                        this.classifyArr.push(newitem);
+                    });
+                }
+            });
+        },
+        // 获取作者
+        getreportauthor() {
+			apiSmartReport.reportAuthor({}).then((res) => {
+				if (res.Ret == 200) {
+					this.authorlist = res.Data.List || [];
+				}
+			});
+		},
+    },
+    mounted(){
+        this.getclassifylist()
+        this.getreportauthor()
+    },
+}
+</script>
+
+<style lang="scss">
+.baseinfo-form-wrap{
+    .el-input{
+        width: 100%;
+    }
+    .el-form-item{
+        width: 340px;
+        margin-left: auto;
+        margin-right: auto;
+    }
+}
+</style>

+ 20 - 0
src/views/smartReport/components/ChartComp.vue

@@ -0,0 +1,20 @@
+<template>
+    <div 
+        class="report-comp-item chart-comp"
+        style="min-height:300px;width:100%;height:100%;overflow: hidden;display:flex;flex-direction: column;margin-bottom:10px"
+    >
+        <iframe :src="compData.content" style="flex:1;width:100%;height:100%;border-width:0px;"></iframe>
+    </div>
+</template>
+
+<script>
+export default {
+    props:{
+        compData:{}
+    }
+}
+</script>
+
+<style>
+
+</style>

Some files were not shown because too many files changed in this diff