import React, { useState, useEffect } from 'react'; import { X, Check, User, LogOut, ClipboardList, Sun, Moon } from 'lucide-react'; export default function App() { // --- 後端 API 網址 (請替換為你的 Cloudflare Worker 網址) --- const API_URL = 'https://treasure-bowl.sbackfud.workers.dev'; // --- 狀態管理 --- // 當前登入的使用者與 Token const [currentUser, setCurrentUser] = useState(null); const [authToken, setAuthToken] = useState(null); // 紀錄資料 const [userRecords, setUserRecords] = useState([]); // 登入後的雲端紀錄 const [guestRecords, setGuestRecords] = useState([]); // 訪客的本地紀錄 // 深色模式狀態 const [isDarkMode, setIsDarkMode] = useState(false); // 登入/註冊彈窗狀態 const [authModal, setAuthModal] = useState({ isOpen: false, type: 'login' }); const [authForm, setAuthForm] = useState({ username: '', password: '', confirm: '' }); const [authError, setAuthError] = useState(''); // 度數狀態,預設排到 200 度 const [degrees, setDegrees] = useState([ 45, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200 ]); // --- 初始化:檢查是否已登入 --- useEffect(() => { const token = localStorage.getItem('treasure_token'); const user = localStorage.getItem('treasure_user'); if (token && user) { setAuthToken(token); setCurrentUser(user); fetchUserRecords(token); } }, []); // 取得雲端紀錄 const fetchUserRecords = async (token) => { try { const res = await fetch(`${API_URL}/records`, { headers: { 'Authorization': `Bearer ${token}` } }); const data = await res.json(); if (data.success) { setUserRecords(data.records); } else if (res.status === 401) { handleLogout(); // Token 過期或無效 } } catch (e) { console.error('無法載入紀錄', e); } }; // 取得目前的紀錄列表 (有登入看專屬雲端紀錄,沒登入看訪客紀錄) const currentRecords = currentUser ? userRecords : guestRecords; // 處理點擊打勾或 X const handleAction = async (degree, actionType) => { const now = new Date(); const timeString = now.toLocaleTimeString('zh-TW', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' }); const dateString = now.toLocaleDateString('zh-TW'); const fullTime = `${dateString} ${timeString}`; const newRecord = { id: Date.now(), // 暫時的 ID,避免畫面延遲 time: fullTime, degree: degree, action: actionType }; if (currentUser && authToken) { // 樂觀更新 UI (讓點擊瞬間就有反應) setUserRecords(prev => [newRecord, ...prev]); // 同步到雲端 try { await fetch(`${API_URL}/records`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${authToken}` }, body: JSON.stringify({ time: fullTime, degree, action: actionType }) }); // 實際應用中可以在此重新 fetchUserRecords() 以獲得真正的資料庫 ID } catch (e) { console.error('紀錄同步失敗', e); } } else { // 訪客模式,只保存在本地 setGuestRecords(prev => [newRecord, ...prev]); } }; // 增加 100 度的級距 (10 個欄位) const addMoreDegrees = () => { const maxDegree = degrees[degrees.length - 1]; const newDegrees = Array.from({ length: 10 }, (_, i) => maxDegree + (i + 1) * 10); setDegrees(prev => [...prev, ...newDegrees]); }; // 清除所有紀錄 const handleClearRecords = async () => { if (window.confirm('確定要清除所有紀錄嗎?')) { if (currentUser && authToken) { setUserRecords([]); // 先清空 UI try { await fetch(`${API_URL}/records`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${authToken}` } }); } catch (e) { console.error('清除雲端紀錄失敗', e); } } else { setGuestRecords([]); } } }; // 處理表單輸入 const handleInputChange = (e) => { setAuthForm({ ...authForm, [e.target.name]: e.target.value }); setAuthError(''); }; // 送出註冊或登入 const submitAuth = async (e) => { e.preventDefault(); const { username, password, confirm } = authForm; if (!username || !password) { setAuthError('帳號與密碼不能為空'); return; } const endpoint = authModal.type === 'register' ? '/register' : '/login'; if (authModal.type === 'register' && password !== confirm) { setAuthError('兩次輸入的密碼不一致'); return; } try { const res = await fetch(`${API_URL}${endpoint}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const data = await res.json(); if (data.success) { localStorage.setItem('treasure_token', data.token); localStorage.setItem('treasure_user', data.username); setAuthToken(data.token); setCurrentUser(data.username); closeAuthModal(); fetchUserRecords(data.token); if (authModal.type === 'register') alert('註冊成功並已自動登入!'); } else { setAuthError(data.error || '發生錯誤'); } } catch (e) { setAuthError('無法連線至伺服器,請確認 API 網址是否正確。'); } }; const closeAuthModal = () => { setAuthModal({ isOpen: false, type: 'login' }); setAuthForm({ username: '', password: '', confirm: '' }); setAuthError(''); }; const handleLogout = () => { localStorage.removeItem('treasure_token'); localStorage.removeItem('treasure_user'); setAuthToken(null); setCurrentUser(null); setUserRecords([]); }; // --- UI 渲染 --- return (
{/* 導覽列與頭部 */}
{/* 左上角深淺色切換 */}
{/* 右上角登入區塊 (非強制) */}
{currentUser ? (
{currentUser}
) : ( <> )}

聚寶盆

說明:木水-人的運勢順  |  金水-身體順

{/* 主要內容區 - 設定固定高度讓內部出現捲軸 */}
{/* 左側:操作區 */}

操作面板

{degrees.map(degree => (
{degree}度
))}
{/* 增加 100 度按鈕 */}
{/* 右側:紀錄區 */}

紀錄清單

{currentUser ? `會員雲端紀錄:${currentUser}` : '本地訪客模式'}
{currentRecords.length === 0 ? (

目前還沒有任何紀錄

) : (
    {currentRecords.map((record, idx) => (
  • {record.time}
    {record.degree}度 {record.action === 'V' ? ( ) : ( )}
  • ))}
)}
{/* 清除紀錄按鈕 */}
{/* 登入/註冊彈窗 */} {authModal.isOpen && (

{authModal.type === 'login' ? '會員登入' : '註冊新帳號'}

{authError && (
{authError}
)}
{authModal.type === 'register' && (
)}
)}
); }