1. 项目背景与核心需求
社区医院作为基层医疗服务的第一线,每天需要处理大量患者就诊、药品管理和医生排班等事务。传统的手工记录方式不仅效率低下,还容易出现信息遗漏和错误。我在实际调研中发现,很多社区医院还在使用Excel表格管理患者信息,医生排班靠纸质登记,药品库存更新滞后,这些问题严重影响了医疗服务的质量和效率。
这套社区医院管理系统正是为了解决这些痛点而设计的。系统采用前后端分离架构,前端用Vue.js实现响应式界面,后端基于SpringBoot构建,数据库选用MySQL,通过MyBatis实现数据持久化。这种技术栈的选择主要基于以下考虑:
- SpringBoot的自动配置和起步依赖能快速搭建后端服务
- Vue.js的组件化开发适合构建复杂的医疗管理界面
- MySQL作为成熟的关系型数据库,能保证医疗数据的安全性和一致性
- MyBatis的灵活性便于处理复杂的医疗业务查询
2. 系统架构设计
2.1 技术选型解析
前端技术栈:
- Vue 2.x:核心框架,提供响应式数据绑定和组件系统
- Element UI:提供丰富的UI组件,加速界面开发
- Axios:处理HTTP请求,与后端API交互
- Vue Router:实现前端路由管理
- Vuex:状态管理,共享登录状态等全局数据
后端技术栈:
- SpringBoot 2.5.x:快速构建RESTful API
- Spring Security:处理认证和授权
- MyBatis-Plus:增强的ORM框架,简化数据库操作
- Redis:缓存高频访问的数据如药品目录
- Swagger:API文档生成
数据库设计原则:
- 患者数据与就诊记录分离,避免数据冗余
- 医生排班采用时间片设计,支持灵活排班
- 药品库存设置预警机制,防止缺货
- 所有表都包含创建时间和更新时间字段
2.2 系统模块划分
系统主要分为以下几个核心模块:
-
患者管理模块
- 患者注册与信息维护
- 就诊记录管理
- 病历查询与统计
-
医生工作台模块
- 医生信息管理
- 排班管理
- 患者接诊处理
- 电子处方开具
-
药品管理模块
- 药品信息维护
- 库存动态管理
- 库存预警通知
- 药品出入库记录
-
预约挂号模块
- 在线预约
- 号源管理
- 预约统计
-
系统管理模块
- 用户权限管理
- 系统参数配置
- 操作日志审计
3. 核心功能实现细节
3.1 患者信息管理实现
患者信息管理采用分页查询设计,前端通过axios发送请求:
java复制@RestController
@RequestMapping("/api/patient")
public class PatientController {
@Autowired
private PatientService patientService;
@GetMapping("/list")
public Result listPatients(
@RequestParam(required = false) String name,
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize) {
Page<Patient> page = patientService.getPatientList(name, pageNum, pageSize);
return Result.success(page);
}
// 其他CRUD接口...
}
关键点:
- 使用MyBatis-Plus的分页插件实现物理分页
- 模糊查询支持按姓名搜索患者
- 返回统一封装的Result对象,包含状态码和消息
3.2 医生排班算法设计
排班系统采用时间片管理,每个医生每天最多安排8个时间段:
java复制public class ScheduleService {
public Result createSchedule(ScheduleDTO dto) {
// 检查时间段冲突
if (checkTimeConflict(dto.getDoctorId(), dto.getScheduleDate(),
dto.getStartTime(), dto.getEndTime())) {
return Result.error("该时间段已有排班");
}
// 创建排班记录
Schedule schedule = new Schedule();
BeanUtils.copyProperties(dto, schedule);
schedule.setCreateTime(LocalDateTime.now());
scheduleMapper.insert(schedule);
return Result.success("排班创建成功");
}
private boolean checkTimeConflict(String doctorId, LocalDate date,
LocalTime start, LocalTime end) {
// 查询该医生当天的所有排班
List<Schedule> schedules = scheduleMapper.selectByDoctorAndDate(doctorId, date);
for (Schedule s : schedules) {
if (isTimeOverlap(start, end, s.getStartTime(), s.getEndTime())) {
return true;
}
}
return false;
}
}
排班冲突检测逻辑:
- 查询医生指定日期的所有排班记录
- 检查新排班时间段与已有排班是否重叠
- 使用LocalTime比较时间范围
3.3 药品库存预警实现
库存预警通过定时任务检查库存量:
java复制@Scheduled(cron = "0 0 9 * * ?") // 每天上午9点执行
public void checkMedicineStock() {
List<Medicine> medicines = medicineMapper.selectList(null);
for (Medicine medicine : medicines) {
if (medicine.getStockQuantity() < medicine.getWarningThreshold()) {
// 发送预警通知
String message = String.format("药品【%s】库存不足,当前数量:%d,预警阈值:%d",
medicine.getMedicineName(),
medicine.getStockQuantity(),
medicine.getWarningThreshold());
notificationService.sendStockWarning(medicine.getMedicineId(), message);
}
}
}
优化点:
- 使用@Scheduled注解配置定时任务
- 预警消息包含药品名称和具体库存数据
- 通知服务支持多种通知方式(站内信、邮件等)
4. 权限控制设计
4.1 基于角色的访问控制
系统定义了几种核心角色:
- 系统管理员:拥有所有权限
- 医生:可以管理患者、排班和处方
- 药剂师:管理药品库存
- 患者:预约挂号和查看个人病历
权限配置通过Spring Security实现:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/doctor/**").hasAnyRole("DOCTOR", "ADMIN")
.antMatchers("/api/pharmacist/**").hasAnyRole("PHARMACIST", "ADMIN")
.antMatchers("/api/patient/**").authenticated()
.anyRequest().permitAll()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
4.2 JWT认证流程
- 用户登录成功后生成JWT token
- 前端将token存储在localStorage中
- 每次请求携带token在Authorization头中
- 服务端验证token有效性
java复制public class JwtUtils {
private static final String SECRET = "your-secret-key";
private static final long EXPIRATION = 86400000; // 24小时
public static String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
claims.put("roles", userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList()));
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
}
// 验证token的方法...
}
5. 系统部署方案
5.1 生产环境配置
推荐使用Docker Compose部署整套系统:
yaml复制version: '3'
services:
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: hospital
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:alpine
ports:
- "6379:6379"
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
volumes:
mysql_data:
部署步骤:
- 安装Docker和Docker Compose
- 准备配置文件(application-prod.yml等)
- 构建前端静态资源:
npm run build - 启动服务:
docker-compose up -d
5.2 性能优化建议
-
数据库优化:
- 为常用查询字段添加索引
- 使用连接池配置(HikariCP)
- 复杂查询使用MyBatis二级缓存
-
前端优化:
- 使用路由懒加载
- 组件按需引入
- 启用Gzip压缩
-
后端优化:
- 启用SpringBoot Actuator监控
- 配置合理的线程池
- 高频数据使用Redis缓存
6. 开发中的经验总结
6.1 遇到的典型问题及解决方案
问题1:患者预约冲突
- 现象:多个患者同时预约同一时段导致超约
- 解决方案:使用数据库乐观锁控制预约数量
java复制@Transactional
public Result makeAppointment(AppointmentDTO dto) {
// 查询当前已预约数
int current = appointmentMapper.countBySchedule(dto.getScheduleId());
Schedule schedule = scheduleMapper.selectById(dto.getScheduleId());
if (current >= schedule.getMaxAppointments()) {
return Result.error("该时段预约已满");
}
// 创建预约记录
Appointment appointment = new Appointment();
BeanUtils.copyProperties(dto, appointment);
appointmentMapper.insert(appointment);
// 更新已预约数
scheduleMapper.increaseAppointedCount(dto.getScheduleId());
return Result.success("预约成功");
}
问题2:药品库存并发更新
- 现象:多个入库操作同时进行导致库存不准
- 解决方案:使用MySQL行锁保证更新原子性
sql复制UPDATE medicine
SET stock_quantity = stock_quantity + #{quantity}
WHERE medicine_id = #{medicineId}
6.2 值得分享的开发技巧
-
API文档自动化:
使用Swagger UI自动生成API文档,减少手动维护工作量:java复制@Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.hospital.controller")) .paths(PathSelectors.any()) .build() .apiInfo(apiInfo()); } } -
前端表单验证:
使用Element UI的表单验证规则,提高用户体验:javascript复制rules: { patientName: [ { required: true, message: '请输入患者姓名', trigger: 'blur' }, { min: 2, max: 50, message: '长度在2到50个字符', trigger: 'blur' } ], phone: [ { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' } ] } -
数据库迁移管理:
使用Flyway管理数据库变更,确保各环境schema一致:sql复制-- V1__Initial_schema.sql CREATE TABLE patient ( patient_id VARCHAR(20) PRIMARY KEY, patient_name VARCHAR(50) NOT NULL, -- 其他字段... );
7. 系统扩展方向
在实际使用过程中,可以考虑以下几个扩展方向:
-
移动端适配:
- 开发微信小程序版本,方便患者随时预约
- 使用uni-app框架实现多端统一
-
智能推荐:
- 基于历史数据推荐就诊科室
- 根据症状推荐合适的医生
-
医保对接:
- 接入医保系统实现实时结算
- 开发医保对账功能
-
数据分析:
- 使用ECharts实现就诊数据可视化
- 基于Spring Batch实现定期报表生成
-
消息推送:
- 预约成功短信通知
- 药品到货提醒
- 复查提醒服务
这套社区医院管理系统经过多次迭代,目前已在3家社区医院试运行,显著提高了他们的工作效率。特别是在疫情期间,线上预约功能有效减少了人员聚集,获得了院方的好评。