药店管理系统作为医药零售行业数字化转型的核心工具,正在经历从传统单机版向云端协同的转型。2025年的行业数据显示,超过78%的中小型药店开始采用B/S架构管理系统,而基于SpringBoot+Vue的技术栈因其快速迭代和前后端分离优势,已成为主流选择方案。
这个开源项目采用当前企业级开发中最稳定的技术组合:
注意:系统默认使用MySQL8.0的特性如窗口函数,若需降级到5.7版本需要修改部分SQL语句
采用批次管理与效期双维度库存模型:
java复制// 药品入库核心逻辑示例
public class DrugStorageService {
@Transactional
public void batchInStock(DrugBatchDTO dto) {
// 1. 校验效期格式(yyyy-MM-dd)
LocalDate expiryDate = DateValidator.validate(dto.getExpiryDate());
// 2. 生成唯一批次号(规则:药品ID+入库日期+4位随机数)
String batchNo = generateBatchNumber(dto.getDrugId());
// 3. 库存记录(带乐观锁控制)
drugStockMapper.updateStockWithLock(
dto.getDrugId(),
batchNo,
dto.getQuantity(),
expiryDate
);
}
}
关键业务规则:
实现符合GSP规范的"四查十对"流程:
创新性地整合了:
code复制pharmacy-backend
├── drug-core // 药品核心业务
├── order-system // 订单交易
├── report-engine // 报表生成
├── task-center // 定时任务
└── api-gateway // 统一鉴权
性能优化点:
使用Spring Cache抽象层实现三级缓存:
采用Redisson实现分布式锁,解决超卖问题:
java复制public void deductStock(Long drugId, int quantity) {
RLock lock = redissonClient.getLock("stock:" + drugId);
try {
if(lock.tryLock(3, 10, TimeUnit.SECONDS)) {
// 库存操作...
}
} finally {
lock.unlock();
}
}
vue复制<template>
<div ref="chart" style="width:100%;height:400px"></div>
</template>
<script setup>
import * as echarts from 'echarts';
onMounted(() => {
const chart = echarts.init(instance.value);
chart.setOption({
tooltip: {...},
visualMap: {...},
calendar: {...},
series: [{...}]
});
});
</script>
css复制.dashboard-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1rem;
}
推荐使用Docker Compose编排:
yaml复制version: '3.8'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql-data:/var/lib/mysql
redis:
image: redis:6-alpine
ports:
- "6379:6379"
backend:
build: ./pharmacy-backend
depends_on:
- mysql
- redis
ports:
- "8080:8080"
frontend:
build: ./pharmacy-frontend
ports:
- "80:80"
遵循RESTful规范:
java复制public class Result<T> {
private Integer code;
private String msg;
private T data;
private Long timestamp = System.currentTimeMillis();
}
基于Apache POI + Velocity模板引擎:
技巧:大数据量导出时采用分页查询+异步导出
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 登录后跳转空白页 | JWT令牌失效 | 检查Redis连接及token过期时间配置 |
| 药品查询缓慢 | 未建拼音码索引 | 执行ALTER TABLE drug ADD INDEX idx_pinyin(pinyin_code) |
| 打印小票乱码 | 打印机编码设置错误 | 调整为GB18030编码 |
性能调优实测数据:
实际开发中我们发现,药品批号管理是最容易出错的环节。建议在数据库设计阶段就建立唯一约束:
sql复制ALTER TABLE drug_batch
ADD UNIQUE INDEX uk_drug_batch (drug_id, batch_no);
这个系统在连锁药店场景下需要特别注意门店间数据隔离的问题。我们通过在每个查询中自动注入store_id条件来实现:
java复制@Interceptor
public class StoreFilterInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String storeId = SecurityUtils.getCurrentStoreId();
RequestContextHolder.setStoreId(storeId);
}
}