282 lines
14 KiB
HTML
282 lines
14 KiB
HTML
<!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/book.css') }}">
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<div class="header-content">
|
|
<div class="logo">KJF航班订票</div>
|
|
<div class="nav-buttons">
|
|
<a href="{{ url_for('index') }}">首页</a>
|
|
<a href="{{ url_for('order_list') }}">我的订单</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>
|
|
<h2>预定航班</h2>
|
|
<div class="flight-info">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>航班号</th>
|
|
<th>航空公司</th>
|
|
<th>出发机场</th>
|
|
<th>到达机场</th>
|
|
<th>出发时间</th>
|
|
<th>到达时间</th>
|
|
<th>头等舱剩余座位</th>
|
|
<th>商务舱剩余座位</th>
|
|
<th>经济舱剩余座位</th>
|
|
<th>头等舱价格</th>
|
|
<th>商务舱价格</th>
|
|
<th>经济舱价格</th>
|
|
<th>状态</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="flight-row">
|
|
<td>{{ flight.ID }}</td>
|
|
<td>{{ flight.Airline }}</td>
|
|
<td>{{ flight.Departure_airport_name }}</td>
|
|
<td>{{ flight.Arrival_airport_name }}</td>
|
|
<td>{{ flight.Departure_time }}</td>
|
|
<td>{{ flight.Arrival_time }}</td>
|
|
<td id="first-class-seats">{{ flight.First_class_seats_remaining }}</td>
|
|
<td id="business-class-seats">{{ flight.Business_class_seats_remaining }}</td>
|
|
<td id="economy-class-seats">{{ flight.Economy_class_seats_remaining }}</td>
|
|
<td id="first-class-price">{{ flight.First_class_price }}</td>
|
|
<td id="business-class-price">{{ flight.Business_class_price }}</td>
|
|
<td id="economy-class-price">{{ flight.Economy_class_price }}</td>
|
|
<td>{{ flight.Status }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<form id="booking-form" method="post" action="{{ url_for('book', flight_id=flight.ID) }}" onsubmit="return validateBookingForm()">
|
|
<div id="passenger-list">
|
|
<div class="passenger" data-index="0">
|
|
<h3>乘机人 1</h3>
|
|
<button type="button" class="delete-btn" onclick="removePassenger(this)">删除</button>
|
|
<div class="form-row">
|
|
<label for="card-code-0">身份证号:</label>
|
|
<input type="text" id="card-code-0" name="passengers[0][card_code]" oninput="validateCardCode(this)">
|
|
<div class="error-message" id="card-code-error-0"></div>
|
|
</div>
|
|
<div class="form-row">
|
|
<label for="name-0">真实姓名:</label>
|
|
<input type="text" id="name-0" name="passengers[0][name]">
|
|
</div>
|
|
<div class="form-row">
|
|
<label for="phone-number-0">手机号:</label>
|
|
<input type="text" id="phone-number-0" name="passengers[0][phone_number]" oninput="validatePhoneNumber(this)">
|
|
<div class="error-message" id="phone-number-error-0"></div>
|
|
</div>
|
|
<div class="form-row">
|
|
<label for="seat-class-0">座位级别:</label>
|
|
<select id="seat-class-0" name="passengers[0][seat_class]" onchange="updateSeatCount(this)">
|
|
<option value="" disabled selected>请选择座位级别</option>
|
|
<option value="First Class">头等舱</option>
|
|
<option value="Business Class">商务舱</option>
|
|
<option value="Economy Class">经济舱</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="total-price">
|
|
总价: <span id="total-price">0</span> 元
|
|
</div>
|
|
<button type="button" class="btn" onclick="addPassenger()">添加乘机人</button>
|
|
<button type="submit" class="btn">预定</button>
|
|
</form>
|
|
</main>
|
|
<footer>
|
|
<p>© 2024 KJF航班订票. 保留所有权利。</p>
|
|
</footer>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Initialize seat counts
|
|
var passengerCount = 1;
|
|
var firstClassSeats = {{ flight.First_class_seats_remaining }};
|
|
var businessClassSeats = {{ flight.Business_class_seats_remaining }};
|
|
var economyClassSeats = {{ flight.Economy_class_seats_remaining }};
|
|
var firstClassPrice = parseFloat(document.getElementById("first-class-price").textContent);
|
|
var businessClassPrice = parseFloat(document.getElementById("business-class-price").textContent);
|
|
var economyClassPrice = parseFloat(document.getElementById("economy-class-price").textContent);
|
|
|
|
window.addPassenger = function() {
|
|
passengerCount++;
|
|
const passengerList = document.getElementById('passenger-list');
|
|
const passengerDiv = document.createElement('div');
|
|
passengerDiv.classList.add('passenger');
|
|
passengerDiv.setAttribute('data-index', passengerCount - 1);
|
|
|
|
const disabledFirstClass = firstClassSeats <= 0 ? 'disabled' : '';
|
|
const disabledBusinessClass = businessClassSeats <= 0 ? 'disabled' : '';
|
|
const disabledEconomyClass = economyClassSeats <= 0 ? 'disabled' : '';
|
|
|
|
passengerDiv.innerHTML = `
|
|
<h3>乘机人 ${passengerCount}</h3>
|
|
<button type="button" class="delete-btn" onclick="removePassenger(this)">删除</button>
|
|
<div class="form-row">
|
|
<label for="card-code-${passengerCount - 1}">身份证号:</label>
|
|
<input type="text" id="card-code-${passengerCount - 1}" name="passengers[${passengerCount - 1}][card_code]" oninput="validateCardCode(this)">
|
|
<div class="error-message" id="card-code-error-${passengerCount - 1}"></div>
|
|
</div>
|
|
<div class="form-row">
|
|
<label for="name-${passengerCount - 1}">真实姓名:</label>
|
|
<input type="text" id="name-${passengerCount - 1}" name="passengers[${passengerCount - 1}][name]">
|
|
</div>
|
|
<div class="form-row">
|
|
<label for="phone-number-${passengerCount - 1}">手机号:</label>
|
|
<input type="text" id="phone-number-${passengerCount - 1}" name="passengers[${passengerCount - 1}][phone_number]" oninput="validatePhoneNumber(this)">
|
|
<div class="error-message" id="phone-number-error-${passengerCount - 1}"></div>
|
|
</div>
|
|
<div class="form-row">
|
|
<label for="seat-class-${passengerCount - 1}">座位级别:</label>
|
|
<select id="seat-class-${passengerCount - 1}" name="passengers[${passengerCount - 1}][seat_class]" onchange="updateSeatCount(this)">
|
|
<option value="" disabled selected>请选择座位级别</option>
|
|
<option value="First Class" ${disabledFirstClass}>头等舱</option>
|
|
<option value="Business Class" ${disabledBusinessClass}>商务舱</option>
|
|
<option value="Economy Class" ${disabledEconomyClass}>经济舱</option>
|
|
</select>
|
|
</div>
|
|
`;
|
|
|
|
passengerList.appendChild(passengerDiv);
|
|
};
|
|
|
|
window.removePassenger = function(button) {
|
|
const passengerDiv = button.parentElement;
|
|
const index = passengerDiv.getAttribute('data-index');
|
|
const seatClassSelect = document.getElementById(`seat-class-${index}`);
|
|
const seatClass = seatClassSelect.value;
|
|
|
|
if (seatClass === 'First Class') firstClassSeats++;
|
|
else if (seatClass === 'Business Class') businessClassSeats++;
|
|
else if (seatClass === 'Economy Class') economyClassSeats++;
|
|
|
|
passengerDiv.remove();
|
|
updateSeatDisplay();
|
|
calculateTotalPrice();
|
|
};
|
|
|
|
window.validateCardCode = function(input) {
|
|
const 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]$/;
|
|
const errorDiv = document.getElementById(`card-code-error-${input.id.split('-')[2]}`);
|
|
if (!regexCardCode.test(input.value)) {
|
|
errorDiv.textContent = '身份证号格式不正确';
|
|
} else {
|
|
errorDiv.textContent = '';
|
|
}
|
|
};
|
|
|
|
window.validatePhoneNumber = function(input) {
|
|
const regexMobileNo = /^1[3-9]\d{9}$/;
|
|
const errorDiv = document.getElementById(`phone-number-error-${input.id.split('-')[2]}`);
|
|
if (!regexMobileNo.test(input.value)) {
|
|
errorDiv.textContent = '手机号格式不正确';
|
|
} else {
|
|
errorDiv.textContent = '';
|
|
}
|
|
};
|
|
|
|
window.updateSeatCount = function(select) {
|
|
const index = select.id.split('-')[2];
|
|
const previousClass = select.getAttribute("data-previous-class");
|
|
const newClass = select.value;
|
|
|
|
if (previousClass) {
|
|
if (previousClass === 'First Class') firstClassSeats++;
|
|
else if (previousClass === 'Business Class') businessClassSeats++;
|
|
else if (previousClass === 'Economy Class') economyClassSeats++;
|
|
}
|
|
|
|
if (newClass === 'First Class') {
|
|
if (firstClassSeats <= 0) {
|
|
alert("头等舱座位已满");
|
|
select.value = "";
|
|
return;
|
|
}
|
|
firstClassSeats--;
|
|
} else if (newClass === 'Business Class') {
|
|
if (businessClassSeats <= 0) {
|
|
alert("商务舱座位已满");
|
|
select.value = "";
|
|
return;
|
|
}
|
|
businessClassSeats--;
|
|
} else if (newClass === 'Economy Class') {
|
|
if (economyClassSeats <= 0) {
|
|
alert("经济舱座位已满");
|
|
select.value = "";
|
|
return;
|
|
}
|
|
economyClassSeats--;
|
|
}
|
|
|
|
select.setAttribute("data-previous-class", newClass);
|
|
updateSeatDisplay();
|
|
calculateTotalPrice();
|
|
};
|
|
|
|
function updateSeatDisplay() {
|
|
document.getElementById("first-class-seats").textContent = firstClassSeats;
|
|
document.getElementById("business-class-seats").textContent = businessClassSeats;
|
|
document.getElementById("economy-class-seats").textContent = economyClassSeats;
|
|
}
|
|
|
|
function calculateTotalPrice() {
|
|
let totalPrice = 0;
|
|
const seatClassSelects = document.querySelectorAll("select[id^='seat-class-']");
|
|
seatClassSelects.forEach(select => {
|
|
if (select.value === 'First Class') totalPrice += firstClassPrice;
|
|
else if (select.value === 'Business Class') totalPrice += businessClassPrice;
|
|
else if (select.value === 'Economy Class') totalPrice += economyClassPrice;
|
|
});
|
|
document.getElementById("total-price").textContent = totalPrice.toFixed(2);
|
|
}
|
|
|
|
window.validateBookingForm = function() {
|
|
// Validate seat availability
|
|
if (firstClassSeats < 0 || businessClassSeats < 0 || economyClassSeats < 0) {
|
|
alert("预定的座位数不能超过余座数");
|
|
return false;
|
|
}
|
|
|
|
// Validate all card codes and phone numbers
|
|
const cardCodes = document.querySelectorAll("input[id^='card-code-']");
|
|
const phoneNumbers = document.querySelectorAll("input[id^='phone-number-']");
|
|
for (let cardCode of cardCodes) {
|
|
validateCardCode(cardCode);
|
|
if (document.getElementById(`card-code-error-${cardCode.id.split('-')[2]}`).textContent !== '') {
|
|
return false;
|
|
}
|
|
}
|
|
for (let phoneNumber of phoneNumbers) {
|
|
validatePhoneNumber(phoneNumber);
|
|
if (document.getElementById(`phone-number-error-${phoneNumber.id.split('-')[2]}`).textContent !== '') {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
};
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|