完成大作业服务端代码,新建管理端,管理端不可用

This commit is contained in:
2024-06-14 14:53:50 +08:00
parent ad767a806b
commit cfbaf585a7
80 changed files with 3563 additions and 128 deletions

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,92 @@
from flask import render_template, request, redirect, url_for, g, flash, session
from .config import db
import pymysql
from datetime import datetime
def book():
flight_id = request.args.get('flight_id')
if request.method == 'GET':
if not g.user:
return redirect(url_for("login"))
conn = pymysql.connect(**db)
cursor = conn.cursor(pymysql.cursors.DictCursor)
flight_sql = """
SELECT f.*, d.Name as Departure_airport_name, a.Name as Arrival_airport_name
FROM Flights f
JOIN Airports d ON f.Departure_airport = d.ID
JOIN Airports a ON f.Arrival_airport = a.ID
WHERE f.ID = %s;
"""
cursor.execute(flight_sql, (flight_id,))
flight = cursor.fetchone()
cursor.close()
conn.close()
return render_template('book.html', flight=flight, username=g.name)
if request.method == 'POST':
passengers = []
passenger_keys = ['card_code', 'name', 'phone_number', 'seat_class']
for i in range(len(request.form) // len(passenger_keys)):
passenger = {}
for key in passenger_keys:
passenger[key] = request.form.get(f'passengers[{i}][{key}]')
passengers.append(passenger)
conn = pymysql.connect(**db)
cursor = conn.cursor()
try:
# 插入订单记录
insert_order_sql = """
INSERT INTO Orders (Order_time, Paid, User_phone_number)
VALUES (%s, 0, %s)
"""
cursor.execute(insert_order_sql, (datetime.now(), g.user))
order_id = cursor.lastrowid
for passenger in passengers:
passenger_id = passenger['card_code']
name = passenger['name']
phone_number = passenger['phone_number']
seat_class = passenger['seat_class']
price_field = f"{seat_class.replace(' ', '_').lower()}_price"
price_sql = f"SELECT {price_field} FROM Flights WHERE ID = %s"
cursor.execute(price_sql, (flight_id,))
price = cursor.fetchone()[0]
insert_passenger_sql = """
INSERT INTO Passengers (ID, Name, Phone_number)
VALUES (%s, %s, %s)
ON DUPLICATE KEY UPDATE Name=VALUES(Name), Phone_number=VALUES(Phone_number);
"""
cursor.execute(insert_passenger_sql, (passenger_id, name, phone_number))
update_seat_sql = f"""
UPDATE Flights
SET {seat_class.replace(' ', '_').lower()}_seats_remaining = {seat_class.replace(' ', '_').lower()}_seats_remaining - 1
WHERE ID = %s
"""
cursor.execute(update_seat_sql, (flight_id,))
insert_ticket_sql = """
INSERT INTO Tickets (Price, FlightID, Seat_class, PassengerID, OrderID)
VALUES (%s, %s, %s, %s, %s)
"""
cursor.execute(insert_ticket_sql, (price, flight_id, seat_class, passenger_id, order_id))
conn.commit()
return redirect(url_for('order', order_id=order_id))
except Exception as e:
conn.rollback()
print(e)
flash("订票失败", "error")
return redirect(url_for('search'))
finally:
cursor.close()
conn.close()

View File

@@ -0,0 +1,51 @@
from flask import request, redirect, url_for, g
from .config import db
import pymysql
def cancel_order():
order_id = request.args.get('order_id')
if not g.user:
return redirect(url_for("login"))
conn = pymysql.connect(**db)
cursor = conn.cursor(pymysql.cursors.DictCursor)
# 检查订单是否存在
check_order_sql = "SELECT ID FROM Orders WHERE ID = %s"
cursor.execute(check_order_sql, (order_id,))
order_exists = cursor.fetchone()
if not order_exists:
cursor.close()
conn.close()
return redirect(url_for("order_list"))
# 查询订单中所有机票的航班ID和座位级别
tickets_sql = "SELECT FlightID, Seat_class FROM Tickets WHERE OrderID = %s"
cursor.execute(tickets_sql, (order_id,))
tickets = cursor.fetchall()
# 恢复航班的对应余座数
for ticket in tickets:
flight_id = ticket['FlightID']
seat_class = ticket['Seat_class']
seat_column = seat_class.replace(' ', '_').lower() + "_seats_remaining"
update_seat_sql = f"""
UPDATE Flights
SET {seat_column} = {seat_column} + 1
WHERE ID = %s
"""
cursor.execute(update_seat_sql, (flight_id,))
# 删除对应的机票
delete_tickets_sql = "DELETE FROM Tickets WHERE OrderID = %s"
cursor.execute(delete_tickets_sql, (order_id,))
# 删除订单
delete_order_sql = "DELETE FROM Orders WHERE ID = %s"
cursor.execute(delete_order_sql, (order_id,))
conn.commit()
cursor.close()
conn.close()
return redirect(url_for('order_list'))

View File

@@ -0,0 +1,18 @@
db = {
'host':'localhost',
'user':'kejingfan',
'password':'KJF2811879',
'database':'TESTDB'
}
SECRET_KEY = 'ILOVEDATABASETECH'
slideshow_images = [
{"link": "https://www.csair.com/mcms/mcms/SG/zh/2024/20240208_6/index-zh.html?lang=zh&country=sg&utm_campaign=2402gwstu&utm_source=gw&utm_channel=sg-lb", "src": "https://www.csair.com/mcms/20240321/3ee85acd463f481bb33f0d535a5814c6.jpg"},
{"link": "https://www.csair.com/mcms/mcms/SG/zh/2024/20240605_10/index_sg_cn.html?lang=zh&country=sg&utm_source=sg&utm_campaign=ZB001lydc&utm_channel=gw", "src": "https://www.csair.com/mcms/20240605/a553252769834188b0c76a9698292f27.jpg"},
{"link": "https://www.csair.com/mcms/mcms/SG/zh/2024/20240426_17/index_cn.html?lang=zh&country=sg&utm_source=sg&utm_campaign=ZB001znjp&utm_channel=gw", "src": "https://www.csair.com/mcms/20240321/820cd99c111849408b84c2b579086ef6.jpg"},
{"link": "https://www.csair.com/mcms/mcms/SG/zh/2024/20240524_2/index_cn.html?lang=zh&country=sg&country=my&utm_source=us&utm_campaign=ZB001nhzgx&utm_channel=gw", "src": "https://www.csair.com/mcms/20240321/61889331ca174670babd144bb064d398.jpg"},
{"link": "https://www.csair.com/mcms/mcms/SG/zh/2024/20240514_7/coupon.html?lang=zh&country=sg", "src": "https://www.csair.com/mcms/20240321/97e67c05291b4c64a8905e8a0c915d89.jpg"},
{"link": "#", "src": "https://www.csair.com/mcms/1026/43124f5d5124487f8d6678745ae42f57.jpg"},
{"link": "https://www.csair.com/mcms/mcms/SG/zh/2023/20231120_2/index_sg_cn.html?lang=zh&country=sg&utm_source=sg&utm_campaign=ZB001mq&utm_channel=gw", "src": "https://www.csair.com/mcms/1026/ea00e9cb9d9b43bea6497a6895c6d9e1.jpg"}
]

View File

@@ -0,0 +1,18 @@
from flask import render_template, request, g, redirect, url_for, session
from .config import slideshow_images
from .utils import get_cities
def index():
if request.method == 'GET':
if not g.user:
return redirect(url_for("login"))
images = slideshow_images
return render_template(
'index.html', cities=get_cities(),
images=images, username=g.name
)
def logout():
session.clear()
session.pop('user_id', None)
return redirect(url_for('login'))

View File

@@ -0,0 +1,35 @@
from flask import request, jsonify, session, url_for, render_template
from .config import db, slideshow_images
import pymysql
def connect(mobileNo, encrypted_password):
conn = pymysql.connect(**db)
cursor = conn.cursor(pymysql.cursors.DictCursor)
args = (mobileNo, encrypted_password)
verify_sql = "SELECT Phone_number FROM Users WHERE Phone_number = %s AND `Password` = %s;"
cursor.execute(verify_sql, args)
user = cursor.fetchone()
cursor.close()
conn.close()
return user
def login():
if request.method == 'GET':
images = slideshow_images
return render_template('login.html', images=images)
if request.method == 'POST':
session.pop('user_id', None)
mobileNo = request.json.get('username')
encrypted_password = request.json.get('password')
try:
user = connect(mobileNo, encrypted_password)
if not user:
return jsonify({'message': '用户不存在,请点击注册按钮注册'}), 401
session['user_id'] = mobileNo
session.modified = True
return jsonify({'redirect': url_for('index')})
except Exception as e:
print(e)
return jsonify({'message': '数据库错误,请稍后再试'}), 500

View File

@@ -0,0 +1,119 @@
from flask import render_template, request, flash, redirect, url_for, session, g
from typing import Dict
from pymysql.cursors import Cursor
import pymysql
from .config import db
def verify_user(cursor: Cursor, phone_number: str, password: str) -> str:
sql = """
SELECT Password FROM Users WHERE Phone_number = %s;
"""
cursor.execute(sql, (phone_number,))
record = cursor.fetchone()
if not record:
return "NO_USER"
if record[0] != password:
return "WRONG_PASSWORD"
return "USER_VERIFIED"
class ModifyInfo:
def __init__(self, form: Dict[str, str], user_phone: str):
self.phone_number = user_phone
modifyType = form['modifyType']
self.new_password = form.get('encryptedNewPassword', None)
self.new_phone_number = form.get('mobileNo', None)
self.new_username = form.get('username', None)
modifyType2command = {
'删除账户': 'delete account',
'修改密码': 'modify Password',
'修改手机号': 'modify Phone_Number',
'修改用户名': 'modify Username'
}
self.sql_dict = {
'delete account': 'DELETE FROM Users WHERE Phone_number = %s;',
'modify Password': 'UPDATE Users SET Password = %s WHERE Phone_number = %s;',
'modify Phone_Number': 'UPDATE Users SET Phone_number = %s WHERE Phone_number = %s;',
'modify Username': 'UPDATE Users SET Username = %s WHERE Phone_number = %s;'
}
self.sql_args_dict = {
'delete account': (self.phone_number,),
'modify Password': (self.new_password, self.phone_number),
'modify Phone_Number': (self.new_phone_number, self.phone_number),
'modify Username': (self.new_username, self.phone_number)
}
self.ok_message_dict = {
'delete account': "删除账户成功",
'modify Password': "修改密码成功",
'modify Phone_Number': "修改手机号成功",
'modify Username': "修改用户名成功"
}
self.fail_message_dict = {
'delete account': "数据库异常,删除账户失败",
'modify Password': "数据库异常,修改密码失败",
'modify Phone_Number': "数据库异常,修改手机号失败",
'modify Username': "数据库异常,修改用户名失败"
}
self.command = modifyType2command[modifyType]
def get_sql(self):
return self.sql_dict[self.command]
def get_args(self):
return self.sql_args_dict[self.command]
def get_ok_message(self):
return self.ok_message_dict[self.command]
def get_fail_message(self):
return self.fail_message_dict[self.command]
def modify():
if request.method == 'GET':
if not g.user:
return redirect(url_for("login"))
user_phone = session.get('user_id')
return render_template('modify.html', current_user_phone=user_phone, current_username=g.name)
if request.method == 'POST':
user_phone = session.get('user_id')
password = request.form['encryptedPassword']
conn = pymysql.connect(**db)
cursor = conn.cursor(pymysql.cursors.DictCursor)
verify_info = verify_user(cursor, user_phone, password)
if verify_info == "NO_USER":
session.clear()
return redirect(url_for('login'))
elif verify_info == "WRONG_PASSWORD":
flash("密码错误")
conn.close()
return redirect(url_for('modify'))
modifyInfo = ModifyInfo(request.form, user_phone)
if modifyInfo.command == 'modify Phone_Number':
check_sql = "SELECT COUNT(*) FROM Users WHERE Phone_number = %s;"
cursor.execute(check_sql, (modifyInfo.new_phone_number,))
if cursor.fetchone()[0] > 0:
flash("手机号已存在,请使用其他手机号")
conn.close()
return redirect(url_for('modify'))
try:
cursor.execute(modifyInfo.get_sql(), modifyInfo.get_args())
conn.commit()
flash(modifyInfo.get_ok_message())
conn.close()
if modifyInfo.command in ['modify Phone_Number', 'modify Password', 'delete account']:
session.clear()
session.pop("user_id", None)
return redirect(url_for('login'))
elif modifyInfo.command == 'modify Username':
return redirect(url_for('modify'))
except Exception as e:
conn.rollback()
print(e)
flash(modifyInfo.get_fail_message())
conn.close()
return redirect(url_for('modify'))

View File

@@ -0,0 +1,47 @@
from flask import render_template, request, redirect, url_for, g
from .config import db
import pymysql
def order():
order_id = request.args.get('order_id')
if not g.user:
return redirect(url_for("login"))
conn = pymysql.connect(**db)
cursor = conn.cursor(pymysql.cursors.DictCursor)
# 查询订单信息和航班信息
order_sql = """
SELECT o.*, f.*, d.Name as Departure_airport_name, a.Name as Arrival_airport_name
FROM Orders o
JOIN Tickets t ON o.ID = t.OrderID
JOIN Flights f ON t.FlightID = f.ID
JOIN Airports d ON f.Departure_airport = d.ID
JOIN Airports a ON f.Arrival_airport = a.ID
WHERE o.ID = %s
"""
cursor.execute(order_sql, (order_id,))
order_info = cursor.fetchone()
# 如果订单信息不存在,返回订单列表页面
if not order_info:
cursor.close()
conn.close()
return redirect(url_for("order_list"))
# 查询乘客信息和票据信息
tickets_sql = """
SELECT t.*, p.Name, p.Phone_number
FROM Tickets t
JOIN Passengers p ON t.PassengerID = p.ID
WHERE t.OrderID = %s
"""
cursor.execute(tickets_sql, (order_id,))
tickets = cursor.fetchall()
cursor.close()
conn.close()
total_price = sum(ticket['Price'] for ticket in tickets)
return render_template('order.html', order=order_info, tickets=tickets, total_price=total_price, username=g.name)

View File

@@ -0,0 +1,54 @@
from flask import render_template, request, redirect, url_for, g
from .config import db
import pymysql
def order_list():
if not g.user:
return redirect(url_for("login"))
conn = pymysql.connect(**db)
cursor = conn.cursor(pymysql.cursors.DictCursor)
# 查询用户关联的所有订单信息
orders_sql = """
SELECT o.ID as OrderID, o.Order_time, o.Paid, f.ID as FlightID, f.Airline,
d.Name as Departure_airport_name, a.Name as Arrival_airport_name,
f.Departure_time, f.Status, p.Name as PassengerName, t.Price
FROM Orders o
JOIN Tickets t ON o.ID = t.OrderID
JOIN Flights f ON t.FlightID = f.ID
JOIN Airports d ON f.Departure_airport = d.ID
JOIN Airports a ON f.Arrival_airport = a.ID
JOIN Passengers p ON t.PassengerID = p.ID
WHERE o.User_phone_number = %s
"""
cursor.execute(orders_sql, (g.user,))
orders = cursor.fetchall()
cursor.close()
conn.close()
# 整理订单信息
order_dict = {}
for order in orders:
order_id = order['OrderID']
if order_id not in order_dict:
order_dict[order_id] = {
'OrderID': order_id,
'Order_time': order['Order_time'],
'Paid': order['Paid'],
'FlightID': order['FlightID'],
'Airline': order['Airline'],
'Departure_airport_name': order['Departure_airport_name'],
'Arrival_airport_name': order['Arrival_airport_name'],
'Departure_time': order['Departure_time'],
'Status': order['Status'],
'Passengers': [],
'TotalPrice': 0
}
order_dict[order_id]['Passengers'].append(order['PassengerName'])
order_dict[order_id]['TotalPrice'] += order['Price']
order_list = list(order_dict.values())
return render_template('order_list.html', orders=order_list, username=g.name)

View File

@@ -0,0 +1,30 @@
from flask import redirect, url_for, g, request
from .config import db
import pymysql
def pay_confirm():
order_id = request.args.get('order_id')
if not g.user:
return redirect(url_for("login"))
conn = pymysql.connect(**db)
cursor = conn.cursor()
# 检查订单是否存在
check_order_sql = "SELECT ID FROM Orders WHERE ID = %s"
cursor.execute(check_order_sql, (order_id,))
order_exists = cursor.fetchone()
if not order_exists:
cursor.close()
conn.close()
return redirect(url_for("order_list"))
update_order_sql = "UPDATE Orders SET Paid = 1 WHERE ID = %s"
cursor.execute(update_order_sql, (order_id,))
conn.commit()
cursor.close()
conn.close()
return redirect(url_for('order_list', order_id=order_id))

View File

@@ -0,0 +1,49 @@
from flask import render_template, request, g, abort, redirect, url_for
from .config import db
from .utils import get_cities
import pymysql
import datetime
def search():
if not g.user:
return redirect(url_for("login"))
departure_city = request.args.get('departure')
destination_city = request.args.get('destination')
departure_date = request.args.get('departure-date')
passengers = int(request.args.get('passengers', 1))
# Date validation
try:
departure_date_obj = datetime.datetime.strptime(departure_date, '%Y-%m-%d').date()
if departure_date_obj < datetime.date.today():
abort(400, description="Departure date cannot be in the past.")
except ValueError:
abort(400, description="Invalid date format.")
conn = pymysql.connect(**db)
cursor = conn.cursor(pymysql.cursors.DictCursor)
search_sql = """
SELECT f.*, d.Name as Departure_airport_name, a.Name as Arrival_airport_name
FROM Flights f
JOIN Airports d ON f.Departure_airport = d.ID
JOIN Airports a ON f.Arrival_airport = a.ID
WHERE d.City = %s AND a.City = %s
AND DATE(f.Departure_time) = %s
AND (f.First_class_seats_remaining + f.Business_class_seats_remaining + f.Economy_class_seats_remaining) >= %s
AND f.Status NOT IN ('已起飞', '已降落');
"""
cursor.execute(search_sql, (departure_city, destination_city, departure_date, passengers))
flights = cursor.fetchall()
cursor.close()
conn.close()
return render_template(
'search.html',
cities=get_cities(),
flights=flights,
username=g.name
)

View File

@@ -0,0 +1,74 @@
from flask import render_template, request, redirect, url_for
from .config import db
import re
import pymysql
def signup():
error_messages = {
'username': '',
'mobileNo': '',
'password': '',
'confirmPassword': ''
}
if request.method == 'GET':
return render_template('signup.html', errors=error_messages)
if request.method == 'POST':
username = request.form['username']
phone_number = request.form['mobileNo']
password = request.form['encryptedPassword']
confirm_password = request.form['encryptedConfirmPassword']
# Basic validation for phone number
if not re.match(r'^\d{11}$', phone_number):
error_messages['mobileNo'] = '手机号格式有误'
# Check password length after MD5 hash
if len(password) != 32: # MD5 hash length is 32 characters
error_messages['password'] = '密码格式有误'
# Confirm password validation
if password != confirm_password:
error_messages['confirmPassword'] = '两次输入的密码不一致'
if any(error_messages.values()):
return render_template('signup.html', errors=error_messages)
conn = pymysql.connect(**db)
cursor = conn.cursor(pymysql.cursors.DictCursor)
# 检查已有用户
sql = """
SELECT COUNT(*) FROM Users \
WHERE Phone_number = %s;
"""
try:
cursor.execute(sql, (phone_number,))
phone_exist = cursor.fetchall()[0]['COUNT(*)']
except Exception as e:
error_messages['mobileNo'] = "数据库异常,查询失败"
print(e)
return render_template('signup.html', errors=error_messages)
if phone_exist != 0:
error_messages['mobileNo'] = "该手机号已注册,请勿重复注册"
conn.close()
return render_template('signup.html', errors=error_messages)
# 插入
sql = '''
INSERT INTO Users (Phone_number, Username, `Password`) \
VALUES (%s, %s, %s); \
'''
try:
cursor.execute(sql, (phone_number, username, password))
conn.commit()
return redirect(url_for('index'))
except Exception as e:
conn.rollback()
print(e)
error_messages['mobileNo'] = "数据库异常,注册失败"
return render_template('signup.html', errors=error_messages)
finally:
conn.close()

View File

@@ -0,0 +1,20 @@
from .config import db
import pymysql
from xpinyin import Pinyin
from pymysql.cursors import Cursor
def get_cities():
conn = pymysql.connect(**db)
cursor = conn.cursor(pymysql.cursors.DictCursor)
cursor.execute("SELECT DISTINCT City FROM Airports")
cities = [row['City'] for row in cursor.fetchall()]
cursor.close()
conn.close()
p = Pinyin()
cities = [
(row, p.get_pinyin(row).replace("-", ""))
for row in cities
]
cities = sorted(cities, key=lambda x: x[1])
cities = [row[0] for row in cities]
return cities