using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using Microsoft.AspNetCore.Hosting; using OpenAuth.Repository.Domain; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace OpenAuth.App.Common { public class MiWordHelper { // 在服务类中添加以下方法 public string GenerateSeizureDocumentWord(MiSeizureDocument mr, IWebHostEnvironment env) { // 模板文件路径(假设放在项目根目录的 Templates 文件夹下) string templatePath = Path.Combine(env.ContentRootPath, "Templates", "扣押财物决定书.docx"); if (!File.Exists(templatePath)) throw new FileNotFoundException("模板文件不存在", templatePath); // 生成文件名(使用ID保证唯一) string fileName = $"扣押财物决定书_{mr.Id}.docx"; // 上传目录(发布文件夹下的 upload) string uploadDir = Path.Combine(env.ContentRootPath, "upload"); if (!Directory.Exists(uploadDir)) Directory.CreateDirectory(uploadDir); string outputPath = Path.Combine(uploadDir, fileName); // 复制模板到输出路径(避免修改原模板) File.Copy(templatePath, outputPath, true); // 使用 OpenXml 修改文档 using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(outputPath, true)) { MainDocumentPart mainPart = wordDoc.MainDocumentPart; Body body = mainPart.Document.Body; // 1. 替换物品列表(先处理,避免后续替换影响索引) ReplaceItemsList(body, mr.Items); // 2. 替换其他占位符 ReplacePlaceholders(body, mr); mainPart.Document.Save(); } // 返回相对路径(用于存入数据库) return $"/upload/{fileName}"; } /// /// 替换物品列表部分 /// private void ReplaceItemsList(Body body, string itemsStr) { var paragraphs = body.Elements().ToList(); // 解析物品列表(按分号分隔) string[] items = itemsStr.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); // 查找列表起始段落(包含 "1、" 和 "[设备及车辆类型]") int startIdx = -1; for (int i = 0; i < paragraphs.Count; i++) { string text = paragraphs[i].InnerText; if (text.Contains("1、") && text.Contains("[设备及车辆类型]")) { startIdx = i; break; } } if (startIdx == -1) return; // 未找到列表区域,不处理 // 查找列表结束段落(包含 "3、" 和 "[其它设备的录入内容]") int endIdx = startIdx; for (int i = startIdx; i < paragraphs.Count; i++) { string text = paragraphs[i].InnerText; if (text.Contains("3、") && text.Contains("[其它设备的录入内容]")) { endIdx = i; break; } } // 如果没找到结束,默认往后找2个段落(假设模板固定三行) if (endIdx == startIdx) endIdx = Math.Min(startIdx + 2, paragraphs.Count - 1); // 移除原列表段落 for (int i = endIdx; i >= startIdx; i--) { paragraphs[i].Remove(); } // 获取参考段落样式(取前一段落或后一段落的样式属性) Paragraph refPara = null; if (startIdx > 0) refPara = paragraphs[startIdx - 1]; else if (startIdx < paragraphs.Count - 1) refPara = paragraphs[startIdx + 1]; // 在起始位置插入新的列表项 for (int i = 0; i < items.Length; i++) { string itemText = $"{i + 1}、 {items[i].Trim()}"; Paragraph newPara = new Paragraph(); // 复制参考段落的样式(如果有) if (refPara != null) { // 复制段落属性 if (refPara.ParagraphProperties != null) newPara.ParagraphProperties = (ParagraphProperties)refPara.ParagraphProperties.CloneNode(true); // 复制第一个Run的样式(如果有) Run refRun = refPara.Elements().FirstOrDefault(); if (refRun != null && refRun.RunProperties != null) { Run newRun = new Run(); newRun.RunProperties = (RunProperties)refRun.RunProperties.CloneNode(true); newRun.AppendChild(new Text(itemText)); newPara.AppendChild(newRun); } else { newPara.AppendChild(new Run(new Text(itemText))); } } else { newPara.AppendChild(new Run(new Text(itemText))); } // 在起始索引位置插入(body.InsertAt 需要索引,但由于已经移除了原段落,现在的段落集合已变化,需要使用 body 的插入方法) // 更简单的方法:重新获取 body 的段落列表,找到合适的插入点 var currentParas = body.Elements().ToList(); if (startIdx <= currentParas.Count) body.InsertAt(newPara, startIdx + i); else body.AppendChild(newPara); } } /// /// 替换文档中的占位符 /// private void ReplacePlaceholders(Body body, MiSeizureDocument mr) { string dateStr = mr.SeizureDate?.ToString("yyyy年MM月dd日") ?? " 年 月 日"; foreach (var para in body.Elements()) { // 处理日期占位符(单独的“年 月 日”段落) string paraText = para.InnerText.Trim(); if (paraText == "年 月 日") { // 清除原有内容 para.RemoveAllChildren(); // 添加新的Run Run run = new Run(); run.AppendChild(new Text(dateStr)); para.AppendChild(run); continue; // 已处理,跳过后续替换 } // 处理其他占位符(遍历Run) foreach (var run in para.Elements()) { Text text = run.Elements().FirstOrDefault(); if (text == null) continue; string original = text.Text; string replaced = original; // 替换 [当事人] replaced = replaced.Replace("[当事人]", mr.Party ?? ""); // 替换 [线索位置] replaced = replaced.Replace("[线索位置]", mr.ClueLocation ?? ""); // 替换 [违法类型] replaced = replaced.Replace("[违法类型]", mr.ViolationType ?? ""); // 替换组合占位符 [于[线索位置]的[违法类型]行为] string combined = $"于{mr.ClueLocation}的{mr.ViolationType}行为"; replaced = replaced.Replace("[于[线索位置]的[违法类型]行为]", combined); // 如果文本有变化,更新 if (original != replaced) text.Text = replaced; } } } } }