Browse Source

Merge branch 'gn2.2'

cldu 19 hours ago
parent
commit
57fbd89cfb
29 changed files with 2930 additions and 98 deletions
  1. 1 0
      package.json
  2. 8 1
      src/api/modules/BIBoard.js
  3. 10 0
      src/api/modules/knowledge.js
  4. BIN
      src/assets/img/data_m/bi_konw_delete.png
  5. BIN
      src/assets/img/data_m/white_delete_icon.png
  6. BIN
      src/assets/img/smartReport/know-resource-icon.png
  7. 5 0
      src/utils/buttonConfig.js
  8. 217 54
      src/views/BI_manage/components/BoardContent.vue
  9. 109 8
      src/views/BI_manage/components/ChartBox.vue
  10. 228 0
      src/views/BI_manage/components/KnowBox.vue
  11. 12 1
      src/views/BI_manage/components/SelectChart.vue
  12. 518 0
      src/views/BI_manage/components/SelectKnow.vue
  13. 12 1
      src/views/BI_manage/components/SelectTable.vue
  14. 50 3
      src/views/BI_manage/components/TableBox.vue
  15. 130 9
      src/views/BI_manage/editBoard.vue
  16. 26 1
      src/views/BI_manage/index.vue
  17. 22 3
      src/views/approve_manage/approveDetail.vue
  18. 18 1
      src/views/home_manage/index.vue
  19. 4 0
      src/views/knowledge_manage/list.vue
  20. 440 0
      src/views/ppt_manage/newVersion/components/editor/InsertKnowledge.vue
  21. 2 1
      src/views/ppt_manage/newVersion/components/formatEl/TextEl.vue
  22. 39 1
      src/views/ppt_manage/newVersion/pptEditor.vue
  23. 481 0
      src/views/report_manage/reportV2/normalReport/components/KnowResource.vue
  24. 5 1
      src/views/report_manage/reportV2/normalReport/components/insertContent.vue
  25. 7 2
      src/views/report_manage/reportV2/normalReport/editReport.vue
  26. 23 1
      src/views/report_manage/reportV2/normalReport/mixins/reportMixin.js
  27. 501 0
      src/views/report_manage/reportV2/smartReport/components/KnowResource.vue
  28. 20 0
      src/views/report_manage/reportV2/smartReport/components/KnowResourceComp.vue
  29. 42 10
      src/views/report_manage/reportV2/smartReport/editReport.vue

+ 1 - 0
package.json

@@ -58,6 +58,7 @@
     "vue-drag-resize": "^1.5.4",
     "vue-froala-wysiwyg": "^3.1.0",
     "vue-giant-tree": "^1.0.0",
+    "vue-grid-layout": "2.3.7",
     "vue-i18n": "^8.28.2",
     "vue-masonry": "^0.16.0",
     "vue-pdf": "^4.2.0",

+ 8 - 1
src/api/modules/BIBoard.js

@@ -91,7 +91,14 @@ export default{
   setHomePageBoard:params=>{
     return http.post('/bi_dashborad/home_page/save',params)
   },
-
+  //保存知识资源引用
+  saveKnowledge:params=>{
+    return http.post('/knowledge/resource/bi_dashboard/save',params)
+  },
+  //获取知识资源引用
+  getKnowledge:params=>{
+    return http.get('/knowledge/resource/bi_dashboard/list',params)
+  },
 
   
 }

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

@@ -74,6 +74,16 @@ export const eventInterface = {
     return http.get("/knowledge/resource/list",params)
   },
 
+  /**
+   * 事件列表
+   * @param {*} params 
+   * PageSize CurrentIndex ClassifyIds SysUserIds TagIds Keyword
+   * @returns 
+   */
+  getEventListByES: params => {
+    return http.get("/knowledge/resource/search_by_es",params)
+  },
+
   /**
    * 新建事件
    * @param {*} params 

BIN
src/assets/img/data_m/bi_konw_delete.png


BIN
src/assets/img/data_m/white_delete_icon.png


BIN
src/assets/img/smartReport/know-resource-icon.png


+ 5 - 0
src/utils/buttonConfig.js

@@ -897,6 +897,7 @@ export const knowledgePermission = {
     event_tagEdit: 'event:tagEdit',//标签管理
     event_edit: 'event:edit',
     event_del: 'event:del',
+    event_view: 'event:view',
 
     //政策库
     policy_add: 'policy:add',
@@ -905,6 +906,7 @@ export const knowledgePermission = {
     policy_tagEdit: 'policy:tagEdit',
     policy_edit: 'policy:edit',
     policy_del: 'policy:del',
+    policy_view: 'policy:view',
 
     //观点库
     viewpoint_add: 'viewpoint:add',
@@ -913,6 +915,7 @@ export const knowledgePermission = {
     viewpoint_tagEdit: 'viewpoint:tagEdit',
     viewpoint_edit: 'viewpoint:edit',
     viewpoint_del: 'viewpoint:del',
+    viewpoint_view: 'viewpoint:view',
 
     //知识库
     know_add: 'know:add',
@@ -921,6 +924,7 @@ export const knowledgePermission = {
     know_tagEdit: 'know:tagEdit',
     know_edit: 'know:edit',
     know_del: 'know:del',
+    know_view: 'know:view',
 }
 
 
@@ -934,6 +938,7 @@ export const BIBoardPermission = {
     BIBoard_delete:'BI:delete',//
     BIBoard_refresh:'BI:refresh',//
     BIBoard_sort:'BI:sort',//
+    BIBoard_view:'BI:view',//bi看板查看数据
 }
 
 /* 首页配置 */

+ 217 - 54
src/views/BI_manage/components/BoardContent.vue

@@ -1,33 +1,50 @@
 <template>
   <div class="BI-board-content">
     <div class="BI-board-list" :style="{height:renderHeight}">
-      <table-no-data v-if="value.length===0" style="flex:1"/>
-      <div
-        class="BI-board-item-box"
-        v-for="(item, index) in value"
-        :key="item.BiDashboardDetailId"
-        @dragover.prevent
-        @drop="drop(index)"
-      >
-        <component :is="getCompType(item.Type)" :compData="item">
-          <template v-slot:drag>
-            <!-- Draggable icon -->
-            <img
-              v-if="canDrag"
-              class="icon"
-              src="~@/assets/img/data_m/move_ico.png"
-              alt=""
-              @mousedown="setDraggable(true, index)"
-              @dragstart="dragStart(index)"
-              @dragend="setDraggable(false, index)"
-              style="cursor: move"
-            />
-          </template>
-          <template v-slot:delete>
-            <img class="icon" v-if="canDelete" src="~@/assets/img/icons/delete-red.png" alt="" @click="handleDel(index)"/>
-          </template>
-        </component>
-      </div>
+      <table-no-data v-if="dataList.length===0" style="flex:1"/>
+      <grid-layout :layout.sync="dataList"
+          :col-num="layout.colNum"
+          :rowHeight="layout.rowHeight"
+          :is-draggable="canDrag"
+          :is-resizable="canDrag"
+          :vertical-compact="true"
+          :use-css-transforms="true"
+          :margin="layout.margin"
+          > 
+          <grid-item v-for="(item) in dataList"
+              :key="item.i" 
+              :x="item.x"
+              :y="item.y"
+              :w="item.w"
+              :h="item.h"
+              :i="item.i"
+              drag-allow-from=".vue-draggable-handle"
+              @resized="resizedEvent"
+              @moved="movedEvent"
+          >
+              <component 
+                :is="getCompType(item.Type)" 
+                :compData="item" 
+                :knowList="knowList"
+                :ref="'item' + item.i"
+                :canDelete="canDelete"
+                @deleteKnowledge="deleteKnowledge($event,item)"
+                @deleteKnowledgeType="deleteKnowledgeType($event,item)">
+                <template v-slot:drag>
+                  <img
+                    v-if="canDrag"
+                    class="icon vue-draggable-handle"
+                    src="~@/assets/img/data_m/move_ico.png"
+                    alt=""
+                    style="cursor: move"
+                  />
+                </template>
+                <template v-slot:delete>
+                  <img class="icon" v-if="canDelete" src="~@/assets/img/icons/delete-red.png" alt="" @click="handleDel(item)"/>
+                </template>
+              </component>
+          </grid-item>
+      </grid-layout>
     </div>
   </div>
 </template>
@@ -37,9 +54,12 @@ import apiBiBoard from '@/api/modules/BIBoard.js'
 import TableNoData from '../../../components/tableNoData.vue';
 import ChartBox from './ChartBox.vue';
 import TableBox from './TableBox.vue';
+import KnowBox from './KnowBox.vue';
+import { GridLayout, GridItem } from "vue-grid-layout";
+import {createRandomCode} from '@/views/ppt_manage/newVersion/utils/untils';
 
 export default {
-  components: { ChartBox, TableBox, TableNoData },
+  components: { ChartBox, TableBox, TableNoData, GridLayout, GridItem, KnowBox },
   props: {
     value: {
       type: Array,
@@ -57,37 +77,178 @@ export default {
     renderHeight:{
       type:String,
       default:"calc(100vh - 300px)"
-    }
+    },
+    knowList:{//知识资源列表
+      type:Array,
+      default: () => []
+    },
+  },
+  watch:{
+    value(newval){
+      const { wItem , hItem , colNum } = this.layout;
+      let itemList = _.cloneDeep(newval) || [];
+      itemList.map((item,index) => {
+          if(!item.Conf){ //旧数据
+            item.w = wItem;
+            item.h = hItem;
+            item.x = wItem * (index % (colNum / wItem));
+            item.y = hItem * Math.floor(index / (colNum / wItem));
+            item.i = `${item.UniqueCode}_${createRandomCode()}_${index}`;
+          } else {
+            let conf = JSON.parse(item.Conf)
+            item.w = conf.w;
+            item.h = conf.h;
+            item.x = conf.x;
+            item.y = conf.y;
+            item.i = `${item.UniqueCode}_${createRandomCode()}_${index}`
+          }
+      });
+      this.dataList = itemList;
+    },
+    dataList(newval){ 
+      let list = this.knowList || [];
+      this.$emit('update:knowList',list);//处理插件拖拽重新渲染知识资源列表不展示
+      this.setFirstKnow()
+      this.$nextTick(() => {
+        this.$emit('checkDataList',newval);//grid-layout对x.y进行处理之后数据发生变化  同步给编辑页面
+      })
+    },
   },
   data() {
     return {
       draggedIndex: null,
+      dataList:[], //看板列表
+      layout:{
+         colNum:12,
+         rowHeight:96,
+         margin:[20,20],
+         wItem:3,
+         hItem:4,
+      },
+      typeWidth:{ //不同种类的占位宽度
+         1:3,
+         2:3,
+         3:6,
+      },
     };
   },
   methods: {
+    getAddMessage(arr){ //获取添加内容的位置信息
+       if(!arr || !arr.length) return;
+       let d = _.cloneDeep(this.dataList) || [];
+       let result  = [];
+      arr.map((item) => {  //位置只与最后一个元素的位置有关
+          let yMax = d.length ? Math.max.apply(null,d.map(_=>_.y)) : 0;
+          let yMaxItems = d.length ? d.filter(_=>_.y == yMax) : [];
+
+          let xMax = d.length ? Math.max.apply(null,yMaxItems.map(_=>_.x)) : 0;
+          let hMax = d.length ? Math.max.apply(null,yMaxItems.map(_=>_.h)) : 0;
+          let lastTag = d.length ? d.find(_=>_.y == yMax &&_.x == xMax) : null;
+          let y =d.length ? (this.layout.colNum - xMax - lastTag.w >= this.typeWidth[item.Type] ? yMax : yMax + hMax) : 0;
+          let x =d.length ? (this.layout.colNum - xMax - lastTag.w >= this.typeWidth[item.Type] ? xMax + lastTag.w : 0) : 0;
+
+          let configs = {
+            x,
+            y,
+            w:this.typeWidth[item.Type],
+            h:this.layout.hItem,
+            i:`${item.UniqueCode}_${createRandomCode()}_${d.length}`
+          };
+          let i = {...item,...configs,Conf:JSON.stringify(configs)};
+          d.push(i);
+          result.push(i);
+      })
+       return result;
+    },
+    resizedEvent(i){
+      // this.$refs[`item${i}`] && this.$refs[`item${i}`][0] && this.$refs[`item${i}`][0].handleResize && this.$refs[`item${i}`][0].handleResize();
+      this.handleChangeDataList();
+    },
+    movedEvent(){
+      this.handleChangeDataList();
+    },
     getCompType(type) {
-      return type === 1 ? ChartBox : TableBox;
+      return type === 1 ? ChartBox : type === 2 ? TableBox : KnowBox;
+    },
+    handleDel(item){
+      if(item.Type == 3) {
+        this.deleteKnowBox(item)
+      };
+      let index = this.dataList.findIndex(_=>_.BiDashboardDetailId == item.BiDashboardDetailId);
+      this.dataList.splice(index,1);
+      this.handleChangeDataList();
+      this.$emit('delete',this.dataList)
     },
-    handleDel(index){
-      this.value.splice(index,1)
-      this.$emit('delete',this.value)
+    handleChangeDataList(){
+      this.dataList.map(item=>{
+        let configs = {
+          w : item.w,
+          h : item.h,
+          x : item.x,
+          y : item.y,
+          i : item.i,
+        }
+        item.Conf = JSON.stringify(configs);
+      });
+      this.$emit('input',this.dataList)
     },
-    setDraggable(draggable, index) {
-      const box = this.$el.querySelectorAll('.BI-board-item-box')[index];
-      box.draggable = draggable;
+    deleteKnowBox(v){
+      this.$emit('update:knowList',[]);
+      apiBiBoard.saveKnowledge({
+          BiDashboardDetailId:v ? (/^selfId_\d+$/.test(v.BiDashboardDetailId) ? 0 : v.BiDashboardDetailId) : 0,
+          KnowledgeResourceList:[]
+      });
     },
-    dragStart(index) {
-      this.draggedIndex = index;
+    async deleteKnowledgeType(item,v){
+      let { type } = item;
+      let knowList = this.knowList.filter(_=>_.ResourceType != type);
+      let res = await apiBiBoard.saveKnowledge({
+          BiDashboardDetailId:v ? (/^selfId_\d+$/.test(v.BiDashboardDetailId) ? 0 : v.BiDashboardDetailId) : 0,
+          KnowledgeResourceList:knowList.map(_=>({
+            ResourceType:_.ResourceType,
+            KnowledgeResourceId:_.KnowledgeResourceId
+          }))
+        });
+      if(res.Ret != 200) return this.$message.warning('删除失败,请重试');
+      this.knowList = knowList;
+      if(!this.knowList.length){ //清空掉知识资源
+        this.dataList = this.dataList.filter(_=>_.Type != 3);
+        this.$emit('input',this.dataList)
+      }
+      this.setFirstKnow();
     },
-    async drop(index) {
-      if (this.draggedIndex === null) return
-      // Swap the two items
-      const temp=this.value[this.draggedIndex]
-      this.$set(this.value, this.draggedIndex, this.value[index]);
-      this.$set(this.value, index, temp);
-      this.draggedIndex = null;
-      this.$emit('input',this.value)
-      this.$emit('change',this.value)
+    async deleteKnowledge(item,v){
+      let index = this.knowList.findIndex(_=>_.KnowledgeResourceId == item.KnowledgeResourceId && _.ResourceType == item.ResourceType)
+      if(index >= 0){
+        let knowList = _.cloneDeep(this.knowList);
+        knowList.splice(index,1)
+        let r = await apiBiBoard.saveKnowledge({
+          BiDashboardDetailId:v ? (/^selfId_\d+$/.test(v.BiDashboardDetailId) ? 0 : v.BiDashboardDetailId) : 0,
+          KnowledgeResourceList:knowList.map(_=>({
+            ResourceType:_.ResourceType,
+            KnowledgeResourceId:_.KnowledgeResourceId
+          }))
+        });
+        if(r.Ret != 200) return this.$message.warning('删除失败,请重试')
+
+        this.knowList.splice(index,1);
+        this.$emit('update:knowList',this.knowList)
+
+        //当前删除后为当前种类为空时
+        let nowTypeKnows = this.knowList.filter(_=>_.ResourceType == item.ResourceType);
+        if(!nowTypeKnows.length) this.setFirstKnow();
+      }
+      if(!this.knowList.length){ //清空掉知识资源
+        this.dataList = this.dataList.filter(_=>_.Type != 3);
+        this.$emit('input',this.dataList)
+      }
+    },
+    setFirstKnow(){
+      this.$nextTick(() => {
+        let v = this.dataList.find(_=>_.Type == 3); //寻找唯一的知识资源库类型
+        if(!v) return;
+        this.$refs[`item${v.i}`] && this.$refs[`item${v.i}`][0] && this.$refs[`item${v.i}`][0].setFirstKnow && this.$refs[`item${v.i}`][0].setFirstKnow();
+      });
     },
   }
 };
@@ -95,19 +256,21 @@ export default {
 
 <style lang="scss" scoped>
 .BI-board-content {
-  padding: 20px;
+  // padding: 20px;
   .BI-board-list {
     height: calc(100vh - 300px);
     overflow-y: auto;
     display: flex;
     flex-wrap: wrap;
     gap: 20px;
-    .BI-board-item-box {
-      width: calc(50% - 14px);
-      height: 560px;
-      border: 1px solid #dcdfe6;
-      box-shadow: 0px 2px 8px 0px #00000014;
+    .vue-grid-layout {
+        width: 100%;
+    }
+    .vue-grid-item {
+        overflow: hidden;
+        border: 1px solid #dcdfe6;
+        box-shadow: 0px 2px 8px 0px #00000014;
     }
   }
 }
-</style>
+</style>

+ 109 - 8
src/views/BI_manage/components/ChartBox.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="chart-box" v-if="compData" ref="compRef" v-loading="loading" element-loading-text="拼命加载中">
     <div class="top-title-box">
-      <div class="title" @click="goDetail">{{ chartInfo&&chartInfo.ChartName }}</div>
+      <div class="title">{{ chartInfo&&chartInfo.ChartName }}</div>
       <div class="opt-box">
         <img
           class="icon"
@@ -10,23 +10,69 @@
           v-permission="permissionBtn.BIBoardPermission.BIBoard_refresh"
           @click="refreshHandle"
         />
-        <slot name="drag"></slot>
         <slot name="delete"></slot>
+        <slot name="drag"></slot>
       </div>
     </div>
     <!-- 无权限 -->
     <div class="nodata" v-if="chartInfo.HaveOperaAuth === false">
       <noDataAuth :text="$t('MsgPrompt.no_chart_auth')" />
     </div>
-    <div class="chart-render-wrap" v-else>
+    <div class="chart-render-wrap" @click="goDetail" v-else>
       <Chart
-        minHeight="480px"
-        height="480px"
+        v-if="showChart"
+        minHeight="100%"
+        height="100%"
         :options="options"
         :chartInfo="chartInfo"
         :index="compData.BiDashboardDetailId"
       />
     </div>
+    <div class="bottom-tip">
+        <div v-if="showSourceFrom" :style="`width: ${getWidth('source')};`">
+          <el-tooltip
+            placement="top"
+            v-tooltipHidable
+          >
+            <div slot="content" class="tooltip-maxwidth-bi">{{ JSON.parse(chartInfo.SourcesFrom).text }}</div>
+            <div
+                class="bottom-overflow"
+                ref="sourceRef"
+                :style="`
+                        color: ${
+                          JSON.parse(chartInfo.SourcesFrom).isShow
+                            ? JSON.parse(chartInfo.SourcesFrom).color || '#999'
+                            : '#999'
+                        };
+                        fontSize: ${
+                          JSON.parse(chartInfo.SourcesFrom).fontSize || 14
+                        }px;
+                        width:100%;
+                      `"
+                ><!-- 来源 -->{{ $t("Chart.Detail.source") }}:{{
+                  JSON.parse(chartInfo.SourcesFrom).text
+                }}
+            </div>
+          </el-tooltip>
+        </div>
+       <div v-if="showInstruction" :style="`width: ${getWidth('instruction')};`">
+        <el-tooltip
+            placement="top"
+            v-tooltipHidable
+          >
+          <div slot="content" class="tooltip-maxwidth-bi">{{ JSON.parse(chartInfo.Instructions).text }}</div>
+          <div
+            class="chart-instruction bottom-overflow"
+            v-text="JSON.parse(chartInfo.Instructions).text"
+            :style="`
+                color: ${JSON.parse(chartInfo.Instructions).color};
+                fontSize: ${JSON.parse(chartInfo.Instructions).fontSize}px;
+                width:100%;
+              `"
+          ></div>
+        </el-tooltip>
+       </div>
+    </div>
   </div>
 </template>
 
@@ -37,6 +83,7 @@ import { dataBaseInterface } from '@/api/api.js';
 import chartRelevanceApi from '@/api/modules/chartRelevanceApi';
 import apiIntervalAnalysis from '@/api/modules/intervalAnalysis'
 import { fittingEquationInterface,statisticFeatureInterface,crossVarietyInterface } from '@/api/modules/chartRelevanceApi';
+import tooltipHidable from "@/directives/tooltip-hidable.js"
 export default {
   components: { Chart },
   mixins: [chartSetMixin],
@@ -51,12 +98,21 @@ export default {
       deep: true,
     },
   },
+  directives:{tooltipHidable},
+  computed:{
+     showSourceFrom(){
+      return this.chartInfo && this.chartInfo.SourcesFrom && JSON.parse(this.chartInfo.SourcesFrom).isShow
+     },
+     showInstruction(){
+      return this.chartInfo && this.chartInfo.Instructions && JSON.parse(this.chartInfo.Instructions).isShow
+     },
+  },
   data() {
     return {
       loading: true,
       observer: null,
       isVisible: false, // 是否可见
-
+      showChart: true,
       chartInfo: {},
     }
   },
@@ -70,6 +126,21 @@ export default {
     }
   },
   methods: {
+    getWidth(type){
+      let w = '50%';
+      if(type == 'source'){
+        w = this.showSourceFrom ?  (this.showInstruction ? '35%' : '100%') : 0
+      } else {
+        w = this.showInstruction ?  (this.showSourceFrom ? '60%' : '100%') : 0
+      }
+      return w
+    },
+    handleResize(){
+      this.showChart = false;
+      this.$nextTick(()=>{
+        this.showChart = true;
+      })
+    },
     /* 一键刷新 超长等待..*/
     async refreshHandle() {
       // 清除缓存配置项
@@ -98,7 +169,12 @@ export default {
       this.handleGetChartData()
     },
 
-    goDetail() {
+    goDetail(e) {
+      // 判断点击的部分是不是图例,图例不进行跳转
+      let target = e.target;
+      const legendItem = target.closest('.highcharts-legend-item');
+      if(legendItem) return;
+      
       const pathMap = new Map([
         [1, '/chartsetting'],
         [3, '/chartrelevance'],
@@ -257,7 +333,7 @@ export default {
   flex-direction: column;
   .top-title-box {
     display: flex;
-    margin-bottom: 10px;
+    margin-bottom: 4px;
     .title {
       font-size: 20px;
       font-weight: bold;
@@ -290,8 +366,33 @@ export default {
     }
   }
   .chart-render-wrap {
+    cursor: pointer;
     width: 100%;
     flex: 1;
+    overflow: auto;
   }
+  .bottom-tip{
+    width: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    flex-wrap: nowrap;
+  
+    .bottom-overflow{
+      white-space: nowrap;      
+      overflow: hidden;        
+      text-overflow: ellipsis;  
+    };
+    .chart-instruction{
+      text-align: right;
+    }
+  }
+}
+</style>
+<style lang="scss">
+.tooltip-maxwidth-bi{
+    max-width: 500px; 
+    white-space: normal; 
+    word-break: break-word;
 }
 </style>

+ 228 - 0
src/views/BI_manage/components/KnowBox.vue

@@ -0,0 +1,228 @@
+<template>
+  <div class="know-box" v-if="compData" ref="compRef">
+    <div class="top-title-box min-width">
+      <div class="title">知识资源</div>
+      <div class="types">
+        <div
+          v-for="(item, index) in knowledgeTypes"
+          :key="item.type"
+          class="type-item"
+          :class="{ 'type-item-in': choosedType == item.type }"
+          @click="changeType(item, index)"
+        >
+          {{ item.title }}
+          <img
+            v-if="canDelete && choosedType == item.type"
+            src="~@/assets/img/data_m/white_delete_icon.png"
+            alt=""
+            style="width: 20px;height: 20px;margin-left: 4px;cursor: default;"
+            @click.stop="deleteType(item)"
+          />
+        </div>
+      </div>
+      <div class="icons">
+        <slot name="delete"></slot>
+        <slot name="drag"></slot>
+      </div>
+    </div>
+    <div class="list-wrap min-width">
+      <div
+        v-for="item in showKnowList"
+        :key="item.KnowledgeResourceId"
+        class="item"
+      >
+        <div class="item-time" @click="go2Detail(item)">{{ item.StartTime }}</div>
+        <div class="item-title" @click="go2Detail(item)">
+          <div class="rect"></div>
+          <div class="title">
+            {{ item.Title }}
+          </div>
+        </div>
+        <img
+          v-if="canDelete"
+          src="~@/assets/img/data_m/bi_konw_delete.png"
+          alt=""
+          @click.stop="deleteItem(item)"
+          style="width: 15px; vertical-align: middle; margin-left: 20px;cursor: pointer;"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+const knowTypes = [
+  { type: 0, title: "事件库" },
+  { type: 1, title: "政策库" },
+  { type: 2, title: "报告库" },
+  { type: 3, title: "知识库" },
+];
+export default {
+  props: {
+    compData: null,
+    knowList: {
+      type: Array,
+      default: [],
+    },
+    canDelete:{
+      type:Boolean,
+      default:false
+    }
+  },
+  computed:{
+    knowledgeTypes(){
+      let type = [];
+      knowTypes.map(v=>{
+         if(this.knowList.some(_=>_.ResourceType == v.type)){
+           type.push(v)
+         }
+      });
+      return type || [];
+    },
+    showKnowList(){
+      return this.knowList.filter(_=>_.ResourceType == this.choosedType) || [];
+    },
+  },
+  data() {
+    return {
+      choosedType: 0,
+    };
+  },
+
+  mounted() {},
+
+  methods: {
+    deleteType(item){
+      this.$emit('deleteKnowledgeType',item)
+    },
+    changeType(item) {
+      this.choosedType = item.type;
+    },
+    deleteItem(item){
+       this.$emit('deleteKnowledge',item)
+    },
+    setFirstKnow(){
+      setTimeout(() => {
+        this.choosedType = this.knowledgeTypes[0] ? this.knowledgeTypes[0].type : 0;
+      });
+    },
+    go2Detail(item){
+      const href = this.$router.resolve({
+        path: '/knowledgeDetail',
+        query: {
+          id: item.KnowledgeResourceId,
+          source: item.ResourceType
+        }
+      }).href
+      window.open(href, "_blank")
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+.know-box {
+  width: 100%;
+  height: 100%;
+  overflow: auto;
+  box-sizing: border-box;
+  padding: 20px;
+  .top-title-box {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-bottom: 10px;
+    padding-bottom: 20px;
+    border-bottom: 1px solid #d9d9d9;
+    .types {
+      display: flex;
+      align-items: center;
+      .type-item {
+        font-size: 14px;
+        font-weight: 400;
+        padding: 4px 12px;
+        border-top: 1px solid #c8cdd9;
+        border-bottom: 1px solid #c8cdd9;
+        border-right: 1px solid #c8cdd9;
+        background: #fff;
+        color: #666666;
+        cursor: pointer;
+        display: flex;
+        align-items: center;
+      }
+      .type-item:first-of-type {
+        border-left: 1px solid #c8cdd9;
+        border-top-left-radius:6px;
+        border-bottom-left-radius:6px;
+      }
+      .type-item:last-of-type {
+        border-top-right-radius:6px;
+        border-bottom-right-radius:6px;
+      }
+      .type-item-in {
+        background: #0052d9;
+        color: #fff;
+      }
+    }
+    .icons{
+      .icon{
+        width: 24px;
+        height: 24px;
+        margin-left: 5px;
+      }
+    }
+    .title {
+      font-size: 20px;
+      font-weight: bold;
+      &::before {
+        content: "";
+        display: inline-block;
+        width: 4px;
+        height: 20px;
+        background-color: #0052d9;
+        position: relative;
+        top: 2px;
+        margin-right: 5px;
+      }
+    }
+  }
+  .list-wrap {
+    padding-top: 5px;
+    .item {
+      margin-top: 10px;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      line-height: 22px;
+      .item-time {
+        cursor: pointer;
+        color: #666666;
+        margin-right: 20px;
+        white-space: nowrap;
+      }
+      .item-title {
+        cursor: pointer;
+        flex: 1;
+        display: flex;
+        align-items: center;
+        color: #666666;
+        .title {
+          flex: 1;
+          width: 0;
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
+        }
+        .rect {
+          width: 8px;
+          height: 8px;
+          background-color: #f7ba1e;
+          margin-right: 10px;
+        }
+      }
+    }
+  }
+  .min-width{
+    min-width: 380px;
+  }
+}
+</style>

+ 12 - 1
src/views/BI_manage/components/SelectChart.vue

@@ -57,7 +57,7 @@
                     ><span>&nbsp;</span></el-checkbox
                   >
               </div>
-              <img :src="(chart_source===1&&!chart.HaveOperaAuth) ? $icons.lock_big : chart.ChartImage" alt="" class="chart-img" />
+              <img :src="(chart_source===1&&!chart.HaveOperaAuth) ? $icons.lock_big : chart.ChartImage" alt="" class="chart-img" @click="handleCheckbox(chart)"/>
               <div class="item-bottom">
                 <span class="last-time">创建时间:{{ chart.CreateTime.substr(0,10) }}</span>
               </div>
@@ -145,6 +145,7 @@ export default {
         10: crossVarietyInterface.searchChart,
         12: apiIntervalAnalysis.chartSearch
       }
+      if(this.chart_source == 12) params['Keyword'] = this.search_txt; //区间分析的Keyword不同
       let res = await apiMap[this.chart_source](params)
 
 
@@ -159,6 +160,15 @@ export default {
       
     },
 
+    handleCheckbox(item){
+      let index = this.checkList.findIndex(_=>_ == item.ChartInfoId);
+      if(index >= 0) {
+        this.checkList.splice(index,1);
+      } else {
+        this.checkList.push(item.ChartInfoId);
+      }
+    },
+
     loadMove() {
       this.page_no++;
       this.getPublicChartList();
@@ -227,6 +237,7 @@ export default {
           width: 100%;
           height: 180px;
           object-fit: fill !important;
+          cursor: pointer;
         }
         .item-bottom {
           margin-top: 10px;

+ 518 - 0
src/views/BI_manage/components/SelectKnow.vue

@@ -0,0 +1,518 @@
+<template>
+  <div class="choose-know-container">
+    <el-dialog
+      :visible.sync="show"
+      :close-on-click-modal="false"
+      :modal-append-to-body="false"
+      custom-class="dialog"
+      @close="cancelHandle"
+      :title="'添加知识资源-' + knowMessage[ResourceType].title"
+      top="3vh"
+      center
+      width="1200px"
+      v-dialogDrag
+    >
+      <div class="dialog-top">
+        <div>
+          <el-input
+            @input="filterChange"
+            placeholder="请输入标题"
+            v-model="filterForm.keyWord"
+            clearable
+            style="width: 240px"
+            prefix-icon="el-icon-search"
+          />
+
+          <el-popover
+            placement="bottom"
+            trigger="click"
+            :visible-arrow="false"
+            popper-class="report-select-popover"
+            width="350"
+            style="display: inline-block"
+          >
+            <div class="select-wrap-know">
+              <div class="select-top">
+                <h4>筛选条件</h4>
+                <span @click="handleClearFilter"
+                  style="cursor: pointer;"
+                  ><i class="el-icon-delete" style="margin-right: 4px;"/>清空所选条件</span
+                >
+              </div>
+              <div class="select-item">
+                <el-cascader
+                  v-model="filterForm.classifys"
+                  :options="classifyOptions"
+                  :props="{
+                    value: 'ClassifyId',
+                    label: 'ClassifyName',
+                    children: 'Child',
+                    emitPath: false,
+                    multiple: true,
+                  }"
+                  :show-all-levels="false"
+                  clearable
+                  placeholder="请选择分类"
+                  style="width: 100%"
+                  @change="filterChange"
+                ></el-cascader>
+              </div>
+              <div class="select-item">
+                <el-select
+                  v-model="filterForm.sources"
+                  placeholder="请选择来源"
+                  size="medium"
+                  clearable
+                  style="width: 100%"
+                  multiple
+                  @change="filterChange"
+                >
+                  <el-option
+                    v-for="item in sourcesOptions"
+                    :key="item"
+                    :label="item"
+                    :value="item"
+                  />
+                </el-select>
+              </div>
+
+              <div class="select-item">
+                <el-select
+                  v-model="filterForm.tags"
+                  placeholder="请选择标签"
+                  size="medium"
+                  clearable
+                  style="width: 100%"
+                  multiple
+                  @change="filterChange"
+                >
+                  <el-option
+                    v-for="item in tagsOptions"
+                    :key="item.TagId"
+                    :label="item.TagName"
+                    :value="item.TagId"
+                  />
+                </el-select>
+              </div>
+              <div class="select-item">
+                <el-select
+                  v-model="filterForm.users"
+                  placeholder="请选择用户"
+                  size="medium"
+                  clearable
+                  style="width: 100%"
+                  multiple
+                  @change="filterChange"
+                >
+                  <el-option
+                    v-for="item in usersOptions"
+                    :key="item.AdminId"
+                    :label="item.AdminRealName"
+                    :value="item.AdminId"
+                  />
+                </el-select>
+              </div>
+            </div>
+            <div class="select-btn" slot="reference">
+              <img src="~@/assets/icons/filter.svg" />
+              <span class="select-num">
+                <span class="circle-rect"></span>
+                <span>{{ selectNum }}</span>
+              </span>
+              <span>筛选条件</span>
+            </div>
+          </el-popover>
+        </div>
+        <div>
+          <el-checkbox v-model="filterForm.IsShowMe" @change="filterChange"
+            >只看我的</el-checkbox
+          >
+        </div>
+      </div>
+      <div class="main">
+        <el-table
+          :data="tableData"
+          style="
+            box-shadow: 0px 3px 6px rgba(155, 170, 219, 0.2);
+            margin-top: 20px;
+          "
+          border
+          v-loading="dataLoading"
+          @select="selectHandle"
+          @select-all="selectAllPageHandle"
+          ref="table"
+        >
+          <el-table-column type="selection" width="50" />
+          <el-table-column
+            v-for="item in tableColums"
+            :key="item.key"
+            :label="item.label"
+            :width="item.widthsty"
+            :min-width="item.minwidthsty"
+            show-overflow-tooltip
+            align="center"
+          >
+            <template slot-scope="{ row }">
+              <span>{{ row[item.key] }}</span>
+            </template>
+          </el-table-column>
+
+          <div class="nodata" slot="empty">
+            <tableNoData :text="$t('Table.prompt_slogan')" size="mini" />
+          </div>
+        </el-table>
+        <div style="height: 35px; margin: 20px 0; padding-right: 30px">
+          <m-page
+            :page_no="filterForm.pageNo"
+            :pageSize="filterForm.pageSize"
+            :total="total"
+            @handleCurrentChange="pageChange"
+          />
+        </div>
+      </div>
+
+      <div class="dia-footer-know">
+        <el-button
+          type="primary"
+          plain
+          @click="cancelHandle"
+          style="margin-right: 20px"
+          >{{ $t("Dialog.cancel_btn") }}</el-button
+        >
+        <el-button type="primary" @click="saveHandle" :loading="btnLoading">{{
+          $t("Dialog.confirm_save_btn")
+        }}</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+const knowMessage = {
+  0: { title: "事件库" },
+  1: { title: "政策库" },
+  2: { title: "报告库" },
+  3: { title: "知识库" },
+};
+import { eventInterface } from "@/api/modules/knowledge";
+import mPage from "@/components/mPage.vue";
+export default {
+  props: {
+    show: {
+      type: Boolean,
+      default: false,
+    },
+    ResourceType: {
+      type: Number,
+      default: 0,
+    },
+    knowList:{
+      type:Array,
+      default:() => []
+    }
+  },
+  components: { mPage },
+  data() {
+    return {
+      knowMessage,
+      filterForm: {
+        pageNo: 1,
+        pageSize: 10,
+        classifys: [],
+        sources: [],
+        tags: [],
+        users: [],
+        keyWord: "",
+        IsShowMe: false,
+      },
+      classifyOptions: [],
+      sourcesOptions: [],
+      tagsOptions: [],
+      usersOptions: [],
+      total: 0,
+      tableData: [],
+
+      dataLoading: false,
+      btnLoading:false,
+      selectionReactCancel: false, //手动设置选中中
+      checkedList: [],
+    };
+  },
+  watch: {
+    show(newval) {
+      if (!newval) return;
+      this.getClassifyOptions();
+      this.getSourceOptions();
+      this.getTagOptions();
+      this.getUsersOptions();
+      this.checkedList = this.knowList.filter(_=>_.ResourceType == this.ResourceType);
+      this.getTableData();
+    },
+  },
+  computed: {
+    selectNum() {
+      let num = 0;
+      this.filterForm.classifys.length && num++;
+      this.filterForm.sources.length && num++;
+      this.filterForm.tags.length && num++;
+      this.filterForm.users.length && num++;
+      return num;
+    },
+    tableColums() {
+      return [
+        { label: "时间", key: "StartTime" },
+        { label: "标题", key: "Title", minwidthsty: "150px" },
+        { label: "来源", key: "SourceFrom" },
+        { label: "分类", key: "ClassifyFullName" },
+        { label: "标签", key: "TagName" },
+        { label: "添加人", key: "AdminRealName" },
+      ];
+    },
+  },
+  methods: {
+    selectHandle(selection, row) {
+      if (this.selectionReactCancel) return;
+      //当前项是选中还是取消选
+      let haveChecked = selection.some(
+        (_) => _.KnowledgeResourceId == row.KnowledgeResourceId
+      );
+
+      if (haveChecked) {
+        this.checkedList.push(row);
+      } else {
+        this.checkedList = this.checkedList.filter(
+          (_) => _.KnowledgeResourceId != row.KnowledgeResourceId
+        );
+      }
+      //去重
+      this.checkedList = this.checkedList.filter((item, index, arr) => {
+        return (
+          arr.findIndex(
+            (_) => _.KnowledgeResourceId == item.KnowledgeResourceId
+          ) == index
+        );
+      });
+    },
+    selectAllPageHandle(selection) {
+      if (this.selectionReactCancel) return;
+      //当前页是选中还是取消
+      let haveChecked = selection && selection.length > 0;
+
+      if (haveChecked) {
+        this.checkedList = [...this.checkedList, ...this.tableData];
+      } else {
+        let pageIds = this.tableData.map((_) => _.KnowledgeResourceId);
+        this.checkedList = this.checkedList.filter(
+          (_) => !pageIds.includes(_.KnowledgeResourceId)
+        );
+      }
+      //去重
+      this.checkedList = this.checkedList.filter((item, index, arr) => {
+        return (
+          arr.findIndex(
+            (_) => _.KnowledgeResourceId == item.KnowledgeResourceId
+          ) == index
+        );
+      });
+    },
+    saveHandle() {
+      if(this.checkedList && this.checkedList.length > 10) 
+      return this.$message.warning('每种知识资源最多只能选择10条');
+      this.btnLoading = true;
+      this.$emit("addKnow", {
+        ResourceType: this.ResourceType,
+        checkedList: this.checkedList || [],
+      });
+    },
+    filterChange() {
+      this.filterForm.pageNo = 1;
+      this.getTableData();
+    },
+    pageChange(page) {
+      this.filterForm.pageNo = page;
+      this.getTableData();
+    },
+    async getTableData() {
+      const {
+        pageNo,
+        pageSize,
+        classifys,
+        sources,
+        tags,
+        users,
+        keyWord,
+        IsShowMe,
+      } = this.filterForm;
+      let params = {
+        PageSize: pageSize,
+        CurrentIndex: pageNo,
+        ClassifyIds: classifys.join(","),
+        SysUserIds: users.join(","),
+        TagIds: tags.join(","),
+        Keyword: keyWord,
+        SourceFrom: sources.join(","),
+        ResourceType: this.ResourceType,
+        IncludeFile:'no',
+        IsShowMe,
+      };
+      this.dataLoading = true;
+      const res = await eventInterface.getEventListByES(params);
+
+      this.dataLoading = false;
+      if (res.Ret !== 200) return;
+
+      this.tableData = res.Data.List || [];
+      this.total = res.Data.Paging.Totals || 0;
+      this.handleChoosed();
+    },
+    handleChoosed() {
+      this.selectionReactCancel = true;
+      this.checkedList.map((_) => {
+        let row = this.tableData.find(
+          (item) => item.KnowledgeResourceId == _.KnowledgeResourceId
+        );
+        if (row) {
+          //设置部分选中
+          setTimeout(() => {
+            this.$refs.table.toggleRowSelection(row, true);
+          }, 20);
+        }
+      });
+
+      setTimeout(() => {
+        this.selectionReactCancel = false;
+      }, 30);
+    },
+    cancelHandle() {
+      this.$emit("update:show", false);
+      this.init();
+    },
+    init() {
+      this.filterForm = {
+        pageNo: 1,
+        pageSize: 10,
+        classifys: [],
+        sources: [],
+        tags: [],
+        users: [],
+        keyWord: "",
+        IsShowMe: false,
+      };
+      this.checkedList = [];
+      this.total = 0;
+      this.tableData = [];
+      this.btnLoading = false;
+    },
+    handleClearFilter() {
+      this.filterForm.classifys = [];
+      this.filterForm.sources = [];
+      this.filterForm.tags = [];
+      this.filterForm.users = [];
+      this.filterChange();
+    },
+    async getClassifyOptions() {
+      const res = await eventInterface.getClassify({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.classifyOptions = res.Data.List || [];
+    },
+    async getSourceOptions() {
+      const res = await eventInterface.getSourcesList({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.sourcesOptions = res.Data.List || [];
+    },
+    async getTagOptions() {
+      const res = await eventInterface.getTagList({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.tagsOptions = res.Data.List || [];
+    },
+    async getUsersOptions() {
+      const res = await eventInterface.getUsersList({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.usersOptions = res.Data.List || [];
+    },
+  },
+};
+</script>
+<style lang="scss">
+.choose-know-container {
+  .dialog-top {
+    padding: 5px 15px 0;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    .select-btn {
+      cursor: pointer;
+      width: 140px;
+      height: 40px;
+      text-align: center;
+      background-color: #ecf2fe;
+      border-radius: 4px;
+      box-sizing: border-box;
+      line-height: 40px;
+      margin-left: 20px;
+      box-sizing: border-box;
+      img,
+      span {
+        display: inline-block;
+        vertical-align: middle;
+      }
+      .select-num {
+        margin-left: 10px;
+        color: #0052d9;
+        font-size: 14px;
+        font-weight: 500;
+        margin-right: 2px;
+        .circle-rect{
+          display: inline-block;
+          width: 4px;
+          height: 4px;
+          border-radius: 50%;
+          background-color: #0052D9;
+        }
+      }
+    }
+  }
+  .main {
+    padding: 0 15px 0;
+  }
+  .dia-footer-know {
+    display: flex;
+    justify-content: center;
+    margin: 40px 0 20px 0;
+  }
+}
+.select-wrap-know {
+  padding: 8px;
+  margin: 0 20px;
+  .select-top {
+    display: flex;
+    justify-content: space-between;
+    > span {
+      color: #999;
+    }
+  }
+  .select-item {
+    margin-top: 20px;
+  }
+  .select-bot {
+    display: flex;
+    justify-content: center;
+    margin-top: 20px;
+    .el-button {
+      width: 120px;
+    }
+  }
+}
+</style>

+ 12 - 1
src/views/BI_manage/components/SelectTable.vue

@@ -72,6 +72,7 @@
                   "
                   alt=""
                   class="chart-img"
+                  @click="handleCheckbox(table)"
                 />
                 <div class="item-bottom">
                   <span class="last-time"
@@ -147,7 +148,7 @@ export default {
         PageSize: this.page_size,
         CurrentIndex: this.page_no,
         Source: this.table_source,
-        KeyWord: this.search_txt,
+        Keyword: this.search_txt,
         IsShowMe: this.isShowMe
       };
 
@@ -164,6 +165,15 @@ export default {
 
     },
 
+    handleCheckbox(item){
+      let index = this.checkList.findIndex(_=>_ == item.ExcelInfoId);
+      if(index >= 0) {
+        this.checkList.splice(index,1);
+      } else {
+        this.checkList.push(item.ExcelInfoId)
+      }
+    },
+
     loadMove() {
       this.page_no++;
       this.getPublicTableList();
@@ -235,6 +245,7 @@ export default {
           width: 100%;
           height: 180px;
           object-fit: fill !important;
+          cursor: pointer;
         }
         .item-bottom {
           margin-top: 10px;

+ 50 - 3
src/views/BI_manage/components/TableBox.vue

@@ -7,7 +7,7 @@
     element-loading-text="拼命加载中"
   >
     <div class="top-title-box">
-      <div class="title" @click="goDetail">{{ info&&info.ExcelName }}</div>
+      <div class="title">{{ info&&info.ExcelName }}</div>
       <div class="opt-box">
         <img
           class="icon"
@@ -16,15 +16,15 @@
           v-permission="permissionBtn.BIBoardPermission.BIBoard_refresh"
           @click="handleRefresh"
         />
-        <slot name="drag"></slot>
         <slot name="delete"></slot>
+        <slot name="drag"></slot>
       </div>
     </div>
     <!-- 无权限 -->
     <div class="nodata" v-if="!info">
       <noDataAuth text="暂无数据" />
     </div>
-    <div class="table-render-wrap" v-else>
+    <div class="table-render-wrap" @click="goDetail" v-else>
     <div class="table-wrapper pc-sty" >
       <table
         cellpadding="0"
@@ -73,12 +73,39 @@
       </table>
     </div>
     </div>
+    <div v-if="info && info.SourcesFrom && JSON.parse(info.SourcesFrom) && JSON.parse(info.SourcesFrom).isShow" style="width: 100%;">
+      <el-tooltip
+        placement="top"
+        v-tooltipHidable
+      >
+        <div slot="content" class="tooltip-maxwidth-bi">{{ JSON.parse(info.SourcesFrom).text }}</div>
+        <div
+            class="bottom-overflow"
+            ref="sourceRef"
+            :style="`
+                    color: ${
+                      JSON.parse(info.SourcesFrom).isShow
+                        ? JSON.parse(info.SourcesFrom).color || '#999'
+                        : '#999'
+                    };
+                    fontSize: ${
+                      JSON.parse(info.SourcesFrom).fontSize || 14
+                    }px;
+                    width:100%;
+                  `"
+            >{{ $t("Chart.Detail.source") }}:{{
+              JSON.parse(info.SourcesFrom).text
+            }}
+        </div>
+      </el-tooltip>
+    </div>
   </div>
 </template>
 
 <script>
 import apiBiBoard from '@/api/modules/BIBoard.js'
 import * as sheetInterface from "@/api/modules/sheetApi.js";
+import tooltipHidable from "@/directives/tooltip-hidable.js"
 export default {
   props: {
     compData: null
@@ -91,6 +118,7 @@ export default {
       info:null,
     }
   },
+  directives:{tooltipHidable},
   mounted() {
     console.log('表格组件挂载',);
     this.createObserver();
@@ -180,6 +208,12 @@ export default {
       font-size: 20px;
       font-weight: bold;
       flex: 1;
+      display: -webkit-box;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      -webkit-line-clamp: 1;
+      line-break: anywhere;
+      -webkit-box-orient: vertical;
       &::before {
         content: "";
         display: inline-block;
@@ -220,6 +254,7 @@ export default {
   background: #666;
 }
 .table-render-wrap{
+  cursor: pointer;
   width: 100%;
   flex: 1;
   height: 100%;
@@ -283,5 +318,17 @@ table {
     padding: 0.4em 0;
   }
 }
+.bottom-overflow{
+  white-space: nowrap;      
+  overflow: hidden;        
+  text-overflow: ellipsis;  
+};
+}
+</style>
+<style lang="scss">
+.tooltip-maxwidth-bi{
+    max-width: 500px; 
+    white-space: normal; 
+    word-break: break-word;
 }
 </style>

+ 130 - 9
src/views/BI_manage/editBoard.vue

@@ -12,13 +12,31 @@
       <el-button type="primary" plain @click="showSelectChart = true"
         >添加图表</el-button
       >
+      <el-dropdown @command="handleCommand">
+        <el-button type="primary" style="margin-left: 10px;">
+          添加知识资源<i class="el-icon-arrow-down el-icon--right"></i>
+        </el-button>
+        <el-dropdown-menu slot="dropdown">
+          <el-dropdown-item command="0">事件库</el-dropdown-item>
+          <el-dropdown-item command="1">政策库</el-dropdown-item>
+          <el-dropdown-item command="2">报告库</el-dropdown-item>
+          <el-dropdown-item command="3">知识库</el-dropdown-item>
+        </el-dropdown-menu>
+      </el-dropdown>
       <div class="right-btns">
         <el-button type="primary" plain @click="$router.back()">取消</el-button>
         <el-button type="primary" @click="handleSave">保存</el-button>
       </div>
     </div>
     <!-- 看板内容模块 -->
-    <BIBoardContent v-model="boardDataList" :canDelete="true" :canDrag="true" />
+    <BIBoardContent 
+      ref="boardContent" 
+      :knowList.sync="knowledgeList" 
+      renderHeight="calc(100vh - 190px)"
+      @checkDataList="checkDataList"
+      v-model="boardDataList" 
+      :canDelete="true" 
+      :canDrag="true" />
 
     <!-- 选择图表 -->
     <SelectChart
@@ -30,6 +48,13 @@
       v-model="showSelectTable"
       @addTable="handleAddComp('table', $event)"
     />
+    <!-- 选择知识资源 -->
+    <SelectKnow
+      :show.sync="showSelectKnow"
+      :ResourceType="selectKnowType"
+      :knowList="knowledgeList"
+      @addKnow="handleAddKnow"
+    />
   </div>
 </template>
 
@@ -38,6 +63,7 @@ import apiBiBoard from '@/api/modules/BIBoard.js'
 import BIBoardContent from './components/BoardContent.vue'
 import SelectChart from './components/SelectChart.vue'
 import SelectTable from './components/SelectTable.vue'
+import SelectKnow from './components/SelectKnow.vue'
 const MAX_COUNT = 50
 // 生成唯一ID 
 function createUniqueIdGenerator() {
@@ -53,15 +79,20 @@ export default {
   components: {
     BIBoardContent,
     SelectChart,
-    SelectTable
+    SelectTable,
+    SelectKnow,
   },
   data() {
     return {
       name: '',
       boardDataList: [],
+      knowledgeList:[],//知识资源模块列表的全部数据
 
       showSelectChart: false,
-      showSelectTable: false
+      showSelectTable: false,
+      showSelectKnow: false,
+      selectKnowType:0,
+      getKnowledgeLoading:false,
     }
   },
   created() {
@@ -70,15 +101,51 @@ export default {
     }
   },
   methods: {
+    handleCommand(command){
+       this.selectKnowType = +command || 0;
+       this.showSelectKnow = true;
+    },
     // 获取看板详情
     async getBoardDetail(){
       const res=await apiBiBoard.boardDetail({DashboardId:Number(this.$route.query.id)})
       if(res.Ret===200){
         this.name=res.Data.BiDashboardName
         this.boardDataList=res.Data.List||[]
+        this.handleKnowList();
       }
     },
 
+    async handleKnowList(){
+      let item = this.boardDataList.find(_=>_.Type == 3);
+      if(!item) return;
+      this.getKnowledgeLoading = true;
+      let res = await apiBiBoard.getKnowledge({ BiDashboardDetailId:item.BiDashboardDetailId });
+      this.getKnowledgeLoading = false;
+      if(res.Ret != 200) return;
+      this.knowledgeList = (res.Data && res.Data.KnowledgeResourceList) || [];
+      this.cacheSaveKnowList(); //首次请求暂存,否则后端获取不到
+      if(this.knowledgeList.length > 0) this.setFirstKnow();
+    },
+
+    async cacheSaveKnowList(){
+      let knowItem = this.boardDataList.find(_=>_.Type == 3);
+      this.getKnowledgeLoading = true;
+      await apiBiBoard.saveKnowledge({
+        BiDashboardDetailId:knowItem ? (/^selfId_\d+$/.test(knowItem.BiDashboardDetailId) ? 0 : knowItem.BiDashboardDetailId) : 0,
+        KnowledgeResourceList:this.knowledgeList.map(_=>({
+          ResourceType:_.ResourceType,
+          KnowledgeResourceId:_.KnowledgeResourceId
+        }))
+      });
+      this.getKnowledgeLoading = false
+    },
+
+    setFirstKnow(){
+      this.$nextTick(()=>{
+        this.$refs.boardContent && this.$refs.boardContent.setFirstKnow()
+      })
+    },
+
     async handleSave() {
       if (!this.name) {
         this.$message.warning('请填写看板名称')
@@ -88,11 +155,14 @@ export default {
         this.$message.warning('请至少选择一个图表或表格!')
         return
       }
-
+      if(this.getKnowledgeLoading){
+        return this.$message.warning('请等待数据加载完成之后再操作')
+      }
       const arr=this.boardDataList.map(item=>{
         return {
           Type:item.Type,
-          UniqueCode:item.UniqueCode
+          UniqueCode:item.UniqueCode,
+          Conf:item.Conf,
         }
       })
       const params={
@@ -111,22 +181,73 @@ export default {
       }
 
     },
+    checkDataList(dataList){ //grid-layout对x.y进行处理之后数据发生变化  同步x.y数据
+      if(!dataList || !dataList.length) return;
+       dataList.map((item) => { 
+         let i = this.boardDataList.findIndex(_=>item.BiDashboardDetailId == _.BiDashboardDetailId && item.Type == _.Type);
+         if(i >= 0 && (item.x != this.boardDataList[i].x || item.y != this.boardDataList[i].y)){
+          this.boardDataList[i].x = item.x;
+          this.boardDataList[i].y = item.y;
+          let configs = {
+            w : item.w,
+            h : item.h,
+            x : item.x,
+            y : item.y,
+            i : item.i,
+          };
+          this.boardDataList[i].Conf = JSON.stringify(configs);
+         }
+       });
+    },
+    async handleAddKnow(data){
+      const { ResourceType, checkedList} = data;
+      let knowList = [...this.knowledgeList.filter(_=>_.ResourceType != ResourceType),...checkedList];
+      
+      let knowItem = this.boardDataList.find(_=>_.Type == 3);
+      //后端需要暂存数据
+      let r = await apiBiBoard.saveKnowledge({
+        BiDashboardDetailId:knowItem ? (/^selfId_\d+$/.test(knowItem.BiDashboardDetailId) ? 0 : knowItem.BiDashboardDetailId) : 0,
+        KnowledgeResourceList:knowList.map(_=>({
+          ResourceType:_.ResourceType,
+          KnowledgeResourceId:_.KnowledgeResourceId
+        }))
+      });
+      if(r.Ret != 200) return this.$message.warning('添加失败,请重试')
+      this.knowledgeList = knowList;
 
+      if(!knowItem){
+        let i = {
+          Type: 3,
+          UniqueCode:'uniqueTimeCode' + new Date().getTime(),
+          BiDashboardDetailId:getUniqueId()
+        }
+        let addItem = this.$refs.boardContent ? this.$refs.boardContent.getAddMessage([i]) : []; //处理添加内容的位置信息
+        this.boardDataList = [...this.boardDataList,...addItem];
+      }else {
+        if(!knowList.length){
+           this.boardDataList = this.boardDataList.filter(_=>_.Type != 3);
+        }
+      }
+      this.setFirstKnow();
+      this.showSelectKnow = false;
+    },
     handleAddComp(type, data) {
       const arr = data || []
       if (this.boardDataList.length + arr.length > MAX_COUNT) {
         this.$message.warning('添加已达上限(上限50)!')
         return
       }
-      arr.forEach(item => {
-        const obj = {
-          Type: type === 'chart' ? 1 : 2,
+      let objs = arr.map(item => {
+        return {
+          Type: type == 'chart' ? 1 : 2,
           UniqueCode:item.UniqueCode,
           BiDashboardDetailId:getUniqueId()
         }
-        this.boardDataList.push(obj)
       });
 
+      let addItems = this.$refs.boardContent ? this.$refs.boardContent.getAddMessage(objs) : []; //处理添加内容的位置信息
+      this.boardDataList = [...this.boardDataList,...addItems];
+
       this.showSelectChart = false
       this.showSelectTable = false
     },

+ 26 - 1
src/views/BI_manage/index.vue

@@ -96,7 +96,7 @@
       </div>
     </div>
     <!-- 看板内容模块 -->
-    <BIBoardContent v-model="boardDataList" :boardInfo="boardInfo"/>
+    <BIBoardContent ref="boardContent" :knowList.sync="knowledgeList" v-model="boardDataList" :boardInfo="boardInfo" renderHeight="calc(100vh - 260px)"/>
 
     <!-- 设置共享 -->
     <set-share v-model="showSetShare" :boardInfo="boardInfo" @change="handleSetShareBack"/>
@@ -137,6 +137,7 @@ export default {
 
       boardInfo: null,//看板详情数据
       boardDataList: [],//看板数据
+      knowledgeList:[],//知识资源模块列表的全部数据
 
       selectBoardId: '',//当前选择的看板id
       myBoardList: [],
@@ -154,6 +155,8 @@ export default {
     }
   },
   created() {
+    if(!this.permissionBtn.isShowBtn('BIBoardPermission','BIBoard_view')) 
+      return this.$message.warning('您当前暂无查看数据权限,如需查看,请联系管理员');
     if(this.$route.query.id){
       
       this.selectBoardId=Number(this.$route.query.id)
@@ -240,9 +243,25 @@ export default {
       if (res.Ret === 200) {
         this.boardInfo = res.Data
         this.boardDataList = res.Data.List || []
+        this.handleKnowList();
       }
     },
 
+    async handleKnowList(){
+      let item = this.boardDataList.find(_=>_.Type == 3);
+      if(!item) return;
+      let res = await apiBiBoard.getKnowledge({ BiDashboardDetailId:item.BiDashboardDetailId });
+      if(res.Ret != 200) return;
+      this.knowledgeList = (res.Data && res.Data.KnowledgeResourceList) || [];
+      if(this.knowledgeList.length > 0) this.setFirstKnow();
+    },
+
+    setFirstKnow(){
+      this.$nextTick(()=>{
+        this.$refs.boardContent && this.$refs.boardContent.setFirstKnow()
+      })
+    },
+
     // 设置公共回调
     handleSetCommonBack(){
       this.getBoardDetail()
@@ -263,6 +282,8 @@ export default {
 
     // 我的看板列表
     async getMyBoardList(type) {
+      if(!this.permissionBtn.isShowBtn('BIBoardPermission','BIBoard_view')) 
+      return this.$message.warning('您当前暂无查看数据权限,如需查看,请联系管理员');
       const res = await apiBiBoard.myBoardList()
       if (res.Ret === 200) {
         this.myBoardList = res.Data || []
@@ -276,6 +297,8 @@ export default {
 
     // 共享看板列表
     async getShareBoardList(type) {
+      if(!this.permissionBtn.isShowBtn('BIBoardPermission','BIBoard_view')) 
+      return this.$message.warning('您当前暂无查看数据权限,如需查看,请联系管理员');
       const res = await apiBiBoard.shareBoardList()
       if (res.Ret === 200) {
         const myArr = res.Data.MyList || []
@@ -322,6 +345,8 @@ export default {
 
     // 公共看板列表
     async getCommonBoardList(type) {
+      if(!this.permissionBtn.isShowBtn('BIBoardPermission','BIBoard_view')) 
+      return this.$message.warning('您当前暂无查看数据权限,如需查看,请联系管理员');
       const res = await apiBiBoard.commonBoardList()
       if (res.Ret === 200) {
         const arr = res.Data || []

+ 22 - 3
src/views/approve_manage/approveDetail.vue

@@ -24,7 +24,7 @@
             <div v-else class="approve-content" 
                 v-loading="isLoading"
                 element-loading-text="看板加载中...">
-                <BIBoardContent :value="boardDataList" renderHeight="calc(100vh - 250px)" />
+                <BIBoardContent ref="boardContent" :knowList.sync="knowledgeList" :value="boardDataList" renderHeight="calc(100vh - 200px)" />
             </div>
         </div>
         <div class="approve-tool">
@@ -100,6 +100,7 @@ export default {
             },
             waterMarkStr:'',//水印
             boardDataList:[],
+            knowledgeList:[],//知识资源模块列表的全部数据
         };
     },
     computed:{
@@ -160,8 +161,24 @@ export default {
             this.isLoading = false;
             if (res.Ret === 200) {
                 this.boardDataList = res.Data.List || []
+                this.handleKnowList();
             }
         },
+        async handleKnowList(){
+            let item = this.boardDataList.find(_=>_.Type == 3);
+            if(!item) return;
+            let res = await apiBiBoard.getKnowledge({ BiDashboardDetailId:item.BiDashboardDetailId });
+            if(res.Ret != 200) return;
+            this.knowledgeList = (res.Data && res.Data.KnowledgeResourceList) || [];
+            if(this.knowledgeList.length > 0) this.setFirstKnow();
+        },
+        
+        setFirstKnow(){
+          this.$nextTick(()=>{
+            this.$refs.boardContent && this.$refs.boardContent.setFirstKnow()
+          })
+        },
+        
         //转换接口数据
         formatTimeLineData({Approve={},ApproveFlowNodes=[]}){
             //发起人节点
@@ -206,7 +223,9 @@ export default {
                         //只有依次审批需要看顺序
                         if(i.ApproveType===1){
                             this.approveInfo.isCurrentApprover = i.Users[hasUser].ApproveRecord?true:false
-                        }else{
+                        } else if(i.ApproveType===2){ //会签
+                            this.approveInfo.isCurrentApprover = i.Users[hasUser].ApproveRecord && i.Users[hasUser].ApproveRecord.State == 1 ? true : false;
+                        } else{
                             this.approveInfo.isCurrentApprover = true
                         }
                     }else{
@@ -457,7 +476,7 @@ export default {
         .approve-content{
             flex: 1;
             min-width: 840px;
-            padding:20px;
+            // padding:20px;
             overflow-y: auto;
             position:relative;
         }

+ 18 - 1
src/views/home_manage/index.vue

@@ -8,7 +8,7 @@
       </div>
     </div>
     <!-- 看板内容模块 -->
-    <BIBoardContent v-model="boardDataList"/>
+    <BIBoardContent ref="boardContent" :knowList.sync="knowledgeList" v-model="boardDataList" renderHeight="calc(100vh - 190px)"/>
 
     <!-- 设置看板 -->
     <SelectBoard v-model="showSet" :boardId="boardId" :homeBoardInfo="homeBoardInfo" @change="getBoardData"/>
@@ -27,6 +27,7 @@ export default {
       boardId:'',
       boardInfo:null,
       boardDataList:[],
+      knowledgeList:[],//知识资源模块列表的全部数据
       showSet:false
     }
   },
@@ -49,8 +50,24 @@ export default {
       if(res.Ret===200){
         this.boardInfo = res.Data
         this.boardDataList = res.Data.List || []
+        this.handleKnowList();
       }
     },
+    
+    async handleKnowList(){
+      let item = this.boardDataList.find(_=>_.Type == 3);
+      if(!item) return;
+      let res = await apiBiBoard.getKnowledge({ BiDashboardDetailId:item.BiDashboardDetailId });
+      if(res.Ret != 200) return;
+      this.knowledgeList = (res.Data && res.Data.KnowledgeResourceList) || [];
+      if(this.knowledgeList.length > 0) this.setFirstKnow();
+    },
+
+    setFirstKnow(){
+      this.$nextTick(()=>{
+        this.$refs.boardContent && this.$refs.boardContent.setFirstKnow()
+      })
+    },
 
     async getBoardData(){
       const res=await apiBiBoard.getHomePageBoard()

+ 4 - 0
src/views/knowledge_manage/list.vue

@@ -292,6 +292,8 @@ export default {
     }
   },
   mounted(){
+    if(!this.checkBtnAuth('view')) 
+    return this.$message.warning('您当前暂无查看数据权限,如需查看,请联系管理员');
     this.getClassifyOptions();
     this.getSourceOptions();
     this.getTagOptions()
@@ -332,6 +334,8 @@ export default {
 
 
     async getTableData() {
+      if(!this.checkBtnAuth('view'))  //权限拦截
+      return this.$message.warning('您当前暂无查看数据权限,如需查看,请联系管理员');
       const { pageNo,
         pageSize,
         classifys,

+ 440 - 0
src/views/ppt_manage/newVersion/components/editor/InsertKnowledge.vue

@@ -0,0 +1,440 @@
+<template>
+  <div class="import-knowledge-wrap">
+    <div class="search-box">
+      <div class="headers">
+        <el-input
+          @input="filterChange"
+          placeholder="请输入标题"
+          v-model="filterForm.keyWord"
+          clearable
+          style="width: 180px"
+          prefix-icon="el-icon-search"
+        />
+
+        <el-popover
+          placement="bottom"
+          trigger="click"
+          :visible-arrow="false"
+          popper-class="report-select-popover"
+          width="350"
+          style="display: inline-block"
+        >
+          <div class="select-wrap-knowledge">
+            <div class="select-top">
+              <h4>筛选条件</h4>
+              <span @click="handleClearFilter" style="cursor: pointer"
+                ><i
+                  class="el-icon-delete"
+                  style="margin-right: 4px"
+                />清空所选条件</span
+              >
+            </div>
+            <div class="select-item">
+              <el-cascader
+                v-model="filterForm.classifys"
+                :options="classifyOptions"
+                :props="{
+                  value: 'ClassifyId',
+                  label: 'ClassifyName',
+                  children: 'Child',
+                  emitPath: false,
+                  multiple: true,
+                }"
+                :show-all-levels="false"
+                clearable
+                placeholder="请选择分类"
+                style="width: 100%"
+                @change="filterChange"
+              ></el-cascader>
+            </div>
+            <div class="select-item">
+              <el-select
+                v-model="filterForm.sources"
+                placeholder="请选择来源"
+                size="medium"
+                clearable
+                style="width: 100%"
+                multiple
+                @change="filterChange"
+              >
+                <el-option
+                  v-for="item in sourcesOptions"
+                  :key="item"
+                  :label="item"
+                  :value="item"
+                />
+              </el-select>
+            </div>
+
+            <div class="select-item">
+              <el-select
+                v-model="filterForm.tags"
+                placeholder="请选择标签"
+                size="medium"
+                clearable
+                style="width: 100%"
+                multiple
+                @change="filterChange"
+              >
+                <el-option
+                  v-for="item in tagsOptions"
+                  :key="item.TagId"
+                  :label="item.TagName"
+                  :value="item.TagId"
+                />
+              </el-select>
+            </div>
+
+            <div class="select-item">
+              <el-select
+                v-model="filterForm.users"
+                placeholder="请选择用户"
+                size="medium"
+                clearable
+                style="width: 100%"
+                multiple
+                @change="filterChange"
+              >
+                <el-option
+                  v-for="item in usersOptions"
+                  :key="item.AdminId"
+                  :label="item.AdminRealName"
+                  :value="item.AdminId"
+                />
+              </el-select>
+            </div>
+          </div>
+          <div class="select-btn" slot="reference">
+            <img src="~@/assets/icons/filter.svg" />
+            <span class="select-num">
+              <span class="circle-rect"></span>
+              <span>{{ selectNum }}</span>
+            </span>
+            <span>筛选条件</span>
+          </div>
+        </el-popover>
+      </div>
+      <el-radio-group
+        v-model="ResourceType"
+        style="margin: 10px 0 6px 0"
+        @change="activeTypeChange"
+      >
+        <el-radio
+          v-for="item in typeOpts"
+          :key="item.type"
+          :label="item.type"
+          style="margin-bottom: 5px; margin-top: 2px"
+          >{{ item.title }}</el-radio
+        >
+      </el-radio-group>
+      <div style="margin-bottom: 6px">
+        <el-checkbox v-model="filterForm.IsShowMe" @change="filterChange"
+          >只看我的</el-checkbox
+        >
+      </div>
+    </div>
+    <div style="flex: 1; overflow: hidden">
+      <div
+        class="knowledge-list"
+        v-infinite-scroll="handleLoadMore"
+        :infinite-scroll-immediate="true"
+        infinite-scroll-distance="10"
+      >
+        <div class="knowledge-list-box">
+          <div
+            class="card-item"
+            v-for="item in tableData"
+            :key="item.KnowledgeResourceId"
+            @click="handleClickItem(item)"
+          >
+            <div class="title">{{ item.Title }}</div>
+            <div class="content">{{ item.Content }}</div>
+            <div class="time">时间:{{ item.StartTime }}</div>
+            <div class="source">来源:{{ item.SourceFrom }}</div>
+          </div>
+        </div>
+        <tableNoData
+          :text="$t('ReportManage.ReportList.no_chart_table_available')"
+          size="mini"
+          v-if="tableData.length === 0 && isEnd"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { eventInterface } from "@/api/modules/knowledge";
+export default {
+  data() {
+    return {
+      ResourceType: 0,
+      filterForm: {
+        pageNo: 1,
+        pageSize: 30,
+        classifys: [],
+        sources: [],
+        tags: [],
+        users: [],
+        keyWord: "",
+        IsShowMe: false,
+      },
+      classifyOptions: [],
+      sourcesOptions: [],
+      tagsOptions: [],
+      usersOptions: [],
+      tableData: [],
+      dataLoading: false,
+      isEnd: false,
+    };
+  },
+
+  computed: {
+    selectNum() {
+      let num = 0;
+      this.filterForm.classifys.length && num++;
+      this.filterForm.sources.length && num++;
+      this.filterForm.tags.length && num++;
+      this.filterForm.users.length && num++;
+      return num;
+    },
+    typeOpts() {
+      return [
+        { type: 0, title: "事件库" },
+        { type: 1, title: "政策库" },
+        { type: 2, title: "报告库" },
+        { type: 3, title: "知识库" },
+      ];
+    },
+  },
+
+  created() {
+    this.getFilters();
+    this.getTableData();
+  },
+
+  methods: {
+    handleClickItem(item) {
+      this.$parent.chooseKnowledge(item);
+    },
+    async getTableData() {
+      const {
+        pageNo,
+        pageSize,
+        classifys,
+        sources,
+        tags,
+        users,
+        keyWord,
+        IsShowMe,
+      } = this.filterForm;
+      let params = {
+        PageSize: pageSize,
+        CurrentIndex: pageNo,
+        ClassifyIds: classifys.join(","),
+        SysUserIds: users.join(","),
+        TagIds: tags.join(","),
+        Keyword: keyWord,
+        SourceFrom: sources.join(","),
+        ResourceType: this.ResourceType,
+        IncludeFile: "no",
+        IsShowMe,
+      };
+      this.dataLoading = true;
+      const res = await eventInterface.getEventListByES(params);
+
+      this.dataLoading = false;
+      if (res.Ret !== 200) return;
+
+      let dataList = res.Data.List || [];
+      this.tableData =
+        pageNo == 1 ? dataList : [...this.tableData, ...dataList];
+      this.isEnd = res.Data.Paging.IsEnd;
+    },
+    handleLoadMore() {
+      if (this.isEnd || this.dataLoading) return;
+      this.filterForm.pageNo++;
+      this.getTableData();
+    },
+    activeTypeChange(item) {
+      this.ResourceType = item;
+      this.dataInit();
+      this.getFilters();
+      this.getTableData();
+    },
+    dataInit() {
+      this.filterForm.pageNo = 1;
+      this.filterForm.classifys = [];
+      this.filterForm.sources = [];
+      this.filterForm.tags = [];
+      this.filterForm.users = [];
+      this.isEnd = false;
+      this.tableData = [];
+    },
+    filterChange() {
+      this.filterForm.pageNo = 1;
+      this.tableData = [];
+      this.getTableData();
+    },
+    handleClearFilter() {
+      this.filterForm.classifys = [];
+      this.filterForm.sources = [];
+      this.filterForm.tags = [];
+      this.filterForm.users = [];
+      this.filterChange();
+    },
+    getFilters() {
+      this.getClassifyOptions();
+      this.getSourceOptions();
+      this.getTagOptions();
+      this.getUsersOptions();
+    },
+    async getClassifyOptions() {
+      const res = await eventInterface.getClassify({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.classifyOptions = res.Data.List || [];
+    },
+    async getSourceOptions() {
+      const res = await eventInterface.getSourcesList({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.sourcesOptions = res.Data.List || [];
+    },
+    async getTagOptions() {
+      const res = await eventInterface.getTagList({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.tagsOptions = res.Data.List || [];
+    },
+    async getUsersOptions() {
+      const res = await eventInterface.getUsersList({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.usersOptions = res.Data.List || [];
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+.import-knowledge-wrap {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  .search-box {
+    .headers {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      .select-btn {
+        cursor: pointer;
+        width: 110px;
+        height: 40px;
+        text-align: center;
+        background-color: #ecf2fe;
+        border-radius: 4px;
+        box-sizing: border-box;
+        line-height: 40px;
+        margin-left: 8px;
+        box-sizing: border-box;
+        img,
+        span {
+          display: inline-block;
+          vertical-align: middle;
+        }
+        .select-num {
+          margin-left: 4px;
+          color: #0052d9;
+          font-size: 14px;
+          font-weight: 500;
+          margin-right: 2px;
+          .circle-rect {
+            display: inline-block;
+            width: 4px;
+            height: 4px;
+            border-radius: 50%;
+            background-color: #0052d9;
+          }
+        }
+      }
+    }
+  }
+  .knowledge-list {
+    height: 100%;
+    overflow-y: auto;
+    .card-item {
+      box-sizing: border-box;
+      cursor: pointer;
+      width: 100%;
+      border: 1px solid #c8cdd9;
+      border-radius: 4px;
+      margin-bottom: 20px;
+      padding: 10px;
+      .title {
+        color: #000000;
+        font-weight: 500;
+        font-size: 16px;
+        font-weight: 400;
+        line-height: 22px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        display: -webkit-box;
+        -webkit-box-orient: vertical;
+        -webkit-line-clamp: 2;
+      }
+      .content {
+        margin-top: 14px;
+        line-height: 20px;
+        font-size: 14px;
+        color: #666666;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        display: -webkit-box;
+        -webkit-box-orient: vertical;
+        -webkit-line-clamp: 3;
+      }
+      .time,
+      .source {
+        margin-top: 10px;
+        color: #666666;
+        line-height: 20px;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+      }
+    }
+  }
+}
+</style>
+<style lang="scss">
+.select-wrap-knowledge {
+  padding: 8px;
+  margin: 0 20px;
+  .select-top {
+    display: flex;
+    justify-content: space-between;
+    > span {
+      color: #999;
+    }
+  }
+  .select-item {
+    margin-top: 20px;
+  }
+  .select-bot {
+    display: flex;
+    justify-content: center;
+    margin-top: 20px;
+    .el-button {
+      width: 120px;
+    }
+  }
+}
+</style>

+ 2 - 1
src/views/ppt_manage/newVersion/components/formatEl/TextEl.vue

@@ -72,7 +72,8 @@ export default {
     };
   },
   watch:{
-    content(con) {
+    async content(con) {
+      await this.$nextTick();
       const { elementId } = this.$refs.editor;
       if (this.initFlag) {
         //不会触发contentWatch但是会改变getContent

+ 39 - 1
src/views/ppt_manage/newVersion/pptEditor.vue

@@ -232,6 +232,9 @@
               <div v-show="tabsactive == '语义分析插入'" class="chart-tool flex-column">
                 <InsertSemantics />
               </div>
+              <div v-show="tabsactive == '知识资源'" class="chart-tool flex-column">
+                <insert-knowledge />
+              </div>
             </div>
             <!-- 图层编辑 -->
             <div class="layer-edit-box" v-if="isEditLayer && !isVersionHistory">
@@ -345,6 +348,7 @@ import { dataBaseInterface ,sandInterface } from "@/api/api.js";
 import futuresInterface from '@/api/modules/futuresBaseApi';
 import chartRelevanceApi from '@/api/modules/chartRelevanceApi';
 import { fittingEquationInterface,statisticFeatureInterface,crossVarietyInterface } from '@/api/modules/chartRelevanceApi';
+import { eventInterface } from "@/api/modules/knowledge";
 import pptmixin from '../mixins/pptMixins';
 import {uploadFileDirect} from "@/utils/common.js"
 import mixins from '../mixins/mixins';
@@ -368,6 +372,7 @@ import addMyClassifyDia from '@/views/dataEntry_manage/components/addMyClassifyD
 import InsertCharts from './components/editor/InsertCharts.vue';
 import ContextMenu from './components/ContextMenu.vue';
 import InsertSemantics from './components/editor/InsertSemantics.vue';
+import InsertKnowledge from './components/editor/InsertKnowledge.vue'
 import ChooseCoverNew from './components/editor/ChooseCoverNew.vue';
 import TitleEditorTool from './components/editor/TitleEditorTool';
 import selectImage from './components/selectImage.vue';
@@ -381,7 +386,7 @@ export default {
   components: {
     IndexItem, ChooseCover, AddFormat, ShapePreview,
     LayerEditTool, DeletePageDialog, ChangeFormatDialog, InsertPageDialog, addMyClassifyDia, InsertCharts, ContextMenu, InsertSemantics,
-    ChooseCoverNew, TitleEditorTool,selectImage, VersionRecord
+    ChooseCoverNew, TitleEditorTool,selectImage, VersionRecord,InsertKnowledge
 },
   data() {
     return {
@@ -449,6 +454,7 @@ export default {
         {val:'图表',label:this.$t('Slides.table_chart') },
         {val:'沙盘', label:this.$t('Slides.sandbox_name')},
         {val:'表格', label:this.$t('Slides.table_name')},
+        {val:'知识资源',label:'知识资源'}
       ]
     },  
     
@@ -952,6 +958,38 @@ export default {
 				this.getSandTable()
 			}
 		},200),
+    //点击右侧知识资源
+    chooseKnowledge:_.throttle(async function(item){
+      if(this.pageList.length===0||!this.currentItem){
+        this.$message.warning(this.$t('Slides.please_add_page_msg') );
+        return;
+      }
+      if(this.isChartLoading) return
+      await this.$nextTick();
+      // 判断当前页是否有文本元素框
+      let v = defaultPosition[this.currentItem.modelId];
+      if(!v) return;
+      let arr = Object.entries(v);
+      let textItem = arr.find(_=>_[1].type=="text");
+      if(!textItem) return this.$message.warning('该页PPT无文本位置,无法插入');
+      //寻找目标文本元素框
+      let i = this.pageList.findIndex(_=>_.id == this.currentItem.id);
+      let pageItemDom = this.$refs[`pptPage_${i}`] ? this.$refs[`pptPage_${i}`][0] : null;
+      if(!pageItemDom) return;
+      let textItemDom = pageItemDom.$refs[`${textItem[1].type}_${i}_${+textItem[0]}`];
+      if(!textItemDom) return;
+
+      this.isChartLoading = true;
+      const res = await eventInterface.getEventDetail({
+            ResourceType: item.ResourceType,
+            KnowledgeResourceId: item.KnowledgeResourceId
+      });
+      this.isChartLoading = false;
+      if(res.Ret != 200) return;
+      let content = res.Data.Content || '';
+      let allContent = `<p>${item.Title}</p>${content}`;
+      textItemDom.content += allContent;
+    },300),
     //点击右侧图表/沙盘图/表格
     chooseChart:_.throttle(async function(item,type){
       const noAuthMsg = {

+ 481 - 0
src/views/report_manage/reportV2/normalReport/components/KnowResource.vue

@@ -0,0 +1,481 @@
+<template>
+  <div class="know-resource-wrap">
+    <div class="top-box">
+      <div class="left-card">
+        <span
+          :class="['item', ResourceType === item.type ? 'active' : '']"
+          @click="activeTypeChange(item)"
+          v-for="item in typeOpts"
+          :key="item.type"
+          >{{ item.title }}</span
+        >
+      </div>
+      <div style="display: flex;align-items: center;">
+          <el-input
+            @input="filterChange"
+            placeholder="请输入标题"
+            v-model="filterForm.keyWord"
+            clearable
+            style="width: 240px"
+            prefix-icon="el-icon-search"
+          />
+
+          <el-popover
+            placement="bottom"
+            trigger="click"
+            :visible-arrow="false"
+            popper-class="report-select-popover"
+            width="350"
+            style="display: inline-block"
+          >
+            <div class="select-wrap-know">
+              <div class="select-top">
+                <h4>筛选条件</h4>
+                <span @click="handleClearFilter" style="cursor: pointer"
+                  ><i
+                    class="el-icon-delete"
+                    style="margin-right: 4px"
+                  />清空所选条件</span
+                >
+              </div>
+              <div class="select-item">
+                <el-cascader
+                  v-model="filterForm.classifys"
+                  :options="classifyOptions"
+                  :props="{
+                    value: 'ClassifyId',
+                    label: 'ClassifyName',
+                    children: 'Child',
+                    emitPath: false,
+                    multiple: true,
+                  }"
+                  :show-all-levels="false"
+                  clearable
+                  placeholder="请选择分类"
+                  style="width: 100%"
+                  @change="filterChange"
+                ></el-cascader>
+              </div>
+              <div class="select-item">
+                <el-select
+                  v-model="filterForm.sources"
+                  placeholder="请选择来源"
+                  size="medium"
+                  clearable
+                  style="width: 100%"
+                  multiple
+                  @change="filterChange"
+                >
+                  <el-option
+                    v-for="item in sourcesOptions"
+                    :key="item"
+                    :label="item"
+                    :value="item"
+                  />
+                </el-select>
+              </div>
+
+              <div class="select-item">
+                <el-select
+                  v-model="filterForm.tags"
+                  placeholder="请选择标签"
+                  size="medium"
+                  clearable
+                  style="width: 100%"
+                  multiple
+                  @change="filterChange"
+                >
+                  <el-option
+                    v-for="item in tagsOptions"
+                    :key="item.TagId"
+                    :label="item.TagName"
+                    :value="item.TagId"
+                  />
+                </el-select>
+              </div>
+
+              <div class="select-item">
+                <el-select
+                  v-model="filterForm.users"
+                  placeholder="请选择用户"
+                  size="medium"
+                  clearable
+                  style="width: 100%"
+                  multiple
+                  @change="filterChange"
+                >
+                  <el-option
+                    v-for="item in usersOptions"
+                    :key="item.AdminId"
+                    :label="item.AdminRealName"
+                    :value="item.AdminId"
+                  />
+                </el-select>
+              </div>
+            </div>
+            <div class="select-btn" slot="reference">
+              <img src="~@/assets/icons/filter.svg" />
+              <span class="select-num">
+                <span class="circle-rect"></span>
+                <span>{{ selectNum }}</span>
+              </span>
+              <span style="margin-left: 4px;">筛选条件</span>
+            </div>
+          </el-popover>
+        </div>
+    </div>
+
+    <div class="main-box">
+      <div class="dialog-top">
+          <el-checkbox v-model="filterForm.IsShowMe" @change="filterChange"
+            >只看我的</el-checkbox
+          >
+      </div>
+
+      <div style="flex: 1; overflow: hidden">
+        <div
+          class="list-wrap"
+          v-infinite-scroll="handleLoadMore"
+          :infinite-scroll-immediate="true"
+          infinite-scroll-distance="10"
+        >
+          <div
+            class="card-item"
+            v-for="item in tableData"
+            :key="item.KnowledgeResourceId"
+            @click="$emit('insertHtml',item)"
+          >
+            <div class="title">{{ item.Title }}</div>
+            <div class="content">{{ item.Content }}</div>
+            <div class="time">时间:{{ item.StartTime }}</div>
+            <div class="source">来源:{{ item.SourceFrom }}</div>
+          </div>
+          <tableNoData
+            :text="$t('Table.prompt_slogan')"
+            size="mini"
+            v-if="tableData.length === 0 && isEnd"
+          />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { eventInterface } from "@/api/modules/knowledge";
+export default {
+  data() {
+    return {
+      ResourceType: 0,
+      filterForm: {
+        pageNo: 1,
+        pageSize: 30,
+        classifys: [],
+        sources: [],
+        tags: [],
+        users: [],
+        keyWord: "",
+        IsShowMe: false,
+      },
+      classifyOptions: [],
+      sourcesOptions: [],
+      tagsOptions: [],
+      usersOptions: [],
+      tableData: [],
+      dataLoading: false,
+      isEnd: false,
+    };
+  },
+  computed: {
+    selectNum() {
+      let num = 0;
+      this.filterForm.classifys.length && num++;
+      this.filterForm.sources.length && num++;
+      this.filterForm.tags.length && num++;
+      this.filterForm.users.length && num++;
+      return num;
+    },
+    typeOpts() {
+      return [
+        { type: 0, title: "事件库" },
+        { type: 1, title: "政策库" },
+        { type: 2, title: "报告库" },
+        { type: 3, title: "知识库" },
+      ];
+    },
+  },
+
+  created() {
+    this.getFilters();
+    this.getTableData();
+  },
+
+  methods: {
+    getFilters() {
+      this.getClassifyOptions();
+      this.getSourceOptions();
+      this.getTagOptions();
+      this.getUsersOptions();
+    },
+    async getTableData() {
+      const {
+        pageNo,
+        pageSize,
+        classifys,
+        sources,
+        tags,
+        users,
+        keyWord,
+        IsShowMe,
+      } = this.filterForm;
+      let params = {
+        PageSize: pageSize,
+        CurrentIndex: pageNo,
+        ClassifyIds: classifys.join(","),
+        SysUserIds: users.join(","),
+        TagIds: tags.join(","),
+        Keyword: keyWord,
+        SourceFrom: sources.join(","),
+        ResourceType: this.ResourceType,
+        IncludeFile: "no",
+        IsShowMe,
+      };
+      this.dataLoading = true;
+      const res = await eventInterface.getEventListByES(params);
+
+      this.dataLoading = false;
+      if (res.Ret !== 200) return;
+
+      let dataList = res.Data.List || [];
+      this.tableData =
+        pageNo == 1 ? dataList : [...this.tableData, ...dataList];
+      this.isEnd = res.Data.Paging.IsEnd;
+    },
+    handleLoadMore() {
+      if (this.isEnd || this.dataLoading) return;
+      this.filterForm.pageNo++;
+      this.getTableData();
+    },
+    filterChange() {
+      this.filterForm.pageNo = 1;
+      this.tableData = [];
+      this.getTableData();
+    },
+    handleClearFilter() {
+      this.filterForm.classifys = [];
+      this.filterForm.sources = [];
+      this.filterForm.tags = [];
+      this.filterForm.users = [];
+      this.filterChange();
+    },
+    activeTypeChange(item) {
+      this.ResourceType = item.type;
+      this.dataInit();
+      this.getFilters();
+      this.getTableData();
+    },
+    dataInit() {
+      this.filterForm.pageNo = 1;
+      this.filterForm.classifys = [];
+      this.filterForm.sources = [];
+      this.filterForm.tags = [];
+      this.filterForm.users = [];
+      this.isEnd = false;
+      this.tableData = [];
+    },
+    async getClassifyOptions() {
+      const res = await eventInterface.getClassify({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.classifyOptions = res.Data.List || [];
+    },
+    async getSourceOptions() {
+      const res = await eventInterface.getSourcesList({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.sourcesOptions = res.Data.List || [];
+    },
+    async getTagOptions() {
+      const res = await eventInterface.getTagList({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.tagsOptions = res.Data.List || [];
+    },
+    async getUsersOptions() {
+      const res = await eventInterface.getUsersList({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.usersOptions = res.Data.List || [];
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+div {
+  box-sizing: border-box;
+}
+.know-resource-wrap {
+  .top-box {
+    .left-card {
+      margin-bottom: 15px;
+      border-radius: 4px;
+      border: 1px solid var(--unnamed, #dcdfe6);
+      background: var(--gary-gy-3-disabled, #ebeff6);
+      display: inline-flex;
+      flex-wrap: wrap;
+      align-items: center;
+      gap: 0 3px;
+      padding: 6px;
+      .item {
+        cursor: pointer;
+        display: block;
+        width: 110px;
+        height: 30px;
+        line-height: 30px;
+        text-align: center;
+        border-radius: 4px;
+        font-size: 18px;
+        color: #666;
+        &.active {
+          background: #fff;
+          color: #002d78;
+        }
+      }
+    }
+    .select-btn {
+        cursor: pointer;
+        width: 140px;
+        height: 40px;
+        background-color: #ecf2fe;
+        border-radius: 4px;
+        box-sizing: border-box;
+        margin-left: 20px;
+        box-sizing: border-box;
+        border: 1px solid #0052D9;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        img,
+        span {
+          display: inline-block;
+          vertical-align: middle;
+        }
+        .select-num {
+          margin-left: 10px;
+          color: #0052d9;
+          font-size: 14px;
+          font-weight: 500;
+          margin-right: 2px;
+          .circle-rect {
+            display: inline-block;
+            width: 4px;
+            height: 4px;
+            border-radius: 50%;
+            background-color: #0052d9;
+          }
+        }
+      }
+  }
+
+  .main-box {
+    margin-top: 30px;
+    height: calc(100vh - 260px);
+    border-radius: 4px;
+    border: 1px solid var(--gary-gy-5-line, #c8cdd9);
+    background: #fff;
+    padding: 20px;
+    display: flex;
+    flex-direction: column;
+    .dialog-top {
+      padding: 5px 15px 0;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+    }
+    .list-wrap {
+      height: 100%;
+      overflow-y: auto;
+      display: flex;
+      flex-wrap: wrap;
+      align-content: flex-start;
+      gap: 0 20px;
+      .card-item {
+        cursor: pointer;
+        width: 266px;
+        height: 200px;
+        border: 1px solid #c8cdd9;
+        border-radius: 4px;
+        margin-top: 20px;
+        padding: 10px;
+        .title {
+          color: #000000;
+          height: 47px;
+          font-weight: 500;
+          font-size: 16px;
+          font-weight: 400;
+          line-height: 22px;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          display: -webkit-box;
+          -webkit-box-orient: vertical;
+          -webkit-line-clamp: 2;
+        }
+        .content {
+          margin-top: 10px;
+          line-height: 20px;
+          font-size: 14px;
+          color: #666666;
+          height: 62px;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          display: -webkit-box;
+          -webkit-box-orient: vertical;
+          -webkit-line-clamp: 3;
+        }
+        .time,
+        .source {
+          margin-top: 10px;
+          color: #666666;
+          line-height: 20px;
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
+        }
+      }
+    }
+  }
+}
+</style>
+<style lang="scss">
+.select-wrap-know {
+  padding: 8px;
+  margin: 0 20px;
+  .select-top {
+    display: flex;
+    justify-content: space-between;
+    > span {
+      color: #999;
+    }
+  }
+  .select-item {
+    margin-top: 20px;
+  }
+  .select-bot {
+    display: flex;
+    justify-content: center;
+    margin-top: 20px;
+    .el-button {
+      width: 120px;
+    }
+  }
+}
+</style>

+ 5 - 1
src/views/report_manage/reportV2/normalReport/components/insertContent.vue

@@ -21,6 +21,9 @@
     <SemanticAnalysis v-if="actTab==='semanticAnalysis'" @insertHtml="item => {$emit('insertHtml',{item,type:'image'})}"/>
     <!-- 版本记录 -->
     <VersionRecord v-if="actTab==='versionRecord'" ref="version" :selectChapterId="selectChapterId" @handleRestore="handleRestore"/>
+    <!-- 知识资源 -->
+    <KnowResource v-if="actTab==='knowledgeResources'" @insertHtml="item => {$emit('insertHtml',{item,type:'knowledge'})}"/>
+
   </div>
 </template>
 <script>
@@ -31,6 +34,7 @@ import ETAPriceChart from './ETAPriceChart.vue'
 import ETASandBox from './ETASandBox.vue'
 import SemanticAnalysis from './SemanticAnalysis.vue'
 import VersionRecord from './VersionRecord.vue'
+import KnowResource from './KnowResource.vue'
 export default {
   props: {
     actTab: {
@@ -40,7 +44,7 @@ export default {
       type: Number
     }
   },
-  components: {ETAChart,ETASheet,StatisticAnalysis,ETAPriceChart,ETASandBox,SemanticAnalysis,VersionRecord},
+  components: {ETAChart,ETASheet,StatisticAnalysis,ETAPriceChart,ETASandBox,SemanticAnalysis,VersionRecord,KnowResource},
   data() {
     return {
     }

+ 7 - 2
src/views/report_manage/reportV2/normalReport/editReport.vue

@@ -203,7 +203,7 @@ export default {
 		window.addEventListener('message',this.reInitIframe)
 	},
 	updated() {
-		$('#leftfroala').find('p').css({ fontSize: '16px',width:'100%'});
+		this.setFroalaFontSize(16);
 	},
 	destroyed() {
 		window.removeEventListener('message',this.reInitIframe)
@@ -213,6 +213,11 @@ export default {
 	},
 
 	methods: {
+	    setFroalaFontSize(fontSize){
+		  this.$nextTick(() => {
+		    $('#leftfroala').find('p').css({ fontSize: `${fontSize}px`,width:'100%'}); 
+		  })
+		},
 		/* 当前章节信息 */
 		handleChapterInfo({ selectChapterId,editChapterId }) {
 			this.timer && clearInterval(this.timer);
@@ -718,5 +723,5 @@ export default {
 		height: 0;
 	}
 	.el-tabs__item { font-size: 16px; }
-}	
+} 
 </style>

+ 23 - 1
src/views/report_manage/reportV2/normalReport/mixins/reportMixin.js

@@ -7,6 +7,7 @@ import {
   statisticFeatureInterface,
   crossVarietyInterface
 } from "@/api/modules/chartRelevanceApi";
+import { eventInterface } from '@/api/modules/knowledge';
 export default {
   watch:{
     'taskTime'(){
@@ -86,6 +87,11 @@ export default {
             //     type:'semanticAnalysis',
             //     icon:require('@/assets/img/smartReport/icon09.png')
             // }
+            {
+              name:'知识资源',
+              type:'knowledgeResources',
+              icon:require('@/assets/img/smartReport/know-resource-icon.png')
+            },
           ]
       },
       
@@ -258,7 +264,7 @@ export default {
         'chart': this.$t('MsgPrompt.no_chart_auth'),
         'sheet': this.$t('MsgPrompt.no_sheet_auth')
       }
-      if(!item.HaveOperaAuth&&noAuthMsg[type]) return this.$message.warning(noAuthMsg[type])
+      if(type!='knowledge'&&!item.HaveOperaAuth&&noAuthMsg[type]) return this.$message.warning(noAuthMsg[type])
 
       //设置编辑器获取焦点
       this.editor.events.focus();
@@ -275,6 +281,7 @@ export default {
         image: this.insertImage,
         chart: this.insertChart,
         sheet: this.insertSheet,
+        knowledge:this.insertKnowledge,
       };
       insertMap[type](item);
       this.lastEditRange = selection.getRangeAt(0);
@@ -289,6 +296,21 @@ export default {
       });
     },
 
+    /* 插入知识资源 */
+    async insertKnowledge(item){
+      const res = await eventInterface.getEventDetail({
+        ResourceType: item.ResourceType,
+        KnowledgeResourceId: item.KnowledgeResourceId
+      });
+      if(res.Ret != 200) return;
+      let content = res.Data.Content || '';
+      let allContent = `<p>${item.Title}</p>${content}`
+      await this.$nextTick();
+      this.editor.html.insert(allContent);
+      await this.$nextTick();
+      this.setFroalaFontSize && this.setFroalaFontSize(16);
+    },
+
     /* 插入图表 */
     insertChart(item) {
       if (item.Disabled)

+ 501 - 0
src/views/report_manage/reportV2/smartReport/components/KnowResource.vue

@@ -0,0 +1,501 @@
+<template>
+  <div class="know-resource-wrap">
+    <div class="top-box">
+      <div class="left-card">
+        <span
+          :class="['item', ResourceType === item.type ? 'active' : '']"
+          @click="activeTypeChange(item)"
+          v-for="item in typeOpts"
+          :key="item.type"
+          >{{ item.title }}</span
+        >
+      </div>
+      <div style="display: flex;align-items: center;">
+          <el-input
+            @input="filterChange"
+            placeholder="请输入标题"
+            v-model="filterForm.keyWord"
+            clearable
+            style="width: 240px"
+            prefix-icon="el-icon-search"
+          />
+
+          <el-popover
+            placement="bottom"
+            trigger="click"
+            :visible-arrow="false"
+            popper-class="report-select-popover"
+            width="350"
+            style="display: inline-block"
+          >
+            <div class="select-wrap-know">
+              <div class="select-top">
+                <h4>筛选条件</h4>
+                <span @click="handleClearFilter" style="cursor: pointer"
+                  ><i
+                    class="el-icon-delete"
+                    style="margin-right: 4px"
+                  />清空所选条件</span
+                >
+              </div>
+              <div class="select-item">
+                <el-cascader
+                  v-model="filterForm.classifys"
+                  :options="classifyOptions"
+                  :props="{
+                    value: 'ClassifyId',
+                    label: 'ClassifyName',
+                    children: 'Child',
+                    emitPath: false,
+                    multiple: true,
+                  }"
+                  :show-all-levels="false"
+                  clearable
+                  placeholder="请选择分类"
+                  style="width: 100%"
+                  @change="filterChange"
+                ></el-cascader>
+              </div>
+              <div class="select-item">
+                <el-select
+                  v-model="filterForm.sources"
+                  placeholder="请选择来源"
+                  size="medium"
+                  clearable
+                  style="width: 100%"
+                  multiple
+                  @change="filterChange"
+                >
+                  <el-option
+                    v-for="item in sourcesOptions"
+                    :key="item"
+                    :label="item"
+                    :value="item"
+                  />
+                </el-select>
+              </div>
+
+              <div class="select-item">
+                <el-select
+                  v-model="filterForm.tags"
+                  placeholder="请选择标签"
+                  size="medium"
+                  clearable
+                  style="width: 100%"
+                  multiple
+                  @change="filterChange"
+                >
+                  <el-option
+                    v-for="item in tagsOptions"
+                    :key="item.TagId"
+                    :label="item.TagName"
+                    :value="item.TagId"
+                  />
+                </el-select>
+              </div>
+
+              <div class="select-item">
+                <el-select
+                  v-model="filterForm.users"
+                  placeholder="请选择用户"
+                  size="medium"
+                  clearable
+                  style="width: 100%"
+                  multiple
+                  @change="filterChange"
+                >
+                  <el-option
+                    v-for="item in usersOptions"
+                    :key="item.AdminId"
+                    :label="item.AdminRealName"
+                    :value="item.AdminId"
+                  />
+                </el-select>
+              </div>
+            </div>
+            <div class="select-btn" slot="reference">
+              <img src="~@/assets/icons/filter.svg" />
+              <span class="select-num">
+                <span class="circle-rect"></span>
+                <span>{{ selectNum }}</span>
+              </span>
+              <span style="margin-left: 4px;">筛选条件</span>
+            </div>
+          </el-popover>
+        </div>
+    </div>
+
+    <div class="main-box">
+      <div class="dialog-top">
+          <el-checkbox v-model="filterForm.IsShowMe" @change="filterChange"
+            >只看我的</el-checkbox
+          >
+      </div>
+
+      <div style="flex: 1; overflow: hidden">
+        <div
+          class="list-wrap"
+          v-infinite-scroll="handleLoadMore"
+          :infinite-scroll-immediate="true"
+          infinite-scroll-distance="10"
+        >
+          <draggable
+            :list="tableData"
+            :group="{ name: 'component', pull: 'clone', put: false }"
+            class="knowledge-list-box"
+            animation="300"
+            :sort="false"
+            tag="div"
+          >
+            <div
+              class="card-item"
+              v-for="item in tableData"
+              :key="item.KnowledgeResourceId"
+              :comp-data="getCompData(item)"
+            >
+              <div class="title">{{ item.Title }}</div>
+              <div class="content">{{ item.Content }}</div>
+              <div class="time">时间:{{ item.StartTime }}</div>
+              <div class="source">来源:{{ item.SourceFrom }}</div>
+            </div>
+          </draggable>
+          <tableNoData
+            :text="$t('Table.prompt_slogan')"
+            size="mini"
+            v-if="tableData.length === 0 && isEnd"
+          />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { eventInterface } from "@/api/modules/knowledge";
+export default {
+  data() {
+    return {
+      ResourceType: 0,
+      filterForm: {
+        pageNo: 1,
+        pageSize: 30,
+        classifys: [],
+        sources: [],
+        tags: [],
+        users: [],
+        keyWord: "",
+        IsShowMe: false,
+      },
+      classifyOptions: [],
+      sourcesOptions: [],
+      tagsOptions: [],
+      usersOptions: [],
+      tableData: [],
+      dataLoading: false,
+      isEnd: false,
+    };
+  },
+  computed: {
+    selectNum() {
+      let num = 0;
+      this.filterForm.classifys.length && num++;
+      this.filterForm.sources.length && num++;
+      this.filterForm.tags.length && num++;
+      this.filterForm.users.length && num++;
+      return num;
+    },
+    typeOpts() {
+      return [
+        { type: 0, title: "事件库" },
+        { type: 1, title: "政策库" },
+        { type: 2, title: "报告库" },
+        { type: 3, title: "知识库" },
+      ];
+    },
+  },
+
+  created() {
+    this.getFilters();
+    this.getTableData();
+  },
+
+  methods: {
+    getCompData(item) {
+      const obj = {
+        compId: 5,
+        compType: "knowledge",
+        content: '',
+        compItem:item,
+      };
+      return JSON.stringify(obj);
+    },
+    getFilters() {
+      this.getClassifyOptions();
+      this.getSourceOptions();
+      this.getTagOptions();
+      this.getUsersOptions();
+    },
+    async getTableData() {
+      const {
+        pageNo,
+        pageSize,
+        classifys,
+        sources,
+        tags,
+        users,
+        keyWord,
+        IsShowMe,
+      } = this.filterForm;
+      let params = {
+        PageSize: pageSize,
+        CurrentIndex: pageNo,
+        ClassifyIds: classifys.join(","),
+        SysUserIds: users.join(","),
+        TagIds: tags.join(","),
+        Keyword: keyWord,
+        SourceFrom: sources.join(","),
+        ResourceType: this.ResourceType,
+        IncludeFile: "no",
+        IsShowMe,
+      };
+      this.dataLoading = true;
+      const res = await eventInterface.getEventListByES(params);
+
+      this.dataLoading = false;
+      if (res.Ret !== 200) return;
+
+      let dataList = res.Data.List || [];
+      this.tableData =
+        pageNo == 1 ? dataList : [...this.tableData, ...dataList];
+      this.isEnd = res.Data.Paging.IsEnd;
+    },
+    handleLoadMore() {
+      if (this.isEnd || this.dataLoading) return;
+      this.filterForm.pageNo++;
+      this.getTableData();
+    },
+    filterChange() {
+      this.filterForm.pageNo = 1;
+      this.tableData = [];
+      this.getTableData();
+    },
+    handleClearFilter() {
+      this.filterForm.classifys = [];
+      this.filterForm.sources = [];
+      this.filterForm.tags = [];
+      this.filterForm.users = [];
+      this.filterChange();
+    },
+    activeTypeChange(item) {
+      this.ResourceType = item.type;
+      this.dataInit();
+      this.getFilters();
+      this.getTableData();
+    },
+    dataInit() {
+      this.filterForm.pageNo = 1;
+      this.filterForm.classifys = [];
+      this.filterForm.sources = [];
+      this.filterForm.tags = [];
+      this.filterForm.users = [];
+      this.isEnd = false;
+      this.tableData = [];
+    },
+    async getClassifyOptions() {
+      const res = await eventInterface.getClassify({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.classifyOptions = res.Data.List || [];
+    },
+    async getSourceOptions() {
+      const res = await eventInterface.getSourcesList({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.sourcesOptions = res.Data.List || [];
+    },
+    async getTagOptions() {
+      const res = await eventInterface.getTagList({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.tagsOptions = res.Data.List || [];
+    },
+    async getUsersOptions() {
+      const res = await eventInterface.getUsersList({
+        ResourceType: this.ResourceType,
+      });
+      if (res.Ret !== 200) return;
+
+      this.usersOptions = res.Data.List || [];
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+div {
+  box-sizing: border-box;
+}
+.know-resource-wrap {
+  .top-box {
+    .left-card {
+      margin-bottom: 15px;
+      border-radius: 4px;
+      border: 1px solid var(--unnamed, #dcdfe6);
+      background: var(--gary-gy-3-disabled, #ebeff6);
+      display: inline-flex;
+      flex-wrap: wrap;
+      align-items: center;
+      gap: 0 3px;
+      padding: 6px;
+      .item {
+        cursor: pointer;
+        display: block;
+        width: 110px;
+        height: 30px;
+        line-height: 30px;
+        text-align: center;
+        border-radius: 4px;
+        font-size: 18px;
+        color: #666;
+        &.active {
+          background: #fff;
+          color: #002d78;
+        }
+      }
+    }
+    .select-btn {
+        cursor: pointer;
+        width: 140px;
+        height: 40px;
+        background-color: #ecf2fe;
+        border-radius: 4px;
+        box-sizing: border-box;
+        margin-left: 20px;
+        box-sizing: border-box;
+        border: 1px solid #0052D9;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        img,
+        span {
+          display: inline-block;
+          vertical-align: middle;
+        }
+        .select-num {
+          margin-left: 10px;
+          color: #0052d9;
+          font-size: 14px;
+          font-weight: 500;
+          margin-right: 2px;
+          .circle-rect {
+            display: inline-block;
+            width: 4px;
+            height: 4px;
+            border-radius: 50%;
+            background-color: #0052d9;
+          }
+        }
+      }
+  }
+
+  .main-box {
+    margin-top: 30px;
+    height: calc(100vh - 240px);
+    border-radius: 4px;
+    border: 1px solid var(--gary-gy-5-line, #c8cdd9);
+    background: #fff;
+    padding: 20px;
+    display: flex;
+    flex-direction: column;
+    .dialog-top {
+      padding: 5px 15px 0;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+    }
+    .list-wrap {
+      height: 100%;
+      overflow-y: auto;
+      .knowledge-list-box {
+        display: flex;
+        flex-wrap: wrap;
+        align-content: flex-start;
+        gap: 0 20px;
+      }
+      .card-item {
+        cursor: pointer;
+        width: 266px;
+        height: 200px;
+        border: 1px solid #c8cdd9;
+        border-radius: 4px;
+        margin-top: 20px;
+        padding: 10px;
+        .title {
+          color: #000000;
+          height: 47px;
+          font-weight: 500;
+          font-size: 16px;
+          font-weight: 400;
+          line-height: 22px;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          display: -webkit-box;
+          -webkit-box-orient: vertical;
+          -webkit-line-clamp: 2;
+        }
+        .content {
+          margin-top: 10px;
+          line-height: 20px;
+          font-size: 14px;
+          color: #666666;
+          height: 62px;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          display: -webkit-box;
+          -webkit-box-orient: vertical;
+          -webkit-line-clamp: 3;
+        }
+        .time,
+        .source {
+          margin-top: 10px;
+          color: #666666;
+          line-height: 20px;
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
+        }
+      }
+    }
+  }
+}
+</style>
+<style lang="scss">
+.select-wrap-know {
+  padding: 8px;
+  margin: 0 20px;
+  .select-top {
+    display: flex;
+    justify-content: space-between;
+    > span {
+      color: #999;
+    }
+  }
+  .select-item {
+    margin-top: 20px;
+  }
+  .select-bot {
+    display: flex;
+    justify-content: center;
+    margin-top: 20px;
+    .el-button {
+      width: 120px;
+    }
+  }
+}
+</style>

+ 20 - 0
src/views/report_manage/reportV2/smartReport/components/KnowResourceComp.vue

@@ -0,0 +1,20 @@
+<template>
+  <div 
+      class="report-comp-item knowledge-comp" 
+      style="width:100%;height: 100%;overflow-y: auto;"
+  >
+      <div class="rich-text-box" v-html="compData.content"></div>
+  </div>
+</template>
+
+<script>
+export default {
+  props:{
+      compData:{}
+  },
+}
+</script>
+
+<style>
+
+</style>

+ 42 - 10
src/views/report_manage/reportV2/smartReport/editReport.vue

@@ -188,7 +188,7 @@
                         <div :style="rightType !=='versionRecord' ? 'overflow-x:auto;height:calc(100% + 12px);' : 'overflow-x:auto;'">
                         <div :style="rightType !=='versionRecord' ? 'height: 100%;' : 'height: 100%;'">
                         <TextEdit 
-                            v-if="rightType==='text'"
+                            v-if="rightType==='text' || rightType==='knowledge'"
                             :key="activeId"
                             :content="activeContent" 
                             @textChange="handleTextChange" 
@@ -218,6 +218,8 @@
                         <VersionRecord v-if="rightType==='versionRecord'" ref="version" :selectChapterId="selectChapterId" @handleRestore="handleRestore"/>
                         <!-- 版图资源库 -->
                         <ImgSource v-if="rightType==='imgSource'" @change="handleInsertImgSource" @close="handleCloseRight"/>
+                        <!-- 知识资源 -->
+                        <KnowResource v-if="rightType==='knowledgeResources'"/>
                         </div>
                         </div>
                     </div>
@@ -274,6 +276,8 @@ import TextEdit from './components/TextEdit.vue'
 import ImgEdit from './components/ImgEdit.vue'
 import ETAChart from './components/ETAChart.vue'
 import ETASheet from './components/ETASheet.vue'
+import KnowResourceComp from "./components/KnowResourceComp.vue"
+import KnowResource from "./components/KnowResource.vue"
 import { getPublicSettingsApi } from '@/api/modules/oldApi';
 import { dataBaseInterface } from "@/api/api.js";
 import {
@@ -304,6 +308,7 @@ import chapterWrapper from '../components/chapterEditWrapper.vue';
 import smartReportDetail from './reportDetail.vue'
 import { GetQueryString } from '@/utils/common'
 import { reportV2Interface } from '@/api/modules/reportV2';
+import { eventInterface } from "@/api/modules/knowledge";
 export default {
     mixins:[reportApproveConfig],
     name:"smartReportEditV2",
@@ -326,7 +331,9 @@ export default {
         ImgSource,
         editHeader,
         chapterWrapper,
-        smartReportDetail
+        smartReportDetail,
+        KnowResource,
+        KnowResourceComp,
     },
     watch:{
         'taskTime'(){
@@ -542,7 +549,6 @@ export default {
 
         /* 表格标题可修改,保存时获取每个sheet最新的title存进conList */
         formatContentListElData() {
-            console.log(this.conList)
             let newList = this.conList.map(_ => {
                 if(_.child&&_.child.length) { //一行多个
                     return {
@@ -766,7 +772,7 @@ export default {
             });
         },
 
-        handleParentAdd(e){
+        async handleParentAdd(e){
             console.log('container-onAdd操作------------------->');
 
             const {item,newDraggableIndex}=e
@@ -793,18 +799,37 @@ export default {
                 style:compData.compType==='chart'?'height:350px':'',
                 child:[]
             }
+            //知识资源数据特殊处理
+            if(compData && compData.compId==5 && !compData.content && compData.compItem ){
+                const knowDetail = await eventInterface.getEventDetail({
+                    ResourceType: compData.compItem.ResourceType,
+                    KnowledgeResourceId: compData.compItem.KnowledgeResourceId
+                });
+                if(knowDetail.Ret != 200) return;
+                let content = knowDetail.Data.Content || '';
+                let allContent = `<p>${compData.compItem.Title}</p>${content}`
+                tempCompData.content = allContent;
+            }
             this.conList.splice(newDraggableIndex,1,tempCompData)
         },
 
-        handleChildAdd(e,parent,parentIndex){
+        async handleChildAdd(e,parent,parentIndex){
             console.log('child-onAdd操作------------------->');
             // console.log(parent);
             const {item,newDraggableIndex}=e
 
             const compData=JSON.parse(item.getAttribute('comp-data'))
-
-            console.log(compData,newDraggableIndex);
-
+            //知识资源数据特殊处理
+            if(compData && compData.compId===5 && !compData.content && compData.compItem ){
+                const knowDetail = await eventInterface.getEventDetail({
+                    ResourceType: compData.compItem.ResourceType,
+                    KnowledgeResourceId: compData.compItem.KnowledgeResourceId
+                });
+                if(knowDetail.Ret != 200) return;
+                let content = knowDetail.Data.Content || '';
+                let allContent = `<p>${compData.compItem.Title}</p>${content}`
+                compData.content = allContent;
+            };
             const index=parentIndex
             // if(index>-1){
                 let obj=_.cloneDeep(this.conList[index]) 
@@ -957,7 +982,7 @@ export default {
         // 当前再编辑哪个
         handleChoose(item,index,cindex){
             //{item:数据,index:父序号,cindex:子序号}
-            if(!item.id||this.isDragResize||!['text','img'].includes(item.compType)) return
+            if(!item.id||this.isDragResize||!['text','img','knowledge'].includes(item.compType)) return
             this.activeId=item.id
             this.showRight=true
             this.rightType=item.compType
@@ -991,7 +1016,8 @@ export default {
                 ['text',TextComp],
                 ['chart',ChartComp],
                 ['img',ImgComp],
-                ['sheet',SheetComp]
+                ['sheet',SheetComp],
+                ['knowledge',KnowResourceComp]
             ])
             return temMap.get(item.compType)
         },
@@ -1409,6 +1435,12 @@ export default {
                     visable:true,
                     icon:require('@/assets/img/smartReport/icon08.png')
                 },
+                {
+                    name:'知识资源',
+                    type:'knowledgeResources',
+                    visable:true,
+                    icon:require('@/assets/img/smartReport/know-resource-icon.png'),
+                },
             ]
       },