1. 项目背景与核心需求
航空票务管理系统是现代民航业的核心业务支撑平台,它需要处理实时航班数据、动态票价计算、多终端用户交互等高并发场景。传统售票系统往往采用C/S架构或纯后端渲染,存在响应速度慢、用户体验差、扩展性受限等问题。
这个基于Python和Vue的解决方案,本质上要解决三个核心矛盾:
- 实时性需求:航班余票数据需要秒级更新
- 复杂性管理:票价计算涉及舱位折扣、燃油附加费等多维度因素
- 用户体验:需要支持PC端、移动端等多设备适配
我选择的技术栈组合(Django+DRF+Vue)在实践中表现出独特优势:
- Django的ORM能优雅处理航空领域复杂的票务关系模型
- DRF提供的API框架完美支持前后端分离架构
- Vue的响应式特性特别适合实时票务状态展示
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计
2.1 整体技术架构
采用分层架构设计,各层技术选型如下:
| 层级 | 技术方案 | 选型理由 |
|---|---|---|
| 数据持久层 | PostgreSQL + Redis | PG的事务隔离级别适合票务系统,Redis处理高并发查询 |
| 后端服务层 | Django 4.2 + DRF | Django Admin快速构建管理后台,DRF的序列化器完美处理航班-机票-订单关系 |
| 前端展示层 | Vue3 + Element Plus | Composition API更适合复杂票务状态管理,Element提供专业级UI组件 |
| 实时通信 | WebSocket | 解决余票实时更新问题 |
| 部署环境 | Docker + Nginx | 容器化解决环境依赖,Nginx处理静态资源和负载均衡 |
2.2 数据库设计要点
机票系统的ER模型有几个关键设计决策:
-
航班表(flight)与机票表(ticket)分离
- 航班表存储固定信息(航班号、机型、航线等)
- 机票表动态生成(价格、状态、座位号等)
- 通过flight_id关联,1:N关系
-
价格动态计算字段
python复制class Ticket(models.Model):
base_price = models.DecimalField(max_digits=10, decimal_places=2)
fuel_surcharge = models.DecimalField(max_digits=6, decimal_places=2)
tax = models.DecimalField(max_digits=6, decimal_places=2)
@property
def final_price(self):
return self.base_price + self.fuel_surcharge + self.tax
- 订单状态机设计
使用Django FSM实现订单状态流转:
python复制from django_fsm import FSMField, transition
class Order(models.Model):
status = FSMField(default='created')
@transition(field=status, source='created', target='paid')
def pay(self):
pass
@transition(field=status, source='*', target='canceled')
def cancel(self):
pass
3. 核心功能实现
3.1 余票实时更新方案
解决高并发下的超卖问题,我们采用多级缓存策略:
- Redis库存计数器
python复制# 航班余票初始化
r = redis.StrictRedis()
r.set(f'flight:{flight_id}:economy', 200)
r.set(f'flight:{flight_id}:business', 50)
# 扣减库存Lua脚本
LUA_DEDUCT = """
local key = KEYS[1]
local change = tonumber(ARGV[1])
local current = tonumber(redis.call('GET', key))
if current >= change then
return redis.call('DECRBY', key, change)
else
return -1
end
"""
- WebSocket推送机制
前端建立长连接接收余票变更:
javascript复制// Vue组件内
const socket = new WebSocket('wss://yourdomain.com/ws/flights/')
socket.onmessage = (event) => {
const data = JSON.parse(event.data)
this.remainingSeats = data.remaining
}
3.2 动态票价计算
票价计算需要考虑:
- 基础票价(距离×单价)
- 舱位系数(经济舱1.0,商务舱2.5)
- 动态折扣(提前购票折扣)
- 燃油附加费(按航距阶梯计算)
实现方案:
python复制class PricingService:
@staticmethod
def calculate_price(flight, seat_class, days_before):
base = flight.distance * 0.12 # 每公里单价
class_factor = 2.5 if seat_class == 'business' else 1.0
discount = max(0.7, 1 - days_before/30*0.2) # 提前购票折扣
fuel_fee = min(500, flight.distance * 0.02) # 燃油费封顶500
return (base * class_factor * discount) + fuel_fee
4. 前端关键技术实现
4.1 航班查询组件
使用Vue3的Composition API封装查询逻辑:
javascript复制// useFlightSearch.js
export default function useFlightSearch() {
const flights = ref([])
const loading = ref(false)
const search = async (params) => {
loading.value = true
try {
const { data } = await axios.get('/api/flights/', { params })
flights.value = data
} finally {
loading.value = false
}
}
return { flights, loading, search }
}
4.2 座位选择可视化
基于SVG实现机舱座位图:
vue复制<template>
<svg :viewBox="`0 0 ${width} ${height}`">
<g v-for="seat in seats" :key="seat.id">
<rect
:x="seat.x"
:y="seat.y"
width="30"
height="30"
:class="{ 'occupied': !seat.available }"
@click="selectSeat(seat)"
/>
<text :x="seat.x+15" :y="seat.y+20">{{ seat.number }}</text>
</g>
</svg>
</template>
5. 部署与性能优化
5.1 Docker化部署
典型docker-compose.yml配置:
yaml复制version: '3.8'
services:
db:
image: postgres:14
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- pg_data:/var/lib/postgresql/data
redis:
image: redis:6
web:
build: .
command: gunicorn --workers 4 core.wsgi
ports:
- "8000:8000"
depends_on:
- db
- redis
volumes:
pg_data:
5.2 高并发优化措施
-
数据库层面
- 为查询频率高的字段建立索引:
python复制class Flight(models.Model): departure_time = models.DateTimeField(db_index=True) route = models.ForeignKey(Route, on_delete=models.CASCADE, db_index=True) -
缓存策略
- 使用Django的cache_page装饰器缓存静态航班信息
python复制@cache_page(60 * 15) def flight_list(request): # 航班列表查询 -
异步任务
耗时的出票操作交给Celery:python复制@shared_task(bind=True) def process_ticket(self, order_id): try: order = Order.objects.get(pk=order_id) # 生成电子票PDF等操作 except Exception as e: self.retry(exc=e, countdown=60)
6. 安全防护方案
6.1 防爬虫措施
- 关键API添加速率限制:
python复制REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
'search': '10/minute',
'purchase': '3/minute'
}
}
- 验证码集成:
vue复制<template>
<vue-recaptcha
sitekey="your_site_key"
@verify="onVerify"
/>
</template>
6.2 支付安全
- 敏感操作审计日志:
python复制class Order(models.Model):
def save(self, *args, **kwargs):
if self.pk: # 更新操作
AuditLog.objects.create(
user=current_user,
action=f'UPDATE_ORDER_{self.status}',
content=str(self.changes)
)
super().save(*args, **kwargs)
- 支付结果验证:
python复制def verify_payment(order_no):
"""调用支付网关验证交易真实性"""
resp = requests.post(PAYMENT_GATEWAY, data={
'order_no': order_no,
'sign': generate_sign(order_no)
})
return resp.json()['status'] == 'SUCCESS'
7. 项目扩展方向
7.1 多语言支持
- 后端i18n配置:
python复制# settings.py
LANGUAGES = [
('en', _('English')),
('zh-hans', _('Simplified Chinese')),
]
MIDDLEWARE += ['django.middleware.locale.LocaleMiddleware']
- 前端语言切换:
javascript复制// i18n.js
const messages = {
en: {
departure: 'Departure'
},
zh: {
departure: '出发'
}
}
const i18n = createI18n({
locale: localStorage.getItem('lang') || 'en',
messages
})
7.2 数据分析模块
- 使用Pandas生成销售报表:
python复制def generate_sales_report(start_date, end_date):
queryset = Order.objects.filter(
created_at__range=(start_date, end_date)
).values('flight__route', 'seat_class')
df = pd.DataFrame.from_records(queryset)
return df.pivot_table(
index='flight__route',
columns='seat_class',
aggfunc=len,
fill_value=0
)
- 可视化展示:
vue复制<template>
<v-chart :option="chartOptions" />
</template>
<script setup>
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { PieChart } from 'echarts/charts'
import { TitleComponent, TooltipComponent } from 'echarts/components'
use([CanvasRenderer, PieChart, TitleComponent, TooltipComponent])
const chartOptions = {
series: [{
type: 'pie',
data: props.chartData
}]
}
</script>
8. 开发经验与避坑指南
-
时区处理陷阱
- 所有时间字段必须明确时区:
python复制# settings.py USE_TZ = True TIME_ZONE = 'Asia/Shanghai' # 模型定义 departure_time = models.DateTimeField() # 自动转为UTC存储 -
Vue响应式丢失问题
当从API获取嵌套数据时,需要手动保持响应式:javascript复制// 错误做法 this.flight = response.data // 正确做法 import { reactive } from 'vue' this.flight = reactive(response.data) -
数据库连接池配置
高并发下必须调整连接池:python复制# settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'OPTIONS': { 'connect_timeout': 5, 'options': '-c statement_timeout=3000ms' }, 'CONN_MAX_AGE': 300, # 连接复用时间 'POOL': { # 使用django-db-geventpool 'max_conn': 50, 'timeout': 30 } } } -
前端性能优化
- 路由懒加载:
javascript复制const FlightList = () => import('./views/FlightList.vue')- 关键API预加载:
javascript复制// 在首页预加载可能需要的资源 onMounted(() => { import('./api/ticketService') })
这个项目完整实现了从航班管理、票务销售到订单处理的完整闭环。在实际部署中,建议采用蓝绿部署策略保证服务连续性,同时建立完善的监控体系跟踪关键指标(如订单转化率、API响应时间等)。对于需要进一步扩展的团队,可以考虑加入会员积分系统、行李托运管理等增值模块。
