|
@@ -1,12 +1,21 @@
|
|
|
<template>
|
|
|
<div class="publish-page-wrap page-wrap">
|
|
|
<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>
|
|
|
+
|
|
|
+ <!-- 下载配置 -->
|
|
|
+ <!-- <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-dropdown split-button style="width:182px;height:40px;" type="primary" @click="transHandle" @command="handleCommand" :disabled="isPublish">
|
|
|
{{layoutStr}}
|
|
@@ -65,7 +74,7 @@ import Cover from './components/Cover.vue';
|
|
|
import CustomCover from './components/CustomCover.vue';
|
|
|
import TransReport from './components/catalog/transReport.vue';
|
|
|
//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 pptmixin from '../mixins/pptMixins';
|
|
|
import mixins from '../mixins/mixins';
|
|
@@ -117,7 +126,10 @@ export default {
|
|
|
layoutStr:`10:7${this.$t('Slides.default_publish')}`,
|
|
|
ReportId:0,//ppt对应的双周报id,如果没转过,则为0
|
|
|
transReportShow:false,//转双周报的弹窗是否显示
|
|
|
- transChartType:2,//生成PPT时,转换动态图表的方式:1.将svg传至服务端转换;2.调用changeUrl转换
|
|
|
+
|
|
|
+ setCompression:true,
|
|
|
+ setCompression2:true,
|
|
|
+ downloadLoading:null
|
|
|
};
|
|
|
},
|
|
|
watch:{
|
|
@@ -149,20 +161,24 @@ export default {
|
|
|
text: this.$t('Slides.generating_powerPoint_msg'),
|
|
|
});
|
|
|
this.isPublish = true
|
|
|
- if(this.loadingAll){
|
|
|
- await this.pageToPptx()
|
|
|
- }
|
|
|
- this.isPublish = false
|
|
|
+ this.$nextTick(()=>{
|
|
|
+ setTimeout(async ()=>{
|
|
|
+ await this.pageToPptx()
|
|
|
+ },50)
|
|
|
+ })
|
|
|
},
|
|
|
async downloadPPT(){
|
|
|
this.loadingInstance = this.$loading({
|
|
|
lock:true,
|
|
|
fullscreen: true,
|
|
|
- text: "生成ppt中...",
|
|
|
+ text: this.$t('Slides.generating_powerPoint_msg'),
|
|
|
});
|
|
|
this.isPublish = true
|
|
|
- await this.pageToPptx('dowload')
|
|
|
- this.isPublish = false
|
|
|
+ this.$nextTick(()=>{
|
|
|
+ setTimeout(async ()=>{
|
|
|
+ await this.pageToPptx('dowload')
|
|
|
+ },50)
|
|
|
+ })
|
|
|
},
|
|
|
//计算ppt的版式名称
|
|
|
getComponentName(modelId){
|
|
@@ -270,8 +286,20 @@ export default {
|
|
|
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()
|
|
|
+ //添加封面
|
|
|
+ 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;
|
|
|
for (let i = 0; i < length; i++) {
|
|
|
let slide = pptx.addSlide({ masterName: pptSlideMaster.title });
|
|
@@ -291,17 +319,15 @@ export default {
|
|
|
console.log("img/chart...");
|
|
|
let svgData = this.optionMap[this.pageList[i].elements[j].chartId] instanceof Object
|
|
|
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字符串
|
|
|
- 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'){
|
|
|
console.log('text...')
|
|
@@ -325,16 +351,6 @@ export default {
|
|
|
elements[j].position
|
|
|
);
|
|
|
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({
|
|
|
data:imgData,
|
|
|
x: x,
|
|
@@ -343,7 +359,6 @@ export default {
|
|
|
h: height,
|
|
|
size: { type: "contain" },
|
|
|
});
|
|
|
- }
|
|
|
|
|
|
//追加生成图表底部文字
|
|
|
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 realX = Number(x.substring(0,x.length-1))+offsetX
|
|
|
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({
|
|
|
path:imgData2+'?v='+new Date().getTime(),
|
|
|
x:realX+'%',
|
|
@@ -430,61 +442,25 @@ export default {
|
|
|
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.isPublish = false
|
|
|
//结束计时
|
|
|
const end = Date.now()
|
|
|
console.log("转换ppt用时:",Math.floor((end-start)/1000),' s')
|
|
|
- //pptx2.writeFile({ fileName: "test.pptx" });//本地测试用
|
|
|
+ //pptx.writeFile({ fileName: "test.pptx" });//本地测试用
|
|
|
//直接下载
|
|
|
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
|
|
|
}
|
|
|
this.publishLoading = this.$loading({
|
|
@@ -515,14 +491,18 @@ export default {
|
|
|
|
|
|
//console.log('pptx',pptx)
|
|
|
//根据配置选择是走后端接口上传还是直接前端上传到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走后端接口上传
|
|
|
const uploadType=this.$setting.dynamicOutLinks.PptUpdateApi ||
|
|
|
this.$store.state.dynamicOutLinks.PptUpdateApi ||
|
|
|
JSON.parse(localStorage.getItem('dynamicOutLinks')).PptUpdateApi
|
|
|
if(uploadType==1){
|
|
|
let form = new FormData()
|
|
|
- form.append("file",data)
|
|
|
+ form.append("file",blob)
|
|
|
form.append("PptId",this.$route.query.id)
|
|
|
pptInterface.uploadPPTXFile(form).then(res=>{
|
|
|
if(res.Ret===200){
|
|
@@ -539,7 +519,7 @@ export default {
|
|
|
this.$store.state.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);
|
|
|
this.publishPPT(url)
|
|
|
}).catch(err=>{
|
|
@@ -835,5 +815,16 @@ $titleColor:#333333;
|
|
|
width:1100px;
|
|
|
height: 770px;
|
|
|
}
|
|
|
+ .el-dropdown{
|
|
|
+ .el-button-group{
|
|
|
+ display: flex;
|
|
|
+ width: 100%;
|
|
|
+ .el-button{
|
|
|
+ &:first-of-type{
|
|
|
+ flex:1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|