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("\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("\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; } }