预约功能更新

This commit is contained in:
vijay 2024-09-02 14:47:14 +08:00
parent 87e791e853
commit f5f09c89da
4 changed files with 260 additions and 113 deletions

View File

@ -202,6 +202,65 @@ class Customers extends EA_Controller
} }
} }
/**
* Filter customers by the provided keyword.
*/
public function search_by_phone(): void
{
$phoneNumber = request('phone_number', '');
if (empty($phoneNumber)) {
// 返回错误信息
echo json_encode(['success' => false, 'message' => 'Invalid phone number']);
return;
}
// 查询数据库中的预约信息
$appointments = $this->appointments_model->get_appointments_by_phone($phoneNumber);
foreach ($appointments as &$appointment) {
$this->appointments_model->load($appointment, ['service', 'provider']);
}
if (!empty($appointments)) {
// 返回预约信息
echo json_encode(['success' => true, 'appointments' => $appointments]);
} else {
// 如果没有找到预约信息
echo json_encode(['success' => false, 'message' => 'No appointments found']);
}
}
public function cancel(): void
{
try {
$appointmentId = request('appointmentId');
// 查找指定的预约记录
$appointment = $this->appointments_model->find($appointmentId);
if ($appointment) {
// 更新状态为 '取消'
$appointment['status'] = '取消';
// 保存更新后的预约记录
$this->appointments_model->save($appointment);
json_response([
'success' => true,
'id' => $appointmentId,
]);
} else {
// 处理预约记录不存在的情况
json_response([
'success' => false,
'message' => '預約記錄不存在。',
], 404);
}
} catch (Throwable $e) {
json_exception($e);
}
}
/** /**
* Store a new customer. * Store a new customer.
*/ */

View File

@ -649,7 +649,7 @@ class Appointments_model extends EA_Model
->like('providers.phone_number', $phone_number) ->like('providers.phone_number', $phone_number)
->or_like('customers.phone_number', $phone_number) ->or_like('customers.phone_number', $phone_number)
->group_end() ->group_end()
->where('appointments.start_datetime >=', date('Y-m-d H:i:s')) // 过滤掉当天00点之前的预约 // ->where('appointments.start_datetime >=', date('Y-m-d H:i:s')) // 过滤掉当天00点之前的预约
->limit($limit) ->limit($limit)
->offset($offset) ->offset($offset)
->order_by($order_by) ->order_by($order_by)
@ -662,4 +662,5 @@ class Appointments_model extends EA_Model
return $appointments; return $appointments;
} }
} }

View File

@ -1,5 +1,6 @@
<!doctype html> <!doctype html>
<html lang="<?= config('language_code') ?>"> <html lang="<?= config('language_code') ?>">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
@ -7,9 +8,9 @@
<meta name="theme-color" content="#35A768"> <meta name="theme-color" content="#35A768">
<meta name="google" content="notranslate"> <meta name="google" content="notranslate">
<meta property="og:title" content="<?= lang('page_title') . ' ' . vars('company_name') ?> | TFE Group"/> <meta property="og:title" content="<?= lang('page_title') . ' ' . vars('company_name') ?> | TFE Group" />
<meta property="og:url" content="<?= base_url() ?>"> <meta property="og:url" content="<?= base_url() ?>">
<meta property="og:image" content="<?= base_url('assets/img/social-card.png') ?>"/> <meta property="og:image" content="<?= base_url('assets/img/social-card.png') ?>" />
<meta property="og:type" content="website"> <meta property="og:type" content="website">
<?php slot('meta'); ?> <?php slot('meta'); ?>
@ -38,9 +39,11 @@
flex-direction: column; flex-direction: column;
min-height: 44.2vh; min-height: 44.2vh;
} }
.search-container-title { .search-container-title {
color: #666666; color: #666666;
} }
.search-container { .search-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -49,6 +52,7 @@
max-width: 400px; max-width: 400px;
margin-bottom: 20px; margin-bottom: 20px;
} }
.search-container input { .search-container input {
width: 100%; width: 100%;
padding: 10px; padding: 10px;
@ -56,6 +60,7 @@
border-radius: 5px; border-radius: 5px;
border: 1px solid #ccc; border: 1px solid #ccc;
} }
.search-container button { .search-container button {
padding: 10px 20px; padding: 10px 20px;
background-color: #429a82; background-color: #429a82;
@ -65,12 +70,15 @@
cursor: pointer; cursor: pointer;
width: 100%; width: 100%;
} }
.appointments-container { .appointments-container {
display: none; display: none;
width: 100%; width: 100%;
max-width: 600px; max-width: 600px;
margin-top: 20px; margin-top: 20px;
padding: 0 12px;
} }
.no-appointments { .no-appointments {
display: none; display: none;
color: red; color: red;
@ -81,140 +89,219 @@
</head> </head>
<body> <body>
<div id="main" class="container"> <div id="main" class="container">
<div class="row wrapper"> <div class="row wrapper">
<div id="book-appointment-wizard" class="col-12 col-lg-10 col-xl-8 col-xxl-7"> <div id="book-appointment-wizard" class="col-12 col-lg-10 col-xl-8 col-xxl-7">
<?php component('home_header', [ <?php component('home_header', [
'company_name' => vars('company_name'), 'company_name' => vars('company_name'),
'company_logo' => vars('company_logo'), 'company_logo' => vars('company_logo'),
]); ?> ]); ?>
<div class="search-container-wrapper"> <div class="search-container-wrapper">
<h2 class="search-container-title">查询预约信息</h2> <h2 class="search-container-title">查询预约信息</h2>
<div class="search-container"> <div class="search-container">
<input type="text" id="phoneNumber" placeholder="请输入手机号"> <input type="text" id="phoneNumber" placeholder="请输入手机号">
<button id="searchButton">查询</button> <button id="searchButton">查询</button>
</div>
<div class="appointments-container" id="appointmentsContainer">
<h3>预约结果</h3>
<ul id="appointmentsList"></ul>
</div>
<div class="no-appointments" id="noAppointmentsMessage">
未找到预约信息。
</div>
</div> </div>
<div class="appointments-container" id="appointmentsContainer">
<h3>预约结果</h3>
<ul id="appointmentsList"></ul>
</div>
<div class="no-appointments" id="noAppointmentsMessage">
未找到预约信息。
</div>
</div>
</div> </div>
<?php component('booking_footer', ['display_login_button' => vars('display_login_button')]); ?> <?php component('booking_footer', ['display_login_button' => vars('display_login_button')]); ?>
</div> </div>
</div> </div>
</div> </div>
<?php if (vars('display_cookie_notice') === '1'): ?> <?php if (vars('display_cookie_notice') === '1'): ?>
<?php component('cookie_notice_modal', ['cookie_notice_content' => vars('cookie_notice_content')]); ?> <?php component('cookie_notice_modal', ['cookie_notice_content' => vars('cookie_notice_content')]); ?>
<?php endif; ?> <?php endif; ?>
<?php if (vars('display_terms_and_conditions') === '1'): ?> <?php if (vars('display_terms_and_conditions') === '1'): ?>
<?php component('terms_and_conditions_modal', [ <?php component('terms_and_conditions_modal', [
'terms_and_conditions_content' => vars('terms_and_conditions_content'), 'terms_and_conditions_content' => vars('terms_and_conditions_content'),
]); ?> ]); ?>
<?php endif; ?> <?php endif; ?>
<?php if (vars('display_privacy_policy') === '1'): ?> <?php if (vars('display_privacy_policy') === '1'): ?>
<?php component('privacy_policy_modal', ['privacy_policy_content' => vars('privacy_policy_content')]); ?> <?php component('privacy_policy_modal', ['privacy_policy_content' => vars('privacy_policy_content')]); ?>
<?php endif; ?> <?php endif; ?>
<script src="<?= asset_url('assets/vendor/jquery/jquery.min.js') ?>"></script> <script src="<?= asset_url('assets/vendor/jquery/jquery.min.js') ?>"></script>
<script src="<?= asset_url('assets/vendor/cookieconsent/cookieconsent.min.js') ?>"></script> <script src="<?= asset_url('assets/vendor/cookieconsent/cookieconsent.min.js') ?>"></script>
<script src="<?= asset_url('assets/vendor/@popperjs-core/popper.min.js') ?>"></script> <script src="<?= asset_url('assets/vendor/@popperjs-core/popper.min.js') ?>"></script>
<script src="<?= asset_url('assets/vendor/bootstrap/bootstrap.min.js') ?>"></script> <script src="<?= asset_url('assets/vendor/bootstrap/bootstrap.min.js') ?>"></script>
<script src="<?= asset_url('assets/vendor/moment/moment.min.js') ?>"></script> <script src="<?= asset_url('assets/vendor/moment/moment.min.js') ?>"></script>
<script src="<?= asset_url('assets/vendor/moment-timezone/moment-timezone-with-data.min.js') ?>"></script> <script src="<?= asset_url('assets/vendor/moment-timezone/moment-timezone-with-data.min.js') ?>"></script>
<script src="<?= asset_url('assets/vendor/@fortawesome-fontawesome-free/fontawesome.min.js') ?>"></script> <script src="<?= asset_url('assets/vendor/@fortawesome-fontawesome-free/fontawesome.min.js') ?>"></script>
<script src="<?= asset_url('assets/vendor/@fortawesome-fontawesome-free/solid.min.js') ?>"></script> <script src="<?= asset_url('assets/vendor/@fortawesome-fontawesome-free/solid.min.js') ?>"></script>
<script src="<?= asset_url('assets/vendor/tippy.js/tippy-bundle.umd.min.js') ?>"></script> <script src="<?= asset_url('assets/vendor/tippy.js/tippy-bundle.umd.min.js') ?>"></script>
<script src="<?= asset_url('assets/vendor/flatpickr/flatpickr.min.js') ?>"></script> <script src="<?= asset_url('assets/vendor/flatpickr/flatpickr.min.js') ?>"></script>
<script src="<?= asset_url('assets/js/app.js') ?>"></script> <script src="<?= asset_url('assets/js/app.js') ?>"></script>
<script src="<?= asset_url('assets/js/utils/date.js') ?>"></script> <script src="<?= asset_url('assets/js/utils/date.js') ?>"></script>
<script src="<?= asset_url('assets/js/utils/file.js') ?>"></script> <script src="<?= asset_url('assets/js/utils/file.js') ?>"></script>
<script src="<?= asset_url('assets/js/utils/http.js') ?>"></script> <script src="<?= asset_url('assets/js/utils/http.js') ?>"></script>
<script src="<?= asset_url('assets/js/utils/lang.js') ?>"></script> <script src="<?= asset_url('assets/js/utils/lang.js') ?>"></script>
<script src="<?= asset_url('assets/js/utils/message.js') ?>"></script> <script src="<?= asset_url('assets/js/utils/message.js') ?>"></script>
<script src="<?= asset_url('assets/js/utils/string.js') ?>"></script> <script src="<?= asset_url('assets/js/utils/string.js') ?>"></script>
<script src="<?= asset_url('assets/js/utils/url.js') ?>"></script> <script src="<?= asset_url('assets/js/utils/url.js') ?>"></script>
<script src="<?= asset_url('assets/js/utils/validation.js') ?>"></script> <script src="<?= asset_url('assets/js/utils/validation.js') ?>"></script>
<script src="<?= asset_url('assets/js/layouts/booking_layout.js') ?>"></script> <script src="<?= asset_url('assets/js/http/localization_http_client.js') ?>"></script>
<script src="<?= asset_url('assets/js/http/localization_http_client.js') ?>"></script>
<script src="<?= asset_url('assets/js/http/customers_search_http_client.js') ?>"></script>
<script src="<?= asset_url('assets/js/pages/customers.js') ?>"></script>
<script> <script>
document.getElementById('searchButton').addEventListener('click', function() { function doSearch() {
var phoneNumber = document.getElementById('phoneNumber').value; var phoneNumber = document.getElementById('phoneNumber').value;
if (phoneNumber.trim() === '') { if (phoneNumber.trim() === '') {
alert('请输入有效的手机号'); alert('请输入有效的手机号');
return; return;
}
// 发送请求前获取CSRF token
//var csrfToken = document.querySelector('meta[name="csrf_token"]').getAttribute('content');
const url = App.Utils.Url.siteUrl('customers/search_by_phone');
const data = {
csrf_token: vars('csrf_token'),
phone_number: phoneNumber,
};
$.post(url, data).done((response) => {
// console.log('data',typeof(data));
const data = JSON.parse(response);
if (data.success && data.appointments.length > 0) {
displayAppointments(data.appointments);
} else {
showNoAppointmentsMessage();
}
});
} }
// 发送请求前获取CSRF token document.getElementById('searchButton').addEventListener('click', function() {
var csrfToken = document.querySelector('meta[name="csrf_token"]').getAttribute('content');
fetch('/index.php/appointmentSearch/search_by_phone', { doSearch();
method: 'POST', // fetch('/index.php/customers/search_by_phone', {
headers: { // method: 'POST',
'Content-Type': 'application/json', // headers: {
'X-CSRF-TOKEN': csrfToken // 添加CSRF Token到请求头 // 'Content-Type': 'application/json',
}, // //'X-CSRF-TOKEN': csrfToken // 添加CSRF Token到请求头
body: JSON.stringify({ phone_number: phoneNumber }) // },
}) // body: formData
.then(response => response.json()) // })
.then(data => { // .then(response => response.json())
if (data.success && data.appointments.length > 0) { // .then(data => {
displayAppointments(data.appointments); // if (data.success && data.appointments.length > 0) {
} else { // displayAppointments(data.appointments);
showNoAppointmentsMessage(); // } else {
} // showNoAppointmentsMessage();
}) // }
.catch(error => { // })
console.error('Error fetching appointments:', error); // .catch(error => {
showNoAppointmentsMessage(); // console.error('Error fetching appointments:', error);
}); // showNoAppointmentsMessage();
}); // });
function displayAppointments(appointments) {
var appointmentsContainer = document.getElementById('appointmentsContainer');
var appointmentsList = document.getElementById('appointmentsList');
appointmentsList.innerHTML = '';
appointments.forEach(function(appointment) {
var listItem = document.createElement('li');
listItem.textContent = `预约时间:${appointment.start_datetime}提供者ID${appointment.id_users_provider}`;
appointmentsList.appendChild(listItem);
}); });
appointmentsContainer.style.display = 'block'; function displayAppointments(appointments) {
document.getElementById('noAppointmentsMessage').style.display = 'none'; var appointmentsContainer = document.getElementById('appointmentsContainer');
} var appointmentsList = document.getElementById('appointmentsList');
function showNoAppointmentsMessage() { appointmentsList.innerHTML = '';
document.getElementById('appointmentsContainer').style.display = 'none'; appointments.forEach(function(appointment) {
document.getElementById('noAppointmentsMessage').style.display = 'block'; var listItem = document.createElement('li');
}
</script>
<?php component('js_vars_script'); ?> // 创建服务名称和提供者姓名的 div
<?php component('js_lang_script'); ?> var serviceDiv = document.createElement('div');
serviceDiv.textContent = `${appointment.service.name} - ${appointment.provider.last_name}${appointment.provider.first_name}`;
<?php component('google_analytics_script', ['google_analytics_code' => vars('google_analytics_code')]); ?> // 创建预约时间的 div
<?php component('matomo_analytics_script', [ var timeDiv = document.createElement('div');
'matomo_analytics_url' => vars('matomo_analytics_url'), timeDiv.textContent = `開始時間:${appointment.start}`;
'matomo_analytics_site_id' => vars('matomo_analytics_site_id'),
]); ?>
<?php slot('scripts'); ?> // 创建结束时间的 div
var endDiv = document.createElement('div');
endDiv.textContent = `結束時間:${appointment.end}`;
// 创建状态的 div
var statusDiv = document.createElement('div');
statusDiv.textContent = `狀態:${appointment.status}`;
// 将每个 div 添加到 li 中
listItem.appendChild(serviceDiv);
listItem.appendChild(timeDiv);
listItem.appendChild(endDiv);
listItem.appendChild(statusDiv);
// 如果状态是“已预约”,添加取消预约按钮
if (appointment.status === '已預約') {
var cancelButton = document.createElement('button');
cancelButton.textContent = '取消預約';
cancelButton.className = 'btn btn-danger'; // 添加一些样式类名
cancelButton.addEventListener('click', function() {
// 确认对话框
var confirmCancel = confirm('您確定要取消這個預約嗎?');
if (confirmCancel) {
// 添加取消预约的逻辑
// 例如,发起一个请求到服务器取消预约
console.log(`取消預約:${appointment.id}`);
// 这里可以添加实际的请求代码
const url = App.Utils.Url.siteUrl('customers/cancel');
const data = {
csrf_token: vars('csrf_token'),
appointmentId: appointment.id,
};
$.post(url, data).done((data) => {
// console.log('data',response);
if (data.success) {
//重新加载
doSearch();
alert('取消預約成功。');
} else {
alert('取消預約失敗。');
}
});
}
});
listItem.appendChild(cancelButton);
}
// 将 li 添加到 ul 或 ol 列表中
appointmentsList.appendChild(listItem);
});
appointmentsContainer.style.display = 'block';
document.getElementById('noAppointmentsMessage').style.display = 'none';
}
function showNoAppointmentsMessage() {
document.getElementById('appointmentsContainer').style.display = 'none';
document.getElementById('noAppointmentsMessage').style.display = 'block';
}
</script>
<?php component('js_vars_script'); ?>
<?php component('js_lang_script'); ?>
<?php component('google_analytics_script', ['google_analytics_code' => vars('google_analytics_code')]); ?>
<?php component('matomo_analytics_script', [
'matomo_analytics_url' => vars('matomo_analytics_url'),
'matomo_analytics_site_id' => vars('matomo_analytics_site_id'),
]); ?>
<?php slot('scripts'); ?>
</body> </body>
</html> </html>