1. 项目概述
电影院售票管理系统是现代影院运营的核心支撑平台,它需要同时处理票务销售、场次管理、会员服务等多维度业务需求。基于Django+Vue3的技术栈组合,我们构建了一套高性能、易维护的全栈解决方案。这套系统不仅满足了基础售票功能,还通过前后端分离架构实现了响应式用户界面与稳健后台服务的完美结合。
在传统影院管理中,手工排片、纸质票务等方式效率低下且容易出错。我们采用Python+Django构建RESTful API服务层,利用其强大的ORM能力和admin后台,快速实现了放映计划、座位库存、订单处理等核心业务逻辑。前端选用Vue3的组合式API开发模式,配合Element Plus组件库,打造了流畅的选座购票体验。
2. 技术架构设计
2.1 整体架构解析
系统采用经典的前后端分离架构:
- 后端服务:Django 4.x + Django REST framework
- 前端框架:Vue3 + TypeScript + Pinia状态管理
- 数据库:PostgreSQL 14(支持JSON字段存储座位图)
- 辅助工具:Celery异步任务队列(处理订票超时释放)
这种架构的优势在于:
- 前后端可以并行开发,通过Swagger文档保持接口同步
- Vue3的响应式特性特别适合实时更新座位状态
- Django Admin提供开箱即用的运营管理后台
2.2 数据库设计要点
核心表结构设计考虑了影院业务的特殊需求:
python复制class Screening(models.Model):
movie = models.ForeignKey(Movie, on_delete=models.PROTECT)
auditorium = models.ForeignKey(Auditorium, on_delete=models.PROTECT)
start_time = models.DateTimeField()
end_time = models.DateTimeField()
seat_map = models.JSONField() # 存储座位状态矩阵
class Order(models.Model):
ORDER_STATUS = (
('P', '待支付'),
('S', '已售出'),
('E', '已过期')
)
user = models.ForeignKey(User, on_delete=models.CASCADE)
screening = models.ForeignKey(Screening, on_delete=models.PROTECT)
seats = models.JSONField() # 如 ["A1", "B5"]
total_price = models.DecimalField(max_digits=8, decimal_places=2)
status = models.CharField(max_length=1, choices=ORDER_STATUS)
created_at = models.DateTimeField(auto_now_add=True)
关键设计决策:使用JSONField存储座位状态而非关联表,大幅减少高频查询时的数据库压力。实测在100并发请求下,查询性能提升3倍以上。
3. 核心功能实现
3.1 实时选座功能
前端采用Canvas绘制交互式座位图,关键技术点包括:
- 使用Vue3的watchEffect实时响应座位状态变化
- 通过WebSocket与后端保持长连接,确保座位状态同步
- 防抖处理频繁的座位选择事件(300ms间隔)
后端关键API实现:
python复制@api_view(['POST'])
@transaction.atomic
def reserve_seats(request):
screening = get_object_or_404(Screening, pk=request.data['screening_id'])
seats = request.data['seats']
# 检查座位是否可用
for seat in seats:
if screening.seat_map[seat['row']][seat['col']] != 'available':
raise ValidationError(f"座位 {seat} 已被预定")
# 临时锁定座位
for seat in seats:
screening.seat_map[seat['row']][seat['col']] = 'reserved'
screening.save()
# 创建预订单
order = Order.objects.create(...)
# 设置15分钟过期任务
release_seats.apply_async(args=[order.id], countdown=15*60)
return Response(...)
3.2 支付流程设计
支付流程采用状态机模式管理订单生命周期:
- 待支付(15分钟倒计时)
- 支付中(防止重复提交)
- 已支付(生成电子票)
- 已取消/已过期(释放座位)
关键状态转换代码:
python复制def process_payment(order_id, payment_method):
with transaction.atomic():
order = Order.objects.select_for_update().get(pk=order_id)
if order.status != 'P':
raise InvalidTransitionError()
# 调用支付网关
result = PaymentGateway.charge(order.total_price, payment_method)
if result.success:
order.status = 'S'
order.save()
generate_ticket.delay(order.id)
else:
order.status = 'E'
order.save()
release_seats.delay(order.id)
4. 性能优化实践
4.1 高并发场景处理
针对热门场次的抢购场景,我们实施了多级缓存策略:
- Redis缓存热门场次的座位状态(TTL 5秒)
- 数据库层面使用select_for_update进行行级锁
- 前端实施排队机制,避免突发流量冲击
压力测试结果(JMeter模拟):
| 并发用户数 | 平均响应时间 | 错误率 |
|---|---|---|
| 100 | 230ms | 0% |
| 500 | 420ms | 0.2% |
| 1000 | 780ms | 1.5% |
4.2 数据库查询优化
通过Django ORM的优化技巧提升性能:
- 使用select_related/prefetch_related减少查询次数
- 对筛查列表添加conditional缓存
- 建立复合索引加速场次查询
优化前后的查询对比:
python复制# 优化前(产生N+1查询)
screenings = Screening.objects.all()
for s in screenings:
print(s.movie.title) # 每次循环都查询movie表
# 优化后
screenings = Screening.objects.select_related('movie').all()
5. 安全防护措施
5.1 防刷票机制
- 用户行为分析:限制同一IP/账号的购票频率
- 验证码策略:在可疑操作时触发图形验证
- 业务规则限制:新注册账号首日最多购票3张
实现代码示例:
python复制def check_anti_spam(request):
client_ip = request.META.get('HTTP_X_FORWARDED_FOR') or request.META.get('REMOTE_ADDR')
today = timezone.now().date()
# 检查IP当日订单数
ip_orders = Order.objects.filter(
created_at__date=today,
user_ip=client_ip
).count()
if ip_orders > 10:
raise PermissionDenied("操作过于频繁")
# 检查用户当日订单数
if request.user.is_authenticated:
user_orders = Order.objects.filter(
user=request.user,
created_at__date=today
).count()
if request.user.date_joined.date() == today and user_orders >= 3:
raise PermissionDenied("新用户首日限购3张")
5.2 敏感数据保护
- 支付信息使用PCI DSS兼容的第三方服务处理
- 用户密码采用PBKDF2算法加密存储
- 日志系统自动脱敏手机号、身份证等字段
6. 部署与监控
6.1 容器化部署方案
使用Docker Compose编排服务:
yaml复制version: '3.8'
services:
web:
build: ./backend
command: gunicorn cinema.wsgi:application --bind 0.0.0.0:8000
volumes:
- static:/app/static
environment:
- DATABASE_URL=postgres://user:pass@db:5432/cinema
depends_on:
- db
- redis
frontend:
build: ./frontend
ports:
- "8080:80"
db:
image: postgres:14
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:6
6.2 监控指标配置
关键监控项包括:
- 订单创建成功率(>99.5%)
- 支付平均处理时间(<2秒)
- API错误率(<0.1%)
- 座位缓存命中率(>90%)
使用Prometheus+Grafana搭建监控看板,设置以下告警规则:
- 500错误率连续5分钟>1%
- 数据库连接数>最大值的80%
- 订单取消率突然上升(可能支付系统故障)
7. 项目演进方向
当前系统已经支持基础售票功能,后续可以扩展:
- 会员积分系统(消费累计/兑换)
- 动态定价策略(根据上座率调整价格)
- 无人检票闸机对接(QR码扫码入场)
- 影片推荐引擎(基于用户历史行为)
在开发过程中我们发现,Vue3的Composition API特别适合处理复杂的选座状态逻辑。通过将座位选择、价格计算、优惠券应用等逻辑拆分为独立composable函数,代码可维护性得到显著提升。例如:
javascript复制// useSeatSelection.js
export function useSeatSelection(screeningId) {
const selectedSeats = ref([])
const totalPrice = computed(() => {
return selectedSeats.value.reduce((sum, seat) => sum + seat.price, 0)
})
function toggleSeat(seat) {
const index = selectedSeats.value.findIndex(s => s.id === seat.id)
if (index >= 0) {
selectedSeats.value.splice(index, 1)
} else {
if (selectedSeats.value.length < 6) { // 最多选6个座位
selectedSeats.value.push(seat)
}
}
}
return { selectedSeats, totalPrice, toggleSeat }
}
这种模块化开发方式使得后续新增IMAX座位、情侣座等特殊座位类型时,只需扩展seat对象结构而不需要重写核心逻辑。