|
|
@@ -93,38 +93,48 @@ const WordMergePage: React.FC = () => {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 使用第一个文档作为基础模板
|
|
|
- const baseFile = files[0].file;
|
|
|
- const baseArrayBuffer = await baseFile.arrayBuffer();
|
|
|
- const baseZip = new PizZip(baseArrayBuffer);
|
|
|
-
|
|
|
- // 创建一个新的JSZip实例来合并内容
|
|
|
+ // 创建一个新的空JSZip实例来构建合并后的文档
|
|
|
const mergedZip = new JSZip();
|
|
|
|
|
|
- // 加载基础文档
|
|
|
- const baseDocx = await mergedZip.loadAsync(baseArrayBuffer);
|
|
|
+ // 使用第一个文档作为基础模板,复制所有文件
|
|
|
+ const baseFile = files[0].file;
|
|
|
+ const baseArrayBuffer = await baseFile.arrayBuffer();
|
|
|
+ const baseZip = await mergedZip.loadAsync(baseArrayBuffer);
|
|
|
|
|
|
- // 获取基础文档的word/document.xml内容,使用arrayBuffer避免编码问题
|
|
|
- const baseXmlArrayBuffer = await baseDocx.file('word/document.xml').async('arraybuffer');
|
|
|
+ // 获取基础文档的word/document.xml内容
|
|
|
+ const baseXmlArrayBuffer = await baseZip.file('word/document.xml').async('arraybuffer');
|
|
|
const textDecoder = new TextDecoder('utf-8');
|
|
|
let mergedContent = textDecoder.decode(baseXmlArrayBuffer);
|
|
|
|
|
|
// 移除基础文档的结束标签,以便添加其他文档内容
|
|
|
mergedContent = mergedContent.replace(/<\/w:body>\s*<\/w:document>\s*$/, '');
|
|
|
|
|
|
- // 逐个添加其他文档的内容(从第二个文件开始)
|
|
|
+ // 逐个添加其他文档的完整内容(从第二个文件开始)
|
|
|
for (let i = 1; i < files.length; i++) {
|
|
|
const file = files[i].file;
|
|
|
const fileArrayBuffer = await file.arrayBuffer();
|
|
|
- const fileZip = await mergedZip.loadAsync(fileArrayBuffer);
|
|
|
+ const fileZip = new JSZip();
|
|
|
+ await fileZip.loadAsync(fileArrayBuffer);
|
|
|
+
|
|
|
const fileXmlArrayBuffer = await fileZip.file('word/document.xml').async('arraybuffer');
|
|
|
let fileContent = textDecoder.decode(fileXmlArrayBuffer);
|
|
|
|
|
|
- // 提取文档主体内容
|
|
|
+ // 提取文档的完整body内容(包括样式和格式)
|
|
|
const bodyMatch = fileContent.match(/<w:body(?:\s+[^>]*)?>([\s\S]*?)<\/w:body>/);
|
|
|
if (bodyMatch && bodyMatch[1]) {
|
|
|
+ // 添加分页符以确保每个文档在新页面开始
|
|
|
+ mergedContent += '<w:p><w:r><w:br w:type="page"/></w:r></w:p>';
|
|
|
mergedContent += bodyMatch[1];
|
|
|
}
|
|
|
+
|
|
|
+ // 复制其他文档的样式、字体、主题等资源文件
|
|
|
+ const fileEntries = fileZip.file(/^(word\/media|word\/theme|word\/_rels|word\/styles|docProps|_rels|\[Content_Types\].xml)/);
|
|
|
+ for (const entry of fileEntries) {
|
|
|
+ if (!baseZip.file(entry.name)) {
|
|
|
+ const fileData = await entry.async('arraybuffer');
|
|
|
+ baseZip.file(entry.name, fileData);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 添加完整的结束标签,确保XML结构完整
|
|
|
@@ -136,7 +146,7 @@ const WordMergePage: React.FC = () => {
|
|
|
}
|
|
|
|
|
|
// 更新合并后的内容
|
|
|
- baseDocx.file('word/document.xml', mergedContent);
|
|
|
+ baseZip.file('word/document.xml', mergedContent);
|
|
|
|
|
|
// 生成合并后的Word文档
|
|
|
const mergedDoc = await baseDocx.generateAsync({
|