Jelajahi Sumber

Merge branch 'ppt-zip' into custom

cxmo 1 tahun lalu
induk
melakukan
540541fc51

+ 42 - 8
src/views/ppt_manage/mixins/pptMixins.js

@@ -70,7 +70,10 @@ export default {
 
 
       //截面散点设置英文props
       //截面散点设置英文props
 			enChartInfo: {},
 			enChartInfo: {},
-			enEdblist:[]
+			enEdblist:[],
+
+
+        chartSVGDataMap:{}
     }
     }
   },
   },
   methods: {
   methods: {
@@ -592,7 +595,8 @@ export default {
           this.initChart(
           this.initChart(
 				    `chart_${index}_${item.position}`,
 				    `chart_${index}_${item.position}`,
 				    this.optionMap[item.chartId],
 				    this.optionMap[item.chartId],
-				    page
+				    page,
+                    item.chartId
 			    )
 			    )
         }else{
         }else{
           //显示图表已被删除
           //显示图表已被删除
@@ -604,7 +608,7 @@ export default {
 			
 			
       });
       });
     },
     },
-    initChart(refName, options, page) {
+    initChart(refName, options, page,chartId="") {
       console.log("refName", refName);
       console.log("refName", refName);
       const index = this.pageList.findIndex((i) => i.id === page.id)
       const index = this.pageList.findIndex((i) => i.id === page.id)
       if(index===-1) return
       if(index===-1) return
@@ -626,7 +630,7 @@ export default {
      
      
     /* 主题样式*/
     /* 主题样式*/
     const chartTheme =  ChartThemeStyle ? JSON.parse(ChartThemeStyle) : null;
     const chartTheme =  ChartThemeStyle ? JSON.parse(ChartThemeStyle) : null;
-
+    console.log('chartTheme',chartTheme)
       //console.log(options)
       //console.log(options)
       this.$nextTick(() => {
       this.$nextTick(() => {
         let is_linear = options.series 
         let is_linear = options.series 
@@ -727,22 +731,52 @@ export default {
 
 
         if(!$(`#${refName}`)[0]) return
         if(!$(`#${refName}`)[0]) return
 
 
-        console.log(SpecialOption)
-
+        let chart = null
         if(is_linear)
         if(is_linear)
-          Highcharts.chart({
+          chart = Highcharts.chart({
             // Highcharts 配置
             // Highcharts 配置
             ...options,
             ...options,
             ...SpecialOption,
             ...SpecialOption,
             ...secialBarOpt
             ...secialBarOpt
             });
             });
         else
         else
-        Highcharts.stockChart({
+        chart = Highcharts.stockChart({
           // Highcharts 配置
           // Highcharts 配置
           ...options,
           ...options,
           ...SpecialOption,
           ...SpecialOption,
           ...secialBarOpt
           ...secialBarOpt
         });
         });
+        
+        
+        if(isPublish&&chartId){
+            const {clientWidth,clientHeight} = $(`#${refName}`)[0]
+            const {plotBackgroundColor} = chartTheme&&chartTheme.drawOption||{}
+            const svgData = chart.getSVG({
+                    chart:{
+                        width:clientWidth,
+                        height:clientHeight,
+                        backgroundColor:null,
+                        plotBorderColor:null,
+                        plotBackgroundColor:null,
+                        plotBackgroundImage:null,
+                        plotBorderWidth:null,
+                        plotShadow:false,
+                        animation: false,
+                    }
+                })
+            let  parser = new DOMParser();
+            let svgDoc = parser.parseFromString(svgData, 'image/svg+xml');
+
+            // 查找class为'background'的rect元素并修改fill属性
+            let rectElement = svgDoc.querySelector('rect.highcharts-plot-background');
+            if (rectElement) {
+                rectElement.setAttribute('fill', plotBackgroundColor);
+            }
+            // 将修改后的SVG文档转换回字符串
+            let serializer = new XMLSerializer();
+            let updatedSvgCode = serializer.serializeToString(svgDoc);
+            this.chartSVGDataMap[`${refName}_${chartId}`] = updatedSvgCode
+        }
       });
       });
     },
     },
     initImages(elements,page){
     initImages(elements,page){

+ 3 - 2
src/views/ppt_manage/newVersion/pptCatalog.vue

@@ -851,14 +851,15 @@ export default {
             window.open(urlMap[item.key],'_blank');
             window.open(urlMap[item.key],'_blank');
           }else if(item.key==='publish'){
           }else if(item.key==='publish'){
             //this.$message.warning('该PPT页数超过60页或图表数量超过100张,无法发布,请修改后重试')
             //this.$message.warning('该PPT页数超过60页或图表数量超过100张,无法发布,请修改后重试')
-            if(!this.pptItem.overLimitHint.chartNum){
+            /* if(!this.pptItem.overLimitHint.chartNum){
               this.$message.warning(this.$t('Slides.exceed_ppt_msg') )
               this.$message.warning(this.$t('Slides.exceed_ppt_msg') )
               return
               return
             }
             }
             if(!this.pptItem.overLimitHint.pageNum){
             if(!this.pptItem.overLimitHint.pageNum){
               this.$message.warning(this.$t('Slides.exceed_sixty_ppt_msg') )
               this.$message.warning(this.$t('Slides.exceed_sixty_ppt_msg') )
               return
               return
-            }
+            } */
+            window.open(urlMap[item.key],'_blank');
           }     
           }     
         }else{
         }else{
           if(item.key==='publish'){
           if(item.key==='publish'){

+ 62 - 86
src/views/ppt_manage/newVersion/pptEnPublish.vue

@@ -1,11 +1,20 @@
 <template>
 <template>
   <div class="publish-page-wrap page-wrap">
   <div class="publish-page-wrap page-wrap">
       <div class="pub-btn-list">
       <div class="pub-btn-list">
-        <!-- <div>图表转换方式:
-          <el-radio v-model="transChartType" :label="1">传服务器</el-radio>
-          <el-radio v-model="transChartType" :label="2">本地转</el-radio>
-        </div> -->
         <el-button  type="primary" plain style="width:182px;height:40px;" @click="$router.push({path:'/pptenlist'})">{{$t('Slides.return_to_list')}}</el-button>
         <el-button  type="primary" plain style="width:182px;height:40px;" @click="$router.push({path:'/pptenlist'})">{{$t('Slides.return_to_list')}}</el-button>
+          <!-- 下载配置 -->
+          <!-- <div class="setting">
+            <div>
+                <span>是否压缩</span>
+                <el-radio v-model="setCompression" :label="true">是</el-radio>
+                <el-radio v-model="setCompression" :label="false">否</el-radio>
+            </div>
+            <div>
+                <span>图表转换优化</span>
+                <el-radio v-model="setCompression2" :label="true">开</el-radio>
+                <el-radio v-model="setCompression2" :label="false">关</el-radio>
+            </div>
+        </div> -->
         <el-button  type="primary" style="width:182px;height:40px;margin-left: 0;" @click="downloadPPT" :disabled="isPublish">{{$t('Slides.operations_download')}}</el-button>
         <el-button  type="primary" style="width:182px;height:40px;margin-left: 0;" @click="downloadPPT" :disabled="isPublish">{{$t('Slides.operations_download')}}</el-button>
         <el-dropdown split-button style="width:182px;height:40px;" type="primary" @click="transHandle" @command="handleCommand" :disabled="isPublish">
         <el-dropdown split-button style="width:182px;height:40px;" type="primary" @click="transHandle" @command="handleCommand" :disabled="isPublish">
           {{layoutStr}}
           {{layoutStr}}
@@ -51,7 +60,7 @@
 import Cover from './components/CoverEn.vue';
 import Cover from './components/CoverEn.vue';
 import CustomCover from './components/CustomCover.vue';
 import CustomCover from './components/CustomCover.vue';
 import TransReport from './components/catalog/transReport.vue';
 import TransReport from './components/catalog/transReport.vue';
-import {countComponentName,pptConfigInit,toTextProps,toJson,svg2Base64,getImgRealSize,calcScale,getShapeOptions,createRandomCode,getTableData,getChartInfo} from './utils/untils';
+import {countComponentName,pptConfigInit,toTextProps,toJson,svg2Base64,svgData2Base64,getImgRealSize,calcScale,getShapeOptions,createRandomCode,getTableData,getChartInfo} from './utils/untils';
 import {marginTop,modelConfig,pptSlideMaster,pptSlideMasterEn,pptCoverEn} from './utils/config';
 import {marginTop,modelConfig,pptSlideMaster,pptSlideMasterEn,pptCoverEn} from './utils/config';
 import pptmixin from '../mixins/pptMixins';
 import pptmixin from '../mixins/pptMixins';
 import mixins from '../mixins/mixins';
 import mixins from '../mixins/mixins';
@@ -105,6 +114,10 @@ export default {
       transReportShow:false,//转双周报的弹窗是否显示
       transReportShow:false,//转双周报的弹窗是否显示
       transChartType:2,//生成PPT时,转换动态图表的方式:1.将svg传至服务端转换;2.调用changeUrl转换
       transChartType:2,//生成PPT时,转换动态图表的方式:1.将svg传至服务端转换;2.调用changeUrl转换
       currentLang:'en',//语言标识
       currentLang:'en',//语言标识
+
+      setCompression:true,
+      setCompression2:true,
+      downloadLoading:null,
     };
     };
   },
   },
   watch:{
   watch:{
@@ -127,10 +140,11 @@ export default {
         text: this.$t('Slides.generating_powerPoint_msg'),
         text: this.$t('Slides.generating_powerPoint_msg'),
       });
       });
       this.isPublish = true
       this.isPublish = true
-      if(this.loadingAll){
-        await this.pageToPptx()       
-      } 
-      this.isPublish = false
+      this.$nextTick(()=>{
+            setTimeout(async ()=>{
+                await this.pageToPptx() 
+            },50)
+        })
     },
     },
     async downloadPPT(){
     async downloadPPT(){
         this.loadingInstance = this.$loading({
         this.loadingInstance = this.$loading({
@@ -139,8 +153,11 @@ export default {
             text: "生成ppt中...",
             text: "生成ppt中...",
         });
         });
         this.isPublish = true
         this.isPublish = true
-        await this.pageToPptx('dowload') 
-        this.isPublish = false
+        this.$nextTick(()=>{
+            setTimeout(async ()=>{
+                await this.pageToPptx('dowload') 
+            },50)
+        })
     },
     },
     //计算ppt的版式名称
     //计算ppt的版式名称
     getComponentName(modelId){
     getComponentName(modelId){
@@ -244,8 +261,21 @@ export default {
       const SlideMaster = _.cloneDeep(pptSlideMasterEn) 
       const SlideMaster = _.cloneDeep(pptSlideMasterEn) 
       SlideMaster.objects[1] = {image: {x:0,y:0,w:10,h:7,path:this.pptBgImage}}
       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)
       let pptx = pptConfigInit(new pptxgen(),this.LayoutType,'en',SlideMaster,this.pptBgImage)
-      //添加一页空白页,后续转换需要
-      pptx.addSlide()
+      //添加封面
+      let cover = pptx.addSlide()
+      let coverId = this.loadingAll?'cover':'changecover'
+      //let coverImg = await this.htmlToCanvans(coverId)
+      let coverImg = $(`#${coverId} .cover img`)[0].src
+      cover.addImage({
+        path: coverImg,
+        x: 0,
+        y: 0,
+        w:'100%',
+        h: '100%',
+        size: { type: "contain" },
+      })
+      //自定义封面页的内容
+      cover = this.setPPTCover(cover,this.pptCoverContent,this.coverInfo.page.Title)
       const length = this.pageList.length;
       const length = this.pageList.length;
       for (let i = 0; i < length; i++) {
       for (let i = 0; i < length; i++) {
         let slide = pptx.addSlide({ masterName: pptSlideMaster.title });
         let slide = pptx.addSlide({ masterName: pptSlideMaster.title });
@@ -265,17 +295,10 @@ export default {
             console.log("img/chart...");
             console.log("img/chart...");
             let svgData = this.optionMap[this.pageList[i].elements[j].chartId] instanceof Object
             let svgData = this.optionMap[this.pageList[i].elements[j].chartId] instanceof Object
             if(svgData){
             if(svgData){
-              if(this.transChartType===1){
-                //将svg传至服务端,返回一个线上图片地址
-                const params = new FormData();
-			          params.append('Img',svgData)
-                const { Data } = await dataBaseInterface.uploadImgSvg(params);
-                imgData = Data.ResourceUrl
-              }else if(this.transChartType===2){
                 //将svgDom转为base64 png,返回一个base64字符串
                 //将svgDom转为base64 png,返回一个base64字符串
-                imgData = await this.changeUrl(`chart_${i}_${elements[j].position}`)
-                //imgData = svg2Base64($(`#chart_${i}_${elements[j].position} svg`)[0])//生成的svg背景色是黑色不是透明
-              }
+                imgData = this.setCompression2
+                         ?svgData2Base64(this.chartSVGDataMap[`chart_${i}_${elements[j].position}_${elements[j].chartId}`])
+                         :await this.changeUrl(`chart_${i}_${elements[j].position}`)
             }
             }
           } else if (elements[j].type === 'text'){
           } else if (elements[j].type === 'text'){
             console.log('text...')
             console.log('text...')
@@ -299,16 +322,6 @@ export default {
             elements[j].position
             elements[j].position
           );
           );
           if (imgData) {
           if (imgData) {
-            if(this.transChartType===1){
-              slide.addImage({
-                path:imgData,
-                x: x,
-                y: y,
-                w: width,
-                h: height,
-                size: { type: "contain" },
-              });
-            }else if(this.transChartType===2){
               slide.addImage({
               slide.addImage({
                 data:imgData,
                 data:imgData,
                 x: x,
                 x: x,
@@ -317,7 +330,6 @@ export default {
                 h: height,
                 h: height,
                 size: { type: "contain" },
                 size: { type: "contain" },
               });
               });
-            }
 
 
             //追加生成图表底部文字
             //追加生成图表底部文字
             this.transChartBottomInfo(slide,{x,y,width,height},this.optionMap[this.pageList[i].elements[j].chartId])
             this.transChartBottomInfo(slide,{x,y,width,height},this.optionMap[this.pageList[i].elements[j].chartId])
@@ -400,62 +412,24 @@ export default {
             size: { type: "contain" },
             size: { type: "contain" },
         })
         })
       }
       }
-      //为了把封面放到第一页,操作pptx.slides达不成想要的效果,于是弄了个pptx2
-      //将封面放在最后生成是因为htmlToCanvans占用太多内存会导致页面假死
-      let pptx2 = pptConfigInit(new pptxgen(),this.LayoutType,'en',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,
-        x: 0,
-        y: 0,
-        w:'100%',
-        h: '100%',
-        size: { type: "contain" },
-      })
-      //生成的ppt需要可以在封面页更改标题和类型,所以封面信息手动写入
-      /* const coverInfo = [
-        //{text:'—————————————————————————————————\n',options:{fontSize:16*0.75,breakLine:true}},
-        {text:this.coverInfo.page.Title,options:{fontSize:28*0.75,breakLine:true}},
-        {text:`\n${this.pptCoverCompenyName||'ETA'}`,
-         options:{fontSize:16*0.75,breakLine:true}},
-        {text:`\n — ${this.coverInfo.page.ReportType} —`,options:{fontSize:16*0.75,breakLine:true}}, 
-        {text:`\n${this.pptCoverDepartName||'Research Department'}`,options:{fontSize:16*0.75,breakLine:true}},
-        {text:this.coverInfo.page.PptDate,options:{fontSize:16*0.75,breakLine:true}},
-        //{text:'\n—————————————————————————',options:{fontSize:16*0.75,breakLine:true}}
-      ]
-      cover.addText(coverInfo,{
-        x:'38%',
-        y:'50%',
-        w:'60%',
-        h:'28%',
-        color:(this.pptCoverTextColor||'#ffffff').slice(1),
-        align:'center',
-        fontFace:'SimHei'
-      }) */
-      //自定义封面页的内容
-      cover = this.setPPTCover(cover,this.pptCoverContent,this.coverInfo.page.Title)
-      //遍历pptx.slides,重新给每一项的部分属性赋值,再推入pptx2.slides中
-      //第一页不需要,因为是空白的
-      for(let i=1;i<pptx.slides.length;i++){
-        let item  = _.cloneDeep(pptx.slides[i])
-        item._name = `Slide ${i+1}`
-        item._slideNum = i+1
-        item._rId = cover._rId+i
-        item._slideId  = cover._slideId+i
-        pptx2._slides.push(item)
-      }
       this.loadingInstance.close();
       this.loadingInstance.close();
+      this.isPublish = false
       //结束计时
       //结束计时
       const end = Date.now()
       const end = Date.now()
       console.log("转换ppt用时:",Math.floor((end-start)/1000),' s')
       console.log("转换ppt用时:",Math.floor((end-start)/1000),' s')
       //pptx2.writeFile({ fileName: "test.pptx" });//本地测试用
       //pptx2.writeFile({ fileName: "test.pptx" });//本地测试用
       //直接下载
       //直接下载
       if(type==='dowload'){
       if(type==='dowload'){
-        pptx2.writeFile({ fileName: `${this.coverInfo.page.Title||'unname'}.pptx` });
+        this.downloadLoading = this.$loading({
+            fullscreen:true,
+            text:'生成PPT完成,正在下载PPT...'
+        })
+        pptx2.writeFile({ 
+            fileName: `${this.coverInfo.page.Title||'unname'}.pptx`,
+            compression:this.setCompression
+        }).then(()=>{
+            this.downloadLoading.close()
+        })
         return
         return
       }
       }
       this.publishLoading = this.$loading({
       this.publishLoading = this.$loading({
@@ -486,15 +460,17 @@ export default {
           partSize: 1024 * 1024 * 10, // 10MB
           partSize: 1024 * 1024 * 10, // 10MB
         }
         }
       };
       };
-
-      pptx2.write('blob').then((data)=>{
+      //outputType为blob时不会启用压缩,为STREAM时会按nodebuffer压缩
+      pptx2.write({compression:this.setCompression,outputType:'STREAM'}).then((data)=>{
+        //将nodebuffer转为blob
+        const blob = new Blob([data])
         // 1走后端接口上传
         // 1走后端接口上传
         const uploadType=this.$setting.dynamicOutLinks.PptUpdateApi ||
         const uploadType=this.$setting.dynamicOutLinks.PptUpdateApi ||
                         this.$store.state.dynamicOutLinks.PptUpdateApi ||
                         this.$store.state.dynamicOutLinks.PptUpdateApi ||
                         JSON.parse(localStorage.getItem('dynamicOutLinks')).PptUpdateApi
                         JSON.parse(localStorage.getItem('dynamicOutLinks')).PptUpdateApi
         if(uploadType==1){
         if(uploadType==1){
           let form = new FormData()
           let form = new FormData()
-          form.append("file",data)
+          form.append("file",blob)
           form.append("PptId",this.$route.query.id) 
           form.append("PptId",this.$route.query.id) 
           pptInterface.uploadPPTXFile(form).then(res=>{
           pptInterface.uploadPPTXFile(form).then(res=>{
             if(res.Ret===200){
             if(res.Ret===200){

+ 84 - 93
src/views/ppt_manage/newVersion/pptPublish.vue

@@ -1,12 +1,21 @@
 <template>
 <template>
   <div class="publish-page-wrap page-wrap">
   <div class="publish-page-wrap page-wrap">
       <div class="pub-btn-list">
       <div class="pub-btn-list">
-        <!-- <el-button  type="primary" style="width:120px;height:40px;" @click="transHandle" :loading="isPublish">{{isPublish?'发布中':'发布'}}</el-button> -->
-        <!-- <div>图表转换方式:
-          <el-radio v-model="transChartType" :label="1">传服务器</el-radio>
-          <el-radio v-model="transChartType" :label="2">本地转</el-radio>
-        </div> -->
         <el-button  type="primary" plain style="width:182px;height:40px;" @click="$router.push({path:'/pptlist'})">{{$t('Slides.return_to_list')}}</el-button>
         <el-button  type="primary" plain style="width:182px;height:40px;" @click="$router.push({path:'/pptlist'})">{{$t('Slides.return_to_list')}}</el-button>
+
+        <!-- 下载配置 -->
+        <!-- <div class="setting">
+            <div>
+                <span>是否压缩</span>
+                <el-radio v-model="setCompression" :label="true">是</el-radio>
+                <el-radio v-model="setCompression" :label="false">否</el-radio>
+            </div>
+            <div>
+                <span>图表转换优化</span>
+                <el-radio v-model="setCompression2" :label="true">开</el-radio>
+                <el-radio v-model="setCompression2" :label="false">关</el-radio>
+            </div>
+        </div> -->
         <el-button  type="primary" style="width:182px;height:40px;margin-left: 0;" @click="downloadPPT" :disabled="isPublish">{{$t('Slides.operations_download')}}</el-button>
         <el-button  type="primary" style="width:182px;height:40px;margin-left: 0;" @click="downloadPPT" :disabled="isPublish">{{$t('Slides.operations_download')}}</el-button>
         <el-dropdown split-button style="width:182px;height:40px;" type="primary" @click="transHandle" @command="handleCommand" :disabled="isPublish">
         <el-dropdown split-button style="width:182px;height:40px;" type="primary" @click="transHandle" @command="handleCommand" :disabled="isPublish">
           {{layoutStr}}
           {{layoutStr}}
@@ -65,7 +74,7 @@ import Cover from './components/Cover.vue';
 import CustomCover from './components/CustomCover.vue';
 import CustomCover from './components/CustomCover.vue';
 import TransReport from './components/catalog/transReport.vue';
 import TransReport from './components/catalog/transReport.vue';
 //import {pageList} from './utils/mock';
 //import {pageList} from './utils/mock';
-import {countComponentName,pptConfigInit,toTextProps,toJson,svg2Base64,getImgRealSize,calcScale,countStrSize,getShapeOptions,createRandomCode,getTableData,getChartInfo,pptInit,rgbaToHex } from './utils/untils';
+import {countComponentName,pptConfigInit,toTextProps,toJson,svg2Base64,svgData2Base64,getImgRealSize,calcScale,countStrSize,getShapeOptions,createRandomCode,getTableData,getChartInfo,pptInit,rgbaToHex } from './utils/untils';
 import {marginTop,modelConfig,pptSlideMaster} from './utils/config';
 import {marginTop,modelConfig,pptSlideMaster} from './utils/config';
 import pptmixin from '../mixins/pptMixins';
 import pptmixin from '../mixins/pptMixins';
 import mixins from '../mixins/mixins';
 import mixins from '../mixins/mixins';
@@ -117,7 +126,10 @@ export default {
       layoutStr:`10:7${this.$t('Slides.default_publish')}`,
       layoutStr:`10:7${this.$t('Slides.default_publish')}`,
       ReportId:0,//ppt对应的双周报id,如果没转过,则为0
       ReportId:0,//ppt对应的双周报id,如果没转过,则为0
       transReportShow:false,//转双周报的弹窗是否显示
       transReportShow:false,//转双周报的弹窗是否显示
-      transChartType:2,//生成PPT时,转换动态图表的方式:1.将svg传至服务端转换;2.调用changeUrl转换
+
+      setCompression:true,
+      setCompression2:true,
+      downloadLoading:null
     };
     };
   },
   },
   watch:{
   watch:{
@@ -149,20 +161,24 @@ export default {
         text: this.$t('Slides.generating_powerPoint_msg'),
         text: this.$t('Slides.generating_powerPoint_msg'),
       });
       });
       this.isPublish = true
       this.isPublish = true
-      if(this.loadingAll){
-        await this.pageToPptx() 
-      }
-      this.isPublish = false
+      this.$nextTick(()=>{
+            setTimeout(async ()=>{
+                await this.pageToPptx() 
+            },50)
+        })
     },
     },
     async downloadPPT(){
     async downloadPPT(){
         this.loadingInstance = this.$loading({
         this.loadingInstance = this.$loading({
             lock:true,
             lock:true,
             fullscreen: true,
             fullscreen: true,
-            text: "生成ppt中...",
+            text: this.$t('Slides.generating_powerPoint_msg'),
         });
         });
         this.isPublish = true
         this.isPublish = true
-        await this.pageToPptx('dowload') 
-        this.isPublish = false
+        this.$nextTick(()=>{
+            setTimeout(async ()=>{
+                await this.pageToPptx('dowload') 
+            },50)
+        })
     },
     },
     //计算ppt的版式名称
     //计算ppt的版式名称
     getComponentName(modelId){
     getComponentName(modelId){
@@ -270,8 +286,20 @@ export default {
       const SlideMaster = _.cloneDeep(pptSlideMaster) 
       const SlideMaster = _.cloneDeep(pptSlideMaster) 
       SlideMaster.objects[1] = {image: {x:0,y:0,w:10,h:7,path:this.pptBgImage}}
       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)
       let pptx = pptConfigInit(new pptxgen(),this.LayoutType,'ch',SlideMaster,this.pptBgImage)
-      //添加一页空白页,后续转换需要
-      pptx.addSlide()
+      //添加封面
+      let cover = pptx.addSlide()
+      let coverId = this.loadingAll?'cover':'changecover'
+      let coverImg = $(`#${coverId} .cover img`)[0].src
+      cover.addImage({
+        path: coverImg,
+        x: 0,
+        y: 0,
+        w:'100%',
+        h: '100%',
+        size: { type: "contain" },
+      })
+      //自定义封面页的内容
+      cover = this.setPPTCover(cover,this.pptCoverContent,this.coverInfo.page.Title)
       const length = this.pageList.length;
       const length = this.pageList.length;
       for (let i = 0; i < length; i++) {
       for (let i = 0; i < length; i++) {
         let slide = pptx.addSlide({ masterName: pptSlideMaster.title });
         let slide = pptx.addSlide({ masterName: pptSlideMaster.title });
@@ -291,17 +319,15 @@ export default {
             console.log("img/chart...");
             console.log("img/chart...");
             let svgData = this.optionMap[this.pageList[i].elements[j].chartId] instanceof Object
             let svgData = this.optionMap[this.pageList[i].elements[j].chartId] instanceof Object
             if(svgData){
             if(svgData){
-              if(this.transChartType===1){
-                //将svg传至服务端,返回一个线上图片地址
-                const params = new FormData();
-			          params.append('Img',svgData)
-                const { Data } = await dataBaseInterface.uploadImgSvg(params);
-                imgData = Data.ResourceUrl
-              }else if(this.transChartType===2){
                 //将svgDom转为base64 png,返回一个base64字符串
                 //将svgDom转为base64 png,返回一个base64字符串
-                imgData = await this.changeUrl(`chart_${i}_${elements[j].position}`)
-                //imgData = svg2Base64($(`#chart_${i}_${elements[j].position} svg`)[0])//生成的svg背景色是黑色不是透明
-              }
+                //转换方式有两种,两者生成的图表无明显差别
+                /**
+                 * svgData2Base64:通过chart.getSVG获取,可能会与页面上的图表有所差别,但生成的svg更小,速度更快
+                 * changeUrl:通过html获取,页面上什么样,图表就什么样,为了保证清晰度将原图表放大4倍后通过canvas转为png,这个过程比较耗时,生成的文件也会比较大
+                 */
+                imgData = this.setCompression2
+                         ?svgData2Base64(this.chartSVGDataMap[`chart_${i}_${elements[j].position}_${elements[j].chartId}`])
+                         :await this.changeUrl(`chart_${i}_${elements[j].position}`)
             }
             }
           } else if (elements[j].type === 'text'){
           } else if (elements[j].type === 'text'){
             console.log('text...')
             console.log('text...')
@@ -325,16 +351,6 @@ export default {
             elements[j].position
             elements[j].position
           );
           );
           if (imgData) { //图表
           if (imgData) { //图表
-            if(this.transChartType===1){
-              slide.addImage({
-                path:imgData,
-                x: x,
-                y: y,
-                w: width,
-                h: height,
-                size: { type: "contain" },
-              });
-            }else if(this.transChartType===2){
               slide.addImage({
               slide.addImage({
                 data:imgData,
                 data:imgData,
                 x: x,
                 x: x,
@@ -343,7 +359,6 @@ export default {
                 h: height,
                 h: height,
                 size: { type: "contain" },
                 size: { type: "contain" },
               });
               });
-            }
 
 
             //追加生成图表底部文字
             //追加生成图表底部文字
             this.transChartBottomInfo(slide,{x,y,width,height},this.optionMap[this.pageList[i].elements[j].chartId])
             this.transChartBottomInfo(slide,{x,y,width,height},this.optionMap[this.pageList[i].elements[j].chartId])
@@ -365,10 +380,7 @@ export default {
             const offsetY = realSize.height===imgData2Obj.imgHeight?0:(percentHeight-(realSize.height/imgData2Obj.imgHeight*percentHeight))/2
             const offsetY = realSize.height===imgData2Obj.imgHeight?0:(percentHeight-(realSize.height/imgData2Obj.imgHeight*percentHeight))/2
             const realX = Number(x.substring(0,x.length-1))+offsetX
             const realX = Number(x.substring(0,x.length-1))+offsetX
             const realY = Number(y.substring(0,y.length-1))+offsetY
             const realY = Number(y.substring(0,y.length-1))+offsetY
-            /* const realWidth = offsetX===0?width:(realSize.width/imgData2Obj.imgWidth*percentWidth)
-            const realHeight = offsetY===0?height:(realSize.height/imgData2Obj.imgHeight*percentHeight) */
-            //console.log('position x',x,' y',y,' width',width,' height',height)
-            //console.log('x y',realX,realY,'w h',realWidth,realHeight)
+
             slide.addImage({
             slide.addImage({
               path:imgData2+'?v='+new Date().getTime(),
               path:imgData2+'?v='+new Date().getTime(),
               x:realX+'%',
               x:realX+'%',
@@ -430,61 +442,25 @@ export default {
             size: { type: "contain" },
             size: { type: "contain" },
         })
         })
       }
       }
-      
-      //为了把封面放到第一页,操作pptx.slides达不成想要的效果,于是弄了个pptx2
-      //将封面放在最后生成是因为htmlToCanvans占用太多内存会导致页面假死
-      let pptx2 = pptConfigInit(new pptxgen(),this.LayoutType,'ch',SlideMaster,this.pptBgImage)
-      //添加封面
-      let cover = pptx2.addSlide()
-      let coverId = this.loadingAll?'cover':'changecover'
-      let coverImg = $(`#${coverId} .cover img`)[0].src
-      cover.addImage({
-        path: coverImg,
-        x: 0,
-        y: 0,
-        w:'100%',
-        h: '100%',
-        size: { type: "contain" },
-      })
-      //生成的ppt需要可以在封面页更改标题和类型,所以封面信息手动写入
-      /* const coverInfo = [
-        {text:'—————————————————————————————————\n',options:{fontSize:16*0.75,breakLine:true}},
-        {text:this.coverInfo.page.Title,options:{fontSize:28*0.75,breakLine:true}},
-        {text:`\n— ${this.pptCoverCompenyName||'ETA'} ● ${this.coverInfo.page.ReportType} —`,
-         options:{fontSize:16*0.75,breakLine:false}},
-        {text:`\n${this.pptCoverDepartName||'投研部'}`,options:{fontSize:16*0.75,breakLine:true}},
-        {text:this.coverInfo.page.PptDate,options:{fontSize:16*0.75,breakLine:true}},
-        {text:'\n—————————————————————————',options:{fontSize:16*0.75,breakLine:true}}
-      ]
-      cover.addText(coverInfo,{
-        x:'38%',
-        y:'50%',
-        w:'60%',
-        h:'28%',
-        color:(this.pptCoverTextColor||'#ffffff').slice(1),
-        align:'center',
-        fontFace:'SimHei'
-      }) */
-      //自定义封面页的内容
-      cover = this.setPPTCover(cover,this.pptCoverContent,this.coverInfo.page.Title)
-      //遍历pptx.slides,重新给每一项的部分属性赋值,再推入pptx2.slides中
-      //第一页不需要,因为是空白的
-      for(let i=1;i<pptx.slides.length;i++){
-        let item  = _.cloneDeep(pptx.slides[i])
-        item._name = `Slide ${i+1}`
-        item._slideNum = i+1
-        item._rId = cover._rId+i
-        item._slideId  = cover._slideId+i
-        pptx2._slides.push(item)
-      }
+     
       this.loadingInstance.close();
       this.loadingInstance.close();
+      this.isPublish = false
       //结束计时
       //结束计时
       const end = Date.now()
       const end = Date.now()
       console.log("转换ppt用时:",Math.floor((end-start)/1000),' s')
       console.log("转换ppt用时:",Math.floor((end-start)/1000),' s')
-      //pptx2.writeFile({ fileName: "test.pptx" });//本地测试用
+      //pptx.writeFile({ fileName: "test.pptx" });//本地测试用
       //直接下载
       //直接下载
       if(type==='dowload'){
       if(type==='dowload'){
-        pptx2.writeFile({ fileName: `${this.coverInfo.page.Title||'unname'}.pptx` });
+        this.downloadLoading = this.$loading({
+            fullscreen:true,
+            text:'生成PPT完成,正在下载PPT...'
+        })
+        pptx.writeFile({ 
+            fileName: `${this.coverInfo.page.Title||'unname'}.pptx`,
+            compression:this.setCompression 
+        }).then(()=>{
+            this.downloadLoading.close()
+        })
         return
         return
       }
       }
       this.publishLoading = this.$loading({
       this.publishLoading = this.$loading({
@@ -515,14 +491,18 @@ export default {
 
 
       //console.log('pptx',pptx)
       //console.log('pptx',pptx)
       //根据配置选择是走后端接口上传还是直接前端上传到oss
       //根据配置选择是走后端接口上传还是直接前端上传到oss
-      pptx2.write('blob').then((data)=>{
+
+      //outputType为blob时不会启用压缩,为STREAM时会按nodebuffer压缩
+      pptx.write({compression:this.setCompression,outputType:'STREAM'}).then((data)=>{
+        //将nodebuffer转为blob
+        const blob = new Blob([data])
         // 1走后端接口上传
         // 1走后端接口上传
         const uploadType=this.$setting.dynamicOutLinks.PptUpdateApi ||
         const uploadType=this.$setting.dynamicOutLinks.PptUpdateApi ||
                         this.$store.state.dynamicOutLinks.PptUpdateApi ||
                         this.$store.state.dynamicOutLinks.PptUpdateApi ||
                         JSON.parse(localStorage.getItem('dynamicOutLinks')).PptUpdateApi
                         JSON.parse(localStorage.getItem('dynamicOutLinks')).PptUpdateApi
         if(uploadType==1){
         if(uploadType==1){
           let form = new FormData()
           let form = new FormData()
-          form.append("file",data)
+          form.append("file",blob)
           form.append("PptId",this.$route.query.id) 
           form.append("PptId",this.$route.query.id) 
           pptInterface.uploadPPTXFile(form).then(res=>{
           pptInterface.uploadPPTXFile(form).then(res=>{
             if(res.Ret===200){
             if(res.Ret===200){
@@ -539,7 +519,7 @@ export default {
                         this.$store.state.dynamicOutLinks.ObjectStorageClient ||
                         this.$store.state.dynamicOutLinks.ObjectStorageClient ||
                         JSON.parse(localStorage.getItem('dynamicOutLinks')).ObjectStorageClient
                         JSON.parse(localStorage.getItem('dynamicOutLinks')).ObjectStorageClient
         // 上传到 对象存储器
         // 上传到 对象存储器
-        uploadFileDirect(clientType,data,temName,options).then(url=>{
+        uploadFileDirect(clientType,blob,temName,options).then(url=>{
           console.log('文件地址',url);
           console.log('文件地址',url);
           this.publishPPT(url)
           this.publishPPT(url)
         }).catch(err=>{
         }).catch(err=>{
@@ -835,5 +815,16 @@ $titleColor:#333333;
     width:1100px;
     width:1100px;
     height: 770px;
     height: 770px;
   }
   }
+  .el-dropdown{
+    .el-button-group{
+        display: flex;
+        width: 100%;
+        .el-button{
+            &:first-of-type{
+                flex:1;
+            }
+        }
+    }
+  }
 }
 }
 </style>
 </style>

+ 4 - 1
src/views/ppt_manage/newVersion/utils/untils.js

@@ -461,6 +461,9 @@ const encode = (input) => {
   }
   }
   return output
   return output
 }
 }
+export const svgData2Base64 = (svg)=>{
+    return PREFIX + encode(svg)
+}
 export const svg2Base64 = (element) => {
 export const svg2Base64 = (element) => {
   const XMLS = new XMLSerializer()
   const XMLS = new XMLSerializer()
   const svg = XMLS.serializeToString(element)
   const svg = XMLS.serializeToString(element)
@@ -624,7 +627,7 @@ export const getTableData = (data)=>{
       let cellOptions = {
       let cellOptions = {
         colspan:cell.mc.cs===0?1:cell.mc.cs,
         colspan:cell.mc.cs===0?1:cell.mc.cs,
         rowspan:cell.mc.rs===0?1:cell.mc.rs,
         rowspan:cell.mc.rs===0?1:cell.mc.rs,
-        color: cell.fc?cell.fc.substring(1):'333',
+        color: cell.fc?cell.fc.substring(1):'333333',
         fill: cell.bg ? cell.bg.substring(1):'',
         fill: cell.bg ? cell.bg.substring(1):'',
         bold: cell.bl ? true : false,
         bold: cell.bl ? true : false,
         italic: cell.it ? true : false,
         italic: cell.it ? true : false,