医药行业的仓储管理有着严格的合规性要求和特殊的业务场景。我们采用Flask+Vue.js技术栈构建的这套系统,核心目标是实现药品全生命周期的数字化追踪。与普通仓储系统相比,医药仓库需要特别关注以下几个特性:
关键设计原则:采用"前后端分离+微服务"架构,后端API使用Flask的Blueprint进行模块化拆分,前端通过Vue3的组合式API实现高内聚组件。这种架构在保证系统灵活性的同时,也便于通过等保2.0三级认证。
在Python生态中,我们对比了Flask和Django两种主流框架的适用性:
| 特性 | Flask方案 | Django方案 |
|---|---|---|
| 开发速度 | 快速原型开发 | 全功能开箱即用 |
| 灵活性 | 可自由组合扩展包 | 强耦合的完整生态 |
| 性能 | 轻量级,路由处理更快 | 全栈框架稍重 |
| 医药行业适配 | 便于集成专业库如PyPDF2(处方处理) | 内置Admin适合快速搭建后台 |
最终选择Flask作为核心框架,主要基于以下考量:
Vue3的组合式API特别适合构建医药管理系统中的复杂交互界面:
javascript复制// 药品批次选择器组件示例
const useBatchSelector = () => {
const batches = ref([])
const loading = ref(false)
const fetchBatches = async (drugId) => {
loading.value = true
try {
batches.value = await api.get(`/drugs/${drugId}/batches`)
} finally {
loading.value = false
}
}
return { batches, loading, fetchBatches }
}
这种模式可以很好地封装药品批号查询、效期校验等业务逻辑,实现跨组件复用。
医药产品的数据模型需要包含GMP要求的完整属性:
python复制class Medicine(db.Model):
__tablename__ = 'medicines'
id = db.Column(db.Integer, primary_key=True)
code = db.Column(db.String(20), unique=True) # 药品电子监管码
name = db.Column(db.String(100), nullable=False)
specification = db.Column(db.String(50)) # 规格(如0.5g*24片)
dosage_form = db.Column(db.String(30)) # 剂型(片剂、注射液等)
manufacturer = db.Column(db.String(100))
approval_number = db.Column(db.String(50)) # 批准文号
storage_conditions = db.Column(db.JSON) # 存储条件(常温/阴凉/冷藏)
# 其他GMP要求字段...
特别注意:药品基础信息一旦创建不应修改,所有变更应通过版本控制记录。我们使用SQLAlchemy的event监听实现审计日志:
python复制@event.listens_for(Medicine, 'after_update')
def record_medicine_change(mapper, connection, target):
change = MedicineHistory(
medicine_id=target.id,
changed_fields={col.name: getattr(target, col.name)
for col in target.__table__.columns},
operator=get_current_user()
)
db.session.add(change)
医药仓库的出入库操作需要实现严格的ACID事务:
python复制@app.route('/api/inventory/outbound', methods=['POST'])
@jwt_required()
def create_outbound():
try:
data = request.get_json()
# 开启事务
db.session.begin_nested()
# 1. 扣减库存
medicine = Medicine.query.with_for_update().get(data['medicine_id'])
if medicine.quantity < data['quantity']:
raise BusinessError('库存不足')
medicine.quantity -= data['quantity']
# 2. 创建出库记录
outbound = OutboundOrder(
medicine_id=data['medicine_id'],
batch_number=data['batch_number'],
quantity=data['quantity'],
destination=data['destination'],
operator=get_jwt_identity()
)
db.session.add(outbound)
# 3. 记录库存流水
transaction = InventoryTransaction(
medicine_id=data['medicine_id'],
change_type='OUTBOUND',
before_quantity=medicine.quantity + data['quantity'],
after_quantity=medicine.quantity,
reference_id=outbound.id
)
db.session.add(transaction)
db.session.commit()
return jsonify({'success': True})
except Exception as e:
db.session.rollback()
current_app.logger.error(f'出库失败: {str(e)}')
return jsonify({'error': str(e)}), 400
对于需要2-8℃冷藏的药品,我们设计了双通道温度监控方案:
前端使用ECharts实现温度波动可视化:
javascript复制const initTempChart = () => {
const chart = echarts.init(document.getElementById('temp-chart'))
const option = {
tooltip: {
trigger: 'axis',
formatter: params => {
const time = dayjs(params[0].value[0]).format('YYYY-MM-DD HH:mm:ss')
return `时间: ${time}<br/>温度: ${params[0].value[1]}℃`
}
},
xAxis: { type: 'time' },
yAxis: {
type: 'value',
min: 0,
max: 10,
splitLine: { lineStyle: { type: 'dashed' } }
},
series: [{
data: [],
type: 'line',
markArea: {
silent: true,
itemStyle: {
color: 'rgba(255, 173, 177, 0.4)'
},
data: [[{ yAxis: 0 }, { yAxis: 2 }], [{ yAxis: 8 }, { yAxis: 10 }]]
}
}]
}
chart.setOption(option)
return chart
}
通过APScheduler实现多级效期检查:
python复制from apscheduler.schedulers.background import BackgroundScheduler
def init_scheduler():
scheduler = BackgroundScheduler()
# 每日凌晨检查效期
@scheduler.scheduled_job('cron', hour=0)
def check_expiry():
now = datetime.now()
# 即将3个月内过期
soon = now + timedelta(days=90)
soon_expires = MedicineBatch.query.filter(
MedicineBatch.expiry_date <= soon,
MedicineBatch.expiry_date > now
).all()
notify_soon_expire(soon_expires)
# 已经过期
expired = MedicineBatch.query.filter(
MedicineBatch.expiry_date <= now
).all()
lock_expired(expired)
scheduler.start()
所有关键操作均记录不可篡改的审计日志:
python复制class OperationLog(db.Model):
__tablename__ = 'operation_logs'
id = db.Column(db.Integer, primary_key=True)
operator_id = db.Column(db.Integer, db.ForeignKey('users.id'))
operation_type = db.Column(db.String(50)) # 'CREATE_MEDICINE'等
target_id = db.Column(db.Integer) # 操作目标ID
parameters = db.Column(db.JSON) # 操作参数快照
ip_address = db.Column(db.String(45))
user_agent = db.Column(db.Text)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
operator = db.relationship('User')
针对医药行业信息系统安全等级保护要求,我们实现了以下关键措施:
身份鉴别:
访问控制:
安全审计:
数据完整性:
使用Docker Compose编排服务:
yaml复制version: '3.8'
services:
web:
build: .
ports:
- "5000:5000"
environment:
- FLASK_ENV=production
- DATABASE_URL=postgresql://user:pass@db:5432/warehouse
depends_on:
- db
- redis
db:
image: postgres:13
volumes:
- pg_data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=securepassword
redis:
image: redis:6
volumes:
- redis_data:/data
volumes:
pg_data:
redis_data:
医药系统需要保证7×24小时可用,我们采用以下策略:
在实际开发医药仓储系统时,我们总结了以下关键经验:
批次管理陷阱:
温控数据要点:
性能优化技巧:
合规性检查:
这个医药仓储管理系统经过三个月的迭代开发,目前已在某三甲医院药房稳定运行。系统每天处理超过2000笔出入库交易,平均库存准确率达到99.97%。后续计划增加AI驱动的智能补货预测和药品不良反应关联分析模块