// 引入工具(已修正 htmlparser2 导入) import PizZip from 'pizzip'; import Docxtemplater from 'docxtemplater'; import JSZipUtils from 'jszip-utils'; import { saveAs } from 'file-saver'; import ImageModule from 'docxtemplater-image-module-free'; import { Parser } from 'htmlparser2'; import CSSOM from 'cssom'; // 加载 .docx 模板文件(不变) function loadFile(url, callback) { JSZipUtils.getBinaryContent(url, callback); } // 下载生成的文档(不变) export function download(file, name) { } // 辅助函数:base64 转 Uint8Array(不变) function base64ToUint8Array(base64) { const base64WithoutPrefix = base64.replace(/^data:image\/\w+;base64,/, ''); const binaryString = atob(base64WithoutPrefix); const length = binaryString.length; const uint8Array = new Uint8Array(length); for (let i = 0; i < length; i++) { uint8Array[i] = binaryString.charCodeAt(i); } return uint8Array; } // -------------------------- 富文本处理核心函数(不变) -------------------------- function getFontSizeFromStyle(styleStr) { if (!styleStr) return 12; try { const style = CSSOM.parse(`.temp { ${styleStr} }`).cssRules[0].style; const fontSize = style.getPropertyValue('font-size'); if (!fontSize) return 12; const sizeNum = parseInt(fontSize.replace(/[^\d]/g, ''), 10); return isNaN(sizeNum) ? 12 : sizeNum; } catch (e) { return 12; } } function htmlToDocxXml(html) { let xml = ''; let currentFontSize = 12; const entityMap = { ' ': ' ', '<': '<', '>': '>', '&': '&', '"': '"', ''': "'" }; const parser = new Parser({ onopentag: (name, attributes) => { switch (name) { case 'p': xml += ''; break; case 'span': const fontSize = getFontSizeFromStyle(attributes.style); currentFontSize = fontSize; const szVal = currentFontSize * 2; xml += ``; break; case 'b': case 'strong': xml += ''; break; case 'br': xml += ''; break; } }, ontext: (text) => { const processedText = text .replace(/ |<|>|&|"|'/g, match => entityMap[match]) .replace(/\n/g, ''); xml += `${processedText}`; }, onclosetag: (name) => { switch (name) { case 'p': xml += ''; currentFontSize = 12; break; case 'span': case 'b': case 'strong': xml += ''; break; } } }, { decodeEntities: true }); parser.write(html); parser.end(); return xml; } function processRichTextData(data, richTextFields = []) { const process = (obj) => { if (typeof obj !== 'object' || obj === null) return obj; if (Array.isArray(obj)) { return obj.map(item => process(item)); } const processedObj = { ...obj }; for (const key in processedObj) { if (processedObj.hasOwnProperty(key)) { if (richTextFields.includes(key) && typeof processedObj[key] === 'string') { const filteredHtml = processedObj[key].replace(/

\s*( )?\s*<\/p>/g, ''); processedObj[key] = htmlToDocxXml(filteredHtml); } else { processedObj[key] = process(processedObj[key]); } } } return processedObj; }; return process(data); } // -------------------------- 核心:生成 Word 文档(修正构造函数配置) -------------------------- export function generateWordDocument(templatePath, data, name, richTextFields = []) { loadFile(templatePath, function (error, content) { if (error) { console.error('加载模板失败:', error); return; } try { const processedData = processRichTextData(data, richTextFields); // 图片处理模块(不变) const imageModule = new ImageModule({ getImage: function (tagValue, tagName) { return base64ToUint8Array(tagValue); }, getSize: function (tagValue, tagName) { switch (tagName) { case 'avatar': return [200, 200]; case 'coverImg': return [600, 300]; default: return [80, 130]; } } }); // 关键修正:将 parser 直接传入构造函数 options,删除 setOptions() const zip = new PizZip(content); const doc = new Docxtemplater(zip, { paragraphLoop: true, linebreaks: true, raw: true, // 富文本核心:允许插入原始 XML modules: [imageModule], // 图片模块 nullGetter: () => '', // 空值处理 // 直接在这里传入 parser 配置(无需 setOptions()) parser: (tag, _variable) => { return { get(scope) { if (scope[tag] !== undefined) { return scope[tag] || ''; } if (tag.startsWith('$')) { const varName = tag.slice(1); return scope[varName] || ''; } return ''; } }; } }); // 删除这一行!!!v4 构造函数已包含 parser,无需手动 setOptions // doc.setOptions({ parser }); // 注入数据并渲染(不变) doc.setData(processedData); doc.render(); const fileWord = doc.getZip().generate({ type: 'blob', mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', }); saveAs(fileWord, name); console.log('导出成功!'); } catch (error) { console.error('生成文档失败:', error); } }); }