Pi-Search2 / student.html
Lashtw's picture
Upload student.html
ac97948 verified
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>圓周率之神的眷顧 - 信徒儀表板</title>
<style>
:root {
--primary: #d4af37;
--primary-hover: #b49126;
--bg-overlay: rgba(20, 15, 10, 0.85);
--panel: rgba(45, 35, 25, 0.7);
--border: rgba(212, 175, 55, 0.3);
--accent: #fcd34d;
}
* { box-sizing: border-box; }
body {
margin: 0;
padding: 0;
font-family: 'Inter', system-ui, -apple-system, sans-serif;
background: var(--bg-overlay) url('pigod.png') center center / cover fixed;
background-blend-mode: overlay;
color: white;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
width: 100%;
max-width: 400px;
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(15px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 1.5rem;
padding: 2rem;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
animation: slideUp 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes slideUp {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
h1 {
text-align: center;
font-size: 1.5rem;
margin-top: 0;
margin-bottom: 0.5rem;
}
.room-badge {
display: block;
text-align: center;
font-size: 0.875rem;
color: #cbd5e1;
margin-bottom: 2rem;
padding: 0.5rem;
background: rgba(0,0,0,0.2);
border-radius: 0.5rem;
}
.form-group {
margin-bottom: 1.5rem;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
color: #cbd5e1;
}
input {
width: 100%;
padding: 0.875rem 1rem;
background: rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 0.75rem;
color: white;
font-size: 1rem;
transition: all 0.3s ease;
}
input:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.3);
}
button {
background: linear-gradient(135deg, var(--primary), var(--primary-hover));
color: #111;
border: 1px solid rgba(255,255,255,0.2);
padding: 1rem;
font-size: 1.25rem;
border-radius: 0.75rem;
cursor: pointer;
font-weight: bold;
width: 100%;
transition: all 0.2s;
margin-top: 1rem;
box-shadow: 0 4px 6px rgba(0,0,0,0.5);
display: flex;
justify-content: center;
align-items: center;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px var(--border);
}
button:active {
transform: translateY(0);
}
.spinner {
border: 3px solid rgba(255,255,255,0.3);
border-top: 3px solid white;
border-radius: 50%;
width: 24px;
height: 24px;
animation: spin 1s linear infinite;
display: none;
}
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
.success-state {
display: none;
text-align: center;
}
.success-icon {
font-size: 4rem;
margin-bottom: 1rem;
animation: popIn 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes popIn {
0% { transform: scale(0); }
}
.waiting-state, .result-state { display: none; text-align: center; }
.rocket-icon { font-size: 4rem; animation: float 2s ease-in-out infinite; margin-bottom: 1rem;}
@keyframes float {
0% { transform: translateY(0px) rotate(0deg); }
50% { transform: translateY(-15px) scale(1.1) rotate(5deg); }
100% { transform: translateY(0px) rotate(0deg); }
}
.result-box {
background: rgba(212, 175, 55, 0.2);
border: 2px solid var(--primary);
padding: 1.5rem;
border-radius: 1rem;
margin-top: 1.5rem;
}
.result-box.error {
background: rgba(239, 68, 68, 0.2);
border-color: #ef4444;
}
.final-val { font-size: clamp(1.5rem, 8vw, 2.5rem); font-weight: bold; color: var(--accent); margin: 0.5rem 0; white-space: nowrap; }
.trivia-box {
margin-top: 1.5rem;
padding: 1rem;
background: rgba(0,0,0,0.3);
border: 1px dashed var(--border);
border-radius: 0.75rem;
text-align: left;
font-size: 0.9rem;
line-height: 1.4;
color: #cbd5e1;
animation: fadeIn 0.5s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body>
<div class="container" id="mainContainer">
<div id="inputForm">
<h1 style="color: var(--accent); text-align: center; margin-top: 0; font-size: 2rem; text-shadow: 0 2px 4px rgba(0,0,0,0.8);">祈求眷顧</h1>
<p style="text-align: center; color: #d1d5db; margin-bottom: 2rem;">填寫資訊,將你的號碼獻給圓周率之神吧!</p>
<span class="room-badge" id="roomBadge">載入中...</span>
<div class="form-group">
<label for="studentName">信徒尊姓大名</label>
<input type="text" id="studentName" placeholder="例如:王小明" required>
</div>
<div class="form-group">
<label id="luckyNumberLabel" for="luckyNumber">你的幸運數字 (請填滿 X 位數)</label>
<!-- 注意:這裡改用 text,避免手機輸入前導零 (0007) 被瀏覽器吃掉 -->
<input type="text" id="luckyNumber" inputmode="numeric" placeholder="載入中..." required>
<small id="luckyNumberHint" style="color:#9ca3af; display:block; margin-top:0.5rem; font-size:0.85rem;"></small>
</div>
<button id="submitBtn">
<span id="btnText">送出數字</span>
<div class="spinner" id="btnSpinner"></div>
</button>
<div class="trivia-box">
<strong style="color: var(--accent);">💡 圓周率冷知識</strong>
<p id="triviaInput" style="margin: 0.5rem 0 0 0;"></p>
</div>
</div>
<div class="success-state" id="successState">
<div class="success-icon"></div>
<h2 style="color: var(--accent);">獻祭成功!</h2>
<p>神位保留完畢,請仰望老師的大螢幕<br>準備接受神的洗禮。</p>
<div class="trivia-box">
<strong style="color: var(--accent);">💡 圓周率冷知識</strong>
<p id="triviaSuccess" style="margin: 0.5rem 0 0 0;"></p>
</div>
</div>
<div class="waiting-state" id="waitingState">
<div class="rocket-icon"></div>
<h2 style="color: var(--primary);">神諭下達中...</h2>
<p>正在兩億位數的神秘軌跡中<br>尋找你的真理落點!</p>
<div class="trivia-box">
<strong style="color: var(--accent);">💡 圓周率冷知識</strong>
<p id="triviaWaiting" style="margin: 0.5rem 0 0 0;"></p>
</div>
</div>
<div class="result-state" id="resultState">
<h2 style="color: var(--accent);">📜 神諭揭曉 📜</h2>
<div id="resultBox" class="result-box">
<p style="margin:0; font-size:1.2rem;">神之眷顧降臨於:</p>
<div class="final-val" id="finalValText"></div>
<div id="rankContainer" style="display:none; margin-top: 1rem; padding-top: 1rem; border-top: 1px dashed rgba(255,255,255,0.2);">
<p style="margin:0; font-size:1.2rem; color: #d1d5db;">您的總排名為:</p>
<div style="font-size: 2rem; font-weight: bold; color: #fde047; text-shadow: 0 2px 4px rgba(0,0,0,0.8);"><span id="rankValText"></span></div>
</div>
</div>
</div>
</div>
<!-- Firebase SDK (Web Modules) -->
<script type="module">
import { initializeApp } from "https://www.gstatic.com/firebasejs/10.8.1/firebase-app.js";
import { getFirestore, doc, collection, addDoc, serverTimestamp, onSnapshot } from "https://www.gstatic.com/firebasejs/10.8.1/firebase-firestore.js";
const firebaseConfig = {
apiKey: "AIzaSyA2fxxaGAdWSR_QOH2Hm92kttGZmLDH8-w",
authDomain: "pi-search-89a08.firebaseapp.com",
projectId: "pi-search-89a08",
storageBucket: "pi-search-89a08.firebasestorage.app",
messagingSenderId: "1003005654079",
appId: "1:1003005654079:web:636235436f432376d8748a"
};
const piTriviaList = [
"宇宙級精準: NASA 計算整個可觀測宇宙的大小,只要用到 π 小數點後第 39 位,誤差就小於一顆氫原子!",
"你的密碼都在裡面: π 是無限不循環小數,包含所有數字組合。你的生日、電話、未來的密碼,絕對都藏在裡面!",
"神秘的「費曼點」: 在小數點後第 762 位,會突然出現連續六個「9」(999999)!",
"最悲劇的手算: 1873年英國數學家手算了 15 年到第 707 位,結果他在第 527 位就算錯了,後面全部做白工!",
"刻在墓碑的榮耀: 16世紀數學家科伊倫花一輩子只算到第 35 位,但他超驕傲,死後把這 35 個數字刻在了墓碑上。",
"阿基米德的遺言: 古希臘大師阿基米德被敵軍殺死前,正在沙地上算圓周率,他最後大喊:「別踩壞我的圓!」",
"祖沖之超前部署: 西元5世紀,中國數學家祖沖之就算出 π = 3.1415926,這項神級紀錄領先了世界近 900 年!",
"「π」其實很年輕: 人類研究圓周率快 4000 年,但用希臘字母「π」來代表它,大約只有 300 年的歷史。",
"天才的生與死: 3月14日(3.14)剛好是愛因斯坦的生日,也是黑洞大師霍金逝世的日子。",
"鏡子裡的派: 寫下「3.14」拿去照鏡子,字跡會神奇地變成英文的「PIE(派)」!",
"「16」的巧合: 希臘字母「π」是字母表第 16 個;英文字母的「P」也剛剛好是第 16 個!"
];
let currentTriviaIdx = Math.floor(Math.random() * piTriviaList.length);
document.getElementById('triviaInput').innerText = piTriviaList[currentTriviaIdx];
// 取得網址的 room 參數
const urlParams = new URLSearchParams(window.location.search);
const roomCode = urlParams.get('room') || '未指定教室';
document.getElementById('roomBadge').innerHTML = `教室代碼:<strong>${roomCode}</strong>`;
let db = null;
try {
if(firebaseConfig.apiKey !== "YOUR_API_KEY") {
const app = initializeApp(firebaseConfig);
db = getFirestore(app);
}
} catch(e) { console.error("Firebase 初始化失敗:", e); }
// 老師設定的長度
let requiredLength = 0;
// 監聽房間設定狀態
if (db && roomCode !== '未指定教室') {
const roomRef = doc(db, "rooms", roomCode);
onSnapshot(roomRef, (docSnap) => {
if(docSnap.exists()) {
const data = docSnap.data();
if(data.digitLength && requiredLength === 0) {
requiredLength = data.digitLength;
document.getElementById('luckyNumberLabel').innerText = `你的幸運數字 (請填滿 ${requiredLength} 位數)`;
document.getElementById('luckyNumber').placeholder = `例如:${'0'.repeat(requiredLength - 1)}4`;
document.getElementById('luckyNumberHint').innerText = `老師已設定尋找 ${requiredLength} 位數,開頭可以是 0 (如 ${'0'.repeat(requiredLength - 1)}4)`;
document.getElementById('luckyNumber').maxLength = requiredLength;
}
// 如果老師按下了開始搜尋
if(data.isSearching && document.getElementById('successState').style.display === 'block') {
document.getElementById('successState').style.display = 'none';
document.getElementById('waitingState').style.display = 'block';
}
}
});
}
const submitBtn = document.getElementById('submitBtn');
const btnText = document.getElementById('btnText');
const btnSpinner = document.getElementById('btnSpinner');
submitBtn.addEventListener('click', async () => {
if(firebaseConfig.apiKey === "YOUR_API_KEY"){
alert("系統錯誤:老師尚未設定 Firebase!");
return;
}
const name = document.getElementById('studentName').value.trim();
const number = document.getElementById('luckyNumber').value.trim();
if (!name || !number) {
alert('請填寫完整姓名與幸運數字!');
return;
}
if (requiredLength > 0 && number.length !== requiredLength) {
alert(`請輸入剛好 ${requiredLength} 位的代碼喔!\n不夠位數請在前面補 0。`);
return;
}
// UI 狀態:載入中
submitBtn.disabled = true;
btnText.style.display = 'none';
btnSpinner.style.display = 'block';
try {
// 將資料寫入 Firebase 中對應教室的 Subcollection
const studentsRef = collection(db, "rooms", roomCode, "students");
const docRef = await addDoc(studentsRef, {
name: name,
number: number,
timestamp: serverTimestamp()
});
// 更新冷知識
let nextTriviaIdx;
do {
nextTriviaIdx = Math.floor(Math.random() * piTriviaList.length);
} while (nextTriviaIdx === currentTriviaIdx);
document.getElementById('triviaSuccess').innerText = piTriviaList[nextTriviaIdx];
document.getElementById('triviaWaiting').innerText = piTriviaList[nextTriviaIdx];
// UI 狀態:成功
document.getElementById('inputForm').style.display = 'none';
document.getElementById('successState').style.display = 'block';
// 監聽自己的結果是否出爐
onSnapshot(doc(db, "rooms", roomCode, "students", docRef.id), (studentSnap) => {
if (studentSnap.exists()) {
const sData = studentSnap.data();
if (sData.status === 'done') {
document.getElementById('waitingState').style.display = 'none';
document.getElementById('successState').style.display = 'none';
document.getElementById('resultState').style.display = 'block';
const rb = document.getElementById('resultBox');
if (typeof sData.resultVal === 'number') {
document.getElementById('finalValText').innerText = sData.finalOutput;
// 若 Firebase 已寫入 rank 資料,便可顯示總排名
if (sData.rank) {
document.getElementById('rankContainer').style.display = 'block';
document.getElementById('rankValText').innerText = sData.rank;
} else {
document.getElementById('rankContainer').style.display = 'none';
}
} else {
rb.classList.add('error');
document.getElementById('finalValText').innerText = "未尋獲 QQ";
rb.querySelector('p').innerText = "可惜了,這 2 億位數中:";
}
}
} else {
// 如果被刪除 (如老師剔除)
alert("老師已將您從名單中剔除或重置。");
window.location.reload();
}
});
} catch (error) {
console.error("寫入發生錯誤: ", error);
alert("發生錯誤,請稍後再試!\n" + error.message);
// 還原 UI
submitBtn.disabled = false;
btnText.style.display = 'block';
btnSpinner.style.display = 'none';
}
});
</script>
</body>
</html>