mars 0d57273021 添加数据库集成和用户认证功能
- 新增用户注册和登录系统 (login.html, register.html)
- 集成Supabase数据库连接 (config.js, api.js)
- 完善数据库架构设计 (database-schema.sql)
- 添加部署指南和配置文档 (DEPLOYMENT_GUIDE.md)
- 修复主页面结构和功能完善 (index.html)
- 支持通话记录保存到数据库
- 完整的账单管理和用户认证流程
- 集成OpenAI、Twilio、Stripe等API服务
2025-06-30 19:34:58 +08:00

325 lines
9.2 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录 - 翻译服务平台</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.login-container {
background: white;
border-radius: 20px;
padding: 40px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
width: 100%;
max-width: 400px;
text-align: center;
}
.logo {
width: 80px;
height: 80px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 20px;
margin: 0 auto 30px;
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
color: white;
font-weight: bold;
}
h1 {
color: #333;
margin-bottom: 10px;
font-size: 28px;
font-weight: 600;
}
.subtitle {
color: #666;
margin-bottom: 40px;
font-size: 16px;
}
.form-group {
margin-bottom: 25px;
text-align: left;
}
label {
display: block;
margin-bottom: 8px;
color: #333;
font-weight: 500;
font-size: 14px;
}
input[type="email"],
input[type="password"] {
width: 100%;
padding: 15px 20px;
border: 2px solid #e1e5e9;
border-radius: 12px;
font-size: 16px;
transition: all 0.3s ease;
background: #f8f9fa;
}
input[type="email"]:focus,
input[type="password"]:focus {
outline: none;
border-color: #667eea;
background: white;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.login-btn {
width: 100%;
padding: 15px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 12px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
margin-bottom: 20px;
}
.login-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
}
.login-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.forgot-password {
color: #667eea;
text-decoration: none;
font-size: 14px;
margin-bottom: 30px;
display: inline-block;
}
.forgot-password:hover {
text-decoration: underline;
}
.divider {
margin: 30px 0;
position: relative;
text-align: center;
}
.divider::before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1px;
background: #e1e5e9;
}
.divider span {
background: white;
padding: 0 20px;
color: #666;
font-size: 14px;
}
.register-link {
color: #667eea;
text-decoration: none;
font-weight: 500;
}
.register-link:hover {
text-decoration: underline;
}
.error-message {
background: #fee;
color: #c33;
padding: 12px;
border-radius: 8px;
margin-bottom: 20px;
font-size: 14px;
border: 1px solid #fcc;
}
.success-message {
background: #efe;
color: #3c3;
padding: 12px;
border-radius: 8px;
margin-bottom: 20px;
font-size: 14px;
border: 1px solid #cfc;
}
.loading {
display: inline-block;
width: 20px;
height: 20px;
border: 2px solid #ffffff;
border-radius: 50%;
border-top-color: transparent;
animation: spin 1s ease-in-out infinite;
margin-right: 10px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
@media (max-width: 480px) {
.login-container {
padding: 30px 20px;
margin: 10px;
}
h1 {
font-size: 24px;
}
}
</style>
</head>
<body>
<div class="login-container">
<div class="logo"></div>
<h1>欢迎回来</h1>
<p class="subtitle">登录您的翻译服务账户</p>
<div id="message-container"></div>
<form id="loginForm">
<div class="form-group">
<label for="email">邮箱地址</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" id="password" name="password" required>
</div>
<button type="submit" class="login-btn" id="loginBtn">
<span class="btn-text">登录</span>
</button>
</form>
<a href="#" class="forgot-password">忘记密码?</a>
<div class="divider">
<span>还没有账户?</span>
</div>
<a href="register.html" class="register-link">立即注册</a>
</div>
<!-- 引入必要的脚本 -->
<script src="https://unpkg.com/@supabase/supabase-js@2"></script>
<script src="config.js"></script>
<script src="api.js"></script>
<script>
// 登录表单处理
document.getElementById('loginForm').addEventListener('submit', async (e) => {
e.preventDefault();
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
const loginBtn = document.getElementById('loginBtn');
const messageContainer = document.getElementById('message-container');
// 显示加载状态
loginBtn.disabled = true;
loginBtn.innerHTML = '<span class="loading"></span>登录中...';
try {
const result = await apiManager.login(email, password);
if (result.success) {
showMessage('登录成功!正在跳转...', 'success');
// 延迟跳转,让用户看到成功消息
setTimeout(() => {
window.location.href = '../index.html';
}, 1500);
} else {
showMessage(result.error || '登录失败,请检查邮箱和密码', 'error');
}
} catch (error) {
showMessage('登录失败:' + error.message, 'error');
} finally {
// 恢复按钮状态
loginBtn.disabled = false;
loginBtn.innerHTML = '<span class="btn-text">登录</span>';
}
});
// 显示消息
function showMessage(message, type) {
const messageContainer = document.getElementById('message-container');
const messageClass = type === 'success' ? 'success-message' : 'error-message';
messageContainer.innerHTML = `<div class="${messageClass}">${message}</div>`;
// 3秒后自动清除消息
setTimeout(() => {
messageContainer.innerHTML = '';
}, 3000);
}
// 检查是否已登录
window.addEventListener('load', async () => {
// 等待API管理器初始化
await new Promise(resolve => {
const checkInit = () => {
if (window.apiManager && window.apiManager.supabase) {
resolve();
} else {
setTimeout(checkInit, 100);
}
};
checkInit();
});
// 如果已登录,直接跳转到主页
if (apiManager.currentUser) {
window.location.href = '../index.html';
}
});
// 回车键登录
document.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
document.getElementById('loginForm').dispatchEvent(new Event('submit'));
}
});
</script>
</body>
</html>