(() => { const $ = (sel) => document.querySelector(sel); const rechargeOptionListEl = $('#rechargeOptionList') || $('#planList'); const estimateBoxEl = $('#estimateBox'); const resultBoxEl = $('#orderResultBox'); const holderNameEl = $('#holderName'); const customInitialBalanceEl = $('#customInitialBalance') || $('#initialBalance'); const customRechargeBoxEl = $('#customRechargeBox'); const submitBtn = $('#submitOrderBtn'); const HOLDER_NAME_PATTERN = /^[A-Za-z][A-Za-z .,'()&@/_\-+]*$/; const state = { rechargeOptions: [5, 10, 15, 20], selectedAmount: 5, customMode: false }; if (!rechargeOptionListEl || !estimateBoxEl || !resultBoxEl || !holderNameEl || !customInitialBalanceEl || !submitBtn) { console.error('[ic-card-order] Missing required DOM nodes', { rechargeOptionListEl: !!rechargeOptionListEl, estimateBoxEl: !!estimateBoxEl, resultBoxEl: !!resultBoxEl, holderNameEl: !!holderNameEl, customInitialBalanceEl: !!customInitialBalanceEl, customRechargeBoxEl: !!customRechargeBoxEl, submitBtn: !!submitBtn }); return; } const api = { async request(url, opts = {}) { const res = await fetch(url, opts); const data = await res.json().catch(() => ({})); if (!res.ok || data.ok === false) { throw new Error(data.error || res.statusText || '请求失败'); } return data; }, fetchConfig() { return api.request('/api/public/ic-cards/config'); }, createOrder(payload) { return api.request('/api/public/ic-cards/orders', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); } }; const escapeHtml = (value) => String(value == null ? '' : value) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); const getInitialBalance = () => { if (state.customMode) { return Math.max(1, Number(customInitialBalanceEl.value || 0) || 0); } return Math.max(1, Number(state.selectedAmount || 0) || 0); }; const renderRechargeOptions = () => { const options = Array.isArray(state.rechargeOptions) && state.rechargeOptions.length ? state.rechargeOptions : [5, 10, 15, 20]; rechargeOptionListEl.innerHTML = options.map((amount) => ` `).join('') + ` `; if (customRechargeBoxEl) { customRechargeBoxEl.classList.toggle('is-active', !!state.customMode); } rechargeOptionListEl.querySelectorAll('[data-amount]').forEach((button) => { button.addEventListener('click', () => { state.customMode = false; state.selectedAmount = Number(button.getAttribute('data-amount')) || 5; customInitialBalanceEl.disabled = true; renderRechargeOptions(); renderEstimate(); }); }); const customBtn = rechargeOptionListEl.querySelector('[data-custom="true"]'); if (customBtn) { customBtn.addEventListener('click', () => { state.customMode = true; customInitialBalanceEl.disabled = false; customInitialBalanceEl.focus(); if (!customInitialBalanceEl.value) customInitialBalanceEl.value = '25'; renderRechargeOptions(); renderEstimate(); }); } }; const syncLegacyDom = () => { const holderPhoneEl = $('#holderPhone'); const orderNoteEl = $('#orderNote'); if (holderPhoneEl) { holderPhoneEl.disabled = true; holderPhoneEl.value = ''; holderPhoneEl.placeholder = '已停用'; holderPhoneEl.style.display = 'none'; } if (orderNoteEl) { orderNoteEl.disabled = true; orderNoteEl.value = ''; orderNoteEl.placeholder = '已停用'; orderNoteEl.style.display = 'none'; } const createTypeSelect = $('#createType'); if (createTypeSelect) { createTypeSelect.disabled = true; createTypeSelect.style.display = 'none'; } }; const validateHolderName = (value) => { const holderName = String(value || '').trim(); if (!holderName) return '请输入持卡人姓名'; if (holderName.length > 24) return '持卡人姓名不能超过 24 个字符'; if (!HOLDER_NAME_PATTERN.test(holderName)) return '持卡人姓名仅支持英文与常用符号'; return ''; }; const validateInitialBalance = () => { const initialBalance = getInitialBalance(); if (!Number.isFinite(initialBalance) || initialBalance < 1) { return '首次充值金额必须大于 0'; } return ''; }; const renderEstimate = () => { const initialBalance = getInitialBalance(); if (!Number.isFinite(initialBalance) || initialBalance < 1) { estimateBoxEl.innerHTML = '

请选择有效的首次充值金额。

'; return; } estimateBoxEl.innerHTML = `
卡片类型IC 储值卡
首次充值${escapeHtml(initialBalance)}
持卡人限制仅英文与常用符号
预计金额${escapeHtml(initialBalance)}
`; }; const renderResult = (data) => { if (!data) { resultBoxEl.className = 'jr-center-empty'; resultBoxEl.innerHTML = '

提交后将在此显示卡号、凭证码和领卡提示。

'; return; } const isDomain = location.hostname.includes('fse-media.group'); const voucherCode = data.code || data.voucher_code || data.order_code || '---'; const cardStatus = String(data.card?.status || data.status || '').trim().toLowerCase(); const lookupKey = (cardStatus === 'pending_pickup') ? voucherCode : (data.card?.card_id || data.card_id || voucherCode); const searchHref = isDomain ? `https://ticket.fse-media.group/ic-card/search?q=${encodeURIComponent(lookupKey)}` : `/ic-card-search.html?q=${encodeURIComponent(lookupKey)}`; const detailHref = isDomain ? `https://ticket.fse-media.group/ic/${encodeURIComponent(lookupKey)}` : `/ic/${encodeURIComponent(lookupKey)}`; const shownCardId = data.display_card_id || data.card?.display_card_id || data.card_id || '---'; const amount = Number(data.amount ?? data.card?.purchase_amount ?? data.card?.balance ?? getInitialBalance()) || getInitialBalance(); resultBoxEl.className = ''; resultBoxEl.innerHTML = `
ORDER CREATED
凭证码 ${escapeHtml(voucherCode)}
卡号 ${escapeHtml(shownCardId)}
首次充值 ${escapeHtml(amount)}
当前状态 待领卡

购卡信息已生成。请保存卡号与凭证码,前往站内办理领卡或后续状态查询。

卡片详情 查询此卡
`; }; const submitOrder = async () => { const holderNameError = validateHolderName(holderNameEl.value); if (holderNameError) { alert(holderNameError); return; } const balanceError = validateInitialBalance(); if (balanceError) { alert(balanceError); return; } const payload = { holder_name: holderNameEl.value.trim(), initial_balance: getInitialBalance() }; submitBtn.disabled = true; try { const data = await api.createOrder(payload); renderResult(data); alert(`购卡成功,凭证码:${data.code}`); } finally { submitBtn.disabled = false; } }; customInitialBalanceEl.addEventListener('input', renderEstimate); submitBtn.addEventListener('click', () => submitOrder().catch((error) => alert(error.message || String(error)))); (async () => { syncLegacyDom(); const data = await api.fetchConfig(); state.rechargeOptions = (data.recharge_options || data.initial_balance_options || [5, 10, 15, 20]) .map((value) => Number(value) || 0) .filter((value) => value > 0); state.selectedAmount = state.rechargeOptions[0] || 5; customInitialBalanceEl.disabled = true; if (customRechargeBoxEl) customRechargeBoxEl.classList.remove('is-active'); renderRechargeOptions(); renderEstimate(); renderResult(null); })().catch((error) => { rechargeOptionListEl.innerHTML = `

${escapeHtml(error.message || String(error))}

`; estimateBoxEl.innerHTML = '

配置加载失败。

'; }); })();