/** * 学園祭 マイページ(利用者向け) * * 依存: /js/customDialog.js * * ★ 認証はURLのトークン。ゲストカードは `?c=`、生徒・保護者・教職員は `?t=`。 * トークン無しで開いた教職員は Portal のログインで本人を決める(生徒・保護者は parents.html)。 * 旧版は `?ic=` と生のUIDを載せていた。 * ★ トークンを画面のHTMLに書き込まない(スクリーンショットや共有で漏れないように)。 */ (function () { 'use strict'; const $ = (id) => document.getElementById(id); const params = new URLSearchParams(location.search); const cardToken = (params.get('c') || '').trim(); const linkToken = (params.get('t') || '').trim(); const yen = (n) => Number(n || 0).toLocaleString('ja-JP'); async function api(op) { const body = { op: op }; if (cardToken) body.c = cardToken; else body.t = linkToken; const res = await fetch('../api/mypage.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); return await res.json(); } function fail(message) { $('loading').classList.add('hidden'); $('error').classList.remove('hidden'); $('error').textContent = message; } // ------------------------------------------------------------ let loadingAccount = false; let loadAgain = false; async function load() { if (loadingAccount) { loadAgain = true; return; } loadingAccount = true; try { await loadAccount(); } finally { loadingAccount = false; if (loadAgain) { loadAgain = false; load(); } } } // ★ トークン無しでも API に問い合わせる。教職員は Portal のログインで開ける(→ api/mypage.php) async function loadAccount() { let json; try { json = await api('open'); } catch (e) { console.error(e); return fail('通信できませんでした。電波の良い場所でもう一度お試しください。'); } if (!json.ok) return fail(json.message || '表示できませんでした。'); render(json); watch(json.room); } /** * この口座で決済・入出金・取消があったら、すぐ取り直す(→ ../js/realtime.js)。 * ルームに入るのは最初の1回だけ(取り直しのたびに入り直さない)。 */ let watchingRoom = null; function watch(room) { if (!room || watchingRoom || typeof gsRT === 'undefined') return; watchingRoom = room; gsRT.join(room, { account_changed: load }); } function render(json) { $('loading').classList.add('hidden'); $('app').classList.remove('hidden'); $('error').classList.add('hidden'); $('stoppedBadge').classList.toggle('hidden', !json.stopped); $('eventName').textContent = json.settings.event_name; // 販売状況のページを閉じているときはリンクを出さない(→ 全体設定 dashboard_enabled) document.querySelectorAll('.dash-link').forEach((a) => a.classList.toggle('hidden', json.settings.dashboard_open === false)); $('label').textContent = json.label; if (json.stopped) { // 「紛失で停止」と「返金済み」はどちらも使えないが、原因が違うので書き分ける $('stoppedBadge').textContent = json.card_status === 'refunded' ? '返金済み(利用できません)' : '利用停止中'; $('stoppedBadge').classList.remove('hidden'); } const m = json.money; if (json.is_guest) { $('guestMoney').classList.remove('hidden'); $('balance').textContent = yen(m.balance); $('deposited').textContent = yen(m.deposited); $('spentGuest').textContent = yen(m.spent); if (json.settings.refund_deadline) { $('refundNote').textContent = '残高の返金は事務室で ' + json.settings.refund_deadline + ' まで承ります。'; } } else { $('debitMoney').classList.remove('hidden'); $('spent').textContent = yen(m.spent); // 上限なし(credit_limit が null)は「なし」。0 と区別する $('limit').textContent = m.limit === null ? 'なし' : yen(m.limit) + '円'; $('remain').textContent = m.balance === null ? '—' : yen(m.balance) + '円'; } // 失くしたときの案内:紙のゲストカードはこの画面で停止、教職員(学校ICカード)はポータルの IC のロック $('lostSection').classList.toggle('hidden', !json.is_guest); $('lostIcSection').classList.toggle('hidden', !!json.is_guest); // すでに停止済みなら停止ボタンを出さない(押しても何も起きないボタンを置かない) $('suspendSelf').classList.toggle('hidden', !!json.stopped); renderHistory(json.history, !!json.is_guest); } // 履歴の表は学園祭ゲストページと共用(→ ./account-history.js)。返金のお知らせも表の上に出る function renderHistory(history, guest) { gsRenderAccountHistory($('historyTable'), history, { guest: guest }); } // ------------------------------------------------------------ $('suspendSelf').addEventListener('click', async () => { const ok = await customConfirm( 'このカードの利用を停止します。
' + '残高は消えません。停止の解除は学園祭本部でのみ行えます。' ); if (!ok) return; let json; try { json = await api('suspend_self'); } catch (e) { console.error(e); return alertDialog('通信できませんでした。もう一度お試しください。', 3000, 'warn'); } if (!json.ok) return alertDialog(json.message || '停止できませんでした', 3000, 'warn'); alertDialog('利用を停止しました'); load(); }); load(); })();