董黎的空间
项目

信息比对助手

博主 2026年4月22日 0 阅读 约 11 分钟
本文档介绍了信息比对助手项目的技术架构与核心业务逻辑。当前实现采用 Blazor Server + Photino.NET 桌面窗口,内嵌 Kestrel 服务,使用 SQLite 数据库和 SqlSugar ORM,支持 Excel 导入导出。核心流程包括:以身份证号为主键维护底册,导入外部死亡名单并进行唯一性校验,执行比对并生成结果,支持确认注销状态,可导出结果,并在应用退出时尝试备份数据库。
# C# # Blazor # SQLite # Photino

信息比对助手 — 项目规划与实现说明

本文档在原规划基础上,补充当前已实现架构与数据库各表字段说明,便于对照代码(InfoCompareAssistant/Data/Entities.cs)进行检查与调整。


一、技术架构选型(规划 + 当前实现)

1.1 规划目标

  • 统一技术栈、支持国产化与离线场景。
  • 桌面端轻量、本地 SQLite、大批量 Excel 友好。

1.2 当前实现(与规划的差异说明)

维度 原规划 当前实现 说明
客户端 Blazor Hybrid + Photino(偏 WASM 宿主) Blazor Server + Photino.NET 打开窗口,内嵌本机 Kestrel 页面 数据访问(SqlSugar + SQLite)在完整 CLR 上运行,避免纯 WASM 下 SQLite 能力受限;界面仍为 Blazor + WebView 体验。
UI Blazor + Tailwind CSS Blazor + 自研主题 CSS(蓝/绿柔和卡片风格) 视觉目标与规划一致;若需严格 Tailwind 构建链,可后续接入 npm/postcss。
数据库 SQLite SQLite,文件路径:%LocalApplicationData%\InfoCompareAssistant\app.db 随用户目录持久化。
ORM SqlSugar SqlSugar(CodeFirst 建表) 实体见下文与 Entities.cs。
Excel MiniExcel MiniExcel 底册导入、死亡名单导入、结果导出。
监听端口 — http://127.0.0.1:0(系统分配空闲端口) 避免固定端口被占用导致启动失败;Photino 加载地址为启动后解析的实际 URL。

1.3 依赖包(实现侧)

  • Photino.NET:桌面窗口承载 WebView。
  • SqlSugarCore + Microsoft.Data.Sqlite:SQLite 访问与 ORM。
  • MiniExcel:流式/低内存 Excel 读写。

二、核心业务逻辑(与实现对齐)

  1. 底册(特殊人员)
    以身份证号为底册主键;支持单条维护与 Excel 批量导入(按身份证号 upsert)。

  2. 外部死亡名单
    每次向导导入形成一批 DeathRecord 行,并与历史做 身份证号规范化 + 死亡日期 Key 的全局唯一校验(见数据库索引),防止重复导入。

  3. 比对
    将本批死亡记录与 PersonRegistry 按规范化身份证号关联;底册状态**不等于「已故」**的命中写入 CompareMatch,供界面展示与确认。

  4. 确认注销
    对选中/一键确认的比对结果:底册对应人员 Status → 已故,CancelDate → 业务当天(日期);比对行 Confirmed / ConfirmedAt 更新。

  5. 导出
    按批次导出比对结果为 Excel(HTTP:/api/export/{batchId})。

  6. 退出备份
    应用停止时尝试将 app.db 复制到 D:\数据备份(目录不存在则创建;无 D 盘或无权限则静默失败,不阻断退出)。


三、界面与交互(规划要点)

  • 首页:在册总数、本月待处理预警、上次比对完成时间;快捷入口。
  • 一键比对向导:上传 → 列映射 → 比对进度 → 结果表(未确认高亮)、确认注销、导出。
  • 人员名册:网格/类别筛选、分页、单条编辑、Excel 导入。

四、防呆与容错(规划 + 实现要点)

  • 身份证:去控制字符与空白、大写、15 位升 18 位、展示与匹配以规范化字段为准(底册主键与死亡表 IdNumberNorm)。
  • 死亡日期:同时存 DeathDateKey(用于唯一性与关联)与 DeathDateDisplay(展示原文或可解析日期)。
  • 重复导入:数据库层 DeathRecord(IdNumberNorm, DeathDateKey) 唯一索引 + 业务层导入前校验。
  • 备份:见第二节「退出备份」。

五、数据库表结构说明(详细字段)

以下与 SQLite 中实际表名、字段一致,对应 C# 类在命名空间 InfoCompareAssistant.Data。
时间字段:代码中写入多为 UTC(DateTime.UtcNow),界面展示可按本地时区转换;CancelDate 为业务意义上的「注销日期」,使用 日期(当天 DateTime.Today)。


5.1 表 PersonRegistry(特殊人员底册)

用途:在册人员主数据;业务上以身份证号唯一标识一人。

字段名 类型(C# / 逻辑) 可空 约束 说明
IdNumber string 否 主键,长度约 32 身份证号,存规范化后值(清洗 + 15 转 18 + 大写等),与业务「一人一号」一致。
Name string 否 长度约 64 姓名。
Contact string 是 长度约 64 联系方式(电话等)。
GridCommunity string 是 长度约 128 管辖网格 / 社区。
SpecialCategory string 是 长度约 64 特殊类别(低保、残疾、重病等),可自定义文案。
Status string 否 长度约 16,默认 "正常" 人员状态;约定取值:正常、已故、迁出(与比对、筛选逻辑一致,修改时请全局检索)。
CancelDate DateTime? 是 — 注销日期;在「确认并注销底册人员」时写入,一般为操作当日日期。
CreatedAt DateTime 否 — 首次写入时间(UTC)。
UpdatedAt DateTime 否 — 最后更新时间(UTC)。

检查/调整建议:若需增加字段(如备注、照片路径),在本表扩展后同步:名册页表单、RegistryService、底册 Excel 导入列识别逻辑。


5.2 表 DeathRecord(外部死亡名单导入明细)

用途:每次向导导入的一批死亡行;全局用于「身份证号 + 死亡日期」重复拦截(与批次无关,历史任一导入占坑后即不可再导入相同组合)。

字段名 类型 可空 约束 说明
Id int 否 主键,自增 SQLite 下为 INTEGER PRIMARY KEY 自增行标识。
BatchId int 否 逻辑外键 → CompareBatch.Id 所属导入批次。
IdNumberNorm string 否 长度约 32 规范化身份证号,与 PersonRegistry.IdNumber 对齐比较。
DeathDateKey string 否 长度约 32 死亡日期规范化键(如 yyyyMMdd 或无法解析时的占位规则),用于唯一性与去重;与 IdNumberNorm 联合唯一。
Name string 否 长度约 64 名单中的姓名(可为空串,视导入数据而定)。
DeathDateDisplay string 是 长度约 64 死亡日期展示用字符串(保留 Excel 原样或格式化可读日期)。
SourceFileName string 是 长度约 256 上传时的原始文件名(审计/追溯)。
ImportedAt DateTime 否 — 导入时间(UTC)。

索引(代码初始化脚本)

  • ux_death_id_date:唯一索引 (IdNumberNorm, DeathDateKey)
    • 含义:同一规范化身份证 + 同一死亡日期键在全库仅允许一条死亡导入记录。
    • 调整注意:修改 DeathDateKey 生成规则会导致「是否与历史重复」判定变化,需评估历史数据迁移或重建索引。

5.3 表 CompareBatch(一次比对导入批次)

用途:一次「上传 + 比对」会话的元数据,与多条 DeathRecord、CompareMatch 关联。

字段名 类型 可空 约束 说明
Id int 否 主键,自增 批次号;导出接口 /api/export/{batchId} 即此 Id。
SourceFileName string 是 长度约 256 本次上传文件名。
StartedAt DateTime 否 — 批次开始时间(UTC)。
FinishedAt DateTime 否 — 批次结束时间(UTC),比对写库完成后更新。
RowCount int 否 — 本批解析到的有效死亡行数(业务统计)。
MatchCount int 否 — 本批产生的「待处理/已展示」命中条数(CompareMatch 行数)。

检查/调整建议:若需记录操作员、机构、备注等,可在本表增加字段并在 CompareFlowService.ImportAndCompare 中赋值。


5.4 表 CompareMatch(比对命中结果)

用途:本批中「底册存在且导入当时底册状态非已故」的命中记录;支持确认后写回底册并标记本行已确认。

字段名 类型 可空 约束 说明
Id int 否 主键,自增 单行比对结果标识。
BatchId int 否 逻辑外键 → CompareBatch.Id 所属批次。
IdNumberNorm string 否 长度约 32 规范化身份证号,对应底册人员。
Name string 否 长度约 64 展示姓名(优先名单姓名,缺省用底册姓名)。
DeathDateDisplay string 是 长度约 64 死亡日期展示。
RegistryStatus string 否 长度约 16 写入比对结果时底册中的 Status 快照(用于审计「当时为何预警」)。
GridCommunity string 是 长度约 128 底册管辖网格/社区快照。
SpecialCategory string 是 长度约 64 底册特殊类别快照。
Contact string 是 长度约 64 底册联系方式快照。
Confirmed bool 否 默认 false 是否已在界面执行「确认注销」处理。
ConfirmedAt DateTime? 是 — 确认操作时间(UTC)。
CreatedAt DateTime 否 — 本行生成时间(UTC)。

检查/调整建议:若需保留「确认人」或「二次复核」状态,可增加字段并扩展确认接口。


5.5 表关系简图(逻辑)

CompareBatch (1) ──< (N) DeathRecord          # 一批导入多条死亡行
CompareBatch (1) ──< (N) CompareMatch         # 一批产生多条命中(仅非已故底册)
PersonRegistry (1) ← 按 IdNumberNorm 关联 ─ DeathRecord / CompareMatch(比对逻辑)

说明:DeathRecord 与 PersonRegistry 在库中无强制外键声明,由业务代码关联;删除底册人员前需评估是否保留历史 DeathRecord / CompareMatch。


六、运行与调试(补充)

  • 默认桌面:dotnet run(启动配置 Photino)。
  • 仅浏览器:dotnet run --launch-profile 浏览器调试,按控制台打印的实际 http://127.0.0.1:端口 打开。
  • 强制浏览器、不启 Photino:dotnet run -- --browser。

七、后续可优化方向(可选)

  • 死亡/底册数据量在 十万级以上 时:可对导入校验、命中查询做分批或索引优化,并评估 MiniExcel 全量入内存策略。
  • 严格接入 Tailwind 构建与 design token。
  • 表结构变更时:同步更新本文档第五节与 DatabaseInitializer 中的手工 SQL(若有)。

文档版本与实现对齐;修改表字段后请同时更新 Data/Entities.cs 与本节内容。

An unhandled error has occurred. Reload 🗙

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.