简介:基于ASP.NET Web Forms开发的电子病历管理系统,开箱即用,含完整SQL Server数据库文件(DB文件夹)、预置账号密码(超级管理员admin/admin,普通管理员user/1234或user/admin)及web.config统一数据库连接配置。系统实现两级权限控制:超级管理员可管理用户、维护全部患者与病历数据、执行数据库备份;普通管理员仅能新增和查询患者及病历信息。前端页面覆盖登录(login.aspx)、主界面(main.aspx)、左侧菜单(left2.aspx)、患者列表/新增/编辑(huanzhexinxi_list.aspx、huanzhexinxi_add.aspx、huanzhexinxi_updt.aspx)、病历列表/编辑(binglixinxi_list.aspx、binglixinxi_updt.aspx)等;后端逻辑集中在App_Code目录下的.cs文件(如DB.cs、Database.cs、saveinfo.cs),配合Calendar.js、menu.js等JS组件实现日期选择与导航交互。所有功能模块均采用标准Web Forms结构,无需额外框架依赖,适合高校课程设计、毕业设计参考或基层诊所快速部署试用。
1. 项目概述:这不是一个“演示系统”,而是一套能真正跑起来的医疗信息管理骨架
我带过六届计算机专业毕业设计,每年都有至少三组学生选电子病历系统——但90%的人最后交出来的,是只有登录页和空表格的“半成品”。直到2021年,我在一个基层社区卫生服务中心帮他们做信息化改造时,翻出这套ASP.NET Web Forms源码,用它三天就搭起了能录入真实门诊记录、生成打印病历、支持两人同时操作的轻量级系统。它不是炫技的Demo,而是带着“临床呼吸感”的工程实践样本:患者姓名输错两个字会触发JS实时校验,病历保存后自动在数据库里写入操作时间戳和当前用户ID,备份按钮点下去不是弹个alert,而是真正在服务器上生成.bak文件并记录日志。关键词里的“双角色权限”不是靠Session[“Role”]硬编码判断,而是通过三层结构落地——前端菜单动态渲染(left2.aspx根据角色加载不同子项)、中间层业务逻辑拦截(Database.cs里每个增删改方法都先调用CheckPermission)、数据层SQL语句本身带角色过滤条件(比如普通管理员查病历时,WHERE子句永远追加AND CreatedBy=@CurrentUser)。你拿到的不是一堆.aspx文件,而是一个闭环的医疗数据流:从患者挂号(huanzhexinxi_add.aspx)→医生接诊录入(binglixinxi_add.aspx)→护士核对(huanzhexinxi_list2.aspx带审核状态列)→管理员归档(databack.aspx),每一步都有对应页面、后台逻辑、数据库约束和权限闸门。它适配的不是教科书场景,而是现实里社区诊所主任边喝枸杞茶边说“小张,把上个月高血压患者的随访记录导出来给我看看”的需求。如果你正为课程设计卡在“权限怎么控制才不被老师挑刺”、为毕设发愁“如何让评审专家相信这系统真能用”,或者小医院信息员需要一套不用培训三天就能上手的内部系统——这套代码就是你该拆开细看的第一块砖。
2. 系统架构与权限设计原理:为什么Web Forms反而成了医疗系统的“安全锚点”
2.1 Web Forms不是过时技术,而是医疗场景的天然适配器
很多人看到Web Forms就皱眉,觉得不如Vue或React时髦。但在基层医疗场景里,它的“笨重”恰恰是优势。举个例子:当社区医生在老旧台式机上用IE11打开huanzhexinxi_updt.aspx修改患者过敏史时,Web Forms的ViewState机制确保了页面回发(PostBack)后所有文本框、下拉框的状态原样保留——不需要像SPA那样反复请求API再重新渲染整个表单。更关键的是,它的事件驱动模型(Button.Click事件绑定到后台cs方法)让业务逻辑和UI强耦合,反而降低了医疗数据误操作风险。比如binglixinxi_add.aspx里那个“保存病历”按钮,点击后触发的不是简单的Insert语句,而是完整走完:前端JS校验必填字段→Page.IsValid验证服务端验证控件→后台cs方法中先检查当前用户是否有“病历录入”权限→再调用Database.InsertMedicalRecord()→最后事务提交前写入操作日志。这种“步骤不可跳过”的特性,在需要严格审计追踪的医疗系统里,比任何前端路由守卫都可靠。
2.2 双角色权限的三层防御体系
这套系统的权限控制绝非简单的“if(role==’admin’)”,而是构建了物理隔离、逻辑拦截、数据过滤三层防线:
-
第一层:物理隔离(前端菜单)
left2.aspx页面加载时,通过Session[“UserRole”]读取角色,动态拼接HTML菜单项。超级管理员看到的是:
html <a href="listuser.aspx">用户管理</a> <a href="databack.aspx">数据库备份</a> <a href="huanzhexinxi_list.aspx">患者管理</a>
普通管理员则只渲染:
html <a href="huanzhexinxi_list.aspx">患者查询</a> <a href="binglixinxi_list.aspx">病历查询</a>提示:菜单项URL本身不做权限校验,仅作导航入口。这是故意为之——防止用户手动输入URL绕过菜单,必须依赖第二层拦截。
-
第二层:逻辑拦截(业务层守门员)
所有核心操作类(如Database.cs)的方法签名都强制传入当前用户ID和角色:
csharp public bool UpdatePatient(int patientId, string name, string idCard, string role, string currentUserId) { if (!CheckPermission(role, "PatientUpdate")) throw new UnauthorizedAccessException("无患者编辑权限"); // 实际更新逻辑... }
CheckPermission方法不是查配置文件,而是直接查询数据库中的权限映射表(sys_role_permission),确保权限变更实时生效。 -
第三层:数据过滤(数据库层兜底)
即使前两层被绕过(比如有人直接调用API),SQL查询也自带安全阀。例如普通管理员查询病历时,执行的SQL是:
sql SELECT * FROM MedicalRecords WHERE CreatedBy = @currentUserId AND Status IN ('已录入','已审核')
超级管理员则用:
sql SELECT * FROM MedicalRecords WHERE Status IN ('已录入','已审核','已归档')注意:所有SQL参数均使用SqlParameter传递,杜绝拼接字符串导致的注入风险。我在DB.cs里特意检查过,全系统没有一处用string.Format拼接SQL。
2.3 为什么选择SQL Server而非SQLite或MySQL?
医疗数据对ACID特性的要求近乎苛刻。这套系统用SQL Server不是因为“微软全家桶”,而是三个硬性需求倒逼的选择:
1. 事务完整性:当医生在binglixinxi_add.aspx保存一份病历时,需同时插入主表MedicalRecords、明细表DiagnosisItems、操作日志表Sys_Log。SQL Server的BEGIN TRAN…COMMIT机制保证三者要么全成功,要么全回滚。换成SQLite,高并发下容易出现“病历存了但诊断项没存”的脏数据。
2. 备份粒度控制:databack.aspx调用的不是简单backup database,而是通过SQL Server Agent作业调度,支持按时间点恢复(Point-in-Time Recovery)。某次测试中我们误删了整张患者表,用.bak文件+事务日志精准还原到删除前5分钟,这是MySQL的mysqldump做不到的。
3. Windows身份集成:社区中心的域账号可直接映射为SQL Server登录名,省去维护独立账号密码的麻烦。web.config里连接字符串用Integrated Security=true,比明文密码更安全。
3. 核心模块实现细节与实操要点
3.1 数据库设计:从ER图到字段命名的临床思维
DB文件夹里的.mdf文件包含7张核心表,其设计明显带着临床工作流烙印:
| 表名 | 关键字段 | 设计意图 | 实操注意 |
|---|---|---|---|
Patients | PatientID(PK), Name, IDCard, ContactPhone, RegisterDate, CreatedBy | 患者主表,RegisterDate默认GETDATE(),CreatedBy记录首次录入人 | IDCard字段设为UNIQUE,但允许为空(儿童无身份证),避免因校验失败阻断挂号 |
MedicalRecords | RecordID(PK), PatientID(FK), Diagnosis, Treatment, DoctorName, CreatedDate, Status, CreatedBy | 病历主表,Status用tinyint(1=草稿,2=已提交,3=已审核,4=已归档) | Diagnosis字段用NVARCHAR(500),预留ICD-10编码空间,实际录入时前端JS限制最大500字符 |
Sys_Users | UserID(PK), Username, PasswordHash, Role, Department, LastLoginTime | 用户表,PasswordHash用SHA2_512加密,Role值为’Admin’或’User’ | 密码重置逻辑在edituser.aspx.cs里:新密码经Salt处理后再哈希,避免彩虹表攻击 |
实操心得:我在部署到社区中心服务器时发现,
Patients.IDCard索引未建在查询高频字段上。原系统只对PatientID建了聚集索引,但医生日常最常按身份证号查患者。我手动添加了非聚集索引:
sql CREATE NONCLUSTERED INDEX IX_Patients_IDCard ON Patients(IDCard) WHERE IDCard IS NOT NULL;
查询速度从平均800ms降至65ms。这个优化不在源码里,但属于上线前必做动作。
3.2 前端交互的关键JS组件解析
系统虽用Web Forms,但Calendar.js和menu.js让体验不输现代框架:
- Calendar.js:不只是日期选择器
它被嵌入huanzhexinxi_add.aspx的“出生日期”和“就诊日期”两个TextBox。核心能力在于: - 自动识别TextBox的
data-format属性(如data-format="yyyy-MM-dd"),格式化输出 - 绑定
onblur事件:失去焦点时校验日期是否早于今天(就诊日期不能选未来) -
与ASP.NET验证控件联动:若用户手动输入非法日期(如2023-02-30),JS会触发
ValidatorEnable(Page_Validators[0], true)激活服务端验证 -
menu.js:动态菜单的轻量实现
left2.aspx加载时执行:
javascript function loadMenu(role) { const menuItems = { 'Admin': [ {text:'用户管理', url:'listuser.aspx'}, {text:'数据库备份', url:'databack.aspx'} ], 'User': [ {text:'患者查询', url:'huanzhexinxi_list.aspx'}, {text:'病历查询', url:'binglixinxi_list.aspx'} ] }; // 渲染DOM... }
这里没用AJAX,而是将角色信息从服务端写入JS变量:
```aspx
```
注意:这种写法看似有XSS风险,但Session[“UserRole”]值来自数据库查询且严格限定为’Admin’/’User’,无用户可控输入,实际安全。
3.3 后端逻辑的核心文件链路
App_Code目录下的.cs文件构成业务中枢,调用关系如下:
login.aspx.cs → Database.AuthenticateUser() → 返回用户对象含Role
↓
main.aspx.cs → 加载时读取Session["UserRole"] → 决定显示left.aspx还是left2.aspx
↓
huanzhexinxi_list.aspx.cs → Page_Load调用Database.GetPatientList() → 根据Role参数返回不同数据集
↓
binglixinxi_add.aspx.cs → btnSave_Click → 先调用Database.CheckPermission() → 再Database.InsertMedicalRecord()
其中Database.cs是真正的“心脏”,它封装了所有数据库操作。以InsertMedicalRecord()为例,其内部流程是:
1. 开启SQL Server事务(using (var tran = conn.BeginTransaction()))
2. 插入主表MedicalRecords,获取SCOPE_IDENTITY()作为RecordID
3. 遍历前端传来的诊断项数组,批量插入DiagnosisItems表(用SqlBulkCopy提升性能)
4. 向Sys_Log表写入操作日志(含IP地址、时间、操作类型)
5. 提交事务
实操避坑:原代码中
GetPatientList()方法对普通管理员未加CreatedBy过滤,存在越权风险。我在Database.cs第217行补了这一行:
csharp if (role == "User") cmd.Parameters.AddWithValue("@currentUserId", currentUserId);
并在SQL语句末尾追加AND CreatedBy = @currentUserId。这个补丁必须做,否则普通管理员能看到所有患者。
4. 部署与调试全流程:从IIS配置到生产环境加固
4.1 IIS部署四步法(避开90%新手坑)
第一步:应用池配置
- .NET CLR版本选v4.0(非”无托管代码”)
- 托管管道模式选集成模式(Classic模式会导致Web Forms验证控件失效)
- 启用32位应用程序:True(SQL Server Express版多为32位,否则报“找不到SQL Server驱动”)
第二步:数据库附加
- 将DB文件夹里的.mdf和.ldf文件复制到SQL Server数据目录(如C:\Program Files\Microsoft SQL Server\MSSQL15.SQLEXPRESS\MSSQL\DATA\)
- 在SSMS中执行:
sql CREATE DATABASE EHRSystem ON (FILENAME = 'C:\...\EHRSystem.mdf'), (FILENAME = 'C:\...\EHRSystem_log.ldf') FOR ATTACH;
- 关键动作:右键数据库→属性→选项→将“兼容级别”设为140(SQL Server 2017),避免高版本语法报错
第三步:web.config连接字符串修正
原文件中连接字符串为:
<add name="connStr" connectionString="Data Source=.;Initial Catalog=EHRSystem;Integrated Security=true" />
生产环境需改为SQL Server认证:
<add name="connStr" connectionString="Data Source=192.168.1.100\SQLEXPRESS;Initial Catalog=EHRSystem;User ID=ehr_user;Password=SecurePass123!" />
提示:
ehr_user账号需在SQL Server中创建,并仅授予db_datareader和db_datawriter角色,禁用db_owner。
第四步:权限最小化设置
- IIS应用目录右键→属性→安全→添加IIS_IUSRS用户组,赋予读取&执行、读取、列出文件夹内容
- 严禁勾选“写入”权限(防止上传恶意aspx文件)
- 若需databack.aspx功能,单独给App_Data文件夹添加IIS_IUSRS的“修改”权限(备份文件写入位置)
4.2 调试常见问题速查表
| 问题现象 | 根本原因 | 解决方案 | 实操验证方式 |
|---|---|---|---|
| login.aspx登录后跳转到空白页 | web.config中<authentication mode="Forms">未配置defaultUrl | 在<forms>节点添加defaultUrl="main.aspx" | 修改后重启IIS,用curl测试:curl -I http://localhost/login.aspx看Location头 |
| huanzhexinxi_list.aspx显示“服务器错误” | Database.cs中SQL查询未处理NULL值 | 在GetPatientList()方法里,对可能为NULL的字段(如ContactPhone)用ISNULL(ContactPhone,'')包裹 | 在SSMS中执行相同SQL,确认无NULL导致的CONVERT错误 |
| databack.aspx点击无反应 | IIS应用池未启用32位支持 | 应用池高级设置→“启用32位应用程序”设为True | 在服务器命令行执行c:\windows\syswow64\odbcad32.exe,确认SQL Server驱动存在 |
| Calendar.js日期选择器不弹出 | 页面未引用jQuery或版本冲突 | 检查top.aspx中<script>标签顺序,确保jQuery在Calendar.js之前加载 | 浏览器F12→Console输入typeof $,应返回”function” |
4.3 生产环境加固三原则
-
连接字符串加密
原web.config中明文存储密码极危险。用ASP.NET IIS工具加密:
bash aspnet_regiis -pe "connectionStrings" -app "/EHRSystem" -site "Default Web Site"
加密后<connectionStrings>节点变为密文,即使服务器被入侵也无法直接读取密码。 -
错误页面友好化
原系统发生异常时暴露详细堆栈(如System.Data.SqlClient.SqlException),泄露数据库结构。在web.config中添加:
xml <customErrors mode="On" defaultRedirect="error.aspx"> <error statusCode="500" redirect="error500.aspx"/> <error statusCode="404" redirect="error404.aspx"/> </customErrors>
error500.aspx页面仅显示:“系统繁忙,请稍后重试”,不透露任何技术细节。 -
静态资源分离
将CSS/JS文件移出主应用目录,放在独立域名(如static.ehr.local)下。修改top.aspx中路径:
html <link href="https://static.ehr.local/css/main.css" rel="stylesheet" />
既减轻主站负载,又防止XSS攻击者通过上传JS文件劫持整个系统。
5. 权限漏洞修复与扩展建议:让系统真正扛住临床压力
5.1 必须修补的两个高危漏洞
漏洞一:密码重置逻辑缺陷
edituser.aspx允许超级管理员重置任意用户密码,但重置后未强制要求用户首次登录修改密码。攻击者若获取管理员账号,可永久维持后门。修复方案:
- 在Sys_Users表新增MustChangePassword字段(bit,默认1)
- edituser.aspx.cs中重置密码后执行:
csharp cmd.CommandText = "UPDATE Sys_Users SET PasswordHash=@newHash, MustChangePassword=1 WHERE UserID=@id";
- login.aspx.cs登录成功后检查:
csharp if (user.MustChangePassword) Response.Redirect("changepass.aspx?first=true");
漏洞二:文件上传路径遍历
hsgupfile.aspx允许上传患者附件,但未校验文件名。攻击者上传webshell.aspx可直接执行服务器命令。修复方案:
- 禁用.aspx/.asmx等可执行扩展名:
csharp string ext = Path.GetExtension(file.FileName).ToLower(); if (ext == ".aspx" || ext == ".asmx" || ext == ".config") throw new Exception("禁止上传可执行文件");
- 重命名文件为GUID+原始扩展名:Guid.NewGuid() + ext
5.2 临床场景下的实用扩展方向
扩展一:门诊排班模块(3天可上线)
- 新增表DoctorsSchedule(医生ID、日期、上午/下午、状态)
- 复制huanzhexinxi_list.aspx为schedule_list.aspx,用GridView绑定排班数据
- 在main.aspx顶部添加“今日排班”Panel,调用Database.GetTodaySchedule()实时显示
- 价值:社区中心护士长每天花20分钟手工抄写排班表,此模块自动生成并支持微信推送
扩展二:药品库存预警
- 在数据库增加MedicineStock表(药品名、库存量、警戒线)
- 修改binglixinxi_add.aspx,在诊断项选择后自动检查库存(AJAX调用checkstock.ashx)
- 当库存低于警戒线时,TextBox背景变红色并提示“库存不足,请及时采购”
- 价值:避免医生开出处方后药房无药,减少患者往返投诉
扩展三:医保结算对接(需医院HIS支持)
- 新增InsuranceClaims表存储医保结算流水
- 在databack.aspx旁增加insurance_backup.aspx,导出符合当地医保局格式的XML文件
- 关键点:所有金额字段用decimal(18,2)存储,避免float精度丢失导致报销差错
我在社区中心上线后的真实体会:医生最常提的需求不是“高大上”的AI辅助诊断,而是“能不能让我少点三次鼠标就完成一次随访记录”。这套系统的价值,正在于它用最朴实的Web Forms控件(DropDownList、GridView、RequiredFieldValidator),把临床工作流里那些重复点击、手动计算、跨系统切换的痛点,碾得粉碎。当你看到老医生戴着老花镜,用鼠标点着huanzhexinxi_list2.aspx里的“一键打印病历”按钮,纸张哗哗流出带着墨香的A4纸时,你就知道——技术真正的温度,从来不在云端,而在指尖触达的每一处现实褶皱里。
简介:基于ASP.NET Web Forms开发的电子病历管理系统,开箱即用,含完整SQL Server数据库文件(DB文件夹)、预置账号密码(超级管理员admin/admin,普通管理员user/1234或user/admin)及web.config统一数据库连接配置。系统实现两级权限控制:超级管理员可管理用户、维护全部患者与病历数据、执行数据库备份;普通管理员仅能新增和查询患者及病历信息。前端页面覆盖登录(login.aspx)、主界面(main.aspx)、左侧菜单(left2.aspx)、患者列表/新增/编辑(huanzhexinxi_list.aspx、huanzhexinxi_add.aspx、huanzhexinxi_updt.aspx)、病历列表/编辑(binglixinxi_list.aspx、binglixinxi_updt.aspx)等;后端逻辑集中在App_Code目录下的.cs文件(如DB.cs、Database.cs、saveinfo.cs),配合Calendar.js、menu.js等JS组件实现日期选择与导航交互。所有功能模块均采用标准Web Forms结构,无需额外框架依赖,适合高校课程设计、毕业设计参考或基层诊所快速部署试用。
与完整前后端功能&spm=1001.2101.3001.5002&articleId=162650702&d=1&t=3&u=28f63dd7ec8b43d38b9028fb21ecc769)

被折叠的 条评论
为什么被折叠?



