ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

家谱电子化实战:JavaScript + C# 前后端协作与数据模型设计

家谱电子化实战:JavaScript + C# 前后端协作与数据模型设计 简介本资源为基于JavaScript与C#的FamilyTree家谱电子化项目设计源码面向需要完成家族族谱数字化管理系统的开发者与课程设计学习者尤其适合具备一定前后端基础、希望参考完整工程结构的中高级人员。项目通过JavaScript负责前端交互与页面呈现C#承担后端业务逻辑与数据处理实现家族成员信息的录入、维护与可视化展示。压缩包共290个文件约60.45MB其中包含77个DLL、42个XML、28个JavaScript、25个Nupkg、24个XDT、21个CS文件以及CSHTML、CSS、配置文件与构建脚本等覆盖依赖库、配置、视图与编译产物目录结构完整便于按模块查阅。目前已有396人学习下载。读者可从中获取一套可直接运行或二次开发的家谱管理系统源码理解前后端协作方式、项目分层组织与配置管理思路并借助现有结构快速搭建自己的族谱应用。1. 家谱电子化这件事为什么我最后选了 JavaScript C# 这套组合前阵子帮一个宗亲会做族谱数字化需求听起来简单把纸质家谱录入、存起来、能查、能导出。真上手才发现坑不少——家族成员关系是典型的树形结构但现实中存在过继、入赘、改嫁、同名同辈等一堆非标准情况纯前端存 localStorage 根本扛不住纯后端又没法让老一辈在手机上直接翻看。最后落地的方案是前端 JavaScript 负责交互和树形渲染后端 C# 负责数据持久化和复杂查询中间用 REST 接口打通。这套 FamilyTree 家谱电子化项目源码就是按这个思路组织的包含前端页面、C# 服务端、CSS 样式和数据库脚本。它适合两类人一是想拿现成架子改造成自己家族系统的开发者二是正在学 JavaScript 与 C# 前后端协作、需要一个真实业务场景练手的同学。下面我按实际拆包的顺序把结构、跑法、参数和踩过的坑一次讲清。2. 拆开源码包目录结构、技术栈与数据模型怎么对上号2.1 目录分层与文件职责拿到包先别急着 dotnet run花十分钟把目录过一遍能省后面两小时。这个项目的典型分层是这样的前端资源集中在wwwroot或独立的frontend目录里面按js/、css/、pages/分开C# 服务端通常是Controllers/、Models/、Services/、Data/四块数据库脚本单独放sql/或Scripts/。我一般会先找入口文件——前端的index.html和后端的Program.cs或Startup.cs这两个决定了整个项目怎么启动、路由怎么配。# 先看整体结构重点确认前端资源目录和后端入口 tree -L 3 -I bin|obj|node_modules # 输出示例不同版本略有差异 # . # ├── Controllers/ # C# 接口层 # ├── Models/ # 实体类FamilyMember 等 # ├── Services/ # 业务逻辑关系计算 # ├── Data/ # 数据库上下文 # ├── wwwroot/ # │ ├── js/ # 前端逻辑 # │ ├── css/ # 样式 # │ └── index.html # └── sql/ # 建表脚本这段命令的作用是快速建立空间感。-L 3限制三层避免输出爆炸-I排除编译产物。重点看Models/里有没有FamilyMember、Relation这类实体它们决定了家谱数据能表达多复杂的关系。如果只有一张平表那过继、入赘这些场景就得自己扩展。2.2 家谱数据模型为什么不能只用一张表家谱的核心是「人」和「关系」。新手最容易犯的错是设计成id, name, father_id, mother_id一张表完事结果遇到配偶、兄弟姐妹、辈分排序就抓瞎。这个项目里我看到的常见做法是拆成两张表FamilyMember存个人属性Relation存两人之间的边。表名关键字段作用FamilyMemberId, Name, Gender, BirthDate, Generation, Remark存个人基本信息Generation 表示第几世RelationId, FromId, ToId, RelationType存关系边RelationType 区分父子/配偶/过继FamilyId, Surname, Origin, CreatedAt存家族元信息支持多家族Generation这个字段很关键它让「按辈分排序」和「同辈校验」变得简单。RelationType用枚举而不是字符串查询时性能更好也避免「父亲」「父」这种脏数据。如果你要扩展建议再加一个RelationMeta字段存 JSON把「过继给谁」「入赘时间」这类非标准信息塞进去比无限加列优雅。2.3 前后端接口约定JavaScript 和 C# 之间靠 HTTP 接口通信约定不清就会出现前端传fatherId、后端等parentId的翻车。这个项目里接口一般集中在Controllers/FamilyController.cs前端在js/api.js里封装调用。我习惯先看接口返回结构再写前端。// js/api.js 里常见的封装方式 async function getMemberTree(familyId) { // 统一走 /api/family/tree参数用 query string const res await fetch(/api/family/tree?familyId${familyId}, { method: GET, headers: { Content-Type: application/json } }); if (!res.ok) throw new Error(请求失败: ${res.status}); return res.json(); // 期望返回嵌套的树形结构 }逻辑说明fetch用 GET 拿树形数据familyId作为查询参数区分不同家族。参数说明familyId必传缺失时后端应返回 400 而不是空树否则前端会误以为家族没人。返回结构建议是{ code, data, message }三段式data里放嵌套节点前端递归渲染时不用再拼装。如果后端直接返回扁平数组前端就得自己建索引再组树多一步但更灵活看你团队习惯。3. 把项目跑起来环境、数据库与前后端联调步骤3.1 环境准备与依赖安装跑这个项目需要 .NET SDK建议 6.0 及以上和任意现代浏览器前端如果用了构建工具还需要 Node.js。我一般先确认版本避免「在我机器上能跑」的玄学。# 检查 .NET 版本低于 6.0 建议升级 dotnet --version # 还原后端依赖 dotnet restore # 如果有前端构建步骤 npm install npm run builddotnet restore会根据.csproj拉取 NuGet 包常见依赖是 EntityFrameworkCore 和对应的数据库驱动。如果卡在还原先看网络和 NuGet 源配置别急着删obj。npm install只在有package.json时需要纯静态前端可以跳过。3.2 数据库初始化家谱数据必须落库SQLite 适合单机演示SQL Server 或 MySQL 适合多人访问。项目里通常有建表脚本先执行再改连接串。-- sql/init.sql 核心建表语句 CREATE TABLE FamilyMember ( Id INTEGER PRIMARY KEY AUTOINCREMENT, Name NVARCHAR(50) NOT NULL, Gender TINYINT NOT NULL, -- 0 未知 1 男 2 女 Generation INT NOT NULL, -- 第几世 BirthDate DATE, Remark NVARCHAR(200) ); CREATE TABLE Relation ( Id INTEGER PRIMARY KEY AUTOINCREMENT, FromId INT NOT NULL, ToId INT NOT NULL, RelationType TINYINT NOT NULL, -- 1 父子 2 配偶 3 过继 FOREIGN KEY (FromId) REFERENCES FamilyMember(Id), FOREIGN KEY (ToId) REFERENCES FamilyMember(Id) );逻辑说明FamilyMember存人Relation存边外键保证不会出现指向不存在成员的脏关系。参数说明Gender和RelationType用 TINYINT 省空间但要在代码里定义枚举对应别裸写数字。Generation建索引后按辈分查询会快很多。执行完脚本记得在appsettings.json里改连接串SQLite 是文件路径SQL Server 是完整连接字符串。3.3 启动与联调后端和前端分别启动或者后端托管静态文件一起跑。联调时重点看浏览器 Network 面板和后端控制台。# 启动后端默认监听 5000 或 5001 dotnet run # 如果前端独立启动 npm run dev启动后先访问健康检查接口如果有/api/health再打开首页。常见现象是页面能开但树是空的这时按 F12 看/api/family/tree返回什么。如果是 401检查有没有鉴权中间件如果是 500看后端日志里的异常堆栈多半是连接串或表结构不匹配。联调通过后试着新增一个成员再刷新确认写入和读取都正常这一步过了基本就稳了。4. 避坑与排查家谱项目里最容易翻车的五件事4.1 递归查树导致栈溢出现象家族人数上千后查询接口变慢甚至进程崩溃。原因用递归函数逐层查数据库N1 查询加上深递归。解决一次性把FamilyMember和Relation全查出来在内存里组树或者用 CTE 递归查询交给数据库。我一般选前者数据量在万级以内内存完全扛得住。4.2 中文姓名排序错乱现象按姓名排序时「张」跑到「李」前面。原因数据库默认排序规则是二进制或英文规则不认拼音。解决建表时指定COLLATE Chinese_PRC_CI_ASSQL Server或在应用层用localeCompare排序。前端排序更灵活但大数据量时还是数据库排更省事。4.3 关系环导致无限循环现象渲染树时页面卡死。原因数据录入错误形成 A 是 B 的父亲、B 又是 A 的父亲的环。解决写入Relation前做环检测用并查集或简单的 DFS 判断ToId是否已能到达FromId。这个校验放在 C# 服务层前端也加一层提示双保险。4.4 日期格式前后端不一致现象生日显示成Invalid Date或差一天。原因C# 的DateTime序列化成 ISO 格式带时区JavaScriptnew Date()解析时区处理不一致。解决后端统一返回yyyy-MM-dd字符串前端按字符串处理需要计算年龄时再手动解析别直接丢给Date构造函数。4.5 并发写入覆盖现象两个人同时录入后提交的覆盖了先提交的。原因没做乐观锁更新时直接覆盖整行。解决FamilyMember加RowVersion字段C# 用[Timestamp]特性更新时带上版本号冲突就提示重试。家谱录入场景并发不高但宗亲会多人同时操作时这个坑很真实。5. 进阶技巧用 Generation 字段做辈分校验与导出优化5.1 辈分自动校验录入时最容易出错的是辈分填错导致树形结构错乱。利用Generation字段可以在保存前做校验如果新增成员指定了父亲那他的Generation必须等于父亲的Generation 1。// Services/FamilyService.cs 里的校验逻辑 public bool ValidateGeneration(FamilyMember member, FamilyMember father) { // 父亲存在时辈分必须严格加一 if (father ! null member.Generation ! father.Generation 1) { return false; } // 配偶辈分必须相同 // ... 其他校验 return true; }逻辑说明这个方法在保存前调用father为 null 表示是始祖不校验。参数说明member.Generation来自前端表单father.Generation从数据库查。返回 false 时接口应返回具体错误信息别只给「保存失败」。这个校验能拦住八成以上的录入错误比事后修树省事得多。5.2 导出 PDF 的字体坑家谱最终要导出成 PDF 给长辈看中文乱码是高频问题。常见做法是用iTextSharp或PuppeteerSharp关键是嵌入中文字体。// 用 iTextSharp 导出时嵌入字体 var fontPath Path.Combine(env.WebRootPath, fonts, simsun.ttf); var baseFont BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED); var font new Font(baseFont, 12);逻辑说明IDENTITY_H表示用 Unicode 编码EMBEDDED把字体嵌进 PDF换台机器也不会乱码。参数说明字体文件要放对路径simsun.ttf注意版权商用换开源字体如思源宋体。导出前先小批量测试确认分页和缩进正常再全量跑。5.3 大数据量下的树形渲染家族超过五千人时前端一次性渲染整棵树会卡。我一般改成懒加载默认只渲染前三代展开节点时再请求子节点。接口加parentId参数返回直接子节点而非整棵树。这样首屏快用户也不会被几千个节点淹没。配合虚拟滚动万级数据也能流畅翻看。从那以后我每次接家谱类项目都强制先跑一遍辈分校验和环检测再谈界面美化。数据错了界面再漂亮也是白搭。希望帮到你。本文还有配套的精品资源点击获取
返回列表