Ver Fonte

汾渭煤炭

jwyu há 1 ano atrás
pai
commit
6a25748dcf
100 ficheiros alterados com 5697 adições e 186 exclusões
  1. 0 9
      index.html
  2. 6 2
      src/api/api.js
  3. 2 2
      src/api/http.js
  4. 225 0
      src/api/modules/approve.js
  5. 338 1
      src/api/modules/chartRelevanceApi.js
  6. 10 0
      src/api/modules/pptApi.js
  7. 10 0
      src/api/modules/pptEnApi.js
  8. 21 0
      src/api/modules/sheetApi.js
  9. 20 0
      src/api/modules/smartReport.js
  10. 87 2
      src/api/modules/thirdBaseApi.js
  11. BIN
      src/assets/img/approve_m/approve.png
  12. BIN
      src/assets/img/approve_m/future-icon.png
  13. 3 0
      src/assets/img/approve_m/future-icon.svg
  14. BIN
      src/assets/img/approve_m/passed-icon.png
  15. 10 0
      src/assets/img/approve_m/passed-icon.svg
  16. 3 0
      src/assets/img/approve_m/passed-msg.svg
  17. BIN
      src/assets/img/approve_m/passed.png
  18. BIN
      src/assets/img/approve_m/pending.png
  19. BIN
      src/assets/img/approve_m/process-icon.png
  20. 6 0
      src/assets/img/approve_m/process-icon.svg
  21. 3 0
      src/assets/img/approve_m/process-msg.svg
  22. BIN
      src/assets/img/approve_m/reject-icon.png
  23. 3 0
      src/assets/img/approve_m/reject-icon.svg
  24. 10 0
      src/assets/img/approve_m/reject-msg.svg
  25. BIN
      src/assets/img/approve_m/reject.png
  26. BIN
      src/assets/img/approve_m/return-icon.png
  27. 5 0
      src/assets/img/approve_m/return-icon.svg
  28. 3 0
      src/assets/img/approve_m/return-msg.svg
  29. BIN
      src/assets/img/approve_m/return.png
  30. BIN
      src/assets/img/approve_m/select.png
  31. BIN
      src/assets/img/approve_m/start.png
  32. BIN
      src/assets/img/icons/add_blue_new.png
  33. BIN
      src/assets/img/icons/ai_Company.png
  34. BIN
      src/assets/img/icons/ai_avatar.png
  35. BIN
      src/assets/img/icons/fullsreen.png
  36. BIN
      src/assets/img/icons/gpt-4-turbo.png
  37. BIN
      src/assets/img/icons/gpt-4.png
  38. BIN
      src/assets/img/icons/more.png
  39. BIN
      src/assets/img/smartReport/icon17.png
  40. BIN
      src/assets/img/smartReport/icon18.png
  41. 22 10
      src/components/chart/chartDetailHandlesWrap.vue
  42. 7 3
      src/components/chart/chartListWrap.vue
  43. 130 42
      src/components/lzTable.vue
  44. 146 0
      src/components/notificationMsg.vue
  45. 65 0
      src/mixins/reportApproveConfig.js
  46. 27 0
      src/routes/modules/approveRoutes.js
  47. 21 7
      src/routes/modules/chartRoutes.js
  48. 16 0
      src/routes/modules/dataRoutes.js
  49. 12 0
      src/routes/modules/oldRoutes.js
  50. 44 5
      src/utils/buttonConfig.js
  51. 1 0
      src/utils/parseData.js
  52. 8 1
      src/utils/svgToblob.js
  53. 18 3
      src/views/Home.vue
  54. 12 12
      src/views/Login.vue
  55. 386 0
      src/views/approve_manage/approveDetail.vue
  56. 194 0
      src/views/approve_manage/approveEdit.vue
  57. 311 0
      src/views/approve_manage/approveList.vue
  58. 162 0
      src/views/approve_manage/approveSetting.vue
  59. 112 0
      src/views/approve_manage/components/flowEdiotr.vue
  60. 44 0
      src/views/approve_manage/components/flowNode/addNode.vue
  61. 280 0
      src/views/approve_manage/components/flowNode/approveNode.vue
  62. 26 0
      src/views/approve_manage/components/flowNode/endNode.vue
  63. 43 0
      src/views/approve_manage/components/flowNode/startNode.vue
  64. 81 0
      src/views/approve_manage/components/rejectDialog.vue
  65. 60 0
      src/views/approve_manage/components/timeLine.vue
  66. 120 0
      src/views/approve_manage/components/timeLineItem.vue
  67. 185 0
      src/views/approve_manage/components/treeTransfer.vue
  68. 95 0
      src/views/approve_manage/config/tableConfig.js
  69. 39 0
      src/views/approve_manage/css/nodeStyle.scss
  70. 6 0
      src/views/approve_manage/css/pageStyle.scss
  71. 31 0
      src/views/approve_manage/mixins/approveMixins.js
  72. 19 0
      src/views/chartFrame_manage/common/config.js
  73. 1 5
      src/views/chartFrame_manage/common/graph.js
  74. 31 6
      src/views/chartFrame_manage/components/frameContainer.vue
  75. 9 1
      src/views/chartFrame_manage/components/frameToolBar.vue
  76. 9 1
      src/views/chartFrame_manage/css/basePage.scss
  77. 1 1
      src/views/chartFrame_manage/css/customTree.scss
  78. 14 2
      src/views/chartFrame_manage/frameEditor.vue
  79. 16 8
      src/views/chartFrame_manage/index.vue
  80. 24 0
      src/views/chartRelevance_manage/components/explainText.js
  81. 670 0
      src/views/chartRelevance_manage/crossVarietyAnalysis/chartEditor.vue
  82. 208 0
      src/views/chartRelevance_manage/crossVarietyAnalysis/components/chartFormSection.vue
  83. 140 0
      src/views/chartRelevance_manage/crossVarietyAnalysis/components/edbTableSection.vue
  84. 182 0
      src/views/chartRelevance_manage/crossVarietyAnalysis/components/tagRelationDialog.vue
  85. 207 0
      src/views/chartRelevance_manage/crossVarietyAnalysis/components/tagSetDialog.vue
  86. 570 0
      src/views/chartRelevance_manage/crossVarietyAnalysis/list.vue
  87. 1 1
      src/views/chartRelevance_manage/css/index.scss
  88. 4 4
      src/views/chartRelevance_manage/fittingEquation/fittingEquationChartEditor.vue
  89. 3 3
      src/views/chartRelevance_manage/fittingEquation/fittingEquationList.vue
  90. 35 21
      src/views/chartRelevance_manage/mixins/classifyMixin.js
  91. 4 4
      src/views/chartRelevance_manage/relevance/list.vue
  92. 5 5
      src/views/chartRelevance_manage/relevance/relevanceChartEditor.vue
  93. 5 5
      src/views/chartRelevance_manage/statistic/statisticFeatureChartEditor.vue
  94. 3 3
      src/views/chartRelevance_manage/statistic/statisticFeatureList.vue
  95. 2 1
      src/views/dataEntry_manage/addChart.vue
  96. 1 1
      src/views/dataEntry_manage/chartSetting.vue
  97. 8 2
      src/views/dataEntry_manage/components/LegendEditDia.vue
  98. 8 2
      src/views/dataEntry_manage/components/SaveChartOther.vue
  99. 41 10
      src/views/dataEntry_manage/components/addTarget.vue
  100. 7 1
      src/views/dataEntry_manage/components/insertData.vue

+ 0 - 9
index.html

@@ -47,15 +47,6 @@
             src: url(./static/css/fonts/SourceHanSerifCN-Regular.ttf);
             src: url(./static/css/fonts/SourceHanSerifCN-Regular.ttf);
         }
         }
     </style>
     </style>
-	<script>
-		var _hmt = _hmt || [];
-		(function() {
-		  var hm = document.createElement("script");
-		  hm.src = "https://hm.baidu.com/hm.js?2147f2700a1a306aa027116f80ef640d";
-		  var s = document.getElementsByTagName("script")[0]; 
-		  s.parentNode.insertBefore(hm, s);
-		})();
-	</script>	
 	<script>
 	<script>
 		window.addEventListener('error',(e)=>{
 		window.addEventListener('error',(e)=>{
 			if(e.message=="Uncaught SyntaxError: Unexpected token '<'"){
 			if(e.message=="Uncaught SyntaxError: Unexpected token '<'"){

+ 6 - 2
src/api/api.js

@@ -10,7 +10,9 @@ import {
   sciDataInterface,
   sciDataInterface,
   baiinfoInterface,
   baiinfoInterface,
   nationalInterface,
   nationalInterface,
-  databankInterface
+  databankInterface,
+  yongyiInterface,
+  fwmtInterface
 } from './modules/thirdBaseApi';
 } from './modules/thirdBaseApi';
 
 
 //手工指标 手工数据 手工数据权限
 //手工指标 手工数据 手工数据权限
@@ -112,7 +114,9 @@ export {
   cloudDiskInterface,
   cloudDiskInterface,
   homeInterface,
   homeInterface,
   businessTripInterence,
   businessTripInterence,
-  reportVarietyENInterence
+  reportVarietyENInterence,
+  yongyiInterface,
+  fwmtInterface
 };
 };
 
 
 //老接口 研报 ppt等
 //老接口 研报 ppt等

+ 2 - 2
src/api/http.js

@@ -77,7 +77,7 @@ const cancelTimeoutUrlPost = ["/cloud_disk/resource/upload"];
 export default {
 export default {
   post(url, data) {
   post(url, data) {
     //post请求方式
     //post请求方式
-    let timeout = cancelTimeoutUrlPost.includes(url) ? 0 : 100000;
+    let timeout = cancelTimeoutUrlPost.includes(url) ? 0 : 600000;
     return axios({
     return axios({
       method: "post",
       method: "post",
       url: url,
       url: url,
@@ -100,7 +100,7 @@ export default {
       baseURL: process.env.VUE_APP_API_ROOT,
       baseURL: process.env.VUE_APP_API_ROOT,
       url: url,
       url: url,
       params: getData(data, url),
       params: getData(data, url),
-      timeout: 100000,
+      timeout:600000,
       headers: {
       headers: {
         "Content-type": "application/x-www-form-urlencoded; charset=utf-8",
         "Content-type": "application/x-www-form-urlencoded; charset=utf-8",
       },
       },

+ 225 - 0
src/api/modules/approve.js

@@ -0,0 +1,225 @@
+import http from "@/api/http.js"
+
+export const approveInterence = {
+    /**
+     * 获取审批流列表
+     * @param {Object} params 
+     * @param {Number} params.PageSize
+     * @param {Number} params.CurrentIndex
+     * @param {Number} params.ReportType 报告类型:1-中文研报;2-英文研报;3-智能研报
+     * @param {Number} params.ClassifyFirstId 关联报告一级分类ID
+     * @param {Number} params.ClassifySecondId 关联报告二级分类ID
+     * @param {String} params.Keyword
+     * @param {Number} params.SortRule 排序方式: 1-正序; 2-倒序(默认)
+     * @returns 
+     */
+    getApproveFlowList(params){
+        return http.get("/report_approve/flow/list",params)
+    },
+    /**
+     * 获取报告分类树
+     * @param {Object} params 
+     * @param {Number} params.ReportApproveFlowId 审批流ID(非必填)
+     * @returns 
+     */
+    getReportClassifyTree(params){
+        return http.get("/report_approve/report/classify_tree",params)
+    },
+    /**
+     * 删除审批流
+     * @param {Object} params 
+     * @param {Number} params.ReportApproveFlowId
+     * @returns 
+     */
+    deleteApproveFlow(params){
+        return http.post("/report_approve/flow/remove",params)
+    },
+    /**
+     * 获取审批流详情
+     * @param {Object} params 
+     * @param {Number} params.ReportApproveFlowId
+     * @returns 
+     */
+    getApproveFlowDetail(params){
+        return http.get("/report_approve/flow/detail",params)
+    },
+    /**
+     * 新增审批流
+     * @param {Object} params 
+     * @param {String} params.FlowName 审批流名称
+     * @param {Number} params.ReportType 报告类型:1-中文研报;2-英文研报;3-智能研报
+     * @param {Number} params.ClassifyFirstId 一级分类ID
+     * @param {Number} params.ClassifySecondId 二级分类ID
+     * @param {Object[]} params.Nodes 审批节点
+     * @param {Number} params.Nodes[].ApproveType 审批类型:1-依次审批;2-会签;3-或签
+     * @param {Object[]} params.Nodes[].Users 审批人信息
+     * @param {String} params.Nodes[].Users[].UserType 审批人类型: user-用户; role-角色
+     * @param {Number} params.Nodes[].Users[].UserId 用户/角色ID
+     * @param {String} params.Nodes[].Users[].UserName 用户/角色姓名
+     * @param {String} params.Nodes[].Users[].Sort 依次审批时的排序
+     * @returns 
+     */
+    addNewApproveFlow(params){
+        return http.post("/report_approve/flow/add",params)
+    },
+    /**
+     * 编辑审批流
+     * @param {Object} params 
+     * @param {Number} params.ReportApproveFlowId 审批流Id
+     * 其他参数同上
+     * @returns 
+     */
+    editApproveFlow(params){
+        return http.post("/report_approve/flow/edit",params)
+    },
+
+
+    /**
+     * 获取审批列表
+     * @param {Object} params 
+     * @param {Number} params.PageSize
+     * @param {Number} params.CurrentIndex
+     * @param {Number} params.ReportType 报告类型:1-中文研报;2-英文研报;3-智能研报
+     * @param {Number} params.ClassifyFirstId 报告的倒数第二级id
+     * @param {Number} params.ClassifySecondId 报告的倒数第一级id
+     * @param {String} params.Keyword
+     * @param {Number} params.SortRule 排序方式: 1-正序; 2-倒序(默认)
+     * @param {Number} params.SortField 排序字段:1-提交时间;2-处理时间;3-审批时间
+     * @param {Number} params.ListType 列表类型:1-待处理;2-已处理;3-我发起的
+     * @param {Number} params.ApproveState 审批状态:1-待审批;2-已审批/已通过;3-已驳回;4-已撤回/已撤销
+     * @param {Number} params.TimeType 时间类型:1-提交时间;2-处理时间;3-审批时间
+     * @param {String} params.StartTime 开始时间
+     * @param {String} params.EndTime 结束时间
+     * @returns 
+     */
+    getApproveList(params){
+        return http.get("/report_approve/list",params)
+    },
+    /**
+     * 获取审批详情
+     * @param {Object} params
+     * @param {Number} params.ReportApproveId
+     * @returns 
+     */
+    getApproveDetail(params){
+        return http.get("/report_approve/detail",params)
+    },
+    /**
+     * 审批消息通知
+     * @param {Object} params 
+     * @param {Number} params.PageSize
+     * @param {Number} params.CurrentIndex
+     * @returns 
+     */
+    getApproveMsgList(params){
+        return http.get("/report_approve/message/list",params)
+    },
+    /**
+     * 消息通知已读
+     * @param {Object} params 
+     * @param {Number} params.MessageId
+     * @returns 
+     */
+    readApproveMsg(params){
+        return http.post("/report_approve/message/read",params)
+    },
+    /**
+     * 撤销审批
+     * @param {Object} params 
+     * @param {Number} params.ReportApproveId
+     * @returns 
+     */
+    cancelApprove(params){
+        return http.post("/report_approve/cancel",params)
+    },
+    /**
+     * 通过审批
+     * @param {Object} params 
+     * @param {Number} params.ReportApproveId
+     * @returns 
+     */
+    passApprove(params){
+        return http.post("/report_approve/approve",params)
+    },
+    /**
+     * 驳回审批
+     * @param {Object} params 
+     * @param {Number} params.ReportApproveId
+     * @param {String} params.ApproveRemark
+     * @returns 
+     */
+    rejectApprove(params){
+        return http.post("/report_approve/refuse",params)
+    },
+    /**
+     * 校验研报分类是否有审批流
+     * @param {Object} params 
+     * @param {Number} params.ReportType 报告类型:1-中文研报;2-英文研报;3-智能研报
+     * @param {Number} params.ClassifyFirstId 倒数第二级分类的id
+     * @param {Number} params.ClassifySecondId 倒数第一级分类的id
+     * @returns 
+     */
+    checkClassifyApprove(params){
+        return http.post("/report_approve/classify/check_open",params)
+    },
+
+
+
+
+    /*------------研报审批接口----------- */
+    /**
+     * 中文研报提交审批
+     * @param {Object} params 
+     * @param {Number} params.ReportId
+     * @returns 
+     */
+    reportCnSubmit(params){
+        return http.post("/report/approve/submit",params)
+    },
+    /**
+     * 中文研报撤销审批
+     * @param {Object} params 
+     * @param {Number} params.ReportId
+     * @returns 
+     */
+    reportCnCancel(params){
+        return http.post("/report/approve/cancel",params)
+    },
+    /**
+     * 英文研报提交审批
+     * @param {Object} params 
+     * @param {Number} params.ReportId
+     * @returns 
+     */
+    reportEnSubmit(params){
+        return http.post("/english_report/approve/submit",params)
+    },
+    /**
+     * 英文研报撤销审批
+     * @param {Object} params 
+     * @param {Number} params.ReportId
+     * @returns 
+     */
+    reportEnCancel(params){
+        return http.post("/english_report/approve/cancel",params)
+    },
+    /**
+     * 智能研报提交审批
+     * @param {Object} params 
+     * @param {Number} params.ReportId
+     * @returns 
+     */
+    reportSmartSubmit(params){
+        return http.post("/smart_report/approve/submit",params)
+    },
+    /**
+     * 智能研报撤销审批
+     * @param {Object} params 
+     * @param {Number} params.ReportId
+     * @returns 
+     */
+    reportSmartCancel(params){
+        return http.post("/smart_report/approve/cancel",params)
+    },
+
+}

+ 338 - 1
src/api/modules/chartRelevanceApi.js

@@ -635,7 +635,19 @@ export const statisticFeatureInterface = {
 
 
   /**
   /**
    * 设置英文
    * 设置英文
-   * @param {*} params  ChartInfoId ChartNameEn
+   * @param {*} params  ChartInfoId ChartNameEn 
+   * "TagList": [
+      {
+        "ChartTagId": 1,
+        "TagNameEn": "宏观en"
+      }
+    ],
+    "VarietyList": [
+      {
+        "ChartVarietyId": 2,
+        "VarietyNameEn": "甲醇en"
+      }
+    ]
    * @returns 
    * @returns 
    */
    */
   editChartEn: params => {
   editChartEn: params => {
@@ -682,4 +694,329 @@ export const statisticFeatureInterface = {
     previewSpline: params => {
     previewSpline: params => {
       return http.post('/line_feature/preview_cure',params)
       return http.post('/line_feature/preview_cure',params)
     }
     }
+}
+
+/* 跨品种分析 */
+export const crossVarietyInterface = {
+  /**
+   * 分类列表
+   * @param {*} params 
+   * @returns 
+   */
+  classifyList: params => {
+    return http.get('/cross_variety/classify/list',params)
+  },
+
+  /**
+   * 分类添加
+   * @param {*} params ChartClassifyName
+   * @returns 
+   */
+  classifyAdd: params => {
+    return http.post('/cross_variety/classify/add',params)
+  },
+
+  /**
+   * 分类编辑
+   * @param {*} params ChartClassifyName ChartClassifyId
+   * @returns 
+   */
+  classifyEdit: params => {
+    return http.post('/cross_variety/classify/edit',params)
+  },
+
+  /**
+   * 分类移动
+   * @param {*} params 
+   * "ClassifyId": 269,
+    "PrevClassifyId": 0,
+    "NextClassifyId": 227,
+   * @returns 
+   */
+  classifyMove: params => {
+    return http.post('/cross_variety/classify/move',params)
+  },
+
+   /**
+   * 图表拖动
+   * @param {*} params 
+   * "ChartInfoId": 844,
+    "PrevChartInfoId": 0,
+    "NextChartInfoId": 839,
+    "ChartClassifyId": 270
+   * @returns 
+   */
+    chartMove: params => {
+      return http.post('/cross_variety/chart_info/move',params)
+    },
+  
+    /**
+     * 获取图表列表
+     * @param {*} params 
+     * CurrentIndex PageSize ChartClassifyId Keyword IsShowMe
+     * @returns 
+     */
+    getChartList: params => {
+      return http.get('/cross_variety/chart_info/list',params)
+    },
+  
+    /**
+     * 图表详情
+     * @param {*} params  ChartInfoId
+     * @returns 
+     */
+    chartDetail: params => {
+      return http.get('/cross_variety/chart_info/detail',params)
+    },
+
+    /**
+     * 添加图表
+     * @param {*} params 
+     * "ChartName": "跨品种分析图标名称",
+      "TagX": 1,
+      "TagY": 2,
+      "CalculateValue": 6,
+      "CalculateUnit": "月",
+      "DateConfigList": [
+        {
+          "DateType": 2,
+          "Num": 60
+        }
+      ],
+      "VarietyList": [2,5]
+     * @returns 
+     */
+    chartAdd: params => {
+      return http.post('/cross_variety/chart_info/add',params)
+    },
+
+    /**
+     * 编辑图表
+     * @param {*} params 
+     * ChartInfoId
+     * "ChartName": "跨品种分析图标名称",
+      "TagX": 1,
+      "TagY": 2,
+      "CalculateValue": 6,
+      "CalculateUnit": "月",
+      "DateConfigList": [
+        {
+          "DateType": 2,
+          "Num": 60
+        }
+      ],
+      "VarietyList": [2,5]
+     * @returns 
+     */
+    chartEdit: params => {
+      return http.post('/cross_variety/chart_info/edit',params)
+    },
+
+    /**
+     * 删除图表
+     * @param {*} params ChartInfoId
+     * @returns 
+     */
+    chartDel: params => {
+      return http.post('/cross_variety/chart_info/delete',params)
+    },
+
+    /**
+     * 预览图表
+     * @param {*} params 
+     *  "TagX": 1,
+        "TagY": 2,
+        "CalculateValue": 6,
+        "CalculateUnit": "月",
+        "DateConfigList": [
+          {
+            "DateType": 1,
+            "Num": 0
+          }
+        ],
+        "VarietyList": [2,5]
+     * @returns 
+     */
+    chartPreview: params => {
+      return http.post('/cross_variety/chart_info/preview',params)
+    },
+
+    /**
+     * 设置英文
+     * @param {*} params  ChartInfoId ChartNameEn
+     * "TagList": [
+        {
+          "ChartTagId": 1,
+          "TagNameEn": "宏观en"
+        }
+      ],
+      "VarietyList": [
+        {
+          "ChartVarietyId": 2,
+          "VarietyNameEn": "甲醇en"
+        }
+      ]
+     */
+    editChartEn: params => {
+      return http.post('/cross_variety/chart_info/en/edit',params)
+    },
+
+    /**
+     * 图表搜索
+     * @param {*} params Keyword
+     * @returns 
+     */
+    searchChart: params => {
+      return http.get('/cross_variety/chart_info/search_by_es',params)
+    },
+
+    /**
+     * 刷新图表
+     * @param {*} params ChartInfoId
+     * @returns 
+     */
+    refreshChart: params => {
+      return http.get('/cross_variety/chart_info/refresh',params)
+    },
+
+    /**
+     * 图表另存为
+     * @param {*} params ChartInfoId ChartName
+     * @returns 
+     */
+    saveOtherChart: params => {
+      return http.post('/cross_variety/chart_info/copy',params)
+    },
+    
+    /**
+     * 编辑英文名称
+     * @param {*} params 
+     * @returns 
+     */
+    editChartEn: params => {
+      return http.post('/cross_variety/chart_info/en/edit',params)
+    },
+
+    /**
+     * 图表设置语言配置信息
+     * @param {*} params  ChartInfoId
+     * @returns 
+     */
+    chartLangOption: params => {
+      return http.get('/cross_variety/chart_info/relation',params)
+    },
+    
+    /**
+     * 品种列表
+     * @param {*} params 
+     */
+    getVarietyList: params => {
+      return http.get('/cross_variety/variety/list',params)
+    },
+
+    /**
+     * 添加品种
+     * @param {VarietyName} params 
+     * @returns 
+     */
+    varietyAdd: params => {
+      return http.post('/cross_variety/variety/add',params)
+    },
+    
+    /**
+     * 编辑品种
+     * @param {VarietyName ChartVarietyId} params 
+     * @returns 
+     */
+    varietyEdit: params => {
+      return http.post('/cross_variety/variety/edit',params)
+    },
+    
+    /**
+     * 删除品种检测
+     * @param {ChartVarietyId} params 
+     * @returns 
+     */
+    varietyDelCheck: params => {
+      return http.post('/cross_variety/variety/delete/check',params)
+    },
+    
+    /**
+     * 删除品种
+     * @param {ChartVarietyId} params 
+     * @returns 
+     */
+    varietyDel: params => {
+      return http.post('/cross_variety/variety/delete',params)
+    },
+
+    /**
+     * 标签列表
+     * @param {*} params 
+     */
+    getTagList: params => {
+      return http.get('/cross_variety/tag/list',params)
+    },
+
+    /**
+     * 添加标签
+     * @param {TagName} params 
+     * @returns 
+     */
+    tagAdd: params => {
+      return http.post('/cross_variety/tag/add',params)
+    },
+
+    /**
+     * 编辑标签
+     * @param {TagName ChartTagId} params 
+     * @returns 
+     */
+    tagEdit: params => {
+      return http.post('/cross_variety/tag/edit',params)
+    },
+
+    /**
+     * 删除标签检测
+     * @param {ChartTagId} params 
+     * @returns 
+     */
+    tagDelCheck: params => {
+      return http.post('/cross_variety/tag/delete/check',params)
+    },
+
+    /**
+     * 添加标签
+     * @param {ChartTagId} params 
+     * @returns 
+     */
+    tagDel: params => {
+      return http.post('/cross_variety/tag/delete',params)
+    },
+
+    /**
+     * 设置标签关联品种对应信息
+     * @param {
+        "ChartTagId": 1,
+        "VarietyEdb": [
+            {
+                "ChartVarietyId": 2,
+                "EdbInfoId": 103407
+            },
+        ]
+     * } params 
+     * @returns 
+     */
+    setTagRelationVariety: params => {
+      return http.post('/cross_variety/tag/variety_edb/save',params)
+    },
+
+
+    /**
+     * 获取标签关联的品种信息
+     * @param {ChartTagId} params 
+     */
+    getTagRelation: params => {
+      return http.get('/cross_variety/tag/variety_edb/list',params)
+    }
 }
 }

+ 10 - 0
src/api/modules/pptApi.js

@@ -256,6 +256,16 @@ export default{
      */
      */
     transCatalogtoEn:params=>{
     transCatalogtoEn:params=>{
       return http.post('pptv2/batchToEn',params)
       return http.post('pptv2/batchToEn',params)
+    },
+    /**
+     * PPT编辑加锁
+     * @param {*} params 
+     * @param {Number} params.PptId 
+     * @param {Number} params.Status :0仅查看,1编辑中,2编辑完成
+     * @returns 
+     */
+    pptEditLock:params=>{
+        return http.post('pptv2/editing',params)
     }
     }
 
 
 }
 }

+ 10 - 0
src/api/modules/pptEnApi.js

@@ -217,6 +217,16 @@ export const pptEnInterface = {
      */
      */
     transPPTtoReport:params => {
     transPPTtoReport:params => {
       return http.post('/ppt_english/toReport',params)
       return http.post('/ppt_english/toReport',params)
+    },
+    /**
+     * PPT编辑加锁
+     * @param {*} params 
+     * @param {Number} params.PptId 
+     * @param {Number} params.Status :0仅查看,1编辑中,2编辑完成
+     * @returns 
+     */
+    pptEditLock:params=>{
+        return http.post('ppt_english/editing',params)
     }
     }
 
 
 }
 }

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

@@ -287,6 +287,27 @@ export const getMixedCalculateData = params => {
 	return http.post('/datamanage/excel_info/mixed/calculate',params)
 	return http.post('/datamanage/excel_info/mixed/calculate',params)
 }
 }
 
 
+/**
+ * 表格一键刷新
+ * @param {Object} params
+ * @param {Array} params.ExcelCodes 表格唯一编码
+ * @param {String} params.Source 来源,枚举值:report、english_report、smart_report
+ * @param {Number} params.ReportId 报告id
+ * @param {Number} params.ReportChapterId 章节id 非章节传0
+ */
+export const refreshSheet = (params)=>{
+    return http.post('/datamanage/excel_info/table/batch_refresh',params)
+}
+/**
+ * 获取表格刷新结果
+ * @param {Object} params
+ * @param {String} params.Source 来源,枚举值:report、english_report、smart_report
+ * @param {Number} params.ReportId 报告id
+ * @param {Number} params.ReportChapterId 章节id 非章节传0
+ */
+export const getRefreshResult = (params)=>{
+    return http.post('/datamanage/excel_info/table/batch_refresh/result',params)
+}
 
 
 /* =====自定义分析==== */
 /* =====自定义分析==== */
 
 

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

@@ -76,6 +76,26 @@ const apiSmartReport={
     //获取上期已发布报告
     //获取上期已发布报告
     getLastReport:params=>{
     getLastReport:params=>{
         return http.get('/smart_report/last_published_report',params)
         return http.get('/smart_report/last_published_report',params)
+    },
+
+    // 资源库列表
+    imgReourceList:params=>{
+        return http.get('/smart_report/resource/list',params)
+    },
+
+    //新增资源库图片
+    imgReourceAdd:params=>{
+        return http.post('/smart_report/resource/add',params)
+    },
+
+    //资源库图片重命名
+    imgReourceRename:params=>{
+        return http.post('/smart_report/resource/rename',params)
+    },
+
+    //资源库图片删除
+    imgReourceDel:params=>{
+        return http.post('/smart_report/resource/remove',params)
     }
     }
 
 
 }
 }

+ 87 - 2
src/api/modules/thirdBaseApi.js

@@ -186,7 +186,38 @@ const smmDataInterface = {
 	 */
 	 */
   cleanClassify:params=>{
   cleanClassify:params=>{
     return http.post('/datamanage/smm/reset',params)
     return http.post('/datamanage/smm/reset',params)
-  }
+  },
+	// 有色原始数据库
+	/**
+   * 列表
+	*/
+	getYsDataList:params=>{
+		return http.get('datamanage/smm/api/list',params)
+	},
+	/**
+   * 分类列表
+	*/
+	getYsTypeDataList:params=>{
+		return http.get('datamanage/smm/api/type/list',params)
+	},
+	/**
+   * 检验有色指标是否存在
+	*/
+	getYsEdbCodeCheck:params=>{
+		return http.get('datamanage/edb_info/smm/exist/check',params)
+	},
+	/**
+   * 查询有色指标
+	*/
+	getYsEdbCodeSearch:params=>{
+		return http.get('datamanage/edb_info/smm/search',params)
+	},
+	/**
+   * 批量添加有色指标
+	*/
+	ysEdbAddBatch:params=>{
+		return http.post('datamanage/edb_info/smm/batch/add',params)
+	},
 }
 }
 
 
 /* 中国煤炭网 */
 /* 中国煤炭网 */
@@ -720,6 +751,58 @@ const databankInterface = {
     },
     },
 }
 }
 
 
+/* 涌益咨询 */
+const yongyiInterface={
+	/**
+	 * 分类列表
+	 * @param {} params 
+	 * @returns 
+	 */
+	classifyList: params => {
+		return http.get('/datamanage/yongyi/classify',params);
+	},
+	/**
+	 * 获取指标列表详情
+	 */
+	dataList: params => {
+		return http.get('/datamanage/yongyi/index/data',params);
+	},
+	//单个指标数据
+	getTargetDataList:params=>{
+		return http.get('/datamanage/yongyi/single_data',params);
+	},
+	// 搜索
+	getTargetListByName:params=>{
+		return http.get('/datamanage/yongyi/search_list',params);
+	},
+}
+
+/* 汾渭煤炭树 */
+const fwmtInterface={
+	/**
+	 * 分类列表
+	 * @param {} params 
+	 * @returns 
+	 */
+	classifyList: params => {
+		return http.get('/datamanage/fenwei/classify',params);
+	},
+	/**
+	 * 获取指标列表详情
+	 */
+	dataList: params => {
+		return http.get('/datamanage/fenwei/index/data',params);
+	},
+	//单个指标数据
+	getTargetDataList:params=>{
+		return http.get('/datamanage/fenwei/single_data',params);
+	},
+	// 搜索
+	getTargetListByName:params=>{
+		return http.get('/datamanage/fenwei/search_list',params);
+	},
+}
+
 export { 
 export { 
 	lzDataInterface,
 	lzDataInterface,
 	glDataInterface,
 	glDataInterface,
@@ -730,5 +813,7 @@ export {
   sciDataInterface,
   sciDataInterface,
   baiinfoInterface,
   baiinfoInterface,
   nationalInterface,
   nationalInterface,
-  databankInterface
+  databankInterface,
+  yongyiInterface,
+  fwmtInterface
 }
 }

BIN
src/assets/img/approve_m/approve.png


BIN
src/assets/img/approve_m/future-icon.png


+ 3 - 0
src/assets/img/approve_m/future-icon.svg

@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<circle cx="8" cy="8" r="7" stroke="#C0C4CC" stroke-width="2"/>
+</svg>

BIN
src/assets/img/approve_m/passed-icon.png


+ 10 - 0
src/assets/img/approve_m/passed-icon.svg

@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_2561_11064)">
+<path d="M0 8C0 3.58179 3.58179 0 8 0C12.4182 0 16 3.58179 16 8C16 12.4182 12.4182 16 8 16C3.58179 16 0 12.4182 0 8ZM6.55172 11.0411C6.65221 11.1447 6.78931 11.2048 6.9336 11.2086C7.0779 11.2123 7.2179 11.1593 7.32359 11.061L12.5661 6.18703C12.6724 6.08722 12.735 5.94935 12.7399 5.80357C12.7449 5.65779 12.692 5.51596 12.5927 5.40911C12.4934 5.30227 12.3558 5.23909 12.2101 5.2334C12.0643 5.22771 11.9222 5.27997 11.8149 5.37876L6.98483 9.9029L4.71724 7.56469C4.66696 7.51198 4.60675 7.46975 4.54006 7.44043C4.47338 7.41111 4.40155 7.39529 4.32872 7.39387C4.25589 7.39246 4.1835 7.40548 4.11573 7.43219C4.04795 7.4589 3.98614 7.49876 3.93386 7.54948C3.88157 7.6002 3.83985 7.66077 3.81109 7.7277C3.78233 7.79463 3.76712 7.86659 3.76632 7.93943C3.76552 8.01227 3.77915 8.08455 3.80642 8.15209C3.8337 8.21964 3.87408 8.28111 3.92524 8.33297L6.552 11.0411H6.55172Z" fill="#0052D9"/>
+</g>
+<defs>
+<clipPath id="clip0_2561_11064">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>

+ 3 - 0
src/assets/img/approve_m/passed-msg.svg

@@ -0,0 +1,3 @@
+<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M9.50115 0C4.25336 0 0 4.25284 0 9.5C0 14.7472 4.25336 19 9.50115 19C14.7489 19 19 14.7449 19 9.4977C19 4.25054 14.7444 0 9.50115 0ZM14.0439 7.59633L10.3922 11.1855L8.62384 12.9147C8.61695 12.9239 8.60776 12.933 8.59628 12.9445C8.5825 12.9583 8.56642 12.9721 8.55034 12.9859C8.44011 13.0915 8.29542 13.1489 8.14155 13.1489H8.11628C7.95552 13.1489 7.80624 13.0892 7.696 12.979C7.67992 12.9652 7.66614 12.9514 7.65236 12.9399C7.64318 12.9307 7.63629 12.9239 7.6294 12.9147L4.68053 9.96616C4.44168 9.72734 4.45775 9.32318 4.71498 9.06599C4.84588 8.9351 5.02043 8.86162 5.19727 8.86162C5.35803 8.86162 5.50731 8.92132 5.61755 9.03155L8.13006 11.5438L9.4644 10.2394L13.1183 6.65023C13.2286 6.5423 13.3756 6.48489 13.534 6.48489C13.7132 6.48489 13.89 6.56067 14.0209 6.69386C14.2735 6.95564 14.2873 7.3598 14.0439 7.59633Z" fill="#68BB8D"/>
+</svg>

BIN
src/assets/img/approve_m/passed.png


BIN
src/assets/img/approve_m/pending.png


BIN
src/assets/img/approve_m/process-icon.png


+ 6 - 0
src/assets/img/approve_m/process-icon.svg

@@ -0,0 +1,6 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<circle cx="8" cy="8" r="7" fill="white" stroke="#0052D9" stroke-width="2"/>
+<circle cx="4" cy="8.5" r="1.5" fill="#0052D9"/>
+<circle cx="8" cy="8.5" r="1.5" fill="#0052D9"/>
+<circle cx="12" cy="8.5" r="1.5" fill="#0052D9"/>
+</svg>

+ 3 - 0
src/assets/img/approve_m/process-msg.svg

@@ -0,0 +1,3 @@
+<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M9.5 0C4.25327 0 0 4.25324 0 9.50002C0 12.894 1.81074 16.0301 4.75 17.7273C7.68945 19.4242 11.3107 19.4242 14.25 17.7273C17.1895 16.0303 19 12.8942 19 9.50002C19.0002 4.25343 14.7467 0 9.5 0ZM9.5 14.7779C8.91712 14.7779 8.44444 14.3053 8.44444 13.7224C8.44444 13.3454 8.64566 12.9968 8.97222 12.8083C9.29879 12.6198 9.70122 12.6198 10.0278 12.8083C10.3543 12.9968 10.5556 13.3454 10.5556 13.7224C10.5556 14.3051 10.0831 14.7779 9.5 14.7779ZM10.5556 10.5556C10.5556 11.1888 10.1333 11.6111 9.5 11.6111C8.86667 11.6111 8.44444 11.1888 8.44444 10.5556V5.27788C8.44444 4.64459 8.86667 4.22234 9.5 4.22234C10.1333 4.22234 10.5556 4.64459 10.5556 5.27788V10.5556Z" fill="#E98F36"/>
+</svg>

BIN
src/assets/img/approve_m/reject-icon.png


+ 3 - 0
src/assets/img/approve_m/reject-icon.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="M0 7.93442C0.036889 5.7137 0.851645 3.75612 2.51279 2.18473C4.14539 0.640302 6.11295 -0.0867217 8.35598 0.00822671C10.511 0.0994046 12.3505 0.946285 13.8273 2.5179C15.3632 4.15237 16.0877 6.11726 15.9915 8.35695C15.8993 10.5061 15.0568 12.3422 13.4922 13.8175C11.8572 15.3593 9.89104 16.0873 7.6479 15.9917C5.49497 15.8998 3.6592 15.0518 2.18102 13.4843C0.735039 11.951 0.0268387 10.1078 0 7.93442ZM7.19038 7.98972C7.168 8.01406 7.15441 8.02971 7.1399 8.04434C6.69461 8.48983 6.24909 8.93521 5.80368 9.38081C5.46322 9.72142 5.12266 10.062 4.78278 10.4031C4.62677 10.5596 4.57172 10.747 4.62471 10.962C4.68981 11.2261 4.95203 11.4084 5.21859 11.3856C5.37289 11.3724 5.49612 11.3054 5.60347 11.1979C6.38351 10.4164 7.16423 9.63573 7.94484 8.85489C7.96071 8.839 7.97716 8.82392 8.01348 8.78907C8.02684 8.81352 8.03392 8.83797 8.04968 8.85374C8.82812 9.63401 9.60781 10.413 10.3861 11.1935C10.5262 11.3339 10.6882 11.4011 10.8888 11.3838C11.1686 11.3595 11.4141 11.0681 11.3896 10.7885C11.3755 10.6285 11.31 10.4993 11.1977 10.3872C10.4339 9.62464 9.6712 8.86083 8.90818 8.09747C8.80505 7.99418 8.80493 7.99429 8.90749 7.89169C9.67188 7.12696 10.4359 6.36189 11.201 5.59784C11.3367 5.46233 11.4045 5.30466 11.3859 5.11042C11.3538 4.77553 11.0216 4.53764 10.6937 4.61397C10.5534 4.64653 10.4503 4.73097 10.3522 4.82923C9.58337 5.60013 8.81316 6.36966 8.04454 7.1409C8.00776 7.17781 7.98801 7.17895 7.95055 7.14113C7.57515 6.76271 7.19781 6.38623 6.82104 6.00929C6.41195 5.60002 6.0032 5.19029 5.59353 4.78159C5.41857 4.607 5.2106 4.55181 4.9775 4.63751C4.58931 4.78021 4.47145 5.27975 4.78963 5.59499C5.46014 6.25928 6.12528 6.92918 6.79294 7.59645C6.92291 7.72659 7.0547 7.85558 7.19038 7.98972Z" fill="#AD352F"/>
+</svg>

+ 10 - 0
src/assets/img/approve_m/reject-msg.svg

@@ -0,0 +1,10 @@
+<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_5316_6053)">
+<path d="M9.5 19C4.25362 19 0 14.7464 0 9.5C0 4.25362 4.25362 0 9.5 0C14.7464 0 19 4.25362 19 9.5C19 14.7464 14.7464 19 9.5 19ZM9.5 8.38058L5.57808 4.45708C5.50453 4.38405 5.41731 4.32621 5.32141 4.28688C5.2255 4.24756 5.12279 4.2275 5.01914 4.22787C4.91548 4.22824 4.81292 4.24902 4.71729 4.28903C4.62167 4.32903 4.53487 4.38749 4.46183 4.46104C4.38799 4.53391 4.32929 4.62067 4.28911 4.71631C4.24892 4.81195 4.22804 4.9146 4.22767 5.01834C4.22731 5.12209 4.24745 5.22488 4.28696 5.3208C4.32647 5.41673 4.38455 5.5039 4.45787 5.57729L8.38058 9.5L4.45708 13.4219C4.38405 13.4955 4.32621 13.5827 4.28688 13.6786C4.24756 13.7745 4.2275 13.8772 4.22787 13.9809C4.22824 14.0845 4.24902 14.1871 4.28903 14.2827C4.32903 14.3783 4.38749 14.4651 4.46104 14.5382C4.53391 14.612 4.62067 14.6707 4.71631 14.7109C4.81195 14.7511 4.9146 14.772 5.01834 14.7723C5.12209 14.7727 5.22488 14.7525 5.3208 14.713C5.41673 14.6735 5.5039 14.6154 5.57729 14.5421L9.5 10.6194L13.4219 14.5421C13.4955 14.6152 13.5827 14.673 13.6786 14.7123C13.7745 14.7517 13.8772 14.7717 13.9809 14.7713C14.0845 14.771 14.1871 14.7502 14.2827 14.7102C14.3783 14.6702 14.4651 14.6117 14.5382 14.5382C14.612 14.4653 14.6707 14.3785 14.7109 14.2829C14.7511 14.1873 14.772 14.0846 14.7723 13.9809C14.7727 13.8771 14.7525 13.7743 14.713 13.6784C14.6735 13.5825 14.6154 13.4953 14.5421 13.4219L10.6194 9.5L14.5421 5.57808C14.6152 5.50453 14.673 5.41731 14.7123 5.32141C14.7517 5.2255 14.7717 5.12279 14.7713 5.01914C14.771 4.91548 14.7502 4.81292 14.7102 4.71729C14.6702 4.62167 14.6117 4.53487 14.5382 4.46183C14.4653 4.38799 14.3785 4.32929 14.2829 4.28911C14.1873 4.24892 14.0846 4.22804 13.9809 4.22767C13.8771 4.22731 13.7743 4.24745 13.6784 4.28696C13.5825 4.32647 13.4953 4.38455 13.4219 4.45787L9.5 8.38058Z" fill="#D81E06"/>
+</g>
+<defs>
+<clipPath id="clip0_5316_6053">
+<rect width="19" height="19" fill="white"/>
+</clipPath>
+</defs>
+</svg>

BIN
src/assets/img/approve_m/reject.png


BIN
src/assets/img/approve_m/return-icon.png


+ 5 - 0
src/assets/img/approve_m/return-icon.svg

@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<circle cx="8" cy="8" r="8" fill="#999999"/>
+<path d="M6.21355 4.34426C6.26948 4.28793 6.34477 4.255 6.42411 4.25215C6.50345 4.24931 6.5809 4.27677 6.64072 4.32896C6.70055 4.38115 6.73827 4.45416 6.74622 4.53315C6.75418 4.61214 6.73177 4.6912 6.68355 4.75426L6.65563 4.78635L5.10855 6.33301L6.65563 7.87968C6.70906 7.9331 6.74133 8.00407 6.74646 8.07945C6.75159 8.15483 6.72924 8.22951 6.68355 8.28968L6.65563 8.32176C6.60221 8.3752 6.53124 8.40746 6.45586 8.4126C6.38048 8.41773 6.3058 8.39538 6.24563 8.34968L6.21355 8.32176L4.44605 6.55385C4.39262 6.50043 4.36035 6.42946 4.35521 6.35408C4.35008 6.2787 4.37243 6.20402 4.41813 6.14385L4.44605 6.11218L6.21355 4.34426Z" fill="white" stroke="white" stroke-width="0.3"/>
+<path d="M9.25023 6.02051C9.87811 6.01989 10.4811 6.26579 10.9296 6.70528C11.378 7.14477 11.636 7.74273 11.648 8.3705C11.66 8.99827 11.4251 9.60566 10.9938 10.062C10.5625 10.5183 9.96934 10.7871 9.3419 10.8105L9.25023 10.8122H4.6669C4.58772 10.8122 4.5115 10.7821 4.45365 10.728C4.3958 10.674 4.36062 10.6 4.35522 10.521C4.34982 10.442 4.37461 10.3639 4.42458 10.3025C4.47454 10.241 4.54596 10.2009 4.6244 10.1901L4.6669 10.1872H9.25023C9.71244 10.1872 10.1563 10.0064 10.4871 9.68358C10.8179 9.36073 11.0093 8.92135 11.0205 8.45927C11.0317 7.99719 10.8618 7.54905 10.5471 7.21054C10.2323 6.87204 9.79773 6.67001 9.33606 6.64759L9.25023 6.64551H4.6669C4.58772 6.64548 4.5115 6.61541 4.45365 6.56135C4.3958 6.5073 4.36062 6.4333 4.35522 6.35431C4.34982 6.27532 4.37461 6.19722 4.42458 6.1358C4.47454 6.07438 4.54596 6.03422 4.6244 6.02343L4.6669 6.02051H9.25023Z" fill="white" stroke="white" stroke-width="0.3"/>
+</svg>

+ 3 - 0
src/assets/img/approve_m/return-msg.svg

@@ -0,0 +1,3 @@
+<svg width="20" height="18" viewBox="0 0 20 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12.6234 14.45C12.4885 14.45 12.3592 14.4018 12.2638 14.316C12.1685 14.2302 12.1149 14.1138 12.1149 13.9924C12.1149 13.871 12.1685 13.7546 12.2638 13.6688C12.3592 13.583 12.4885 13.5348 12.6234 13.5348C14.2122 13.5348 15.5047 12.3715 15.5047 10.9416C15.5047 9.51163 14.2122 8.34834 12.6234 8.34834H5.21424L8.66102 11.4501C8.75106 11.5369 8.80011 11.6518 8.79783 11.7705C8.79555 11.8893 8.74211 12.0026 8.64879 12.0865C8.55547 12.1705 8.42957 12.2185 8.29765 12.2205C8.16572 12.2225 8.0381 12.1783 7.94169 12.0972L3.26746 7.89071L7.94169 3.6839C8.03708 3.59805 8.16646 3.54982 8.30136 3.54982C8.43626 3.54982 8.56563 3.59805 8.66102 3.6839C8.7564 3.76975 8.80999 3.88618 8.80999 4.00759C8.80999 4.129 8.7564 4.24544 8.66102 4.33129L5.21424 7.43308H12.6234C14.7729 7.43308 16.5217 9.00702 16.5217 10.9416C16.5217 12.8761 14.7729 14.45 12.6234 14.45ZM10 0C4.48576 0 0 4.03749 0 9C0 13.9625 4.48576 18 10 18C15.5139 18 20 13.9625 20 9C20 4.03749 15.5139 0 10 0Z" fill="#797979"/>
+</svg>

BIN
src/assets/img/approve_m/return.png


BIN
src/assets/img/approve_m/select.png


BIN
src/assets/img/approve_m/start.png


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


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


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


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


BIN
src/assets/img/icons/gpt-4-turbo.png


BIN
src/assets/img/icons/gpt-4.png


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


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


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


+ 22 - 10
src/components/chart/chartDetailHandlesWrap.vue

@@ -162,20 +162,32 @@ export default {
             enNameSetting:checkPermissionBtn(productPricePermission.goodsPrice_incomeLine_enNameSetting),
             enNameSetting:checkPermissionBtn(productPricePermission.goodsPrice_incomeLine_enNameSetting),
             del:checkPermissionBtn(productPricePermission.goodsPrice_incomeLine_del),
             del:checkPermissionBtn(productPricePermission.goodsPrice_incomeLine_del),
         }
         }
-        //相关性分析
-        if(path==='/chartrelevance'){
-            return chartrelevanceMap[btn]
+
+         const crossVarietyBtnMap = {
+            share:checkPermissionBtn(statisticPermission.crossVariety_share),
+            addMyChart:checkPermissionBtn(statisticPermission.crossVariety_addMyChart),
+            refresh:checkPermissionBtn(statisticPermission.crossVariety_refresh),
+            otherSave:checkPermissionBtn(statisticPermission.crossVariety_otherSave),
+            edit:checkPermissionBtn(statisticPermission.crossVariety_edit),
+            copyOffice:checkPermissionBtn(statisticPermission.crossVariety_copyOffice),
+            copyWechat:checkPermissionBtn(statisticPermission.crossVariety_copyWechat),
+            enNameSetting:checkPermissionBtn(statisticPermission.crossVariety_enNameSetting),
+            del:checkPermissionBtn(statisticPermission.crossVariety_del),
         }
         }
+        //相关性分析
+        if(path==='/chartrelevance') return chartrelevanceMap[btn]
+
         //拟合方程曲线
         //拟合方程曲线
-        if(path==='/fittingEquationList'){
-            return fittingEquationMap[btn]
-        }
+        else if(path==='/fittingEquationList') return fittingEquationMap[btn]
+        
         //统计特性
         //统计特性
-        if(path==='/statisticFeatureList'){
-            return statisticFeatureMap[btn]
-        }
+        else if(path==='/statisticFeatureList') return statisticFeatureMap[btn]
+
+        //跨品种分析
+        else if(path==='/crossVarietyChartList') return crossVarietyBtnMap[btn]
+
         //商品价格曲线
         //商品价格曲线
-        if(path==='/commordityChartBase'){
+        else if(path==='/commordityChartBase'){
             const {Source,ChartType} = this.chartInfo
             const {Source,ChartType} = this.chartInfo
             if(Source===2&&ChartType===8){//是商品价格曲线
             if(Source===2&&ChartType===8){//是商品价格曲线
                 return priceLineMap[btn]
                 return priceLineMap[btn]

+ 7 - 3
src/components/chart/chartListWrap.vue

@@ -67,15 +67,19 @@ export default {
             return checkPermissionBtn(statisticPermission.corrAnalysis_addMyChart)
             return checkPermissionBtn(statisticPermission.corrAnalysis_addMyChart)
         }
         }
         //拟合方程曲线
         //拟合方程曲线
-        if(path==='/fittingEquationList'){
+        else if(path==='/fittingEquationList'){
             return checkPermissionBtn(statisticPermission.fittingEq_addMyChart)
             return checkPermissionBtn(statisticPermission.fittingEq_addMyChart)
         }
         }
         //统计特性
         //统计特性
-        if(path==='/statisticFeatureList'){
+        else if(path==='/statisticFeatureList'){
             return checkPermissionBtn(statisticPermission.statisticFeature_addMyChart)
             return checkPermissionBtn(statisticPermission.statisticFeature_addMyChart)
         }
         }
+        //跨品种分析
+        else if(path==='/crossVarietyChartList') {
+          return checkPermissionBtn(statisticPermission.crossVariety_addMyChart)
+        }
         //商品价格曲线
         //商品价格曲线
-        if(path==='/commordityChartBase'){
+        else if(path==='/commordityChartBase'){
             const {Source,ChartType} = item
             const {Source,ChartType} = item
             if(Source===2&&ChartType===8){//是商品价格曲线
             if(Source===2&&ChartType===8){//是商品价格曲线
                 return checkPermissionBtn(productPricePermission.goodsPrice_priceLine_addMyChart)
                 return checkPermissionBtn(productPricePermission.goodsPrice_priceLine_addMyChart)

+ 130 - 42
src/components/lzTable.vue

@@ -65,19 +65,107 @@ export default {
 			defalut:'lz'
 			defalut:'lz'
 		}
 		}
 	},
 	},
+	computed: {
+		headerArr(){
+			let arr=['QuotaName','LzCode','Frequency','UnitName','ModifyTime']
+
+			if(this.source==='gl'){
+				arr=['IndexName','IndexCode','FrequencyName','UnitName','UpdateTime']
+			}
+			if(this.source==='smm'){
+				arr=['IndexName','IndexCode','Frequency','Unit','ModifyTime']
+			}
+			if(this.source==='coal'){
+				arr=['IndexName','IndexCode','Frequency','Unit','ModifyTime']
+			}
+			if(this.source==='baiinfo'){
+				arr=['IndexName','IndexCode','Frequency','Unit','ModifyTime']
+			}
+			if(this.source==='yyzx'){
+				arr=['IndexName','IndexCode','Frequency','Unit','ModifyTime']
+			}
+
+			return arr
+		},
+		labelArr(){
+			let temMap=new Map([
+				['QuotaName', '指标名称'],
+				['LzCode', '指标ID'],
+				['Frequency', '频度'],
+				['UnitName', '单位'],
+				['ModifyTime', '更新时间'],
+			])
+
+			if(this.source==='gl'){
+				temMap=new Map([
+					['IndexName', '指标名称'],
+					['IndexCode', '指标ID'],
+					['FrequencyName', '频度'],
+					['UnitName', '单位'],
+					['UpdateTime', '更新时间'],
+				])
+			}
+			if(this.source==='smm'){
+				temMap=new Map([
+					['IndexName', '指标名称'],
+					['IndexCode', '指标ID'],
+					['Frequency', '频度'],
+					['Unit', '单位'],
+					['ModifyTime', '更新时间'],
+				])
+			}
+			if(this.source==='coal'){
+				temMap=new Map([
+					['IndexName', '指标名称'],
+					['IndexCode', '指标ID'],
+					['Frequency', '频度'],
+					['Unit', '单位'],
+					['ModifyTime', '更新时间'],
+				])
+			}
+			if(this.source==='baiinfo'){
+				temMap=new Map([
+					['IndexName', '指标名称'],
+					['IndexCode', '指标ID'],
+					['Frequency', '频度'],
+					['Unit', '单位'],
+					['ModifyTime', '更新时间'],
+				])
+			}
+			if(this.source==='yyzx'){
+				temMap=new Map([
+					['IndexName', '指标名称'],
+					['IndexCode', '指标ID'],
+					['Frequency', '频度'],
+					['Unit', '单位'],
+					['ModifyTime', '更新时间'],
+				])
+			}
+
+			return temMap
+		},
+		dynamic_key(){
+			let key='InputValue'
+			if(['smm','baiinfo','coal','yyzx'].includes(this.source)){
+				key='Value'
+			}
+
+			return key
+		}
+	},
 	data() {
 	data() {
 		return {
 		return {
-			dynamic_key: (this.source === 'smm'||this.source ==='baiinfo')? 'Value' 
-			:this.source==='coal'?'Value': 'InputValue',
-			headerArr: this.source === 'gl' 
-			? ['IndexName','IndexCode','FrequencyName','UnitName','UpdateTime']
-			: this.source === 'smm' 
-			? ['IndexName','IndexCode','Frequency','Unit','ModifyTime']
-			: this.source==='coal'
-			? ['IndexName','IndexCode','Frequency','Unit','ModifyTime']
-      : this.source==='baiinfo'
-      ? ['IndexName','IndexCode','Frequency','Unit','ModifyTime']
-			:['QuotaName','LzCode','Frequency','UnitName','ModifyTime'],
+			// dynamic_key: (this.source === 'smm'||this.source ==='baiinfo')? 'Value' 
+			// :this.source==='coal'?'Value': 'InputValue',
+	// 		headerArr: this.source === 'gl' 
+	// 		? ['IndexName','IndexCode','FrequencyName','UnitName','UpdateTime']
+	// 		: this.source === 'smm' 
+	// 		? ['IndexName','IndexCode','Frequency','Unit','ModifyTime']
+	// 		: this.source==='coal'
+	// 		? ['IndexName','IndexCode','Frequency','Unit','ModifyTime']
+    //   : this.source==='baiinfo'
+    //   ? ['IndexName','IndexCode','Frequency','Unit','ModifyTime']
+	// 		:['QuotaName','LzCode','Frequency','UnitName','ModifyTime'],
 			frequencyType:new Map([
 			frequencyType:new Map([
 				[1,'日度'],
 				[1,'日度'],
 				[2,'周度'],
 				[2,'周度'],
@@ -86,37 +174,37 @@ export default {
 				[5,'年度'],
 				[5,'年度'],
 				[99,'无固定频率'],
 				[99,'无固定频率'],
 			]),
 			]),
-			labelArr: this.source === 'gl' ? new Map([
-				['IndexName', '指标名称'],
-				['IndexCode', '指标ID'],
-				['FrequencyName', '频度'],
-				['UnitName', '单位'],
-				['UpdateTime', '更新时间'],
-			]): this.source === 'smm' ? new Map([
-				['IndexName', '指标名称'],
-				['IndexCode', '指标ID'],
-				['Frequency', '频度'],
-				['Unit', '单位'],
-				['ModifyTime', '更新时间'],
-			]) :this.source === 'coal' ? new Map([
-				['IndexName', '指标名称'],
-				['IndexCode', '指标ID'],
-				['Frequency', '频度'],
-				['Unit', '单位'],
-				['ModifyTime', '更新时间'],
-			]) :this.source==='baiinfo'?new Map([
-        ['IndexName', '指标名称'],
-				['IndexCode', '指标ID'],
-				['Frequency', '频度'],
-				['Unit', '单位'],
-				['ModifyTime', '更新时间'],
-      ]):new Map([
-				['QuotaName', '指标名称'],
-				['LzCode', '指标ID'],
-				['Frequency', '频度'],
-				['UnitName', '单位'],
-				['ModifyTime', '更新时间'],
-			]),
+			// labelArr: this.source === 'gl' ? new Map([
+			// 	['IndexName', '指标名称'],
+			// 	['IndexCode', '指标ID'],
+			// 	['FrequencyName', '频度'],
+			// 	['UnitName', '单位'],
+			// 	['UpdateTime', '更新时间'],
+			// ]): this.source === 'smm' ? new Map([
+			// 	['IndexName', '指标名称'],
+			// 	['IndexCode', '指标ID'],
+			// 	['Frequency', '频度'],
+			// 	['Unit', '单位'],
+			// 	['ModifyTime', '更新时间'],
+			// ]) :this.source === 'coal' ? new Map([
+			// 	['IndexName', '指标名称'],
+			// 	['IndexCode', '指标ID'],
+			// 	['Frequency', '频度'],
+			// 	['Unit', '单位'],
+			// 	['ModifyTime', '更新时间'],
+			// ]) :this.source==='baiinfo'?new Map([
+        	// 	['IndexName', '指标名称'],
+			// 	['IndexCode', '指标ID'],
+			// 	['Frequency', '频度'],
+			// 	['Unit', '单位'],
+			// 	['ModifyTime', '更新时间'],
+      		// ]):new Map([
+			// 	['QuotaName', '指标名称'],
+			// 	['LzCode', '指标ID'],
+			// 	['Frequency', '频度'],
+			// 	['UnitName', '单位'],
+			// 	['ModifyTime', '更新时间'],
+			// ]),
 		};
 		};
 	},
 	},
 	methods: {
 	methods: {

+ 146 - 0
src/components/notificationMsg.vue

@@ -0,0 +1,146 @@
+<template>
+    <!-- 消息通知 -->
+    <el-popover
+        placement="bottom"
+        width="443"
+        trigger="click" v-model="visible">
+        <div class="notifation-wrap">
+            <!-- 防止tabs在popover前渲染,会导致tab选中状态不正确 -->
+            <el-tabs v-model="activeName" v-if="visible">
+                <el-tab-pane :label="`研报审批(${UnreadTotal})`" name="first"></el-tab-pane>
+            </el-tabs>
+            <div class="massage-list" v-if="visible">
+                <div class="message-item" :class="{'IsRead':item.IsRead}" v-for="item in msgList" :key="item.Id" @click="readMsg(item)">
+                    <span class="icon">
+                        <img :src="require(`@/assets/img/approve_m/${approveState[item.ApproveState]||'process'}-msg.svg`)" alt="">
+                    </span>
+                    <div class="info">
+                        <div class="head">
+                            <span class="title">{{item.Content}}</span>
+                            <span class="time">{{item.CreateTime}}</span>
+                        </div>
+                        <div class="content">{{item.Remark||''}}&nbsp;</div>
+                    </div>
+                </div>
+                <tableNoData v-if="!msgList.length" text="暂无消息"></tableNoData>
+            </div>
+            <el-button type="text" class="close-btn" @click="visible=false">关闭</el-button>
+        </div>
+        <span slot="reference" @click="visible = !visible" class="msg-btn">
+            <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M16.7344 15.4904L15.2941 12.9564V7.84847C15.2941 5.89142 13.8231 3.77337 11.6786 2.99732C11.5741 1.96012 10.8811 1.20374 9.97287 1.20374C9.06595 1.20374 8.37036 1.96014 8.26717 2.99732C6.12392 3.77337 4.65292 5.8914 4.65292 7.84847V12.9564L3.14258 15.6146C3.04183 15.7903 3.04429 16.0054 3.14504 16.1799C3.24581 16.3544 3.43263 16.4601 3.63415 16.4601H7.22871C7.49293 17.7357 8.62233 18.6967 9.97289 18.6967C11.3247 18.6967 12.4541 17.7357 12.7171 16.4601H16.3116C16.3215 16.4601 16.3288 16.4601 16.3374 16.4601C16.6508 16.4601 16.904 16.2082 16.904 15.8948C16.904 15.7362 16.8401 15.5925 16.7344 15.4904ZM9.97287 2.33803C10.1769 2.33803 10.3415 2.49286 10.4472 2.7239C10.2899 2.70792 10.1375 2.67106 9.97287 2.67106C9.8082 2.67106 9.65583 2.70792 9.49851 2.7239C9.60422 2.49284 9.76889 2.33803 9.97287 2.33803ZM9.97287 17.5636C9.25396 17.5636 8.65303 17.1016 8.41951 16.4601H11.5262C11.2927 17.1015 10.693 17.5636 9.97287 17.5636ZM4.60745 15.3282L5.71102 13.3853C5.76015 13.3017 5.78719 13.2034 5.78719 13.1051V7.84847C5.78719 5.93934 7.57648 3.80413 9.97287 3.80413C12.3692 3.80413 14.161 5.93934 14.161 7.84847V13.1051C14.161 13.2034 14.1868 13.3017 14.2347 13.3853L15.3395 15.3282H4.60745Z" fill="currentColor"/>
+            </svg>
+            <div class="unread" v-if="UnreadTotal">{{UnreadTotal>99?'99+':UnreadTotal}}</div>
+        </span>
+    </el-popover>
+</template>
+
+<script>
+import {approveInterence} from '@/api/modules/approve.js';
+export default {
+    data() {
+        this.approveState=['','process','passed','reject','return',]
+        return {
+            activeName:'first',
+            visible:false,
+            msgList:[],
+            UnreadTotal:0
+        };
+    },
+    watch:{
+        visible(val){
+            if(val){
+                this.getMsgList()
+            }
+        }
+    },
+    methods:{
+        readMsg(msg){
+            const {ApproveState,ReportApproveId,Id} = msg
+            approveInterence.readApproveMsg({
+                MessageId:Id
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                this.getMsgList()
+            })
+            const type = ApproveState===1?'approve':ApproveState===4?'detail':'myself'
+            this.$router.push({
+                path:'/approveDetail',
+                query:{
+                    type,
+                    approveId:ReportApproveId
+                }
+            })
+        },
+        getMsgList(){
+            approveInterence.getApproveMsgList({
+                CurrentIndex:1,
+                PageSize:1000
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                this.msgList = res.Data.List||[]
+                this.UnreadTotal = res.Data.UnreadTotal||0
+            })
+        }
+    }
+};
+</script>
+
+<style lang="scss">
+.notifation-wrap{
+    position:relative;
+    .massage-list{
+        padding: 0 10px;
+        max-height: 320px;
+        overflow-y: auto;
+        .message-item{
+            cursor: pointer;
+            display: flex;
+            padding: 5px 0;
+            border-bottom: 1px solid #E4E7ED;
+            color:#333;
+            &.IsRead{
+                color:#999;
+            }
+            .icon{
+                width:40px;
+                display: flex;
+                align-items: flex-start;
+                justify-content: center;
+            }
+            .info{
+                flex:1;
+                .head{
+                    display: flex;
+                    justify-content: space-between;
+                }
+
+            }
+        }
+    }
+    .close-btn{
+        position:absolute;
+        top:0;
+        right:0;
+        box-sizing: border-box;
+    }
+}
+.msg-btn{
+    cursor: pointer;
+    display: inline-block;
+    width: 50px;
+    text-align: center;
+    position: relative;
+    .unread{
+        position: absolute;
+        width:23px;
+        height:14px;
+        color:#fff;
+        background-color:#AD352F;
+        border-radius: 40px;
+        top:-4px;
+        right:4px;
+        font-size: 12px;
+    }
+}
+</style>

+ 65 - 0
src/mixins/reportApproveConfig.js

@@ -0,0 +1,65 @@
+/*
+    研报及审批配置,涉及到:
+    智能研报
+    中文研报(除晨周报)
+    英文研报
+    审批流配置
+    审批管理
+    审批详情
+ */
+import {etaBaseConfigInterence} from '@/api/modules/etaBaseConfigApi.js';
+import {approveInterence} from '@/api/modules/approve.js';
+export default{
+    data(){
+        return{
+            ReportApproveType:'',
+            IsReportApprove:false,
+            pageLoading:false,
+            hasApproveFlow:false,
+            checkLoading:false,
+        }
+    },
+    computed:{
+        //是否开启审批流
+        isApprove(){
+            return this.IsReportApprove
+        },
+        //是否开启了ETA审批流
+        isETAApprove(){
+            return this.IsReportApprove&&this.ReportApproveType==='eta'
+        },
+        //是否开启了接口审批
+        isOtherApprove(){
+            return this.IsReportApprove&&this.ReportApproveType==='other'
+        },
+    },
+    methods:{
+        async getBaseConfig(){
+            //从基本配置中获取是否开启审批流的数据
+            this.pageLoading = true
+            const res = await etaBaseConfigInterence.getBaseConfig()
+            this.pageLoading = false
+            if(res.Ret!==200) return
+            const {IsReportApprove='',ReportApproveType=''} = res.Data
+            this.IsReportApprove = IsReportApprove==='true'?true:false,
+            this.ReportApproveType = ReportApproveType
+        },
+        //检查是否有审批流
+        checkClassifyNameArr(type=1,classify=[]){
+            this.checkLoading=true
+            let params = {
+                ReportType:type,
+                ClassifyFirstId:classify[classify.length-2]||0,
+                ClassifySecondId:classify[classify.length-1]||0,
+            }
+            approveInterence.checkClassifyApprove(params).then(res=>{
+                this.checkLoading=false
+                if(res.Ret!==200) return 
+                this.hasApproveFlow = res.Data||false
+            })
+        },
+    },
+    mounted(){
+        this.getBaseConfig()
+    }
+}

+ 27 - 0
src/routes/modules/approveRoutes.js

@@ -0,0 +1,27 @@
+const home = r => require.ensure([], () => r(require('@/views/Home.vue')), 'Home'); //主页
+export default [
+    {
+        path:'/',
+        component:home,
+        name:'审批管理',
+        hidden:false,
+        icon_path: require('@/assets/img/home/data_ic.png'),
+        children:[{
+            path:'approveList',
+            name:'审批列表',
+            component:()=>import('@/views/approve_manage/approveList.vue'),
+            hidden:false
+        },{
+            path:'approveDetail',
+            name:'审批详情',
+            component:()=>import('@/views/approve_manage/approveDetail.vue'),
+            hidden:false,
+            meta: {
+                pathFrom: "approveList",
+                pathName: "审批列表",
+                keepAlive: false,
+              },
+        }
+        ]
+    }
+]

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

@@ -229,17 +229,17 @@ export default [
 			{
 			{
 				path: 'chartrelevance',
 				path: 'chartrelevance',
 				name: '相关性分析',
 				name: '相关性分析',
-				component:()=>import('@/views/chartRelevance_manage/list.vue')
+				component:()=>import('@/views/chartRelevance_manage/relevance/list.vue')
 			},
 			},
 			{
 			{
 				path: 'fittingEquationList',
 				path: 'fittingEquationList',
 				name: '拟合方程曲线',
 				name: '拟合方程曲线',
-				component:()=>import('@/views/chartRelevance_manage/fittingEquationList.vue')
+				component:()=>import('@/views/chartRelevance_manage/fittingEquation/fittingEquationList.vue')
 			},
 			},
 			{
 			{
 				path: 'fittingEquationChartEditor',
 				path: 'fittingEquationChartEditor',
 				name: '添加图表',
 				name: '添加图表',
-				component: () => import('@/views/chartRelevance_manage/fittingEquationChartEditor.vue'),
+				component: () => import('@/views/chartRelevance_manage/fittingEquation/fittingEquationChartEditor.vue'),
 				meta: { 
 				meta: { 
 					pathFrom: "fittingEquationList",
 					pathFrom: "fittingEquationList",
           			pathName: "拟合方程曲线",
           			pathName: "拟合方程曲线",
@@ -248,7 +248,7 @@ export default [
 			{
 			{
 				path: 'relevancechartEditor',
 				path: 'relevancechartEditor',
 				name: '编辑图表',
 				name: '编辑图表',
-				component:()=>import('@/views/chartRelevance_manage/relevanceChartEditor.vue'),
+				component:()=>import('@/views/chartRelevance_manage/relevance/relevanceChartEditor.vue'),
 				meta: { 
 				meta: { 
 					pathFrom: "chartrelevance",
 					pathFrom: "chartrelevance",
           			pathName: "相关性图表",
           			pathName: "相关性图表",
@@ -257,17 +257,31 @@ export default [
 			{
 			{
 				path: 'statisticFeatureList',
 				path: 'statisticFeatureList',
 				name: '统计特征',
 				name: '统计特征',
-				component: () => import('@/views/chartRelevance_manage/statisticFeatureList.vue')
+				component: () => import('@/views/chartRelevance_manage/statistic/statisticFeatureList.vue')
 			},
 			},
 			{
 			{
 				path: 'statisticFeatureChartEditor',
 				path: 'statisticFeatureChartEditor',
 				name: '编辑图表',
 				name: '编辑图表',
-				component:()=>import('@/views/chartRelevance_manage/statisticFeatureChartEditor.vue'),
+				component:()=>import('@/views/chartRelevance_manage/statistic/statisticFeatureChartEditor.vue'),
 				meta: { 
 				meta: { 
 					pathFrom: "statisticFeatureList",
 					pathFrom: "statisticFeatureList",
           			pathName: "统计特征",
           			pathName: "统计特征",
 				}
 				}
-			}
+			},
+			{
+				path: 'crossVarietyChartList',
+				name: '跨品种分析',
+				component: () => import('@/views/chartRelevance_manage/crossVarietyAnalysis/list.vue')
+			},
+			{
+				path: 'crossVarietyChartEditor',
+				name: '编辑图表',
+				component:()=>import('@/views/chartRelevance_manage/crossVarietyAnalysis/chartEditor.vue'),
+				meta: { 
+					pathFrom: "crossVarietyChartList",
+          pathName: "跨品种分析",
+				}
+			},
 		]
 		]
 	},
 	},
 
 

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

@@ -201,6 +201,22 @@ export default [
           keepAlive: false,
           keepAlive: false,
         },
         },
       },
       },
+      {
+        path: "yyzx",
+        component: () => import("@/views/dataEntry_manage/thirdBase/YyzxData.vue"),
+        name: "涌益咨询",
+        hidden: false,
+        meta: {
+          keepAlive: false,
+        },
+      },
+      {
+        path: "ysTarget",
+        component: () =>
+          import("@/views/dataEntry_manage/thirdBase/ysTargetBase.vue"),
+        name: "有色原始数据库",
+        hidden: false,
+      },
       {
       {
         path: "fwmtData",
         path: "fwmtData",
         component: () => import("@/views/dataEntry_manage/thirdBase/FwmtData.vue"),
         component: () => import("@/views/dataEntry_manage/thirdBase/FwmtData.vue"),

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

@@ -323,6 +323,18 @@ export default [
         name: "外部链接配置",
         name: "外部链接配置",
         hidden: true,
         hidden: true,
       },
       },
+      {
+        path: "approveSetting",
+        component: () => import("@/views/approve_manage/approveSetting.vue"),
+        name: "审批流配置",
+        hidden: true,
+      },
+      {
+        path: "approveEdit",
+        component: () => import("@/views/approve_manage/approveEdit.vue"),
+        name: "编辑审批流",
+        hidden:true,
+      },
       {
       {
         path: "dataSourceAccountList",
         path: "dataSourceAccountList",
         component: () => import("@/views/dataSource_manage/accountList.vue"),
         component: () => import("@/views/dataSource_manage/accountList.vue"),

+ 44 - 5
src/utils/buttonConfig.js

@@ -42,7 +42,7 @@ export const reportManageBtn={
     reportManage_reportView:'smartReportManage:reportView',//研报预览:即是否能点击研报名称跳转预览页面
     reportManage_reportView:'smartReportManage:reportView',//研报预览:即是否能点击研报名称跳转预览页面
     reportManage_reportView_wechartShare:'smartReportManage:reportView:wechartShare',//研报预览页面-微信分享
     reportManage_reportView_wechartShare:'smartReportManage:reportView:wechartShare',//研报预览页面-微信分享
     reportManage_reportView_copyWechat:'smartReportManage:reportView:copyWechat',//研报预览页面-复制链接
     reportManage_reportView_copyWechat:'smartReportManage:reportView:copyWechat',//研报预览页面-复制链接
-    reportManage_reportView_exportImg:'smartReportManage:reportView:exportImg',//研报预览页面-导出图片
+    reportManage_exportImg:'smartReportManage:exportImg',//导出图片
     reportManage_audioDownload:'smartReportManage:audioDownload',//音频下载
     reportManage_audioDownload:'smartReportManage:audioDownload',//音频下载
     reportManage_audioUpload:'smartReportManage:audioUpload',//音频上传
     reportManage_audioUpload:'smartReportManage:audioUpload',//音频上传
     reportManage_reportDel:'smartReportManage:reportDel',//删除研报
     reportManage_reportDel:'smartReportManage:reportDel',//删除研报
@@ -233,12 +233,13 @@ export const dataSourcePermission = {
     eiaData_export:'eiaData:export',
     eiaData_export:'eiaData:export',
     /*--------国家统计局---- */
     /*--------国家统计局---- */
     gjtjjData_export:'gjtjjData:export',
     gjtjjData_export:'gjtjjData:export',
-
     /*--------数据报表管理---- */
     /*--------数据报表管理---- */
     /*--------数据源终端管理---- */
     /*--------数据源终端管理---- */
     dataSource_account_add:'dataSourceAccount:add',//新增终端账号
     dataSource_account_add:'dataSourceAccount:add',//新增终端账号
     dataSource_account_edit:'dataSourceAccount:edit',//编辑
     dataSource_account_edit:'dataSourceAccount:edit',//编辑
     dataSource_account_enable:'dataSourceAccount:enable',//禁用/启用
     dataSource_account_enable:'dataSourceAccount:enable',//禁用/启用
+    /*--------涌益咨询---- */
+    yyzxData_export:'yyzx:exportData'
 }
 }
 
 
 /*
 /*
@@ -513,6 +514,24 @@ export const statisticPermission = {
     fittingEq_refresh:'fittingEq:refresh',
     fittingEq_refresh:'fittingEq:refresh',
     fittingEq_addMyChart:'fittingEq:addMyChart',
     fittingEq_addMyChart:'fittingEq:addMyChart',
     fittingEq_share:'fittingEq:share',
     fittingEq_share:'fittingEq:share',
+
+    /* 跨品种分析 */
+    crossVariety_addChart:'crossVariety:addChart',//添加图表按钮
+    crossVariety_onlyMine:'crossVariety:onlyMine',//只看我的
+    crossVariety_classifyOpt_edit:'crossVariety:classifyOpt:edit',//添加编辑分类
+    crossVariety_classifyOpt_delete:'crossVariety:classifyOpt:delete',//删除分类
+    crossVariety_variety_edit: 'crossVariety:variety:edit',//品种管理
+    crossVariety_tag_edit: 'crossVariety:tag:edit',//标签管理
+        /*---图表操作栏--- */
+    crossVariety_del:'crossVariety:del',
+    crossVariety_enNameSetting:'crossVariety:enNameSetting',
+    crossVariety_copyWechat:'crossVariety:copyWechat',
+    crossVariety_copyOffice:'crossVariety:copyOffice',
+    crossVariety_edit:'crossVariety:edit',
+    crossVariety_otherSave:'crossVariety:otherSave',
+    crossVariety_refresh:'crossVariety:refresh',
+    crossVariety_addMyChart:'crossVariety:addMyChart',
+    crossVariety_share:'crossVariety:share',
 }
 }
 /*
 /*
  * --------------------------------------------------------------------------供应分析------------------------------------------------
  * --------------------------------------------------------------------------供应分析------------------------------------------------
@@ -612,7 +631,7 @@ export const baseConfigPermission = {
     etaBaseConfig_ppt:'etaBaseConfig:ppt',
     etaBaseConfig_ppt:'etaBaseConfig:ppt',
     etaBaseConfig_watermark:'etaBaseConfig:watermark',
     etaBaseConfig_watermark:'etaBaseConfig:watermark',
     etaBaseConfig_watermark_ybChart:'etaBaseConfig:watermark:ybChart',//如果没权限,表单不显示也不校验
     etaBaseConfig_watermark_ybChart:'etaBaseConfig:watermark:ybChart',//如果没权限,表单不显示也不校验
-
+    etaBaseConfig_approve:'etaBaseConfig:approve',//研报审批
 }
 }
 
 
 /*-----------外部链接配置-------- */
 /*-----------外部链接配置-------- */
@@ -622,11 +641,30 @@ export const outlinkConfigPermission = {
     outlinkListConfig_edit:'outlinkListConfig:edit',//编辑
     outlinkListConfig_edit:'outlinkListConfig:edit',//编辑
     outlinkListConfig_del:'outlinkListConfig:del',//删除
     outlinkListConfig_del:'outlinkListConfig:del',//删除
 }
 }
+/*----------审批流配置----*/
+export const approveFlowPermission = {
+    reportApprove_save:'reportApprove:save',//保存
+    reportApprove_remove:'reportApprove:remove',//删除
+    reportApprove_edit:'reportApprove:edit',//编辑审批流(按钮)
+    reportApprove_add:'reportApprove:add',//添加审批流
+}
+/*
+ * --------------------------------------------------------------------------审批管理------------------------------------------------
+*/
+export const approvePermission = {
+    reportApprove_approve:'reportApprove:approve',//审批(列表中的按钮)
+    reportApprove_reject:'reportApprove:reject',//驳回(列表中的按钮)
+    reportApprove_agree:'reportApprove:agree',//通过(审批详情-通过按钮)
+    reportApprove_detail:'reportApprove:detail',//详情(列表中的按钮)
+    reportApprove_rejectreason:'reportApprove:rejectreason',//驳回理由(列表中的按钮)
+    reportApprove_return:'reportApprove:return',//返回(审批详情-返回按钮)
+    reportApprove_repeal:'reportApprove:repeal',//撤回(列表中的按钮,审批详情-撤回按钮)
+}
 
 
 
 
 //创建了新的ManageBtn记得添加到这里
 //创建了新的ManageBtn记得添加到这里
 const btnMap  = {
 const btnMap  = {
-    reportManageBtn,enReportManageBtn,
+    reportManageBtn,enReportManageBtn,smartReportManageBtn,
     classifyBtn,enClassifyBtn,authorManage,
     classifyBtn,enClassifyBtn,authorManage,
     enChartPermission,cloudDisk,
     enChartPermission,cloudDisk,
     pptPermission,enPPTPermission,
     pptPermission,enPPTPermission,
@@ -637,7 +675,8 @@ const btnMap  = {
     statisticPermission,stockPlantPermission,
     statisticPermission,stockPlantPermission,
     productPricePermission,sysDepartPermission,
     productPricePermission,sysDepartPermission,
     operateAuthPermission,baseConfigPermission,
     operateAuthPermission,baseConfigPermission,
-    outlinkConfigPermission
+    outlinkConfigPermission,approveFlowPermission,
+    approvePermission
 }
 }
 
 
 /**
 /**

+ 1 - 0
src/utils/parseData.js

@@ -2,6 +2,7 @@ import ParserData from '@/api/crypto.js';
 /* 解密数据处理 */
 /* 解密数据处理 */
 export function parseData(response) {
 export function parseData(response) {
   const headKeyStr=response.headers.dk
   const headKeyStr=response.headers.dk
+  sessionStorage.setItem('dk',headKeyStr);
   const desKey=ParserData.Des3Decrypt(headKeyStr,'JMCqSoUrTAmyNNIRb0TtlrPk')
   const desKey=ParserData.Des3Decrypt(headKeyStr,'JMCqSoUrTAmyNNIRb0TtlrPk')
   let result = process.env.NODE_ENV == "production"
   let result = process.env.NODE_ENV == "production"
   ? JSON.parse(ParserData.Des3Decrypt(response.data,desKey))
   ? JSON.parse(ParserData.Des3Decrypt(response.data,desKey))

+ 8 - 1
src/utils/svgToblob.js

@@ -50,7 +50,14 @@ export function copyFit(value) {
     navigator.clipboard.writeText(value)
     navigator.clipboard.writeText(value)
   }else {
   }else {
     setTimeout(() => {
     setTimeout(() => {
-      bus.$copyText(value)
+      const input = document.createElement('input')
+      input.setAttribute('readonly','readonly')
+      input.setAttribute('id',new Date().getTime())
+      input.value = value
+      document.body.appendChild(input)
+      input.select();
+      document.execCommand('copy');
+      document.body.removeChild(input);
     })
     })
   }
   }
 
 

+ 18 - 3
src/views/Home.vue

@@ -105,7 +105,7 @@
                       :style="`display: flex;align-items:center;color:${
                       :style="`display: flex;align-items:center;color:${
                         child.path === activePath ? $setting.theme_color : '#666'
                         child.path === activePath ? $setting.theme_color : '#666'
                       }`"
                       }`"
-                      @click="(e) => e.preventDefault()"
+                      @click="handleClickSubMenuItem(child,$event)"
                     >
                     >
                       <svg t="1689672247666" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7676" width="30" height="30"><path d="M640 499.2v25.6a21.333333 21.333333 0 0 1-21.333333 21.333333h-213.333334a21.333333 21.333333 0 0 1-21.333333-21.333333v-25.6a21.333333 21.333333 0 0 1 21.333333-21.333333h213.333334a21.333333 21.333333 0 0 1 21.333333 21.333333z"  p-id="7677" :fill="child.path === activePath ? $setting.theme_color : '#666'"></path></svg>
                       <svg t="1689672247666" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7676" width="30" height="30"><path d="M640 499.2v25.6a21.333333 21.333333 0 0 1-21.333333 21.333333h-213.333334a21.333333 21.333333 0 0 1-21.333333-21.333333v-25.6a21.333333 21.333333 0 0 1 21.333333-21.333333h213.333334a21.333333 21.333333 0 0 1 21.333333 21.333333z"  p-id="7677" :fill="child.path === activePath ? $setting.theme_color : '#666'"></path></svg>
                       <span style="margin-left:15px;">{{ child.name }}</span>
                       <span style="margin-left:15px;">{{ child.name }}</span>
@@ -248,7 +248,8 @@
                 style="width: 84px;height: 24; cursor: pointer;" />
                 style="width: 84px;height: 24; cursor: pointer;" />
                 </div>
                 </div>
               </div>
               </div>
-
+               <!-- 消息通知 -->
+              <notification-msg ref="notification"/>
               <el-dropdown trigger="click" style="width:130px;">
               <el-dropdown trigger="click" style="width:130px;">
                 <span class="el-dropdown-link userinfo-inner">
                 <span class="el-dropdown-link userinfo-inner">
                   <img src="~@/assets/img/home/avatar.png"/>
                   <img src="~@/assets/img/home/avatar.png"/>
@@ -316,13 +317,15 @@ import questionnaireDia from "../components/questionnaireDia.vue";
 import EventBus from "@/api/bus.js";
 import EventBus from "@/api/bus.js";
 
 
 import {recordActiveLoginFun,loginEndCalc} from "@/utils/TimeOnPage.js"
 import {recordActiveLoginFun,loginEndCalc} from "@/utils/TimeOnPage.js"
+import NotificationMsg from "../components/notificationMsg.vue";
 
 
 export default {
 export default {
   components: {
   components: {
     PwdDlg,
     PwdDlg,
     questionMsgDia,
     questionMsgDia,
     questionnaireDia,
     questionnaireDia,
-  },
+    NotificationMsg
+},
   inject: ["reload"],
   inject: ["reload"],
   filters: {
   filters: {
     formatDate(e) {
     formatDate(e) {
@@ -463,6 +466,7 @@ export default {
       //链接系统
       //链接系统
       linkSystems: this.$setting.linkSystems,
       linkSystems: this.$setting.linkSystems,
       bus_code:"",
       bus_code:"",
+
     };
     };
   },
   },
   created() {
   created() {
@@ -488,8 +492,19 @@ export default {
       this.getMenuList();
       this.getMenuList();
     }
     }
     this.getPublicSettings();
     this.getPublicSettings();
+    this.$refs.notification&&this.$refs.notification.getMsgList()
   },
   },
   methods: {
   methods: {
+    handleClickSubMenuItem(item,e){
+      e.preventDefault();
+      if(item.path==='AIQA'){
+        e.stopPropagation();
+        let { href } = this.$router.resolve({
+          path:'/'+item.path
+        });
+        window.open(href, '_blank')
+      }
+    },
     // 获取商家Code
     // 获取商家Code
     getBusinessCodeFun(){
     getBusinessCodeFun(){
       getBusinessCode().then(res=>{
       getBusinessCode().then(res=>{

+ 12 - 12
src/views/Login.vue

@@ -247,15 +247,15 @@ export default {
                                 case "researcher":
                                 case "researcher":
                                     path = "/reportlist";
                                     path = "/reportlist";
                                     break;
                                     break;
-                                case "compliance": //合规
-                                    path = "/contractapprovallist";
-                                    break;
+                                // case "compliance": //合规
+                                //     path = "/contractapprovallist";
+                                //     break;
                                 case "special_researcher": //特邀研究员
                                 case "special_researcher": //特邀研究员
                                     path = "/dataList";
                                     path = "/dataList";
                                     break;
                                     break;
-                                case "special_ficc_seller":
-                                    path = "/meetingCalendar";
-                                    break;
+                                // case "special_ficc_seller":
+                                //     path = "/meetingCalendar";
+                                //     break;
                                 default:
                                 default:
                                     path = await this.getOtherRolePath("myCalendar");
                                     path = await this.getOtherRolePath("myCalendar");
                             }
                             }
@@ -474,15 +474,15 @@ export default {
                 case "researcher":
                 case "researcher":
                     path = "/reportlist";
                     path = "/reportlist";
                     break;
                     break;
-                case "compliance": //合规
-                    path = "/contractapprovallist";
-                    break;
+                // case "compliance": //合规
+                //     path = "/contractapprovallist";
+                //     break;
                 case "special_researcher": //特邀研究员
                 case "special_researcher": //特邀研究员
                     path = "/dataList";
                     path = "/dataList";
                     break;
                     break;
-                case "special_ficc_seller":
-                    path = "/meetingCalendar";
-                    break;
+                // case "special_ficc_seller":
+                //     path = "/meetingCalendar";
+                //     break;
                 default:
                 default:
                     path = await this.getOtherRolePath("myCalendar");
                     path = await this.getOtherRolePath("myCalendar");
             }
             }

+ 386 - 0
src/views/approve_manage/approveDetail.vue

@@ -0,0 +1,386 @@
+<template>
+    <!-- 审批详情:查看、进行审批操作 -->
+    <div class="approve-detail-wrap" v-if="isETAApprove">
+        <div class="approve-detail">
+            <div class="approve-info">
+                <span>研报名称:{{reportInfo.title||''}}</span>
+                <span>研报分类:{{reportInfo.classify||''}}</span>
+                <span style="min-width: 100px;">发起人:{{reportInfo.approver||''}}</span>
+            </div>
+            <div class="approve-content" 
+                v-loading="isLoading"
+                element-loading-text="研报加载中...">
+                <component v-if="reportInfo.reportId&&!isError"
+                    :is="reportInfo.componentName"
+                    :reportId="reportInfo.reportId"
+                    :isPreview="true"
+                    :isEn="reportInfo.type===2"
+                    @reportStartLoading="isLoading=true"
+                    @reportEndLoading="isLoading=false"
+                    @reportError="isError=true"
+                ></component>
+                <tableNoData v-if="isError" text="无法获取到报告内容,该报告可能已被删除!"></tableNoData>
+            </div>
+        </div>
+        <div class="approve-tool">
+            <div class="tool-btn">
+                <!-- 根据审批的状态决定显示 -->
+                <el-button type="danger" @click="changeApprove('reject')"
+                    v-if="formType==='approve'&&approveInfo.isCurrentApprover&&permissionBtn.isShowBtn('approvePermission','reportApprove_reject')">驳回</el-button>
+                <el-button type="primary" @click="changeApprove('pass')"
+                    v-if="formType==='approve'&&approveInfo.isCurrentApprover&&permissionBtn.isShowBtn('approvePermission','reportApprove_agree')">同意</el-button>
+                <el-button type="primary" @click="changeApprove('return')"
+                    v-if="formType==='myself'&&approveInfo.state!==4&&permissionBtn.isShowBtn('approvePermission','reportApprove_repeal')">撤销</el-button>
+                <el-button type="primary" plain @click="$router.replace(`/approveList?formType=${formType}`)">返回</el-button>
+            </div>
+            <div class="approve-timeline-wrap">
+                <p>审批流程</p>
+                <div class="timeline">
+                    <TimeLine 
+                        :TimeLineData="TimeLineData"
+                    />
+                </div>
+                <div class="approve-status" >
+                    <img :src="require(`@/assets/img/approve_m/${approveInfo.stateText||'pending'}.png`)" alt="">
+                </div>
+            </div>
+        </div>
+        <RejectDialog 
+            :isDetailDialogShow="isDetailDialogShow"
+            :isEdit="true"
+            @close="isDetailDialogShow=false;"
+            @edit="rejectApprove"
+        />
+    </div>
+    <div class="nodata-wrap approve-page-wrap" v-else>
+        <tableNoData :text="pageLoading?'':'系统暂未开通审批流程,请开启审批流程后再进行操作!'"></tableNoData>
+    </div>
+</template>
+
+<script>
+import ReportDetail from '@/views/smartReport/reportDetail.vue';
+import Reportdtl from '@/views/report_manage/reportdtl.vue'
+import TimeLine from './components/timeLine.vue';
+import RejectDialog from './components/rejectDialog.vue';
+import {approveInterence} from '@/api/modules/approve.js';
+import reportApproveConfig from "@/mixins/reportApproveConfig.js"
+
+const ApproveType = ['','依次审批','会签','或签']
+const ApproveState = ['','待审批','已同意','已驳回']
+export default {
+    mixins:[reportApproveConfig],
+    components: { RejectDialog },
+    data() {
+        return {
+            isError:false,
+            isLoading:false,
+            isDetailDialogShow:false,
+            TimeLineData:[],
+            formType:'detail',//进入审批详情的方式:approve(待处理)/detail(已处理)/myself(我发起的)
+            reportInfo:{ //报告相关信息
+                reportId:0,//研报or智能研报的报告id
+                title:'',
+                classify:'',
+                approver:'',
+                componentName:'',
+                type:0,//1中文研报 2英文研报 3智能研报
+            },
+            approveInfo:{//审批相关的信息
+                state:1,//当前审批的状态:1-待审批;2-已同意;3-已驳回;4-已撤回
+                stateText:'pending',//审批状态对应图片文字:待审批(pending),已同意(passed),已驳回(reject),已撤回(return)
+                isCurrentApprover:false,//审批进行中的节点审批人是否是当前用户,控制通过&驳回按钮显示
+            },
+        };
+    },
+    computed:{
+        UserId(){
+            return Number(localStorage.getItem("AdminId"));
+        }
+    },
+    methods: {
+        getApproveDetail(){
+            const {type,approveId} = this.$route.query
+            if(!approveId) return 
+            approveInterence.getApproveDetail({
+                ReportApproveId:Number(approveId)
+            }).then(res=>{
+                if(res.Ret!==200) return
+                //格式化时间线数据 
+                this.formatTimeLineData(res.Data)
+                const {Report={},Approve={}} = res.Data||{}
+                this.reportInfo = {
+                    reportId:Report.ReportId||0,
+                    title:Report.ReportTitle||'',
+                    classify:Report.ReportClassify||'',
+                    approver:Approve.ApplyUserName||'',
+                    componentName:Report.ReportType===3?'ReportDetail':'Reportdtl',
+                    type:Report.ReportType
+                }
+                this.formType = type||'detail'
+                this.approveInfo.state=Approve.State
+                this.approveInfo.stateText=['','pending','passed','reject','return'][Approve.State]
+            })
+        },
+        //转换接口数据
+        formatTimeLineData({Approve={},ApproveFlowNodes=[]}){
+            //发起人节点
+            const startNode = {
+                nodeType:1,
+                nodeText:'发起人:',
+                nodeStatus:'passed',
+                approveList:[{
+                    approverName:Approve.ApplyUserName||'',
+                    approveTime:Approve.CreateTime||''
+                }]
+            }
+            //排序过的审批节点,遍历
+            let currentIndex = 0
+            let Nodes = ApproveFlowNodes.map((i,index)=>{
+                //找到当前节点的index
+                if(i.ReportApproveNodeId===Approve.CurrNodeId){
+                    currentIndex = index
+                }
+                //审批节点只有一个人时不显示是什么审批流
+                const strApproveType = `(${ApproveType[i.ApproveType]})`
+                const node = {
+                    nodeType:2,
+                    nodeText:'审批人:'+i.Users.length+'人'+(i.Users.length>1?strApproveType:''),
+                    nodeStatus:i.ReportApproveNodeId===Approve.CurrNodeId?'process':'future',
+                    approveType:ApproveType[i.ApproveType]
+                }
+                const approveList = i.Users.map(u=>{
+                    const {State='',ApproveTime='',ApproveRemark=''}=u.ApproveRecord||{}
+                    return {
+                        approverName:u.UserName,
+                        approveStatus:ApproveState[State]||'',
+                        approveTime:ApproveTime,
+                        approveReason:ApproveRemark
+                    }
+                })
+                //检测当前节点的User与当前用户是否匹配 且审批需要是待审批状态
+                if(i.ReportApproveNodeId===Approve.CurrNodeId&&Approve.State===1){
+                    //当前节点的User中,有没有当前用户
+                    const hasUser = i.Users.findIndex(u=>u.UserId===this.UserId)
+                    if(hasUser!==-1){
+                        //只有依次审批需要看顺序
+                        if(i.ApproveType===1){
+                            this.approveInfo.isCurrentApprover = i.Users[hasUser].ApproveRecord?true:false
+                        }else{
+                            this.approveInfo.isCurrentApprover = true
+                        }
+                    }else{
+                        this.approveInfo.isCurrentApprover = false
+                    }
+                }
+                node.approveList = approveList
+                return node
+            })
+            //将当前节点之前的置为通过节点,当前节点之后的置为未进行节点
+            Nodes.forEach((n,index)=>{
+                if(index<currentIndex){
+                    n.nodeStatus = 'passed'
+                }
+                if(index>currentIndex){
+                    n.nodeStatus = 'future'
+                }
+            })
+
+            if(!Nodes.length){
+                this.TimeLineData = [startNode,...Nodes]
+                return
+            }
+
+            //如果当前审批是已驳回,移除当前节点后面的节点
+            if(Approve.State===3){
+                Nodes = Nodes.filter((_,index)=>index<=currentIndex)
+                Nodes[currentIndex].nodeStatus = 'reject'
+            }
+
+            //如果当前审批已撤销,移除当前节点后面的节点,在最后加上撤销节点
+            if(Approve.State===4){
+                Nodes = Nodes.filter((_,index)=>index<=currentIndex)
+                //检查最后一个节点是否有人审批
+                let hasApprove = false
+                let stateNum = 0
+                Nodes[currentIndex].approveList.forEach(u=>{
+                    if(u.approveStatus&&u.approveStatus!=='待审批'){
+                        hasApprove = true
+                    }
+                    //依次审批和会签,计算已同意的数量
+                    if(u.approveStatus==='已同意'){
+                        stateNum++
+                    }
+                    if(u.approveStatus==='已驳回'){
+                        Nodes[currentIndex].nodeStatus = 'reject'
+                    }
+                })
+                //若审批撤销,则检查当前节点是否是通过节点
+                if(Nodes[currentIndex].approveType!=='或签'&&stateNum===Nodes[currentIndex].approveList.length){
+                    Nodes[currentIndex].nodeStatus = 'passed'
+                }
+                if(Nodes[currentIndex].approveType==='或签'&&stateNum>0){
+                    Nodes[currentIndex].nodeStatus = 'passed'
+                }
+                //若没有人审批,则把这个节点删除
+                !hasApprove&&(Nodes.pop())
+                //在最后加上撤销节点
+                Nodes.push({
+                    nodeType:3,
+                    nodeText:'发起人:',
+                    nodeStatus:'return',
+                    approveList:[{
+                        approverName:(Approve.ApplyUserName||'')+'(已撤销)',
+                        approveTime:Approve.ModifyTime||''
+                    }],
+                })
+            }
+
+            //如果当前审批已同意,则最后一个节点状态改为已同意
+            if(Approve.State===2){
+                Nodes[currentIndex].nodeStatus = 'passed'
+            }
+
+            //再次遍历Nodes
+            //1.去除已同意的或签节点,没有审批的审批人状态
+            //2.去除已驳回的节点,没有参与审批的审批人的状态
+            Nodes.forEach(n=>{
+                if(n.nodeStatus==='passed'||n.nodeStatus==='reject'){
+                    n.approveList.forEach(a=>{
+                        if(a.approveStatus==='待审批'){
+                            a.approveStatus = ''
+                        }
+                    })
+                }
+            })
+
+            this.TimeLineData = [startNode,...Nodes]
+        },
+        async changeApprove(type){
+            const {approveId} = this.$route.query
+            if(!approveId) return
+            if(type==='reject'){
+                this.isDetailDialogShow = true
+                return 
+            }
+            let res = null
+            if(type==='return'){
+                res = await approveInterence.cancelApprove({
+                    ReportApproveId:Number(approveId)
+                })
+            }
+            if(type==='pass'){
+                res = await approveInterence.passApprove({
+                    ReportApproveId:Number(approveId)
+                })
+            }
+            if(res.Ret!==200) return 
+            this.$message.success(`${type==='return'?'撤销':'通过'}成功`)
+            type!=='reject'&&(this.$router.replace("/approveList"))
+        },
+        rejectApprove(reason){
+            this.isDetailDialogShow = false
+            approveInterence.rejectApprove({
+                ReportApproveId:Number(this.$route.query.approveId),
+                ApproveRemark:reason||''
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                this.$message.success("驳回成功")
+                this.$router.replace("/approveList")
+            })
+        }
+    },
+    mounted(){
+        this.getApproveDetail()
+    },
+    components: { TimeLine, ReportDetail, Reportdtl, RejectDialog }
+};
+</script>
+
+<style lang="scss">
+.approve-detail-wrap{
+    .approve-content{
+        .smart-report-detail{
+            .main-box{
+                width: auto;
+                box-sizing: border-box;
+                margin:0;
+                padding:10px;
+                border:none !important;
+                border-radius: 4px;
+            }
+        }
+        #reportdtl{
+            margin:0 auto;
+            padding:10px;
+            border:none !important;
+            border-radius: 4px;
+        }
+    }
+}
+</style>
+<style scoped lang="scss">
+@import url('./css/pageStyle.scss');
+.approve-detail-wrap{
+    height: calc(100vh - 120px);
+    display: flex;
+    .approve-detail,.approve-tool{
+        height: 100%;
+        box-sizing: border-box;
+    }
+    .approve-tool{
+        width:400px;
+        min-width: 360px;
+        background-color: #fff;
+        display: flex;
+        flex-direction: column;
+        overflow: hidden;
+        .tool-btn{
+            padding:20px;
+            text-align: right;
+        }
+        .approve-timeline-wrap{
+            position: relative;
+            margin-left:20px;
+            flex:1;
+            overflow-y: auto;
+            .timeline{
+                padding:20px;
+                padding-left: 0;
+            }
+            .approve-status{
+                position:absolute;
+                width:200px;
+                height:200px;
+                right:0;
+                bottom:0;
+                overflow: hidden;
+                pointer-events: none;
+                img{
+                    width:100%;
+                    height:100%;
+                }
+            }
+        }
+    }
+    .approve-detail{
+        flex: 1;
+        margin-right:20px;
+        background-color: #fff;
+        display: flex;
+        flex-direction: column;
+        .approve-info{
+            display: flex;
+            gap:60px;
+            padding:15px 20px;
+            border-bottom: 1px solid #C8CDD9;
+        }
+        .approve-content{
+            flex: 1;
+            min-width: 840px;
+            padding:20px;
+            overflow-y: auto;
+            position:relative;
+        }
+    }
+}
+</style>

+ 194 - 0
src/views/approve_manage/approveEdit.vue

@@ -0,0 +1,194 @@
+<template>
+    <!-- 添加编辑审批流 -->
+    <div class="approve-edit-wrap approve-page-wrap" v-if="isETAApprove">
+        <div class="head-box">
+            <el-form :inline="true" :model="approveForm" ref="approve-form" :rules="formRules"
+                label-width="100px" label-position="left">
+                <el-form-item label="审批流名称" prop="name">
+                    <el-input v-model="approveForm.name" :disabled="this.$route.query.flowId" placeholder="请输入审批流名称"></el-input>
+                </el-form-item>
+                <el-form-item label="关联报告" prop="classify">
+                    <el-cascader v-model="approveForm.classify"
+                        placeholder="请选择关联报告" clearable
+                        :disabled="this.$route.query.flowId"
+                        :options="classifyTree"
+                        :props="{value:'ClassifyId',label:'ClassifyName',children:'Children'}"
+                        style="margin-right: auto;margin-left: 15px;"></el-cascader>
+                </el-form-item>
+            </el-form>
+            <div class="form-btn">
+                <el-button type="primary" plain @click="$router.back()">取消</el-button>
+                <el-button v-permission="permissionBtn.approveFlowPermission.reportApprove_save"
+                    type="primary" @click="checkFlow">保存</el-button>
+            </div>
+        </div>
+        <div class="form-item" style="color:#606266;width:100px;">
+            <span style="color:#F56C6C;margin-right: 4px;">*</span>流程配置
+        </div>
+        <!-- 审批流画布 -->
+        <div class="flow-editor-wrap">
+            <FlowEdiotr
+                ref='floweditor'
+                :flowNodes="approveForm.flowNodes"
+            />
+        </div>
+    </div>
+    <div class="approve-page-wrap" v-else>
+        <tableNoData :text="pageLoading?'':'系统暂未开通审批流程,请开启审批流程后再进行操作!'"></tableNoData>
+    </div>
+</template>
+
+<script>
+import FlowEdiotr from './components/flowEdiotr';
+import {approveInterence} from '@/api/modules/approve.js';
+import approveMixins from './mixins/approveMixins';
+import reportApproveConfig from "@/mixins/reportApproveConfig.js"
+const findParentNode = (arr, id)=>{
+      // 遍历取父级code push数组
+      for (let i of arr) {
+        if (i.ClassifyId === id) {
+          return [i.ClassifyId];
+        }
+        if (i.Children) {
+          let node = findParentNode(i.Children, id);
+          if (node) {
+            return node.concat(i.ClassifyId);
+          }
+        }
+      }
+    }
+export default {
+    mixins:[approveMixins,reportApproveConfig],
+    data() {
+        return {
+            approveForm:{
+                name:'',
+                classify:'',
+                /* flowNodes:null */
+            },
+            formRules:{
+                name:[{ required: true, message: '请输入审批流名称名称', trigger: 'blur' },
+                      { max: 20, message: '长度在20个字符内', trigger: 'change' }],
+                classify:[{ required: true, message: '请选择关联报告', trigger: 'blur' },]
+            },
+
+        };
+    },
+    methods: {
+        async checkFlow(){
+            //检查name,region是否为空
+            await this.$refs["approve-form"].validate()
+            //检查审批流内容:每个审批节点是否都选择了审批人
+            const data = this.$refs.floweditor.flowData
+            if(data.length<3){
+                this.$message.warning("请添加审批节点")
+                return
+            }
+            for(let item of data){
+                if(item.nodeType===2&&!item.approvers.length){
+                    this.$message.warning("有节点未选择审批人,请检查")
+                    return
+                }
+            }
+            let Nodes = []
+            //不需要data的第一项和最后一项,其余转换为接口所需格式
+            for(let i=1;i<data.length-1;i++){
+                const Users = data[i].approvers.map((item,index)=>{
+                    return {
+                        UserType:'user',//目前只有审批节点,都是user
+                        UserId:item.ItemId,
+                        UserName:item.ItemName,
+                        Sort:data[i].ApproveType===1?index+1:0
+                    }
+                })
+                Nodes.push({
+                    ApproveType:data[i].ApproveType,
+                    Users
+                })
+            }
+            this.modifyFlow(Nodes)
+        },
+        async modifyFlow(Nodes){
+            const {name,classify} = this.approveForm
+            const params = {
+                FlowName:name,
+                ReportType:classify[0],
+                ClassifyFirstId:classify[classify.length-2]||0,
+                ClassifySecondId:classify[classify.length-1]||0,
+                Nodes
+            }
+            let res
+            const id = this.$route.query.flowId||0
+            if(id){
+                res = await approveInterence.editApproveFlow({
+                    ...params,
+                    ReportApproveFlowId:Number(id)
+                })
+            }else{
+                res = await approveInterence.addNewApproveFlow(params)
+            }
+            if(res.Ret!==200) return
+            this.$message.success(`${id?'编辑':'新增'}成功`)
+            this.$router.push('/approveSetting')
+        },
+        getFlowDetail(){
+            const id = this.$route.query.flowId||0
+            if(id){
+                approveInterence.getApproveFlowDetail({
+                    ReportApproveFlowId:Number(id)
+                }).then(res=>{
+                    if(res.Ret!==200) return 
+                    const {FlowName,ReportType,ClassifySecondId,Nodes} = res.Data||{}
+                    this.approveForm.name = FlowName||''
+                    //递归获取所有父级id
+                    const classify = this.classifyTree.find(i=>i.ClassifyId===ReportType)||{}
+                    const tempArr = findParentNode(classify.Children||[],ClassifySecondId)
+                    tempArr.push(ReportType)
+                    this.approveForm.classify = tempArr.reverse()
+                    this.approveForm.flowNodes = Nodes||[]
+                })
+            }
+        }
+    },
+    async mounted(){
+        this.getClassifyTree()
+    },
+    components: { FlowEdiotr }
+};
+</script>
+<style lang="scss">
+.approve-edit-wrap{
+    .el-form-item__content{
+        flex: 1;
+    }
+}
+</style>
+<style scoped lang="scss">
+@import url('./css/pageStyle.scss');
+.approve-edit-wrap{
+    display: flex;
+    flex-direction: column;
+    height: calc(100vh - 120px);
+    .head-box{
+        display: flex;
+        justify-content: space-between;
+        .el-form{
+            flex:1;
+            .el-input,.el-cascader{
+                min-width: 200px;
+                max-width: 420px;
+                width:100%;
+            }
+            .el-form-item{
+                width:45%;
+                display: inline-flex;
+            }
+
+        }
+    }
+    .flow-editor-wrap{
+        padding-left: 100px;
+        overflow: auto;
+    }
+}
+</style>

+ 311 - 0
src/views/approve_manage/approveList.vue

@@ -0,0 +1,311 @@
+<template>
+    <!-- 审批管理列表页 -->
+    <div class="approve-list-wrap approve-page-wrap" v-if="isETAApprove">
+        <div class="head-tab">
+            <el-tabs v-model="activeTab" @tab-click="handleClick">
+                <el-tab-pane label="待处理" name="pending"></el-tab-pane>
+                <el-tab-pane label="已处理" name="processed"></el-tab-pane>
+                <el-tab-pane label="我发起的" name="originate"></el-tab-pane>
+            </el-tabs>
+        </div>
+        <div class="approve-list">
+            <div class="select-box">
+                <el-cascader v-model="classify"
+                    placeholder="请选择关联报告" clearable
+                    :options="classifyTree"
+                    :props="{value:'ClassifyId',label:'ClassifyName',children:'Children'}"
+                    @change="handleCurrentChange(1)">
+                </el-cascader>
+                <div class="select-time-box">
+                    <el-select v-show="activeTab!=='pending'" v-model="timeType" 
+                        @change="handleCurrentChange(1)"
+                        placeholder="时间类型" style="max-width:120px;" class="custom-select">
+                        <el-option label="提交时间" :value="1" />
+                        <el-option label="处理时间" :value="2" v-if="activeTab==='processed'"/>
+                        <el-option label="审批时间" :value="3" v-if="activeTab==='originate'"/>
+                    </el-select>
+                    <div class="line" v-show="activeTab!=='pending'"></div>
+                    <el-date-picker v-model="timeDate"
+                        @change="handleCurrentChange(1)"
+                        type="daterange"
+                        value-format="yyyy-MM-dd"
+                        range-separator="至"
+                        start-placeholder="开始日期"
+                        end-placeholder="结束日期">
+                    </el-date-picker>
+                </div>
+                
+                <el-select placeholder="请选择处理状态" v-model="ApproveState" clearable v-show="activeTab!=='pending'"
+                    @change="handleCurrentChange(1)">
+                    <template v-if="activeTab==='processed'">
+                        <el-option label="已同意" :value="2" />
+                        <el-option label="已驳回" :value="3" />
+                    </template>
+                    <template v-if="activeTab==='originate'">
+                        <el-option label="待审批" :value="1" />
+                        <el-option label="已通过" :value="2" />
+                        <el-option label="已驳回" :value="3" />
+                        <el-option label="已撤销" :value="4" />
+                    </template>
+                    
+                </el-select>
+
+                <el-input v-model="keyword" prefix-icon="el-icon-search" clearable @input="handleCurrentChange(1)"
+                    placeholder="请输入报告标题" style="width:260px;margin-left: auto;"></el-input>
+            </div>
+            <div class="list-box">
+                <el-table 
+                    ref="reftable"
+                    v-loading="tableLoading"
+                    :data="tableData" 
+                    @sort-change="sortChange" border>
+                    <el-table-column
+                        v-for="item in tableColumns"
+                        :key="item.key"
+                        :label="item.label"
+                        :prop="item.key"
+                        :sortable="item.sortable"
+                        align="center"
+                    >
+                        <template slot-scope="{row}">
+                            <span v-if="item.key==='State'">
+                                {{['','待审批','已通过','已驳回','已撤销'][row.State]}}
+                            </span>
+                            <span v-else-if="item.key==='RecordState'">
+                                {{['','待审批','已同意','已驳回'][row.RecordState]}}
+                            </span>
+                            <span v-else>{{row[item.key]}}</span>
+                        </template>
+                    </el-table-column>
+                    <el-table-column label="操作" align="center">
+                        <template slot-scope="{row}">
+                            <template v-if="activeTab==='pending'">
+                                <el-button type="text" style="padding:0;" @click="toApproveDetail(row,'approve')"
+                                    v-if="permissionBtn.isShowBtn('approvePermission','reportApprove_approve')">审批</el-button>
+                            </template>
+                            <template v-if="activeTab==='processed'">
+                                <el-button type="text" style="padding:0;" @click="toApproveDetail(row,'detail')">详情</el-button>
+                                <el-button type="text" style="padding:0" @click="handleShowDetail(row)" 
+                                    v-if="row.State===3&&permissionBtn.isShowBtn('approvePermission','reportApprove_rejectreason')">驳回理由</el-button>
+                            </template>
+                            <template v-if="activeTab==='originate'">
+                                <el-button type="text" style="padding:0;" @click="toApproveDetail(row,'myself')">详情</el-button>
+                                <el-button type="text" style="padding:0;" @click="cancelApprove(row)" 
+                                    v-if="row.State!==4&&permissionBtn.isShowBtn('approvePermission','reportApprove_repeal')">撤销</el-button>
+                                <el-button type="text" style="padding:0" @click="handleShowDetail(row)" 
+                                    v-if="row.State===3&&permissionBtn.isShowBtn('approvePermission','reportApprove_rejectreason')">驳回理由</el-button>
+                            </template>
+                        </template>
+                        
+                    </el-table-column>
+                </el-table>
+            <div style="text-align:right;margin-top:20px">
+                <el-pagination 
+                        layout="total,prev,pager,next,jumper" 
+                        background 
+                        :current-page="page"
+                        @current-change="handleCurrentChange"
+                        :page-size="pageSize"
+                        :total="total"
+                        style="display: inline-block"
+                    />
+            </div>
+            </div>
+        </div>
+        <RejectDialog 
+            :isDetailDialogShow="isDetailDialogShow"
+            :isEdit="false"
+            :data="currentData"
+            @close="isDetailDialogShow=false;currentData={};"
+        />
+    </div>
+    <div class="approve-page-wrap" v-else>
+        <tableNoData :text="pageLoading?'':'系统暂未开通审批流程,请开启审批流程后再进行操作!'"></tableNoData>
+    </div>
+</template>
+
+<script>
+import RejectDialog from './components/rejectDialog.vue';
+import approveMixins from './mixins/approveMixins';
+import {approveInterence} from '@/api/modules/approve.js';
+import reportApproveConfig from "@/mixins/reportApproveConfig.js"
+import {
+        approve_pending_columns,
+        approve_processed_columns,
+        approve_originate_columns,
+    } from './config/tableConfig'
+const columnsMap = {
+    'pending':approve_pending_columns,
+    'processed':approve_processed_columns,
+    'originate':approve_originate_columns
+}
+const tabMap = {
+    'pending':1,
+    'processed':2,
+    'originate':3
+}
+export default {
+    mixins:[approveMixins,reportApproveConfig],
+    data() {
+        return {
+            activeTab: 'pending',
+            /* 筛选项 */
+            timeType:1,
+            timeDate:'',
+            ApproveState:'',
+            keyword:'',
+            classify:'',
+            /* 排序项 */
+            SortRule:0,
+            SortField:0,
+
+            tableLoading:false,
+            tableData: [],
+            tableColumns: approve_pending_columns,
+            page: 1,
+            pageSize: 10,
+            total: 0,
+
+            currentData: {},
+            isDetailDialogShow: false
+        };
+    },
+    methods: {
+        getTableData(){
+            this.tableLoading = true
+            this.tableData=[]
+            const baseParams = {
+                ListType:tabMap[this.activeTab]||0,
+                PageSize:this.pageSize,
+                CurrentIndex:this.page,
+                Keyword:this.keyword,
+            }
+            const selectParams = {
+                //关联报告
+                ReportType:this.classify[0]||0,
+                ClassifyFirstId:this.classify[this.classify.length-2]||0,
+                ClassifySecondId:this.classify[this.classify.length-1]||0,
+                //时间
+                TimeType:this.timeType,
+                StartTime:this.timeDate?this.timeDate[0]||'':'',
+                EndTime:this.timeDate?this.timeDate[1]||'':'',
+                //排序
+                SortRule:this.SortRule,
+                SortField:this.SortField,
+                //处理状态
+                ApproveState:this.ApproveState,
+            }
+            approveInterence.getApproveList({
+                ...baseParams,
+                ...selectParams
+            }).then(res=>{
+                this.tableLoading=false
+                if(res.Ret!==200) return 
+                const {List=[],Paging={}} = res.Data||{}
+                this.tableData = List||[]
+                this.total = Paging.Totals||0
+            })
+        },
+        handleCurrentChange(page) {
+            this.page = page;
+            this.getTableData()
+        },
+        sortChange({ prop, order }) {
+            this.SortRule = order==='ascending'?1:2
+            this.SortField= prop==='CreateTime'?1
+                            :prop==='HandleTime'?2:3
+            this.handleCurrentChange(1)
+        },
+        handleClick() {
+            this.timeType = 1
+            this.timeDate=''
+            this.SortField=0
+            this.SortField=0
+            this.tableColumns = columnsMap[this.activeTab];
+            this.$refs.reftable&&this.$refs.reftable.clearSort()
+            this.handleCurrentChange(1)
+        },
+        handleShowDetail(data) {
+            this.currentData = data;
+            this.isDetailDialogShow = true;
+        },
+        toApproveDetail(data,type){
+            this.$router.push({
+                path:'/approveDetail',
+                query:{
+                    type,
+                    approveId:data.ReportApproveId
+                }
+            })
+        },
+        cancelApprove(item){
+            approveInterence.cancelApprove({
+                ReportApproveId:Number(item.ReportApproveId)
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                this.$message.success("撤销成功")
+                this.handleCurrentChange(1)
+            })
+        },
+    },
+    mounted(){
+        this.getClassifyTree()
+        const {formType='approve'} = this.$route.query
+        const formTypeMap = {
+            'approve':'pending',
+            'detail':'processed',
+            'myself':'originate'
+        }
+        this.activeTab = formTypeMap[formType]||'pending'
+        this.getTableData()
+    },
+    components: { RejectDialog }
+};
+</script>
+
+<style lang="scss">
+.approve-list-wrap{
+    .custom-select{
+        .el-input__inner{
+            border-color: #0052D9;
+            background-color: #ECF2FE;
+            color:#0052D9;
+        }
+        .el-input__suffix{
+            color:#0052D9;
+            .el-select__caret{
+                color:#0052D9;
+            }
+        }
+        
+    }
+}
+</style>
+<style scoped lang="scss">
+@import url('./css/pageStyle.scss');
+.approve-list-wrap{
+    .head-tab{
+        margin-bottom: 5px;
+    }
+    .approve-list{
+        .select-box{
+            display: flex;
+            justify-content: space-between;
+            gap:10px;
+            .select-time-box{
+                display: flex;
+                align-items: center;
+                max-width: 380px;
+                .line{
+                    width:10px;
+                    height:1px;
+                    background-color: #C8CDD9;
+                }
+            }
+        }
+    }
+    .list-box{
+        margin-top:20px;
+    }
+}
+</style>

+ 162 - 0
src/views/approve_manage/approveSetting.vue

@@ -0,0 +1,162 @@
+<template>
+    <!-- 审批流配置列表 -->
+    <div class="approve-setting-wrap approve-page-wrap" v-if="isETAApprove">
+        <div class="head-box">
+            <el-button v-permission="permissionBtn.approveFlowPermission.reportApprove_add"
+                type="primary" @click="$router.push('/approveEdit')">添加审批流</el-button>
+            <el-cascader v-model="classify"
+                placeholder="请选择关联报告" clearable
+                :options="classifyTree"
+                :props="{value:'ClassifyId',label:'ClassifyName',children:'Children'}"
+                @change="handleSearchChange"
+                style="margin-right: auto;margin-left: 15px;"></el-cascader>
+            <el-input v-model="Keyword" @input="handleCurrentChange(1)"
+                placeholder="请输入审批流名称" prefix-icon="el-icon-search" clearable style="width:260px;"></el-input>
+        </div>
+        <div class="list-box">
+            <el-table :data="tableData" @sort-change="sortChange" border>
+                <el-table-column
+                    v-for="item in tableColumns"
+                    :key="item.key"
+                    :label="item.label"
+                    :prop="item.key"
+                    :sortable="item.sortable"
+                    align="center"
+                ></el-table-column>
+                <el-table-column label="操作" align="center">
+                    <template slot-scope="{row}">
+                        <el-button v-permission="permissionBtn.approveFlowPermission.reportApprove_edit"
+                            type="text" style="padding:0;" @click="handleEditFlow(row)">编辑</el-button>
+                        <el-button v-permission="permissionBtn.approveFlowPermission.reportApprove_remove"
+                            type="text" style="padding:0;color:red;" @click="handleDeleteFlow(row)">删除</el-button>
+                    </template>
+                    
+                </el-table-column>
+            </el-table>
+            <div style="text-align:right;margin-top:20px">
+                <el-pagination 
+                        layout="total,prev,pager,next,jumper" 
+                        background 
+                        :current-page="page"
+                        @current-change="handleCurrentChange"
+                        :page-size="pageSize"
+                        :total="total"
+                        style="display: inline-block"
+                    />
+            </div>
+        </div>
+    </div>
+    <div class="approve-page-wrap" v-else>
+        <tableNoData :text="pageLoading?'':'系统暂未开通审批流程,请开启审批流程后再进行操作!'"></tableNoData>
+    </div>
+</template>
+
+<script>
+import {approveInterence} from '@/api/modules/approve.js'
+import approveMixins from './mixins/approveMixins';
+import reportApproveConfig from "@/mixins/reportApproveConfig.js"
+export default {
+    mixins:[approveMixins,reportApproveConfig],
+    data() {
+        return {
+            /* 列表筛选项 */
+            ClassifyFirstId:0,//研报倒数第二级分类id
+            ClassifySecondId:0,//研报最后一级分类id
+            ReportType:0,//研报类型 1-中文研报;2-英文研报;3-智能研报
+            SortRule:0,//排序规则:1-正序; 2-倒序(默认)
+            Keyword:'',
+            classify:'',
+
+            tableData:[],
+            tableColumns:[{
+                label:'审批流名称',
+                key:'FlowName'
+            },{
+                label:'关联报告',
+                key:'ReportClassify'
+            },{
+                label:'创建时间',
+                key:'CreateTime',
+                sortable:'custom'
+            }],
+            page:1,
+            pageSize:10,
+            total:0,
+        };
+    },
+    methods: {
+        handleCurrentChange(page){
+            this.page = page
+            this.getTableData()
+        },
+        handleSearchChange(){
+            this.ReportType = this.classify[0]||0
+            this.ClassifySecondId = this.classify[this.classify.length-1]||0
+            if(this.classify.length>=3){
+                this.ClassifyFirstId = this.classify[this.classify.length-2]||0
+            }else{
+                this.ClassifyFirstId = 0
+            }
+            this.handleCurrentChange(1)
+        },
+        sortChange({prop,order}){
+            this.SortRule = order==='ascending'?1:2
+            this.handleCurrentChange(1)
+        },
+        getTableData(){
+            approveInterence.getApproveFlowList({
+                PageSize:this.pageSize,
+                CurrentIndex:this.page,
+                ReportType:this.ReportType,
+                ClassifyFirstId:this.ClassifyFirstId,
+                ClassifySecondId:this.ClassifySecondId,
+                Keyword:this.Keyword,
+                SortRule:this.SortRule
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                const {List=[],Paging={}} = res.Data||{}
+                this.tableData = List||[]
+                this.total = Paging.Totals||0
+            })
+        },
+        handleEditFlow(item){
+            this.$router.push({
+                path:'/approveEdit',
+                query:{
+                    flowId:item.ReportApproveFlowId
+                }
+            })
+        },
+        handleDeleteFlow(item){
+            this.$confirm("删除后不可恢复,确认删除吗?","提示",{
+                type:"warning"
+            }).then(()=>{
+                approveInterence.deleteApproveFlow({
+                    ReportApproveFlowId:item.ReportApproveFlowId
+                }).then(res=>{
+                    if(res.Ret!==200) return 
+                    this.$message.success("删除成功")
+                    this.handleCurrentChange(1)
+                })
+            }).catch(()=>{})
+        }
+    },
+    mounted(){
+        this.getClassifyTree()
+        this.getTableData()
+    },
+};
+</script>
+
+<style scoped lang="scss">
+@import url('./css/pageStyle.scss');
+.approve-setting-wrap{
+    .head-box{
+        display: flex;
+        justify-content: space-between;
+    }
+    .list-box{
+        margin-top:30px;
+    }
+}
+</style>

+ 112 - 0
src/views/approve_manage/components/flowEdiotr.vue

@@ -0,0 +1,112 @@
+<template>
+    <!-- 审批流内容 -->
+    <div class="flow-editor">
+        <span class="circle-point"></span>
+        <span class="circle-point end"></span>
+        <component v-for="(node,index) in flowData" :key="index"
+            :is="node.nodeName"
+            :flowNode="{...node,...{index}}"
+            @addNode="addFlowNode"
+            @editNode="editFlowNode"
+            @removeNode="removeNode">
+        </component>
+    </div>
+</template>
+
+<script>
+import StartNode from './flowNode/startNode.vue';
+import AddNode from './flowNode/addNode.vue';
+import ApproveNode from './flowNode/approveNode.vue';
+import EndNode from './flowNode/endNode.vue';
+export default {
+    props:{
+        flowNodes:{ //审批流原数据,只包含审批节点
+            type:Array,
+            default:[]
+        }
+    },
+    data() {
+        return {
+            flowData:[{
+                nodeType: 1,
+                nodeName: 'StartNode',
+            },{
+                nodeType:3,
+                nodeName:'EndNode'
+            }]
+        };
+    },
+    watch:{
+        flowNodes(val){
+            this.initFlowData()
+        }
+    },
+    methods: {
+        initFlowData(){
+            const approveData = this.flowNodes.map(n=>{
+                const approvers = n.Users.map(i=>{
+                    return {
+                        ItemId:i.UserId,
+                        ItemName:i.UserName
+                    }
+                })
+                return {
+                    ...n,
+                    nodeType:2,
+                    nodeName:'ApproveNode',
+                    approvers
+                }
+            })
+            this.flowData.splice(1,0,...approveData)
+        },
+        addFlowNode(node){
+            const {prevNode} = node
+            delete node.prevNode
+            const {index} = prevNode
+            this.flowData.splice(index+1,0,node)
+        },
+        removeNode(node){
+            const {index} = node
+            this.flowData.splice(index,1)
+        },
+        editFlowNode(node){
+            const {index} = node
+            this.flowData.splice(index,1,node)
+        }
+    },
+    mounted(){
+        //this.initFlowData()
+    },
+    components: { StartNode,AddNode,ApproveNode,EndNode }
+};
+</script>
+
+<style scoped lang="scss">
+@import url('../css/nodeStyle.scss');
+.flow-editor{
+    margin-left: 20px;
+    position:relative;
+    .circle-point{
+            position:absolute;
+            top:0;
+            left:-22px;
+            width:6px;
+            height:6px;
+            border-radius: 50%;
+            background-color: #0052D9;
+            &.end{
+                top:auto;
+                bottom:0;
+            }
+        }
+        &::before{
+            content: '';
+            top:0;
+            left:-20px;
+            bottom: 0;
+            width:2px;
+            background-color: #0052D9;
+            position: absolute;
+        }
+}
+</style>

+ 44 - 0
src/views/approve_manage/components/flowNode/addNode.vue

@@ -0,0 +1,44 @@
+<template>
+    <div class="add-node-wrap">
+        <div class="add-btn" @click="handleAddApprove">
+            <span> <i class="el-icon-circle-plus-outline"></i></span>
+            <span>添加审批人</span>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    props:["node"],
+    data() {
+        return {
+            visible:false,
+        };
+    },
+    methods: {
+        handleAddApprove(){
+            this.visible = false
+            const data = {
+                nodeType:2,
+                ApproveType:1,
+                nodeName:'ApproveNode',
+                approvers:[],
+                prevNode:this.node
+            }
+            this.$emit("addNode",data)
+        }
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.add-node-wrap{
+    margin: 20px 0;
+    .add-btn{
+        user-select: none;
+        cursor: pointer;
+        color:#0052D9;
+        display: inline-block;
+    }
+}
+</style>

+ 280 - 0
src/views/approve_manage/components/flowNode/approveNode.vue

@@ -0,0 +1,280 @@
+<template>
+    <div class="approve-node-wrap node-wrap">
+        <div class="node-content">
+            <div class="head">
+                <span class="icon"></span>
+                <span class="name">审核人</span>
+                <span class="icon-btn" @click="removeNode"><i class="el-icon-close"></i></span>
+            </div>
+            <div class="content" @click="showDrawer">
+                <ul class="approver-list" v-if="flowNode.approvers.length">
+                    <li class="list-item" v-for="(item,index) in flowNode.approvers" :key="item.ItemId">
+                        {{item.ItemName}}{{index===flowNode.approvers.length-1?'':'、'}}
+                    </li>
+                </ul>
+                <span v-else style="color:#0052D9;display: flex;align-items: center;">
+                    <img src="~@/assets/img/approve_m/select.png">
+                    请选择审批人
+                </span>
+            </div>
+        </div>
+        <AddNode :node="flowNode" v-on="$listeners"/>
+        <el-drawer
+            direction="rtl"
+            :visible.sync="drawerShow"
+            :withHeader="true"
+            :modal-append-to-body="false"
+            >
+            <div class="approve-drawer-wrap">
+                <div class="header">
+                    <p>审批人设置</p>
+                    <span class="close-icon" @click="drawerShow=false" style="cursor: pointer;"><i class="el-icon-close"></i></span>
+                </div>
+                <div class="drawer-content">
+                    <div class="block">
+                        <p>选择审批人</p>
+                        <div class="choose-box">
+                            <el-radio v-model="block1" :label="1">指定人员</el-radio>
+                            <el-button @click="chooseDialogShow=true" type="primary">
+                                <i class="el-icon-circle-plus-outline" style="margin-right: 5px;"></i>
+                                选择人员
+                            </el-button>
+                        </div>
+                        <draggable 
+                            v-model="choosedList"
+                            animation="300"
+                            tag="ul"
+                            class="approve-list">
+                            <li class="list-item" v-for="item in choosedList" :key="item.ItemId">
+                                <span class="name">{{item.ItemName}}</span>
+                                <span class="icon-btn">
+                                    <i class="el-icon-close" @click.stop="removeChoosedItem(item)"></i>
+                                </span>
+                            </li>
+                        </draggable>
+                    </div>
+                    <div class="line"></div>
+                    <div class="block" style="margin-top:30px;">
+                        <p>多人审批时</p>
+                        <el-radio-group v-model="approveType">
+                            <el-radio :label="1">
+                                依次审批
+                                <el-tooltip effect="dark" placement="top" content="多个审批人依次进行审批;只有当所有审批人同意,该节点才能通过;按选择顺序审批" >
+                                    <span class="hint-text">
+                                        <i class="el-icon-info"></i>
+                                    </span>
+                                </el-tooltip>
+                            </el-radio>
+                            <el-radio :label="2">
+                                会签(须所有审批人同意)
+                                <el-tooltip effect="dark" placement="top" content="所有审批人同意,该节点才能通过;审批无先后顺序" >
+                                    <span class="hint-text">
+                                        <i class="el-icon-info"></i>
+                                    </span>
+                                </el-tooltip>
+                            </el-radio>
+                            <el-radio :label="3">
+                                或签(一名审批人同意或拒绝即可)
+                                <el-tooltip effect="dark" placement="top" content="任意一名审批人同意,该节点即通过;审批无先后顺序" >
+                                    <span class="hint-text">
+                                        <i class="el-icon-info"></i>
+                                    </span>
+                                </el-tooltip>
+                            </el-radio>
+                        </el-radio-group>
+                    </div>
+                </div>
+                <div class="drawer-btn">
+                    <el-button type="primary" plain @click="drawerShow=false">取消</el-button>
+                    <el-button type="primary" @click="editApproveNode">确认</el-button>
+                </div>
+            </div>
+        </el-drawer>
+        <!-- 选择人员弹窗 -->
+        <el-dialog 
+            title="选择人员"
+            width="600px"
+            :visible.sync="chooseDialogShow"
+            :modal-append-to-body="false"
+            :append-to-body="false"
+            @close="chooseDialogShow=false"
+        >
+            <div class="dialog-wrap">
+                <TreeTransfer 
+                    ref="tree-trans"
+                    :defaultList="choosedList"
+                    :chooseDialogShow="chooseDialogShow"
+                />
+            </div>
+            <div class="dialog-btn">
+                <el-button type="primary" plain @click="chooseDialogShow=false">取消</el-button>
+                <el-button type="primary" @click="getChoosedList">确认</el-button>
+            </div>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+import TreeTransfer from '../treeTransfer';
+import draggable from 'vuedraggable';
+import AddNode from './addNode';
+export default {
+    props:{
+        flowNode:{
+            type:Object,
+            default:{}
+        }
+    },
+    data() {
+        return {
+            drawerShow: false,
+            block1: 1,
+            approveType: 1,
+            chooseDialogShow: false,
+            choosedList:[]
+        };
+    },
+    watch:{
+        drawerShow(val){
+            if(val){
+                this.choosedList = _.cloneDeep(this.flowNode.approvers||[])
+                this.approveType = this.flowNode.ApproveType
+            }
+        }
+    },
+    methods: {
+        removeNode() {
+            this.$emit('removeNode', this.flowNode);
+        },
+        showDrawer() {
+            this.drawerShow = true;
+        },
+        getChoosedList(){
+            if(!this.$refs["tree-trans"].choosedList.length){
+                this.$message.warning("请至少选择一人")
+                return
+            }
+            this.choosedList = _.cloneDeep(this.$refs["tree-trans"].choosedList)||[]
+            this.chooseDialogShow = false
+        },
+        removeChoosedItem(item){
+            const index = this.choosedList.findIndex(i=>i.ItemId===item.ItemId)
+            index!==-1&&this.choosedList.splice(index,1)
+        },
+        editApproveNode(){
+            const node = _.cloneDeep(this.flowNode)
+            node.approvers = _.cloneDeep(this.choosedList)
+            node.ApproveType = this.approveType
+            this.$emit('editNode',node)
+            this.drawerShow = false
+        },
+    },
+    components: { TreeTransfer, draggable, AddNode }
+};
+</script>
+
+<style lang="scss">
+.approve-node-wrap{
+    .el-drawer__body{
+        overflow: hidden;
+    }
+    #el-drawer__title{ //drawer弹出时会自动聚焦第一个元素,设置无内容的title清除聚焦状态
+        height:0px;
+        margin:0px;
+        padding:0px;
+    }
+    .dialog-btn{
+        margin-top:60px;
+        padding-bottom: 40px;
+        text-align: center;
+    }
+}
+</style>
+<style scoped lang="scss">
+.approve-node-wrap{
+    .head{
+        background-color: #0052D9;
+        .icon{
+            background-image: url('~@/assets/img/approve_m/approve.png');
+        }
+        .icon-btn{
+            font-size: 20px;
+        }
+    }
+    .content{
+        .approver-list{
+            color:#0052D9;
+            display: flex;
+            align-items: center;
+            flex-wrap: wrap;
+        }
+    }
+    .approve-drawer-wrap{
+        height: 100%;
+        display: flex;
+        flex-direction: column;
+        overflow: hidden;
+        .header{
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            /* font-weight: bold; */
+            font-size: 18px;
+            height:35px;
+            padding:20px;
+            border-bottom: 1px solid #C8CDD9;
+        }
+        .drawer-content{
+            flex:1;
+            overflow-y: auto;
+            box-sizing: border-box;
+            padding:30px;
+            .block{
+                min-height: 340px;
+                .choose-box{
+                    margin-top: 20px;
+                    display: flex;
+                    justify-content: space-between;
+                    align-items: center;
+                }
+            }
+            .line{
+                margin:0 -30px;
+                height: 1px;
+                background-color:#C8CDD9;
+            }
+            .approve-list{
+                margin-top: 10px;
+                display: flex;
+                flex-wrap: wrap;
+                gap:10px;
+                .list-item{
+                    cursor: move;
+                    padding:8px;
+                    border-radius: 4px;
+                    border:1px solid #C8CDD9;
+                    .icon-btn{
+                        cursor: pointer;
+                    }
+                }
+            }
+            .el-radio-group{
+                margin-top: 20px;
+                .el-radio{
+                    display: block;
+                    margin-bottom: 10px;
+                    .hint-text{
+                        color:#C0C4CC;
+                    }
+
+                }
+            }
+        }
+        .drawer-btn{
+            text-align: center;
+            margin:10px;
+        }
+    }
+    
+}
+</style>

+ 26 - 0
src/views/approve_manage/components/flowNode/endNode.vue

@@ -0,0 +1,26 @@
+<template>
+    <div class="end-node-wrap node-wrap">
+        <div class="end-content">流程结束</div>
+    </div>
+</template>
+
+<script>
+export default {
+    data() {
+        return {
+
+        };
+    },
+    methods: {
+
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.end-node-wrap{
+    .end-content{
+        color:#C0C4CC;
+    }
+}
+</style>

+ 43 - 0
src/views/approve_manage/components/flowNode/startNode.vue

@@ -0,0 +1,43 @@
+<template>
+    <div class="start-node-wrap node-wrap">
+        <div class="node-content">
+            <div class="head">
+                <span class="icon"></span>
+                <p class="name">发起人</p>
+            </div>
+            <div class="content">所有人</div>
+        </div>
+        <AddNode :node="flowNode" v-on="$listeners"/>
+    </div>
+</template>
+
+<script>
+import AddNode from './addNode.vue';
+export default {
+    components: { AddNode},
+    props:{
+        flowNode:{
+            type:Object,
+            default:{}
+        }
+    },
+    data() {
+        return {};
+    },
+    methods: {},
+};
+</script>
+
+<style scoped lang="scss">
+.start-node-wrap{
+    .head{
+        background-color: #ECF2FE;
+        .name{
+            color:#0052D9;
+        }
+        .icon{
+            background-image: url('~@/assets/img/approve_m/start.png');
+        }
+    }
+}
+</style>

+ 81 - 0
src/views/approve_manage/components/rejectDialog.vue

@@ -0,0 +1,81 @@
+<template>
+    <el-dialog custom-class="approve-reject-dialog"
+        title="审批驳回"
+        :visible.sync="isDetailDialogShow"
+        :close-on-click-modal="false"
+        :modal-append-to-body="false"
+        @close="$emit('close')"
+        width="692px"
+        v-dialogDrag
+        center
+    >
+        <div class="dialog-content-wrap">
+            <el-input type="textarea" v-model="content" :disabled="!isEdit" :rows="10" :placeholder="isEdit?'请输入驳回理由':'无'"></el-input>
+        </div>
+        <div class="dialog-btn-wrap">
+            
+            <template v-if="isEdit">
+                <el-button @click="$emit('close')">取消</el-button>
+                <el-button type="primary" @click="handleConfirm">确认</el-button>
+            </template>
+            <el-button v-else @click="$emit('close')">知道了</el-button>
+        </div>
+    </el-dialog>
+</template>
+
+<script>
+export default {
+    props:{
+        isDetailDialogShow:{
+            type:Boolean,
+            default:false
+        },
+        isEdit:{
+            type:Boolean,
+            default:true
+        },
+        data:{
+            type:Object,
+            default:()=>{return{}}
+        }
+    },
+    watch:{
+        isDetailDialogShow(val){
+            if(val){
+                this.content = this.data.ApproveRemark||''
+            }
+        }
+    },
+    data() {
+        return {
+            content:''
+        };
+    },
+    methods: {
+        handleConfirm(){
+            /* if(!this.content.length){
+                this.$message.warning("请输入驳回理由")
+                return
+            } */
+            this.$emit('edit',this.content)
+        }
+    },
+};
+</script>
+
+<style lang="scss">
+.approve-reject-dialog{
+    .dialog-content-wrap{
+        .el-textarea{
+            textarea{
+                resize: none !important;
+            }
+        }
+    }
+    .dialog-btn-wrap{
+        text-align: center;
+        margin-top: 20px;
+        padding-bottom: 25px;
+    }
+}
+</style>

+ 60 - 0
src/views/approve_manage/components/timeLine.vue

@@ -0,0 +1,60 @@
+<template>
+    <div class="time-line-wrap">
+        <ul>
+            <li v-for="(node,index) in TimeLineData" :key="index">
+                <TimeLineItem :node="node" :isLast="index===TimeLineData.length-1"/>
+            </li>
+        </ul>
+    </div>
+</template>
+
+<script>
+import TimeLineItem from './timeLineItem.vue';
+export default {
+    components:{TimeLineItem},
+    props:{
+        TimeLineData:{
+            type:Array
+        }
+    },
+    data() {
+        return {
+            //时间线数据格式
+            mockTimeLine:[
+                {
+                    nodeType:1,
+                    nodeText:'发起人:',
+                    approveList:[{
+                        approverName:'张三',
+                        approveTime:'2023-10-10 10:10:10'
+                    }],
+                    nodeStatus:'passed',//passed节点已通过,return节点已撤回,reject节点已驳回,future节点未进行到
+                },{
+                    nodeType:2,
+                    nodeText:'审批人:', //需要拼接成 审批人:2人(会签)
+                    nodeStatus:'process',//节点正在进行中
+                    approveType:'会签',
+                    approveList:[//参与审批的人员
+                        {
+                            approverName:'李四',
+                            approveTime:'2023-10-10 10:15:10',
+                            approveStatus:'已同意'
+                        },{
+                            approverName:'王五',
+                            approveTime:'2023-10-10 10:22:00',
+                            approveStatus:'已驳回',
+                            approveReason:'就是驳回'
+                        }
+                    ]
+                }
+            ]
+        };
+    },
+    methods: {
+
+    },
+};
+</script>
+
+<style scoped lang="scss">
+</style>

+ 120 - 0
src/views/approve_manage/components/timeLineItem.vue

@@ -0,0 +1,120 @@
+<template>
+    <div class="item-wrap">
+        <div class="icon-wrap">
+            <div :class="['icon',node.nodeStatus]">
+                <img :src="require(`@/assets/img/approve_m/${node.nodeStatus}-icon.svg`)" alt="">
+            </div>
+            <div :class="['line',isLast?'last':'',node.nodeStatus]"></div>
+        </div>
+        <div class="info-wrap">
+            <!-- 发起人或审批人 -->
+            <div class="normal-text">
+                <p>{{node.nodeText}}</p>
+            </div>
+            <ul class="approve-list">
+                <li v-for="(item,itemIndex) in node.approveList" :key="itemIndex">
+                    <div class="approve-item-wrap">
+                        <!-- 审批人(审批状态) 审批时间-->
+                        <div class="normal-text">
+                            <p :class="{'passed':item.approveStatus==='已同意'}">{{item.approverName}} <span v-if="item.approveStatus">{{'('+item.approveStatus+')'}}</span> </p>
+                            <span class="time">{{item.approveTime||''}}</span>
+                        </div>
+                        <!-- 驳回理由 -->
+                        <div class="approve-reason" v-if="item.approveReason">
+                            驳回理由:{{item.approveReason}}
+                        </div>
+                    </div>
+                </li>
+            </ul>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    props:{
+        node:{
+            type:Object,
+            default:{}
+        },
+        isLast:{
+            type:Boolean,
+            default:false
+        }
+    },
+    data() {
+        return {
+
+        };
+    },
+    methods: {
+
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.item-wrap{
+    display: flex;
+    width:100%;
+    .icon-wrap{
+        width:25px;
+        /* border:1px solid black; */
+        position:relative;
+        .icon,.line{
+            position:absolute;
+            left:50%;
+            transform: translateX(-50%);
+        }
+        .icon{
+            width:16px;
+            height:16px;
+            border-radius: 50%;
+            background-color: #fff;
+            overflow: hidden;
+            img{
+                width:100%;
+                height:100%;
+            }
+        }
+        .line{
+            top:16px;
+            width:1px;
+            height:calc(100% - 16px);
+            background-color: gray;
+            &.passed{
+                background-color: #0052D9;
+            }
+            &.last{
+                background-color: transparent;
+            }
+        }
+    }
+    .info-wrap{
+        flex:1;
+        margin-left: 15px;
+        margin-bottom: 20px;
+        .approve-list{
+            .approve-item-wrap{
+                .normal-text{
+                    display: flex;
+                    justify-content: space-between;
+                    margin-bottom: 10px;
+                    color:gray;
+                    &.passed{
+                        color:#0052D9;
+                    }
+                }
+                .approve-reason{
+                   /*  margin-left: -40px; */
+                    padding:10px;
+                    /* padding-left: 40px; */
+                    color:#AD352F;
+                    background-color: #FFF0ED;
+                }
+            }
+        }
+        
+    }
+}
+</style>

+ 185 - 0
src/views/approve_manage/components/treeTransfer.vue

@@ -0,0 +1,185 @@
+<template>
+    <!-- 选择审批人组件 -->
+    <div class="tree-transfer">
+        <div class="before-transfer transfer">
+            <div class="search">
+                <el-input placeholder="搜索" suffix-icon="el-icon-search" style="width:100%;"
+                    v-model="searchText" @input="$refs['trans-tree'].filter(searchText)"></el-input>
+            </div>
+            <div class="content">
+                <el-tree 
+                    node-key="ItemId"
+                    ref="trans-tree"
+                    show-checkbox
+                    :data="treeData"
+                    :props="{
+                        label:'ItemName',
+                        children:'Children'
+                    }"
+                    :filter-node-method="filterNode"
+                    @check="SetCheckedNode"
+                ></el-tree>
+            </div>
+        </div>
+        <div class="after-transfer transfer">
+            <div class="head">
+                <span>已选{{choosedList.length}}项</span>
+                <span class="btn-text delete" @click="clearnItem">清空</span>
+            </div>
+            <draggable 
+                v-model="choosedList"
+                animation="300"
+                tag="ul"
+                class="content">
+                <li class="list-item" v-for="item in choosedList" :key="item.ItemId">
+                    <span class="name">{{item.ItemName}}</span>
+                    <span class="icon-btn" style="color:#C0C4CC;">
+                        <i class="el-icon-close" @click.stop="removeItem(item)"></i>
+                    </span>
+                </li>
+            </draggable>
+        </div>
+    </div>
+</template>
+
+<script>
+import { dataAuthInterface } from "@/api/api.js";
+import draggable from 'vuedraggable';
+export default {
+    components:{draggable},
+    props:{
+        defaultList:{
+            type:Array,
+            default:[]
+        },
+        chooseDialogShow:{
+            type:Boolean,
+            default:false
+        }
+    },
+    data() {
+        return {
+            totalNum:0,
+            treeData:[],
+            searchText:'',
+            choosedList:[]
+        };
+    },
+    watch:{
+        chooseDialogShow:{
+            handler(val){
+                if(val){
+                    this.searchText=''
+                    this.getTreeData()
+                }
+            },
+            immediate:true
+        }
+    },
+    methods: {
+        getTreeData(){
+            ///datamanage/manual/sysuser/search?KeyWord= ,要用新接口再换
+            dataAuthInterface.userSearch({
+                KeyWord: ''
+            }).then(res => {
+                if(res.Ret === 200) {
+                    this.treeData = res.Data||[];
+                }
+                this.$nextTick(()=>{
+                    const keys = this.defaultList.map(i=>{
+                        return i.ItemId
+                    })
+                    this.$refs["trans-tree"].setCheckedKeys(keys)
+                    this.choosedList = _.cloneDeep(this.defaultList)
+                })
+            })
+        },
+        filterNode(value,data){
+            if(!value) return true
+            return data.ItemName.indexOf(value)!==-1
+        },
+        SetCheckedNode(data,{checkedNodes}){
+            if(!this.choosedList.length){
+                 //只获取人员
+                this.choosedList = checkedNodes.filter(i=>{
+                    if(i.ItemId<10000&&!i.Children)
+                        return i
+                })
+            }else{
+                //遍历 filterArr choosedList里没有的,push进去
+                const filterArr = checkedNodes.filter(i=>{
+                    if(i.ItemId<10000&&!i.Children)
+                        return i
+                })
+                filterArr.forEach(i=>{
+                    const index = this.choosedList.findIndex(item=>i.ItemId===item.ItemId)
+                    if(index===-1){this.choosedList.push(i)}
+                })
+                //遍历choosedList,filterArr里没有的,删除
+                const tempArr = _.cloneDeep(this.choosedList)
+                tempArr.forEach(i=>{
+                    const checkIndex = filterArr.findIndex(item=>item.ItemId===i.ItemId)
+                    if(checkIndex===-1){
+                        const index = this.choosedList.findIndex(item=>item.ItemId===i.ItemId)
+                        index!==-1&&this.choosedList.splice(index,1)
+                    }
+                })
+            }
+        },
+        removeItem(item){
+            const {ItemId} = item
+            this.$refs["trans-tree"].setChecked(ItemId,false,false)
+            const index = this.choosedList.findIndex(i=>i.ItemId===ItemId)
+            index!==-1&&this.choosedList.splice(index,1)
+        },
+        clearnItem(){
+            this.$refs["trans-tree"].setCheckedKeys([])
+            this.choosedList = []
+        },
+    },
+    mounted(){
+        //this.getTreeData()
+    }
+};
+</script>
+
+<style scoped lang="scss">
+.tree-transfer{
+    display: flex;
+    align-items: center;
+    gap:12px;
+    .transfer{
+        display: flex;
+        flex-direction: column;
+        width:254px;
+        height: 400px;
+        border:1px solid #DCDCDC;
+        border-radius: 6px;
+        padding:8px;
+        .head,.search,.content{
+            padding:10px;
+        }
+        .head{
+            display: flex;
+            justify-content: space-between;
+            .btn-text{
+                cursor: pointer;
+                &.delete{
+                    color:red;
+                }
+            }
+        }
+        .content{
+            flex:1;
+            overflow-y: scroll;
+            margin-bottom: 10px;
+            .list-item{
+                cursor: pointer;
+                padding:6px 0;
+                display: flex;
+                justify-content: space-between;
+            }
+        }
+    }
+}
+</style>

+ 95 - 0
src/views/approve_manage/config/tableConfig.js

@@ -0,0 +1,95 @@
+//审批管理-待处理
+export const approve_pending_columns = [
+    {
+        key:'ReportTitle',
+        label:'报告标题'
+    },{
+        key:'ReportClassify',
+        label:'关联报告'
+    },{
+        key:'ApplyUserName',
+        label:'提交人'
+    },{
+        key:'CreateTime',
+        label:'提交时间',
+        sortable:'custom'
+    },{
+        key:'RecordState',
+        label:'审批状态',
+    }
+]
+export const appreve_pending_status = [
+    {
+        type:1,
+        label:'待审批'
+    }
+]
+//审批管理-已处理
+export const approve_processed_columns=[
+    {
+        key:'ReportTitle',
+        label:'报告标题'
+    },{
+        key:'ReportClassify',
+        label:'关联报告'
+    },{
+        key:'ApplyUserName',
+        label:'提交人'
+    },{
+        key:'CreateTime',
+        label:'提交时间',
+        sortable:'custom'
+    },{
+        key:'HandleTime',
+        label:'处理时间',
+        sortable:'custom'
+    },{
+        key:'RecordState',
+        label:'处理结果',
+    }
+]
+export const approve_processed_status = [
+    {
+        type:1,
+        label:'已同意'
+    },{
+        type:2,
+        label:'已驳回'
+    }
+]
+//审批管理-我发起的
+export const approve_originate_columns=[
+    {
+        key:'ReportTitle',
+        label:'报告标题'
+    },{
+        key:'ReportClassify',
+        label:'关联报告'
+    },{
+        key:'CreateTime',
+        label:'提交时间',
+        sortable:'custom'
+    },{
+        key:'ApproveTime',
+        label:'审批时间',
+        sortable:'custom'
+    },{
+        key:'State',
+        label:'审批状态',
+    }
+]
+export const approve_originate_status=[
+    {
+        type:1,
+        label:'待审批'
+    },{
+        type:2,
+        label:'已通过'
+    },{
+        type:3,
+        label:'已驳回'
+    },{
+        type:4,
+        label:'已撤销'
+    }
+]

+ 39 - 0
src/views/approve_manage/css/nodeStyle.scss

@@ -0,0 +1,39 @@
+.node-wrap{
+    display: flex;
+    flex-direction: column;
+    /* align-items: center; */
+    .node-content{
+        overflow: hidden;
+        cursor: pointer;
+        border-radius: 4px;
+        width:300px;
+        min-height: 100px;
+        background-color: #fff;
+        border:1px solid #0052D9;
+        .head{
+            user-select: none;
+            color:#fff;
+            height:35px;
+            display: flex;
+            align-items: center;
+            padding: 5px;
+            justify-content: space-between;
+            border-bottom: 1px solid #0052D9;
+            .name{
+                margin-left: 5px;
+                margin-right: auto;
+            }
+            .icon{
+                display: inline-block;
+                width:20px;
+                height:20px;
+            }
+        }
+        .content{
+            padding:5px;
+        }
+    }
+    div{
+        box-sizing: border-box;
+    }
+}

+ 6 - 0
src/views/approve_manage/css/pageStyle.scss

@@ -0,0 +1,6 @@
+.approve-page-wrap{
+    min-height: calc(100vh - 120px);
+    background-color: #fff;
+    box-sizing: border-box;
+    padding:30px;
+}

+ 31 - 0
src/views/approve_manage/mixins/approveMixins.js

@@ -0,0 +1,31 @@
+import {approveInterence} from '@/api/modules/approve.js'
+const filterNodes = (arr,hasDisabled)=>{
+    arr.length &&arr.forEach((item) => {
+        hasDisabled&&(item.disabled = item.HasFlow)
+        item.Children.length && filterNodes(item.Children,hasDisabled);
+        if (!item.Children.length) {
+            delete item.Children;
+        }
+    })
+}
+
+export default{
+    data(){
+        return {
+            classifyTree:[],
+        }
+    },
+    methods:{
+        getClassifyTree(){
+            approveInterence.getReportClassifyTree().then(res=>{
+                if(res.Ret!==200) return 
+                this.classifyTree = res.Data||[]
+                const hasDisabled = window.location.pathname.startsWith('/approveEdit')
+                filterNodes(this.classifyTree,hasDisabled)
+                if(this.getFlowDetail){
+                    this.getFlowDetail()
+                }
+            })
+        },
+    }
+}

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

@@ -10,6 +10,25 @@ const portStyle = {
         }
         }
     }
     }
     }
     }
+//利用NodeTool实现角标
+export const textTool = {
+    name:'button',
+    args:{
+        x:'100%',
+        y:'100%',
+        offset:{x:-12,y:-5},
+        markup:[{
+            tagName:'text',
+            textContent:'aaa',
+            attrs:{
+                fill: '#0052D9',
+                fontSize: 12,
+                textAnchor: 'middle',
+                pointerEvents: 'none',
+            }
+        }]
+    }
+}
 //基础节点
 //基础节点
 export const baseNode = {
 export const baseNode = {
     shape:'rect',
     shape:'rect',

+ 1 - 5
src/views/chartFrame_manage/common/graph.js

@@ -9,13 +9,9 @@ const viewConfig = {
         restrict:true,//节点移动时无法超出画布
         restrict:true,//节点移动时无法超出画布
     },
     },
     interacting:function (cellView){ //禁止节点移动
     interacting:function (cellView){ //禁止节点移动
-        /* if(cellView.cell.getData().disableMove){
-            return false
-        } */
-        return false
+        return {'nodeMovable':false,'edgeMovable':false}
     },
     },
     highlighting:{},
     highlighting:{},
-    /* connecting:{}, */
     history:false,//关闭画布撤销/重做能力。
     history:false,//关闭画布撤销/重做能力。
     keyboard:false,
     keyboard:false,
     clipboard: false,
     clipboard: false,

+ 31 - 6
src/views/chartFrame_manage/components/frameContainer.vue

@@ -32,7 +32,7 @@
 <script>
 <script>
 import { ElDropdownMenu } from 'element-ui';
 import { ElDropdownMenu } from 'element-ui';
 import { myGraph } from '../common/graph';
 import { myGraph } from '../common/graph';
-import { baseNode } from '../common/config';
+import { baseNode , textTool } from '../common/config';
 import FrameToolBar from './frameToolBar.vue';
 import FrameToolBar from './frameToolBar.vue';
 export default {
 export default {
     components:{ElDropdownMenu,FrameToolBar},
     components:{ElDropdownMenu,FrameToolBar},
@@ -40,6 +40,10 @@ export default {
         FrameworkContent:{ //框架内容
         FrameworkContent:{ //框架内容
             type:String,
             type:String,
             default:''
             default:''
+        },
+        Nodes:{
+            type:Array,
+            default:[]
         }
         }
     },
     },
     data() {
     data() {
@@ -70,9 +74,6 @@ export default {
                 this.currentCell = null
                 this.currentCell = null
             }
             }
         },
         },
-        FrameworkContent(newVal){//当框架内容发生改变时,画布内容也发生改变
-            newVal.length&&this.gragh&&this.graph.fromJSON(JSON.parse(newVal))
-        }
     },
     },
     computed:{
     computed:{
         contextMenu(){//右键菜单,根据权限配置
         contextMenu(){//右键菜单,根据权限配置
@@ -95,6 +96,8 @@ export default {
             this.FrameworkContent.length&&this.graph.fromJSON(JSON.parse(this.FrameworkContent))
             this.FrameworkContent.length&&this.graph.fromJSON(JSON.parse(this.FrameworkContent))
             //如果有内容,将画布内容居中
             //如果有内容,将画布内容居中
             this.FrameworkContent.length&&this.graph.scrollToContent({ animation: { duration: 600 }})
             this.FrameworkContent.length&&this.graph.scrollToContent({ animation: { duration: 600 }})
+            //如果有内容,遍历每个节点,赋值chartNum
+            this.FrameworkContent.length&&this.setNodeInfo()
             //如果是非编辑页,加载完成画布内容后冻结画布
             //如果是非编辑页,加载完成画布内容后冻结画布
             window.location.pathname.startsWith('/chartframe')&&this.graph.freeze()
             window.location.pathname.startsWith('/chartframe')&&this.graph.freeze()
             //如果是编辑页,加载完成后清除历史数据
             //如果是编辑页,加载完成后清除历史数据
@@ -104,6 +107,17 @@ export default {
         dispose(){
         dispose(){
             this.graph&&this.graph.dispose()
             this.graph&&this.graph.dispose()
         },
         },
+        setNodeInfo(){
+            const nodes = this.graph.getNodes()
+            this.Nodes.forEach(node=>{
+                const currentNode = nodes.find(item=>item.id===node.NodeId)
+                if(currentNode){
+                    currentNode.removeTools()
+                    const toolOption = this.getToolOption({chartNum:node.ChartNum||0,color:currentNode.attrs.label.fill})
+                    currentNode.addTools(toolOption)
+                }
+            })
+        },
         //添加/编辑节点
         //添加/编辑节点
         editNode(node){
         editNode(node){
             //获取视口范围
             //获取视口范围
@@ -114,6 +128,9 @@ export default {
                 currentNode.data.id=node.nodeLink.MyChartClassifyId
                 currentNode.data.id=node.nodeLink.MyChartClassifyId
                 currentNode.label=node.nodeName
                 currentNode.label=node.nodeName
                 currentNode.data.nodeLink = node.nodeLink
                 currentNode.data.nodeLink = node.nodeLink
+                currentNode.removeTools()
+                const toolOption = this.getToolOption({chartNum:node.nodeLink.ChartNum,color:currentNode.attrs.label.fill})
+                currentNode.addTools(toolOption)
             }else{
             }else{
                 //在视口范围内添加节点
                 //在视口范围内添加节点
                 this.graph.addNode({
                 this.graph.addNode({
@@ -125,12 +142,19 @@ export default {
                     height:50,
                     height:50,
                     data:{
                     data:{
                         id:node.nodeLink.MyChartClassifyId,//存储节点对应的myETA分类id
                         id:node.nodeLink.MyChartClassifyId,//存储节点对应的myETA分类id
-                        nodeLink:node.nodeLink
+                        nodeLink:node.nodeLink,
                     },
                     },
-                    label:node.nodeName||''
+                    label:node.nodeName||'',
+                    tools:[this.getToolOption({chartNum:node.nodeLink.ChartNum,color:baseNode.attrs.label.fill})]
                 }})
                 }})
             }
             }
         },
         },
+        getToolOption({chartNum,color}){
+            const options = _.cloneDeep(textTool)
+            options.args.markup[0].textContent = chartNum +''
+            options.args.markup[0].attrs.fill = color
+            return options
+        },
         //点击右键菜单事件
         //点击右键菜单事件
         handleContext(key){
         handleContext(key){
             const select_cell = this.graph.getSelectedCells()
             const select_cell = this.graph.getSelectedCells()
@@ -191,6 +215,7 @@ export default {
         getContentNodes(){
         getContentNodes(){
             return this.graph.getNodes().map(node=>{
             return this.graph.getNodes().map(node=>{
                 return {
                 return {
+                    NodeId:node.id,
                     NodeName:node.label,
                     NodeName:node.label,
                     MyChartClassifyId:Number(node.data.id)
                     MyChartClassifyId:Number(node.data.id)
                 }
                 }

+ 9 - 1
src/views/chartFrame_manage/components/frameToolBar.vue

@@ -115,7 +115,7 @@
                             :class="{'img-disabled':!isSelectNode&&!isSelectEdge,'actived':isSelectNode||isSelectEdge}">
                             :class="{'img-disabled':!isSelectNode&&!isSelectEdge,'actived':isSelectNode||isSelectEdge}">
                     </label>
                     </label>
                     <input type="color" id="storke" style="width: 0;height: 0;visibility: hidden;" 
                     <input type="color" id="storke" style="width: 0;height: 0;visibility: hidden;" 
-                        :value="cellStyle.stroke"
+                        :value="nodeStyle.stroke"
                         @input="valueChange"/>
                         @input="valueChange"/>
                     <span class="disabled" v-if="!isSelectNode&&!isSelectEdge"></span>
                     <span class="disabled" v-if="!isSelectNode&&!isSelectEdge"></span>
                 </span>
                 </span>
@@ -311,7 +311,15 @@ export default {
                 if(styleMap[id]){
                 if(styleMap[id]){
                     attr = this.isSelectNode?styleMap[id][0]:styleMap[id][1]
                     attr = this.isSelectNode?styleMap[id][0]:styleMap[id][1]
                 } 
                 } 
+                
                 this.currentCell.attr(attr,value)
                 this.currentCell.attr(attr,value)
+                //改变节点字体颜色时,角标的颜色也一起改变
+                if(attr==='label/fill'){
+                    let tool = this.currentCell.getTools().items[0]
+                    tool.args.markup[0].attrs.fill = value
+                    this.currentCell.removeTools()
+                    this.currentCell.addTools(tool)
+                }
             }
             }
         },
         },
         changeCellStyle({attr,value}){
         changeCellStyle({attr,value}){

+ 9 - 1
src/views/chartFrame_manage/css/basePage.scss

@@ -57,12 +57,20 @@
                 overflow-y: auto;
                 overflow-y: auto;
             } */
             } */
             .public-catalog{
             .public-catalog{
+                .title{
+                    cursor: pointer;
+                    span{
+                        margin-left: 5px;
+                    }
+                }
                 .catalog-tree{
                 .catalog-tree{
-                    margin: 20px 0;
+                   /*  margin: 20px 0; */
+                   margin-top:20px;
                     min-height: 100px;
                     min-height: 100px;
                 }
                 }
             }
             }
             .my-list{
             .my-list{
+                margin-top: 20px;
                 .classify-item{
                 .classify-item{
                     display: flex;
                     display: flex;
                     align-items: center;
                     align-items: center;

+ 1 - 1
src/views/chartFrame_manage/css/customTree.scss

@@ -1,4 +1,4 @@
-.chart-frame-wrap{
+.chart-frame-wrap,.tree-wrap{
     .catalog-tree{
     .catalog-tree{
         .custom-tree-node {
         .custom-tree-node {
             display: flex !important;
             display: flex !important;

+ 14 - 2
src/views/chartFrame_manage/frameEditor.vue

@@ -3,7 +3,8 @@
     <div class="frame-editor-wrap">
     <div class="frame-editor-wrap">
         <div class="option-wrap">
         <div class="option-wrap">
             <el-input style="width:240px;" placeholder="请输入框架名称" v-model.trim="frameDetail.FrameworkName"></el-input>
             <el-input style="width:240px;" placeholder="请输入框架名称" v-model.trim="frameDetail.FrameworkName"></el-input>
-            <el-button type="primary" style="margin-left:auto;" @click="handleEditNode({})"
+            <el-button type="primary" plain style="margin-left:auto;" @click="returnListPage">返回</el-button>
+            <el-button type="primary" style="margin-left:20px;" @click="handleEditNode({})"
                 v-if="permissionBtn.isShowBtn('chartFramePermission','chartframe_my_editNode')">添加节点</el-button>
                 v-if="permissionBtn.isShowBtn('chartFramePermission','chartframe_my_editNode')">添加节点</el-button>
             <el-button type="primary" style="margin-left:20px;" @click="saveFrame"
             <el-button type="primary" style="margin-left:20px;" @click="saveFrame"
                 v-if="permissionBtn.isShowBtn('chartFramePermission','chartframe_my_saveFrame')">保存</el-button>
                 v-if="permissionBtn.isShowBtn('chartFramePermission','chartframe_my_saveFrame')">保存</el-button>
@@ -12,6 +13,7 @@
             <!-- 沙盘图组件 -->
             <!-- 沙盘图组件 -->
             <FrameContainer ref="container"
             <FrameContainer ref="container"
                 :FrameworkContent="frameDetail.FrameworkContent"
                 :FrameworkContent="frameDetail.FrameworkContent"
+                :Nodes="frameDetail.Nodes"
                 @editNode="handleEditNode"
                 @editNode="handleEditNode"
                 @framePic="getFramePic"
                 @framePic="getFramePic"
             />
             />
@@ -70,6 +72,7 @@ export default {
             frameDetail:{
             frameDetail:{
                 FrameworkName:'',
                 FrameworkName:'',
                 FrameworkContent:'',
                 FrameworkContent:'',
+                Nodes:[]
             },
             },
             lockLoding:null,
             lockLoding:null,
             modifyNode: {},//正在编辑的节点
             modifyNode: {},//正在编辑的节点
@@ -151,6 +154,11 @@ export default {
                     this.$router.replace({path:'/editframe',query:{frameId:this.frameId}})
                     this.$router.replace({path:'/editframe',query:{frameId:this.frameId}})
                 })
                 })
             }
             }
+            //重新加载一次画布
+            this.$refs.container.dispose()
+            this.$nextTick(()=>{
+                this.$refs.container.init()
+            })
         },
         },
         getMyList(){
         getMyList(){
             mychartInterface.classifyList().then((res)=>{
             mychartInterface.classifyList().then((res)=>{
@@ -163,7 +171,7 @@ export default {
             if(this.frameId){
             if(this.frameId){
                 const res = await chartFrameInterface.getFrameDetail({ChartFrameworkId:Number(this.frameId)})
                 const res = await chartFrameInterface.getFrameDetail({ChartFrameworkId:Number(this.frameId)})
                 if(res.Ret!==200) return 
                 if(res.Ret!==200) return 
-                this.frameDetail = res.Data||{FrameworkName:'',FrameworkContent:''}
+                this.frameDetail = res.Data||{FrameworkName:'',FrameworkContent:'',Nodes:[]}
             }
             }
             //获取到框架内容后再加载graph
             //获取到框架内容后再加载graph
             this.$nextTick(()=>{
             this.$nextTick(()=>{
@@ -171,6 +179,10 @@ export default {
             })
             })
             
             
         },
         },
+        //返回至列表页,并选中当前页的框架(如果是编辑)
+        returnListPage(){
+            this.$router.push({path:'/chartframe',query:{frameId:this.frameId||''}})
+        }
     },
     },
     mounted(){
     mounted(){
         this.getMyList()
         this.getMyList()

+ 16 - 8
src/views/chartFrame_manage/index.vue

@@ -34,8 +34,8 @@
             </div>
             </div>
             <div class="catalog-list">
             <div class="catalog-list">
                 <div class="public-catalog">
                 <div class="public-catalog">
-                    <p>公共框架</p>
-                    <div class="catalog-tree">
+                    <p @click="expandPublic = !expandPublic" class="title">公共框架<span><i :class="{'el-icon-arrow-down':!expandPublic,'el-icon-arrow-up':expandPublic}"></i></span></p>
+                    <div class="catalog-tree" v-show="expandPublic">
                         <el-tree
                         <el-tree
                             ref="catalogTree"
                             ref="catalogTree"
                             class="catalog-tree other-tree"
                             class="catalog-tree other-tree"
@@ -167,7 +167,8 @@
                     <div class="frame-wrap">
                     <div class="frame-wrap">
                         <!--沙盘图组件-->
                         <!--沙盘图组件-->
                         <FrameContainer ref="container"
                         <FrameContainer ref="container"
-                            :FrameworkContent="currentFrame.FrameworkContent"
+                            :FrameworkContent="currentFrameDetail.FrameworkContent"
+                            :Nodes="currentFrameDetail.Nodes"
                             @showDialog="handleShowDialog"/>
                             @showDialog="handleShowDialog"/>
                     </div>
                     </div>
                 </div>
                 </div>
@@ -243,7 +244,7 @@
 
 
 <script>
 <script>
 import draggable from 'vuedraggable';
 import draggable from 'vuedraggable';
-import FrameContainer from './components/frameContainer.vue';
+import FrameContainer from './components/frameContainer';
 import chartDetail from '@/views/mychart_manage/components/chartDetailDia.vue';
 import chartDetail from '@/views/mychart_manage/components/chartDetailDia.vue';
 import { mychartInterface,chartFrameInterface } from '@/api/api.js';
 import { mychartInterface,chartFrameInterface } from '@/api/api.js';
 import {copyBlob} from '@/utils/svgToblob.js';
 import {copyBlob} from '@/utils/svgToblob.js';
@@ -273,6 +274,7 @@ export default {
     data() {
     data() {
         return {
         return {
             isSlideLeft:false,//控制左侧目录栏是否显示
             isSlideLeft:false,//控制左侧目录栏是否显示
+            expandPublic:false,//控制公共框架展开收起
 
 
             /* drag 我的框架相关 */
             /* drag 我的框架相关 */
             dragStartIndex:0,
             dragStartIndex:0,
@@ -291,6 +293,7 @@ export default {
             currentList:[],//选择公共框架时,框架列表
             currentList:[],//选择公共框架时,框架列表
             myFrameList:[],//我的框架列表
             myFrameList:[],//我的框架列表
             currentFrame:{},//选择的框架
             currentFrame:{},//选择的框架
+            currentFrameDetail:{},//选中的框架详情
             /* frame node */
             /* frame node */
             myETADetailDialogShow:false,//点击节点时,弹出myeta图表详情弹框
             myETADetailDialogShow:false,//点击节点时,弹出myeta图表详情弹框
             modifyFrame:{},//正在修改的框架
             modifyFrame:{},//正在修改的框架
@@ -391,16 +394,21 @@ export default {
                 this.currentFrame={}
                 this.currentFrame={}
             }
             }
         },
         },
-        handleInitGraph(){
+        async handleInitGraph(){
+            //获取框架详情
+            if(this.currentFrame.ChartFrameworkId){
+                const res = await chartFrameInterface.getFrameDetail({ChartFrameworkId:Number(this.currentFrame.ChartFrameworkId)})
+                this.currentFrameDetail = res.Data||{}
+            }
             //判断一下框架内容是否是合法的JSON,否则置为空
             //判断一下框架内容是否是合法的JSON,否则置为空
             try{
             try{
-                JSON.parse(this.currentFrame.FrameworkContent)
+                JSON.parse(this.currentFrameDetail.FrameworkContent)
             }catch(e){
             }catch(e){
-                this.currentFrame.FrameworkContent = ''
+                this.currentFrameDetail.FrameworkContent = ''
             }
             }
             this.$nextTick(()=>{
             this.$nextTick(()=>{
                 //若框架有内容,才加载画布
                 //若框架有内容,才加载画布
-                this.currentFrame.FrameworkContent&&this.$refs.container.init()
+                this.currentFrameDetail.FrameworkContent&&this.$refs.container.init()
             })
             })
         },
         },
         /* 拖动相关 */
         /* 拖动相关 */

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

@@ -35,4 +35,28 @@ export const statisticFeatureListTextArr = [
     <p>2、根据频段数划分多个间距相同的区间(左闭右开,最后一个区间为左闭右闭),统计数据值落在每个区间的数据个数;</p>
     <p>2、根据频段数划分多个间距相同的区间(左闭右开,最后一个区间为左闭右闭),统计数据值落在每个区间的数据个数;</p>
     <p>3、频率=落在某区间数据个数/所选时间段内数据总个数;</p>
     <p>3、频率=落在某区间数据个数/所选时间段内数据总个数;</p>
     <p>4、累计频率为从最小值所在区间对应的频率开始累加;</p>`
     <p>4、累计频率为从最小值所在区间对应的频率开始累加;</p>`
+]
+
+//跨品种分析
+export const crossVarietyAnalisisTextArr = [
+    `<p style="font-weight:bold;">一、处理逻辑</p>
+    <p>1、百分位计算公式:对所选时间范围内的数据,取最大值Max,最小值Min,计算Max-Min,百分位=(现值-Min)/(Max-Min),Max=Min时不计算</p>
+    <p>2、取值方式:</p>
+    <p>(1)通过“选择日期”和“时间长度”,时间范围为“选择日期”至选择的日期往过去推“时间长度”,在这个时间段找出指标最大值和最小值,进行百分位计算。</p>
+    <p>(2)若在(1)的时间范围下找不到值,则继续往过去找,直到找到值。</p>
+    <p>3、图表说明:</p>
+    <p> (1)某个品种会有多个坐标点(坐标点的数量取决于设置的日期数量);</p>
+    <p> (2)坐标点的X、Y值取实际日期与值。</p>`,
+
+    `<p style="font-weight:bold;">二、相关配置</p>
+    <p>1、基本配置</p>
+    <p>(1)管理员进行品种管理、标签管理;</p>
+    <p>(2)使用者对标签的品种关联指标。</p>
+    <p>2、计算配置</p>
+    <p>(1)时间长度:默认显示6个月;</p>
+    <p>(2)选择日期:最多支持选择5个日期;</p>
+    <p>(3)X轴坐标:选择标签;</p>
+    <p>(4)Y轴坐标:选择标签;</p>
+    <p>(5)图表名称:X轴坐标和Y轴坐标的拼接。</p>`
+
 ]
 ]

+ 670 - 0
src/views/chartRelevance_manage/crossVarietyAnalysis/chartEditor.vue

@@ -0,0 +1,670 @@
+<template>
+  <div class="crossVariety-edit-page" id="box">
+    <span
+      class="slide-icon slide-right"
+      @click="isSlideLeft = !isSlideLeft"
+      v-show="isSlideLeft"
+    >
+      <i class="el-icon-d-arrow-right"></i>
+    </span>
+    <div class="left-cont" v-show="!isSlideLeft" id="left">
+      <div class="left-top">
+        <div>
+          <el-button type="primary" @click="saveChartHandle">保存</el-button>
+          <el-button type="primary" plain @click="$router.back()">取消</el-button>
+
+        </div>
+        <div style="color:#409EFF;font-size: 16px;cursor: pointer;" @click="showExplain = true">
+            <i class="el-icon-document" style="font-size:22px;"></i>
+            操作说明
+        </div>
+      </div>
+
+      <div class="left-min">
+        <section class="section-item">
+          <div class="top">
+            <label>选择品种</label>
+            <el-button
+              v-permission="permissionBtn.statisticPermission.crossVariety_variety_edit"
+              type="text" 
+              @click="setDialogOpen('variety')"
+            >品种管理</el-button>
+          </div>
+          <div class="list" v-if="varietyOptions.length">
+            <el-tag 
+              size="small" 
+              :class="['tag',{'act':checkedVarietys.includes(item.ChartVarietyId)}]"
+              v-for="item in varietyOptions"
+              :key="item.ChartVarietyId"
+              @click="checkVarietyHandle(item)"
+            >{{item.ChartVarietyName}}</el-tag>
+          </div>
+
+          <tableNoData v-else text="暂无品种" size="mini"/>
+        </section>
+
+        <el-divider/>
+
+        <section class="section-item">
+          <div class="top">
+            <label>标签配置</label>
+            <el-button
+              v-permission="permissionBtn.statisticPermission.crossVariety_tag_edit"
+              type="text" 
+              @click="setDialogOpen('tag')"
+            >标签管理</el-button>
+          </div>
+          <div class="list" v-if="tagOptions.length">
+            <el-tag 
+              size="small" 
+              :class="item.VarietyTotal?'act tag':'tag'"
+              v-for="item in tagOptions"
+              :key="item.ChartTagId"
+              @click="setTagRelationOpen(item)"
+            >{{item.ChartTagName}}</el-tag>
+          </div>
+
+          <tableNoData text="暂无标签" size="mini" v-else/>
+        </section>
+
+      </div>
+      
+      <span
+        class="move-btn resize"
+        v-drag
+        id="resize"
+      ></span>
+      <span class="slide-icon slide-left" @click="isSlideLeft = !isSlideLeft">
+        <i class="el-icon-d-arrow-left"></i>
+      </span>
+    </div>
+    <div
+      class="right-cont"
+      id="right"
+      :style="isSlideLeft ? 'width:100%' : `width:80%`"
+    >
+      <div
+        class="chart-min-cont"
+      >
+        <div class="chart-wrapper" v-if="options.series&&options.series.length">
+          <div class="chart-show-cont"  v-if="!chartInfo.WarnMsg">
+            <div style="position:relative;">
+              <h2 class="chart-title">{{ chartInfo.ChartName }}</h2>
+              <Chart 
+                :options="options"
+                minHeight="400px" 
+                height="450px"
+                ref="chartRef"
+              />
+              <span class="chart-author">作者:{{ chartInfo.SysUserRealName || accountName}}</span>
+
+              <!-- 上下限 -->
+              <template>	
+                <div class="range-cont left">
+                  <el-input
+                    style="width: 60px; display: block"
+                    size="mini"
+                    type="number"
+                    :min="0"
+                    :max="100"
+                    placeholder="上限"
+                    v-model="chartLimit.max"
+                    @change="changeLimit"
+                  />
+                  <el-input
+                    class="min-data-input"
+                    size="mini"
+                    type="number"
+                    :min="0"
+                    :max="100"
+                    placeholder="下限"
+                    v-model="chartLimit.min"
+                    @change="changeLimit"
+                  />
+                </div>
+                <!-- x轴上下限 -->
+                <div class="range-cont bottom" > 
+                  <el-input
+                    class="left"
+                    size="mini"
+                    type="number"
+                    :min="0"
+                    :max="100"
+                    placeholder="下限"
+                    v-model="chartLimit.x_min"
+                    @change="changeLimit"
+                  />
+                  <el-input
+                    class="left"
+                    size="mini"
+                    type="number"
+                    :min="0"
+                    :max="100"
+                    placeholder="上限"
+                    v-model="chartLimit.x_max"
+                    @change="changeLimit"
+                  />
+                </div>
+              </template>
+              
+            </div>
+          </div>
+
+          <!-- 异常显示 -->
+          <p class="error-tip" style="min-height: 400px;" v-if="chartInfo.WarnMsg">{{chartInfo.WarnMsg}}</p>
+        </div>
+
+        <div class="nodata" v-else>
+          <tableNoData text="暂无信息"/>
+        </div>
+
+        <div class="bottom-wrapper">
+          <!-- 图表相关配置 -->
+          <chartFormSection
+            :tagList="tagOptions"
+            :chartInfo="chartInfo"
+            ref="chartFormRef"
+            @getData="getChartPreviewData"
+          />
+
+          <!-- 指标列表 -->
+          <edbTableSection :tableData="tableData"/>
+        </div>
+
+      </div> 
+
+    </div>
+
+    <!-- 管理弹窗 -->
+    <tagSetDialog
+      :isShow.sync="isShowSetDia"
+      :type="dialogType"
+      :dataList="dialogType==='variety'?varietyOptions:tagOptions"
+      @refresh="dialogType==='tag'?getTagList():getVarietyList();"
+    />
+
+    <!-- 标签指标配置 -->
+    <tagRelationDialog
+      :isShow.sync="isShowTagRelationDia"
+      :varietyList="varietyOptions"
+      :info="tagRelationInfo"
+      @refresh="getTagList"
+    />
+
+    <!-- 操作说明 -->
+    <ExplainDialog 
+        textArrName="crossVarietyAnalisisTextArr"
+        :show-explain="showExplain"
+        @close="showExplain = false"
+    />
+  </div>
+</template>
+
+<script>
+import { crossVarietyInterface } from '@/api/modules/chartRelevanceApi';
+import { dataBaseInterface } from '@/api/api';
+import { chartSetMixin } from '@/views/dataEntry_manage/mixins/chartPublic';
+import Chart from '@/views/dataEntry_manage/components/chart';
+import ExplainDialog from '../components/explainDialog.vue';
+import chartFormSection from './components/chartFormSection.vue';
+import tagSetDialog from './components/tagSetDialog.vue';
+import tagRelationDialog from './components/tagRelationDialog.vue';
+import edbTableSection from './components/edbTableSection.vue'
+export default {
+  components: {
+    ExplainDialog,
+    Chart,
+    chartFormSection,
+    tagSetDialog,
+    tagRelationDialog,
+    edbTableSection
+  },
+  directives: {
+    drag(el, bindings) {
+      el.onmousedown = function (e) {
+        var init = e.clientX;
+        // console.log(init);
+        var box = $('#box')[0];
+        // console.log(box.clientWidth)
+        let total_wid = box.offsetWidth;
+        var left = $('#left')[0];
+        var right = $('#right')[0];
+        var initWidth = left.offsetWidth;
+        document.onmousemove = function (e) {
+          var end = e.clientX;
+          var newWidth = end - init + initWidth;
+          left.style.width = newWidth + 'px';
+          right.style.width = newWidth > 300 ? total_wid - newWidth + 'px' : total_wid - 320 + 'px';
+        };
+        document.onmouseup = function () {
+          document.onmousemove = document.onmouseup = null;
+          e.releaseCapture && e.releaseCapture();
+        };
+        e.setCapture && e.setCapture();
+        return false;
+      };
+    },
+  },
+  mixins: [ chartSetMixin ],
+  computed: {
+    accountName() {
+      return localStorage.getItem('userName')
+    }
+  },
+  data() {
+    return {
+      chart_code: this.$route.query.code || '',
+      isSlideLeft: false,
+      chartInfo: {
+        Source: 10,
+        ChartName: '',
+        SysUserRealName: ''
+      },
+
+      showExplain: false,
+
+      checkedVarietys: [], //选中的品种
+      varietyOptions: [],
+      tagOptions: [],
+
+      isShowSetDia: false,//管理弹窗
+      dialogType: '',
+
+      isShowTagRelationDia: false,//标签指标管理弹窗
+      tagRelationInfo: {
+        tagName:'',
+        id: 0
+      }
+    };
+  },
+  methods: {
+
+    /* 获取图表详情 */
+    async getChartDetail() {
+      if(!this.chart_code) return 
+
+      let res = await dataBaseInterface.getChartByCode({
+				UniqueCode: this.chart_code
+			})
+
+      if(res.Ret !== 200) return
+
+      const { ChartInfo,DataResp,EdbInfoList } = res.Data;
+      let configSet = JSON.parse(ChartInfo.ExtraConfig);
+      this.checkedVarietys = configSet.VarietyList;
+      this.$refs.chartFormRef.initData(configSet);
+
+      this.chartInfo = ChartInfo;
+      this.tableData = EdbInfoList;
+      this.crossVarietyChartData = DataResp;
+      this.chartLimit = {
+        min: DataResp.YMinValue,
+        max: DataResp.YMaxValue ,
+        x_min: DataResp.XMinValue,
+        x_max: DataResp.XMaxValue,
+      }
+
+      this.setCrossVarietyChart()
+    },
+
+    checkParmas(type='') {
+      if(!this.checkedVarietys.length || !this.$refs.chartFormRef.form.CalculateValue || !this.$refs.chartFormRef.form.TagX ||!this.$refs.chartFormRef.form.TagY){
+        
+        type && this.dealWarnings()
+        return false
+      }
+      return true
+    },
+
+    dealWarnings() {
+      const {CalculateValue,TagX,TagY } = this.$refs.chartFormRef.form;
+      let message = '';
+      
+      if(!this.checkedVarietys.length) message = '请选择品种'
+      else if(!CalculateValue) message = '请输入时间长度'
+      else if(!TagX) message = '请选择X轴坐标'
+      else if(!TagY) message = '请选择Y轴坐标'
+
+      this.$message.warning(message)
+    },
+
+    /* 获取标签列表 */
+    async getTagList() {
+      let res = await crossVarietyInterface.getTagList()
+
+      if(res.Ret !== 200) return
+      this.tagOptions = res.Data.List || []
+    },
+
+    async getVarietyList() {
+      let res = await crossVarietyInterface.getVarietyList()
+
+      if(res.Ret !== 200) return
+      this.varietyOptions = res.Data.List || []
+    },
+
+    /* 预览数据 */
+    async getChartPreviewData() {
+      if(!this.checkParmas()) return;
+
+      let params = {
+        VarietyList: this.checkedVarietys,
+        ...this.$refs.chartFormRef.form
+      }
+      let res = await crossVarietyInterface.chartPreview(params)
+
+      if(res.Ret !== 200) return
+
+      const { DataResp,EdbInfoList } = res.Data;
+      this.tableData = EdbInfoList;
+      
+      this.chartLimit = {
+        min: Number(DataResp.YMinValue),
+        max: Number(DataResp.YMaxValue),
+        x_min: Number(DataResp.XMinValue),
+        x_max: Number(DataResp.XMaxValue)
+      }
+      this.crossVarietyChartData = DataResp;
+      this.setCrossVarietyChart()
+    },
+    
+    /* 选择品种 */
+    checkVarietyHandle(item) {
+      this.checkedVarietys.includes(item.ChartVarietyId) 
+        ? this.checkedVarietys.splice(this.checkedVarietys.indexOf(item.ChartVarietyId),1) 
+        : this.checkedVarietys.push(item.ChartVarietyId)
+
+      this.getChartPreviewData();
+    },
+
+    /* 打开标签关联弹窗 */
+    setTagRelationOpen(item) {
+      this.tagRelationInfo = {
+        tagName: item.ChartTagName,
+        id: item.ChartTagId
+      }
+      this.isShowTagRelationDia = true;
+    },
+
+    /* 标签管理 */
+    setDialogOpen(type) {
+      this.dialogType = type;
+      this.isShowSetDia = true;
+    },
+
+    /* 保存图表 */
+    async saveChartHandle() {
+      if(!this.checkParmas('warning')) return;
+
+      let { min,max,x_min,x_max } = this.chartLimit;
+      let params = {
+        VarietyList: this.checkedVarietys,
+        ...this.$refs.chartFormRef.form,
+        XMinValue: String(x_min),
+				XMaxValue: String(x_max),
+				YMinValue: String(min),
+				YMaxValue: String(max),
+      }
+      let res = this.chart_code 
+        ? await crossVarietyInterface.chartEdit({...params,ChartInfoId: this.chartInfo.ChartInfoId})
+        : await crossVarietyInterface.chartAdd(params)
+
+      if(res.Ret !== 200) return
+      this.setChartImage(res.Data);
+    },
+
+     /* 设置图表封面图片 */
+    setChartImage(data) {
+      let svg = this.$refs.chartRef.chart.getSVG({
+        chart: {
+          width: 340,
+          height: 230,
+        }
+      });
+      let form = new FormData();
+      form.append('Img', svg);
+      this.setImageHandle(form,data);
+    },
+    async setImageHandle(form,{ UniqueCode,ChartInfoId }) {
+      let { Data } = await dataBaseInterface.uploadImgSvg(form);
+      await dataBaseInterface.setChartImage({
+        ChartInfoId: ChartInfoId,
+        ImageUrl: Data.ResourceUrl,
+      });
+
+			this.$message.success('保存成功');
+			this.$router.replace({
+				path: '/crossVarietyChartList',
+				query: {
+					code: UniqueCode,
+					id: ChartInfoId
+				}
+			})
+
+    },
+   
+    reloadRightWid() {
+      let total_wid = $('#box')[0].offsetWidth;
+      let left = $('#left')[0].offsetWidth;
+      let rigtWid = total_wid - left - 20 + 'px';
+      $('#right')[0].style.width = rigtWid;
+    },
+
+  },
+  mounted() {
+    this.getVarietyList();
+    this.getTagList();
+    this.getChartDetail();
+    window.addEventListener('resize', this.reloadRightWid);
+  },
+  destroyed() {
+    window.removeEventListener('resize', this.reloadRightWid);
+  },
+  beforeRouteEnter(to, from, next) {
+    if(to.query.code){
+      to.matched[1].name='编辑图表'
+    }else{
+      to.matched[1].name='添加图表'
+    }
+    next()
+  }
+};
+</script>
+<style lang="scss" scoped>
+.crossVariety-edit-page {
+  $font-small: 12px;
+  $font-normal: 14px;
+  display: flex;
+  * {
+    box-sizing: border-box;
+  }
+
+  .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;
+    }
+  }
+  .left-cont {
+    width: 380px;
+    min-width: 380px;
+    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 - 113px);
+    overflow: hidden;
+    position: relative;
+    box-sizing: border-box;
+    .left-top {
+      padding: 15px 20px;
+      border-bottom: 1px solid #ececec;
+      box-shadow: 0px 3px 6px rgba(167, 167, 167, 0.09);
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+    }
+    .left-min {
+      padding: 0 20px;
+      max-height: calc(100vh - 190px);
+      overflow-y: auto;
+      
+      .section-item{
+        padding: 20px 0;
+        .top {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          margin-bottom: 15px;
+
+        }
+        .list {
+          display: flex;
+          flex-wrap: wrap;
+          gap: 10px;
+          .tag {
+            color: #333;
+            background: #fff;
+            border-color: transparent;
+            cursor: pointer;
+            &.act {
+              color: #0052D9;
+              background-color: #e6eefb;
+              border-color: #ccdcf7;
+            }
+          }
+        }
+      }
+
+      .left-bottom {
+        margin-top: 20px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+     
+    }
+    .move-btn {
+      height: 100%;
+      width: 4px;
+      position: absolute;
+      right: 0px;
+      top: 0;
+      &:hover {
+        cursor: col-resize;
+      }
+    }
+  }
+  .right-cont {
+    width: 80%;
+    overflow-x: auto;
+    .chart-min-cont {
+      background: #fff;
+      min-width: 880px;
+      height: calc(100vh - 118px);
+      overflow-y: auto;
+      display: flex;
+      flex-wrap: wrap;
+      .chart-wrapper {
+				padding: 30px 0;
+        width: 100%;
+				/* =================== */
+				.chart-show-cont {
+					min-height: 400px;
+					padding: 0 100px 50px;
+					position: relative;
+					.chart-title {
+						font-size: 16px;
+						font-weight: normal;
+						text-align: center;
+						margin-bottom: 10px;
+					}
+					.chart-author {
+						font-size: 14px;
+						color: #333;
+						position: absolute;
+						bottom: -50px;
+						right: -70px;
+					}
+          .range-cont {
+            position: absolute;
+            top: 15%;
+            .min-data-input {
+              width: 60px;
+              display: block;
+            }
+            &.left {
+              left: -70px;
+            }
+            &.bottom {
+              width: 100%;
+              display: flex;
+              justify-content: space-between;
+              top: auto;
+              right: 0;
+              bottom: -4%;
+              .left {
+                width: 60px;
+                display: block;
+                flex-shrink: 0;
+              }
+            }
+          }
+				}
+				.options-cont {
+					display: flex;
+					flex-wrap: wrap;
+					justify-content: space-between;
+				}
+			}
+
+      @media screen and (min-width: 1711px) {
+        .min-data-input {
+          margin-top: 290px;
+        }
+      }
+      @media screen and (max-width: 1710px) {
+        .min-data-input {
+          margin-top: 250px;
+        }
+      }
+
+    }
+    .nodata {
+      background-color: #fff;
+      text-align: center;
+      font-size: 16px;
+      color: #666;
+      width: 100%;
+      padding: 100px 0;
+    }
+    .bottom-wrapper {
+      width: 100%;
+      padding: 20px;
+      border-top: 1px solid #ebeff6;
+    }
+  }
+}
+</style>
+<style lang="scss">
+.crossVariety-edit-page {
+  .el-input--mini .el-input__inner {
+		padding: 0 0 0 4px;
+	}
+}
+</style>

+ 208 - 0
src/views/chartRelevance_manage/crossVarietyAnalysis/components/chartFormSection.vue

@@ -0,0 +1,208 @@
+<template>
+  <div class="form-cont">
+    <el-form
+      ref="diaForm"
+      label-position="left"
+      label-width="80px"
+      :model="form"
+      :rules="formRules"
+    >
+      <el-form-item label="时间长度" prop="CalculateValue">
+        <el-input
+          v-model="form.CalculateValue"
+          style="width: 140px"
+          :step="1"
+          type="number"
+          @change="(val) => {form.CalculateValue = Number(val);changeParams()}"
+        />
+        <el-select
+          v-model="form.CalculateUnit"
+          placeholder="请选择"
+          style="width: 100px"
+          @change="changeParams"
+        >
+          <el-option
+            v-for="item in unitOpt"
+            :key="item.val"
+            :label="item.label"
+            :value="item.val"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="X轴坐标" prop="TagX">
+        <el-select
+          v-model="form.TagX"
+          style="width: 240px"
+          placeholder="请选择"
+          @change="changeSeries"
+        >
+          <el-option
+            v-for="item in tagList"
+            :key="item.ChartTagId"
+            :label="item.ChartTagName"
+            :value="item.ChartTagId"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="Y轴坐标" prop="TagY">
+        <el-select
+          v-model="form.TagY"
+          placeholder="请选择"
+          style="width: 240px"
+          @change="changeSeries"
+        >
+          <el-option
+            v-for="item in tagList"
+            :key="item.ChartTagId"
+            :label="item.ChartTagName"
+            :value="item.ChartTagId"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="图表名称" prop="ChartName">
+        <el-input
+          v-model="form.ChartName"
+          style="width: 240px"
+          placeholder="请输入图表名称"
+          @change="changeParams"
+        />
+      </el-form-item>
+    </el-form>
+
+    <div class="date-section">
+      <label class="el-form-item__label">选择日期</label>
+      <ul>
+        <li class="date-li" v-for="(item,index) in form.DateConfigList" :key="index">
+          <el-select
+            v-model="item.DateType"
+            style="width: 150px"
+            placeholder="请选择"
+            @change="changeParams"
+          >
+            <el-option
+              v-for="item in dateOptions"
+              :key="item.val"
+              :label="item.label"
+              :value="item.val"
+            />
+          </el-select>
+
+          <el-input
+            v-model="item.Num"
+            v-if="item.DateType===2"
+            style="width: 140px"
+            :step="1"
+            type="number"
+            @change="(val) => {item.Num = Number(val);changeParams()}"
+          />
+
+          <el-button type="text" v-if="index===0" @click="addDateHandle">
+            <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 -2 16 16" fill="none">
+              <path d="M5.23966 8.48046H7.51966V10.7605C7.51966 10.8265 7.57366 10.8805 7.63966 10.8805H8.35966C8.42566 10.8805 8.47966 10.8265 8.47966 10.7605V8.48046H10.7597C10.8257 8.48046 10.8797 8.42646 10.8797 8.36046V7.64046C10.8797 7.57446 10.8257 7.52046 10.7597 7.52046H8.47966V5.24046C8.47966 5.17446 8.42566 5.12046 8.35966 5.12046H7.63966C7.57366 5.12046 7.51966 5.17446 7.51966 5.24046V7.52046H5.23966C5.17366 7.52046 5.11966 7.57446 5.11966 7.64046V8.36046C5.11966 8.42646 5.17366 8.48046 5.23966 8.48046Z" fill="#0052D9"/>
+              <path d="M13.52 2H2.48C2.2145 2 2 2.2145 2 2.48V13.52C2 13.7855 2.2145 14 2.48 14H13.52C13.7855 14 14 13.7855 14 13.52V2.48C14 2.2145 13.7855 2 13.52 2ZM12.92 12.92H3.08V3.08H12.92V12.92Z" fill="#0052D9"/>
+            </svg>添加日期
+          </el-button>
+
+          <i 
+            v-else 
+            class="el-icon-delete" 
+            style="cursor:pointer;color:#f00;"
+            @click="() => {form.DateConfigList.splice(index,1);changeParams()}"
+          />
+
+        </li>
+      </ul>
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    tagList: {
+      type: Array,
+    },
+    chartInfo: {
+      type: Object
+    }
+  },
+  data() {
+    return {
+      form: {
+        ChartName:'',
+        Source: 10,
+        CalculateValue: 6,
+        CalculateUnit: '月',
+        TagX: '',
+        TagY: '',
+        DateConfigList: [
+          { DateType: 1,Num: 0 },
+        ],
+      },
+      unitOpt: [
+        { label: "年", val: "年" },
+        { label: "季", val: "季" },
+        { label: "月", val: "月" },
+        { label: "周", val: "周" },
+        { label: "天", val: "天" },
+      ],
+
+      dateOptions: [
+        { label: '最新日期',val: 1 },
+        { label: 'N天前',val: 2 },
+      ]
+    };
+  },
+  methods: {
+    addDateHandle() {
+      if(this.form.DateConfigList.length === 5) return this.$message.warning('日期数量已达上限')
+
+      this.form.DateConfigList.push({
+        DateType: 1,Num: 1
+      })
+      
+      this.changeParams()
+    },
+
+    initData(data) {
+      const { ChartName,CalculateValue,CalculateUnit,TagX,TagY,DateConfigList } = data;
+      this.form = {
+        ChartName,
+        CalculateValue,
+        CalculateUnit,
+        TagX,
+        TagY,
+        DateConfigList
+      }
+    },
+
+    changeSeries() {
+      let xName = this.tagList.find(_ => _.ChartTagId===Number(this.form.TagX))?this.tagList.find(_ => _.ChartTagId===Number(this.form.TagX)).ChartTagName:'';
+      let yName = this.tagList.find(_ => _.ChartTagId===Number(this.form.TagY))?this.tagList.find(_ => _.ChartTagId===Number(this.form.TagY)).ChartTagName:'';
+
+      this.form.ChartName = (xName&&yName) ? `${xName}百分位和${yName}百分位` : '';
+      this.changeParams()
+    },
+
+    changeParams() {
+      this.$emit('getData')
+    },
+  },
+};
+</script>
+<style scoped lang="scss">
+.form-cont {
+  width: 100%;
+  display: flex;
+  gap: 50px;
+
+  .date-section {
+    display: flex;
+    .date-li {
+      display: flex;
+      align-items: center;
+      gap: 10px;
+      margin-bottom: 20px;
+    }
+  }
+}
+</style>

+ 140 - 0
src/views/chartRelevance_manage/crossVarietyAnalysis/components/edbTableSection.vue

@@ -0,0 +1,140 @@
+<template>
+  <el-table
+    :data="tableData"
+    ref="tableRef"
+    highlight-current-row
+    border
+    >
+      <el-table-column
+        v-for="item in tableColums"
+        :key="item.label"
+        :label="item.label"
+        :width="item.widthsty"
+        :min-width="item.minwidthsty"
+        align="center"
+      >
+        <template slot-scope="scope">
+          <span>{{ scope.row[item.key] }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" key="Copy" align="center" width="140">
+        <template slot-scope="scope">
+          <span class="editsty" @click="copyCode(scope.row)">
+          <i class="el-icon-document-copy" />&nbsp;复制数据</span
+        ><br />
+        <span class="editsty" @click="viewTarget(scope.row)">查看数据</span>
+      </template>
+    </el-table-column>
+    <div slot="empty">
+      <tableNoData text="暂无指标" size="mini"/>
+    </div>
+  </el-table>
+</template>
+<script>
+import { dataBaseInterface } from '@/api/api';
+import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
+export default {
+  props: {
+    tableData: {
+      type: Array,
+      default: () => []
+    }
+  },
+  data() {
+    return {
+      tableColums: [
+        {
+          label: '指标名称',
+          key: 'EdbName',
+          enKey:'EdbNameEn',
+					inputTip:'点击输入英文指标名称',
+          minwidthsty: '150px',
+        },
+        {
+          label: '指标ID',
+          key: 'EdbCode',
+          widthsty: '120px',
+        },
+        {
+          label: '更新频度',
+          key: 'Frequency',
+          enKey:'FrequencyEn',
+          minwidthsty: '60px',
+        },
+        {
+          label: '单位',
+          key: 'Unit',
+          enKey:'UnitEn',
+					inputTip:'英文单位',
+          minwidthsty: '50px',
+        },
+        {
+          label: '起始时间',
+          key: 'StartDate',
+          minwidthsty: '100px',
+        },
+        {
+          label: '最新日期',
+          key: 'LatestDate',
+          minwidthsty: '90px',
+        },
+        {
+          label: '最新值',
+          key: 'LatestValue',
+          minwidthsty: '90px',
+        },
+        {
+          label: '最近更新',
+          key: 'ModifyTime',
+          minwidthsty: '100px',
+        },
+        {
+          label: '数据来源',
+          key: 'SourceName',
+        },
+      ],//表格列
+    }
+  },
+  methods:{
+    /* 用于复制指标 */
+    async copyCode({EdbInfoId, EdbInfoCategoryType}) {
+      let params = {
+        PageSize: 100000,
+        CurrentIndex: 1,
+        EdbInfoId: EdbInfoId,
+      }
+      const res = EdbInfoCategoryType === 1 
+        ? await preDictEdbInterface.edbDataInfo(params)
+        : await dataBaseInterface.targetList(params);
+      if (res.Ret !== 200) return
+
+      let arr = res.Data.Item.DataList || [];
+
+      let str = '日期\t 值\n';
+      arr.forEach((item) => (str += `${item.DataTime}\t${item.Value}\n`));
+      this.$copyText(str).then(
+        (res) => {
+          this.$message.success('已成功复制!');
+        },
+        (err) => {
+          this.$message.error('复制失败!');
+        }
+      );
+    },
+
+    /* 查看数据 跳转指标库展开具体指标 */
+    viewTarget({ UniqueCode,EdbInfoId,EdbInfoCategoryType,ClassifyId }) {
+      let path = EdbInfoCategoryType ? '/predictEdb' : '/database';
+      let {href} = this.$router.resolve({path, query: {
+        code: UniqueCode,
+        id: EdbInfoId,
+        classifyId:ClassifyId
+      }});
+			window.open(href,'_blank');
+    },
+  },
+}
+</script>
+<style scoped lang='scss'>
+
+</style>

+ 182 - 0
src/views/chartRelevance_manage/crossVarietyAnalysis/components/tagRelationDialog.vue

@@ -0,0 +1,182 @@
+<template>
+  <el-dialog
+    :visible.sync="isShow"
+    :close-on-click-modal="false"
+    :modal-append-to-body="false"
+    :title="`${info.tagName}指标配置`"
+    @close="cancelHandle"
+    custom-class="tag-relation-dialog"
+    center
+    width="650px"
+    v-dialogDrag
+  >
+    <div class="dialog-min">
+      <ul class="list-ul">
+        <li class="list-li" v-for="(item,index) in list" :key="index">
+          <label class="variety-name">{{item.varietyName}}</label>
+
+          <selectTarget
+            :defaultId="item.edbInfoId"
+            :defaultOpt="searchOptions"
+            @select="e => selectTargetHandle(e,item)"  
+            :filter="false"
+            style="max-width: 200px;"
+          />
+          <el-date-picker
+            v-model="item.endDate"
+            type="date"
+            value-format="yyyy-MM-dd"
+            disabled
+            style="width:140px;"
+            placeholder="最新日期"
+          />
+
+          <el-input
+            v-model="item.endValue"
+            style="width: 100px;"
+            disabled
+            placeholder="最新值"
+          />
+
+        </li>
+      </ul>
+
+      <div class="dialog-bot">
+        <el-button type="primary" style="margin-right: 20px" @click="saveHandle"
+          >保存</el-button
+        >
+        <el-button type="primary" plain @click="cancelHandle">取消</el-button>
+      </div>
+    </div>
+  </el-dialog>
+</template>
+<script>
+import { crossVarietyInterface } from '@/api/modules/chartRelevanceApi';
+import selectTarget from '@/views/chartRelevance_manage/components/selectTarget.vue';
+export default {
+  components: { selectTarget },
+  props: {
+    isShow: {
+      type: Boolean
+    },
+    info: {
+      type:  Object
+    },
+    varietyList: {
+      type: Array
+    }
+  },
+  watch: {
+    isShow(nval) {
+      if(!nval) return
+
+      this.getRelationList() 
+    }
+  },
+  data() {
+    return {
+      list: [],
+      searchOptions: []
+    }
+  },
+  methods:{
+    selectTargetHandle(e,item) {
+      if(!e){
+        item.edbName = '';
+        item.edbInfoId = '';
+        item.endDate = '';
+        item.endValue = '';
+        return
+      } 
+      const { EndDate,EndValue,EdbName,EdbInfoId } = e;
+      
+      item.edbName = EdbName;
+      item.edbInfoId = EdbInfoId;
+      item.endDate = EndDate;
+      item.endValue = EndValue;
+    },
+
+    /* 获取标签关联品种列表 */
+    async getRelationList() {
+      let res = await crossVarietyInterface.getTagRelation({ ChartTagId: this.info.id })
+      if(res.Ret!==200) return
+
+      let relationArr = res.Data.List || [];
+
+      this.list = this.varietyList.map(_ => {
+        let relationItem = relationArr.length ? relationArr.find(item => item.ChartVarietyId===_.ChartVarietyId) : undefined
+
+        return {
+          varietyName: _.ChartVarietyName,
+          varietyId: _.ChartVarietyId,
+          edbName: relationItem?relationItem.EdbName:'',
+          edbInfoId: relationItem?relationItem.EdbInfoId:0,
+          endDate: relationItem?relationItem.EndDate:'',
+          endValue: relationItem?relationItem.EndValue:''
+        }
+      })
+
+      this.searchOptions = this.list.map(_ => ({
+        EdbName: _.edbName,
+        EdbInfoId: _.edbInfoId
+      }))
+    },
+
+    /* 保存`` */
+    saveHandle: _.debounce(async function() {
+      let params = {
+        ChartTagId: this.info.id,
+        VarietyEdb: this.list.map(_ => ({
+          ChartVarietyId: _.varietyId,
+          EdbInfoId: _.edbInfoId
+        })).filter(_ => _.EdbInfoId)
+      }
+      let res = await crossVarietyInterface.setTagRelationVariety(params)
+
+      if(res.Ret!==200) return
+      this.$message.success('配置保存成功')
+      this.$emit('refresh')
+      this.cancelHandle()
+    },300),
+
+    cancelHandle() {
+      this.list = [];
+      this.searchOptions=[];
+      this.$emit('update:isShow',false)
+    }
+  },
+}
+</script>
+<style scoped lang='scss'>
+.dialog-min {
+  padding: 30px 0 50px;
+  .list-ul{
+    padding: 0 15px;
+    max-height: calc(100vh - 500px);
+    min-height: 300px;
+    overflow-y: auto;
+    .list-li {
+      display: flex;
+      align-items: center;
+      gap: 20px;
+      margin-bottom: 20px;
+      .variety-name {
+        /* margin-right: 20px; */
+        width: 100px;
+      }
+    }
+  }
+  .dialog-bot {
+    display: flex;
+    margin-top: 30px;
+    justify-content: center;
+  }
+}
+</style>
+<style lang="scss">
+  /* .tag-relation-dialog .el-dialog__body {
+    max-height: calc(100vh - 350px);
+    min-height: 300px;
+    overflow-y: auto;
+  } */
+</style>

+ 207 - 0
src/views/chartRelevance_manage/crossVarietyAnalysis/components/tagSetDialog.vue

@@ -0,0 +1,207 @@
+<template>
+  <el-dialog
+    :visible.sync="isShow"
+    :close-on-click-modal="false"
+    :modal-append-to-body="false"
+    :title="type==='tag'?'标签管理':'品种管理'"
+    @close="cancelHandle"
+    custom-class="dialog"
+    center
+    width="560px"
+    v-dialogDrag
+  >
+    <div class="dialog-min">
+      <el-input
+        v-model="searchTxt"
+        placeholder="请输入名称"
+        prefix-icon="el-icon-search"
+        size="medium"
+        clearable 
+        @input="inputVisible = false;"
+      />
+      <div class="tag-list">
+        <div
+          v-for="(item,index) in showList"
+          :key="item.id"
+          class="el-tag"
+          :style="item.isEdit&&'padding:0;border:none;'"
+          @dblclick="editTagOpen(item,index)"
+        >
+
+          <el-input
+            v-model="item.label"
+            v-if="item.isEdit"
+            class="input-edit"
+            :ref="`inputRef${index}`"
+            size="small"
+            @blur="editItemHandle(item)"
+          />
+          <span v-else>
+            {{ item.label }}
+            <el-popconfirm
+              :title="`是否确认删除该${type==='tag'?'标签':'品种'}`"
+              @onConfirm="closeItemHandle(item)"
+            >
+              <i
+                slot="reference"
+                class="el-tag__close el-icon-close" 
+              />
+                <!-- @click.stop="closeItemHandle(item)" -->
+            </el-popconfirm>
+          </span>
+        </div>
+
+        <el-input
+          class="input-edit"
+          v-if="inputVisible"
+          v-model="inputValue"
+          ref="saveTagInput"
+          size="small"
+          @blur="addNewTagHandle"
+        >
+        </el-input>
+        <el-button v-else size="small" @click="addNewItem">+ {{type==='tag'?'标签':'品种'}}</el-button>
+
+      </div>
+    </div>
+
+  </el-dialog>
+</template>
+<script>
+import { crossVarietyInterface } from '@/api/modules/chartRelevanceApi';
+export default {
+  props: {
+    isShow: {
+      type: Boolean
+    },
+    type: { //tag  variety
+      type: String
+    },
+    dataList: {
+      type: Array,
+      default: () => []
+    }
+  },
+  watch: {
+    isShow(nval) {
+      if(!nval) return
+      this.initData()
+    },
+
+    dataList(nval) {
+      this.initData();
+    }
+  },
+  computed: {
+    showList() {
+      return this.list.length ? this.list.filter(_ => _.label.includes(this.searchTxt)) : []
+    }
+  },
+  data() {
+    return {
+      searchTxt: '',
+      inputVisible: false,
+      inputValue: '',
+      list: []
+    }
+  },
+  mounted(){
+
+  },
+  methods:{
+    /* 关闭标签 */
+    closeItemHandle(item) {
+      this.delItem(item)
+    },
+
+    async delItem(item) {
+      let res = this.type==='tag' 
+        ? await crossVarietyInterface.tagDel({ChartTagId:item.id})
+        : await crossVarietyInterface.varietyDel({ChartVarietyId:item.id})
+
+      if(res.Ret !== 200) return
+      this.$message.success('删除成功')
+      
+      this.refreshData()
+    },
+
+    addNewItem() {
+      this.inputValue = '';
+      this.inputVisible = true;
+      this.$nextTick(_ => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+
+    /* 新增标签 */
+    async addNewTagHandle() {
+      this.inputVisible = false;
+      if(!this.inputValue) return
+
+      let res = this.type==='tag' 
+        ? await crossVarietyInterface.tagAdd({ TagName: this.inputValue})
+        : await crossVarietyInterface.varietyAdd({ VarietyName: this.inputValue})
+        
+      if(res.Ret!==200) return
+      this.refreshData()
+      
+    },
+
+    editTagOpen(item,index) {
+      this.$set(item,'isEdit',true)
+      this.$nextTick(_ => {
+        this.$refs[`inputRef${index}`][0].$refs.input.focus();
+      });
+    },
+
+    /* 编辑标签 */
+    async editItemHandle(item) {
+      if(item.label===item.ChartVarietyName || item.label===item.ChartTagName) {
+        item.isEdit = false;
+        return
+      }
+
+      let res = this.type==='tag' 
+        ? await crossVarietyInterface.tagEdit({ TagName: item.label,ChartTagId:item.id})
+        : await crossVarietyInterface.varietyEdit({ VarietyName: item.label,ChartVarietyId:item.id})
+      if(res.Ret !== 200) return
+
+      item.isEdit = false;
+      this.refreshData()
+    },
+
+    refreshData() {
+      this.searchTxt = ''
+      this.$emit('refresh')
+    },
+
+    initData() {
+      this.list = this.dataList.map(_ => ({
+        label: _.ChartTagName || _.ChartVarietyName,
+        id:  _.ChartTagId || _.ChartVarietyId,
+        ..._
+      }))
+    },
+
+    cancelHandle() {
+      this.searchTxt = '';
+      this.inputVisible = false;
+      this.$emit('update:isShow',false)
+    }
+  },
+}
+</script>
+<style scoped lang='scss'>
+.dialog-min {
+  padding: 0 0 60px;
+  .tag-list { 
+    margin-top: 30px;
+    display: flex;
+    flex-wrap: wrap;
+    gap: 15px;
+  }
+  .input-edit {
+    width: 100px;
+  }
+}
+</style>

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

@@ -0,0 +1,570 @@
+<template>
+	<div class=" pub-chart-box" 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 v-permission="permissionBtn.statisticPermission.crossVariety_addChart"
+							 type="primary" @click="goAddChart">添加图表</el-button>
+				</div>
+
+				<div class="search-cont">
+					<el-checkbox v-model="isShowMe"  
+						v-permission="permissionBtn.statisticPermission.crossVariety_onlyMine"
+						@change="() => { getTreeData();getPublicList() }">只看我的</el-checkbox>
+					<el-select
+						v-model="search_txt"
+						v-loadMore="searchLoad"
+						:filterable="!search_txt"
+						remote
+						clearable
+						placeholder="请输入图表名称"
+						style="width: 100%; margin-top: 20px"
+						:remote-method="searchHandle"
+						@click.native="inputFocusHandle"
+					>
+						<i slot="prefix" class="el-input__icon el-icon-search"></i>
+						<el-option
+							v-for="item in searchOptions"
+							:key="item.ChartInfoId"
+							:label="item.ChartName"
+							:value="item.ChartInfoId"
+						>
+						</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&&permissionBtn.isShowBtn('statisticPermission','crossVariety_classifyOpt_edit')"
+								@blur="changeValue(data)"
+							/>
+							<span
+								@dblclick.stop="handleDblClick(data)"
+								v-else
+								class="text_oneLine node_label"
+								:style="`width:${
+									(select_node === data.UniqueCode && node.Nodewidth) || ''
+								}`"
+							>
+								<span>{{ data.ChartClassifyName }}</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.ChartInfoId&&permissionBtn.isShowBtn('statisticPermission','crossVariety_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.ChartInfoId&&permissionBtn.isShowBtn('statisticPermission','crossVariety_classifyOpt_delete')"
+								/> -->
+							</span>
+						</span>
+					</el-tree>
+
+				</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="chart-detail-wrapper" v-if="chartInfo.ChartInfoId">
+					<el-row class="bottom-min">
+              <el-col
+                :span="21"
+                style="padding: 20px 0;"
+              >
+                <div class="chartEn-mark" v-show="chartInfo.IsEnChart" style="top: 0;left: 0;">En</div>
+                <div class="chart-show-cont"  v-if="!chartInfo.WarnMsg">
+                  <div class="chartWrapper" id="chartWrapper">
+                    <h2 class="chart-title">{{ chartInfo.ChartName }}</h2>
+                    <Chart 
+											:options="options"
+											minHeight="440px" 
+											height="500px"
+											ref="chartRef"
+										/>
+                  </div>
+                  <span class="chart-author">作者:{{ chartInfo.SysUserRealName}}</span>
+                </div>
+
+                <!-- 异常显示 -->
+                <p class="error-tip" style="min-height: 400px;" v-if="chartInfo.WarnMsg">{{chartInfo.WarnMsg}}</p>
+              </el-col>
+              <el-col :span="3" style="position: absolute;height: 100%;right: 0;">
+								<!-- 操作 -->
+								<chartHandlesWrap
+									:chartInfo="chartInfo"
+									:linkUrl="linkUrl"
+									@copyChartConfirm="copyChartConfirm"
+									@addMychartHandle="addMychartHandle"
+									@refreshHandle="refreshHandle"
+									@saveChartOtherHandle="saveChartOtherHandle"
+									@editChartHandle="editChartHandle"
+									@openEnNameDia="openEnNameDia"
+									@delChartHandle="delChartHandle"
+								/>
+              </el-col>
+          </el-row>
+
+					<!-- 指标列表 -->
+					<edbTableSection :tableData="tableData"/>
+
+				</div>
+				<!-- 列表 -->
+				<chartListWrap
+          v-else 
+          :total="chart_total"
+          :list="chartList" 
+          @loadMoreHandle="loadMoreHandle"
+          @detailShowHandle="detailShowHandle"
+          @addMychartHandle="addMychartHandle"
+          ref="chartListWrap"
+        />
+			</div>
+		</div>
+
+
+		<!-- 分类弹窗 -->
+		<classify-dia
+			:isOpenDialog.sync="classifyDia"
+			:title="dialog_title"
+			:form="classifyForm"
+			@successCallback="getTreeData"
+		/>
+
+		 <!-- 加入我的图库弹窗 -->
+    <addMyClassifyDia
+      :isAddMyDialog="isAddMyChart"
+      :add_id="add_chart_id"
+      :add_ids="add_ids"
+      @cancel="isAddMyChart = false"
+      @addSuccess="addMySuccess"
+    />
+
+		 <!-- 图表另存 -->
+    <SaveChartOther 
+      :show.sync="isShowSaveOther" 
+      fromType="chartsetting"
+			source="cross_variety"
+      :data="chartInfo"
+      @ensure="getTreeData"
+    />
+
+		<!-- 输入英文指标弹窗 -->
+		<set-en-name-dia 
+			:isOpenDialog="setEnName" 
+		  :formData="formItemArray"
+			@cancel="setEnName=false"
+   	  @updateEnName="updateEnName"
+		/>
+
+	</div>
+</template>
+
+<script>
+import { crossVarietyInterface } from '@/api/modules/chartRelevanceApi';
+import leftMixin from '../mixins/classifyMixin';
+import Chart from '@/views/dataEntry_manage/components/chart';
+import classifyDia from '@/views/datasheet_manage/components/sheetClassifyDia.vue';
+import addMyClassifyDia from '@/views/dataEntry_manage/components/addMyClassifyDia';
+import SaveChartOther from '@/views/dataEntry_manage/components/SaveChartOther';
+import setEnNameDia from '@/views/dataEntry_manage/components/setEnNameDia.vue'
+import { chartSetMixin } from '@/views/dataEntry_manage/mixins/chartPublic';
+import { copyOtherOptions } from '@/utils/defaultOptions';
+import edbTableSection from './components/edbTableSection.vue';
+export default {
+	components: {
+		classifyDia,
+		Chart,
+		addMyClassifyDia,
+		SaveChartOther,
+		setEnNameDia,
+		edbTableSection
+	},
+	mixins:[ leftMixin,chartSetMixin ],
+	computed: {
+		/* 分享地址 */
+    linkUrl() {
+      const LINK_CHART_URL = this.$setting.dynamicOutLinks.ChartViewUrl+'/chartshow';
+      return `${LINK_CHART_URL}?code=${this.chartInfo.UniqueCode}&fromType=share?&lang=${this.currentLang}`
+    }
+	},
+	data () {
+		return {
+			showData: false,
+			refreshLoading: false,
+			isShowMe: false,
+			search_txt: '',
+			searchOptions:[],
+			isSlideLeft: false,//左侧分类收起
+
+			select_node: '',//节点唯一标识code
+			select_classify: '',
+			new_label:'',//双击修改的value
+			treeData: [], //分类数据
+      defaultShowNodes: [], //展开节点
+      defaultProp: {
+        label: 'ChartClassifyName',
+        children: 'Children',
+      }, //树结构配置项
+			dynamicNode: null,
+
+			/* 分类弹窗 */
+			dialog_title:'',
+			classifyDia: false, //
+			classifyForm: {},
+
+			select_id: '',//选中的图表id
+			chartInfo: {},
+			chart_title:'',//图表标题 双击标题修改时来存储最新值
+
+			isAddMyChart: false, //加入图库弹窗
+      add_chart_id: 0, //要加入的图表
+			add_ids:[],//加入时已有的分类
+
+			/* 图表列表 */
+			publicHaveMove: true,//是否还有列表数据
+			chartList: [],
+			chart_total: 0,
+			chart_page: 1,
+			chart_pages_size: 16,
+
+			search_page: 1,
+			search_have_more: false,
+			current_search:'',
+		};
+	},
+	methods: {
+
+		/* 添加图表 */
+		goAddChart() {
+			this.$router.push({ path: '/crossVarietyChartEditor' });
+		},
+
+		/* 获取分类 */
+		getTreeData(params=null) {
+			crossVarietyInterface.classifyList({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) {
+			this.search_page = 1;
+			this.current_search = query;
+			this.searchApi(this.current_search)
+		},
+
+		searchApi(query,page=1) {
+      /* 查找列表 */
+      crossVarietyInterface
+        .searchChart({
+          Keyword: query,
+          IsShowMe:this.isShowMe,
+          CurrentIndex: page
+        })
+        .then((res) => {
+          if (res.Ret !== 200) return
+          const { List,Paging } = res.Data;
+          this.search_have_more = page < Paging.Pages;
+          this.searchOptions = page === 1 ? List : [...this.searchOptions,...List];
+        });
+		},
+
+		/* 聚焦获取当前检索 */
+		inputFocusHandle(e) {
+			this.search_page = 1;
+			this.current_search = e.target.value;
+      if(this.current_search) {
+        this.searchApi(this.current_search)
+      }else {
+        this.searchOptions = [];
+      }
+		},
+
+		searchLoad() {
+			if(!this.search_have_more) return;
+			this.searchApi(this.current_search,++this.search_page);
+		},
+
+		/* 选中分类变化时 */
+		nodeChange({ UniqueCode,ChartInfoId,ChartClassifyId },node) {
+			this.search_txt = '';
+			this.select_node = UniqueCode;
+			this.select_classify = !ChartInfoId ? ChartClassifyId : 0;
+			this.select_id = ChartInfoId || 0;
+			this.resetNodeStyle(node);
+			this.dynamicNode = node;
+		},
+
+
+    /* 编辑节点 */
+    editNode(node, { ChartClassifyName,ChartClassifyId }) {
+
+      this.dialog_title = '编辑图表分类';
+      /* 编辑目录 */
+      this.classifyForm = {
+        classify_name: ChartClassifyName,
+        classify_id: ChartClassifyId,
+      };
+      this.classifyDia = true;
+    },
+
+		 /* 删除方法 */
+    delApi(ChartInfoId) {
+      crossVarietyInterface.chartDel({
+				ChartInfoId
+			})
+      .then((res) => {
+				if (res.Ret !== 200) return
+				this.$message.success(res.Msg);
+
+				if (!res.Data.ChartInfoId) this.select_id = '';
+
+				//删除自动显示下一张
+				res.Data.ChartInfoId
+					? this.getTreeData({
+							code: res.Data.UniqueCode,
+							id: res.Data.ChartInfoId
+						})
+					: this.getTreeData();
+			});
+    },
+
+		/* 分类成功回调 */
+		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 = '';
+
+      }
+		},
+
+		/* 获取图表列表 */
+		getPublicList() {
+			crossVarietyInterface.getChartList({
+				CurrentIndex: this.chart_page,
+				PageSize: this.chart_pages_size,
+        ChartClassifyId: this.select_classify || 0,
+				IsShowMe: this.isShowMe
+			}).then(res => {
+				if(res.Ret !== 200) return
+
+				this.publicHaveMove = res.Data
+            ? this.chart_page < res.Data.Paging.Pages
+            : false;
+          this.chartList = res.Data
+            ? this.chart_page === 1
+              ? res.Data.List
+              : [...this.chartList, ...res.Data.List]
+            : [];
+        this.chart_total = res.Data ? res.Data.Paging.Totals : 0;
+			})
+		},
+
+		getChartInfo() {
+			this.getDetailHandle();
+		},
+
+		/* 获取图表详情 */
+		getDetailHandle() {
+			crossVarietyInterface.chartDetail({
+				ChartInfoId: this.select_id
+			}).then(res => {
+				if(res.Ret !== 200) return
+
+				const { ChartInfo,DataResp,EdbInfoList } = res.Data;
+
+				this.chartInfo = ChartInfo;
+				this.tableData = EdbInfoList;
+				this.crossVarietyChartData = DataResp;
+				this.chartLimit = {
+					min: DataResp.YMinValue,
+					max: DataResp.YMaxValue ,
+					x_min: DataResp.XMinValue,
+					x_max: DataResp.XMaxValue,
+				}
+
+				this.setCrossVarietyChart()
+			})
+		},
+
+		/* 删除图表 */
+		delChartHandle() {
+			const { ChartClassifyId,ChartInfoId } = this.chartInfo;
+			this.$confirm('删除后该图表将不能再引用,确认删除吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          this.delApi(ChartInfoId)
+        })
+        .catch(() => {});
+		},
+
+		/* 刷新图表 */
+		refreshHandle() {
+			this.refreshLoading = this.$loading({
+        lock: true,
+        target: '.main-right',
+        text: '刷新图表中...',
+        spinner: 'el-icon-loading',
+        background: 'rgba(255, 255, 255, 0.8)',
+      });
+      crossVarietyInterface.refreshChart({
+          ChartInfoId: this.chartInfo.ChartInfoId,
+      }).then((res) => {
+				this.refreshLoading.close();
+				if (res.Ret === 200) {
+					this.getDetailHandle();
+					this.$message.success(res.Msg);
+				}
+			});
+		},
+
+		/* 编辑图表 */
+		editChartHandle() {
+			this.$router.push({
+        path: '/crossVarietyChartEditor',
+        query: {
+          code: this.chartInfo.UniqueCode,
+					id: this.chartInfo.ChartInfoId
+        }
+      })
+		},
+
+		copyChartHandle:_.debounce(function(type){
+      let chartsName = this.currentLang=='ch'?this.chartInfo.ChartName:this.chartInfo.ChartNameEn
+      let { heightNum, widthNum , newTitle , dynamic_copyOptions} = this.dynamicWidthAndHeight(type,this.chartInfo.ChartType,chartsName,1)
+      const chartType = 'seasonLegend';
+      // 英文转SVG设置变动
+      if(this.currentLang == 'en'){
+        // 如果竖轴坐标单位为'英文单位',表示客户没填,转成svg时置为空
+        this.$refs.chartRef.chart.options.yAxis.forEach(it => {
+          if(it.title.text == '英文单位') it.title.text='' 
+        });
+      }
+      let svg = this.$refs.chartRef.chart.getSVG({
+        chart:{
+          width:widthNum,
+          height:heightNum,
+          backgroundColor:"rgba(255, 255, 255, 0)",
+        },
+        title: {
+          text: newTitle,
+          margin: 10,
+          style: {
+            fontSize: '18px'
+          }
+        },
+        legend:{
+          ...copyOtherOptions[chartType],
+          ...dynamic_copyOptions[chartType]
+          }
+      });
+      this.copyBlobItem(widthNum,heightNum,svg,type);
+    },500),
+    
+		handleDblClick(data){
+			if(!this.permissionBtn.isShowBtn('statisticPermission','crossVariety_classifyOpt_edit')) return 
+			this.editNodeLabel(data)
+		}
+	},
+	mounted() {
+
+		if(this.$route.query.code) {
+      this.getTreeData({code: this.$route.query.code,id: Number(this.$route.query.id)})
+    } else {
+      this.getTreeData();
+      this.getPublicList();
+    }
+
+		window.addEventListener('resize', this.reloadRightWid);
+	},
+	destroyed() {
+		window.removeEventListener('resize', this.reloadRightWid);
+	}
+}
+</script>
+<style lang='scss' scoped>
+@import '../css/index.scss';
+</style>
+
+<style lang="scss">
+@import '../css/pub.scss';
+</style>

+ 1 - 1
src/views/chartRelevance_manage/css/index.scss

@@ -136,7 +136,7 @@ $normal-font: 14px;
           margin-bottom: 20px;
           margin-bottom: 20px;
 
 
           .chart-show-cont {
           .chart-show-cont {
-            padding: 0 160px 0 120px;
+            padding: 0 160px 0 100px;
             position: relative;
             position: relative;
             min-height: 400px;
             min-height: 400px;
             .chart-title {
             .chart-title {

+ 4 - 4
src/views/chartRelevance_manage/fittingEquationChartEditor.vue → src/views/chartRelevance_manage/fittingEquation/fittingEquationChartEditor.vue

@@ -174,10 +174,10 @@
 import { fittingEquationInterface } from '@/api/modules/chartRelevanceApi';
 import { fittingEquationInterface } from '@/api/modules/chartRelevanceApi';
 import { yearSelector } from '@/utils/defaultOptions';
 import { yearSelector } from '@/utils/defaultOptions';
 import Chart from '@/views/dataEntry_manage/components/chart';
 import Chart from '@/views/dataEntry_manage/components/chart';
-import selectTarget from './components/selectTarget.vue';
-import fittingEquationSaveDia from './components/fittingEquationSaveDia.vue';
-import chartCard from './components/chartCard.vue';
-import ExplainDialog from './components/explainDialog.vue';
+import selectTarget from '../components/selectTarget.vue';
+import fittingEquationSaveDia from '../components/fittingEquationSaveDia.vue';
+import chartCard from '../components/chartCard.vue';
+import ExplainDialog from '../components/explainDialog.vue';
 export default {
 export default {
   components: { Chart,selectTarget,fittingEquationSaveDia,chartCard,ExplainDialog },
   components: { Chart,selectTarget,fittingEquationSaveDia,chartCard,ExplainDialog },
 	directives: {
 	directives: {

+ 3 - 3
src/views/chartRelevance_manage/fittingEquationList.vue → src/views/chartRelevance_manage/fittingEquation/fittingEquationList.vue

@@ -243,7 +243,7 @@
 
 
 <script>
 <script>
 import { fittingEquationInterface } from '@/api/modules/chartRelevanceApi';
 import { fittingEquationInterface } from '@/api/modules/chartRelevanceApi';
-import leftMixin from './mixins/classifyMixin';
+import leftMixin from '../mixins/classifyMixin';
 import Chart from '@/views/dataEntry_manage/components/chart';
 import Chart from '@/views/dataEntry_manage/components/chart';
 import changeLang from "@/views/dataEntry_manage/components/changeLang.vue"
 import changeLang from "@/views/dataEntry_manage/components/changeLang.vue"
 import classifyDia from '@/views/datasheet_manage/components/sheetClassifyDia.vue';
 import classifyDia from '@/views/datasheet_manage/components/sheetClassifyDia.vue';
@@ -634,9 +634,9 @@ export default {
 }
 }
 </script>
 </script>
 <style lang='scss' scoped>
 <style lang='scss' scoped>
-@import './css/index.scss';
+@import '../css/index.scss';
 </style>
 </style>
 
 
 <style lang="scss">
 <style lang="scss">
-@import './css/pub.scss';
+@import '../css/pub.scss';
 </style>
 </style>

+ 35 - 21
src/views/chartRelevance_manage/mixins/classifyMixin.js

@@ -1,5 +1,5 @@
 import chartRelevanceApi from '@/api/modules/chartRelevanceApi.js';
 import chartRelevanceApi from '@/api/modules/chartRelevanceApi.js';
-import { fittingEquationInterface,statisticFeatureInterface } from '@/api/modules/chartRelevanceApi';
+import { fittingEquationInterface,statisticFeatureInterface,crossVarietyInterface } from '@/api/modules/chartRelevanceApi';
 import { dataBaseInterface } from '@/api/api.js';
 import { dataBaseInterface } from '@/api/api.js';
 
 
 export default {
 export default {
@@ -117,7 +117,6 @@ export default {
     resetNodeStyle: _.debounce(function(node) {
     resetNodeStyle: _.debounce(function(node) {
 			const tree = $('.target_tree')[0];
 			const tree = $('.target_tree')[0];
 			let width = tree.offsetWidth;
 			let width = tree.offsetWidth;
-			// let label_wid = width > 500 ? 'auto' : (width <= 300 && width < 360) ?  100 : 0.7*width;
 			let label_wid =
 			let label_wid =
 				width > 500
 				width > 500
 					? 'auto'
 					? 'auto'
@@ -143,26 +142,34 @@ export default {
       if(!this.new_label) return this.$message.warning('名称不能为空');
       if(!this.new_label) return this.$message.warning('名称不能为空');
       this.$set(data,'isEdit',false)
       this.$set(data,'isEdit',false)
 
 
-      if(this.new_label !== data.ClassifyName) {
-        let res = this.$route.path === '/fittingEquationList'
-          ? await fittingEquationInterface.classifyEdit({
-              ChartClassifyId: data.ChartClassifyId,
-              ChartClassifyName: this.new_label
-            })
-          : this.$route.path === '/statisticFeatureList'
-          ? await statisticFeatureInterface.classifyEdit({
-              ChartClassifyId: data.ChartClassifyId,
-              ChartClassifyName: this.new_label
-            })
-          :await chartRelevanceApi.classifyEdit({
-              ChartClassifyId: data.ChartClassifyId,
-              ChartClassifyName: this.new_label
-            })
-
-        if(res.Ret !== 200) return
-  
-        this.getTreeData();
+      if(this.new_label === data.ClassifyName) return 
+      
+      let res;
+      if(this.$route.path === '/fittingEquationList') {
+        res = await fittingEquationInterface.classifyEdit({
+                ChartClassifyId: data.ChartClassifyId,
+                ChartClassifyName: this.new_label
+              })
+      }else if(this.$route.path === '/statisticFeatureList') {
+        res = await statisticFeatureInterface.classifyEdit({
+                ChartClassifyId: data.ChartClassifyId,
+                ChartClassifyName: this.new_label
+              })
+      }else if(this.$route.path === '/chartrelevance') {
+        res = await chartRelevanceApi.classifyEdit({
+                ChartClassifyId: data.ChartClassifyId,
+                ChartClassifyName: this.new_label
+              })
+      }else if(this.$route.path === '/crossVarietyChartList') {
+        res = await crossVarietyInterface.classifyEdit({
+          ChartClassifyId: data.ChartClassifyId,
+          ChartClassifyName: this.new_label
+        })
       }
       }
+
+      if(res.Ret !== 200) return
+
+      this.getTreeData();
     },
     },
 
 
     /* 拖拽完成 */
     /* 拖拽完成 */
@@ -214,6 +221,8 @@ export default {
         res=await fittingEquationInterface.classifyMove(params)
         res=await fittingEquationInterface.classifyMove(params)
       }else if(this.$route.path === '/statisticFeatureList') {
       }else if(this.$route.path === '/statisticFeatureList') {
         res=await statisticFeatureInterface.classifyMove(params)
         res=await statisticFeatureInterface.classifyMove(params)
+      }else if(this.$route.path === '/crossVarietyChartList') {
+        res=await crossVarietyInterface.classifyMove(params)
       }
       }
 
 
       if (res.Ret !== 200) return;
       if (res.Ret !== 200) return;
@@ -264,6 +273,8 @@ export default {
         res=await fittingEquationInterface.chartMove(params)
         res=await fittingEquationInterface.chartMove(params)
       }else if(this.$route.path === '/statisticFeatureList') {
       }else if(this.$route.path === '/statisticFeatureList') {
         res=await statisticFeatureInterface.chartMove(params)
         res=await statisticFeatureInterface.chartMove(params)
+      }else if(this.$route.path === '/crossVarietyChartList') {
+        res=await crossVarietyInterface.chartMove(params)
       }
       }
       
       
       if (res.Ret !== 200) return;
       if (res.Ret !== 200) return;
@@ -335,6 +346,9 @@ export default {
           (dropNode.level === 2 && type !== "inner")
           (dropNode.level === 2 && type !== "inner")
         ) {
         ) {
           canDrop = true;
           canDrop = true;
+          
+          //跨品种分析不允许跨分类拖
+          if(draggingNode.data.ChartClassifyId !== dropNode.data.ChartClassifyId)  canDrop = false;
         }
         }
       }
       }
 
 

+ 4 - 4
src/views/chartRelevance_manage/list.vue → src/views/chartRelevance_manage/relevance/list.vue

@@ -302,7 +302,7 @@
 
 
 <script>
 <script>
 import chartRelevanceApi from "@/api/modules/chartRelevanceApi.js";
 import chartRelevanceApi from "@/api/modules/chartRelevanceApi.js";
-import leftMixin from "./mixins/classifyMixin";
+import leftMixin from "../mixins/classifyMixin";
 import Chart from "@/views/dataEntry_manage/components/chart";
 import Chart from "@/views/dataEntry_manage/components/chart";
 import changeLang from "@/views/dataEntry_manage/components/changeLang.vue";
 import changeLang from "@/views/dataEntry_manage/components/changeLang.vue";
 import classifyDia from "@/views/datasheet_manage/components/sheetClassifyDia.vue";
 import classifyDia from "@/views/datasheet_manage/components/sheetClassifyDia.vue";
@@ -745,10 +745,10 @@ export default {
   },
   },
 };
 };
 </script>
 </script>
-<style lang='scss' scoped>
-@import './css/index.scss';
+<style lang="scss" scoped>
+@import '../css/index.scss';
 </style>
 </style>
 
 
 <style lang="scss">
 <style lang="scss">
-@import './css/pub.scss';
+@import '../css/pub.scss';
 </style>
 </style>

+ 5 - 5
src/views/chartRelevance_manage/relevanceChartEditor.vue → src/views/chartRelevance_manage/relevance/relevanceChartEditor.vue

@@ -373,12 +373,12 @@ import { dataBaseInterface } from '@/api/api.js';
 import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
 import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
 import {yearSelector} from '@/utils/defaultOptions';
 import {yearSelector} from '@/utils/defaultOptions';
 import chartRelevanceApi from '@/api/modules/chartRelevanceApi';
 import chartRelevanceApi from '@/api/modules/chartRelevanceApi';
-import selectTarget from './components/selectTarget.vue'
-import chartCard from './components/chartCard.vue';
+import selectTarget from '../components/selectTarget.vue'
+import chartCard from '../components/chartCard.vue';
 import SaveChartOther from '@/views/dataEntry_manage/components/SaveChartOther';
 import SaveChartOther from '@/views/dataEntry_manage/components/SaveChartOther';
-import saveChartToBase from './components/saveChartTobaseDia.vue';
-import saveEdbToBase from './components/saveEdbToBaseDia.vue'
-import ExplainDialog from './components/explainDialog.vue';
+import saveChartToBase from '../components/saveChartTobaseDia.vue';
+import saveEdbToBase from '../components/saveEdbToBaseDia.vue'
+import ExplainDialog from '../components/explainDialog.vue';
 export default {
 export default {
   components: { selectTarget, chartCard, SaveChartOther, saveChartToBase, saveEdbToBase, ExplainDialog },
   components: { selectTarget, chartCard, SaveChartOther, saveChartToBase, saveEdbToBase, ExplainDialog },
   directives: {
   directives: {

+ 5 - 5
src/views/chartRelevance_manage/statisticFeatureChartEditor.vue → src/views/chartRelevance_manage/statistic/statisticFeatureChartEditor.vue

@@ -289,12 +289,12 @@ import { dataBaseInterface } from '@/api/api.js';
 import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
 import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
 import {yearSelector} from '@/utils/defaultOptions';
 import {yearSelector} from '@/utils/defaultOptions';
 import {statisticFeatureInterface} from '@/api/modules/chartRelevanceApi';
 import {statisticFeatureInterface} from '@/api/modules/chartRelevanceApi';
-import selectTarget from './components/selectTarget.vue'
-import chartCard from './components/chartCard.vue';
+import selectTarget from '../components/selectTarget.vue'
+import chartCard from '../components/chartCard.vue';
 import SaveChartOther from '@/views/dataEntry_manage/components/SaveChartOther';
 import SaveChartOther from '@/views/dataEntry_manage/components/SaveChartOther';
-import saveChartToBase from './components/saveChartTobaseDia.vue';
-import saveEdbToBase from './components/saveEdbToBaseDia.vue';
-import ExplainDialog from './components/explainDialog.vue';
+import saveChartToBase from '../components/saveChartTobaseDia.vue';
+import saveEdbToBase from '../components/saveEdbToBaseDia.vue';
+import ExplainDialog from '../components/explainDialog.vue';
 export default {
 export default {
   components: { selectTarget,chartCard,SaveChartOther,saveChartToBase,saveEdbToBase,ExplainDialog },
   components: { selectTarget,chartCard,SaveChartOther,saveChartToBase,saveEdbToBase,ExplainDialog },
   directives: {
   directives: {

+ 3 - 3
src/views/chartRelevance_manage/statisticFeatureList.vue → src/views/chartRelevance_manage/statistic/statisticFeatureList.vue

@@ -229,7 +229,7 @@
 <script>
 <script>
 
 
 import { statisticFeatureInterface } from '@/api/modules/chartRelevanceApi';
 import { statisticFeatureInterface } from '@/api/modules/chartRelevanceApi';
-import leftMixin from './mixins/classifyMixin';
+import leftMixin from '../mixins/classifyMixin';
 import Chart from '@/views/dataEntry_manage/components/chart';
 import Chart from '@/views/dataEntry_manage/components/chart';
 import classifyDia from '@/views/datasheet_manage/components/sheetClassifyDia.vue';
 import classifyDia from '@/views/datasheet_manage/components/sheetClassifyDia.vue';
 import addMyClassifyDia from '@/views/dataEntry_manage/components/addMyClassifyDia';
 import addMyClassifyDia from '@/views/dataEntry_manage/components/addMyClassifyDia';
@@ -602,9 +602,9 @@ export default {
 }
 }
 </script>
 </script>
 <style lang='scss' scoped>
 <style lang='scss' scoped>
-@import './css/index.scss';
+@import '../css/index.scss';
 </style>
 </style>
 
 
 <style lang="scss">
 <style lang="scss">
-@import './css/pub.scss';
+@import '../css/pub.scss';
 </style>
 </style>

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

@@ -152,6 +152,7 @@
 					></el-date-picker>
 					></el-date-picker>
 					<el-checkbox label="跨年" v-model="isSpanYear" :disabled="isSpanYearDisable"
 					<el-checkbox label="跨年" v-model="isSpanYear" :disabled="isSpanYearDisable"
 					style="margin-top: 12px;" @change="changeIsSpanYear"></el-checkbox>
 					style="margin-top: 12px;" @change="changeIsSpanYear"></el-checkbox>
+					<br />
 					<div class="legend-set-text" @click="openLegendEditDia">
 					<div class="legend-set-text" @click="openLegendEditDia">
 						<span>图例名称设置</span>
 						<span>图例名称设置</span>
 						<img src="~@/assets/img/icons/edit-blue.png" />
 						<img src="~@/assets/img/icons/edit-blue.png" />
@@ -835,7 +836,7 @@ export default {
 				.legend-set-text{
 				.legend-set-text{
 					font-size: 15px;
 					font-size: 15px;
 					color: #1B7BDE;
 					color: #1B7BDE;
-					display: flex;
+					display: inline-flex;
 					align-items: center;
 					align-items: center;
 					justify-content: flex-start;
 					justify-content: flex-start;
 					margin-top: 20px;
 					margin-top: 20px;

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

@@ -2166,7 +2166,7 @@ export default {
         .then((res) => {
         .then((res) => {
           this.refreshLoading.close();
           this.refreshLoading.close();
           if (res.Ret === 200) {
           if (res.Ret === 200) {
-            this.getPreviewChartInfo();
+            [7,10].includes(this.chartInfo.ChartType) ? this.getChartDetail() : this.getPreviewChartInfo();
             this.$message.success(res.Msg);
             this.$message.success(res.Msg);
           }
           }
         });
         });

+ 8 - 2
src/views/dataEntry_manage/components/LegendEditDia.vue

@@ -48,8 +48,14 @@ data () {
   };
   };
 },
 },
 watch: {
 watch: {
-  isEditLegend(val) {
-    if(val) {
+  // isEditLegend(val) {
+  //   if(val) {
+  //     // 数据没加载出来时 打开弹窗 legendListCopy 会为空
+  //     this.legendListCopy = _.cloneDeep(this.legendList)
+  //   }
+  // },
+  legendList(val){
+    if(val){
       this.legendListCopy = _.cloneDeep(this.legendList)
       this.legendListCopy = _.cloneDeep(this.legendList)
     }
     }
   }
   }

+ 8 - 2
src/views/dataEntry_manage/components/SaveChartOther.vue

@@ -25,7 +25,7 @@
           clearable
           clearable
         />
         />
       </el-form-item>
       </el-form-item>
-      <el-form-item label="图表分类" prop="classify">
+      <el-form-item label="图表分类" prop="classify" v-if="![10,'cross_variety'].includes(this.source)">
         <el-cascader
         <el-cascader
           v-model="form.classify"
           v-model="form.classify"
           :options="classifyOptions"
           :options="classifyOptions"
@@ -53,7 +53,7 @@
 import { dataBaseInterface } from '@/api/api.js';
 import { dataBaseInterface } from '@/api/api.js';
 import futuresInterface from '@/api/modules/futuresBaseApi';
 import futuresInterface from '@/api/modules/futuresBaseApi';
 import chartRelevanceApi from '@/api/modules/chartRelevanceApi.js';
 import chartRelevanceApi from '@/api/modules/chartRelevanceApi.js';
-import { fittingEquationInterface,statisticFeatureInterface } from '@/api/modules/chartRelevanceApi';
+import { fittingEquationInterface,statisticFeatureInterface,crossVarietyInterface } from '@/api/modules/chartRelevanceApi';
 export default {
 export default {
   props: {
   props: {
     show: Boolean,
     show: Boolean,
@@ -114,6 +114,8 @@ export default {
         res=await fittingEquationInterface.classifyList()
         res=await fittingEquationInterface.classifyList()
       }else if([7,8,9,'statistic_feature'].includes(this.source)) { //标准差 百分位 频率图
       }else if([7,8,9,'statistic_feature'].includes(this.source)) { //标准差 百分位 频率图
         res=await statisticFeatureInterface.classifyList()
         res=await statisticFeatureInterface.classifyList()
+      }else if([10,'cross_variety'].includes(this.source)) { //跨品种分析
+        res = await crossVarietyInterface.classifyList();
       }else{
       }else{
         res=await dataBaseInterface.chartClassify();
         res=await dataBaseInterface.chartClassify();
       }
       }
@@ -128,6 +130,8 @@ export default {
         this.filterNodes(res.Data.AllNodes,1)
         this.filterNodes(res.Data.AllNodes,1)
       }else if([7,8,9,'statistic_feature'].includes(this.source)) { //标准差 百分位 频率图
       }else if([7,8,9,'statistic_feature'].includes(this.source)) { //标准差 百分位 频率图
         this.filterNodes(res.Data.AllNodes,1)
         this.filterNodes(res.Data.AllNodes,1)
+      }else if([10,'cross_variety'].includes(this.source)) { //
+        this.filterNodes(res.Data.AllNodes,1)
       }else{
       }else{
         this.filterNodes(res.Data.AllNodes,3)
         this.filterNodes(res.Data.AllNodes,3)
       }
       }
@@ -163,6 +167,8 @@ export default {
         res=await fittingEquationInterface.saveOtherChart(params)
         res=await fittingEquationInterface.saveOtherChart(params)
       }else if([7,8,9,'statistic_feature'].includes(this.source)) { //标准差 百分位 频率图
       }else if([7,8,9,'statistic_feature'].includes(this.source)) { //标准差 百分位 频率图
         res=await statisticFeatureInterface.saveOtherChart(params)
         res=await statisticFeatureInterface.saveOtherChart(params)
+      }else if([10,'cross_variety'].includes(this.source)) { //跨品种分析
+        res = await crossVarietyInterface.saveOtherChart(params);
       }else{
       }else{
         res=await dataBaseInterface.saveChartOther(params)
         res=await dataBaseInterface.saveChartOther(params)
       }
       }

+ 41 - 10
src/views/dataEntry_manage/components/addTarget.vue

@@ -15,16 +15,22 @@
 			<span style="fontSize:16px;">{{dialogTitle}}</span>
 			<span style="fontSize:16px;">{{dialogTitle}}</span>
 		</div>
 		</div>
 		<div class="dialog-min" style="height:460px;">
 		<div class="dialog-min" style="height:460px;">
-			<div style="overflowY:auto;overflowX:hidden;">
-				<el-tree
-				class="type-list"
-				:data="typeList"
-				accordion
-				highlight-current
-				:props="defaultProps" 
-				@node-click="chooseType"
-				style="width:140px;">
-				</el-tree>
+			<div class="left-cont">
+				<div style="overflowY:auto;overflowX:hidden;">
+					<el-tree
+					class="type-list"
+					:data="typeList"
+					accordion
+					highlight-current
+					:props="defaultProps" 
+					@node-click="chooseType"
+					style="width:140px;">
+					</el-tree>
+				</div>
+				<div class="data-authority-row" @click="dataAuthorityJump">
+					<img src="~@/assets/img/icons/add_blue_new.png" /> 
+					<span>添加手工指标分类</span>
+				</div>
 			</div>
 			</div>
 			<div class="rigth-cont">
 			<div class="rigth-cont">
 				<el-form
 				<el-form
@@ -377,6 +383,10 @@ import {dataInterence} from 'api/api.js';
 					this.classify_id = item.ClassifyId;
 					this.classify_id = item.ClassifyId;
 				}
 				}
 			},
 			},
+			// 手工数据权限页面跳转
+			dataAuthorityJump(){
+				this.$router.push('Sysdatauth')
+			}
 		},
 		},
 		created() {
 		created() {
 			// this.getTargetlist();
 			// this.getTargetlist();
@@ -393,6 +403,27 @@ import {dataInterence} from 'api/api.js';
 .dialog_container {
 .dialog_container {
 	.dialog-min {
 	.dialog-min {
 		display: flex;
 		display: flex;
+		.left-cont{
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+			padding-bottom: 15px;
+			.data-authority-row{
+				margin-top: 10px;
+				display: inline-flex;
+				align-items: center;
+				cursor: pointer;
+				img{
+					margin-right: 6px;
+					height: 17px;
+					width: 17px;
+				}
+				span{
+					color: #1146DB;
+					font-size: 12px;
+				}
+			}
+		}
 		.rigth-cont {
 		.rigth-cont {
 			border-left: 1px solid #dcdcdc;
 			border-left: 1px solid #dcdcdc;
 			padding:  0 0 48px 60px;
 			padding:  0 0 48px 60px;

+ 7 - 1
src/views/dataEntry_manage/components/insertData.vue

@@ -138,7 +138,13 @@ export default {
     },
     },
     // 上传成功之后
     // 上传成功之后
     handleSuccess(result) {
     handleSuccess(result) {
-      let res = this.$parseData(result);
+      //兼容下结构
+      let res = this.$parseData({
+        headers: {
+          dk: sessionStorage.getItem('dk')||""
+        },
+        data: result
+      });
       if (res.Ret === 200) {
       if (res.Ret === 200) {
         // 0成功 1部分失败 -1全部失败
         // 0成功 1部分失败 -1全部失败
         let str = `
         let str = `

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff