feat: 更新导入功能(pptxtojson v0.1.2)

This commit is contained in:
pipipi-pikachu 2023-12-03 19:16:47 +08:00
parent effd46e05e
commit d03f3a9414
4 changed files with 120 additions and 51 deletions

14
package-lock.json generated
View File

@ -24,7 +24,7 @@
"number-precision": "^1.6.0", "number-precision": "^1.6.0",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"pptxgenjs": "^3.12.0", "pptxgenjs": "^3.12.0",
"pptxtojson": "^0.0.13", "pptxtojson": "^0.1.2",
"prosemirror-commands": "^1.3.0", "prosemirror-commands": "^1.3.0",
"prosemirror-dropcursor": "^1.6.0", "prosemirror-dropcursor": "^1.6.0",
"prosemirror-gapcursor": "^1.3.1", "prosemirror-gapcursor": "^1.3.1",
@ -10868,9 +10868,9 @@
"integrity": "sha512-t3rNFBgJRugIhackit2mVcLfF6IRc0JE4oeizPQL8Zrm8n2WY/0wOdpOPhdtG0V9Q2TlW/axbF1MJ6z+Yj/kKQ==" "integrity": "sha512-t3rNFBgJRugIhackit2mVcLfF6IRc0JE4oeizPQL8Zrm8n2WY/0wOdpOPhdtG0V9Q2TlW/axbF1MJ6z+Yj/kKQ=="
}, },
"node_modules/pptxtojson": { "node_modules/pptxtojson": {
"version": "0.0.13", "version": "0.1.2",
"resolved": "https://registry.npmmirror.com/pptxtojson/-/pptxtojson-0.0.13.tgz", "resolved": "https://registry.npmmirror.com/pptxtojson/-/pptxtojson-0.1.2.tgz",
"integrity": "sha512-ltwUe4U6UVvZ2/+4qhzz8LlH7VBox/Y454ppRPlQeMY/yqszpBdD2/Qj+WEslhrciVY+lup8K+7e7pbL9ZTJuQ==", "integrity": "sha512-UvzEuCnspfZqc1Tf7TU6tSyXV+4OngkTfoAEZdPVW2i6wedU16wr8hkNzwQ77ePyfoyaODAFwS9cfJnnEhwfKQ==",
"dependencies": { "dependencies": {
"jszip": "^3.10.1", "jszip": "^3.10.1",
"tinycolor2": "1.6.0", "tinycolor2": "1.6.0",
@ -23339,9 +23339,9 @@
} }
}, },
"pptxtojson": { "pptxtojson": {
"version": "0.0.13", "version": "0.1.2",
"resolved": "https://registry.npmmirror.com/pptxtojson/-/pptxtojson-0.0.13.tgz", "resolved": "https://registry.npmmirror.com/pptxtojson/-/pptxtojson-0.1.2.tgz",
"integrity": "sha512-ltwUe4U6UVvZ2/+4qhzz8LlH7VBox/Y454ppRPlQeMY/yqszpBdD2/Qj+WEslhrciVY+lup8K+7e7pbL9ZTJuQ==", "integrity": "sha512-UvzEuCnspfZqc1Tf7TU6tSyXV+4OngkTfoAEZdPVW2i6wedU16wr8hkNzwQ77ePyfoyaODAFwS9cfJnnEhwfKQ==",
"requires": { "requires": {
"jszip": "^3.10.1", "jszip": "^3.10.1",
"tinycolor2": "1.6.0", "tinycolor2": "1.6.0",

View File

@ -25,7 +25,7 @@
"number-precision": "^1.6.0", "number-precision": "^1.6.0",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"pptxgenjs": "^3.12.0", "pptxgenjs": "^3.12.0",
"pptxtojson": "^0.0.13", "pptxtojson": "^0.1.2",
"prosemirror-commands": "^1.3.0", "prosemirror-commands": "^1.3.0",
"prosemirror-dropcursor": "^1.6.0", "prosemirror-dropcursor": "^1.6.0",
"prosemirror-gapcursor": "^1.3.1", "prosemirror-gapcursor": "^1.3.1",

View File

@ -1,14 +1,25 @@
import { ref } from 'vue' import { ref } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { parse, type Shape, type Element } from 'pptxtojson' import { parse, type Shape, type Element, type ChartItem } from 'pptxtojson'
import { nanoid } from 'nanoid' import { nanoid } from 'nanoid'
import type { Slide, TableCellStyle, TableCell, ChartType, ChartOptions, SlideBackground, PPTShapeElement, PPTLineElement } from '@/types/slides'
import { useSlidesStore } from '@/store' import { useSlidesStore } from '@/store'
import { decrypt } from '@/utils/crypto' import { decrypt } from '@/utils/crypto'
import { type ShapePoolItem, SHAPE_LIST, SHAPE_PATH_FORMULAS } from '@/configs/shapes' import { type ShapePoolItem, SHAPE_LIST, SHAPE_PATH_FORMULAS } from '@/configs/shapes'
import { VIEWPORT_SIZE } from '@/configs/canvas' import { VIEWPORT_SIZE } from '@/configs/canvas'
import useAddSlidesOrElements from '@/hooks/useAddSlidesOrElements' import useAddSlidesOrElements from '@/hooks/useAddSlidesOrElements'
import message from '@/utils/message' import message from '@/utils/message'
import type {
Slide,
TableCellStyle,
TableCell,
ChartType,
ChartOptions,
SlideBackground,
PPTShapeElement,
PPTLineElement,
ShapeTextAlign,
PPTTextElement,
} from '@/types/slides'
export default () => { export default () => {
const slidesStore = useSlidesStore() const slidesStore = useSlidesStore()
@ -65,7 +76,7 @@ export default () => {
top: el.top, top: el.top,
start, start,
end, end,
style: el.borderType, style: el.borderType === 'solid' ? 'solid' : 'dashed',
color: el.borderColor, color: el.borderColor,
points: ['', el.shapType === 'straightConnector1' ? 'arrow' : ''] points: ['', el.shapType === 'straightConnector1' ? 'arrow' : '']
} }
@ -85,7 +96,10 @@ export default () => {
const reader = new FileReader() const reader = new FileReader()
reader.onload = async e => { reader.onload = async e => {
const json = await parse(e.target!.result as ArrayBuffer) const json = await parse(e.target!.result as ArrayBuffer, {
slideFactor: 75 / 914400,
fontsizeFactor: 100 / 98,
})
const width = json.size.width const width = json.size.width
const scale = VIEWPORT_SIZE / width const scale = VIEWPORT_SIZE / width
@ -105,7 +119,7 @@ export default () => {
background = { background = {
type: 'gradient', type: 'gradient',
gradientType: 'linear', gradientType: 'linear',
gradientColor: [value.colors[0], value.colors[1]], gradientColor: [value.colors[0].color, value.colors[value.colors.length - 1].color],
gradientRotate: value.rot, gradientRotate: value.rot,
} }
} }
@ -130,7 +144,7 @@ export default () => {
el.top = el.top * scale el.top = el.top * scale
if (el.type === 'text') { if (el.type === 'text') {
slide.elements.push({ const textEl: PPTTextElement = {
type: 'text', type: 'text',
id: nanoid(10), id: nanoid(10),
width: el.width, width: el.width,
@ -145,10 +159,13 @@ export default () => {
outline: { outline: {
color: el.borderColor, color: el.borderColor,
width: el.borderWidth, width: el.borderWidth,
style: el.borderType, style: el.borderType === 'solid' ? 'solid' : 'dashed',
}, },
fill: el.fillColor, fill: el.fillColor,
}) vertical: el.isVertical,
}
if (el.shadow) textEl.shadow = el.shadow
slide.elements.push(textEl)
} }
else if (el.type === 'image') { else if (el.type === 'image') {
slide.elements.push({ slide.elements.push({
@ -163,14 +180,49 @@ export default () => {
rotate: el.rotate, rotate: el.rotate,
}) })
} }
else if (el.type === 'audio') {
slide.elements.push({
type: 'audio',
id: nanoid(10),
src: el.blob,
width: el.width,
height: el.height,
left: el.left,
top: el.top,
rotate: 0,
fixedRatio: false,
color: theme.value.themeColor,
loop: false,
autoplay: false,
})
}
else if (el.type === 'video') {
slide.elements.push({
type: 'video',
id: nanoid(10),
src: (el.blob || el.src)!,
width: el.width,
height: el.height,
left: el.left,
top: el.top,
rotate: 0,
autoplay: false,
})
}
else if (el.type === 'shape') { else if (el.type === 'shape') {
if (el.shapType === 'line' || el.shapType === 'straightConnector1') { if (el.shapType === 'line' || /Connector/.test(el.shapType)) {
const lineElement = parseLineElement(el) const lineElement = parseLineElement(el)
slide.elements.push(lineElement) slide.elements.push(lineElement)
} }
else { else {
const shape = shapeList.find(item => item.pptxShapeType === el.shapType) const shape = shapeList.find(item => item.pptxShapeType === el.shapType)
const vAlignMap: { [key: string]: ShapeTextAlign } = {
'mid': 'middle',
'down': 'bottom',
'up': 'top',
}
const element: PPTShapeElement = { const element: PPTShapeElement = {
type: 'shape', type: 'shape',
id: nanoid(10), id: nanoid(10),
@ -186,15 +238,18 @@ export default () => {
outline: { outline: {
color: el.borderColor, color: el.borderColor,
width: el.borderWidth, width: el.borderWidth,
style: el.borderType, style: el.borderType === 'solid' ? 'solid' : 'dashed',
}, },
text: { text: {
content: el.content, content: el.content,
defaultFontName: theme.value.fontName, defaultFontName: theme.value.fontName,
defaultColor: theme.value.fontColor, defaultColor: theme.value.fontColor,
align: 'middle', align: vAlignMap[el.vAlign] || 'middle',
} },
flipH: el.isFlipH,
flipV: el.isFlipV,
} }
if (el.shadow) element.shadow = el.shadow
if (shape) { if (shape) {
element.path = shape.path element.path = shape.path
@ -212,6 +267,11 @@ export default () => {
else element.path = pathFormula.formula(el.width, el.height) else element.path = pathFormula.formula(el.width, el.height)
} }
} }
if (el.shapType === 'custom') {
element.special = true
element.path = el.path!
element.viewBox = [el.width, el.height]
}
slide.elements.push(element) slide.elements.push(element)
} }
@ -231,7 +291,7 @@ export default () => {
const cellData = el.data[i][j] const cellData = el.data[i][j]
rowCells.push({ rowCells.push({
id: nanoid(10), id: nanoid(10),
colspan: 1, colspan: cellData.colSpan || 1,
rowspan: cellData.rowSpan || 1, rowspan: cellData.rowSpan || 1,
text: cellData.text, text: cellData.text,
style, style,
@ -258,7 +318,7 @@ export default () => {
color: '#eeece1', color: '#eeece1',
}, },
theme: { theme: {
color: theme.value.themeColor, color: el.themeColor,
rowHeader: true, rowHeader: true,
rowFooter: false, rowFooter: false,
colHeader: false, colHeader: false,
@ -272,40 +332,47 @@ export default () => {
let legends: string[] let legends: string[]
let series: number[][] let series: number[][]
if (el.chartType === 'scatterChart') { if (el.chartType === 'scatterChart' || el.chartType === 'bubbleChart') {
labels = el.data[0].map(item => item + '') const data = el.data
labels = data[0].map(item => item + '')
legends = ['系列1'] legends = ['系列1']
series = [el.data[1]] series = [data[1]]
} }
else { else {
labels = Object.values(el.data[0].xlabels) const data = el.data as ChartItem[]
legends = el.data.map(item => item.key) labels = Object.values(data[0].xlabels)
series = el.data.map(item => item.values.map(v => v.y)) legends = data.map(item => item.key)
series = data.map(item => item.values.map(v => v.y))
} }
let options: ChartOptions = {} const options: ChartOptions = {}
let chartType: ChartType = 'bar' let chartType: ChartType = 'bar'
if (el.chartType === 'barChart') {
switch (el.chartType) {
case 'barChart':
case 'bar3DChart':
chartType = 'bar' chartType = 'bar'
} if (el.barDir === 'bar') options.horizontalBars = true
if (el.chartType === 'stackedBarChart') { if (el.grouping === 'stacked' || el.grouping === 'percentStacked') options.stackBars = true
chartType = 'bar' break
options = { stackBars: true } case 'lineChart':
} case 'line3DChart':
else if (el.chartType === 'lineChart') { case 'areaChart':
case 'area3DChart':
case 'scatterChart':
case 'bubbleChart':
chartType = 'line' chartType = 'line'
} if (el.chartType === 'areaChart' || el.chartType === 'area3DChart') options.showArea = true
else if (el.chartType === 'areaChart') { if (el.chartType === 'scatterChart' || el.chartType === 'bubbleChart') options.showLine = false
chartType = 'line' break
options = { showArea: true } case 'pieChart':
} case 'pie3DChart':
else if (el.chartType === 'scatterChart') { case 'doughnutChart':
chartType = 'line'
options = { showLine: false }
}
else if (el.chartType === 'pieChart' || el.chartType === 'pie3DChart') {
chartType = 'pie' chartType = 'pie'
if (el.chartType === 'doughnutChart') options.donut = true
break
default:
} }
slide.elements.push({ slide.elements.push({
@ -327,7 +394,7 @@ export default () => {
options, options,
}) })
} }
else if (el.type === 'group') { else if (el.type === 'group' || el.type === 'diagram') {
const elements = el.elements.map(_el => ({ const elements = el.elements.map(_el => ({
..._el, ..._el,
left: _el.left + el.left, left: _el.left + el.left,

View File

@ -266,6 +266,8 @@ export interface ShapeGradient {
rotate: number rotate: number
} }
export type ShapeTextAlign = 'top' | 'middle' | 'bottom'
/** /**
* *
* *
@ -281,7 +283,7 @@ export interface ShapeText {
content: string content: string
defaultFontName: string defaultFontName: string
defaultColor: string defaultColor: string
align: 'top' | 'middle' | 'bottom' align: ShapeTextAlign
} }
/** /**