初步完成登录、注册、修改账号、主页内容

This commit is contained in:
Jingfan Ke 2024-06-13 13:53:54 +08:00
parent e48e752b91
commit ad767a806b
31 changed files with 1291 additions and 488 deletions

Binary file not shown.

View File

@ -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 Seats;
DROP TABLE IF EXISTS Flights;
DROP TABLE IF EXISTS Airports;
DROP TABLE IF EXISTS Users;
DROP TABLE IF EXISTS Passengers;
DROP TABLE IF EXISTS Rides;
DROP TABLE IF EXISTS Trains;
DROP TABLE IF EXISTS Stations;
CREATE TABLE Passengers (
ID BIGINT PRIMARY KEY,
`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(Phone_number, '^\\d{11}$'))
);
CREATE TABLE Users (
ID INT AUTO_INCREMENT PRIMARY KEY,
Phone_number BIGINT PRIMARY KEY,
Username VARCHAR(255) NOT NULL,
`Password` VARCHAR(255) NOT NULL,
Phone_number BIGINT UNIQUE NOT NULL,
CitizenID BIGINT UNIQUE NOT NULL,
FOREIGN KEY ( Phone_number ) REFERENCES Passengers ( Phone_number ) ON DELETE CASCADE,
FOREIGN KEY ( CitizenID ) REFERENCES Passengers ( ID ) ON DELETE CASCADE
CHECK (REGEXP_LIKE(Phone_number, '^\\d{11}$'))
);
CREATE TABLE Stations (
CREATE TABLE Airports (
ID INT AUTO_INCREMENT PRIMARY KEY,
`Name` VARCHAR(255) UNIQUE NOT NULL,
Province VARCHAR ( 255 ) NOT NULL,
Country VARCHAR(255) NOT NULL,
City VARCHAR(255) NOT NULL
);
CREATE TABLE Trains (
CREATE TABLE Flights (
ID VARCHAR(255) PRIMARY KEY,
TrainName VARCHAR ( 255 ) NOT NULL,
StationID_start INT NOT NULL,
StationID_arrive INT NOT NULL,
FOREIGN KEY ( StationID_start ) REFERENCES Stations ( ID ) ON DELETE CASCADE,
FOREIGN KEY ( StationID_arrive ) REFERENCES Stations ( ID ) ON DELETE CASCADE
);
CREATE TABLE Seats (
ID VARCHAR ( 255 ) PRIMARY KEY,
Type VARCHAR ( 255 ) NOT NULL,
TrainID VARCHAR ( 255 ) NOT NULL,
FOREIGN KEY ( TrainID ) REFERENCES Trains ( ID ) ON DELETE CASCADE
Airline VARCHAR(255) NOT NULL,
Departure_airport INT NOT NULL,
Arrival_airport INT NOT NULL,
Departure_time DATETIME NOT NULL,
Arrival_time DATETIME NOT NULL,
First_class_seats_remaining INT NOT NULL, -- 头等舱剩余座位
Business_class_seats_remaining INT NOT NULL, -- 商务舱剩余座位
Economy_class_seats_remaining INT NOT NULL, -- 经济舱剩余座位
First_class_price DECIMAL(7, 2) NOT NULL, -- 头等舱价格
Business_class_price DECIMAL(7, 2) NOT NULL, -- 商务舱价格
Economy_class_price DECIMAL(7, 2) NOT NULL, -- 经济舱价格
`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 (
ID INT AUTO_INCREMENT PRIMARY KEY,
Price DECIMAL(7, 2) NOT NULL,
Time_start DATETIME NOT NULL,
Time_arrive DATETIME NOT NULL,
StationID_start INT NOT NULL,
StationID_arrive INT NOT NULL,
SeatID VARCHAR ( 255 ) NOT NULL,
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 Transactions (
ID BIGINT AUTO_INCREMENT PRIMARY KEY,
`Time` DATETIME NOT NULL,
Paid TINYINT NOT NULL,
`User` INT NOT NULL,
FlightID VARCHAR(255) NOT NULL,
Seat_class VARCHAR(255) 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,
Paid TINYINT NOT NULL,
FOREIGN KEY (FlightID) REFERENCES Flights(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 )
CHECK (Seat_class IN ('First Class', 'Business Class', 'Economy Class'))
);

Binary file not shown.

Binary file not shown.

18
Project/func/config.py Normal file
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

@ -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():
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
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

@ -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 pymysql.cursors import Cursor
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:
def __init__(self, form:Dict[str, str]):
self.id = form['cardCode']
def __init__(self, form: Dict[str, str], user_phone: str):
self.phone_number = user_phone
print(form)
modifyType = form['modifyType']
self.new_password = form['encryptedNewPassword']
self.phone_number = form['mobileNo']
self.new_password = form.get('encryptedNewPassword', None)
self.new_phone_number = form.get('mobileNo', None)
self.new_username = form.get('username', None)
modifyType2command = {
'1':'delete account',
'2':'modify Password',
'3':'modify Phone_Number'
'删除账户': 'delete account',
'修改密码': 'modify Password',
'修改手机号': 'modify Phone_Number',
'修改用户名': 'modify Username'
}
self.sql_dict = {
'delete account': 'DELETE FROM passengers WHERE ID = %s;',
'modify Password': 'UPDATE passengers SET `Password` = %s WHERE ID = %s;',
'modify Phone_Number': 'UPDATE passengers SET Phone_number = %s WHERE ID = %s;'
'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.id,),
'modify Password': (self.new_password, self.id),
'modify Phone_Number': (self.phone_number, self.id)
'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 Phone_Number': "修改手机号成功",
'modify Username': "修改用户名成功"
}
self.fail_message_dict = {
'delete account': "数据库异常,删除账户失败",
'modify Password': "数据库异常,修改密码失败",
'modify Phone_Number': "数据库异常,修改手机号失败"
'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':
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':
id = request.form['cardCode']
user_phone = session.get('user_id')
password = request.form['encryptedPassword']
db = get_db()
cursor = db.cursor()
verify_info = verify_user(cursor, id, password)
if (verify_info == "NO_USER"):
flash("您未注册过,无法修改账号")
db.close()
return redirect(url_for('signup'))
elif (verify_info == "WRONG_PASSWORD"):
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("密码错误")
db.close()
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:
cursor.execute(modifyInfo.get_sql(), modifyInfo.get_args())
db.commit()
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:
db.rollback()
print(e)
flash(modifyInfo.get_fail_message())
db.close()
return redirect(url_for('index'))
return redirect(url_for('modify'))

View File

@ -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
import re
def signup():
error_messages = {
'username': '',
'mobileNo': '',
'password': '',
'confirmPassword': ''
}
if request.method == 'GET':
return render_template('signup.html')
return render_template('signup.html', errors=error_messages)
if request.method == 'POST':
id = request.form['cardCode']
name = request.form['name']
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)
db = get_db()
cursor = db.cursor()
@ -17,32 +40,34 @@ def signup():
# 检查已有用户
sql = """
SELECT COUNT(*) FROM Users \
WHERE ID = %s;
WHERE Phone_number = %s;
"""
try:
cursor.execute(sql, (id,))
id_exist = cursor.fetchall()[0][0]
cursor.execute(sql, (phone_number,))
phone_exist = cursor.fetchall()[0][0]
except Exception as e:
flash("数据库异常,查询失败")
error_messages['mobileNo'] = "数据库异常,查询失败"
print(e)
return redirect(url_for('signup'))
if (id_exist != 0):
flash("您已注册过,请勿重复注册")
return render_template('signup.html', errors=error_messages)
if phone_exist != 0:
error_messages['mobileNo'] = "该手机号已注册,请勿重复注册"
db.close()
return redirect(url_for('index'))
return render_template('signup.html', errors=error_messages)
# 插入
sql = '''
INSERT INTO passengers (ID, `Name`, Phone_number, `Password`) \
VALUES (%s, %s, %s, %s); \
INSERT INTO Users (Phone_number, Username, `Password`) \
VALUES (%s, %s, %s); \
'''
try:
cursor.execute(sql, (id, name, phone_number, password))
cursor.execute(sql, (phone_number, username, password))
db.commit()
flash("注册成功")
return redirect(url_for('index'))
except Exception as e:
db.rollback()
print(e)
flash("数据库异常,注册失败")
error_messages['mobileNo'] = "数据库异常,注册失败"
return render_template('signup.html', errors=error_messages)
finally:
db.close()
return redirect(url_for('index'))

View File

@ -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"

View File

@ -1,22 +1,80 @@
from flask import Flask
import os
from flask import Flask, redirect, url_for, session, render_template, request, g
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.modify
import func.index
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("/")
def home():
return redirect(url_for('index'))
@app.route("/index", methods=['GET', 'POST'])
def 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():
return func.signup.signup()
@app.route("/modify.html", methods=('GET', 'POST'))
@app.route("/modify", methods=['GET', 'POST'])
def modify():
if request.method == 'GET':
if not g.user:
return redirect(url_for("login"))
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
)

View File

@ -7,53 +7,124 @@ body {
display: flex;
flex-direction: column;
align-items: center;
overflow-x: hidden; /* 防止出现水平滚动条 */
}
header {
display: flex;
justify-content: space-between;
align-items: center;
background-color: rgba(28, 108, 178, 0.9);
color: white;
padding: 20px 0;
text-align: center;
padding: 20px;
width: 100%;
}
nav ul {
list-style: none;
padding: 0;
margin: 0;
.header-content {
display: flex;
align-items: center;
width: 100%;
justify-content: space-between;
}
nav ul li {
display: inline;
margin: 0 10px;
.logo {
font-size: 24px;
font-weight: bold;
margin-left: 20px;
}
nav ul li a {
.nav-buttons {
display: flex;
gap: 20px;
}
.nav-buttons a {
color: white;
text-decoration: none;
font-weight: bold;
font-size: 16px;
padding: 10px;
border-radius: 5px;
}
main {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
.nav-buttons a:hover {
background-color: #155a8c;
}
.background-container {
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;
.user-menu {
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 {
@ -61,28 +132,79 @@ main {
padding: 20px;
border-radius: 10px;
text-align: center;
position: absolute;
width: 80%;
max-width: 800px;
margin: -50px auto 20px;
position: relative;
}
h2 {
color: #1c6cb2;
.tabcontent {
display: block;
padding: 20px;
}
.links {
margin-top: 20px;
.form-row {
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;
color: white;
padding: 10px 20px;
text-decoration: none;
border: none;
border-radius: 5px;
margin: 10px;
display: inline-block;
cursor: pointer;
}
.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;
}
@ -92,4 +214,12 @@ footer {
text-align: center;
padding: 10px 0;
width: 100%;
margin-top: auto;
}
.error-message {
color: red;
font-size: 12px;
text-align: left;
margin-top: 5px;
}

View 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;
}

View 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%;
}

View 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;
}

View File

@ -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

View File

@ -1,51 +1,15 @@
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
}
var checkInfo = {};
checkInfo.checkMobileNo = function() {
let mobileNo = document.getElementById('mobileNo').value
let regexMobileNo = /^1[3-9]\d{9}$/
if (!regexMobileNo.test(mobileNo)) {
alert('手机号格式有误')
return false
}
return true
let mobileNo = document.getElementById('mobileNo').value;
let regexMobileNo = /^1[3-9]\d{9}$/;
return regexMobileNo.test(mobileNo);
}
checkInfo.checkPassword = function() {
let password = document.getElementById('password')
let regexPassword = /^[A-Za-z0-9\W_]{6,20}$/
if (!regexPassword.test(password.value)) {
alert("密码须为长度为6-20位字母、数字或符号")
return false
}
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
let password = document.getElementById('password').value;
let regexPassword = /^[A-Za-z0-9\W_]{6,20}$/;
let isValidPassword = regexPassword.test(password);
let confirmPassword = document.getElementById('confirmPassword').value;
return isValidPassword && (password === confirmPassword);
}

View File

@ -1,8 +1,29 @@
window.onload = function() {
// Display flashed messages, if any
const messages = [];
// Assuming messages are added via server-side templating
if (messages.length > 0) {
alert(messages.join("\n"));
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;
}
}
};

View 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 = '自动登录失败';
}
}
}

View File

@ -1,28 +1,31 @@
var modify = {}
var modify = {};
modify.showModifyPassword = function() {
let modifyType = document.getElementById('modifyType').value
let modifyType = document.querySelector('.tablinks.active').textContent;
let info = {
modifyPasswordLis: document.getElementsByClassName('modifyPassword'),
modifymobileNoLis: document.getElementsByClassName('modifymobileNo'),
modifyUsernameLis: document.getElementsByClassName('modifyUsername'),
}
// 遍历隐藏所有元素
for (let key in info) {
let elements = info[key];
for (let item of elements) {
item.style.display = 'none'; // 确保所有相关元素被隐藏
item.style.display = 'none';
}
}
// 根据 modifyType 显示相关元素
if (modifyType === "2") {
if (modifyType === "修改密码") {
for (let item of info.modifyPasswordLis) {
item.style.display = 'block';
}
} else if (modifyType === "3") {
} else if (modifyType === "修改手机号") {
for (let item of info.modifymobileNoLis) {
item.style.display = 'block';
}
} else if (modifyType === "修改用户名") {
for (let item of info.modifyUsernameLis) {
item.style.display = 'block';
}
}
}

View 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 = '';
}

View 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();

View File

@ -3,34 +3,129 @@
<head>
<meta charset="UTF-8">
<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') }}">
<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>
<body>
<header>
<h1>中国铁路12306</h1>
<nav>
<ul>
<li><a href="{{ url_for('index') }}">首页</a></li>
<li><a href="{{ url_for('signup') }}">注册</a></li>
<li><a href="{{ url_for('modify') }}">修改账号</a></li>
</ul>
</nav>
<div class="header-content">
<div class="logo">KJF航班订票</div>
<div class="nav-buttons">
<a href="{{ url_for('index') }}">首页</a>
<a href="{{ url_for('orders') }}">我的订单</a>
</div>
<div class="user-menu">
<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>
<main>
<div class="background-container">
<div class="content">
<h2>尽享精彩出行服务</h2>
<div class="links">
<a class="btn" href="{{ url_for('signup') }}">点击跳转注册</a>
<a class="btn" href="{{ url_for('modify') }}">点击跳转修改账号</a>
<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">
<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>
</main>
<footer>
<p>&copy; 2024 中国铁路12306. 保留所有权利。</p>
<p>&copy; 2024 KJF航班订票. 保留所有权利。</p>
</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>
</html>

View 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>&copy; 2024 KJF航班订票. 保留所有权利。</p>
</footer>
<script src="{{ url_for('static', filename='js/slideshow.js') }}"></script>
</body>
</html>

View File

@ -1,8 +1,10 @@
<!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/style.css') }}">
<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() {
@ -20,55 +22,66 @@
</head>
<body>
<form action="#" method="post">
<ul>
<div>
<div>证件号码:</div>
<input type="text" id="cardCode" name="cardCode" placeholder="请输入您的证件号码" required>
<header>
<div class="header-content">
<a href="{{ url_for('index') }}" class="btn-back">返回主页</a>
<h1>KJF航班订票</h1>
<div class="header-spacer"></div>
</div>
</li>
<li>
<div>
</header>
<main>
<div class="content">
<h2>修改账户信息</h2>
<form action="#" method="post" id="modify-form">
<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>
</li>
<li>
<div>
<div>修改内容:</div>
<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 id="deleteAccount" class="tabcontent">
<p>删除账户将无法恢复,请确认。</p>
</div>
</li>
<li class="modifyPassword" style="display: none;">
<div>
<div>修改密码:</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>
</li>
<li class="modifyPassword" style="display: none;">
<div>
<div class="form-group">
<div>确认密码:</div>
<input type="password" id="confirmPassword" placeholder="再次输入您的修改密码">
<input type="password" id="confirmPassword" placeholder="再次输入您的新密码">
</div>
</li>
<li class="modifymobileNo" style="display: none;">
<div>
<div>修改手机号:</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>
</li>
<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>
</ul>
</form>
</div>
</main>
<footer>
<p>&copy; 2024 KJF航班订票. 保留所有权利。</p>
</footer>
<script src="{{ url_for('static', filename='js/checkInfo.js') }}"></script>
<script src="{{ url_for('static', filename='js/modify.js') }}"></script>
@ -76,21 +89,45 @@
function submitForm() {
document.getElementById('encryptedPassword').value = md5(
document.getElementById('password').value
)
);
let modifyType = document.getElementById('modifyType').value
if (modifyType === '1') {
// document.getElementById('newPassword') = ''
return true
} else if (modifyType == '2') {
let modifyType = document.querySelector('.tablinks.active').textContent;
document.getElementById('modifyType').value = modifyType;
if (modifyType === '删除账户') {
return true;
} else if (modifyType === '修改密码') {
document.getElementById('encryptedNewPassword').value = md5(
document.getElementById('newPassword').value
)
return checkInfo.checkNewPassword()
} else if (modifyType == '3') {
return checkInfo.checkMobileNo()
);
return checkInfo.checkNewPassword();
} else if (modifyType === '修改手机号') {
return checkInfo.checkMobileNo();
} else if (modifyType === '修改用户名') {
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";
}
document.addEventListener('DOMContentLoaded', function() {
let activeTab = document.querySelector('.tablinks.active');
if (activeTab) {
openTab({currentTarget: activeTab}, activeTab.getAttribute('onclick').split("'")[1]);
}
});
</script>
</body>
</html>

View File

@ -1,115 +1,51 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>我的12306注册</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>注册 - KJF航班订票</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/signup.css') }}">
<script src="https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js"></script>
<script>
window.onload = function() {
{% with messages = get_flashed_messages() %}
{% if messages %}
var message = "";
{% for msg in messages %}
message += "{{ msg }}\n";
{% endfor %}
alert(message);
{% endif %}
{% endwith %}
};
</script>
<script src="{{ url_for('static', filename='js/checkInfo.js') }}"></script>
<script src="{{ url_for('static', filename='js/signup.js') }}"></script>
</head>
<body>
<form action="#" method="post">
<form action="#" method="post" id="signupForm">
<ul>
<li>
<div>
<div>用户名:</div>
<input type="text" id="name" name="name" placeholder="用户名设置成功后不可修改" required>
<input type="text" id="username" name="username" placeholder="请输入用户名" required>
<div class="error-message">{{ errors.username }}</div>
</div>
</li>
<li>
<div>
<div>登陆密码:</div>
<div>手机号:</div>
<input type="text" id="mobileNo" name="mobileNo" placeholder="请输入手机号" maxlength="11" required>
<div class="error-message" id="mobileNoError">{{ errors.mobileNo }}</div>
</div>
</li>
<li>
<div>
<div>登录密码:</div>
<input type="password" id="password" placeholder="6-20位字母、数字或符号" required>
<input id="encryptedPassword" name="encryptedPassword" type="hidden">
<div class="error-message" id="passwordError">{{ errors.password }}</div>
</div>
</li>
<li>
<div>
<div>确认密码:</div>
<input type="password" id="confirmPassword" placeholder="再次输入您的登录密码" required>
</div>
</li>
<li>
<div>
<div>证件类型:</div>
<input name="cardTypeCode" id="cardTypeCode" value="1" type="hidden">
<select id="cardType" aria-label="请选择您的证件类型" title="请选择您的证件类型" required>
<option value="1">中国居民身份证</option>
<option value="1">港澳台居民身份证</option>
</select>
</div>
</li>
<li>
<div>
<div>姓 名:</div>
<input type="text" id="regist_name" name="regist_name" placeholder="请输入姓名" required>
</div>
</li>
<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>
<input id="encryptedConfirmPassword" name="encryptedConfirmPassword" type="hidden">
<div class="error-message" id="confirmPasswordError">{{ errors.confirmPassword }}</div>
</div>
</li>
<div>
<button type="submit" onclick="return submitForm()">下一步</button>
<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>
</html>