Bläddra i källkod

Merge branch 'toB_ETA1.2'

cxmo 1 år sedan
förälder
incheckning
544e034103
28 ändrade filer med 851 tillägg och 68 borttagningar
  1. 10 0
      src/api/modules/etaBaseConfigApi.js
  2. BIN
      src/assets/img/eta_base_config/company_1.jpg
  3. BIN
      src/assets/img/eta_base_config/disclaimer_1.jpg
  4. BIN
      src/assets/img/eta_base_config/disclaimer_2.jpg
  5. BIN
      src/assets/img/eta_base_config/mark_1.jpg
  6. BIN
      src/assets/img/eta_base_config/ppt_back.jpg
  7. BIN
      src/assets/img/eta_base_config/ppt_bgpic.jpg
  8. BIN
      src/assets/img/eta_base_config/ppt_cover.jpg
  9. 6 0
      src/routes/modules/oldRoutes.js
  10. 24 0
      src/views/ppt_manage/mixins/pptMixins.js
  11. 1 1
      src/views/ppt_manage/newVersion/components/Cover.vue
  12. 1 1
      src/views/ppt_manage/newVersion/components/CoverEn.vue
  13. 4 4
      src/views/ppt_manage/newVersion/components/catalog/pptContent.vue
  14. 4 3
      src/views/ppt_manage/newVersion/components/catalog/pptContentEn.vue
  15. 19 3
      src/views/ppt_manage/newVersion/components/editor/ChooseCover.vue
  16. 19 3
      src/views/ppt_manage/newVersion/components/editor/ChooseCoverEn.vue
  17. 3 1
      src/views/ppt_manage/newVersion/pptEditor.vue
  18. 3 1
      src/views/ppt_manage/newVersion/pptEnEditor.vue
  19. 11 6
      src/views/ppt_manage/newVersion/pptEnPresent.vue
  20. 25 19
      src/views/ppt_manage/newVersion/pptEnPublish.vue
  21. 11 6
      src/views/ppt_manage/newVersion/pptPresent.vue
  22. 25 19
      src/views/ppt_manage/newVersion/pptPublish.vue
  23. 17 0
      src/views/ppt_manage/newVersion/utils/untils.js
  24. 2 1
      src/views/semantics_manage/utils/config.js
  25. 44 0
      src/views/system_manage/components/configAnnotation.vue
  26. 92 0
      src/views/system_manage/components/imgThumbnail.vue
  27. 108 0
      src/views/system_manage/components/imgUpload.vue
  28. 422 0
      src/views/system_manage/etaBaseConfig.vue

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

@@ -0,0 +1,10 @@
+/* ETA-系统设置-基础配置 相关接口 */
+import http from "@/api/http.js"
+export const etaBaseConfigInterence = {
+    getBaseConfig:params=>{
+        return http.get('/business_conf/fetch',params)
+    },
+    saveBaseConfig:params=>{
+        return http.post('/business_conf/save',params)
+    }
+}

BIN
src/assets/img/eta_base_config/company_1.jpg


BIN
src/assets/img/eta_base_config/disclaimer_1.jpg


BIN
src/assets/img/eta_base_config/disclaimer_2.jpg


BIN
src/assets/img/eta_base_config/mark_1.jpg


BIN
src/assets/img/eta_base_config/ppt_back.jpg


BIN
src/assets/img/eta_base_config/ppt_bgpic.jpg


BIN
src/assets/img/eta_base_config/ppt_cover.jpg


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

@@ -293,6 +293,12 @@ export default [
         name: "英文权限配置",
         hidden: false,
       },
+      {
+        path: "etaBaseConfig",
+        component: () => import("@/views/system_manage/etaBaseConfig.vue"),
+        name: "基本配置",
+        hidden: true,
+      },
     ],
   },
 ];

+ 24 - 0
src/views/ppt_manage/mixins/pptMixins.js

@@ -3,6 +3,7 @@ import Highcharts from "highcharts/highstock";
 import HighchartszhCN  from '@/utils/highcahrts-zh_CN'
 HighchartszhCN(Highcharts)
 import { dataBaseInterface,pptInterface } from "@/api/api.js";
+import {etaBaseConfigInterence} from '@/api/modules/etaBaseConfigApi.js';
 import {pptEnInterface} from '@/api/modules/pptEnApi.js';
 import * as sheetInterface from '@/api/modules/sheetApi.js';
 import futuresInterface from '@/api/modules/futuresBaseApi';
@@ -37,6 +38,9 @@ export default {
       dataLoading:null,//getPptData loading
       pageLoading:null,//演示时,切换page需要加载图表数据
       publishLoading:null,//发布时loading
+      pptCoverList:[],//配置ppt封面
+      pptBgImage:'',
+      pptBackImage:'',
 
       setEnName:false,
       // 传入的formItem所需内容
@@ -52,6 +56,23 @@ export default {
     }
   },
   methods: {
+    //获取ppt配置
+    async getpptConfig(){
+        const res = await etaBaseConfigInterence.getBaseConfig()
+        if(res.Ret!==200) return 
+        const {CnPptCoverImgs,CnPptBackgroundImg,CnPptBottomImg,
+               EnPptCoverImgs,EnPptBackgroundImg,EnPptBottomImg,
+              } = res.Data
+        if(this.currentLang==='en'){
+            this.pptCoverList = EnPptCoverImgs.split(',')
+            this.pptBgImage = EnPptBackgroundImg
+            this.pptBackImage = EnPptBottomImg
+        }else{
+            this.pptCoverList = CnPptCoverImgs.split(',')
+            this.pptBgImage = CnPptBackgroundImg
+            this.pptBackImage = CnPptBottomImg
+        }
+    },
     //获取ppt详情
     async getpptDataById(id){
       const res = this.currentLang!=='en'?await pptInterface.getpptDetail({
@@ -710,5 +731,8 @@ export default {
 			})
 			this.setEnName = false
 		},
+  },
+  mounted(){
+    this.getpptConfig()
   }
 }

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

@@ -2,7 +2,7 @@
     <div class="flex-column cover" style="width:100%;" v-if="pageInfo">
         <!-- <img :src="pageInfo.BackgroundImg" class="pptbg" /> -->
         <!-- <img :src="base64Url" class="pptbg" /> -->
-        <img :src="pageInfo.imgLocalUrl.image_url" class="pptbg"  style="width:100%"/>
+        <img :src="pageInfo.BackgroundImg" class="pptbg"  style="width:100%"/>
         <div
         style="width:62%; font-size:16px; text-align:center; line-height:1.6; color:#fff; position:absolute; right:20px; top:50%;zIndex:20;">
         <p style="height:5px; border-top:1px solid #fff;marginBottom:21px;"></p>

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

@@ -1,6 +1,6 @@
 <template>
     <div class="flex-column cover" style="width:100%;" v-if="pageInfo">
-        <img :src="pageInfo.imgLocalUrl" class="pptbg"  style="width:100%"/>
+        <img :src="pageInfo.BackgroundImg" class="pptbg"  style="width:100%"/>
         <div
         style="width:62%; font-size:16px; text-align:center; line-height:1.6; color:#fff; position:absolute; right:20px; top:50%;zIndex:20;">
         <p style="height:5px; border-top:1px solid #fff;marginBottom:21px;"></p>

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

@@ -10,8 +10,8 @@
               <p>{{pptItem.PptxUrl?'发布':'保存'}}时间:{{$moment(pptTime).format('YYYY-MM-DD')}}</p>
             </div>
           </div>
-          <div class="ppt-item" id="back" v-else-if="isLoadBack&&item.name==='back'" :key="item.id">
-            <img src="~@/assets/img/pptlastimg.png" class="pptbg" />
+          <div class="ppt-item" id="back" v-else-if="isLoadBack&&item.name==='back'&&pptBackImage.length" :key="item.id">
+            <img :src="pptBackImage" class="pptbg" />
           </div>
           <div class="ppt-item" v-else :key="item.id">
               <div class="title-wrap" :title="item.title" 
@@ -158,6 +158,7 @@ export default {
       }
       this.$store.commit('SET_CHART_INFO_MAP',chartInfoMap)
       this.dataLoading.close();
+      $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
     },
     async getpptData(){
       const id = this.pptItem.PptId
@@ -261,7 +262,6 @@ export default {
       if($('.editor-content')[0]){
         $('.editor-content').css('transform',`scale(${this.contentScale})`)
       }
-      
     })
     window.onresize = ()=>{
       $('.ppt-item').css('height',$('.ppt-item').width()*0.7);
@@ -290,7 +290,7 @@ export default {
 .ppt-item{
   &#cover,&#back{
     overflow: hidden;
-    background:none;
+    background:none !important;
     img{
       width:100%;
     }

+ 4 - 3
src/views/ppt_manage/newVersion/components/catalog/pptContentEn.vue

@@ -9,8 +9,8 @@
               <p>{{pptItem.PptxUrl?'发布':'保存'}}时间:{{$moment(pptTime).format('YYYY-MM-DD')}}</p>
             </div>
           </div>
-          <div class="ppt-item" id="back" v-else-if="isLoadBack&&item.name==='back'" :key="item.id">
-            <img src="~@/assets/img/ppt_en_last.png" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
+          <div class="ppt-item" id="back" v-else-if="isLoadBack&&item.name==='back'&&pptBackImage.length" :key="item.id">
+            <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
           </div>
           <div class="ppt-item" v-else :key="item.id">
               <div class="title-wrap" :title="item.title" 
@@ -153,6 +153,7 @@ export default {
       }
       this.$store.commit('SET_CHART_INFO_MAP',chartInfoMap)
       this.dataLoading.close();
+      $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
     },
     async getpptData(){
       const id = this.pptItem.PptId
@@ -285,7 +286,7 @@ export default {
 .ppt-item{
   &#cover,&#back{
     overflow: hidden;
-    background:none;
+    background:none !important;
     img{
       width:100%;
     }

+ 19 - 3
src/views/ppt_manage/newVersion/components/editor/ChooseCover.vue

@@ -54,24 +54,40 @@ export default {
     props:{
         firstPage:{
             type:Object
+        },
+        pptCoverList:{
+            type:Array
         }
     },
     data() {
         return {
             bgListIndex:0,
             bgList:[],
-            pageData:{}
+            pageData:{},
+            searchIndex:0
         };
     },
     mounted(){
         $('.el-date-editor .el-input__inner').css({backgroundColor: 'transparent',border:'none',color:'#fff',textAlign:'center',fontSize:'16px'});
 		$('.el-date-editor .el-icon-date' ).css({display:'none'});
-        this.bgList = pptCover
-        this.bgListIndex = this.firstPage.BackIndex
+        this.bgList = this.pptCoverList
+        this.searchIndex = this.bgList.findIndex(i=>i===this.firstPage.BackgroundImg)
+        this.bgListIndex = this.searchIndex===-1?0:this.searchIndex
         this.pageData = _.cloneDeep(this.firstPage)
+        //如果之前配置的图片不在pptCoverList里,则默认选中第一个,防止图片挂掉
+        if(this.searchIndex===-1){
+            this.pageData.BackgroundImg = this.bgList[0]
+            this.pageData.ImgUrl = this.bgList[0]
+            this.pageData.BackIndex = 0
+        }
     },
     methods: {
         closeDialog(){
+            //如果之前配置的图片不在pptCoverList里 用保存强制替换封面图
+            if(this.searchIndex===-1){
+                this.firstPage = Object.assign(this.firstPage,this.pageData)
+                this.$emit('save',this.firstPage)
+            }
             this.$emit('close')
         },
         saveFirstPage(){

+ 19 - 3
src/views/ppt_manage/newVersion/components/editor/ChooseCoverEn.vue

@@ -55,24 +55,40 @@ export default {
     props:{
         firstPage:{
             type:Object
+        },
+        pptCoverList:{
+            type:Array
         }
     },
     data() {
         return {
             bgListIndex:0,
             bgList:[],
-            pageData:{}
+            pageData:{},
+            searchIndex:0
         };
     },
     mounted(){
         $('.el-date-editor .el-input__inner').css({backgroundColor: 'transparent',border:'none',color:'#fff',textAlign:'center',fontSize:'16px'});
 		$('.el-date-editor .el-icon-date' ).css({display:'none'});
-        this.bgList = pptCoverEn
-        this.bgListIndex = this.firstPage.BackIndex
+        this.bgList = this.pptCoverList
+        this.searchIndex = this.bgList.findIndex(i=>i===this.firstPage.BackgroundImg)
+        this.bgListIndex = this.searchIndex===-1?0:this.searchIndex
         this.pageData = _.cloneDeep(this.firstPage)
+        //如果之前配置的图片不在pptCoverList里,则默认选中第一个,防止图片挂掉
+        if(this.searchIndex===-1){
+            this.pageData.BackgroundImg = this.bgList[0]
+            this.pageData.ImgUrl = this.bgList[0]
+            this.pageData.BackIndex = 0
+        }
     },
     methods: {
         closeDialog(){
+            //如果之前配置的图片不在pptCoverList里 用保存强制替换封面图
+            if(this.searchIndex===-1){
+                this.firstPage = Object.assign(this.firstPage,this.pageData)
+                this.$emit('save',this.firstPage)
+            }
             this.$emit('close')
         },
         saveFirstPage(){

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

@@ -2,7 +2,7 @@
   <div class="page-wrap">
     <div class="index-wrap ppt-page-wrap flex-column">
         <div class="cover-wrap" @click="openChooseCover">
-            <div class="cover" :style="'background: no-repeat center/cover url('+bgList[firstPage.BackIndex].image_url+')'">
+            <div class="cover" :style="'background: no-repeat center/cover url('+firstPage.BackgroundImg+')'">
                 <img src="~@/assets/img/ppt_m/add_first.png" />
             </div>
             <p class="hint-text">选择封面页</p>
@@ -222,6 +222,7 @@
     <!-- 选择封面弹窗 -->
     <choose-cover  v-if="isShowChooseCover"
         :firstPage="firstPage"
+        :pptCoverList="pptCoverList"
         @close="closeChooseCover"
         @save="saveCover"
     />
@@ -427,6 +428,7 @@ export default {
         i.isUpdating = false
       })     
       this.dataLoading.close();
+      $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
     },
     async getpptData(){
       const {id} = this.$route.query

+ 3 - 1
src/views/ppt_manage/newVersion/pptEnEditor.vue

@@ -2,7 +2,7 @@
   <div class="page-wrap">
     <div class="index-wrap ppt-page-wrap flex-column">
         <div class="cover-wrap" @click="openChooseCover">
-            <div class="cover" :style="'background: no-repeat center/cover url('+bgList[firstPage.BackIndex].image_url+')'">
+            <div class="cover" :style="'background: no-repeat center/cover url('+firstPage.BackgroundImg+')'">
                 <img src="~@/assets/img/ppt_m/add_first.png" />
             </div>
             <p class="hint-text">选择封面页</p>
@@ -222,6 +222,7 @@
     <!-- 选择封面弹窗 -->
     <choose-cover  v-if="isShowChooseCover"
         :firstPage="firstPage"
+        :pptCoverList="pptCoverList"
         @close="closeChooseCover"
         @save="saveCover"
     />
@@ -447,6 +448,7 @@ export default {
         i.isUpdating = false
       })
       this.dataLoading.close();
+      $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
     },
     async getpptData(){
       const {id} = this.$route.query

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

@@ -24,7 +24,7 @@
         />
         <!-- 封底 -->
         <index-item
-          v-if="currentItem"
+          v-if="currentItem&&isShowBack"
           :pageIndex="pageList.length+1" 
           :pageItem="backInfo.index" 
           :currentItem="currentItem"
@@ -44,7 +44,7 @@
             </div>
             <!-- 封底 -->
             <div class="ppt-item" id="back" v-else-if="currentIndex===pageList.length+1">
-              <img src="~@/assets/img/ppt_en_last.png" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
+              <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
             </div>
             <!-- PPT内容 -->
               <div class="ppt-item" v-else>
@@ -70,7 +70,7 @@
         </div>
         <div class="other">
           <div class="page-info">
-            <span>第{{currentIndex+1}}页PPT,共{{pageList.length+2}}页</span>
+            <span>第{{currentIndex+1}}页PPT,共{{`${isShowBack?(pageList.length+2):(pageList.length+1)}`}}页</span>
           </div>
           <div class="btn-list">
             <el-button @click="(e)=>{FullScreen(e,'live')}" type="primary" class="btn">人像模式播放</el-button>
@@ -102,7 +102,7 @@
             </div>
             <!-- 封底 -->
             <div class="ppt-item" id="back" v-else-if="currentIndex===pageList.length+1">
-              <img src="~@/assets/img/ppt_en_last.png" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
+              <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
             </div>
             <!-- PPT内容 -->
               <div class="ppt-item" v-else>
@@ -237,6 +237,9 @@ export default {
     },
     lineClamp(){
         return this.LayoutType===2?2:3
+    },
+    isShowBack(){
+        return Boolean(this.pptBackImage)
     }
   },
   methods: {
@@ -268,6 +271,7 @@ export default {
           $('.editor-content').css('transform',`scale(${this.contentScale})`)
         }
         this.changeLayersSize()
+        $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
       })
     },
     async init(){
@@ -465,7 +469,8 @@ export default {
     },
     //ppt下一页
     nextPPT(){
-      if(this.currentIndex===this.pageList.length+1){
+        const maxLength = this.isShowBack?(this.pageList.length+1):this.pageList.length
+      if(this.currentIndex===maxLength){
         //this.$message.warning('已经是最后一页')
         !this.hintText&&this.showHint('next')
       }else{
@@ -509,7 +514,7 @@ export default {
     },
     //currentItem内图层元素自适应
     changeLayersSize(){
-      if(this.currentItem.layers){
+      if(this.currentItem&&this.currentItem.layers){
         this.currentItem.layers.map(shape=>{
           const scale = calcScale({w:906,h:906*0.7},{w:$('.ppt-item').width(),h:$('.ppt-item').width()*this.coefficient})
           $('.shape').css('transform',`scale(${scale.x},${scale.y})`)

+ 25 - 19
src/views/ppt_manage/newVersion/pptEnPublish.vue

@@ -37,8 +37,8 @@
             </component>
           </div>
           <!-- 封底 -->
-          <div class="ppt-item" id="back">
-            <img src="~@/assets/img/ppt_en_last.png" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
+          <div class="ppt-item" id="back" v-if="pptBackImage.length">
+            <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
           </div>
         </div>
       </template>
@@ -48,8 +48,8 @@
 <script>
 import Cover from './components/CoverEn.vue';
 import TransReport from './components/catalog/transReport.vue';
-import {countComponentName,pptInit,toTextProps,toJson,svg2Base64,getImgRealSize,calcScale,getShapeOptions,createRandomCode,getTableData} from './utils/untils';
-import {marginTop,modelConfig,pptSlideMaster,pptCoverEn} from './utils/config';
+import {countComponentName,pptInit,pptConfigInit,toTextProps,toJson,svg2Base64,getImgRealSize,calcScale,getShapeOptions,createRandomCode,getTableData} from './utils/untils';
+import {marginTop,modelConfig,pptSlideMaster,pptSlideMasterEn,pptCoverEn} from './utils/config';
 import pptmixin from '../mixins/pptMixins';
 import mixins from '../mixins/mixins';
 import html2canvas from 'html2canvas';
@@ -146,6 +146,7 @@ export default {
           await this.initPageElements(this.pageList[i],'show')
         }
         this.dataLoading.close();
+        $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
       }
     },
     async getpptData(){
@@ -211,7 +212,10 @@ export default {
     async pageToPptx(){
       //开始计时
       const start = Date.now()
-      let pptx = pptInit(new pptxgen(),this.LayoutType,'en');
+      //let pptx = pptInit(new pptxgen(),this.LayoutType,'en');
+      const SlideMaster = _.cloneDeep(pptSlideMasterEn) 
+      SlideMaster.objects[1] = {image: {x:0,y:0,w:10,h:7,path:this.pptBgImage}}
+      let pptx = pptConfigInit(new pptxgen(),this.LayoutType,'en',SlideMaster,this.pptBgImage)
       //添加一页空白页,后续转换需要
       pptx.addSlide()
       const length = this.pageList.length;
@@ -355,22 +359,24 @@ export default {
           }
         }
       }
-      //添加封底
-      let back = pptx.addSlide()
-      let backId = this.loadingAll?'back':'changeback'
-      //let backImg = await this.htmlToCanvans(backId)
-      let backImg = $(`#${backId} img`)[0].src
-      back.addImage({
-        path: backImg,
-        x: 0,
-        y: 0,
-        w:'100%',
-        h: '100%',
-        size: { type: "contain" },
-      })
+      //添加封底 如果有
+      if(this.pptBackImage.length){
+        let back = pptx.addSlide()
+        let backId = this.loadingAll?'back':'changeback'
+        let backImg = $(`#${backId} img`)[0].src
+        back.addImage({
+            path: backImg,
+            x: 0,
+            y: 0,
+            w:'100%',
+            h: '100%',
+            size: { type: "contain" },
+        })
+      }
       //为了把封面放到第一页,操作pptx.slides达不成想要的效果,于是弄了个pptx2
       //将封面放在最后生成是因为htmlToCanvans占用太多内存会导致页面假死
-      let pptx2 = pptInit(new pptxgen(),this.LayoutType,'en');
+      //let pptx2 = pptInit(new pptxgen(),this.LayoutType,'en');
+      let pptx2 = pptConfigInit(new pptxgen(),this.LayoutType,'en',SlideMaster,this.pptBgImage)
       //添加封面
       let cover = pptx2.addSlide()
       let coverId = this.loadingAll?'cover':'changecover'

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

@@ -24,7 +24,7 @@
         />
         <!-- 封底 -->
         <index-item
-          v-if="currentItem"
+          v-if="currentItem&&isShowBack"
           :pageIndex="pageList.length+1" 
           :pageItem="backInfo.index" 
           :currentItem="currentItem"
@@ -44,7 +44,7 @@
             </div>
             <!-- 封底 -->
             <div class="ppt-item" id="back" v-else-if="currentIndex===pageList.length+1">
-              <img src="~@/assets/img/pptlastimg.png" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
+              <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
             </div>
             <!-- PPT内容 -->
               <div class="ppt-item" v-else>
@@ -70,7 +70,7 @@
         </div>
         <div class="other">
           <div class="page-info">
-            <span>第{{currentIndex+1}}页PPT,共{{pageList.length+2}}页</span>
+            <span>第{{currentIndex+1}}页PPT,共{{`${isShowBack?(pageList.length+2):(pageList.length+1)}`}}页</span>
           </div>
           <div class="btn-list">
             <el-button @click="(e)=>{FullScreen(e,'live')}" type="primary" class="btn">人像模式播放</el-button>
@@ -102,7 +102,7 @@
             </div>
             <!-- 封底 -->
             <div class="ppt-item" id="back" v-else-if="currentIndex===pageList.length+1">
-              <img src="~@/assets/img/pptlastimg.png" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
+              <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
             </div>
             <!-- PPT内容 -->
               <div class="ppt-item" v-else>
@@ -235,6 +235,9 @@ export default {
     },
     lineClamp(){
         return this.LayoutType===2?2:3
+    },
+    isShowBack(){
+        return Boolean(this.pptBackImage)
     }
   },
   methods: {
@@ -266,6 +269,7 @@ export default {
           $('.editor-content').css('transform',`scale(${this.contentScale})`)
         }
         this.changeLayersSize()
+        $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
       })
     },
     async init(){
@@ -463,7 +467,8 @@ export default {
     },
     //ppt下一页
     nextPPT(){
-      if(this.currentIndex===this.pageList.length+1){
+      const maxLength = this.isShowBack?(this.pageList.length+1):this.pageList.length
+      if(this.currentIndex===maxLength){
         //this.$message.warning('已经是最后一页')
         !this.hintText&&this.showHint('next')
       }else{
@@ -507,7 +512,7 @@ export default {
     },
     //currentItem内图层元素自适应
     changeLayersSize(){
-      if(this.currentItem.layers){
+      if(this.currentItem&&this.currentItem.layers){
         this.currentItem.layers.map(shape=>{
           const scale = calcScale({w:906,h:906*0.7},{w:$('.ppt-item').width(),h:$('.ppt-item').width()*this.coefficient})
           $('.shape').css('transform',`scale(${scale.x},${scale.y})`)

+ 25 - 19
src/views/ppt_manage/newVersion/pptPublish.vue

@@ -38,8 +38,8 @@
             </component>
           </div>
           <!-- 封底 -->
-          <div class="ppt-item" id="back">
-            <img src="~@/assets/img/pptlastimg.png" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
+          <div class="ppt-item" id="back" v-if="pptBackImage.length">
+            <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
           </div>
         </div>
       </template>
@@ -108,7 +108,7 @@
 import Cover from './components/Cover.vue';
 import TransReport from './components/catalog/transReport.vue';
 //import {pageList} from './utils/mock';
-import {countComponentName,pptInit,toTextProps,toJson,svg2Base64,getImgRealSize,calcScale,getShapeOptions,createRandomCode,getTableData} from './utils/untils';
+import {countComponentName,pptInit,pptConfigInit,toTextProps,toJson,svg2Base64,getImgRealSize,calcScale,getShapeOptions,createRandomCode,getTableData} from './utils/untils';
 import {marginTop,modelConfig,pptSlideMaster} from './utils/config';
 import pptmixin from '../mixins/pptMixins';
 import mixins from '../mixins/mixins';
@@ -209,6 +209,7 @@ export default {
           await this.initPageElements(this.pageList[i],'show')
         }
         this.dataLoading.close();
+        $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
       }else{
         await this.getpptData();
         this.initVirtualScroll()
@@ -278,7 +279,10 @@ export default {
     async pageToPptx(){
       //开始计时
       const start = Date.now()
-      let pptx = pptInit(new pptxgen(),this.LayoutType);
+      //let pptx = pptInit(new pptxgen(),this.LayoutType);
+      const SlideMaster = _.cloneDeep(pptSlideMaster) 
+      SlideMaster.objects[1] = {image: {x:0,y:0,w:10,h:7,path:this.pptBgImage}}
+      let pptx = pptConfigInit(new pptxgen(),this.LayoutType,'ch',SlideMaster,this.pptBgImage)
       //添加一页空白页,后续转换需要
       pptx.addSlide()
       const length = this.pageList.length;
@@ -435,26 +439,28 @@ export default {
           }
         }
       }
-      //添加封底
-      let back = pptx.addSlide()
-      let backId = this.loadingAll?'back':'changeback'
-      //let backImg = await this.htmlToCanvans(backId)
-      let backImg = $(`#${backId} img`)[0].src
-      back.addImage({
-        path: backImg,
-        x: 0,
-        y: 0,
-        w:'100%',
-        h: '100%',
-        size: { type: "contain" },
-      })
+      //添加封底 如果有
+      if(this.pptBackImage.length){
+        let back = pptx.addSlide()
+        let backId = this.loadingAll?'back':'changeback'
+        let backImg = $(`#${backId} img`)[0].src
+        back.addImage({
+            path: backImg,
+            x: 0,
+            y: 0,
+            w:'100%',
+            h: '100%',
+            size: { type: "contain" },
+        })
+      }
+      
       //为了把封面放到第一页,操作pptx.slides达不成想要的效果,于是弄了个pptx2
       //将封面放在最后生成是因为htmlToCanvans占用太多内存会导致页面假死
-      let pptx2 = pptInit(new pptxgen(),this.LayoutType);
+      //let pptx2 = pptInit(new pptxgen(),this.LayoutType);
+      let pptx2 = pptConfigInit(new pptxgen(),this.LayoutType,'ch',SlideMaster,this.pptBgImage)
       //添加封面
       let cover = pptx2.addSlide()
       let coverId = this.loadingAll?'cover':'changecover'
-      //let coverImg = await this.htmlToCanvans(coverId)
       let coverImg = $(`#${coverId} .cover img`)[0].src
       cover.addImage({
         path: coverImg,

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

@@ -60,6 +60,23 @@ export const pptInit = (pptx,LayoutType,lang='ch') => {
   pptx.defineSlideMaster(sliderMaster)
 return pptx
 }
+//ppt配置化后 init ppt
+export const pptConfigInit = (pptx,LayoutType,lang='ch',SlideMaster,pptBgImg)=>{
+    let layout = pptLayout,
+        sliderMaster = SlideMaster
+    //如果布局不是10:7 背景图、页码需要做位置调整
+    if(LayoutType!==1){
+        layout = { name: "myppt", width: 10, height: LayoutType===2?5.625:7.5 }
+        const y = lang==='ch'?0:-0.1
+        const h = LayoutType===2?5.625:7.5
+        sliderMaster.objects[1] = {image: {x:0,y:y,w:10,h:lang==='ch'?h:h+0.1,path:pptBgImg}}
+        sliderMaster.slideNumber = {x:'95%',y:LayoutType===2?'92%':'95%',fontSize:12}
+    }
+    pptx.defineLayout(layout)
+    pptx.layout = layout.name
+    pptx.defineSlideMaster(sliderMaster)
+    return pptx
+}
 //解析富文本,参考https://github.com/pipipi-pikachu/PPTist/tree/master/src/utils/htmlParser
 export const toJson = (html) => {
     const json = parse(html)

+ 2 - 1
src/views/semantics_manage/utils/config.js

@@ -275,7 +275,8 @@ export const froalaConfig = {
   wordPasteKeepFormatting:false,
   pastePlain:true,
   wordPasteModal:false,
-  pasteDeniedTags:['ol','li']
+  pasteDeniedTags:['ol','li'],
+  pluginsEnabled:[],//禁止所有插件,这样就不会粘贴图片
 }
 
 //icon map 方便管理

+ 44 - 0
src/views/system_manage/components/configAnnotation.vue

@@ -0,0 +1,44 @@
+<template>
+    <div class="config-annotation-wrap">
+        <el-button type="text" @click="showImage">{{buttonText}}</el-button>
+        <span class="hint-text">{{picHintText}}</span>
+    </div>
+</template>
+
+<script>
+export default {
+    props:{
+        buttonText:{
+            type:String,
+            default:'查看示意图'
+        },
+        picName:{
+            type:String,
+            default:''
+        },
+        picHintText:{
+            type:String,
+            default:'上传格式:png、jpg'
+        }
+    },
+    data() {
+        return {
+
+        };
+    },
+    methods: {
+        showImage(){
+            this.$emit('showImage',this.picName)
+        }
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.config-annotation-wrap{
+    .hint-text{
+        margin-left: 20px;
+        color: #dcdcdc;
+    }
+}
+</style>

+ 92 - 0
src/views/system_manage/components/imgThumbnail.vue

@@ -0,0 +1,92 @@
+<template>
+    <ul class="img-thumbanail-wrap">
+        <li class="img-item" v-for="(img,index) in _.cloneDeep(this.imgList).reverse()" :key="index" @click="showImage(img)">
+            <img :src="img" />
+            <span class="mask">
+                <span
+                    class="mask-icon"
+                    @click.stop="deleteImg(img)"
+                >
+                    <i class="el-icon-delete"></i>
+                </span>
+            </span>
+        </li>
+    </ul>
+</template>
+
+<script>
+import _ from "lodash";
+export default {
+    props:{
+        imgList:{
+            type:Array,
+            default:()=>{return []}
+        }
+    },
+    data() {
+        return {
+            showList:_.cloneDeep(this.imgList).reverse()
+        };
+    },
+    methods: {
+        deleteImg(img){
+            //数组是逆序过的,需要找到正确的index
+            const index = this.imgList.findIndex(i=>i===img)||0
+            this.$emit('deleteImg',index)
+        },
+        showImage(img){
+            this.$emit('showImage',{list:this.imgList,item:img})
+        }
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.img-thumbanail-wrap{
+    display: flex;
+    width:280px;
+    gap:20px;
+    margin-left: 20px;
+    .img-item{
+        position:relative;
+        width:120px;
+        height: 120px;
+        background-color: #F5F7F9;
+        border: 1px dashed #DCDFE6;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        box-sizing: border-box;
+        padding:4px;
+        overflow: hidden;
+        img,.mask{
+            width:100%;
+            height:100%;
+        }
+        &:hover{
+            border: 1px dashed #3375e1;
+            .mask {
+                opacity: 1;
+            }
+        }
+        .mask {
+            position: absolute;
+            left: 0;
+            top: 0;
+            cursor: default;
+            text-align: center;
+            color: #fff;
+            opacity: 0;
+            font-size: 20px;
+            background-color: rgba(0, 0, 0, .5);
+            transition: opacity .3s;
+            z-index: 2;
+            line-height: 120px;
+            .mask-icon {
+                cursor: pointer;
+            }
+        }
+    }
+}
+</style>

+ 108 - 0
src/views/system_manage/components/imgUpload.vue

@@ -0,0 +1,108 @@
+<template>
+    <el-upload action="" accept="image/*" :http-request="handleUploadImg" :show-file-list="false"
+        :key="uploadKey">
+        <div class="upload-box">
+            <template v-if="!imgUrl.length">
+                <i class="el-icon-plus" style="font-size: 24px;"></i>
+                <p class="form-hint">点击上传图片</p>
+            </template>
+            <template v-else>
+                <img class="upload-img" :src="imgUrl" alt="配图">
+                <span class="upload-mask" @click.stop="showImage">
+                    <span class="mask-icon" @click.stop="handleRemove">
+                        <i class="el-icon-delete"></i>
+                    </span>
+                </span>
+            </template>
+        </div>
+    </el-upload>
+</template>
+
+<script>
+    export default {
+        props: {
+            imgUrl: {
+                type: String,
+                default: ''
+            }
+        },
+        data() {
+            return {
+                uploadKey: 0
+            };
+        },
+        watch: {
+            imgUrl(newVal) {
+                //this.uploadKey++
+            }
+        },
+        methods: {
+            handleUploadImg(file) {
+                this.$emit('upload', file)
+            },
+            handleRemove() {
+                this.$emit('remove')
+            },
+            showImage(){
+                this.$emit('showImage',[this.imgUrl])
+            }
+        },
+    };
+</script>
+
+<style scoped lang="scss">
+    .el-upload {
+        .upload-box {
+            position: relative;
+            width: 120px;
+            height: 120px;
+            background-color: #F5F7F9;
+            border: 1px dashed #DCDFE6;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            justify-content: center;
+            box-sizing: border-box;
+            padding: 4px;
+            overflow: hidden;
+
+            &:hover {
+                border: 1px dashed #3375e1;
+
+                .upload-mask {
+                    opacity: 1;
+                }
+            }
+
+            .form-hint {
+                margin-top: 10px;
+                color: #999999;
+            }
+
+            .upload-img,
+            .upload-mask {
+                width: 100%;
+                height: 100%;
+            }
+
+            .upload-mask {
+                position: absolute;
+                left: 0;
+                top: 0;
+                cursor: default;
+                text-align: center;
+                color: #fff;
+                opacity: 0;
+                font-size: 20px;
+                background-color: rgba(0, 0, 0, .5);
+                transition: opacity .3s;
+                z-index: 2;
+                line-height: 120px;
+
+                .mask-icon {
+                    cursor: pointer;
+                }
+            }
+        }
+    }
+</style>

+ 422 - 0
src/views/system_manage/etaBaseConfig.vue

@@ -0,0 +1,422 @@
+<template>
+    <div class="eta-base-config">
+        <el-form  :model="formData" :rules="rules" label-position="top" class="base-config-form"
+            label-width="120px" ref="baseConfigForm">
+            <div class="part-base part">
+                <div class="side">
+                    <el-form-item label="公司名称" prop="CompanyName">
+                        <el-input type="text" v-model="formData.CompanyName" placeholder="请输入公司名称" />
+                        <ConfigAnnotation picHintText="" picName="CompanyName" @showImage="previewImage"/>
+                    </el-form-item>
+                    <el-form-item label="公司水印" prop="CompanyWatermark" class="watermark">
+                        <ImgUpload 
+                            :imgUrl="formData.CompanyWatermark"
+                            @showImage="showImage"
+                            @upload="(file)=>handleUploadImage(file,'CompanyWatermark')"
+                            @remove="deleteFormImg('CompanyWatermark')"
+                            />
+                        <!-- 后面可能会有新的选项 -->
+                        <el-checkbox-group v-model="checkList" style="position: absolute;top: -40px;left: 100px;">
+                            <el-checkbox label="研报图表"></el-checkbox>
+                        </el-checkbox-group>
+                        <ConfigAnnotation picName="CompanyWatermark" @showImage="previewImage"/>
+                    </el-form-item>
+                </div>
+                <div class="side">
+                    <el-form-item label="免责声明" prop="Disclaimer" class="disclaimer">
+                        <div class="rich-editor-wrap">
+                            <froala :id="`disclaimer-editor`"
+                                :ref="`disclaimerEditor`" 
+                                :tag="'textarea'" 
+                                :config="disclaimerConfig" v-model="formData.Disclaimer">
+                            </froala>
+                        </div>
+                        <ConfigAnnotation picHintText="" picName="Disclaimer" @showImage="previewImage"/>
+                    </el-form-item>
+                </div>
+            </div>
+            <div class="part-ppt part">
+                <el-radio-group v-model="pptLang" style="margin-bottom: 22px;">
+                    <el-radio-button label="cn">中文PPT</el-radio-button>
+                    <el-radio-button label="en">英文PPT</el-radio-button>
+                </el-radio-group>
+                <div v-show="pptLang === 'cn'" class="ppt-form-item-wrap">
+                    <el-form-item label="PPT封面图" prop="CnPptCoverImgs">
+                        <div class="input-line" style="display:flex;">
+                            <ImgUpload 
+                                :imgUrl="formData.CnPptCoverImgs.length===3?formData.CnPptCoverImgs[2]:''"
+                                @showImage="(arr)=>{showImageOrder({list:formData.CnPptCoverImgs,item:arr[0]})}"
+                                @upload="(file)=>handleUploadImage(file,'CnPptCoverImgs')"
+                                @remove="deleteFormImg('CnPptCoverImgs',formData.CnPptCoverImgs.length-1)"
+                                />
+                            <ImgThumbnail 
+                                :imgList="formData.CnPptCoverImgs.length===3?formData.CnPptCoverImgs.slice(0,2):formData.CnPptCoverImgs"
+                                @showImage="({item})=>{showImageOrder({list:formData.CnPptCoverImgs,item})}"
+                                @deleteImg="(index)=>{deleteFormImg('CnPptCoverImgs',index)}"/>
+                        </div>
+                        <ConfigAnnotation picName="pptCoverList" @showImage="previewImage"
+                            picHintText="上传格式:png、jpg,最多上传三张,建议图片比例:10:7 16:9 4:3"/>
+                    </el-form-item>
+                    <el-form-item label="PPT背景图" prop="CnPptBackgroundImg">
+                        <ImgUpload 
+                            :imgUrl="formData.CnPptBackgroundImg"
+                            @showImage="showImage"
+                            @upload="(file)=>handleUploadImage(file,'CnPptBackgroundImg')"
+                            @remove="deleteFormImg('CnPptBackgroundImg')"
+                            />
+                        <ConfigAnnotation picName="pptBgPic" @showImage="previewImage"
+                            picHintText="上传格式:png、jpg,建议图片比例:10:7 16:9 4:3"/>
+                    </el-form-item>
+                    <el-form-item label="PPT封底图" prop="CnPptBottomImg">
+                        <ImgUpload 
+                            :imgUrl="formData.CnPptBottomImg"
+                            @showImage="showImage"
+                            @upload="(file)=>handleUploadImage(file,'CnPptBottomImg')"
+                            @remove="deleteFormImg('CnPptBottomImg')"
+                            />
+                        <ConfigAnnotation picName="pptBackPic" @showImage="previewImage"
+                            picHintText="上传格式:png、jpg,建议图片比例:10:7 16:9 4:3"/>
+                    </el-form-item>
+                </div>
+                <div v-show="pptLang === 'en'" class="ppt-form-item-wrap">
+                    <el-form-item label="PPT封面图" prop="EnPptCoverImgs">
+                        <div class="input-line" style="display:flex;">
+                            <ImgUpload 
+                                :imgUrl="formData.EnPptCoverImgs.length===3?formData.EnPptCoverImgs[2]:''"
+                                @showImage="(arr)=>{showImageOrder({list:formData.EnPptCoverImgs,item:arr[0]})}"
+                                @upload="(file)=>handleUploadImage(file,'EnPptCoverImgs')"
+                                @remove="deleteFormImg('EnPptCoverImgs',formData.EnPptCoverImgs.length-1)"
+                                />
+                            <ImgThumbnail 
+                                :imgList="formData.EnPptCoverImgs.length===3?formData.EnPptCoverImgs.slice(0,2):formData.EnPptCoverImgs"
+                                @showImage="({item})=>{showImageOrder({list:formData.EnPptCoverImgs,item})}"
+                                @deleteImg="(index)=>{deleteFormImg('EnPptCoverImgs',index)}"/>
+                        </div>
+                        <ConfigAnnotation picName="pptCoverList" @showImage="previewImage"
+                            picHintText="上传格式:png、jpg,最多上传三张,建议图片比例:10:7 16:9 4:3"/>
+                    </el-form-item>
+                    <el-form-item label="PPT背景图" prop="EnPptBackgroundImg">
+                        <ImgUpload 
+                            :imgUrl="formData.EnPptBackgroundImg"
+                            @showImage="showImage"
+                            @upload="(file)=>handleUploadImage(file,'EnPptBackgroundImg')"
+                            @remove="deleteFormImg('EnPptBackgroundImg')"
+                            />
+                        <ConfigAnnotation picName="pptBgPic" @showImage="previewImage"
+                            picHintText="上传格式:png、jpg,建议图片比例:10:7 16:9 4:3"/>
+                    </el-form-item>
+                    <el-form-item label="PPT封底图" prop="EnPptBottomImg">
+                        <ImgUpload 
+                            :imgUrl="formData.EnPptBottomImg"
+                            @showImage="showImage"
+                            @upload="(file)=>handleUploadImage(file,'EnPptBottomImg')"
+                            @remove="deleteFormImg('EnPptBottomImg')"
+                            />
+                        <ConfigAnnotation picName="pptBackPic" @showImage="previewImage"
+                            picHintText="上传格式:png、jpg,建议图片比例:10:7 16:9 4:3"/>
+                    </el-form-item>
+                </div>
+            </div>
+            <div class="part-Iflytek part">
+                <!-- 科大讯飞 -->
+                <div style="width:100%;">
+                    <span style="color:#606266;">科大讯飞服务</span> 
+                    <el-switch v-model="Iflytek"></el-switch>
+                </div>
+                <template v-if="Iflytek">
+                    <div class="side">
+                        <el-form-item label="APPID" prop="XfAppid">
+                            <el-input type="text" v-model="formData.XfAppid" placeholder="请输入APPID" />
+                        </el-form-item>
+                        <el-form-item label="APIKey" prop="XfApiKey">
+                            <el-input type="text" v-model="formData.XfApiKey" placeholder="请输入APIKey" />
+                        </el-form-item>
+                    </div>
+                    <div class="side">
+                        <el-form-item label="APISecret" prop="XfApiSecret">
+                            <el-input type="text" v-model="formData.XfApiSecret" placeholder="请输入APISecret" />
+                        </el-form-item>
+                        <el-form-item label="vcn(voice_name)" prop="XfVcn">
+                            <el-input type="text" v-model="formData.XfVcn" placeholder="请输入voice_name" />
+                        </el-form-item>
+                    </div>
+                </template>
+            </div>
+        </el-form>
+        <div class="btn-wrap" style="text-align: center;">
+            <el-button type="primary" plain style="width:200px;" @click="cancel">取消</el-button>
+            <el-button type="primary"  style="margin-left:50px;width:200px;" @click="saveBaseConfig">保存</el-button>
+        </div>
+        <el-image-viewer 
+            v-if="showViewer" 
+            :on-close="()=>{this.picShowList=[];this.showViewer = false}" 
+            :url-list="picShowList" />
+    </div>
+</template>
+
+<script>
+import ImgThumbnail from './components/imgThumbnail.vue';
+import ImgUpload from './components/imgUpload.vue';
+import ConfigAnnotation from './components/configAnnotation.vue';
+import ElImageViewer from 'element-ui/packages/image/src/image-viewer';
+
+import {bannerupload} from '@/api/api.js';
+import {etaBaseConfigInterence} from '@/api/modules/etaBaseConfigApi.js';
+export default {
+    components: { ConfigAnnotation , ElImageViewer , ImgThumbnail , ImgUpload},
+    data() {
+        let ListValidator = (rule,value,callback)=>{
+            if(!value.length){
+                return callback(new Error('请至少选择一张封面图'))
+            }else{
+                return callback()
+            }
+        }
+        return {
+            /* base config */
+            checkList:[],//水印应用
+            Iflytek:false,//是否启用科大讯飞服务
+            formData: {
+                Disclaimer: '',//免责声明
+                CompanyName:'',//公司名称
+                CompanyWatermark:'',//公司水印
+                WatermarkChart:0,//是否在研报图表中使用水印 0否 1是
+
+                UseXf:0,//是否启用科大讯飞服务 0否 1是
+                XfAppid:'',
+                XfApiKey:'',
+                XfApiSecret:'',
+                XfVcn:'',
+
+                CnPptCoverImgs:[],//ppt封面列表
+                CnPptBackgroundImg:'',//ppt背景图
+                CnPptBottomImg:'',//ppt封底图
+                EnPptCoverImgs:[],//英文ppt封面列表
+                EnPptBackgroundImg:'',//英文ppt背景图
+                EnPptBottomImg:'',//英文ppt封底图
+
+            },//表单预设值
+            rules: {
+                Disclaimer:[{ required: true, message: '请输入免责声明', trigger: 'blur' }],
+                CompanyName:[{ required: true, message: '请输入公司名称', trigger: 'blur' }],
+                //CompanyWatermark:[{ required: true, message: '请选择水印图片', trigger: 'blur' }],
+                CnPptBackgroundImg:[{ required: true, message: '请选择中文PPT背景图', trigger: 'blur' }],
+                EnPptBackgroundImg:[{ required: true, message: '请选择英文PPT背景图', trigger: 'blur' }],
+                XfAppid:[{ required: true, message: '请输入APPID', trigger: 'blur' }],
+                XfApiKey:[{ required: true, message: '请输入APIKey', trigger: 'blur' }],
+                XfApiSecret:[{ required: true, message: '请输入APISecret', trigger: 'blur' }],
+                XfVcn:[{ required: true, message: '请输入voice_name', trigger: 'blur' }],
+                CnPptCoverImgs:[{ required: true, validator:ListValidator}],
+                EnPptCoverImgs:[{ required: true, validator:ListValidator}],
+            },//表单校验
+            disclaimerConfig:{
+                toolbarButtons:[
+                    'textColor',
+                    'bold',
+                    'italic',
+                    'underline',
+                    'fontFamily',
+                    'fontSize',
+                    'align',
+                    'outdent',
+                    'indent',
+                    'specialCharacters',
+                    'insertHR',
+                    'selectAll',
+                    'clearFormatting',
+                    'undo',
+                    'redo',
+                ],
+                height:300,
+                fontSizeDefaultSelection: "16",
+                quickInsertEnabled: false,
+                pasteAllowedStyleProps: ['font-family', 'font-size', 'color'],
+                language: "zh_cn",
+                placeholderText:'请输入免责声明',
+                wordPasteKeepFormatting:false,
+                pastePlain:true,
+                wordPasteModal:false,
+                pluginsEnabled:['colors'],//定义可用插件
+            },//富文本编辑器配置项
+
+            /* ppt config */
+            pptLang:'cn',//切换中英文表单 
+            CnPptCoverImgs:[],//中文封面列表
+            EnPptCoverImgs:[],//英文封面列表
+
+            /* image preview */
+            showViewer:false,//控制图片预览组件展示
+            picShowList:[],//ElImageViewer组件展示图片的列表
+            picShowMap:{ //查看示意图需要展示的图片 支持多张
+                'Disclaimer':[
+                    require('@/assets/img/eta_base_config/disclaimer_1.jpg'),
+                    require('@/assets/img/eta_base_config/disclaimer_2.jpg'),
+                ],
+                'CompanyName':[require('@/assets/img/eta_base_config/company_1.jpg')],
+                'CompanyWatermark':[require('@/assets/img/eta_base_config/mark_1.jpg')],
+                'pptCoverList':[require('@/assets/img/eta_base_config/ppt_cover.jpg')],
+                'pptBgPic':[require('@/assets/img/eta_base_config/ppt_bgpic.jpg')],
+                'pptBackPic':[require('@/assets/img/eta_base_config/ppt_back.jpg')]
+            },
+            /* loading */
+            configLoading:null,
+
+        };
+    },
+    methods: {
+        handleUploadImage(file,key){
+            /* console.log('type',key)
+            console.log('file',file) */
+            //如果是封面图
+            if(['CnPptCoverImgs','EnPptCoverImgs'].includes(key)&&this.formData[key].length===3){
+                this.$message.warning('封面图最多只能上传三张')
+                return
+            }
+            //图片大小和格式限制
+            const {size,type} = file.file
+            const sizeLimit = key==='CompanyWatermark'?50*1024:500*1024
+            if(!['image/png','image/jpeg'].includes(type)){
+                this.$message.warning('仅支持png、jpg格式的图片')
+                return
+            }
+            if(size>sizeLimit){
+                this.$message.warning(`${key==='CompanyWatermark'?'水印图大小不能超过50kb':'ppt配图大小不能超过500kb'}`)
+                return
+            }
+            
+            let form = new FormData();
+            form.append('file',file.file);
+            bannerupload(form).then(res=>{
+                if(res.Ret!==200) return 
+                if(['CnPptCoverImgs','EnPptCoverImgs'].includes(key)){
+                    this.formData[key].push(res.Data.ResourceUrl)
+                }else{
+                    this.formData[key] = res.Data.ResourceUrl
+                }
+            })
+        },
+        previewImage(picName){
+            this.picShowList = this.picShowMap[picName]||[]
+            this.picShowList.length&&(this.showViewer = true)
+        },
+        deleteFormImg(key,index){
+            if(['CnPptCoverImgs','EnPptCoverImgs'].includes(key)){
+                this.formData[key].splice(index,1)
+            }else{
+                this.formData[key] = ''
+            }
+        },
+        showImage(imgList){
+            this.picShowList = imgList||[]
+            this.picShowList.length&&(this.showViewer = true)
+        },
+        showImageOrder({list,item}){
+            //改变list的顺序,当前点击的为第一个
+            const index = list.findIndex(img=>img===item)
+            this.picShowList = [...list.slice(index),...list.slice(0,index)]
+            this.picShowList.length&&(this.showViewer = true)
+        },
+        getBaseConfig(){
+            this.configLoading = this.$loading({
+                lock: true,
+                target: '.eta-base-config',
+                text: '正在获取基本配置...',
+                spinner: 'el-icon-loading',
+                background: 'rgba(255, 255, 255, 0.8)',
+            });
+            //获取WatermarkChart的值,赋值checkList
+            //获取UseXf的值,赋值Iflytek
+            etaBaseConfigInterence.getBaseConfig().then(res=>{
+                if(res.Ret!==200) return 
+                const {WatermarkChart,UseXf,CnPptCoverImgs,EnPptCoverImgs} = res.Data
+                this.checkList = WatermarkChart==='true'?['研报图表']:[]
+                this.Iflytek = UseXf==='true'?true:false
+                this.formData = res.Data
+                this.formData.CnPptCoverImgs = CnPptCoverImgs.length?CnPptCoverImgs.split(','):[]
+                this.formData.EnPptCoverImgs = EnPptCoverImgs.length?EnPptCoverImgs.split(','):[]
+                this.configLoading&&this.configLoading.close()
+            })
+        },
+        saveBaseConfig(){
+            //froala 在非本地环境会有版权标识,在表单验证前去掉
+            this.formData.Disclaimer = this.formData.Disclaimer.replace(/<p data-f-id=\"pbf\".*?<\/p>/g, "");
+            //rules验证
+            this.$refs.baseConfigForm.validate((valid,obj)=>{
+                console.log('valid',valid)
+                console.log('obj',obj)
+                //如果是中英文ppt没填写,切换标签栏
+                const keys = Object.keys(obj)
+                const cnProps = ['CnPptCoverImgs','CnPptBackgroundImg','CnPptBottomImg']
+                const enProps = ['EnPptCoverImgs','EnPptBackgroundImg','EnPptBottomImg']
+                for(let i = 0;i < keys.length;i++){
+                    if(cnProps.includes(keys[i])){
+                        this.pptLang = 'cn'
+                        break
+                    }
+                    if(enProps.includes(keys[i])){
+                        this.pptLang = 'en'
+                        break
+                    }
+                }
+                if(valid){
+                    this.formData.WatermarkChart = ''+(this.checkList.includes('研报图表')?true:false)
+                    this.formData.UseXf = ''+(this.Iflytek?true:false)
+                    const CnPptCoverImgs = this.formData.CnPptCoverImgs.join(',')
+                    const EnPptCoverImgs = this.formData.EnPptCoverImgs.join(',')
+                    etaBaseConfigInterence.saveBaseConfig({...this.formData,...{CnPptCoverImgs,EnPptCoverImgs}}).then(res=>{
+                        if(res.Ret!==200) return 
+                        this.$message.success('保存成功,请稍后到对应页面/项目查看')
+                    })
+                }
+            })
+        },
+        cancel(){
+            //取消就恢复原样
+            this.getBaseConfig()
+        }
+    },
+    mounted(){
+        this.getBaseConfig()
+    }
+};
+</script>
+
+<style lang="scss">
+.eta-base-config{
+    .el-form-item{
+        .el-form-item__content{line-height: normal;}
+    }
+}
+</style>
+<style scoped lang="scss">
+.eta-base-config{
+    box-sizing: border-box;
+    padding:30px;
+    border-radius: 4px;
+    background-color: #fff;
+    .base-config-form{
+        .el-form-item{
+            width:100%;
+        }
+        .part{
+            display: flex;
+            justify-content: space-between;
+            flex-wrap: wrap;
+            &:not(:last-child){
+                border-bottom: 1px solid #DCDFE6;
+            }
+            &:not(:first-child){
+                margin-top: 30px;
+            }
+            .side{
+                width:45%;
+            }
+            .ppt-form-item-wrap{
+                width:100%;
+                display: flex;
+                justify-content: space-between;
+            }
+        }
+    }
+}
+</style>