1. 项目概述:基于Flask与微信小程序的家电维修系统
去年帮朋友改造他的家电维修作坊时,我设计了一套数字化管理系统。传统接单方式依赖电话和纸质记录,经常出现漏单、派工混乱的问题。这套系统上线后,维修订单处理效率提升了60%,客户投诉率下降了45%。核心架构采用微信小程序作为用户入口,Python Flask构建后端服务,MySQL存储业务数据。这种技术组合特别适合中小型维修团队,既能快速落地又具备良好的扩展性。
系统主要解决三个痛点:一是客户报修流程标准化,通过小程序表单强制收集完整故障信息;二是维修过程透明化,客户可实时查看工程师位置和服务进度;三是财务对账自动化,微信支付直接与订单系统打通。对于5-20人的维修团队,这套系统可以在两周内完成部署,硬件成本不超过3000元。
2. 技术架构设计解析
2.1 前后端分离架构
采用经典的前后端分离模式,微信小程序与Flask后端通过RESTful API交互。这种架构的优势在于:
- 小程序端专注UI交互和本地缓存管理
- 后端服务无状态化,便于横向扩展
- 接口定义清晰,后续可兼容其他前端(如H5、APP)
实际部署时发现,微信小程序对HTTPS有强制要求。我们在Nginx配置中添加了SSL证书,并通过HTTP/2协议提升传输效率。测试数据显示,启用HTTP/2后API响应时间平均降低23%。
2.2 数据库选型策略
根据团队规模提供两种方案:
- 小型团队(日单量<100):使用SQLite
- 零配置,单文件管理
- 适合初创团队快速验证模式
- 内置在Python标准库中,无需额外安装
- 中型团队(日单量100-500):使用MySQL
- 支持并发读写
- 完善的用户权限管理
- 备份恢复机制更健全
我们最终选择了MySQL 8.0,主要看中其JSON字段支持。维修订单的extend_info字段存储动态扩展属性(如空调维修需要的匹数、制冷剂类型),使用JSON格式比传统的关系型设计更灵活。
3. 核心功能实现细节
3.1 微信登录集成
小程序端调用wx.login获取临时code,传给Flask后端兑换openid。这里有个关键优化点:不要在每次请求都兑换code,而是将session_key和openid缓存在服务端。我们使用Redis存储会话信息,设置15天过期时间。
python复制# 改进后的登录处理
def wechat_auth(code):
cache_key = f"wx_session:{code}"
cached = redis.get(cache_key)
if cached:
return json.loads(cached)
resp = requests.get(f"https://api.weixin.qq.com/sns/jscode2session?appid={APPID}&secret={SECRET}&js_code={code}")
data = resp.json()
if 'errcode' in data:
raise AuthError(data['errmsg'])
redis.setex(cache_key, 3600*24*15, json.dumps(data))
return data
3.2 订单状态机设计
维修订单涉及多状态转换,我们采用状态模式实现:
mermaid复制stateDiagram
[*] --> 待接单
待接单 --> 已派单: assign_technician
已派单 --> 维修中: technician_accept
维修中 --> 待支付: complete_repair
待支付 --> 已完成: confirm_payment
待接单 --> 已取消: user_cancel
维修中 --> 已取消: user_cancel
对应Flask中的实现:
python复制class RepairOrder:
def __init__(self):
self.state = PendingState()
def change_state(self, new_state):
self.state = new_state
def assign_tech(self, tech_id):
self.state.assign(self, tech_id)
class PendingState:
def assign(self, order, tech_id):
if Technician.query.get(tech_id).available:
order.change_state(AssignedState())
db.session.commit()
4. 安全防护方案
4.1 敏感数据加密
用户手机号使用AES-256-GCM模式加密,相比传统的CBC模式能同时保证机密性和完整性。加密密钥通过AWS KMS管理,实现自动轮换。
python复制from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
def encrypt_phone(phone):
key = get_kms_key() # 从KMS获取当前激活的密钥
nonce = os.urandom(12)
cipher = AESGCM(key)
ct = cipher.encrypt(nonce, phone.encode(), None)
return nonce + ct
4.2 接口防刷策略
针对/api/submit_order接口实施三层防护:
- 小程序端防重复点击:提交后按钮禁用5秒
- 服务端频率限制:相同openid 10分钟内不超过3次
- 业务规则校验:同一设备当天最多创建5个订单
使用Redis实现滑动窗口计数器:
python复制def check_rate_limit(openid):
key = f"rate_limit:{openid}"
now = int(time.time())
pipe = redis.pipeline()
pipe.zadd(key, {now: now})
pipe.zremrangebyscore(key, 0, now-600) # 清理10分钟前的记录
pipe.zcard(key)
_, _, count = pipe.execute()
return count <= 3
5. 性能优化实践
5.1 数据库查询优化
通过EXPLAIN分析发现订单列表查询较慢,优化措施包括:
- 为status字段添加索引
- 使用JOIN替代N+1查询
- 对大文本字段(如故障描述)单独分表
优化前后的查询对比:
sql复制-- 优化前
SELECT * FROM repair_orders WHERE user_id=? ORDER BY create_time DESC
-- 优化后
SELECT o.id, o.status, t.name as tech_name
FROM repair_orders o LEFT JOIN technicians t ON o.tech_id=t.id
WHERE o.user_id=?
ORDER BY o.create_time DESC
LIMIT 20
5.2 缓存策略设计
采用多级缓存架构:
- 热点数据:Redis缓存订单最新状态,TTL 5分钟
- 静态资源:CDN加速小程序图片和文档
- 本地缓存:小程序端缓存历史订单24小时
缓存更新采用Write-Through模式:
python复制def update_order_status(order_id, status):
order = RepairOrder.query.get(order_id)
order.status = status
db.session.commit()
# 同步更新缓存
redis.setex(f"order:{order_id}:status", 300, status)
6. 部署与监控方案
6.1 容器化部署
使用Docker Compose编排服务:
yaml复制version: '3'
services:
web:
build: .
ports:
- "8000:8000"
depends_on:
- redis
- mysql
environment:
- FLASK_ENV=production
deploy:
resources:
limits:
cpus: '1'
memory: 1G
redis:
image: redis:6-alpine
volumes:
- redis_data:/data
mysql:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=yourpassword
volumes:
- mysql_data:/var/lib/mysql
volumes:
redis_data:
mysql_data:
6.2 监控指标配置
Prometheus监控关键指标:
- API响应时间(按路由统计)
- MySQL连接池使用率
- Redis内存占用
- 订单状态变更速率
Grafana仪表盘示例配置:
json复制{
"panels": [{
"title": "API响应时间",
"type": "graph",
"targets": [{
"expr": "histogram_quantile(0.95, sum(rate(flask_http_request_duration_seconds_bucket[5m])) by (le, path))",
"legendFormat": "{{path}}"
}]
}]
}
7. 踩坑经验总结
7.1 微信支付回调处理
初期遇到的典型问题:
- 回调验签失败:因为漏传了微信证书
- 重复通知:未实现幂等处理
- 网络超时:未设置合理的timeout
最终解决方案:
python复制@app.route('/pay/notify', methods=['POST'])
def pay_notify():
# 1. 验证签名
try:
result = WXPay.notify_verify(request.data)
except Exception as e:
current_app.logger.error(f"验签失败: {e}")
return "<xml><return_code><![CDATA[FAIL]]></return_code></xml>"
# 2. 幂等检查
if Payment.query.filter_by(transaction_id=result['transaction_id']).first():
return "<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>"
# 3. 业务处理
try:
with db.session.begin():
payment = Payment(
order_id=result['out_trade_no'],
amount=int(result['total_fee'])/100,
status='paid'
)
db.session.add(payment)
order = RepairOrder.query.get(result['out_trade_no'])
order.status = 'paid'
except Exception as e:
current_app.logger.error(f"处理支付失败: {e}")
return "<xml><return_code><![CDATA[FAIL]]></return_code></xml>"
return "<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>"
7.2 地理位置服务优化
维修工位置更新策略调整:
- 原方案:小程序每10秒上报GPS
- 问题:耗电量高,服务端压力大
- 优化方案:
- 接单后改为30秒间隔
- 移动距离超过50米才上报
- 使用高德地图API进行坐标纠偏
实测数据:优化后客户端电量消耗降低40%,日均API调用量减少65%。