You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

241 lines
6.0 KiB

import Color from 'color'
import {
IElement,
ElementType,
TitleLevel,
ListStyle,
Command
} from '../../editor'
import {
Document,
Packer,
Paragraph,
Header,
Footer,
Table,
HeadingLevel,
ParagraphChild,
TextRun,
Tab,
ExternalHyperlink,
ImageRun,
WidthType,
TableRow,
TableCell,
MathRun
} from 'docx'
import { saveAs } from './utils'
// 标题映射
const titleLevelToHeadingLevel = {
[TitleLevel.FIRST]: HeadingLevel.HEADING_1,
[TitleLevel.SECOND]: HeadingLevel.HEADING_2,
[TitleLevel.THIRD]: HeadingLevel.HEADING_3,
[TitleLevel.FOURTH]: HeadingLevel.HEADING_4,
[TitleLevel.FIFTH]: HeadingLevel.HEADING_5,
[TitleLevel.SIXTH]: HeadingLevel.HEADING_6
}
function convertElementToParagraphChild(element: IElement): ParagraphChild {
if (element.type === ElementType.IMAGE) {
return new ImageRun({
type: 'png',
data: element.value,
transformation: {
width: element.width!,
height: element.height!
}
})
}
if (element.type === ElementType.HYPERLINK) {
return new ExternalHyperlink({
children: [
new TextRun({
text: element.valueList?.map(child => child.value).join(''),
style: 'Hyperlink'
})
],
link: element.url!
})
}
if (element.type === ElementType.TAB) {
return new TextRun({
children: [new Tab()]
})
}
if (element.type === ElementType.LATEX) {
return new MathRun(element.value)
}
return new TextRun({
font: element.font,
text: element.value,
bold: element.bold,
size: `${(element.size || 16) / 0.75}pt`,
color: Color(element.color).hex() || '#000000',
italics: element.italic,
strike: element.strikeout,
// highlight: element.highlight ? Color(element.highlight).hex() : undefined,
superScript: element.type === ElementType.SUPERSCRIPT,
subScript: element.type === ElementType.SUBSCRIPT,
underline: element.underline ? {} : undefined
})
}
type DocxChildren = (Paragraph | Table)[]
function convertElementListToDocxChildren(
elementList: IElement[]
): DocxChildren {
const children: DocxChildren = []
let paragraphChild: ParagraphChild[] = []
function appendParagraph() {
if (paragraphChild.length) {
children.push(
new Paragraph({
children: paragraphChild
})
)
paragraphChild = []
}
}
for (let e = 0; e < elementList.length; e++) {
const element = elementList[e]
if (element.type === ElementType.TITLE) {
appendParagraph()
children.push(
new Paragraph({
heading: titleLevelToHeadingLevel[element.level!],
children:
element.valueList?.map(child =>
convertElementToParagraphChild(child)
) || []
})
)
} else if (element.type === ElementType.LIST) {
appendParagraph()
// 拆分列表
const listChildren =
element.valueList
?.map(item => item.value)
.join('')
.split('\n')
.map(
(text, index) =>
new Paragraph({
children: [
new TextRun({
text: `${
!element.listStyle ||
element.listStyle === ListStyle.DECIMAL
? `${index + 1}. `
: ``
}${text}`
})
]
})
) || []
children.push(...listChildren)
} else if (element.type === ElementType.TABLE) {
appendParagraph()
const { trList } = element
const tableRowList: TableRow[] = []
for (let r = 0; r < trList!.length; r++) {
const tdList = trList![r].tdList
const tableCellList: TableCell[] = []
for (let c = 0; c < tdList.length; c++) {
const td = tdList[c]
tableCellList.push(
new TableCell({
columnSpan: td.colspan,
rowSpan: td.rowspan,
children: convertElementListToDocxChildren(td.value) || []
})
)
}
tableRowList.push(
new TableRow({
children: tableCellList
})
)
}
children.push(
new Table({
rows: tableRowList,
width: {
size: '100%',
type: WidthType.PERCENTAGE
}
})
)
} else if (element.type === ElementType.DATE) {
paragraphChild.push(
...(element.valueList?.map(child =>
convertElementToParagraphChild(child)
) || [])
)
} else {
if (/^\n/.test(element.value)) {
appendParagraph()
element.value = element.value.replace(/^\n/, '')
}
paragraphChild.push(convertElementToParagraphChild(element))
}
}
appendParagraph()
return children
}
export interface IExportDocxOption {
fileName: string,
isFile:boolean
}
declare module '../../editor' {
interface Command {
executeExportDocx(options: IExportDocxOption): void
}
}
export default function (command: Command) {
return function (options: IExportDocxOption) {
const { fileName,isFile } = options
const {
data: { header, main, footer }
} = command.getValue()
const doc = new Document({
sections: [
{
headers: {
default: new Header({
children: convertElementListToDocxChildren(header || [])
})
},
footers: {
default: new Footer({
children: convertElementListToDocxChildren(footer || [])
})
},
children: convertElementListToDocxChildren(main || [])
}
]
})
if(isFile){
Packer.toBlob(doc).then(blob => {
saveAs(blob, `${fileName}`)
})
}else{
Packer.toBase64String(doc).then((base64:any) => {
const save = {
data: JSON.stringify({ content: base64, title: fileName }),
type: 'exportDocx'
}
//console.log(save)
window.parent.postMessage(save, '*')
})
}
}
}