| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- {include file="header" /}
- <link rel="stylesheet" href="/assets/xtu/appointment.css?v=20260421-1931">
- {php}
- $appointment_status = 'open';
- $now = time();
- $starttime = isset($starttime) ? (int)$starttime : 0;
- $endtime = isset($endtime) ? (int)$endtime : 0;
- if ($starttime > 0 && $now < $starttime) {
- $appointment_status = 'upcoming';
- } elseif ($endtime > 0 && $now > $endtime) {
- $appointment_status = 'ended';
- }
- $appointment_status_text = $appointment_status === 'upcoming' ? cms_t('appointment_status_upcoming', '预约尚未开始') : ($appointment_status === 'ended' ? cms_t('appointment_status_ended', '预约已结束') : cms_t('appointment_status_open', '预约开启'));
- {/php}
- <main class="appointment-page">
- <section class="appointment-hero{if !empty($video)} appointment-hero-has-video{/if}"{if empty($video)} style="background-image:url({$thumbbig|default=$thumb|default='/assets/xtu/vendor/img/appbanner.jpg'});"{/if}>
- {if !empty($video)}
- <div class="appointment-hero-media">
- <video class="appointment-hero-video" autoplay muted loop playsinline preload="metadata" poster="{$thumb|default=$thumbbig|default='/assets/xtu/vendor/img/appbanner.jpg'}">
- <source src="{$video}" type="video/mp4">
- </video>
- </div>
- {/if}
- <div class="appointment-hero-overlay"></div>
- <div class="content-1300-wrap appointment-hero-inner">
- <div class="appointment-hero-copy">
- <h1>{$title}</h1>
- {if !empty($subtitle)}
- <div class="appointment-hero-subtitle">{$subtitle}</div>
- {/if}
- {if !empty($appointment_status_text)}
- <div class="appointment-hero-status">{$appointment_status_text}</div>
- {/if}
- <form class="appointment-form" id="appointmentForm" action="javascript:;" method="post" novalidate>
- <input type="hidden" name="activity_id" value="{$id}">
- <input type="hidden" name="activity_title" value="{$title}">
- <input type="hidden" name="source_page" id="appointmentSourcePage" value="">
- <input type="hidden" name="lang" id="appointmentLang" value="{$lang?:'cn'}">
- <label class="visually-hidden" for="appointmentMobile">{:cms_t('appointment_mobile_label','手机号')}</label>
- <input id="appointmentMobile" class="appointment-input" type="tel" name="mobile" maxlength="20" placeholder="{:cms_t('appointment_mobile_placeholder','手机号码')}">
- <label class="visually-hidden" for="appointmentEmail">{:cms_t('appointment_email_label','邮箱')}</label>
- <input id="appointmentEmail" class="appointment-input" type="email" name="email" maxlength="191" placeholder="{:cms_t('appointment_email_placeholder','邮箱地址')}">
- <button class="appointment-submit" id="appointmentSubmitBtn" type="submit">{:cms_t('appointment_submit','预约提醒')}</button>
- </form>
- </div>
- </div>
- </section>
- {if !empty($content)}
- <section class="appointment-intro-section">
- <div class="content-1300-wrap">
- <div class="appointment-intro">{$content|raw}</div>
- </div>
- </section>
- {/if}
- {if !empty($images)}
- <section class="appointment-gallery-section">
- <div class="content-1300-wrap">
- <div class="swiper appointment-gallery-swiper">
- <div class="swiper-wrapper">
- {volist name="images" id="img"}
- <div class="swiper-slide appointment-gallery-slide">
- <img src="{$img.url|default=$img}" alt="{$title}">
- </div>
- {/volist}
- </div>
- <button class="appointment-gallery-arrow appointment-gallery-prev" type="button" aria-label="Prev">
- <i class="bi bi-chevron-left"></i>
- </button>
- <button class="appointment-gallery-arrow appointment-gallery-next" type="button" aria-label="Next">
- <i class="bi bi-chevron-right"></i>
- </button>
- <div class="appointment-gallery-pagination"></div>
- </div>
- </div>
- </section>
- {/if}
- <section class="appointment-notice-section">
- <div class="content-1300-wrap">
- <div class="appointment-notice-box">
- <div class="appointment-notice-title">{:cms_t('appointment_notice_title','预约须知')}</div>
- <div class="appointment-notice-content">
- {if !empty($booking_notice)}
- {$booking_notice|raw}
- {else /}
- <p>{:cms_t('appointment_notice_default','提交预约信息后,我们将在合适时间通过短信或邮件与您联系,请确保联系方式填写正确。')}</p>
- {/if}
- </div>
- </div>
- </div>
- </section>
- </main>
- <script>
- document.getElementById('appointmentSourcePage').value = window.location.href;
- const appointmentTexts = {
- invalidMobile: "{:cms_t('appointment_invalid_mobile','请输入正确的手机号')}",
- invalidEmail: "{:cms_t('appointment_invalid_email','请输入正确的邮箱地址')}",
- success: "{:cms_t('appointment_success','预约成功')}",
- failed: "{:cms_t('appointment_failed','预约提交失败')}",
- retryLater: "{:cms_t('appointment_retry_later','提交失败,请稍后再试')}"
- };
- const appointmentForm = document.getElementById('appointmentForm');
- const appointmentMobile = document.getElementById('appointmentMobile');
- const appointmentEmail = document.getElementById('appointmentEmail');
- const appointmentLang = document.getElementById('appointmentLang');
- function resolveAppointmentLang() {
- const raw = (appointmentLang?.value || document.documentElement.getAttribute('lang') || 'cn').toLowerCase();
- return raw || 'cn';
- }
- function isChineseLang(lang) {
- return ['cn', 'zh', 'zh-cn'].includes((lang || '').toLowerCase());
- }
- function syncAppointmentFields() {
- const lang = resolveAppointmentLang();
- const chinese = isChineseLang(lang);
- if (appointmentLang) {
- appointmentLang.value = lang;
- }
- if (appointmentMobile) {
- appointmentMobile.style.display = chinese ? '' : 'none';
- appointmentMobile.disabled = !chinese;
- appointmentMobile.required = chinese;
- if (!chinese) appointmentMobile.value = '';
- }
- if (appointmentEmail) {
- appointmentEmail.style.display = chinese ? 'none' : '';
- appointmentEmail.disabled = chinese;
- appointmentEmail.required = !chinese;
- if (chinese) appointmentEmail.value = '';
- }
- }
- syncAppointmentFields();
- appointmentForm?.addEventListener('submit', async function (e) {
- e.preventDefault();
- const form = e.currentTarget;
- const submit = form.querySelector('.appointment-submit');
- const lang = resolveAppointmentLang();
- const chinese = isChineseLang(lang);
- const mobileValue = (appointmentMobile?.value || '').trim();
- const emailValue = (appointmentEmail?.value || '').trim();
- if (appointmentLang) {
- appointmentLang.value = lang;
- }
- if (chinese) {
- if (!/^1\d{10}$/.test(mobileValue)) {
- appointmentMobile?.focus();
- alert(appointmentTexts.invalidMobile);
- return;
- }
- } else {
- if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailValue)) {
- appointmentEmail?.focus();
- alert(appointmentTexts.invalidEmail);
- return;
- }
- }
- if (submit) submit.disabled = true;
- try {
- const body = new URLSearchParams(new FormData(form));
- const res = await fetch("{:url('index/appointment/submit')}", {
- method: 'POST',
- headers: {
- 'X-Requested-With': 'XMLHttpRequest',
- 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
- },
- body: body.toString()
- });
- const data = await res.json();
- if (data.code === 1) {
- alert(data.msg || appointmentTexts.success);
- form.reset();
- syncAppointmentFields();
- } else {
- alert(data.msg || appointmentTexts.failed);
- }
- } catch (err) {
- alert(appointmentTexts.retryLater);
- } finally {
- if (submit) submit.disabled = false;
- }
- });
- </script>
- {include file="footer" /}
|