这个社区医院管理系统是我去年带队开发的一个实际项目,当时接到需求是要为本地几家社区医院打造一套符合最新医疗信息化标准的解决方案。传统社区医院使用的老系统普遍存在几个痛点:功能模块割裂、数据无法互通、扩展性差,医生和患者的使用体验都很糟糕。我们团队基于SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0技术栈,开发了这套前后端分离的现代化管理系统。
系统最大的特点是采用了"微服务+中台"的架构思想,将核心医疗业务能力抽象为可复用的服务模块。比如我们把患者档案管理、预约挂号引擎、药品库存预警等核心功能都做成了独立服务,这样不同规模的社区医院可以根据实际需求灵活组合功能模块。下面我会结合具体实现细节,分享这个项目中的技术选型考量和开发经验。
选择SpringBoot2作为基础框架主要考虑以下几点:
数据库选用MySQL8.0而非5.7版本,主要看中:
java复制// 典型的数据访问层实现示例
@Repository
public interface PatientRepository extends BaseMapper<Patient> {
@Select("SELECT * FROM patient WHERE health_card_no = #{cardNo}")
Patient selectByHealthCardNo(@Param("cardNo") String encryptedCardNo);
@Select("SELECT * FROM patient WHERE real_name LIKE CONCAT('%',#{name},'%')")
List<Patient> searchByName(@Param("name") String name);
}
前端采用Vue3+TypeScript的组合主要基于:
我们按角色拆分了三个独立前端工程:
vue复制<!-- 典型预约组件实现 -->
<script setup lang="ts">
const timeSlots = ref(['08:00-09:00', '09:00-10:00',...])
const selectedDept = ref('')
const availableDoctors = computed(() => {
return doctors.value.filter(d =>
d.dept === selectedDept.value &&
d.schedule.some(s => s.date === selectedDate.value)
)
})
</script>
患者表设计有几个关键点需要注意:
sql复制-- 患者表创建语句示例
CREATE TABLE `patient` (
`patient_uid` bigint NOT NULL COMMENT '雪花算法生成',
`health_card_no` varchar(64) NOT NULL COMMENT 'AES加密存储',
`real_name` varchar(50) NOT NULL,
`gender_code` tinyint NOT NULL COMMENT '1男2女',
`birth_date` date NOT NULL,
`contact_mobile` varchar(64) NOT NULL COMMENT '加密存储',
`resident_addr` varchar(200) DEFAULT NULL COMMENT '地址密文',
`allergy_history` json DEFAULT NULL COMMENT '过敏史JSON',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`patient_uid`),
UNIQUE KEY `idx_health_card` (`health_card_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
重要提示:医疗数据必须符合等保2.0要求,我们实现了:
- 数据库字段级加密
- 操作日志全量审计
- 敏感数据脱敏展示
排班算法是我们花了最多时间优化的部分,核心逻辑包括:
java复制// 排班冲突检测逻辑
public boolean checkScheduleConflict(DoctorSchedule newSchedule) {
return scheduleMapper.exists(
new QueryWrapper<DoctorSchedule>()
.eq("doctor_uid", newSchedule.getDoctorUid())
.eq("work_date", newSchedule.getWorkDate())
.eq("time_slot", newSchedule.getTimeSlot())
.ne("status_flag", 2) // 排除已停诊
);
}
药品管理实现了以下关键特性:
库存扣减采用乐观锁防止超卖:
java复制@Transactional
public boolean reduceStock(String medicineSku, int quantity) {
Medicine medicine = medicineMapper.selectById(medicineSku);
if (medicine.getCurrentStock() < quantity) {
throw new BusinessException("库存不足");
}
int updated = medicineMapper.update(null,
new UpdateWrapper<Medicine>()
.setSql("current_stock = current_stock - " + quantity)
.eq("medicine_sku", medicineSku)
.ge("current_stock", quantity)
);
return updated > 0;
}
采用JWT+RBAC的权限控制模型:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/doctor/**").hasAnyRole("DOCTOR","ADMIN")
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
采用多级缓存架构:
java复制@Cacheable(value = "doctor", key = "#deptCode")
public List<Doctor> getDoctorsByDept(String deptCode) {
return doctorMapper.selectList(
new QueryWrapper<Doctor>()
.eq("dept_code", deptCode)
.eq("status", 1)
);
}
sql复制-- 复合索引示例
ALTER TABLE `appointment` ADD INDEX `idx_patient_date` (`patient_uid`, `appointment_date`);
使用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql/data:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
这个项目让我深刻体会到医疗信息化系统的特殊性 - 既要保证系统的高可用性,又要满足严格的合规要求。我们在开发过程中建立了完整的质量保障体系,包括:
最后给需要开发类似系统的同行几个建议: