function i18n(key) { return lang[selectedLang][key] || key; } // 显示用户中心特定部分 async function showUserCenterSection(section) { try { const userInfo = await fetchUserInfo(); if (!userInfo) { alert(lang[selectedLang].pleaseLogin); window.location.href = 'login.html'; // 重定向到登录页面 return; } // 检查邮箱验证状态 const emailVerified = userInfo.email_verified === 'True' || userInfo.email_verified === true; console.log('Email Verified:', emailVerified); // 打印邮箱验证状态 if (!emailVerified && section !== 'profile') { alert(lang[selectedLang].pleaseVerifyEmail); section = 'profile'; // 如果邮箱未验证,强制显示个人资料页面 // showUserCenterSection('profile'); // 跳转到个人资料页面 return; } const dashboardContent = document.getElementById('dashboardContent'); const usersContent = document.getElementById('usersContent'); const chatContent = document.getElementById('chatContent'); const featureContent = document.getElementById('featureContent'); const userCenterContent = document.getElementById('userCenterContent'); const pageTitle = document.getElementById('pageTitle'); const showApiDocs = document.getElementById('showApiDocs'); const apiDocsContent = document.getElementById('apiDocsContent'); if (apiDocsContent) apiDocsContent.style.display = 'none'; if (dashboardContent) dashboardContent.style.display = 'none'; if (usersContent) usersContent.style.display = 'none'; if (chatContent) chatContent.style.display = 'none'; if (featureContent) featureContent.style.display = 'none'; if (userCenterContent) userCenterContent.style.display = 'block'; if (showApiDocs) showApiDocs.style.display = 'none'; // 根据选择的部分设置相应的标题 if (pageTitle) { switch(section) { case 'profile': pageTitle.innerText = i18n('personalInfo'); break; case 'apiKey': pageTitle.innerText = i18n('apiKeys'); break; case 'apiUsage': pageTitle.innerText = i18n('modelCalls'); break; default: pageTitle.innerText = i18n('userCenter'); } } const navButtons = document.querySelectorAll('.user-center-nav-btn'); const sections = document.querySelectorAll('.user-center-section'); navButtons.forEach(btn => btn.classList.remove('active')); sections.forEach(sec => sec.classList.remove('active')); const targetButton = document.querySelector(`.user-center-nav-btn[data-target="${section}"]`); const targetSection = document.getElementById(`${section}Section`); if (targetButton) targetButton.classList.add('active'); if (targetSection) targetSection.classList.add('active'); if (section === 'profile') { loadUserProfile(); } else if (section === 'apiKey') { loadApiKeys(); } else if (section === 'apiUsage') { loadapiUsage(); } } catch (error) { console.error('Error in showFeature:', error); alert(lang[selectedLang].errorGettingUserInfo); } } // 将 showUserCenterSection 函数添加到全局作用域 window.showUserCenterSection = showUserCenterSection; const BASE_URL = 'https://user.obscura.work/user'; function updateAllAvatars(avatarUrl) { const avatars = document.querySelectorAll('.user-avatar, #currentAvatar'); avatars.forEach(avatar => { avatar.src = avatarUrl || 'picture/cn__03041_.png'; }); } // 加载用户个人资料 async function loadUserProfile() { try { const response = await fetch(`${BASE_URL}/me`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}` } }); if (response.ok) { const userData = await response.json(); const profileSection = document.getElementById('profileSection'); updateAllAvatars(userData.avatar) profileSection.innerHTML = `

${i18n("basicInfo")}

${i18n("usernameDescription")}

${i18n("emailDescription")}

用户头像

${i18n("userVerification")}

${i18n("emailVerification")}${userData.email_verified ? i18n("verified") : i18n("unverified")}

${userData.email_verified ? '' : ` `}

${i18n("phoneVerification")}${userData.phone_verified ? i18n("verified") : i18n("unverified")}

${userData.phone_verified ? '' : ` `}
`; document.getElementById('profileForm').addEventListener('submit', updateProfile); if (!userData.email_verified) { document.getElementById('sendVerificationEmail').addEventListener('click', sendVerificationEmail); document.getElementById('submitVerificationCode').addEventListener('click', submitVerificationCode); } if (!userData.phone_verified) { document.getElementById('sendPhoneVerification').addEventListener('click', sendPhoneVerification); document.getElementById('submitPhoneVerificationCode').addEventListener('click', submitPhoneVerificationCode); } } else { console.error(i18n('loadProfileFailed')); } } catch (error) { console.error(i18n('loadProfileError'), error); } } // 提交验证码 async function sendVerificationEmail() { const sendButton = document.getElementById('sendVerificationEmail'); if (sendButton.disabled) { return; // 如果按钮已经被禁用,直接返回 } try { const response = await fetch(`${BASE_URL}/send-verification-email`, { method: 'POST', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}` } }); if (response.ok) { alert(i18n('verificationEmailSent')); document.getElementById('verificationCodeSection').style.display = 'block'; // 禁用按钮并开始倒计时 sendButton.disabled = true; let countdown = 60; sendButton.textContent = `${i18n('resend')} (${countdown}s)`; const timer = setInterval(() => { countdown--; if (countdown <= 0) { clearInterval(timer); sendButton.disabled = false; sendButton.textContent = i18n('sendVerificationEmail'); } else { sendButton.textContent = `${i18n('resend')} (${countdown}s)`; } }, 1000); } else { const errorData = await response.json(); alert(`${i18n('sendVerificationEmailFailed')}${errorData.detail || i18n('unknownError')}`); } } catch (error) { console.error(i18n('sendVerificationEmailError'), error); alert(i18n('sendVerificationEmailError')); } } async function submitVerificationCode() { const verificationCode = document.getElementById('verificationCode').value; console.log(i18n('submittingVerificationCode'), verificationCode); try { const response = await fetch(`${BASE_URL}/verify-email`, { method: 'POST', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}`, 'Content-Type': 'application/x-www-form-urlencoded' }, body: `verification_code=${encodeURIComponent(verificationCode)}` }); if (response.ok) { alert(i18n('emailVerificationSuccess')); loadUserProfile(); } else { const errorData = await response.json(); console.error('Error response:', errorData); alert(`${i18n('verificationFailed')}${errorData.detail || i18n('unknownError')}`); } } catch (error) { console.error(i18n('submitVerificationCodeError'), error); alert(i18n('submitVerificationCodeError')); } } // 新增发送手机验证短信的函数 async function sendPhoneVerification() { const sendButton = document.getElementById('sendPhoneVerification'); if (sendButton.disabled) { return; } try { const response = await fetch(`${BASE_URL}/send-phone-verification`, { method: 'POST', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}` } }); if (response.ok) { alert(i18n('verificationSMSSent')); document.getElementById('phoneVerificationCodeSection').style.display = 'block'; sendButton.disabled = true; let countdown = 60; sendButton.textContent = `${i18n('resend')} (${countdown}s)`; const timer = setInterval(() => { countdown--; if (countdown <= 0) { clearInterval(timer); sendButton.disabled = false; sendButton.textContent = i18n('sendPhoneVerification'); } else { sendButton.textContent = `${i18n('resend')} (${countdown}s)`; } }, 1000); } else { const errorData = await response.json(); alert(`${i18n('sendVerificationSMSFailed')}${errorData.detail || i18n('unknownError')}`); } } catch (error) { console.error(i18n('sendVerificationSMSError'), error); alert(i18n('sendVerificationSMSError')); } } // 新增提交手机验证码的函数 async function submitPhoneVerificationCode() { const verificationCode = document.getElementById('phoneVerificationCode').value; try { const response = await fetch(`${BASE_URL}/verify-phone`, { method: 'POST', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}`, 'Content-Type': 'application/x-www-form-urlencoded' }, body: `verification_code=${encodeURIComponent(verificationCode)}` }); if (response.ok) { alert(i18n('phoneVerificationSuccess')); loadUserProfile(); // 重新加载用户资料以更新验证状态 } else { const errorData = await response.json(); alert(`${i18n('verificationFailed')}${errorData.detail || i18n('unknownError')}`); } } catch (error) { console.error(i18n('submitPhoneVerificationCodeError'), error); alert(i18n('submitPhoneVerificationCodeError')); } } // / 打开头像选择模态框 function openAvatarModal() { const modal = document.createElement('div'); modal.className = 'avatar-modal'; modal.innerHTML = `

${i18n("selectAvatar")}

`; document.body.appendChild(modal); loadAvatarOptions(); } // 加载头像选项 async function loadAvatarOptions() { try { const avatars = [ 'picture/cn__02504_.png', 'picture/cn__02505_.png', 'picture/cn__02506_.png', 'picture/cn__02507_.png', 'picture/cn__02510_.png', 'picture/cn__02511_.png', 'picture/cn__02512_.png', 'picture/cn__03018_.png', 'picture/cn__03040_.png', 'picture/cn__03041_.png', 'picture/cn__03042_.png', 'picture/cn__03044_.png', 'picture/cn__03059_.png' ]; const avatarOptions = document.getElementById('avatarOptions'); avatarOptions.innerHTML = avatars.map(avatar => ` 头像选项 `).join(''); } catch (error) { console.error(i18n('loadAvatarOptionsError'), error); } } // 选择头像 function selectAvatar(avatarUrl) { document.getElementById('currentAvatar').src = avatarUrl; document.getElementById('userAvatar').src = avatarUrl; closeAvatarModal(); updateUserAvatar(avatarUrl); // 添加这行来保存头像更改 } async function updateUserAvatar(avatarUrl) { try { const response = await fetch(`${BASE_URL}/me`, { method: 'PUT', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ avatar: avatarUrl }) }); if (response.ok) { console.log(i18n('avatarUpdateSuccess')); updateAllAvatars(avatarUrl); } else { const errorData = await response.json(); console.error(i18n('avatarUpdateFailed'), errorData); alert(`${i18n('avatarUpdateFailed')}${errorData.detail || i18n('unknownError')}`); } } catch (error) { console.error(i18n('avatarUpdateError'), error); alert(i18n('avatarUpdateError')); } } // 关闭头像选择模态框 function closeAvatarModal() { const modal = document.querySelector('.avatar-modal'); if (modal) { modal.remove(); } } async function updateProfile(event) { event.preventDefault(); const email = document.getElementById('email').value; const phone_number = document.getElementById('phone_number').value; const avatar = document.getElementById('currentAvatar').src; try { const response = await fetch(`${BASE_URL}/me`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('access_token')}` }, body: JSON.stringify({ email, phone_number, avatar }) }); if (response.ok) { alert(i18n('profileUpdateSuccess')); } else { const errorData = await response.json(); alert(`${i18n('profileUpdateFailed')}${errorData.detail || i18n('unknownError')}`); } } catch (error) { console.error(i18n('profileUpdateError'), error); alert(i18n('profileUpdateError')); } } // 遮蔽 API 密钥 function maskApiKey(key) { if (!key) return i18n('invalidApiKey'); return key.substring(0, 4) + '*'.repeat(Math.max(0, key.length - 8)) + key.substring(Math.max(0, key.length - 4)); } // 加载 API 密钥 async function loadApiKeys() { try { const response = await fetch(`${BASE_URL}/api-keys`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}`, 'Cache-Control': 'no-cache' } }); if (response.ok) { const apiKeys = await response.json(); const apiKeyContent = document.getElementById('apiKeyContent'); apiKeyContent.innerHTML = ` ${apiKeys.map((key, index) => { const actualKey = key.key.replace('api_key:', ''); return ` `; }).join('')}
${i18n("apiKeyTable")} ${i18n("createdAt")} ${i18n("expiresAt")} ${i18n("operation")}
${maskApiKey(actualKey)} ${new Date(key.created_at).toLocaleString()} ${new Date(key.expires_at).toLocaleString()}
`; } else { console.error(i18n('loadApiKeysError'), response.status, response.statusText); const apiKeyContent = document.getElementById('apiKeyContent'); apiKeyContent.innerHTML = `

${i18n('loadApiKeysFailed')}

`; } } catch (error) { console.error(i18n('loadApiKeysError'), error); const apiKeyContent = document.getElementById('apiKeyContent'); apiKeyContent.innerHTML = `

${i18n('loadApiKeysFailed')}

`; } } // 切换 API 密钥可见性 function toggleApiKeyVisibility(index, fullKey) { const keyElement = document.getElementById(`apiKey${index}`); if (keyElement.textContent === fullKey) { keyElement.textContent = maskApiKey(fullKey); } else { keyElement.textContent = fullKey; } } // 复制到剪贴板 function copyToClipboard(text) { navigator.clipboard.writeText(text).then(() => { alert(i18n('apiKeyCopied')); }).catch(err => { console.error(i18n('copyTextFailed'), err); }); } // 生成新的 API 密钥 async function generateNewApiKey() { try { const response = await fetch(`${BASE_URL}/api-keys`, { method: 'POST', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}` } }); if (response.ok) { const newKey = await response.json(); alert(`${i18n('newApiKeyGenerated')}${newKey.api_key}\n${i18n('expirationTime')}${new Date(newKey.expires_at).toLocaleString()}`); loadApiKeys(); // 重新加载 API 密钥列表 } else { const errorData = await response.json(); alert(`${i18n('generateNewApiKeyFailed')}${errorData.detail || i18n('unknownError')}`); } } catch (error) { console.error(i18n('generateNewApiKeyError'), error); alert(i18n('generateNewApiKeyFailed')); } } // 修改 deleteApiKey 函数 async function deleteApiKey(keyId) { const confirmed = confirm(i18n('confirmDeleteApiKey')); if (confirmed) { try { const encodedKeyId = encodeURIComponent(keyId); const response = await fetch(`${BASE_URL}/api-keys/${encodedKeyId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}` } }); const data = await response.json(); if (response.ok) { alert(data.message); } else { const errorData = await response.json(); alert(`${i18n('deleteApiKeyFailed')}${errorData.detail || i18n('unknownError')}`); } if (data.action === 'clear_api_info') { await loadApiKeys(); // 重新加载API密钥列表 } } catch (error) { console.error(i18n('deleteApiKeyError'), error); alert(i18n('deleteApiKeyFailed')); } finally { await loadApiKeys(); // 无论成功与否,都重新加载API密钥列表 } } } // 新增清除缓存并重新加载的函数 // 确保 refreshApiKeys 函数被正确定义 async function refreshApiKeys() { try { await fetch(`${BASE_URL}/clear-cache`, { method: 'POST', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}` } }); console.log(i18n('cacheCleared')); } catch (error) { console.error(i18n('clearCacheFailed'), error); } finally { await loadApiKeys(); console.log(i18n('apiKeyListRefreshed')); } } // 加载模型调用信息 async function loadapiUsage() { try { const response = await fetch(`${BASE_URL}/api-usage`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}` } }); if (response.ok) { const usageData = await response.json(); const apiUsageContent = document.getElementById('apiUsageContent'); apiUsageContent.innerHTML = `

${i18n("apiUsage")}

${i18n("modelUsage")}

${Object.keys(usageData).length === 0 ? `` : Object.entries(usageData).map(([key, usage], index) => ` `).join('') }
API KEY ${i18n("tokensUsed")} ${i18n("totalTokens")} ${i18n("lastUsedAt")}
${i18n("noUsageRecord")}
${maskApiKey(key)} ${usage.tokens_used || 0} token ${usage.total_tokens || 0} token ${usage.last_used_at ? new Date(usage.last_used_at).toLocaleString() : i18n("unused")}

加载中...

`; // 初始显示API使用情况 showApiUsage(); } else { console.error(i18n('loadModelCallInfoError'), response.status, response.statusText); const apiUsageContent = document.getElementById('apiUsageContent'); apiUsageContent.innerHTML = `

${i18n('loadModelCallInfoFailed')}

`; } } catch (error) { console.error(i18n('loadModelCallInfoError'), error); const apiUsageContent = document.getElementById('apiUsageContent'); apiUsageContent.innerHTML = `

${i18n('loadModelCallInfoFailed')}

`; } } // 显示 API 使用情况 function showApiUsage() { document.getElementById('apiUsageBtn').classList.add('active'); document.getElementById('modelUsageBtn').classList.remove('active'); document.getElementById('apiUsageTable').classList.add('active'); document.getElementById('modelUsageTable').classList.remove('active'); // 添加动画效果 document.getElementById('apiUsageTable').style.animation = 'none'; setTimeout(() => { document.getElementById('apiUsageTable').style.animation = 'fadeIn 0.5s ease-in-out'; }, 10); } // 显示模型使用情况 async function showModelUsage() { document.getElementById('apiUsageBtn').classList.remove('active'); document.getElementById('modelUsageBtn').classList.add('active'); document.getElementById('apiUsageTable').classList.remove('active'); document.getElementById('modelUsageTable').classList.add('active'); // 添加动画效果 document.getElementById('modelUsageTable').style.animation = 'none'; setTimeout(() => { document.getElementById('modelUsageTable').style.animation = 'fadeIn 0.5s ease-in-out'; }, 10); // 加载模型使用情况数据 try { const response = await fetch(`${BASE_URL}/model-usage`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}` } }); if (response.ok) { const modelUsageData = await response.json(); const modelUsageTable = document.getElementById('modelUsageTable'); modelUsageTable.innerHTML = ` ${Object.entries(modelUsageData).map(([model, usage]) => ` `).join('')}
${i18n("modelName")} ${i18n("lastCallTime")} ${i18n("usage")}
${model} ${usage.last_called_at ? new Date(usage.last_called_at).toLocaleString() : '未使用'} ${usage.calls} token
`; } else { console.error(i18n('loadModelUsageFailed'), response.status, response.statusText); } } catch (error) { console.error(i18n('loadModelUsageError'), error); document.getElementById('modelUsageTable').innerHTML = `

${i18n('loadModelUsageFailed')}

`; } } // 初始化用户中心 function initUserCenter() { const navButtons = document.querySelectorAll('.user-center-nav-btn'); navButtons.forEach(button => { button.addEventListener('click', () => { const target = button.getAttribute('data-target'); showUserCenterSection(target); }); }); // 加载用户信息并更新头像 fetch(`${BASE_URL}/me`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}` } }) .then(response => response.json()) .then(userData => { updateAllAvatars(userData.avatar); if (!userData.email_verified) { const sendVerificationEmailBtn = document.getElementById('sendVerificationEmail'); const submitVerificationCodeBtn = document.getElementById('submitVerificationCode'); if (sendVerificationEmailBtn) { sendVerificationEmailBtn.addEventListener('click', sendVerificationEmail); } if (submitVerificationCodeBtn) { submitVerificationCodeBtn.addEventListener('click', submitVerificationCode); } } }) .catch(error => console.error(i18n('getUserInfoFailed'), error)); } // 页面加载完成后初始化用户中心 window.addEventListener('load', initUserCenter); // 将 showUserCenterSection 函数添加到全局作用域 window.showUserCenterSection = showUserCenterSection; window.generateNewApiKey = generateNewApiKey; window.deleteApiKey = deleteApiKey; window.copyToClipboard = copyToClipboard; window.refreshApiKeys = refreshApiKeys; window.loadapiUsage = loadapiUsage; window.showApiUsage = showApiUsage; window.showModelUsage = showModelUsage; window.toggleApiKeyVisibility = toggleApiKeyVisibility; window.openAvatarModal = openAvatarModal; window.selectAvatar = selectAvatar; window.closeAvatarModal = closeAvatarModal; window.showUserCenterSection = showUserCenterSection; window.sendPhoneVerification = sendPhoneVerification; window.submitPhoneVerificationCode = submitPhoneVerificationCode; window.sendVerificationEmail = sendVerificationEmail; window.submitVerificationCode = submitVerificationCode; // 获取用户信息的函数 async function fetchUserInfo() { try { const token = localStorage.getItem('access_token'); if (!token) { console.error(i18n('noAccessTokenFound')); return null; } const response = await fetch(`${BASE_URL}/me`, { headers: { 'Authorization': `Bearer ${token}` } }); if (!response.ok) { console.error(i18n('failedToFetchUserInfo')); return null; } const userInfo = await response.json(); return userInfo; } catch (error) { console.error(i18n('errorFetchingUserInfo'), error); // 可以在这里处理错误,比如清除 token 并重定向到登录页面 localStorage.removeItem('access_token'); window.location.href = 'login.html'; // 重定向到登录页面 return null; } }