200 lines
8.0 KiB
C#
200 lines
8.0 KiB
C#
|
|
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}";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 替换物品列表部分
|
|||
|
|
/// </summary>
|
|||
|
|
private void ReplaceItemsList(Body body, string itemsStr)
|
|||
|
|
{
|
|||
|
|
var paragraphs = body.Elements<Paragraph>().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<Run>().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<Paragraph>().ToList();
|
|||
|
|
if (startIdx <= currentParas.Count)
|
|||
|
|
body.InsertAt(newPara, startIdx + i);
|
|||
|
|
else
|
|||
|
|
body.AppendChild(newPara);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 替换文档中的占位符
|
|||
|
|
/// </summary>
|
|||
|
|
private void ReplacePlaceholders(Body body, MiSeizureDocument mr)
|
|||
|
|
{
|
|||
|
|
string dateStr = mr.SeizureDate?.ToString("yyyy年MM月dd日") ?? " 年 月 日";
|
|||
|
|
|
|||
|
|
foreach (var para in body.Elements<Paragraph>())
|
|||
|
|
{
|
|||
|
|
// 处理日期占位符(单独的“年 月 日”段落)
|
|||
|
|
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<Run>())
|
|||
|
|
{
|
|||
|
|
Text text = run.Elements<Text>().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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|