|
@@ -0,0 +1,224 @@
|
|
|
+import Color from 'color'
|
|
|
+import {
|
|
|
+ IElement,
|
|
|
+ ElementType,
|
|
|
+ TitleLevel,
|
|
|
+ ListStyle,
|
|
|
+ Command
|
|
|
+} from '@hufe921/canvas-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) {
|
|
|
+ if (element.type === ElementType.IMAGE) {
|
|
|
+ return new ImageRun({
|
|
|
+ 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
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+function convertElementListToDocxChildren(
|
|
|
+ elementList
|
|
|
+) {
|
|
|
+ const children = []
|
|
|
+
|
|
|
+ let 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 = []
|
|
|
+ for (let r = 0; r < (trList||[]).length; r++) {
|
|
|
+ const tdList = (trList||[])[r].tdList
|
|
|
+ const tableCellList = []
|
|
|
+ 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 default function (command) {
|
|
|
+ return function (options) {
|
|
|
+ const { fileName } = options
|
|
|
+ const {
|
|
|
+ data: { header, main, footer }
|
|
|
+ } = command.getValue()
|
|
|
+console.log(convertElementListToDocxChildren(main || []))
|
|
|
+ const doc = new Document({
|
|
|
+ sections: [
|
|
|
+ {
|
|
|
+ headers: {
|
|
|
+ default: new Header({
|
|
|
+ children: convertElementListToDocxChildren(header || [])
|
|
|
+ })
|
|
|
+ },
|
|
|
+ footers: {
|
|
|
+ default: new Footer({
|
|
|
+ children: convertElementListToDocxChildren(footer || [])
|
|
|
+ })
|
|
|
+ },
|
|
|
+ children: convertElementListToDocxChildren(main || [])
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ })
|
|
|
+console.log(doc)
|
|
|
+return
|
|
|
+ Packer.toBlob(doc).then(blob => {
|
|
|
+ saveAs(blob, `${fileName}.docx`)
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|