1. 项目背景与核心需求
健康体检预约系统是医疗机构数字化转型的重要环节。传统体检预约存在排队时间长、信息不对称、资源分配不均等问题。通过微信小程序+Python后端的组合方案,可以实现以下核心价值:
- 用户侧:随时随地查看体检套餐、预约时间、支付费用、查看报告
- 机构侧:动态管理预约资源、智能排期、数据统计分析
- 技术侧:uniapp跨端开发降低成本、Python快速构建业务逻辑
我去年为某三甲医院开发同类系统时,上线后预约效率提升300%,人工窗口压力减少65%。下面分享具体实现方案中的关键技术点。
2. 技术架构设计
2.1 整体架构分层
code复制客户端层(uniapp)
├─ 微信小程序
├─ H5网页版
└─ App端(可选)
服务层(Python)
├─ API接口(Flask/Django)
├─ 业务逻辑
└─ 数据缓存
数据层
├─ MySQL(结构化数据)
├─ Redis(高并发缓存)
└─ 文件存储(报告PDF)
2.2 技术选型依据
uniapp选择理由:
- 一套代码多端发布(微信/支付宝/百度小程序)
- 完善的组件库(uViewUI)加速开发
- 原生渲染性能接近原生小程序
Python后端优势:
- Flask轻量级适合快速迭代
- Pandas方便处理体检报告数据
- Celery异步处理报告生成等耗时操作
3. 核心功能实现
3.1 预约流程设计
mermaid复制graph TD
A[选择体检套餐] --> B[选择日期时段]
B --> C[填写个人信息]
C --> D[在线支付]
D --> E[生成预约码]
E --> F[到场签到]
关键代码示例(Python部分):
python复制@app.route('/api/appointment', methods=['POST'])
def create_appointment():
data = request.get_json()
# 校验时段库存
time_slot = db.session.query(TimeSlot).filter_by(
date=data['date'],
period=data['period']
).first()
if time_slot.remaining <= 0:
return jsonify({'code': 400, 'message': '该时段已约满'})
# 创建预约记录
new_appoint = Appointment(
user_id=data['user_id'],
package_id=data['package_id'],
time_slot_id=time_slot.id,
status=0 # 待支付
)
db.session.add(new_appoint)
db.session.commit()
# 减少库存
time_slot.remaining -= 1
db.session.commit()
return jsonify({
'code': 200,
'data': {'appoint_id': new_appoint.id}
})
3.2 微信支付集成
uniapp端关键配置:
javascript复制// 支付方法封装
const pay = (orderInfo) => {
uni.requestPayment({
provider: 'wxpay',
orderInfo: JSON.stringify(orderInfo),
success: (res) => {
console.log('支付成功', res)
// 更新订单状态
updateOrderStatus(orderInfo.out_trade_no, 1)
},
fail: (err) => {
console.error('支付失败', err)
}
})
}
Python后端签名生成:
python复制def create_wxpay_params(order_id, total_fee):
nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
params = {
'appid': wx_appid,
'mch_id': wx_mchid,
'nonce_str': nonce_str,
'body': '体检套餐预约',
'out_trade_no': order_id,
'total_fee': total_fee,
'spbill_create_ip': request.remote_addr,
'notify_url': wx_notify_url,
'trade_type': 'JSAPI',
'openid': get_openid()
}
# 生成签名
stringA = '&'.join([f"{k}={v}" for k,v in sorted(params.items())])
stringSignTemp = f"{stringA}&key={wx_key}"
sign = hashlib.md5(stringSignTemp.encode()).hexdigest().upper()
params['sign'] = sign
return params
4. 性能优化实践
4.1 高并发时段处理
问题现象:
- 早8点放号时段出现500错误
- 数据库CPU飙升到90%
解决方案:
- Redis库存预扣减
python复制def reserve_time_slot(date, period):
key = f"timeslot:{date}:{period}"
with redis.pipeline() as pipe:
while True:
try:
pipe.watch(key)
remaining = int(pipe.get(key) or 0)
if remaining <= 0:
pipe.unwatch()
return False
pipe.multi()
pipe.decr(key)
if pipe.execute()[0] >= 0:
return True
except WatchError:
continue
- 数据库最终一致性
python复制@app.task(bind=True)
def sync_inventory_to_db(self):
slots = redis.keys("timeslot:*")
for key in slots:
date, period = key.split(":")[1:3]
count = redis.get(key)
db.update_time_slot(date, period, count)
4.2 大文件上传优化
体检报告PDF平均8-15MB,采用分片上传方案:
uniapp端实现:
javascript复制const uploadFile = (filePath) => {
const uploadTask = uni.uploadFile({
url: 'https://api.example.com/upload',
filePath: filePath,
name: 'file',
formData: {
chunkIndex: 0,
totalChunks: Math.ceil(file.size / CHUNK_SIZE),
fileHash: file.hash
},
success: (res) => {
console.log('上传成功', res.data)
}
})
uploadTask.onProgressUpdate((res) => {
console.log('上传进度', res.progress)
})
}
Python后端合并逻辑:
python复制@app.route('/merge_files', methods=['POST'])
def merge_files():
file_hash = request.form['file_hash']
temp_dir = os.path.join(UPLOAD_FOLDER, file_hash)
# 按照分片序号排序后合并
chunks = sorted(os.listdir(temp_dir), key=lambda x: int(x.split('-')[1]))
with open(f'reports/{file_hash}.pdf', 'wb') as f:
for chunk in chunks:
with open(os.path.join(temp_dir, chunk), 'rb') as cf:
f.write(cf.read())
# 清理临时文件
shutil.rmtree(temp_dir)
return jsonify({'code': 200})
5. 安全防护措施
5.1 敏感数据保护
实施要点:
- 体检报告文件存储加密
- 数据库字段级加密(如身份证号)
- 传输层HTTPS+数据签名
Python加密示例:
python复制from cryptography.fernet import Fernet
# 生成密钥
key = Fernet.generate_key()
cipher_suite = Fernet(key)
# 加密数据
encrypted_text = cipher_suite.encrypt(b"Sensitive data")
decrypted_text = cipher_suite.decrypt(encrypted_text)
5.2 防刷单机制
组合策略:
- 手机号验证码校验
- IP时段限流(Nginx配置)
nginx复制limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
location /api {
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://backend;
}
- 行为特征分析(Python实现)
python复制def check_risk(request):
# 同IP高频请求检测
ip = request.remote_addr
count = redis.incr(f'req_count:{ip}')
if count > 100:
raise RiskException('访问过于频繁')
# 设备指纹验证
device_id = request.headers.get('X-Device-ID')
if not validate_device(device_id):
raise RiskException('设备验证失败')
6. 部署与监控
6.1 容器化部署
Docker-compose配置示例:
yaml复制version: '3'
services:
web:
build: .
ports:
- "5000:5000"
environment:
- REDIS_HOST=redis
depends_on:
- redis
redis:
image: redis:alpine
volumes:
- redis_data:/data
volumes:
redis_data:
6.2 性能监控方案
监控指标:
- 接口响应时间(P99 < 500ms)
- 数据库查询耗时
- 小程序页面加载速度
Python Prometheus配置:
python复制from prometheus_client import start_http_server, Summary
REQUEST_TIME = Summary('request_processing_seconds', 'Time spent processing request')
@REQUEST_TIME.time()
def process_request(t):
time.sleep(t)
if __name__ == '__main__':
start_http_server(8000)
while True:
process_request(random.random())
7. 典型问题排查
7.1 微信登录失败
常见原因:
- 小程序AppID配置错误
- 服务器域名未备案
- session_key过期
解决方案:
python复制def wx_login(code):
url = f"https://api.weixin.qq.com/sns/jscode2session?appid={appid}&secret={secret}&js_code={code}&grant_type=authorization_code"
resp = requests.get(url)
data = resp.json()
if 'errcode' in data:
if data['errcode'] == 40029:
raise Exception('code无效')
elif data['errcode'] == 45011:
raise Exception('API调用太频繁')
else:
raise Exception(f"微信接口错误: {data['errmsg']}")
return data['openid'], data['session_key']
7.2 支付回调处理
注意事项:
- 验证签名防止伪造请求
- 处理幂等性问题
- 日志记录完整交易流水
Python实现示例:
python复制@app.route('/wxpay/notify', methods=['POST'])
def wxpay_notify():
xml_data = request.data
data = xmltodict.parse(xml_data)['xml']
# 验证签名
sign = data.pop('sign')
calc_sign = generate_sign(data)
if sign != calc_sign:
return wxpay_reply('FAIL', '签名失败')
# 处理业务逻辑
order = get_order(data['out_trade_no'])
if order.status == 0:
update_order_status(order.id, 1)
# 触发后续业务...
return wxpay_reply('SUCCESS', 'OK')
8. 扩展优化方向
8.1 智能推荐升级
可实施策略:
- 基于用户历史数据推荐套餐
- 结合年龄性别等属性过滤
- 实时库存动态调整推荐
Python推荐算法示例:
python复制def recommend_packages(user):
base = Package.query.filter_by(is_active=True).all()
# 规则过滤
if user.age > 40:
base = [p for p in base if '中老年' in p.tags]
# 协同过滤
cf_scores = get_cf_recommendations(user.id)
# 混合排序
recommendations = sorted(
base,
key=lambda x: (
-x.popularity,
-cf_scores.get(x.id, 0),
x.price
)
)
return recommendations[:5]
8.2 体检报告解读
技术实现:
- OCR识别报告图片
- NLP提取关键指标
- 生成可视化趋势图
Python实现片段:
python复制def analyze_report(image_path):
# 文字识别
text = pytesseract.image_to_string(Image.open(image_path), lang='chi_sim')
# 关键信息提取
patterns = {
'blood_pressure': r'血压\s*(\d+)/(\d+)',
'blood_sugar': r'血糖\s*(\d+\.?\d*)'
}
results = {}
for name, pattern in patterns.items():
match = re.search(pattern, text)
if match:
results[name] = match.groups()
return results
