初步完成登录、注册、修改账号、主页内容
This commit is contained in:
parent
e48e752b91
commit
ad767a806b
BIN
Project/__pycache__/config.cpython-311.pyc
Normal file
BIN
Project/__pycache__/config.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
128
Project/db.sql
128
Project/db.sql
@ -1,102 +1,58 @@
|
|||||||
DROP TABLE IF EXISTS Sold;
|
|
||||||
DROP TABLE IF EXISTS Transactions;
|
|
||||||
DROP TABLE IF EXISTS Passbys;
|
|
||||||
DROP TABLE IF EXISTS Tickets;
|
DROP TABLE IF EXISTS Tickets;
|
||||||
DROP TABLE IF EXISTS Seats;
|
DROP TABLE IF EXISTS Flights;
|
||||||
|
DROP TABLE IF EXISTS Airports;
|
||||||
DROP TABLE IF EXISTS Users;
|
DROP TABLE IF EXISTS Users;
|
||||||
DROP TABLE IF EXISTS Passengers;
|
DROP TABLE IF EXISTS Passengers;
|
||||||
DROP TABLE IF EXISTS Rides;
|
|
||||||
DROP TABLE IF EXISTS Trains;
|
|
||||||
DROP TABLE IF EXISTS Stations;
|
|
||||||
|
|
||||||
CREATE TABLE Passengers (
|
CREATE TABLE Passengers (
|
||||||
ID BIGINT PRIMARY KEY,
|
ID BIGINT PRIMARY KEY,
|
||||||
`Name` VARCHAR ( 255 ) NOT NULL,
|
`Name` VARCHAR(255) NOT NULL,
|
||||||
Phone_number BIGINT UNIQUE NOT NULL,
|
Phone_number BIGINT NOT NULL,
|
||||||
CHECK ( REGEXP_LIKE ( ID, '^\\d{18}$' ) ),
|
CHECK (REGEXP_LIKE(ID, '^\\d{18}$')),
|
||||||
CHECK ( REGEXP_LIKE ( Phone_number, '^\\d{11}$' ) )
|
CHECK (REGEXP_LIKE(Phone_number, '^\\d{11}$'))
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE Users (
|
CREATE TABLE Users (
|
||||||
ID INT AUTO_INCREMENT PRIMARY KEY,
|
Phone_number BIGINT PRIMARY KEY,
|
||||||
`Password` VARCHAR ( 255 ) NOT NULL,
|
Username VARCHAR(255) NOT NULL,
|
||||||
Phone_number BIGINT UNIQUE NOT NULL,
|
`Password` VARCHAR(255) NOT NULL,
|
||||||
CitizenID BIGINT UNIQUE NOT NULL,
|
CHECK (REGEXP_LIKE(Phone_number, '^\\d{11}$'))
|
||||||
FOREIGN KEY ( Phone_number ) REFERENCES Passengers ( Phone_number ) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY ( CitizenID ) REFERENCES Passengers ( ID ) ON DELETE CASCADE
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE Stations (
|
CREATE TABLE Airports (
|
||||||
ID INT AUTO_INCREMENT PRIMARY KEY,
|
ID INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
`Name` VARCHAR ( 255 ) UNIQUE NOT NULL,
|
`Name` VARCHAR(255) UNIQUE NOT NULL,
|
||||||
Province VARCHAR ( 255 ) NOT NULL,
|
Country VARCHAR(255) NOT NULL,
|
||||||
City VARCHAR ( 255 ) NOT NULL
|
City VARCHAR(255) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE Trains (
|
CREATE TABLE Flights (
|
||||||
ID VARCHAR ( 255 ) PRIMARY KEY,
|
ID VARCHAR(255) PRIMARY KEY,
|
||||||
TrainName VARCHAR ( 255 ) NOT NULL,
|
Airline VARCHAR(255) NOT NULL,
|
||||||
StationID_start INT NOT NULL,
|
Departure_airport INT NOT NULL,
|
||||||
StationID_arrive INT NOT NULL,
|
Arrival_airport INT NOT NULL,
|
||||||
FOREIGN KEY ( StationID_start ) REFERENCES Stations ( ID ) ON DELETE CASCADE,
|
Departure_time DATETIME NOT NULL,
|
||||||
FOREIGN KEY ( StationID_arrive ) REFERENCES Stations ( ID ) ON DELETE CASCADE
|
Arrival_time DATETIME NOT NULL,
|
||||||
);
|
First_class_seats_remaining INT NOT NULL, -- 头等舱剩余座位
|
||||||
|
Business_class_seats_remaining INT NOT NULL, -- 商务舱剩余座位
|
||||||
CREATE TABLE Seats (
|
Economy_class_seats_remaining INT NOT NULL, -- 经济舱剩余座位
|
||||||
ID VARCHAR ( 255 ) PRIMARY KEY,
|
First_class_price DECIMAL(7, 2) NOT NULL, -- 头等舱价格
|
||||||
Type VARCHAR ( 255 ) NOT NULL,
|
Business_class_price DECIMAL(7, 2) NOT NULL, -- 商务舱价格
|
||||||
TrainID VARCHAR ( 255 ) NOT NULL,
|
Economy_class_price DECIMAL(7, 2) NOT NULL, -- 经济舱价格
|
||||||
FOREIGN KEY ( TrainID ) REFERENCES Trains ( ID ) ON DELETE CASCADE
|
`Status` VARCHAR(255) NOT NULL CHECK (`Status` IN ('候机中', '延误', '已起飞', '已降落', '开始检票')), -- 航班状态
|
||||||
|
FOREIGN KEY (Departure_airport) REFERENCES Airports(ID) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (Arrival_airport) REFERENCES Airports(ID) ON DELETE CASCADE,
|
||||||
|
CHECK (Departure_time < Arrival_time)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE Tickets (
|
CREATE TABLE Tickets (
|
||||||
ID INT AUTO_INCREMENT PRIMARY KEY,
|
ID INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
Price DECIMAL ( 7, 2 ) NOT NULL,
|
Price DECIMAL(7, 2) NOT NULL,
|
||||||
Time_start DATETIME NOT NULL,
|
FlightID VARCHAR(255) NOT NULL,
|
||||||
Time_arrive DATETIME NOT NULL,
|
Seat_class VARCHAR(255) NOT NULL, -- 级别信息
|
||||||
StationID_start INT NOT NULL,
|
PassengerID BIGINT NOT NULL,
|
||||||
StationID_arrive INT NOT NULL,
|
Paid TINYINT NOT NULL,
|
||||||
SeatID VARCHAR ( 255 ) NOT NULL,
|
FOREIGN KEY (FlightID) REFERENCES Flights(ID) ON DELETE CASCADE,
|
||||||
FOREIGN KEY ( StationID_start ) REFERENCES Stations ( ID ) ON DELETE CASCADE,
|
FOREIGN KEY (PassengerID) REFERENCES Passengers(ID) ON DELETE CASCADE,
|
||||||
FOREIGN KEY ( StationID_arrive ) REFERENCES Stations ( ID ) ON DELETE CASCADE,
|
CHECK (Seat_class IN ('First Class', 'Business Class', 'Economy Class'))
|
||||||
FOREIGN KEY ( SeatID ) REFERENCES Seats ( ID ) ON DELETE CASCADE,
|
|
||||||
CHECK ( Time_start <= Time_arrive )
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE Transactions (
|
|
||||||
ID BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
`Time` DATETIME NOT NULL,
|
|
||||||
Paid TINYINT NOT NULL,
|
|
||||||
`User` INT NOT NULL,
|
|
||||||
PassengerID BIGINT NOT NULL,
|
|
||||||
TrainID VARCHAR ( 255 ) NOT NULL,
|
|
||||||
StationID_start INT NOT NULL,
|
|
||||||
StationID_arrive INT NOT NULL,
|
|
||||||
Time_start DATETIME NOT NULL,
|
|
||||||
Time_arrive DATETIME NOT NULL,
|
|
||||||
SeatID VARCHAR ( 255 ) NOT NULL,
|
|
||||||
FOREIGN KEY ( `User` ) REFERENCES Users ( ID ) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY ( PassengerID ) REFERENCES Passengers ( ID ) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY ( TrainID ) REFERENCES Trains ( ID ) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY ( StationID_start ) REFERENCES Stations ( ID ) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY ( StationID_arrive ) REFERENCES Stations ( ID ) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY ( SeatID ) REFERENCES Seats ( ID ) ON DELETE CASCADE,
|
|
||||||
CHECK ( Time_start < Time_arrive )
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE Sold (
|
|
||||||
TransactionID BIGINT NOT NULL,
|
|
||||||
TicketID INT NOT NULL,
|
|
||||||
FOREIGN KEY ( TransactionID ) REFERENCES Transactions ( ID ) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY ( TicketID ) REFERENCES Tickets ( ID ) ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE Passbys (
|
|
||||||
StationID INT NOT NULL,
|
|
||||||
TrainID VARCHAR ( 255 ) NOT NULL,
|
|
||||||
arrive_time DATETIME NOT NULL,
|
|
||||||
leave_time DATETIME NOT NULL,
|
|
||||||
FOREIGN KEY ( StationID ) REFERENCES Stations ( ID ) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY ( TrainID ) REFERENCES Trains ( ID ) ON DELETE CASCADE,
|
|
||||||
CHECK ( arrive_time <= leave_time )
|
|
||||||
);
|
);
|
BIN
Project/func/__pycache__/config.cpython-311.pyc
Normal file
BIN
Project/func/__pycache__/config.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
Project/func/__pycache__/login.cpython-311.pyc
Normal file
BIN
Project/func/__pycache__/login.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
18
Project/func/config.py
Normal file
18
Project/func/config.py
Normal 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"}
|
||||||
|
]
|
@ -1,4 +1,15 @@
|
|||||||
from flask import render_template
|
from flask import render_template, request, g, redirect, url_for, session
|
||||||
|
from .config import slideshow_images
|
||||||
|
|
||||||
def index():
|
def index():
|
||||||
return render_template("index.html")
|
if request.method == 'GET':
|
||||||
|
if not g.user:
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
username = g.name
|
||||||
|
images = slideshow_images
|
||||||
|
return render_template('index.html', images=images, username=username)
|
||||||
|
|
||||||
|
def logout():
|
||||||
|
session.clear()
|
||||||
|
session.pop('user_id', None)
|
||||||
|
return redirect(url_for('login'))
|
||||||
|
35
Project/func/login.py
Normal file
35
Project/func/login.py
Normal 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
|
@ -1,79 +1,127 @@
|
|||||||
from flask import render_template, request, flash, redirect, url_for
|
from flask import render_template, request, flash, redirect, url_for, session
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from pymysql.cursors import Cursor
|
||||||
from .get_db import get_db
|
from .get_db import get_db
|
||||||
from .verify_user import verify_user
|
|
||||||
|
|
||||||
|
def get_current_user(cursor: Cursor, phone_number: str):
|
||||||
|
sql = "SELECT Username FROM Users WHERE Phone_number = %s"
|
||||||
|
cursor.execute(sql, (phone_number,))
|
||||||
|
return cursor.fetchone()
|
||||||
|
|
||||||
|
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:
|
class ModifyInfo:
|
||||||
def __init__(self, form:Dict[str, str]):
|
def __init__(self, form: Dict[str, str], user_phone: str):
|
||||||
self.id = form['cardCode']
|
self.phone_number = user_phone
|
||||||
|
print(form)
|
||||||
modifyType = form['modifyType']
|
modifyType = form['modifyType']
|
||||||
self.new_password = form['encryptedNewPassword']
|
self.new_password = form.get('encryptedNewPassword', None)
|
||||||
self.phone_number = form['mobileNo']
|
self.new_phone_number = form.get('mobileNo', None)
|
||||||
|
self.new_username = form.get('username', None)
|
||||||
modifyType2command = {
|
modifyType2command = {
|
||||||
'1':'delete account',
|
'删除账户': 'delete account',
|
||||||
'2':'modify Password',
|
'修改密码': 'modify Password',
|
||||||
'3':'modify Phone_Number'
|
'修改手机号': 'modify Phone_Number',
|
||||||
|
'修改用户名': 'modify Username'
|
||||||
}
|
}
|
||||||
self.sql_dict = {
|
self.sql_dict = {
|
||||||
'delete account': 'DELETE FROM passengers WHERE ID = %s;',
|
'delete account': 'DELETE FROM Users WHERE Phone_number = %s;',
|
||||||
'modify Password': 'UPDATE passengers SET `Password` = %s WHERE ID = %s;',
|
'modify Password': 'UPDATE Users SET Password = %s WHERE Phone_number = %s;',
|
||||||
'modify Phone_Number': 'UPDATE passengers SET Phone_number = %s WHERE ID = %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 = {
|
self.sql_args_dict = {
|
||||||
'delete account': (self.id,),
|
'delete account': (self.phone_number,),
|
||||||
'modify Password': (self.new_password, self.id),
|
'modify Password': (self.new_password, self.phone_number),
|
||||||
'modify Phone_Number': (self.phone_number, self.id)
|
'modify Phone_Number': (self.new_phone_number, self.phone_number),
|
||||||
|
'modify Username': (self.new_username, self.phone_number)
|
||||||
}
|
}
|
||||||
self.ok_message_dict = {
|
self.ok_message_dict = {
|
||||||
'delete account': "删除账户成功",
|
'delete account': "删除账户成功",
|
||||||
'modify Password': "修改密码成功",
|
'modify Password': "修改密码成功",
|
||||||
'modify Phone_Number': "修改手机号成功"
|
'modify Phone_Number': "修改手机号成功",
|
||||||
|
'modify Username': "修改用户名成功"
|
||||||
}
|
}
|
||||||
self.fail_message_dict = {
|
self.fail_message_dict = {
|
||||||
'delete account': "数据库异常,删除账户失败",
|
'delete account': "数据库异常,删除账户失败",
|
||||||
'modify Password': "数据库异常,修改密码失败",
|
'modify Password': "数据库异常,修改密码失败",
|
||||||
'modify Phone_Number': "数据库异常,修改手机号失败"
|
'modify Phone_Number': "数据库异常,修改手机号失败",
|
||||||
|
'modify Username': "数据库异常,修改用户名失败"
|
||||||
}
|
}
|
||||||
self.command = modifyType2command[modifyType]
|
self.command = modifyType2command[modifyType]
|
||||||
|
|
||||||
def get_sql(self):
|
def get_sql(self):
|
||||||
return self.sql_dict[self.command]
|
return self.sql_dict[self.command]
|
||||||
|
|
||||||
def get_args(self):
|
def get_args(self):
|
||||||
return self.sql_args_dict[self.command]
|
return self.sql_args_dict[self.command]
|
||||||
|
|
||||||
def get_ok_message(self):
|
def get_ok_message(self):
|
||||||
return self.ok_message_dict[self.command]
|
return self.ok_message_dict[self.command]
|
||||||
|
|
||||||
def get_fail_message(self):
|
def get_fail_message(self):
|
||||||
return self.fail_message_dict[self.command]
|
return self.fail_message_dict[self.command]
|
||||||
|
|
||||||
def modify():
|
def modify():
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
return render_template('modify.html')
|
user_phone = session.get('user_id')
|
||||||
|
db = get_db()
|
||||||
|
cursor = db.cursor()
|
||||||
|
current_user = get_current_user(cursor, user_phone)
|
||||||
|
if not current_user:
|
||||||
|
session.clear()
|
||||||
|
return redirect(url_for('login'))
|
||||||
|
return render_template('modify.html', current_user_phone=user_phone, current_username=current_user[0])
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
id = request.form['cardCode']
|
user_phone = session.get('user_id')
|
||||||
password = request.form['encryptedPassword']
|
password = request.form['encryptedPassword']
|
||||||
db = get_db()
|
db = get_db()
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
|
|
||||||
verify_info = verify_user(cursor, id, password)
|
verify_info = verify_user(cursor, user_phone, password)
|
||||||
if (verify_info == "NO_USER"):
|
if verify_info == "NO_USER":
|
||||||
flash("您未注册过,无法修改账号")
|
session.clear()
|
||||||
db.close()
|
return redirect(url_for('login'))
|
||||||
return redirect(url_for('signup'))
|
elif verify_info == "WRONG_PASSWORD":
|
||||||
elif (verify_info == "WRONG_PASSWORD"):
|
|
||||||
flash("密码错误")
|
flash("密码错误")
|
||||||
db.close()
|
db.close()
|
||||||
return redirect(url_for('modify'))
|
return redirect(url_for('modify'))
|
||||||
|
|
||||||
modifyInfo = ModifyInfo(request.form)
|
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("手机号已存在,请使用其他手机号")
|
||||||
|
db.close()
|
||||||
|
return redirect(url_for('modify'))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cursor.execute(modifyInfo.get_sql(), modifyInfo.get_args())
|
cursor.execute(modifyInfo.get_sql(), modifyInfo.get_args())
|
||||||
db.commit()
|
db.commit()
|
||||||
flash(modifyInfo.get_ok_message())
|
flash(modifyInfo.get_ok_message())
|
||||||
|
db.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:
|
except Exception as e:
|
||||||
db.rollback()
|
db.rollback()
|
||||||
print(e)
|
print(e)
|
||||||
flash(modifyInfo.get_fail_message())
|
flash(modifyInfo.get_fail_message())
|
||||||
db.close()
|
db.close()
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('modify'))
|
||||||
|
@ -1,15 +1,38 @@
|
|||||||
from flask import render_template, request, flash, redirect, url_for
|
from flask import render_template, request, redirect, url_for
|
||||||
from .get_db import get_db
|
from .get_db import get_db
|
||||||
|
import re
|
||||||
|
|
||||||
def signup():
|
def signup():
|
||||||
|
error_messages = {
|
||||||
|
'username': '',
|
||||||
|
'mobileNo': '',
|
||||||
|
'password': '',
|
||||||
|
'confirmPassword': ''
|
||||||
|
}
|
||||||
|
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
return render_template('signup.html')
|
return render_template('signup.html', errors=error_messages)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
id = request.form['cardCode']
|
username = request.form['username']
|
||||||
name = request.form['name']
|
|
||||||
phone_number = request.form['mobileNo']
|
phone_number = request.form['mobileNo']
|
||||||
password = request.form['encryptedPassword']
|
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)
|
||||||
|
|
||||||
db = get_db()
|
db = get_db()
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
@ -17,32 +40,34 @@ def signup():
|
|||||||
# 检查已有用户
|
# 检查已有用户
|
||||||
sql = """
|
sql = """
|
||||||
SELECT COUNT(*) FROM Users \
|
SELECT COUNT(*) FROM Users \
|
||||||
WHERE ID = %s;
|
WHERE Phone_number = %s;
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
cursor.execute(sql, (id,))
|
cursor.execute(sql, (phone_number,))
|
||||||
id_exist = cursor.fetchall()[0][0]
|
phone_exist = cursor.fetchall()[0][0]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
flash("数据库异常,查询失败")
|
error_messages['mobileNo'] = "数据库异常,查询失败"
|
||||||
print(e)
|
print(e)
|
||||||
return redirect(url_for('signup'))
|
return render_template('signup.html', errors=error_messages)
|
||||||
if (id_exist != 0):
|
|
||||||
flash("您已注册过,请勿重复注册")
|
if phone_exist != 0:
|
||||||
|
error_messages['mobileNo'] = "该手机号已注册,请勿重复注册"
|
||||||
db.close()
|
db.close()
|
||||||
return redirect(url_for('index'))
|
return render_template('signup.html', errors=error_messages)
|
||||||
|
|
||||||
# 插入
|
# 插入
|
||||||
sql = '''
|
sql = '''
|
||||||
INSERT INTO passengers (ID, `Name`, Phone_number, `Password`) \
|
INSERT INTO Users (Phone_number, Username, `Password`) \
|
||||||
VALUES (%s, %s, %s, %s); \
|
VALUES (%s, %s, %s); \
|
||||||
'''
|
'''
|
||||||
try:
|
try:
|
||||||
cursor.execute(sql, (id, name, phone_number, password))
|
cursor.execute(sql, (phone_number, username, password))
|
||||||
db.commit()
|
db.commit()
|
||||||
flash("注册成功")
|
return redirect(url_for('index'))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
db.rollback()
|
db.rollback()
|
||||||
print(e)
|
print(e)
|
||||||
flash("数据库异常,注册失败")
|
error_messages['mobileNo'] = "数据库异常,注册失败"
|
||||||
db.close()
|
return render_template('signup.html', errors=error_messages)
|
||||||
return redirect(url_for('index'))
|
finally:
|
||||||
|
db.close()
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
from flask import flash, redirect, url_for
|
|
||||||
from pymysql.cursors import Cursor
|
|
||||||
|
|
||||||
def verify_user(cursor:Cursor, id:str, password:str) -> str:
|
|
||||||
# 检查已有用户
|
|
||||||
sql = """
|
|
||||||
SELECT COUNT(*) FROM passengers \
|
|
||||||
WHERE ID = %s;
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
cursor.execute(sql, (id,))
|
|
||||||
id_exist = cursor.fetchall()[0][0]
|
|
||||||
except Exception as e:
|
|
||||||
flash("数据库异常,查询失败")
|
|
||||||
print(e)
|
|
||||||
return redirect(url_for('signup'))
|
|
||||||
if (id_exist == 0):
|
|
||||||
return "NO_USER"
|
|
||||||
|
|
||||||
# 检查密码
|
|
||||||
sql = """
|
|
||||||
SELECT `Password` FROM passengers \
|
|
||||||
WHERE ID = %s;
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
cursor.execute(sql, (id,))
|
|
||||||
record_password = cursor.fetchall()[0][0]
|
|
||||||
except Exception as e:
|
|
||||||
flash("数据库异常,查询失败")
|
|
||||||
print(e)
|
|
||||||
return redirect(url_for('modify'))
|
|
||||||
if (record_password != password):
|
|
||||||
return "WRONG_PASSWORD"
|
|
||||||
|
|
||||||
return "USER_VERIFIED"
|
|
@ -1,22 +1,80 @@
|
|||||||
from flask import Flask
|
from flask import Flask, redirect, url_for, session, render_template, request, g
|
||||||
import os
|
from flask_httpauth import HTTPTokenAuth
|
||||||
|
from flask_cors import CORS
|
||||||
|
from func.config import db, SECRET_KEY, slideshow_images
|
||||||
|
import pymysql
|
||||||
|
|
||||||
import func.index
|
import func.login
|
||||||
import func.signup
|
import func.signup
|
||||||
import func.modify
|
import func.modify
|
||||||
|
import func.index
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = os.environ.get('SECRET_KEY', 'OPTIONALSECRETKEY')
|
app.config["SECRET_KEY"] = SECRET_KEY
|
||||||
|
app.config["JSON_AS_ASCII"] = False
|
||||||
|
app.config['SESSION_COOKIE_HTTPONLY'] = True
|
||||||
|
app.config['SESSION_COOKIE_SECURE'] = False
|
||||||
|
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
|
||||||
|
CORS(app, supports_credentials=True)
|
||||||
|
auth = HTTPTokenAuth(scheme='Bearer')
|
||||||
|
|
||||||
|
@app.before_request
|
||||||
|
def before_request():
|
||||||
|
g.user = None
|
||||||
|
g.name = None
|
||||||
|
if 'user_id' in session:
|
||||||
|
conn = pymysql.connect(**db)
|
||||||
|
cursor = conn.cursor(pymysql.cursors.DictCursor)
|
||||||
|
args = (session.get('user_id'),)
|
||||||
|
verify_sql = "SELECT Phone_number, Username FROM Users WHERE Phone_number = %s;"
|
||||||
|
cursor.execute(verify_sql, args)
|
||||||
|
res = cursor.fetchone()
|
||||||
|
if not res:
|
||||||
|
g.user = None
|
||||||
|
g.name = None
|
||||||
|
else:
|
||||||
|
g.user = res['Phone_number']
|
||||||
|
g.name = res['Username']
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
|
def home():
|
||||||
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
|
@app.route("/index", methods=['GET', 'POST'])
|
||||||
def index():
|
def index():
|
||||||
return func.index.index()
|
return func.index.index()
|
||||||
|
|
||||||
@app.route("/signup.html", methods=('GET', 'POST'))
|
@app.route("/login", methods=['GET', 'POST'])
|
||||||
|
def login():
|
||||||
|
return func.login.login()
|
||||||
|
|
||||||
|
@app.route('/logout')
|
||||||
|
def logout():
|
||||||
|
return func.index.logout()
|
||||||
|
|
||||||
|
@app.route("/signup", methods=['GET', 'POST'])
|
||||||
def signup():
|
def signup():
|
||||||
return func.signup.signup()
|
return func.signup.signup()
|
||||||
|
|
||||||
@app.route("/modify.html", methods=('GET', 'POST'))
|
@app.route("/modify", methods=['GET', 'POST'])
|
||||||
def modify():
|
def modify():
|
||||||
|
if request.method == 'GET':
|
||||||
|
if not g.user:
|
||||||
|
return redirect(url_for("login"))
|
||||||
return func.modify.modify()
|
return func.modify.modify()
|
||||||
|
|
||||||
|
@app.route("/search", methods=['GET'])
|
||||||
|
def search():
|
||||||
|
# 处理搜索逻辑
|
||||||
|
return "搜索结果"
|
||||||
|
|
||||||
|
@app.route("/orders", methods=['GET', 'POST'])
|
||||||
|
def orders():
|
||||||
|
return "我的订单"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(
|
||||||
|
host="0.0.0.0",
|
||||||
|
port=5000,
|
||||||
|
debug=True
|
||||||
|
)
|
||||||
|
@ -7,53 +7,124 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
overflow-x: hidden; /* 防止出现水平滚动条 */
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
background-color: rgba(28, 108, 178, 0.9);
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
color: white;
|
color: white;
|
||||||
padding: 20px 0;
|
padding: 20px;
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav ul {
|
.header-content {
|
||||||
list-style: none;
|
display: flex;
|
||||||
padding: 0;
|
align-items: center;
|
||||||
margin: 0;
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav ul li {
|
.logo {
|
||||||
display: inline;
|
font-size: 24px;
|
||||||
margin: 0 10px;
|
font-weight: bold;
|
||||||
|
margin-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav ul li a {
|
.nav-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons a {
|
||||||
color: white;
|
color: white;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-weight: bold;
|
font-size: 16px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
.nav-buttons a:hover {
|
||||||
flex: 1;
|
background-color: #155a8c;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.background-container {
|
.user-menu {
|
||||||
width: 100%;
|
|
||||||
max-width: 1500px;
|
|
||||||
height: 600px; /* Adjust according to the desired size */
|
|
||||||
background-image: url('/static/images/banner-login-20200629.jpg');
|
|
||||||
background-size: cover;
|
|
||||||
background-position: center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu span {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropbtn {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
min-width: 160px;
|
||||||
|
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||||
|
z-index: 1;
|
||||||
|
right: 0; /* 确保下拉菜单靠右对齐 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content a {
|
||||||
|
color: black;
|
||||||
|
padding: 12px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content a:hover {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown:hover .dropdown-content {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slides {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 400px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slides ul {
|
||||||
|
display: flex;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
transition: transform 0.6s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slides li {
|
||||||
|
min-width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slides img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@ -61,28 +132,79 @@ main {
|
|||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: absolute;
|
width: 80%;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: -50px auto 20px;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
.tabcontent {
|
||||||
color: #1c6cb2;
|
display: block;
|
||||||
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.links {
|
.form-row {
|
||||||
margin-top: 20px;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.links .btn {
|
.form-row label {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 10px;
|
||||||
|
text-align: right;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row input,
|
||||||
|
.form-row select {
|
||||||
|
flex: 2;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passenger-input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passenger-input button {
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-size: 18px;
|
||||||
background-color: #1c6cb2;
|
background-color: #1c6cb2;
|
||||||
color: white;
|
color: white;
|
||||||
padding: 10px 20px;
|
border: none;
|
||||||
text-decoration: none;
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
margin: 10px;
|
cursor: pointer;
|
||||||
display: inline-block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.links .btn:hover {
|
.passenger-input button:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passenger-input input {
|
||||||
|
width: 50px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #1c6cb2;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
background-color: #155a8c;
|
background-color: #155a8c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,4 +214,12 @@ footer {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: red;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: left;
|
||||||
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
|
121
Project/static/css/login.css
Normal file
121
Project/static/css/login.css
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #ffffff;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
padding: 20px 0;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slides {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 600px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slides ul {
|
||||||
|
display: flex;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
transition: transform 0.6s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slides li {
|
||||||
|
min-width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slides img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: #1c6cb2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form input {
|
||||||
|
display: block;
|
||||||
|
margin: 10px auto;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
width: 80%;
|
||||||
|
max-width: 300px;
|
||||||
|
margin-bottom: 20px; /* 增加外边距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form button,
|
||||||
|
.btn {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #1c6cb2;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form button:hover,
|
||||||
|
.btn:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: red;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: left;
|
||||||
|
margin-top: -10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
144
Project/static/css/modify.css
Normal file
144
Project/static/css/modify.css
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #ffffff;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
padding: 20px 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 90%;
|
||||||
|
margin: 0 auto;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content .btn-back {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #1c6cb2;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content .btn-back:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content h1 {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content .header-spacer {
|
||||||
|
width: 100px; /* 占位符,确保标题居中 */
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
background-color: rgba(255, 255, 255, 0.9);
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 10px;
|
||||||
|
text-align: center;
|
||||||
|
width: 400px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: #1c6cb2;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab button {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 10px 20px;
|
||||||
|
transition: 0.3s;
|
||||||
|
font-size: 17px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab button:hover {
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab button.active {
|
||||||
|
background-color: #1c6cb2;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabcontent {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group div {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[type="submit"] {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #1c6cb2;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[type="submit"]:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background-color: rgba(28, 108, 178, 0.9);
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
71
Project/static/css/signup.css
Normal file
71
Project/static/css/signup.css
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #ffffff;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
background-color: rgba(255, 255, 255, 0.9);
|
||||||
|
padding: 40px; /* 增加内边距 */
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
width: 100%;
|
||||||
|
max-width: 500px; /* 增大表单框的最大宽度 */
|
||||||
|
margin: auto;
|
||||||
|
margin-top: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
div div {
|
||||||
|
flex: 1;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"], input[type="password"] {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #1c6cb2;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #155a8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: red;
|
||||||
|
font-size: 12px;
|
||||||
|
height: 12px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
/* h1, ul, li, a, body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
text-decoration: none;
|
|
||||||
} */
|
|
||||||
|
|
||||||
li {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 81 KiB |
@ -1,51 +1,15 @@
|
|||||||
var checkInfo = {}
|
var checkInfo = {};
|
||||||
|
|
||||||
checkInfo.checkCardCode = function() {
|
|
||||||
let cardCode = document.getElementById('cardCode').value
|
|
||||||
let regexCardCode = /^([1-6][1-9]|50)\d{4}(18|19|20)\d{2}((0[1-9])|10|11|12)(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
|
|
||||||
if(!regexCardCode.test(cardCode)) {
|
|
||||||
alert('身份证号格式有误')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
checkInfo.checkMobileNo = function() {
|
checkInfo.checkMobileNo = function() {
|
||||||
let mobileNo = document.getElementById('mobileNo').value
|
let mobileNo = document.getElementById('mobileNo').value;
|
||||||
let regexMobileNo = /^1[3-9]\d{9}$/
|
let regexMobileNo = /^1[3-9]\d{9}$/;
|
||||||
if (!regexMobileNo.test(mobileNo)) {
|
return regexMobileNo.test(mobileNo);
|
||||||
alert('手机号格式有误')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkInfo.checkPassword = function() {
|
checkInfo.checkPassword = function() {
|
||||||
let password = document.getElementById('password')
|
let password = document.getElementById('password').value;
|
||||||
let regexPassword = /^[A-Za-z0-9\W_]{6,20}$/
|
let regexPassword = /^[A-Za-z0-9\W_]{6,20}$/;
|
||||||
if (!regexPassword.test(password.value)) {
|
let isValidPassword = regexPassword.test(password);
|
||||||
alert("密码须为长度为6-20位字母、数字或符号")
|
let confirmPassword = document.getElementById('confirmPassword').value;
|
||||||
return false
|
return isValidPassword && (password === confirmPassword);
|
||||||
}
|
|
||||||
let confirmPassword = document.getElementById('confirmPassword')
|
|
||||||
if (password.value !== confirmPassword.value) {
|
|
||||||
alert("两次输入的密码不一致")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
checkInfo.checkNewPassword = function() {
|
|
||||||
let password = document.getElementById('newPassword')
|
|
||||||
let regexPassword = /^[A-Za-z0-9\W_]{6,20}$/
|
|
||||||
if (!regexPassword.test(password.value)) {
|
|
||||||
alert("密码须为长度为6-20位字母、数字或符号")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let confirmPassword = document.getElementById('confirmNewPassword')
|
|
||||||
if (password.value !== confirmPassword.value) {
|
|
||||||
alert("两次输入的密码不一致")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
@ -1,8 +1,29 @@
|
|||||||
window.onload = function() {
|
function openTab(evt, tabName) {
|
||||||
// Display flashed messages, if any
|
var i, tabcontent, tablinks;
|
||||||
const messages = [];
|
tabcontent = document.getElementsByClassName("tabcontent");
|
||||||
// Assuming messages are added via server-side templating
|
for (i = 0; i < tabcontent.length; i++) {
|
||||||
if (messages.length > 0) {
|
tabcontent[i].style.display = "none";
|
||||||
alert(messages.join("\n"));
|
|
||||||
}
|
}
|
||||||
};
|
tablinks = document.getElementsByClassName("tablinks");
|
||||||
|
for (i = 0; i < tablinks.length; i++) {
|
||||||
|
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||||
|
}
|
||||||
|
document.getElementById(tabName).style.display = "block";
|
||||||
|
evt.currentTarget.className += " active";
|
||||||
|
}
|
||||||
|
|
||||||
|
function increment() {
|
||||||
|
var passengers = document.getElementById("passengers");
|
||||||
|
var value = parseInt(passengers.value, 10);
|
||||||
|
if (value < 50) {
|
||||||
|
passengers.value = value + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function decrement() {
|
||||||
|
var passengers = document.getElementById("passengers");
|
||||||
|
var value = parseInt(passengers.value, 10);
|
||||||
|
if (value > 1) {
|
||||||
|
passengers.value = value - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
81
Project/static/js/login.js
Normal file
81
Project/static/js/login.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
window.onload = function() {
|
||||||
|
autoLogin();
|
||||||
|
};
|
||||||
|
|
||||||
|
var checkInfo = {};
|
||||||
|
|
||||||
|
checkInfo.checkMobileNo = function() {
|
||||||
|
let mobileNo = document.getElementById('mobileNo').value;
|
||||||
|
let regexMobileNo = /^1[3-9]\d{9}$/;
|
||||||
|
if (!regexMobileNo.test(mobileNo)) {
|
||||||
|
document.getElementById('mobileNoError').textContent = '手机号格式有误';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
document.getElementById('mobileNoError').textContent = '';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkInfo.checkPassword = function() {
|
||||||
|
let password = document.getElementById('password').value;
|
||||||
|
let regexPassword = /^[A-Za-z0-9\W_]{6,20}$/;
|
||||||
|
if (!regexPassword.test(password)) {
|
||||||
|
document.getElementById('loginError').textContent = "密码须为长度为6-20位字母、数字或符号";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
document.getElementById('loginError').textContent = '';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitForm() {
|
||||||
|
if (checkInfo.checkMobileNo() && checkInfo.checkPassword()) {
|
||||||
|
document.getElementById('encryptedPassword').value = md5(
|
||||||
|
document.getElementById('password').value
|
||||||
|
);
|
||||||
|
login();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录函数
|
||||||
|
async function login() {
|
||||||
|
const mobileNo = document.getElementById('mobileNo').value;
|
||||||
|
const encryptedPassword = document.getElementById('encryptedPassword').value;
|
||||||
|
try {
|
||||||
|
const response = await fetch('/login', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ username: mobileNo, password: encryptedPassword }),
|
||||||
|
credentials: 'include' // 确保请求包含凭据(cookies)
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
if (response.ok) {
|
||||||
|
alert('登录成功');
|
||||||
|
// 自动跳转到主页
|
||||||
|
window.location.href = data.redirect;
|
||||||
|
} else {
|
||||||
|
document.getElementById('loginError').textContent = data.message;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert('数据库错误,请稍后再试');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动登录函数
|
||||||
|
async function autoLogin() {
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
if (token) {
|
||||||
|
const response = await fetch('http://localhost:5000/index', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + token
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (response.ok) {
|
||||||
|
document.getElementById('content').innerText = '已自动登录';
|
||||||
|
} else {
|
||||||
|
document.getElementById('content').innerText = '自动登录失败';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,28 +1,31 @@
|
|||||||
var modify = {}
|
var modify = {};
|
||||||
|
|
||||||
modify.showModifyPassword = function() {
|
modify.showModifyPassword = function() {
|
||||||
let modifyType = document.getElementById('modifyType').value
|
let modifyType = document.querySelector('.tablinks.active').textContent;
|
||||||
let info = {
|
let info = {
|
||||||
modifyPasswordLis: document.getElementsByClassName('modifyPassword'),
|
modifyPasswordLis: document.getElementsByClassName('modifyPassword'),
|
||||||
modifymobileNoLis: document.getElementsByClassName('modifymobileNo'),
|
modifymobileNoLis: document.getElementsByClassName('modifymobileNo'),
|
||||||
|
modifyUsernameLis: document.getElementsByClassName('modifyUsername'),
|
||||||
}
|
}
|
||||||
|
|
||||||
// 遍历隐藏所有元素
|
|
||||||
for (let key in info) {
|
for (let key in info) {
|
||||||
let elements = info[key];
|
let elements = info[key];
|
||||||
for (let item of elements) {
|
for (let item of elements) {
|
||||||
item.style.display = 'none'; // 确保所有相关元素被隐藏
|
item.style.display = 'none';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据 modifyType 显示相关元素
|
if (modifyType === "修改密码") {
|
||||||
if (modifyType === "2") {
|
|
||||||
for (let item of info.modifyPasswordLis) {
|
for (let item of info.modifyPasswordLis) {
|
||||||
item.style.display = 'block';
|
item.style.display = 'block';
|
||||||
}
|
}
|
||||||
} else if (modifyType === "3") {
|
} else if (modifyType === "修改手机号") {
|
||||||
for (let item of info.modifymobileNoLis) {
|
for (let item of info.modifymobileNoLis) {
|
||||||
item.style.display = 'block';
|
item.style.display = 'block';
|
||||||
}
|
}
|
||||||
|
} else if (modifyType === "修改用户名") {
|
||||||
|
for (let item of info.modifyUsernameLis) {
|
||||||
|
item.style.display = 'block';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
32
Project/static/js/signup.js
Normal file
32
Project/static/js/signup.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
function submitForm() {
|
||||||
|
let isValid = true;
|
||||||
|
clearErrors();
|
||||||
|
|
||||||
|
if (!checkInfo.checkMobileNo()) {
|
||||||
|
document.getElementById('mobileNoError').innerText = '手机号格式有误';
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checkInfo.checkPassword()) {
|
||||||
|
document.getElementById('passwordError').innerText = '密码须为长度为6-20位字母、数字或符号';
|
||||||
|
document.getElementById('confirmPasswordError').innerText = '两次输入的密码不一致';
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isValid) {
|
||||||
|
document.getElementById('encryptedPassword').value = md5(
|
||||||
|
document.getElementById('password').value
|
||||||
|
);
|
||||||
|
document.getElementById('encryptedConfirmPassword').value = md5(
|
||||||
|
document.getElementById('confirmPassword').value
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearErrors() {
|
||||||
|
document.getElementById('mobileNoError').innerText = '';
|
||||||
|
document.getElementById('passwordError').innerText = '';
|
||||||
|
document.getElementById('confirmPasswordError').innerText = '';
|
||||||
|
}
|
14
Project/static/js/slideshow.js
Normal file
14
Project/static/js/slideshow.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
let slideIndex = 0;
|
||||||
|
const slides = document.getElementById('slide-container');
|
||||||
|
const totalSlides = slides.children.length;
|
||||||
|
|
||||||
|
function showSlides() {
|
||||||
|
slideIndex++;
|
||||||
|
if (slideIndex >= totalSlides) {
|
||||||
|
slideIndex = 0;
|
||||||
|
}
|
||||||
|
slides.style.transform = 'translateX(' + (-slideIndex * 100) + '%)';
|
||||||
|
setTimeout(showSlides, 5000); // Change image every 5 seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
showSlides();
|
@ -3,34 +3,129 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>我的12306官网</title>
|
<title>KJF航班订票</title>
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}">
|
||||||
<script src="{{ url_for('static', filename='js/index.js') }}" defer></script>
|
<script src="{{ url_for('static', filename='js/index.js') }}" defer></script>
|
||||||
|
<script src="https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
<h1>中国铁路12306</h1>
|
<div class="header-content">
|
||||||
<nav>
|
<div class="logo">KJF航班订票</div>
|
||||||
<ul>
|
<div class="nav-buttons">
|
||||||
<li><a href="{{ url_for('index') }}">首页</a></li>
|
<a href="{{ url_for('index') }}">首页</a>
|
||||||
<li><a href="{{ url_for('signup') }}">注册</a></li>
|
<a href="{{ url_for('orders') }}">我的订单</a>
|
||||||
<li><a href="{{ url_for('modify') }}">修改账号</a></li>
|
</div>
|
||||||
</ul>
|
<div class="user-menu">
|
||||||
</nav>
|
<span>{{ username }}</span>
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="dropbtn">▼</button>
|
||||||
|
<div class="dropdown-content">
|
||||||
|
<a href="{{ url_for('modify') }}">修改账户信息</a>
|
||||||
|
<a href="{{ url_for('logout') }}">退出登录</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
<div class="background-container">
|
<div class="slides">
|
||||||
<div class="content">
|
<ul id="slide-container">
|
||||||
<h2>尽享精彩出行服务</h2>
|
{% for image in images %}
|
||||||
<div class="links">
|
<li>
|
||||||
<a class="btn" href="{{ url_for('signup') }}">点击跳转注册</a>
|
<a href="{{ image.link }}" target="_blank">
|
||||||
<a class="btn" href="{{ url_for('modify') }}">点击跳转修改账号</a>
|
<img src="{{ image.src }}">
|
||||||
</div>
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div id="ticket" class="tabcontent" style="display: block;">
|
||||||
|
<form action="{{ url_for('search') }}" method="get" class="search-form" onsubmit="return validateForm()">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="departure">出发地:</label>
|
||||||
|
<select id="departure" name="departure">
|
||||||
|
<option value="北京">北京</option>
|
||||||
|
<option value="上海">上海</option>
|
||||||
|
<option value="广州">广州</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="destination">目的地:</label>
|
||||||
|
<select id="destination" name="destination">
|
||||||
|
<option value="北京">北京</option>
|
||||||
|
<option value="上海">上海</option>
|
||||||
|
<option value="广州">广州</option>
|
||||||
|
</select>
|
||||||
|
<div id="destination-warning" class="error-message"></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="departure-date">出发日期:</label>
|
||||||
|
<input type="date" id="departure-date" name="departure-date">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="passengers">乘客人数:</label>
|
||||||
|
<div class="passenger-input">
|
||||||
|
<button type="button" onclick="decrement()">-</button>
|
||||||
|
<input type="number" id="passengers" name="passengers" value="1" min="1" max="50">
|
||||||
|
<button type="button" onclick="increment()">+</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<button type="submit" class="btn">立即查询</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
<p>© 2024 中国铁路12306. 保留所有权利。</p>
|
<p>© 2024 KJF航班订票. 保留所有权利。</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
<script src="{{ url_for('static', filename='js/slideshow.js') }}"></script>
|
||||||
|
<script>
|
||||||
|
function validateForm() {
|
||||||
|
var departure = document.getElementById('departure').value;
|
||||||
|
var destination = document.getElementById('destination').value;
|
||||||
|
var warning = document.getElementById('destination-warning');
|
||||||
|
if (departure === destination) {
|
||||||
|
warning.textContent = '出发地和目的地不能相同';
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
warning.textContent = '';
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function openTab(evt, tabName) {
|
||||||
|
var i, tabcontent, tablinks;
|
||||||
|
tabcontent = document.getElementsByClassName("tabcontent");
|
||||||
|
for (i = 0; i < tabcontent.length; i++) {
|
||||||
|
tabcontent[i].style.display = "none";
|
||||||
|
}
|
||||||
|
tablinks = document.getElementsByClassName("tablinks");
|
||||||
|
for (i = 0; i < tablinks.length; i++) {
|
||||||
|
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||||
|
}
|
||||||
|
document.getElementById(tabName).style.display = "block";
|
||||||
|
evt.currentTarget.className += " active";
|
||||||
|
}
|
||||||
|
|
||||||
|
function increment() {
|
||||||
|
var passengers = document.getElementById("passengers");
|
||||||
|
var value = parseInt(passengers.value, 10);
|
||||||
|
if (value < 50) {
|
||||||
|
passengers.value = value + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function decrement() {
|
||||||
|
var passengers = document.getElementById("passengers");
|
||||||
|
var value = parseInt(passengers.value, 10);
|
||||||
|
if (value > 1) {
|
||||||
|
passengers.value = value - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
47
Project/templates/login.html
Normal file
47
Project/templates/login.html
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>我的航班订票官网</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/login.css') }}">
|
||||||
|
<script src="{{ url_for('static', filename='js/login.js') }}" defer></script>
|
||||||
|
<script src="https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>KJF航班订票</h1>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<div class="slides">
|
||||||
|
<ul id="slide-container">
|
||||||
|
{% for image in images %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ image.link }}" target="_blank">
|
||||||
|
<img src="{{ image.src }}">
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<h2>尽享精彩出行服务</h2>
|
||||||
|
<div class="login-form">
|
||||||
|
<input type="text" id="mobileNo" placeholder="手机号">
|
||||||
|
<div id="mobileNoError" class="error-message"></div>
|
||||||
|
<input type="password" id="password" placeholder="密码">
|
||||||
|
<div id="loginError" class="error-message"></div>
|
||||||
|
<input type="hidden" id="encryptedPassword">
|
||||||
|
<div class="buttons">
|
||||||
|
<button onclick="submitForm()">登录</button>
|
||||||
|
<a class="btn" href="{{ url_for('signup') }}">注册</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<p>© 2024 KJF航班订票. 保留所有权利。</p>
|
||||||
|
</footer>
|
||||||
|
<script src="{{ url_for('static', filename='js/slideshow.js') }}"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,10 +1,12 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
<head>
|
<head>
|
||||||
<title>修改账户</title>
|
<meta charset="UTF-8">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<script src="https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js"></script>
|
<title>修改账户</title>
|
||||||
<script>
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/modify.css') }}">
|
||||||
|
<script src="https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js"></script>
|
||||||
|
<script>
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
{% with messages = get_flashed_messages() %}
|
{% with messages = get_flashed_messages() %}
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
@ -20,77 +22,112 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<form action="#" method="post">
|
<header>
|
||||||
<ul>
|
<div class="header-content">
|
||||||
<div>
|
<a href="{{ url_for('index') }}" class="btn-back">返回主页</a>
|
||||||
<div>证件号码:</div>
|
<h1>KJF航班订票</h1>
|
||||||
<input type="text" id="cardCode" name="cardCode" placeholder="请输入您的证件号码" required>
|
<div class="header-spacer"></div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</header>
|
||||||
<li>
|
<main>
|
||||||
<div>
|
<div class="content">
|
||||||
<div>登陆密码:</div>
|
<h2>修改账户信息</h2>
|
||||||
<input type="password" id="password" placeholder="请输入您的密码" required>
|
<form action="#" method="post" id="modify-form">
|
||||||
<input id="encryptedPassword" name="encryptedPassword" type="hidden">
|
<div class="tab">
|
||||||
|
<button type="button" class="tablinks active" onclick="openTab(event, 'deleteAccount')">删除账户</button>
|
||||||
|
<button type="button" class="tablinks" onclick="openTab(event, 'modifyPassword')">修改密码</button>
|
||||||
|
<button type="button" class="tablinks" onclick="openTab(event, 'modifyPhone')">修改手机号</button>
|
||||||
|
<button type="button" class="tablinks" onclick="openTab(event, 'modifyUsername')">修改用户名</button>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" id="modifyType" name="modifyType" value="删除账户">
|
||||||
|
<div class="form-group">
|
||||||
|
<div>登陆密码:</div>
|
||||||
|
<input type="password" id="password" placeholder="请输入您的密码" required>
|
||||||
|
<input id="encryptedPassword" name="encryptedPassword" type="hidden">
|
||||||
|
</div>
|
||||||
|
<div id="deleteAccount" class="tabcontent">
|
||||||
|
<p>删除账户将无法恢复,请确认。</p>
|
||||||
|
</div>
|
||||||
|
<div id="modifyPassword" class="tabcontent" style="display:none">
|
||||||
|
<div class="form-group">
|
||||||
|
<div>新密码:</div>
|
||||||
|
<input type="password" id="newPassword" placeholder="6-20位字母、数字或符号">
|
||||||
|
<input id="encryptedNewPassword" name="encryptedNewPassword" type="hidden">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div>确认密码:</div>
|
||||||
|
<input type="password" id="confirmPassword" placeholder="再次输入您的新密码">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="modifyPhone" class="tabcontent" style="display:none">
|
||||||
|
<p>原手机号为:{{ current_user_phone }}</p>
|
||||||
|
<div class="form-group">
|
||||||
|
<div>新手机号:</div>
|
||||||
|
<input type="text" id="mobileNo" name="mobileNo" value title="手机号码" aria-label="手机号码" maxlength="11" placeholder="11位手机号">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="modifyUsername" class="tabcontent" style="display:none">
|
||||||
|
<p>原用户名为:{{ current_username }}</p>
|
||||||
|
<div class="form-group">
|
||||||
|
<div>新用户名:</div>
|
||||||
|
<input type="text" id="username" name="username" placeholder="请输入新的用户名">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button type="submit" onclick="return submitForm()">确认</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</main>
|
||||||
<li>
|
<footer>
|
||||||
<div>
|
<p>© 2024 KJF航班订票. 保留所有权利。</p>
|
||||||
<div>修改内容:</div>
|
</footer>
|
||||||
<select id="modifyType" name="modifyType" onchange="modify.showModifyPassword()" aria-label="请选择您的修改内容" title="请选择您的修改内容" required>
|
|
||||||
<option value="1">删除账户</option>
|
|
||||||
<option value="2">修改密码</option>
|
|
||||||
<option value="3">修改手机号</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="modifyPassword" style="display: none;">
|
|
||||||
<div>
|
|
||||||
<div>修改密码:</div>
|
|
||||||
<input type="password" id="newPassword" placeholder="6-20位字母、数字或符号">
|
|
||||||
<input id="encryptedNewPassword" name="encryptedNewPassword" type="hidden">
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="modifyPassword" style="display: none;">
|
|
||||||
<div>
|
|
||||||
<div>确认密码:</div>
|
|
||||||
<input type="password" id="confirmPassword" placeholder="再次输入您的修改密码">
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="modifymobileNo" style="display: none;">
|
|
||||||
<div>
|
|
||||||
<div>修改手机号:</div>
|
|
||||||
<input type="text" id="mobileNo" name="mobileNo" value title="手机号码" aria-label="手机号码" maxlength="11" placeholder="11位手机号">
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<div>
|
|
||||||
<button type="submit" onclick="return submitForm()">确认</button>
|
|
||||||
</div>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</form>
|
<script src="{{ url_for('static', filename='js/checkInfo.js') }}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/modify.js') }}"></script>
|
||||||
|
<script>
|
||||||
|
function submitForm() {
|
||||||
|
document.getElementById('encryptedPassword').value = md5(
|
||||||
|
document.getElementById('password').value
|
||||||
|
);
|
||||||
|
|
||||||
<script src="{{ url_for('static', filename='js/checkInfo.js') }}"></script>
|
let modifyType = document.querySelector('.tablinks.active').textContent;
|
||||||
<script src="{{ url_for('static', filename='js/modify.js') }}"></script>
|
document.getElementById('modifyType').value = modifyType;
|
||||||
<script>
|
|
||||||
function submitForm() {
|
|
||||||
document.getElementById('encryptedPassword').value = md5(
|
|
||||||
document.getElementById('password').value
|
|
||||||
)
|
|
||||||
|
|
||||||
let modifyType = document.getElementById('modifyType').value
|
if (modifyType === '删除账户') {
|
||||||
if (modifyType === '1') {
|
return true;
|
||||||
// document.getElementById('newPassword') = ''
|
} else if (modifyType === '修改密码') {
|
||||||
return true
|
document.getElementById('encryptedNewPassword').value = md5(
|
||||||
} else if (modifyType == '2') {
|
document.getElementById('newPassword').value
|
||||||
document.getElementById('encryptedNewPassword').value = md5(
|
);
|
||||||
document.getElementById('newPassword').value
|
return checkInfo.checkNewPassword();
|
||||||
)
|
} else if (modifyType === '修改手机号') {
|
||||||
return checkInfo.checkNewPassword()
|
return checkInfo.checkMobileNo();
|
||||||
} else if (modifyType == '3') {
|
} else if (modifyType === '修改用户名') {
|
||||||
return checkInfo.checkMobileNo()
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
|
||||||
|
function openTab(evt, tabName) {
|
||||||
|
var i, tabcontent, tablinks;
|
||||||
|
tabcontent = document.getElementsByClassName("tabcontent");
|
||||||
|
for (i = 0; i < tabcontent.length; i++) {
|
||||||
|
tabcontent[i].style.display = "none";
|
||||||
|
}
|
||||||
|
tablinks = document.getElementsByClassName("tablinks");
|
||||||
|
for (i = 0; i < tablinks.length; i++) {
|
||||||
|
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||||
|
}
|
||||||
|
document.getElementById(tabName).style.display = "block";
|
||||||
|
evt.currentTarget.className += " active";
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
let activeTab = document.querySelector('.tablinks.active');
|
||||||
|
if (activeTab) {
|
||||||
|
openTab({currentTarget: activeTab}, activeTab.getAttribute('onclick').split("'")[1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,115 +1,51 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
<head>
|
<head>
|
||||||
<title>我的12306注册</title>
|
<meta charset="UTF-8">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<script src="https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js"></script>
|
<title>注册 - KJF航班订票</title>
|
||||||
<script>
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/signup.css') }}">
|
||||||
window.onload = function() {
|
<script src="https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js"></script>
|
||||||
{% with messages = get_flashed_messages() %}
|
<script src="{{ url_for('static', filename='js/checkInfo.js') }}"></script>
|
||||||
{% if messages %}
|
<script src="{{ url_for('static', filename='js/signup.js') }}"></script>
|
||||||
var message = "";
|
|
||||||
{% for msg in messages %}
|
|
||||||
message += "{{ msg }}\n";
|
|
||||||
{% endfor %}
|
|
||||||
alert(message);
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<form action="#" method="post">
|
<form action="#" method="post" id="signupForm">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<div>
|
<div>
|
||||||
<div>用 户 名:</div>
|
<div>用户名:</div>
|
||||||
<input type="text" id="name" name="name" placeholder="用户名设置成功后不可修改" required>
|
<input type="text" id="username" name="username" placeholder="请输入用户名" required>
|
||||||
</div>
|
<div class="error-message">{{ errors.username }}</div>
|
||||||
</li>
|
</div>
|
||||||
<li>
|
</li>
|
||||||
<div>
|
<li>
|
||||||
<div>登陆密码:</div>
|
<div>
|
||||||
<input type="password" id="password" placeholder="6-20位字母、数字或符号" required>
|
<div>手机号:</div>
|
||||||
<input id="encryptedPassword" name="encryptedPassword" type="hidden">
|
<input type="text" id="mobileNo" name="mobileNo" placeholder="请输入手机号" maxlength="11" required>
|
||||||
</div>
|
<div class="error-message" id="mobileNoError">{{ errors.mobileNo }}</div>
|
||||||
</li>
|
</div>
|
||||||
<li>
|
</li>
|
||||||
<div>
|
<li>
|
||||||
<div>确认密码:</div>
|
<div>
|
||||||
<input type="password" id="confirmPassword" placeholder="再次输入您的登录密码" required>
|
<div>登录密码:</div>
|
||||||
</div>
|
<input type="password" id="password" placeholder="6-20位字母、数字或符号" required>
|
||||||
</li>
|
<input id="encryptedPassword" name="encryptedPassword" type="hidden">
|
||||||
<li>
|
<div class="error-message" id="passwordError">{{ errors.password }}</div>
|
||||||
<div>
|
</div>
|
||||||
<div>证件类型:</div>
|
</li>
|
||||||
<input name="cardTypeCode" id="cardTypeCode" value="1" type="hidden">
|
<li>
|
||||||
<select id="cardType" aria-label="请选择您的证件类型" title="请选择您的证件类型" required>
|
<div>
|
||||||
<option value="1">中国居民身份证</option>
|
<div>确认密码:</div>
|
||||||
<option value="1">港澳台居民身份证</option>
|
<input type="password" id="confirmPassword" placeholder="再次输入您的登录密码" required>
|
||||||
</select>
|
<input id="encryptedConfirmPassword" name="encryptedConfirmPassword" type="hidden">
|
||||||
</div>
|
<div class="error-message" id="confirmPasswordError">{{ errors.confirmPassword }}</div>
|
||||||
</li>
|
</div>
|
||||||
<li>
|
</li>
|
||||||
<div>
|
<div>
|
||||||
<div>姓 名:</div>
|
<button type="submit" onclick="return submitForm()">注册</button>
|
||||||
<input type="text" id="regist_name" name="regist_name" placeholder="请输入姓名" required>
|
</div>
|
||||||
</div>
|
</ul>
|
||||||
</li>
|
</form>
|
||||||
<li>
|
|
||||||
<div>
|
|
||||||
<div>证件号码:</div>
|
|
||||||
<input type="text" id="cardCode" name="cardCode" placeholder="请输入您的证件号码" maxlength="18" required>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div>
|
|
||||||
<div>优惠(待)类型:</div>
|
|
||||||
<select id="passengerType" name="passengerType" aria-label="请选择旅客类型" title="请选择旅客类型" required>
|
|
||||||
<option value="1">成人</option>
|
|
||||||
<option value="2">儿童</option>
|
|
||||||
<option value="3">学生</option>
|
|
||||||
<option value="4">残疾军人</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li style="height: 1px;border-top: 1px dashed #DEDEDE;margin: 15px 0;"></li>
|
|
||||||
<li>
|
|
||||||
<div>
|
|
||||||
<div>邮 箱:</div>
|
|
||||||
<input type="text" id="email" name="email" title="请正确填写邮箱地址" placeholder="请正确填写邮箱地址" aria-label="请正确填写邮箱地址" required>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div>
|
|
||||||
<div>手机号码:</div>
|
|
||||||
<div>
|
|
||||||
<select id="mobileCode" name="mobileCode" required>
|
|
||||||
<option value="86">+86 中国</option>
|
|
||||||
</select>
|
|
||||||
<input type="text" id="mobileNo" name="mobileNo" value title="手机号码" aria-label="手机号码" maxlength="11" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<div>
|
|
||||||
<button type="submit" onclick="return submitForm()">下一步</button>
|
|
||||||
</div>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<script src="{{ url_for('static', filename='js/checkInfo.js') }}"></script>
|
|
||||||
<script>
|
|
||||||
function submitForm() {
|
|
||||||
if (checkInfo.checkCardCode() && checkInfo.checkMobileNo() && checkInfo.checkPassword()) {
|
|
||||||
document.getElementById('encryptedPassword').value = md5(
|
|
||||||
document.getElementById('password').value
|
|
||||||
)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
x
Reference in New Issue
Block a user