import { createClient } from '@supabase/supabase-js'; import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'; // 环境变量检查和默认值 const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || 'https://demo.supabase.co'; const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || 'demo-key'; const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY || 'demo-service-key'; // 检查是否在开发环境中使用默认配置 const isDemoMode = supabaseUrl === 'https://demo.supabase.co'; // 客户端使用的 Supabase 客户端 export const supabase = isDemoMode ? createClient(supabaseUrl, supabaseAnonKey, { realtime: { params: { eventsPerSecond: 0, }, }, auth: { persistSession: false, autoRefreshToken: false, }, }) : createClient(supabaseUrl, supabaseAnonKey); // 组件中使用的 Supabase 客户端 export const createSupabaseClient = () => { if (isDemoMode) { // 在演示模式下返回一个模拟客户端 return { auth: { getUser: () => Promise.resolve({ data: { user: null }, error: null }), signInWithPassword: () => Promise.resolve({ data: null, error: { message: '演示模式:请配置 Supabase 环境变量' } }), signOut: () => Promise.resolve({ error: null }), onAuthStateChange: () => ({ data: { subscription: { unsubscribe: () => {} } } }), } } as any; } return createClientComponentClient(); }; // 服务端使用的 Supabase 客户端(具有管理员权限) export const supabaseAdmin = isDemoMode ? createClient(supabaseUrl, supabaseServiceKey, { auth: { autoRefreshToken: false, persistSession: false, }, realtime: { params: { eventsPerSecond: 0, }, }, }) : createClient(supabaseUrl, supabaseServiceKey, { auth: { autoRefreshToken: false, }, }); // 数据库表名常量 export const TABLES = { USERS: 'users', CALLS: 'calls', APPOINTMENTS: 'appointments', INTERPRETERS: 'interpreters', DOCUMENTS: 'document_translations', ORDERS: 'orders', INVOICES: 'invoices', ENTERPRISE_EMPLOYEES: 'enterprise_employees', PRICING_RULES: 'pricing_rules', NOTIFICATIONS: 'notifications', SYSTEM_SETTINGS: 'system_settings', ACCOUNT_BALANCES: 'account_balances', } as const; // 实时订阅配置 export const REALTIME_CHANNELS = { CALLS: 'calls:*', NOTIFICATIONS: 'notifications:*', APPOINTMENTS: 'appointments:*', } as const; // 用户认证相关函数 export const auth = { // 获取当前用户 getCurrentUser: async () => { const { data: { user }, error } = await supabase.auth.getUser(); if (error) throw error; return user; }, // 登录 signIn: async (email: string, password: string) => { const { data, error } = await supabase.auth.signInWithPassword({ email, password, }); if (error) throw error; return data; }, // 注册 signUp: async (email: string, password: string, metadata?: any) => { const { data, error } = await supabase.auth.signUp({ email, password, options: { data: metadata, }, }); if (error) throw error; return data; }, // 登出 signOut: async () => { const { error } = await supabase.auth.signOut(); if (error) throw error; }, // 重置密码 resetPassword: async (email: string) => { const { data, error } = await supabase.auth.resetPasswordForEmail(email, { redirectTo: `${window.location.origin}/auth/reset-password`, }); if (error) throw error; return data; }, // 更新密码 updatePassword: async (password: string) => { const { data, error } = await supabase.auth.updateUser({ password, }); if (error) throw error; return data; }, }; // 数据库操作辅助函数 export const db = { // 通用查询函数 select: async (table: string, query?: any) => { let queryBuilder = supabase.from(table).select(query || '*'); const { data, error } = await queryBuilder; if (error) throw error; return data as T[]; }, // 通用插入函数 insert: async (table: string, data: any) => { const { data: result, error } = await supabase .from(table) .insert(data) .select() .single(); if (error) throw error; return result as T; }, // 通用更新函数 update: async (table: string, id: string, data: any) => { const { data: result, error } = await supabase .from(table) .update(data) .eq('id', id) .select() .single(); if (error) throw error; return result as T; }, // 通用删除函数 delete: async (table: string, id: string) => { const { error } = await supabase .from(table) .delete() .eq('id', id); if (error) throw error; }, // 分页查询函数 paginate: async ( table: string, page: number = 1, limit: number = 10, query?: any, orderBy?: { column: string; ascending?: boolean } ) => { const from = (page - 1) * limit; const to = from + limit - 1; let queryBuilder = supabase .from(table) .select(query || '*', { count: 'exact' }) .range(from, to); if (orderBy) { queryBuilder = queryBuilder.order(orderBy.column, { ascending: orderBy.ascending ?? true, }); } const { data, error, count } = await queryBuilder; if (error) throw error; return { data: data as T[], total: count || 0, page, limit, has_more: (count || 0) > page * limit, }; }, }; // 文件上传函数 export const storage = { // 上传文件 upload: async (bucket: string, path: string, file: File) => { const { data, error } = await supabase.storage .from(bucket) .upload(path, file, { cacheControl: '3600', upsert: false, }); if (error) throw error; return data; }, // 获取文件公共URL getPublicUrl: (bucket: string, path: string) => { const { data } = supabase.storage .from(bucket) .getPublicUrl(path); return data.publicUrl; }, // 删除文件 remove: async (bucket: string, paths: string[]) => { const { data, error } = await supabase.storage .from(bucket) .remove(paths); if (error) throw error; return data; }, }; // 实时订阅函数 export const realtime = { // 订阅表变化 subscribe: ( table: string, callback: (payload: any) => void, filter?: string ) => { if (isDemoMode) { // 演示模式下返回模拟的订阅对象 return { unsubscribe: () => {}, }; } const channel = supabase .channel(`${table}-changes`) .on( 'postgres_changes', { event: '*', schema: 'public', table, filter, }, callback ) .subscribe(); return channel; }, // 取消订阅 unsubscribe: (channel: any) => { if (isDemoMode) { return; } supabase.removeChannel(channel); }, };