| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>S3 报名</title>
- <script src="./js/tailwindcss.min.js"></script>
- <link rel="stylesheet" href="./css/all.min.css">
- <style>
- body { font-family: 'Roboto', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', sans-serif; }
- .page-top {
- background-image: url('./static/backgroud/top_bg_sddx.png');
- background-repeat: no-repeat;
- background-position: center;
- background-size: cover;
- min-height: 220px;
- }
- .logo-bg {
- background-image: url('./static/logo/jbs.png');
- background-repeat: no-repeat;
- background-position: center;
- background-size: contain;
- width: 80px; height: 80px; margin-top: 10px;
- }
- .e-select-wrapper { position: relative; }
- .e-select-input { width: 100%; padding: 10px; border: 1px solid #dcdfe6; border-radius: 4px; background-color: white; cursor: pointer; display: flex; justify-content: space-between; align-items: center; }
- .e-select-dropdown { position: absolute; width: 100%; background: white; border: 1px solid #dcdfe6; border-radius: 4px; max-height: 200px; overflow-y: auto; z-index: 10; }
- .e-select-item { padding: 10px; cursor: pointer; }
- .e-select-item:hover { background-color: #f0f0f0; }
- </style>
- </head>
- <body class="bg-gray-100 min-h-screen flex flex-col items-center">
- <!-- Top Section -->
- <div class="page-top w-full flex flex-col justify-between items-center pb-4">
- <div class="w-full flex justify-between items-center p-4">
- <button onclick="handleBack()" class="bg-black/20 backdrop-blur-sm p-2 rounded-full w-9 h-9 flex items-center justify-center text-white active:scale-90 transition">
- <i class="fas fa-chevron-left"></i>
- </button>
- <h1 id="mc-name" class="text-white text-lg font-bold">赛事名称</h1>
- <button onclick="handleInfo()" class="bg-black/20 backdrop-blur-sm px-3 py-1.5 rounded-full text-xs font-semibold flex items-center gap-1 text-white active:scale-90 transition">
- <i class="fas fa-question-circle"></i> 说明
- </button>
- </div>
- <div class="flex flex-col items-center gap-2">
- <div class="logo-bg"></div>
- <p id="sub-title" class="text-yellow-400 text-lg font-bold">活动时间</p>
- </div>
- </div>
- <!-- Time Bar -->
- <div class="timebar flex items-center justify-center -mt-4 bg-white px-4 py-2 rounded-full shadow-md z-10 border border-gray-200">
- <img src="./static/common/time.png" class="w-4 h-4 mr-2" alt="clock">
- <span id="act-time" class="text-gray-800 text-sm font-semibold whitespace-nowrap"></span>
- </div>
- <!-- Main Form Section -->
- <div class="flex flex-col items-center w-11/12 max-w-sm px-4 py-6 bg-white rounded-lg shadow-lg mt-4">
- <input type="text" id="nickNameInput" maxlength="12" placeholder="请输入昵称"
- class="w-full h-10 px-3 my-2 border border-gray-300 rounded-md focus:outline-none focus:ring-1 focus:ring-blue-500 text-sm" />
-
- <div class="e-select-wrapper w-full my-2">
- <div id="coiSelectInput" class="e-select-input text-gray-700 text-sm" tabindex="0">
- <span id="selectedCoiName">请选择组织</span>
- <i class="fas fa-chevron-down text-gray-400"></i>
- </div>
- <div id="coiDropdown" class="e-select-dropdown hidden">
- <input type="text" id="coiSearchInput" placeholder="搜索组织" class="w-full px-3 py-2 border-b border-gray-200 focus:outline-none" />
- <div id="coiOptionsContainer"></div>
- </div>
- </div>
- <div id="introduce-section" class="w-full mt-4 text-gray-700 text-sm leading-relaxed hidden">
- <h3 id="introduce-title" class="font-bold text-base mb-1"></h3>
- <div id="introduce-content"></div>
- </div>
- <div id="rules-section" class="w-full mt-4 p-4 bg-gray-100 rounded-lg hidden">
- <h3 id="rules-title" class="font-bold text-sm mb-1"></h3>
- <div id="rules-content" class="text-xs text-gray-600"></div>
- </div>
- <button id="signup-btn" onclick="handleSignup()" class="w-full h-12 mt-6 text-white text-lg font-bold bg-green-500 rounded-full shadow-lg active:scale-95 transition-transform">
- 我要报名
- </button>
- <button id="signup-btn-disabled" class="w-full h-12 mt-6 text-white text-lg font-bold bg-gray-400 rounded-full shadow-lg cursor-not-allowed hidden">
- 活动已结束
- </button>
- </div>
- <!-- Info Modal -->
- <div id="infoModal" class="fixed inset-0 z-50 hidden transition-opacity duration-300">
- <div class="absolute inset-0 bg-slate-900/70 backdrop-blur-sm" onclick="closeInfoModal()"></div>
- <div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-[90%] bg-white rounded-2xl p-6 shadow-2xl">
- <button onclick="closeInfoModal()" class="absolute -top-10 right-0 text-white/80 hover:text-white w-8 h-8 flex items-center justify-center rounded-full border border-white/30">
- <i class="fas fa-times"></i>
- </button>
- <h3 class="text-center font-bold text-lg mb-4 text-blue-600">活动说明</h3>
- <div id="info-modal-content" class="text-sm text-gray-700 max-h-80 overflow-y-auto"></div>
- </div>
- </div>
- <!-- Alert Dialog -->
- <div id="alertDialog" class="fixed inset-0 z-50 hidden transition-opacity duration-300">
- <div class="absolute inset-0 bg-slate-900/70 backdrop-blur-sm" onclick="closeAlertDialog()"></div>
- <div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-[90%] max-w-xs bg-white rounded-lg p-6 shadow-2xl text-center">
- <h3 class="font-bold text-lg mb-4">请确认报名信息</h3>
- <div class="text-sm text-gray-700 space-y-2">
- <p id="alert-mc-name" class="font-bold"></p>
- <p id="alert-nickname-label"></p>
- <p id="alert-coi-label"></p>
- </div>
- <div class="flex justify-around mt-6 space-x-4">
- <button onclick="closeAlertDialog()" class="flex-1 py-2 rounded-md border border-gray-300 text-gray-600">取消</button>
- <button onclick="confirmSignup()" class="flex-1 py-2 rounded-md bg-blue-500 text-white">确认</button>
- </div>
- </div>
- </div>
- <script src="./js/utils.js"></script>
- <script src="./js/bridge.js"></script>
- <script src="./js/api.js"></script>
- <script>
- const STATE = {
- ecId: 0,
- token: '',
- mcId: 0,
- mcType: 0,
- mcName: '',
- beginSecond: 0,
- endSecond: 0,
- mcState: 0,
- nickName: '',
- coiId: 0,
- coiName: '',
- coiOptions: [],
- fromPage: '',
- configParam: { labelName: '昵称', labelOrg: '组织', subTitle: '' },
- introduce: { title: '', content: '' },
- activityRules: { title: '', content: '' },
- popupRuleList: []
- };
- const mcNameEl = document.getElementById('mc-name');
- const subTitleEl = document.getElementById('sub-title');
- const actTimeEl = document.getElementById('act-time');
- const nickNameInput = document.getElementById('nickNameInput');
- const signupBtn = document.getElementById('signup-btn');
- const signupBtnDisabled = document.getElementById('signup-btn-disabled');
- const coiSelectInput = document.getElementById('coiSelectInput');
- const selectedCoiNameEl = document.getElementById('selectedCoiName');
- const coiDropdown = document.getElementById('coiDropdown');
- const coiSearchInput = document.getElementById('coiSearchInput');
- const coiOptionsContainer = document.getElementById('coiOptionsContainer');
- const introduceSection = document.getElementById('introduce-section');
- const introduceTitleEl = document.getElementById('introduce-title');
- const introduceContentEl = document.getElementById('introduce-content');
- const rulesSection = document.getElementById('rules-section');
- const rulesTitleEl = document.getElementById('rules-title');
- const rulesContentEl = document.getElementById('rules-content');
- const infoModal = document.getElementById('infoModal');
- const infoModalContentEl = document.getElementById('info-modal-content');
- const alertDialog = document.getElementById('alertDialog');
- const alertMcNameEl = document.getElementById('alert-mc-name');
- const alertNicknameLabelEl = document.getElementById('alert-nickname-label');
- const alertCoiLabelEl = document.getElementById('alert-coi-label');
- function injectCss(css) {
- if (!css) return;
- const style = document.createElement('style');
- style.innerHTML = css;
- document.head.appendChild(style);
- }
- window.onload = function() {
- STATE.token = Tools.getQueryParam('token') || '';
- STATE.ecId = Tools.getQueryParam('id') || 0;
- STATE.fromPage = Tools.getQueryParam('from') || '';
- if (window.API) {
- API.setToken(STATE.token);
- if (Tools.getQueryParam('env') === 'mock') {
- API.init({ useMock: true });
- if (!STATE.ecId) STATE.ecId = 'mock_id';
- }
- }
- loadCardConfig();
- getCardDetail();
- matchRsDetail();
- coiSelectInput.addEventListener('click', toggleCoiDropdown);
- coiSearchInput.addEventListener('input', filterCoiOptions);
- document.addEventListener('click', (event) => {
- if (!coiDropdown.contains(event.target) && !coiSelectInput.contains(event.target)) {
- coiDropdown.classList.add('hidden');
- }
- });
- };
- function loadCardConfig() {
- if (!window.API) return;
- API.getCardConfig(STATE.ecId, 'signup').then(configRes => {
- let cfg = configRes;
- if (configRes && configRes.configJson) {
- try { cfg = JSON.parse(configRes.configJson); } catch (e) { console.warn('config parse fail', e); }
- }
- if (!cfg) return;
- if (cfg.common && cfg.common.css) injectCss(cfg.common.css);
- const pageCfg = cfg.signup || cfg;
- if (pageCfg && pageCfg.css) injectCss(pageCfg.css);
- if (pageCfg && pageCfg.introduce) {
- STATE.introduce = pageCfg.introduce;
- introduceTitleEl.innerText = STATE.introduce.title || '';
- introduceContentEl.innerHTML = STATE.introduce.content || '';
- introduceSection.classList.remove('hidden');
- }
- if (pageCfg && pageCfg.activityRules) {
- STATE.activityRules = pageCfg.activityRules;
- rulesTitleEl.innerText = STATE.activityRules.title || '';
- rulesContentEl.innerHTML = STATE.activityRules.content || '';
- rulesSection.classList.remove('hidden');
- }
- if (pageCfg && pageCfg.param) STATE.configParam = Object.assign(STATE.configParam, pageCfg.param);
- if (cfg.popupRuleList) STATE.popupRuleList = cfg.popupRuleList;
- nickNameInput.placeholder = `请输入${STATE.configParam.labelName}`;
- selectedCoiNameEl.innerText = `请选择${STATE.configParam.labelOrg}`;
- });
- }
- function getCardDetail() {
- if (!window.API) return;
- API.getCardDetail(STATE.ecId).then(res => {
- if (!res) return;
- STATE.mcType = res.mcType;
- STATE.mcId = res.mcId;
- STATE.mcName = res.mcName;
- STATE.beginSecond = res.beginSecond;
- STATE.endSecond = res.endSecond;
- STATE.coiId = res.coiId;
- STATE.coiName = res.coiName;
- STATE.nickName = res.nickName || '';
- STATE.mcState = Tools.checkMcState(STATE.beginSecond, STATE.endSecond);
- updateUI();
- getOnlineMcSignUpDetail();
- });
- }
- function matchRsDetail() {
- if (!window.API) return;
- API.getMatchRsDetail(STATE.ecId,0).then(() => {});
- }
- function getOnlineMcSignUpDetail() {
- if (!window.API || !STATE.mcId) return;
- API.getOnlineMcSignUpDetail(STATE.ecId, STATE.mcId).then(res => {
- if (!res) return;
- if (res.coiRs) {
- STATE.coiOptions = res.coiRs.map(item => ({ text: item.coiName, value: item.coiId }));
- populateCoiOptions(STATE.coiOptions);
- }
- if (!STATE.nickName && res.name) STATE.nickName = res.name;
- nickNameInput.value = STATE.nickName;
- if (STATE.coiId > 0) {
- const selected = STATE.coiOptions.find(item => item.value == STATE.coiId);
- if (selected) {
- selectedCoiNameEl.innerText = selected.text;
- STATE.coiName = selected.text;
- }
- }
- });
- }
- function updateUI() {
- mcNameEl.innerText = STATE.mcName;
- subTitleEl.innerText = STATE.configParam.subTitle || Tools.fmtMcTime2(STATE.beginSecond, STATE.endSecond);
- actTimeEl.innerText = Tools.getActtime(STATE.beginSecond, STATE.endSecond);
- nickNameInput.value = STATE.nickName;
- if (STATE.mcState === 2) {
- signupBtn.classList.add('hidden');
- signupBtnDisabled.classList.remove('hidden');
- } else {
- signupBtn.classList.remove('hidden');
- signupBtnDisabled.classList.add('hidden');
- }
- }
- function toggleCoiDropdown() {
- coiDropdown.classList.toggle('hidden');
- coiSearchInput.value = '';
- populateCoiOptions(STATE.coiOptions);
- }
- function filterCoiOptions() {
- const searchTerm = coiSearchInput.value.toLowerCase();
- const filtered = STATE.coiOptions.filter(item => item.text.toLowerCase().includes(searchTerm));
- populateCoiOptions(filtered);
- }
- function populateCoiOptions(options) {
- coiOptionsContainer.innerHTML = '';
- options.forEach(option => {
- const div = document.createElement('div');
- div.classList.add('e-select-item');
- div.innerText = option.text;
- div.dataset.value = option.value;
- div.addEventListener('click', () => selectCoiOption(option));
- coiOptionsContainer.appendChild(div);
- });
- }
- function selectCoiOption(option) {
- STATE.coiId = option.value;
- STATE.coiName = option.text;
- selectedCoiNameEl.innerText = option.text;
- coiDropdown.classList.add('hidden');
- }
- function handleInfo() {
- let contentHtml = '';
- if (STATE.popupRuleList && STATE.popupRuleList.length > 0) {
- STATE.popupRuleList.forEach(rule => {
- if (rule.data && rule.data.title) contentHtml += `<h4 class="font-bold mt-2">${rule.data.title}</h4>`;
- if (rule.data && rule.data.content) contentHtml += `<p>${rule.data.content}</p>`;
- });
- } else if (STATE.activityRules && STATE.activityRules.content) {
- contentHtml = `<h4 class="font-bold">${STATE.activityRules.title}</h4><p>${STATE.activityRules.content}</p>`;
- } else {
- contentHtml = '<p>暂无说明信息。</p>';
- }
- infoModalContentEl.innerHTML = contentHtml;
- infoModal.classList.remove('hidden');
- }
- function closeInfoModal() { infoModal.classList.add('hidden'); }
- function handleBack() {
- const qs = window.location.search || `?id=${STATE.ecId}&token=${STATE.token}`;
- if (STATE.fromPage) {
- Bridge.appAction(`./${STATE.fromPage}.html${qs}`);
- } else {
- Bridge.appAction('action://to_home/');
- }
- }
- function handleSignup() {
- STATE.nickName = nickNameInput.value.trim();
- if (!STATE.nickName) {
- Tools.showToast(`请输入${STATE.configParam.labelName}`);
- return;
- }
- if (!STATE.coiId) {
- Tools.showToast(`请选择${STATE.configParam.labelOrg}`);
- return;
- }
- alertMcNameEl.innerText = STATE.mcName;
- alertNicknameLabelEl.innerText = `${STATE.configParam.labelName}: ${STATE.nickName}`;
- alertCoiLabelEl.innerText = `${STATE.configParam.labelOrg}: ${STATE.coiName}`;
- alertDialog.classList.remove('hidden');
- }
- function confirmSignup() {
- if (!window.API) return;
- API.signUpOnline(STATE.mcId, STATE.coiId, 0, STATE.nickName).then(() => {
- Tools.showToast('报名成功');
- const qs = window.location.search || `?id=${STATE.ecId}&token=${STATE.token}`;
- Bridge.appAction(`./ranklist.html${qs}`);
- }).catch(() => {
- Tools.showToast('报名失败,请稍后重试');
- });
- closeAlertDialog();
- }
- function closeAlertDialog() { alertDialog.classList.add('hidden'); }
- </script>
- </body>
- </html>
|