using System.Text;
using System.Text.RegularExpressions;
using Rmsys.Domain.Entities;
namespace Rmsys.Infrastructure;
///
/// 把库里的干部数据写回「干部任免审批表 3.0」标准的 .lrmx(UTF-8 XML),
/// 供「任免表编辑器 V3.0」直接打开编辑。标签名/顺序与国标模板一致。
///
public static class LrmxExporter
{
public const string DefaultVersion = "3.2.1.16";
/// 读取照片字节(PhotoPath 为 App_Data 下的相对路径)
public static byte[]? LoadPhoto(string appDataRoot, string? photoPath)
=> PhotoStore.LoadBytes(appDataRoot, photoPath);
/// 生成 .lrmx 文本(含 XML 声明,调用方按 UTF-8 with BOM 落盘)
public static string BuildXml(
Cadre c,
IEnumerable resumes,
IEnumerable families,
byte[]? photo,
string? reportDept = null,
string? filler = null,
string? version = null)
{
var sb = new StringBuilder(16 * 1024);
sb.Append("\r\n");
sb.Append("\r\n");
void E(string tag, string? val, bool date6 = false)
{
var v = date6 ? Date6ToLrmx(val) : (val ?? "").Trim();
sb.Append(" <").Append(tag).Append('>');
sb.Append(Esc(v));
sb.Append("").Append(tag).Append(">\r\n");
}
// ---------- 基本信息(与国标模板同序)----------
E("XingMing", c.Name);
E("XingBie", c.Sex);
E("ChuShengNianYue", c.Birth, true);
E("MinZu", c.Nation);
E("JiGuan", c.NativePlace);
E("ChuShengDi", c.BirthPlace);
E("RuDangShiJian", c.PartyDate, true);
E("CanJiaGongZuoShiJian", c.WorkDate, true);
E("JianKangZhuangKuang", c.Health);
E("ZhuanYeJiShuZhiWu", c.TechPost);
E("ShuXiZhuanYeYouHeZhuanChang", c.Expertise);
// 全日制教育
E("QuanRiZhiJiaoYu_XueLi", c.EduFullLevel);
E("QuanRiZhiJiaoYu_XueWei", c.EduFullDegree);
E("QuanRiZhiJiaoYu_XueLi_BiYeYuanXiaoXi", c.EduFullSchool);
E("QuanRiZhiJiaoYu_XueWei_BiYeYuanXiaoXi", c.EduFullMajor);
// 在职教育
E("ZaiZhiJiaoYu_XueLi", c.EduInLevel);
E("ZaiZhiJiaoYu_XueWei", c.EduInDegree);
E("ZaiZhiJiaoYu_XueLi_BiYeYuanXiaoXi", c.EduInSchool);
E("ZaiZhiJiaoYu_XueWei_BiYeYuanXiaoXi", c.EduInMajor);
// ---------- 职务 ----------
E("XianRenZhiWu", c.CurrentPost);
E("NiRenZhiWu", c.ProposedPost);
E("NiMianZhiWu", c.DismissPost);
// ---------- 简历:每段「起止时间 内容」一行 ----------
var lines = new List();
foreach (var r in resumes.OrderBy(x => x.Sort))
{
var period = (r.Period ?? "").Trim();
var content = (r.Content ?? "").Trim();
if (period.Length == 0 && content.Length == 0) continue;
lines.Add(period.Length > 0 ? period + " " + content : content);
}
E("JianLi", string.Join("\n", lines));
E("JiangChengQingKuang", c.Rewards);
E("NianDuKaoHeJieGuo", c.Exams);
E("RenMianLiYou", c.AppointReason);
// ---------- 家庭主要成员 ----------
sb.Append(" \r\n");
foreach (var f in families.OrderBy(x => x.Sort))
{
if (string.IsNullOrWhiteSpace(f.Name) && string.IsNullOrWhiteSpace(f.Relation)) continue;
sb.Append(" - \r\n");
void F(string tag, string? v)
=> sb.Append(" <").Append(tag).Append('>').Append(Esc((v ?? "").Trim())).Append("").Append(tag).Append(">\r\n");
F("ChengWei", f.Relation);
F("XingMing", f.Name);
F("ChuShengRiQi", Date6ToLrmx(f.Age));
F("ZhengZhiMianMao", f.Political);
F("GongZuoDanWeiJiZhiWu", f.WorkUnit);
sb.Append("
\r\n");
}
sb.Append(" \r\n");
// ---------- 表尾 ----------
var now = DateTime.Now;
E("ChengBaoDanWei", reportDept);
E("JiSuanNianLingShiJian", now.ToString("yyyyMM"));
E("TianBiaoShiJian", now.ToString("yyyyMM"));
E("TianBiaoRen", filler);
E("ShenFenZheng", c.IdCard);
sb.Append(" ");
if (photo != null && photo.Length > 0) sb.Append(Convert.ToBase64String(photo));
sb.Append("\r\n");
E("Version", string.IsNullOrWhiteSpace(version) ? DefaultVersion : version);
sb.Append("\r\n");
return sb.ToString();
}
/// 「1968.04」→「196804」;已是 6/8 位数字则规整;无法识别原样返回
private static string Date6ToLrmx(string? s)
{
if (string.IsNullOrWhiteSpace(s)) return "";
s = s.Trim();
if (Regex.IsMatch(s, @"^\d{4}\.\d{1,2}$")) return s[..4] + s.Split('.')[1].PadLeft(2, '0');
if (Regex.IsMatch(s, @"^\d{4}[/-]\d{1,2}$"))
{
var p = s.Split('/', '-');
return p[0] + p[1].PadLeft(2, '0');
}
if (Regex.IsMatch(s, @"^\d{6}$")) return s;
if (Regex.IsMatch(s, @"^\d{8}$")) return s[..6];
return s;
}
private static string Esc(string v)
{
if (v.Length == 0) return "";
return v.Replace("&", "&").Replace("<", "<").Replace(">", ">")
.Replace("\"", """).Replace("'", "'");
}
/// 生成可供下载的字节(UTF-8 带 BOM,与国标模板一致)
public static byte[] BuildBytes(
Cadre c, IEnumerable resumes, IEnumerable families,
byte[]? photo, string? reportDept = null, string? filler = null, string? version = null)
{
var xml = BuildXml(c, resumes, families, photo, reportDept, filler, version);
var enc = new UTF8Encoding(true);
// GetBytes 不会自动带 BOM,必须显式拼上(国标模板是 UTF-8 with BOM)
var preamble = enc.GetPreamble();
var body = enc.GetBytes(xml);
var buf = new byte[preamble.Length + body.Length];
Buffer.BlockCopy(preamble, 0, buf, 0, preamble.Length);
Buffer.BlockCopy(body, 0, buf, preamble.Length, body.Length);
return buf;
}
}