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;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|