/** * word文件类 */ import { DocumentOptions, generateDocument, getBinaryData } from '../internal' import JSZip = require('jszip') import { contentTypesXmlHeader, documentXmlRelsHeader, relsXml } from '../assets' import SectionFileInfo from './sectionFileInfo' import HeaderFileInfo from './headerFileInfo' import FooterFileInfo from './footerFileInfo' import { emptyHeaderDocumentTemplate, headerDocumentTemplate, footerDocumentTemplate } from '../templates' export default class WordFile { /** * 文件名 */ fileName: string = '' /** * 章节关联文件 */ rFileArr: SectionFileInfo[] = [] /** * 页眉 */ headerFile: HeaderFileInfo = new HeaderFileInfo() /** * 页脚 */ footerFile: FooterFileInfo = new FooterFileInfo() constructor(name: string) { this.fileName = name } /** * 新增节点 * @param html 要导出的word文本 * @param options 页面配置项-支持边距和纵横向设置 */ addSection(html: string, options: Partial = {}): void { const rFile = new SectionFileInfo(this.rFileArr.length + 1, html, options, this) this.rFileArr.push(rFile) } /** * 为指定的节点设置页眉 * @param html 页眉文本内容 * @param sectionIdx 默认为所有节点设置页眉,大于-1之后 */ setSectionHeader(text: string, exceptSectionIdx: number = -1) { if (!this.headerFile.id) { this.headerFile.id = 'rId-header' this.headerFile.target = `/word/${this.headerFile.id}.xml` } this.headerFile.htmlContent = text if (exceptSectionIdx !== -1) { this.headerFile.exceptSectionIdx = exceptSectionIdx } } /** * 为指定的节点设置页脚 * @param html 页眉文本内容 * @param sectionIdx 默认为所有节点设置页眉 */ setSectionFooter(text: string, exceptSectionIdx: number = -1) { if (!this.footerFile.id) { this.footerFile.id = 'rId-footer' this.footerFile.target = `/word/${this.footerFile.id}.xml` } this.footerFile.htmlContent = text if (exceptSectionIdx !== -1) { this.footerFile.exceptSectionIdx = exceptSectionIdx } } /** * 生成word压缩包并返回异步字节流 */ async asBlob() { const zip = new JSZip() zip.file('[Content_Types].xml', getBinaryData(this._generalContentTypesXml()), { createFolders: false, }) zip.folder('_rels').file('.rels', getBinaryData(relsXml), { createFolders: false }) const wordFolder = zip.folder('word') wordFolder.file('document.xml', this._renderDocumentFile(), { createFolders: false, }) this.rFileArr.forEach((rFile: SectionFileInfo, idx: number) => { wordFolder.file(rFile.mhtName || 'afchunk.mht', rFile.generalMhtDocument(), { createFolders: false, }) }) // 写入页眉文件 if (this.headerFile.id) { wordFolder.file(this.headerFile.mhtName || 'header.xml', headerDocumentTemplate(this.headerFile.htmlContent), { createFolders: false, }) wordFolder.file('header-empty.xml', emptyHeaderDocumentTemplate, { createFolders: false, }) } // 写入页脚文件 if (this.footerFile.id) { wordFolder.file(this.footerFile.mhtName || 'footer.xml', footerDocumentTemplate(), { createFolders: false, }) wordFolder.file('footer-empty.xml', emptyHeaderDocumentTemplate, { createFolders: false, }) } wordFolder.folder('_rels') .file('document.xml.rels', getBinaryData(this._generalRelsXml()), { createFolders: false, }) return await generateDocument(zip) } /** * 生成文档结构 * @private */ private _generalContentTypesXml() { const xmlStrArr: string[] = [] this.rFileArr.forEach((rFile: SectionFileInfo, idx: number) => { xmlStrArr.push(rFile.getContentTypeXml()) }) // 处理页眉 if (this.headerFile.id) { xmlStrArr.push(this.headerFile.getContentTypeXml()) } // 处理页角 if (this.footerFile.id) { xmlStrArr.push(this.footerFile.getContentTypeXml()) } return contentTypesXmlHeader + xmlStrArr.join('\n') + '' } /** * 生成关系文档内容 * @private */ private _generalRelsXml() { const relationArr: string[] = [] this.rFileArr.forEach((rFile: SectionFileInfo) => { relationArr.push(rFile.getRelationXml()) }) if (this.headerFile.id) { relationArr.push(this.headerFile.getRelationXml()) } if (this.footerFile.id) { relationArr.push(this.footerFile.getRelationXml()) } return documentXmlRelsHeader + relationArr.join('\n') + '' } private _renderDocumentFile() { const tmpHeader: string = ` ` const renderOptionArr: string[] = [] this.rFileArr.forEach((rFile: SectionFileInfo, idx: number) => { const isLastOne = (idx === this.rFileArr.length - 1) renderOptionArr.push(rFile.documentOPENXML(isLastOne)) }) return tmpHeader + renderOptionArr.join('') + `\n ` } }