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

352 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// API 管理文件
class APIManager {
constructor() {
this.supabase = null;
this.currentUser = null;
this.init();
}
// 初始化 Supabase 客户端
async init() {
try {
// 加载 Supabase 客户端
const { createClient } = supabase;
this.supabase = createClient(CONFIG.SUPABASE.URL, CONFIG.SUPABASE.ANON_KEY);
// 检查用户登录状态
await this.checkAuthStatus();
console.log('API Manager 初始化成功');
} catch (error) {
console.error('API Manager 初始化失败:', error);
}
}
// 检查认证状态
async checkAuthStatus() {
try {
const { data: { user } } = await this.supabase.auth.getUser();
this.currentUser = user;
if (user) {
console.log('用户已登录:', user.email);
this.updateUIForLoggedInUser(user);
} else {
console.log('用户未登录');
this.updateUIForLoggedOutUser();
}
} catch (error) {
console.error('检查认证状态失败:', error);
}
}
// 用户注册
async register(email, password, userData = {}) {
try {
const { data, error } = await this.supabase.auth.signUp({
email: email,
password: password,
options: {
data: {
full_name: userData.fullName || '',
phone: userData.phone || '',
...userData
}
}
});
if (error) throw error;
// 创建用户档案
if (data.user) {
await this.createUserProfile(data.user, userData);
}
return { success: true, data: data };
} catch (error) {
console.error('注册失败:', error);
return { success: false, error: error.message };
}
}
// 用户登录
async login(email, password) {
try {
const { data, error } = await this.supabase.auth.signInWithPassword({
email: email,
password: password
});
if (error) throw error;
this.currentUser = data.user;
this.updateUIForLoggedInUser(data.user);
return { success: true, data: data };
} catch (error) {
console.error('登录失败:', error);
return { success: false, error: error.message };
}
}
// 用户登出
async logout() {
try {
const { error } = await this.supabase.auth.signOut();
if (error) throw error;
this.currentUser = null;
this.updateUIForLoggedOutUser();
return { success: true };
} catch (error) {
console.error('登出失败:', error);
return { success: false, error: error.message };
}
}
// 创建用户档案
async createUserProfile(user, userData) {
try {
const { data, error } = await this.supabase
.from('user_profiles')
.insert([
{
id: user.id,
email: user.email,
full_name: userData.fullName || '',
phone: userData.phone || '',
avatar_url: userData.avatarUrl || '',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
}
]);
if (error) throw error;
return data;
} catch (error) {
console.error('创建用户档案失败:', error);
throw error;
}
}
// 获取用户档案
async getUserProfile(userId = null) {
try {
const id = userId || this.currentUser?.id;
if (!id) throw new Error('用户未登录');
const { data, error } = await this.supabase
.from('user_profiles')
.select('*')
.eq('id', id)
.single();
if (error) throw error;
return data;
} catch (error) {
console.error('获取用户档案失败:', error);
throw error;
}
}
// 更新用户档案
async updateUserProfile(updates) {
try {
if (!this.currentUser) throw new Error('用户未登录');
const { data, error } = await this.supabase
.from('user_profiles')
.update({
...updates,
updated_at: new Date().toISOString()
})
.eq('id', this.currentUser.id);
if (error) throw error;
return data;
} catch (error) {
console.error('更新用户档案失败:', error);
throw error;
}
}
// 创建通话记录
async createCallRecord(callData) {
try {
if (!this.currentUser) throw new Error('用户未登录');
const { data, error } = await this.supabase
.from('call_records')
.insert([
{
user_id: this.currentUser.id,
call_type: callData.type, // 'voice' or 'video'
duration: callData.duration, // 通话时长(秒)
has_translator: callData.hasTranslator || false,
base_rate: callData.baseRate, // 基础费率
translator_rate: callData.translatorRate || 0, // 翻译费率
total_amount: callData.totalAmount, // 总金额
status: callData.status || 'completed', // 'pending', 'completed', 'cancelled'
created_at: new Date().toISOString()
}
]);
if (error) throw error;
return data;
} catch (error) {
console.error('创建通话记录失败:', error);
throw error;
}
}
// 获取通话记录
async getCallRecords(limit = 50) {
try {
if (!this.currentUser) throw new Error('用户未登录');
const { data, error } = await this.supabase
.from('call_records')
.select('*')
.eq('user_id', this.currentUser.id)
.order('created_at', { ascending: false })
.limit(limit);
if (error) throw error;
return data;
} catch (error) {
console.error('获取通话记录失败:', error);
throw error;
}
}
// 创建预约记录
async createAppointment(appointmentData) {
try {
if (!this.currentUser) throw new Error('用户未登录');
const { data, error } = await this.supabase
.from('appointments')
.insert([
{
user_id: this.currentUser.id,
translator_id: appointmentData.translatorId,
appointment_date: appointmentData.date,
appointment_time: appointmentData.time,
service_type: appointmentData.serviceType, // 'voice', 'video', 'document'
language_pair: appointmentData.languagePair, // '中文-英文'
duration: appointmentData.duration || 60, // 预约时长(分钟)
notes: appointmentData.notes || '',
status: 'pending', // 'pending', 'confirmed', 'completed', 'cancelled'
created_at: new Date().toISOString()
}
]);
if (error) throw error;
return data;
} catch (error) {
console.error('创建预约失败:', error);
throw error;
}
}
// 获取预约记录
async getAppointments() {
try {
if (!this.currentUser) throw new Error('用户未登录');
const { data, error } = await this.supabase
.from('appointments')
.select(`
*,
translator_profiles (
full_name,
avatar_url,
languages,
rating
)
`)
.eq('user_id', this.currentUser.id)
.order('appointment_date', { ascending: true });
if (error) throw error;
return data;
} catch (error) {
console.error('获取预约记录失败:', error);
throw error;
}
}
// 获取翻译员列表
async getTranslators() {
try {
const { data, error } = await this.supabase
.from('translator_profiles')
.select('*')
.eq('is_active', true)
.order('rating', { ascending: false });
if (error) throw error;
return data;
} catch (error) {
console.error('获取翻译员列表失败:', error);
throw error;
}
}
// 更新UI - 已登录用户
updateUIForLoggedInUser(user) {
// 显示用户信息
const userNameElements = document.querySelectorAll('.user-name');
userNameElements.forEach(el => {
el.textContent = user.user_metadata?.full_name || user.email;
});
// 显示/隐藏相关元素
const loginElements = document.querySelectorAll('.login-required');
loginElements.forEach(el => el.style.display = 'none');
const userElements = document.querySelectorAll('.user-only');
userElements.forEach(el => el.style.display = 'block');
}
// 更新UI - 未登录用户
updateUIForLoggedOutUser() {
// 隐藏/显示相关元素
const loginElements = document.querySelectorAll('.login-required');
loginElements.forEach(el => el.style.display = 'block');
const userElements = document.querySelectorAll('.user-only');
userElements.forEach(el => el.style.display = 'none');
}
// Stripe 支付处理
async processPayment(amount, callRecordId) {
try {
// 这里应该调用后端API来处理Stripe支付
// 由于安全考虑Stripe的secret key不应该在前端使用
console.log('处理支付:', amount, callRecordId);
// 模拟支付成功
return { success: true, paymentId: 'pi_test_' + Date.now() };
} catch (error) {
console.error('支付处理失败:', error);
return { success: false, error: error.message };
}
}
// Twilio 视频通话初始化
async initVideoCall() {
try {
// 这里应该调用后端API获取Twilio访问令牌
console.log('初始化视频通话');
return { success: true, token: 'twilio_token_placeholder' };
} catch (error) {
console.error('视频通话初始化失败:', error);
return { success: false, error: error.message };
}
}
}
// 创建全局API管理器实例
window.apiManager = new APIManager();