// ppt发布逻辑
import apiSheet from '@/api/sheet.js'
import {apiPPTPublish} from '@/api/ppt.js'
import { showToast,showLoadingToast } from 'vant';
import pptxgen from "pptxgenjs";
import { parse } from "himalaya";
import _ from 'lodash'
import {pptLayout,pptSlideMaster,pptSlideMasterEn,modelConfig} from '../utils/config'
import {useUploadFileToOSS,useUploadToMinIO,useUploadToS3} from '@/hooks/useUploadFileToOSS'
import {getPPTConfig} from './createPPTContent'
import {usePublicSettingStore} from '@/store/modules/publicSetting'
import moment from 'moment'

const publicSettingStore = usePublicSettingStore()

let LoadingINS=null
let PPTContentList=[]
let pptId=0


// 校验ppt内容是否完整
function checkPPT(){
    for (let index = 1; index < PPTContentList.length-1; index++) {
        const element = PPTContentList[index];
        if(!element.title){
            console.log(`第${index}页内容不完整,请在pc端重新编辑!`);
            showToast(`第${index}页内容不完整,请在pc端重新编辑!`);
            return false
        }
        if(!element.elements.length===0){
            showToast(`第${index}页内容不完整,请在pc端重新编辑!`);
            return false
        }
    }
    return true
}

/**
 * PPT默认配置
 * @param pptx ppt插件实例
 * @param LayoutType ppt版式 1-10:7，2-16:9，3-4:3
 * @param lang 
 */
function PPTInit(pptx,LayoutType,lang='ch'){
    let layout = pptLayout
    let sliderMaster = lang==='ch'?pptSlideMaster:pptSlideMasterEn
    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: lang==='ch'?"/pptImg/pptitem_bg.png":"/pptImg/pptitem_bg_en.png"}}
        sliderMaster.slideNumber = {x:'95%',y:LayoutType===2?'92%':'95%',fontSize:12}
    }
    pptx.defineLayout(layout)
    pptx.layout = layout.name
    pptx.defineSlideMaster(sliderMaster)
    return pptx
}
/**
 * ppt配置化后 init ppt
 * @param pptx ppt插件实例
 * @param LayoutType ppt版式 1-10:7，2-16:9，3-4:3
 * @param lang 
 */
function pptConfigInit(pptx,LayoutType,lang='ch'){
    let layout = pptLayout
    let sliderMaster = lang==='ch'?pptSlideMaster:pptSlideMasterEn
    //将背景图替换成基本配置图
    const pptBgImg = getPPTConfig().pptBgImage||"/pptImg/pptitem_bg.png"
    sliderMaster.objects[1] = {image: {x:0,y:0,w:10,h:lang==='ch'?7:7+0.1,path:pptBgImg}}
    //如果布局不是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
}
//配置自定义封面内容
function setPPTCover(cover,pptCoverContent='',title=''){
    let contentList = []
    try{
        contentList = JSON.parse(pptCoverContent)
    }catch(e){
        contentList=[]
    }
    //将contentList的内容通过addText写入，方法与图层写入文字一致
    for(let i=0;i<contentList.length;i++){
        const {
            percentageTop,
            percentageLeft,
            percentageWidth,
            percentageHeight,
            richContent
        } = contentList[i]
        const position = {
            x:percentageLeft*100+'%',
            y:percentageTop*100+'%',
            w:percentageWidth*100+'%',
            h:percentageHeight*100+'%'
        }
        let textData = toTextProps(toJson(richContent))
        cover.addText(textData,{
            ...position,
            margin:10,
            fontSize:16*0.75,
            valign:'top'
        })
    }
    //不显示
    //若contentList为空，则在右下的位置显示标题
    /* if(!contentList.length){
        cover.addText(
            [{text:title,options:{fontSize:28*0.75,breakLine:true}}],
            {
                x:'38%',
                y:'50%',
                w:'60%',
                h:'28%',
                color:'ffffff',
                align:'center',
                fontFace:'SimHei'
            })
    } */
    return cover
}

// svg转base64图片，参考：https://github.com/scriptex/svg64
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
const PREFIX = 'data:image/svg+xml;base64,'
const utf8Encode = (string) => {
  string = string.replace(/\r\n/g, '\n')
  let utftext = ''
  for (let n = 0; n < string.length; n++) {
    const c = string.charCodeAt(n)
    if (c < 128) {
      utftext += String.fromCharCode(c)
    }
    else if (c > 127 && c < 2048) {
      utftext += String.fromCharCode((c >> 6) | 192)
      utftext += String.fromCharCode((c & 63) | 128)
    }
    else {
      utftext += String.fromCharCode((c >> 12) | 224)
      utftext += String.fromCharCode(((c >> 6) & 63) | 128)
      utftext += String.fromCharCode((c & 63) | 128)
    }
  }
  return utftext
}
const encode = (input) => {
  let output = ''
  let chr1, chr2, chr3, enc1, enc2, enc3, enc4
  let i = 0
  input = utf8Encode(input)
  while (i < input.length) {
    chr1 = input.charCodeAt(i++)
    chr2 = input.charCodeAt(i++)
    chr3 = input.charCodeAt(i++)
    enc1 = chr1 >> 2
    enc2 = ((chr1 & 3) << 4) | (chr2 >> 4)
    enc3 = ((chr2 & 15) << 2) | (chr3 >> 6)
    enc4 = chr3 & 63
    if (isNaN(chr2)) enc3 = enc4 = 64
    else if (isNaN(chr3)) enc4 = 64
    output = output + characters.charAt(enc1) + characters.charAt(enc2) + characters.charAt(enc3) + characters.charAt(enc4)
  }
  return output
}
function svg2Base64 (element) {
    const XMLS = new XMLSerializer()
    const svg = XMLS.serializeToString(element)
    return PREFIX + encode(svg)
    //return PREFIX + new http.Base64().encode(svg)
}

/**
 * 获取图表图片
 * @param id 图表dom中的id
 */
function changeUrl(id){
    let img = new Image()
    // const svgHtml = $(`#${id} svg`)[0].outerHTML
    /* img.src = `data:image/svg+xml;base64,${window.btoa(unescape(encodeURIComponent(svgHtml)))}` */
    img.src = svg2Base64($(`#${id} svg`)[0]);//不支持unescape时可用
    const imgW = $(`#${id}`)[0].offsetWidth*4,imgH = $(`#${id}`)[0].offsetHeight*4
    let canvas = document.createElement('canvas')
    canvas.width = imgW
    canvas.height = imgH
    return new Promise(resolve=>{
        img.onload = ()=>{
            //console.log('src',img.src)
            let ctx = canvas.getContext("2d")
            ctx.drawImage(img, 0, 0, imgW, imgH) 
            resolve(canvas.toDataURL("image/png"))
        }
    })   
}

//解析富文本，参考https://github.com/pipipi-pikachu/PPTist/tree/master/src/utils/htmlParser
//将text中被转义的字符转义回来,如:a<b 在富文本内会被转义成 a&lt;b
function replacer (_, p1){
    return {
        "&lt;": "<",
        "&gt;": ">",
        "&ldquo;": "“",
        "&rdquo;": "”",
        "&amp;":"&",
        "&lsquo;":"‘",
        "&rsquo;":"’",
        "&mdash;":'——',
        "&ge;":'≥',
        "&le;":'≤',
        "&middot;":'·'
    } [p1]
}
function toJson (html) {
    const json = parse(html)
    //console.log('json', json)
    return json
}
function toTextProps (json) {
    const slices = []
    let bulletFlag = false
    //剔除掉ul/li里面多余的\n
    for(const item of json){
      if(item.tagName==='ul'||item.tagName==='ol'){
        item.children = item.children.filter(i=>i.type!=='text')
      }
    }
    //console.log('json',json)
    const _parse = (json, baseStyleObj = {}) => {
      for (const item of json) {
        const isBlockTag = 'tagName' in item && ['div', 'li', 'p'].includes(item.tagName)
        if (isBlockTag && slices.length) {
          const lastSlice = slices[slices.length - 1]
          if (!lastSlice.options) lastSlice.options = {}
          lastSlice.options.breakLine = true
        }
        const styleObj = { ...baseStyleObj }
        const styleAttr = 'attributes' in item ? item.attributes.find(attr => attr.key === 'style') : null
        if (styleAttr && styleAttr.value) {
          const styleArr = styleAttr.value.split(';')
          for (const styleItem of styleArr) {
            const [_key, _value] = styleItem.split(': ')
            const [key, value] = [_key ? _key.trim() : '', _value ? _value.trim() : '']
            if (key && value) styleObj[key] = value
          }
        }
        if ('tagName' in item) {
          if (item.tagName === 'em') {
            styleObj['font-style'] = 'italic'
          }
          if (item.tagName === 'strong') {
            styleObj['font-weight'] = 'bold'
          }
          if (item.tagName === 'sup') {
            styleObj['vertical-align'] = 'super'
          }
          if (item.tagName === 'sub') {
            styleObj['vertical-align'] = 'sub'
          }
          if (item.tagName === 'a') {
            const attr = item.attributes.find(attr => attr.key === 'href')
            styleObj['href'] = attr || ''
          }
          if (item.tagName === 'ul') {
            styleObj['list-type'] = 'ul'
          }
          if (item.tagName === 'ol') {
            styleObj['list-type'] = 'ol'
          }
          if (item.tagName === 'li') {
            bulletFlag = true
          }
        }
        if ('tagName' in item && item.tagName === 'br') {
          slices.push({ text: '', options: { breakLine: true } })
        } else if ('content' in item) {
              const transStr = /(&lt;|&gt;|&ldquo;|&rdquo;|&amp;|&lsquo;|&rsquo;|&mdash;|&ge;|&le;|&middot;)/g
              const text = item.content.replace(/\n/g, '').replace(/&nbsp;/g, ' ').replace(transStr, replacer)
              const options = {}
  
              if (styleObj['font-size']&&styleObj['font-size']!='initial') {
                  options.fontSize = parseInt(styleObj['font-size']) * 0.75
              }
              if (styleObj['color']&&styleObj['color']!='initial') {
                  options.color = styleObj['color']
              }
              if (styleObj['background-color']&&styleObj['background-color']!='initial') {
                  options.highlight = styleObj['background-color']
              }
              if (styleObj['text-decoration-line']) {
                  if (styleObj['text-decoration-line'].indexOf('underline') !== -1) {
                      options.underline = {
                          color: options.color || '#000000',
                          style: 'sng',
                      }
                  }
                  if (styleObj['text-decoration-line'].indexOf('line-through') !== -1) {
                      options.strike = 'sngStrike'
                  }
              }
              if (styleObj['text-decoration']) {
                  if (styleObj['text-decoration'].indexOf('underline') !== -1) {
                      options.underline = {
                          color: options.color || '#000000',
                          style: 'sng',
                      }
                  }
                  if (styleObj['text-decoration'].indexOf('line-through') !== -1) {
                      options.strike = 'sngStrike'
                  }
              }
              if (styleObj['vertical-align']) {
                  if (styleObj['vertical-align'] === 'super') options.superscript = true
                  if (styleObj['vertical-align'] === 'sub') options.subscript = true
              }
              if (styleObj['text-align']&&styleObj['text-align']!='initial') options.align = styleObj['text-align']
              if (styleObj['font-weight']) options.bold = styleObj['font-weight'] === 'bold'
              if (styleObj['font-style']) options.italic = styleObj['font-style'] === 'italic'
              if (styleObj['font-family']&&styleObj['font-family']!='initial') options.fontFace = styleObj['font-family']
              if (styleObj['href']) options.hyperlink = {
                  url: styleObj['href']
              }
              if (bulletFlag && styleObj['list-type'] === 'ol') {
                options.bullet = { type: 'number', indent: 20 * 0.75 }
                options.paraSpaceBefore = 0.1
                bulletFlag = false
              }
              if (bulletFlag && styleObj['list-type'] === 'ul') {
                options.bullet = { indent: 20 * 0.75 }
                options.paraSpaceBefore = 0.1
                bulletFlag = false
              }
              slices.push({ text, options })
          } else if ('children' in item) _parse(item.children, styleObj)
      }
    }
    _parse(json)
    //console.log('slice', slices)
    return slices
}

//转换table的数据格式，写入ppt
function getTableData (data){
    //data:[{m:'表格数据',mc:{rs:2,cs:1}}] -> [{text:'表格数据',options:{rowspan:2,colspan:1}}]
    const tableData = []
    for(let i=0;i<data.length;i++){
      const row = data[i]
      const _row =[]
      for(let j=0;j<row.length;j++){
        const cell = row[j]
        let cellOptions = {
          colspan:cell.mc.cs===0?1:cell.mc.cs,
          rowspan:cell.mc.rs===0?1:cell.mc.rs,
          color: cell.fc?cell.fc.substring(1):'333',
          fill: cell.bg ? cell.bg.substring(1):'',
          bold: cell.bl ? true : false,
          italic: cell.it ? true : false,
        }
          _row.push({
            text:cell.m,
            options:cellOptions
          })
  
      }
      if(_row.length) tableData.push(_row)
    }
    return tableData
}

//计算各版式下,对应position在ppt中的位置
function getPosition(modelId, position) {
    //找到modelConfig[modelId].elments[position]
    const model = modelConfig.find((i) => i.modelId === modelId);
    const { x, y, width, height } = model.elements.find(
      (i) => i.position === position
    );
    return {
        x:x+'%',
        y:y+14+'%',
        width:width+'%',
        height:height+'%'
    };
}

//计算图像的真实尺寸(object-fit:scale-down)
function getImgRealSize ({imgWidth,imgHeight,naturalWidth,naturalHeight}){
    let ratio = naturalWidth/naturalHeight
    let width = imgHeight*ratio,height=imgHeight
    if(width>imgWidth){
        width = imgWidth
        height = imgWidth/ratio
    }
    return {width,height}
}

function toHex(n){
    return `${n > 15 ? '' : 0}${n.toString(16)}`;
} 
function toHexString (colorObj){
   const { r, g, b,} = colorObj;
   return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}

//将rgba转为hex+透明度的格式
//rgba(91,155,213,0.44) -> {color: "#5b9bd5",transparency: 56}
function parseRgbaColor (color) {
    const arr = color.match(/(\d(\.\d+)?)+/g) || [];
    const res = arr.map((s) => parseInt(s, 10));
    return {
        r: res[0],
        g: res[1],
        b: res[2],
        a: parseFloat(arr[3]),
    } 
}
//获取shape的格式数据,写入ppt
function rgbaToHex (rgba)  {
    const colorObj = parseRgbaColor(rgba);
    return {color:toHexString(colorObj),transparency:(1-colorObj.a)*100}
}
function getShapeOptions (el,position,scale){
    let options = {
      x:position.x+'%',
      y:position.y+'%',
      w:position.w+'%',
      h:position.h+'%',
    }
    if(el.type==='shape'&&el.shapeType==='Rect'){
      options.fill = rgbaToHex(el.fill)
      options.points=[
        {x:0,y:0,moveTo:true},
        {x:position.w+'%',y:0},
        {x:position.w+'%',y:position.h+'%'},
        {x:0,y:position.h+'%'},
        {close:true}
      ]
      options.line = {
        type:'solid',
        color:rgbaToHex(el.outline.color).color,
        transparency:rgbaToHex(el.outline.color).transparency,
        width:el.outline.width,
        dashType:el.outline.style === 'solid' ? 'solid' : 'dash',
      }
    }
    if(el.type==='line'){
      const width = Math.max(el.start[0], el.end[0])
      const height = Math.max(el.start[1], el.end[1])
      //px->英尺 1英尺≈100px（在ppt-width为10英尺的情况下）
      //906:628.6(编辑页的宽高比) --> 1008:705.6 相当于扩大了1.13倍
      options.w = (width*scale.x/100)>10?10:width*scale.x/100
      options.h = (height*scale.y/100)>10?10:height*scale.y/100
      options.points = [
        {x:Math.min(el.start[0]*scale.x/100,10),y:Math.min(el.start[1]*scale.y/100,10),moveTo:true},
        {x:Math.min(el.end[0]*scale.x/100,10),y:Math.min(el.end[1]*scale.y/100,10)}
      ]
      options.line={
        type:'solid',
        color:rgbaToHex(el.color).color,
        transparency:rgbaToHex(el.color).transparency,
        width:el.strokeWidth*0.75,//不缩小下的话线太粗了
        dashType:el.style==='solid'?'solid':'dash',
        beginArrowType: el.points[0] ? 'triangle' : 'none',
        endArrowType: el.points[1] ? 'triangle' : 'none',
      }
    }
    return options
}


// 生成随机码
function createRandomCode (len = 8) {
	const charset = `_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`
	const maxLen = charset.length
	let ret = ''
	for (let i = 0; i < len; i++) {
	  const randomIndex = Math.floor(Math.random() * maxLen)
	  ret += charset[randomIndex]
	}
	return ret
}

// 上传到阿里云
async function handleUploadToOSS(data){
	// 生成文件名
  const loading=showLoadingToast({
    message: "上传中...",
    duration: 0,
    forbidClick: true,
  })
	const t=new Date()
	const month=moment(t).format('YYYYMM')
	const day=moment(t).format('YYYYMMDD')
	const temName=`ppt/${month}/${day}/${createRandomCode(32)}.pptx`
	console.log('文件名',temName);
	const url=await useUploadFileToOSS(data,temName)
  loading.close()
	if(!url){
    setTimeout(() => {
      showToast('生成ppt失败')
    }, 60);
		return
	}
	handlePublishPPT(url)
}
// 上传到minio
async function handleUploadToMinIO(data){
    const loading=showLoadingToast({
        message: "上传中...",
        duration: 0,
        forbidClick: true,
      })
    const t=new Date()
	const month=moment(t).format('YYYYMM')
	const day=moment(t).format('YYYYMMDD')
	const temName=`ppt/${month}/${day}/${createRandomCode(32)}.pptx`
	console.log('文件名',temName);
    const url = await useUploadToMinIO(data,temName)
    loading.close()
    if(!url){
        setTimeout(() => {
            showToast('生成ppt失败')
        }, 60);
        return
    }
    handlePublishPPT(url)
}
async function uploadFileDirect(data){
    const loading=showLoadingToast({
        message: "上传中...",
        duration: 0,
        forbidClick: true,
      })
    const t=new Date()
	const month=moment(t).format('YYYYMM')
	const day=moment(t).format('YYYYMMDD')
	const temName=`ppt/${month}/${day}/${createRandomCode(32)}.pptx`
	console.log('文件名',temName);
    const objectStorageType = publicSettingStore.publicSetting.ObjectStorageClient||'oss'
    const uploadMap = {
        'oss':useUploadFileToOSS,
        'minio':useUploadToMinIO,
        's3':useUploadToS3
    }
    const url = await uploadMap[objectStorageType](data,temName)
    loading.close()
    if(!url){
        setTimeout(() => {
            showToast('生成ppt失败')
        }, 60);
        return
    }
    handlePublishPPT(url)

}

// 页面转ppt
async function pageToPPT(){
    //const PPTINS=PPTInit(new pptxgen(),1,window.location.pathname.startsWith('/ppten')?'en':'ch')
    const PPTINS = pptConfigInit(new pptxgen(),1,window.location.pathname.startsWith('/ppten')?'en':'ch')
    PPTINS.addSlide()
    console.log(PPTContentList,'PPTContentList');
    // ppt正文内容
    for (let i = 1; i < PPTContentList.length-1; i++) {
        //console.log(`正在生成,第${i+1}页...`,`lastVisibleItemIndex:`,this.lastVisibleItemIndex)
        
        let slide = PPTINS.addSlide({ masterName: pptSlideMaster.title });
        //添加背景图片
        //slide.background = { path: "/static/pptnextimg.png" };
        slide.addText(PPTContentList[i].title, {
            placeholder:"slideTitle",
            x:'10%',
            y:'5.5%',
            w:'68%',
            h:'7%',
            color:'333333'
        });
        const elements = PPTContentList[i].elements;
        const elLength = elements.length;
        for (let j = 0; j < elLength; j++) {
            let imgData = null,textData = null,imgData2 = null,imgData2Obj=null,sheetData={list:null,SourcesFrom:null};
            if (elements[j].type === "chart") {
                console.log("img/chart...");
                const chartId=`chart${elements[j].chartId}_${i}_${elements[j].position}`
                // 判断图有没有被删除
                const chartIsDel=$(`#${chartId} .empty-img`)
                if(chartIsDel.length==0){
                    //将svgDom转为base64 png,返回一个base64字符串
                    imgData = await changeUrl(chartId)
                }
            } else if (elements[j].type === 'text'){
                console.log('text...')
                textData = toTextProps(toJson(elements[j].richContent))
            }else if (elements[j].type==='image'){
                console.log("img/image...")
                imgData2 = PPTContentList[i].elements[j].src
                imgData2Obj = {
                    imgWidth:$(`#image_${i}_${elements[j].position}`).width(),
                    imgHeight:$(`#image_${i}_${elements[j].position}`).height(),
                    naturalWidth:document.getElementById(`image_${i}_${elements[j].position}`).naturalWidth,
                    naturalHeight:document.getElementById(`image_${i}_${elements[j].position}`).naturalHeight
                }
            }else if (elements[j].type==='sheet'){
                console.log('table...')
                const sheetId = elements[j].sheetId
                const res=await apiSheet.infoByCode({UniqueCode:sheetId})
                if(res.Ret===200){
                    sheetData.list = getTableData(res.Data?.TableInfo?.TableDataList||[])
                    sheetData.SourcesFrom = res.Data?.SourcesFrom ? res.Data.SourcesFrom:
                      res.Data.ExcelSource?setDefaultSource(res.Data.ExcelSource):''
                }
            }
            const { x, y, width, height } = getPosition(
                PPTContentList[i].modelId,
                elements[j].position
            );
            if (imgData) {
                slide.addImage({
                    data:imgData,
                    x: x,
                    y: y,
                    w: width,
                    h: height,
                    size: { type: "contain" },
                });
            }else if (textData){
                slide.addText(textData,{
                    x:x,
                    y:y,
                    w:width,
                    h:height,
                    margin:10,
                    fontSize: 16*0.75,
                    valign:'top'
                })
            }else if(imgData2){
                //console.log('src',imgData2)
                const realSize = getImgRealSize(imgData2Obj)
                const percentWidth = Number(width.substring(0,width.length-1))
                const percentHeight = Number(height.substring(0,height.length-1))
                const offsetX = realSize.width===imgData2Obj.imgWidth?0:(percentWidth-(realSize.width/imgData2Obj.imgWidth*percentWidth))/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 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+'%',
                    y:realY+'%',
                    w:offsetX===0?width:(realSize.width/imgData2Obj.imgWidth*percentWidth)+'%',
                    h:offsetY===0?height:(realSize.height/imgData2Obj.imgHeight*percentHeight)+'%',
                    size:{type:"contain"}
                })
            }else if(sheetData.list){
                slide.addTable(sheetData.list,{
                    x:x,
                    y:y,
                    w:width,
                    h:height,
                    border:{type:'solid',pt:1}
                })
              //追加生成表格底部文字
              transBottomInfo(slide,{x,y,width,height},sheetData)
            }
        }
        //在添加完版式后,添加图层元素
        const layers = PPTContentList[i].layers||[]
        const layersLength = layers.length
        for(let j = 0; j < layersLength; j++){
            const {percentageTop,percentageLeft,percentageWidth,percentageHeight} = layers[j]
            //percent单位基于预留标题位置，所以top和height的百分比需要调整
            let position = {x:percentageLeft*100,y:percentageTop*100*0.86+14,w:percentageWidth*100,h:percentageHeight*100*0.86}
            //type为shape&line
            if(['shape','line'].includes(layers[j].type)){
                // const scale = calcScale({w:906,h:906*0.7},{w:$('.ppt-item').width(),h:$('.ppt-item').width()*this.coefficient})
                let options = getShapeOptions(layers[j],position,{x:1,y:1})
                console.log('options',options)
                slide.addShape('custGeom',options)
            }
            //type为text,则转换内部文字
            if(layers[j].type==='text'){
                let textData = toTextProps(toJson(layers[j].richContent))
                    slide.addText(textData,{
                    x:position.x+'%',
                    y:position.y+'%',
                    w:position.w+'%',
                    h:position.h+'%',
                    margin:10,
                    fontSize: 16*0.75,
                    valign:'top'
                })
            }
        }
    }

    //添加封底
    if($(`#ppt-last-page img`)[0]){
        let back = PPTINS.addSlide()
        let backImg = $(`#ppt-last-page 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(),1,window.location.pathname.startsWith('/ppten')?'en':'ch');
    let pptx2 = pptConfigInit(new pptxgen(),1,window.location.pathname.startsWith('/ppten')?'en':'ch')
    //添加封面
    let cover = pptx2.addSlide()
    let coverImg = $(`#ppt-cover-page .pptbg`)[0].src
    cover.addImage({
        path: coverImg,
        x: 0,
        y: 0,
        w:'100%',
        h: '100%',
        size: { type: "contain" },
    })
    //生成的ppt需要可以在封面页更改标题和类型,所以封面信息手动写入
    /* const coverInfo = window.location.pathname.startsWith('/ppten')?[
        {text:'—————————————————————————————————\n',options:{fontSize:16*0.75,breakLine:true}},
        {text:PPTContentList[0].Title,options:{fontSize:28*0.75,breakLine:true}},
        {text:`\nHORIZON INSIGHTS PTE. LTD.`,options:{fontSize:16*0.75,breakLine:true}},
        {text:`\n — ${PPTContentList[0].ReportType} —`,options:{fontSize:16*0.75,breakLine:true}}, 
        {text:'\nFICC Research Department',options:{fontSize:16*0.75,breakLine:true}},
        {text:PPTContentList[0].PptDate,options:{fontSize:16*0.75,breakLine:true}},
        {text:'\n—————————————————————————',options:{fontSize:16*0.75,breakLine:true}}
    ]:[
        {text:'—————————————————————————————————\n',options:{fontSize:16*0.75,breakLine:true}},
        {text:PPTContentList[0].Title,options:{fontSize:28*0.75,breakLine:true}},
        {text:`\n— 弘则弥道（上海）投资咨询有限公司 ● ${PPTContentList[0].ReportType} —`,options:{fontSize:16*0.75,breakLine:false}},
        {text:'\nFICC研究部',options:{fontSize:16*0.75,breakLine:true}},
        {text:PPTContentList[0].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:'ffffff',
        align:'center',
        fontFace:'SimHei'
    }) */
    //自定义封面页内容
    cover = setPPTCover(cover,PPTContentList[0].CoverContent,PPTContentList[0].Title)
    //遍历pptx.slides,重新给每一项的部分属性赋值,再推入pptx2.slides中
    //第一页不需要,因为是空白的
    for(let i=1;i<PPTINS.slides.length;i++){
        let item  = _.cloneDeep(PPTINS.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)
    }
    pptx2.write('blob').then((data)=>{
      LoadingINS.close()
      /* if(publicSettingStore.publicSetting.ObjectStorageClient==='minio'){
        //上传到minio
        handleUploadToMinIO(data)
      }else{
        handleUploadToOSS(data)
      } */
      //handleUploadToOSS(data)
      uploadFileDirect(data)
    })
    // pptx2.writeFile({ fileName: "test.pptx" }) //本地测试可直接用该方法生成ppt文件
}

function setDefaultSource(sourceText){
  return JSON.stringify({
      isShow: true,
      text: sourceText,
      color: "#606266",
      fontSize: 9
  })
}

/* 生成ppt时 图表、表格 追加底部文字 来源 */
function transBottomInfo(slide,{x,y,width,height},data){
  let yPercent = Number(Math.ceil(height.replace(/%/,''))+Math.ceil(y.replace(/%/,'')))+'%';
  // console.log(yPercent)

  if(data.SourcesFrom&&JSON.parse(data.SourcesFrom).isShow) {
    let sourceObj = JSON.parse(data.SourcesFrom);
    //pptx 只接受6bit的颜色格式,用333警告太多了 优化下
    const color = sourceObj.color.includes('rgb') ? rgbaToHex(sourceObj.color).color.substring(1) 
                : sourceObj.color.indexOf('#')===0 
                ? sourceObj.color.substring(1).length<6 
                ? '000000':sourceObj.color.substring(1)
                : '666666'
    slide.addText(`来源:${sourceObj.text}`,{
      x:x,
      y: yPercent,
      w: width,
      margin:10,
      fontSize: sourceObj.fontSize*0.75,
      color,
    })
  }
}

// 发布ppt
function handlePublishPPT(url){
	apiPPTPublish({
		PptId:Number(pptId),
    PptxUrl:url
	}).then(res=>{
		if(res.Ret===200){
      setTimeout(() => {
        showToast('发布成功')
      }, 50);
      setTimeout(() => {
        location.reload();
      }, 1500);
		}
	})
}

/**
 * 发布ppt入口方法
 * @param data ppt内容list
 * @param id pptid
 */
export async function usePPTPublish(data,id){
    PPTContentList=data
	  pptId=id
    if(!checkPPT()) return
    console.log('校验通过');
    LoadingINS=showLoadingToast({
        message: "发布中...",
        duration: 0,
        forbidClick: true,
    })
    await publicSettingStore.getPublicSetting()
    pageToPPT()
}