master
洁 任 2026-03-06 16:57:19 +08:00
parent f3ed210832
commit 7987906db7
3 changed files with 84 additions and 151 deletions

View File

@ -12,188 +12,123 @@ 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. 替换其他占位符
Body body = wordDoc.MainDocumentPart.Document.Body;
ReplacePlaceholders(body, mr);
mainPart.Document.Save();
wordDoc.MainDocumentPart.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日") ?? " 年 月 日";
// 准备替换值
string party = mr.Party ?? "";
string clueLocation = mr.ClueLocation ?? "";
string violationType = mr.ViolationType ?? "";
string year = mr.Year ?? DateTime.Now.Year.ToString();
string serialNumber = mr.SerialNumber.ToString();
int month = mr.SeizureDate?.Month ?? 0;
int day = mr.SeizureDate?.Day ?? 0;
string monthStr = month > 0 ? month.ToString() : "";
string dayStr = day > 0 ? day.ToString() : "";
foreach (var para in body.Elements<Paragraph>())
var paragraphs = body.Elements<Paragraph>().ToList();
for (int i = 0; i < paragraphs.Count; i++)
{
// 处理日期占位符(单独的“年 月 日”段落)
string paraText = para.InnerText.Trim();
if (paraText == "年 月 日")
Paragraph para = paragraphs[i];
string paraText = para.InnerText;
// 处理物品列表占位符 {{Items}}
if (paraText.Contains("{{Items}}"))
{
// 清除原有内容
para.RemoveAllChildren();
// 添加新的Run
Run run = new Run();
run.AppendChild(new Text(dateStr));
para.AppendChild(run);
continue; // 已处理,跳过后续替换
// 获取原段落属性(用于复制样式)
ParagraphProperties paraProps = para.ParagraphProperties != null
? (ParagraphProperties)para.ParagraphProperties.CloneNode(true)
: null;
// 获取原Run属性如下划线
RunProperties runProps = null;
Run firstRun = para.Elements<Run>().FirstOrDefault();
if (firstRun?.RunProperties != null)
{
runProps = (RunProperties)firstRun.RunProperties.CloneNode(true);
}
// 移除原段落
para.Remove();
// 生成新列表项段落,插入到当前位置
InsertItemsParagraphs(body, i, mr.Items, paraProps, runProps);
// 重新开始循环(因为段落集合已变)
ReplacePlaceholders(body, mr);
return;
}
// 处理其他占位符遍历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;
string replaced = original
.Replace("{{Party}}", party)
.Replace("{{ClueLocation}}", clueLocation)
.Replace("{{Year}}", year)
.Replace("{{Month}}", monthStr)
.Replace("{{Day}}", dayStr)
.Replace("{{SerialNumber}}", serialNumber)
.Replace("[ViolationType]", violationType); // 方括号形式
// 替换 [当事人]
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;
}
}
}
private void InsertItemsParagraphs(Body body, int insertIndex, string itemsStr,
ParagraphProperties templateParaProps, RunProperties templateRunProps)
{
string[] items = itemsStr.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < items.Length; i++)
{
string itemText = $"{i + 1}、 {items[i].Trim()}";
Paragraph newPara = new Paragraph();
// 应用模板段落属性
if (templateParaProps != null)
newPara.ParagraphProperties = (ParagraphProperties)templateParaProps.CloneNode(true);
Run newRun = new Run();
// 应用模板Run属性如下划线
if (templateRunProps != null)
newRun.RunProperties = (RunProperties)templateRunProps.CloneNode(true);
newRun.AppendChild(new Text(itemText));
newPara.AppendChild(newRun);
// 在指定索引插入
body.InsertAt(newPara, insertIndex + i);
}
}
}
}

View File

@ -92,17 +92,15 @@ namespace OpenAuth.App
.LeftJoin<MiViolationReport>((p, r) => p.ViolationReportId == r.Id)
.LeftJoin<MiMinePoint>((p, r, m) => r.MinePointId == m.Id)
.LeftJoin<SysUser>((p, r, m, u) => p.Initiator == u.Id.ToString())
.LeftJoin<SysUser>((p, r, m, u, u1) => p.Reviewer == u1.Id.ToString())
.WhereIF(!string.IsNullOrEmpty(req.pointname), (p, r, m, u, u1) => m.Name.Contains(req.pointname))
.WhereIF(!string.IsNullOrEmpty(req.key), (p, r, m, u, u1) => u.Name.Contains(req.key))
.OrderByDescending((p, r, m, u, u1) => p.InitiateTime)
.Select<dynamic>((p, r, m, u, u1) => new
.WhereIF(!string.IsNullOrEmpty(req.pointname), (p, r, m, u) => m.Name.Contains(req.pointname))
.WhereIF(!string.IsNullOrEmpty(req.key), (p, r, m, u) => u.Name.Contains(req.key))
.OrderByDescending((p, r, m, u) => p.InitiateTime)
.Select<dynamic>((p, r, m, u) => new
{
Id = p.Id.SelectAll(),
InitiatorName = u.Name,
PointName = m.Name,
ReviewerName = u1.Name
PointName = m.Name
})
.ToPageListAsync(req.page, req.limit, totalCount);
return new Response<PageInfo<List<dynamic>>>

View File

@ -0,0 +1,12 @@
费县综合行政执法局
扣押财物决定书
费综执扣字 [2026] 第 8 号
张三
经查,你(单位) 于兰山区柳青街道柳青街道直属测试巡检点的[ViolationType]行为
违反了《中华人民共和国矿产资源法》第四条的规定。本机关根据《中华人民共和国矿产资源法》第五十七条之规定,决定于 2026 年 3 月 6 日对下列物品予以扣押:
1、 装载机*1
2、 挖掘机*1
2026年 3 月 6 日