1. 项目背景与核心价值
作为一名长期从事医药行业信息化建设的开发者,我深刻理解传统药店管理面临的痛点。去年为某连锁药店实施数字化改造时,他们的店长给我看了一摞厚厚的纸质台账——库存盘点误差率高达15%,过期药品损失每年超过20万元。这正是我们开发这套药店销售系统的初衷。
这个基于Spring Boot的全栈系统实现了三大突破:
- 实时库存动态:通过智能预警机制,当库存量低于阈值时自动触发采购流程,将库存误差控制在3%以内
- 全流程追溯:从供应商到客户的完整药品流向记录,满足GSP认证要求
- 多角色协同:独创的"药师-管理员"双审核机制,确保特殊药品的合规销售
2. 技术架构解析
2.1 整体技术栈设计
系统采用经典的三层架构,但在数据持久层做了创新设计:
code复制[前端] Vue.js + ElementUI
↑
[REST API] Spring Boot 2.7 + JWT
↑
[数据层] MyBatis-Plus + Druid + Redis
↑
[存储层] MySQL 8.0 (主从架构)
特别说明几个关键技术选型:
- MyBatis-Plus:相比原生MyBatis,其Lambda查询构建器使药品多条件检索代码量减少60%
- Druid连接池:配置了完善的SQL监控和防火墙规则,防止药品数据泄露
- Redis应用:采用Hash结构缓存药品库存信息,QPS可达20000+
2.3 数据库设计精要
药品管理的核心在于数据关系的严谨性。我们设计了7个关键实体:
-
药品主表(drug_warehouse)
- 采用"一物一码"原则,每个药品有唯一编号
- 包含有效期字段,系统会提前30天预警
-
业务流水表设计
sql复制CREATE TABLE `purchase_order` (
`purchase_number` varchar(64) NOT NULL COMMENT '采购单号规则:PO+年月日+4位序列',
`drug_number` varchar(64) NOT NULL COMMENT '关联药品编号',
`examine_state` enum('待审核','已通过','已拒绝') NOT NULL DEFAULT '待审核',
`audit_chain` json DEFAULT NULL COMMENT '审核链路记录'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3. 核心功能实现
3.1 库存智能预警系统
在药品仓库管理模块,我们实现了动态库存监控:
java复制// 库存检查定时任务
@Scheduled(cron = "0 0 9,15 * * ?")
public void checkInventory() {
List<DrugWarehouse> drugs = drugWarehouseMapper.selectList(
Wrappers.<DrugWarehouse>lambdaQuery()
.lt(DrugWarehouse::getInventoryQuantity, 10));
drugs.forEach(drug -> {
String msg = String.format("药品[%s]库存不足,当前数量:%d",
drug.getDrugName(), drug.getInventoryQuantity());
// 推送给相关药师
pushService.sendToPharmacist(drug.getPharmacist(), msg);
});
}
避坑指南:
- 避免在循环中查询数据库,应使用批量查询
- 预警阈值应该按药品分类设置,抗生素类应该比维生素类设置更高阈值
3.2 双审核业务流程
针对处方药的销售,我们设计了严格的审核流程:
- 药师提交销售订单
- 系统自动检查库存和客户购买记录
- 管理员进行终审
- 生成出库单同时扣减库存
mermaid复制graph TD
A[药师创建订单] --> B{库存检查}
B -->|充足| C[生成待审订单]
B -->|不足| D[返回缺货提示]
C --> E[管理员审核]
E -->|通过| F[生成出库单]
E -->|拒绝| G[通知药师]
4. 特色功能实现
4.1 药品追溯系统
通过二维码实现药品全生命周期追踪:
java复制public String generateDrugQRCode(String drugNumber) {
DrugWarehouse drug = drugWarehouseMapper.selectById(drugNumber);
String traceInfo = String.format("%s|%s|%s|%s",
drug.getDrugNumber(),
drug.getPharmaceuticalManufacturers(),
drug.getLimitedPeriodUntil(),
new SimpleDateFormat("yyyyMMdd").format(new Date()));
return qrCodeService.generateBase64QR(traceInfo);
}
4.2 财务对账模块
采用T+1对账模式,每日23:00自动生成日报:
sql复制INSERT INTO financial_information
SELECT
CURDATE() - INTERVAL 1 DAY as record_date,
SUM(CASE WHEN type='income' THEN amount ELSE 0 END) as income,
SUM(CASE WHEN type='expend' THEN amount ELSE 0 END) as expenditure,
SUM(CASE WHEN type='income' THEN amount ELSE -amount END) as profit
FROM transaction_record
WHERE DATE(create_time) = CURDATE() - INTERVAL 1 DAY;
5. 部署与优化实践
5.1 性能优化方案
我们在生产环境遇到并解决了以下性能问题:
-
药品列表查询慢(原耗时1200ms)
- 添加复合索引:
ALTER TABLE drug_warehouse ADD INDEX idx_class_stock (classification_of_drugs, inventory_quantity) - 引入Redis缓存热门药品数据
- 添加复合索引:
-
高峰期订单提交失败
- 采用消息队列削峰:
java复制@RabbitListener(queues = "order.queue") public void processOrder(Order order) { if(orderService.checkInventory(order)){ orderService.process(order); } }
5.2 安全防护措施
- 药品价格防篡改:
java复制@PostMapping("/order/create")
public Result createOrder(@Valid @RequestBody OrderDTO dto) {
// 验证前端传价与数据库一致
DrugWarehouse drug = drugWarehouseMapper.selectById(dto.getDrugNumber());
if(!drug.getPrice().equals(dto.getUnitPrice())){
throw new BusinessException("药品价格异常");
}
// ...后续处理
}
- 采用JWT+RBAC的权限控制模型,关键接口如药品删除需要管理员+药师双因子认证。
6. 项目演进方向
在实际运营中,我们正在推进以下改进:
- 智能采购预测:基于历史销售数据的LSTM模型,提前生成采购建议
- 电子处方对接:与互联网医院平台对接,实现处方流转
- 冷链监控:为需要冷藏的药品增加温度监控日志
这个项目给我最深的体会是:医药行业的数字化不仅要考虑技术实现,更要理解行业监管要求。比如我们在处理处方药销售流程时,必须严格遵守"审方-调配-复核-发药"的规范,这比普通电商系统的订单处理复杂得多。