2025-07-03 13:12:54 +08:00
|
|
|
|
import { createClient } from '@supabase/supabase-js'
|
|
|
|
|
import { Database } from '../types/database'
|
|
|
|
|
|
|
|
|
|
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
|
|
|
|
|
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
|
|
|
|
|
|
|
|
|
export const supabase = createClient<Database>(supabaseUrl, supabaseAnonKey)
|
2025-06-30 19:42:43 +08:00
|
|
|
|
|
|
|
|
|
// 用户相关接口
|
|
|
|
|
export interface User {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
email: string;
|
|
|
|
|
phone: string;
|
|
|
|
|
userType: 'individual' | 'enterprise' | 'admin';
|
|
|
|
|
status: 'active' | 'inactive' | 'pending';
|
|
|
|
|
createdAt: string;
|
|
|
|
|
lastLogin?: string;
|
|
|
|
|
avatar?: string;
|
|
|
|
|
company?: string;
|
|
|
|
|
totalOrders: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 仪表板统计数据接口
|
|
|
|
|
export interface DashboardStats {
|
|
|
|
|
totalUsers: number;
|
|
|
|
|
totalOrders: number;
|
|
|
|
|
totalRevenue: number;
|
|
|
|
|
activeInterpreters: number;
|
|
|
|
|
todayOrders: number;
|
|
|
|
|
pendingOrders: number;
|
|
|
|
|
completedOrders: number;
|
|
|
|
|
totalCalls: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 最近活动接口
|
|
|
|
|
export interface RecentActivity {
|
|
|
|
|
id: string;
|
|
|
|
|
type: 'order' | 'call' | 'user' | 'payment';
|
|
|
|
|
title: string;
|
|
|
|
|
description: string;
|
|
|
|
|
time: string;
|
|
|
|
|
status: 'success' | 'pending' | 'warning' | 'error';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// API响应接口
|
|
|
|
|
export interface ApiResponse<T> {
|
|
|
|
|
success: boolean;
|
|
|
|
|
data?: T;
|
|
|
|
|
error?: string;
|
|
|
|
|
message?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 用户过滤参数
|
|
|
|
|
export interface UserFilters {
|
|
|
|
|
search?: string;
|
|
|
|
|
userType?: 'all' | 'individual' | 'enterprise' | 'admin';
|
|
|
|
|
status?: 'all' | 'active' | 'inactive' | 'pending';
|
|
|
|
|
page?: number;
|
|
|
|
|
limit?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class ApiService {
|
|
|
|
|
private baseUrl = '/api';
|
|
|
|
|
|
|
|
|
|
// 通用请求方法
|
|
|
|
|
private async request<T>(
|
|
|
|
|
endpoint: string,
|
|
|
|
|
options: RequestInit = {}
|
|
|
|
|
): Promise<ApiResponse<T>> {
|
|
|
|
|
try {
|
|
|
|
|
const token = localStorage.getItem('access_token');
|
|
|
|
|
const response = await fetch(`${this.baseUrl}${endpoint}`, {
|
|
|
|
|
headers: {
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
...(token && { Authorization: `Bearer ${token}` }),
|
|
|
|
|
...options.headers,
|
|
|
|
|
},
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const data = await response.json();
|
|
|
|
|
return data;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(`API request failed: ${endpoint}`, error);
|
|
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
error: error instanceof Error ? error.message : '请求失败',
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取仪表板统计数据
|
|
|
|
|
async getDashboardStats(): Promise<ApiResponse<DashboardStats>> {
|
|
|
|
|
// 先尝试从真实API获取数据
|
|
|
|
|
const response = await this.request<DashboardStats>('/dashboard/stats');
|
|
|
|
|
|
|
|
|
|
// 如果API失败,返回模拟数据
|
|
|
|
|
if (!response.success) {
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: {
|
|
|
|
|
totalUsers: 1248,
|
|
|
|
|
totalOrders: 3567,
|
|
|
|
|
totalRevenue: 245680,
|
|
|
|
|
activeInterpreters: 45,
|
|
|
|
|
todayOrders: 23,
|
|
|
|
|
pendingOrders: 12,
|
|
|
|
|
completedOrders: 3544,
|
|
|
|
|
totalCalls: 2890,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return response;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取最近活动
|
|
|
|
|
async getRecentActivities(): Promise<ApiResponse<RecentActivity[]>> {
|
|
|
|
|
const response = await this.request<RecentActivity[]>('/dashboard/activities');
|
|
|
|
|
|
|
|
|
|
if (!response.success) {
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: [
|
|
|
|
|
{
|
|
|
|
|
id: '1',
|
|
|
|
|
type: 'order',
|
|
|
|
|
title: '新订单创建',
|
|
|
|
|
description: '用户张三创建了文档翻译订单',
|
|
|
|
|
time: '2分钟前',
|
|
|
|
|
status: 'success'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: '2',
|
|
|
|
|
type: 'call',
|
|
|
|
|
title: '通话服务完成',
|
|
|
|
|
description: '英语口译通话服务已完成',
|
|
|
|
|
time: '5分钟前',
|
|
|
|
|
status: 'success'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: '3',
|
|
|
|
|
type: 'user',
|
|
|
|
|
title: '新用户注册',
|
|
|
|
|
description: '企业用户ABC公司完成注册',
|
|
|
|
|
time: '10分钟前',
|
|
|
|
|
status: 'success'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: '4',
|
|
|
|
|
type: 'payment',
|
|
|
|
|
title: '付款待处理',
|
|
|
|
|
description: '订单#1234的付款需要审核',
|
|
|
|
|
time: '15分钟前',
|
|
|
|
|
status: 'warning'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: '5',
|
|
|
|
|
type: 'order',
|
|
|
|
|
title: '订单状态更新',
|
|
|
|
|
description: '文档翻译订单已交付',
|
|
|
|
|
time: '20分钟前',
|
|
|
|
|
status: 'success'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return response;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取用户列表
|
|
|
|
|
async getUsers(filters: UserFilters = {}): Promise<ApiResponse<{ users: User[]; total: number }>> {
|
|
|
|
|
const queryParams = new URLSearchParams();
|
|
|
|
|
|
|
|
|
|
if (filters.search) queryParams.append('search', filters.search);
|
|
|
|
|
if (filters.userType && filters.userType !== 'all') queryParams.append('userType', filters.userType);
|
|
|
|
|
if (filters.status && filters.status !== 'all') queryParams.append('status', filters.status);
|
|
|
|
|
if (filters.page) queryParams.append('page', filters.page.toString());
|
|
|
|
|
if (filters.limit) queryParams.append('limit', filters.limit.toString());
|
|
|
|
|
|
|
|
|
|
const response = await this.request<{ users: User[]; total: number }>(
|
|
|
|
|
`/users?${queryParams.toString()}`
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!response.success) {
|
|
|
|
|
// 返回模拟数据
|
|
|
|
|
const mockUsers: User[] = [
|
|
|
|
|
{
|
|
|
|
|
id: '1',
|
|
|
|
|
name: '张三',
|
|
|
|
|
email: 'zhangsan@example.com',
|
|
|
|
|
phone: '13800138001',
|
|
|
|
|
userType: 'individual',
|
|
|
|
|
status: 'active',
|
|
|
|
|
createdAt: '2024-01-15',
|
|
|
|
|
lastLogin: '2024-01-20 10:30',
|
|
|
|
|
totalOrders: 5
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: '2',
|
|
|
|
|
name: 'ABC公司',
|
|
|
|
|
email: 'contact@abc.com',
|
|
|
|
|
phone: '400-123-4567',
|
|
|
|
|
userType: 'enterprise',
|
|
|
|
|
status: 'active',
|
|
|
|
|
createdAt: '2024-01-10',
|
|
|
|
|
lastLogin: '2024-01-19 15:45',
|
|
|
|
|
company: 'ABC科技有限公司',
|
|
|
|
|
totalOrders: 23
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: '3',
|
|
|
|
|
name: '李四',
|
|
|
|
|
email: 'lisi@example.com',
|
|
|
|
|
phone: '13900139002',
|
|
|
|
|
userType: 'individual',
|
|
|
|
|
status: 'pending',
|
|
|
|
|
createdAt: '2024-01-18',
|
|
|
|
|
totalOrders: 0
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: '4',
|
|
|
|
|
name: '王五',
|
|
|
|
|
email: 'wangwu@example.com',
|
|
|
|
|
phone: '13700137003',
|
|
|
|
|
userType: 'individual',
|
|
|
|
|
status: 'inactive',
|
|
|
|
|
createdAt: '2024-01-12',
|
|
|
|
|
lastLogin: '2024-01-16 09:15',
|
|
|
|
|
totalOrders: 2
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: '5',
|
|
|
|
|
name: '管理员',
|
|
|
|
|
email: 'admin@system.com',
|
|
|
|
|
phone: '13600136004',
|
|
|
|
|
userType: 'admin',
|
|
|
|
|
status: 'active',
|
|
|
|
|
createdAt: '2024-01-01',
|
|
|
|
|
lastLogin: '2024-01-20 08:00',
|
|
|
|
|
totalOrders: 0
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// 应用过滤器
|
|
|
|
|
let filteredUsers = mockUsers;
|
|
|
|
|
|
|
|
|
|
if (filters.search) {
|
|
|
|
|
const searchTerm = filters.search.toLowerCase();
|
|
|
|
|
filteredUsers = filteredUsers.filter(user =>
|
|
|
|
|
user.name.toLowerCase().includes(searchTerm) ||
|
|
|
|
|
user.email.toLowerCase().includes(searchTerm) ||
|
|
|
|
|
user.phone.includes(searchTerm)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (filters.userType && filters.userType !== 'all') {
|
|
|
|
|
filteredUsers = filteredUsers.filter(user => user.userType === filters.userType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (filters.status && filters.status !== 'all') {
|
|
|
|
|
filteredUsers = filteredUsers.filter(user => user.status === filters.status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: {
|
|
|
|
|
users: filteredUsers,
|
|
|
|
|
total: filteredUsers.length
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return response;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建用户
|
|
|
|
|
async createUser(userData: Partial<User>): Promise<ApiResponse<User>> {
|
|
|
|
|
return this.request<User>('/users', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
body: JSON.stringify(userData),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新用户
|
|
|
|
|
async updateUser(userId: string, userData: Partial<User>): Promise<ApiResponse<User>> {
|
|
|
|
|
return this.request<User>(`/users/${userId}`, {
|
|
|
|
|
method: 'PUT',
|
|
|
|
|
body: JSON.stringify(userData),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 删除用户
|
|
|
|
|
async deleteUser(userId: string): Promise<ApiResponse<void>> {
|
|
|
|
|
return this.request<void>(`/users/${userId}`, {
|
|
|
|
|
method: 'DELETE',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 批量删除用户
|
|
|
|
|
async deleteUsers(userIds: string[]): Promise<ApiResponse<void>> {
|
|
|
|
|
return this.request<void>('/users/batch-delete', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
body: JSON.stringify({ userIds }),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取用户详情
|
|
|
|
|
async getUserDetail(userId: string): Promise<ApiResponse<User>> {
|
|
|
|
|
return this.request<User>(`/users/${userId}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查服务状态
|
|
|
|
|
async checkServiceStatus(): Promise<ApiResponse<{ status: string; timestamp: string }>> {
|
|
|
|
|
return this.request<{ status: string; timestamp: string }>('/health');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 导出单例实例
|
|
|
|
|
export const apiService = new ApiService();
|
|
|
|
|
|
|
|
|
|
// 导出默认实例
|
2025-07-03 13:12:54 +08:00
|
|
|
|
export default apiService;
|
|
|
|
|
|
|
|
|
|
// 用户相关API
|
|
|
|
|
export const userAPI = {
|
|
|
|
|
// 获取用户列表
|
|
|
|
|
async getUsers(params?: {
|
|
|
|
|
page?: number
|
|
|
|
|
limit?: number
|
|
|
|
|
search?: string
|
|
|
|
|
user_type?: string
|
|
|
|
|
status?: string
|
|
|
|
|
}) {
|
|
|
|
|
let query = supabase
|
|
|
|
|
.from('users')
|
|
|
|
|
.select('*', { count: 'exact' })
|
|
|
|
|
.order('created_at', { ascending: false })
|
|
|
|
|
|
|
|
|
|
if (params?.search) {
|
|
|
|
|
query = query.or(`name.ilike.%${params.search}%,email.ilike.%${params.search}%`)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (params?.user_type) {
|
|
|
|
|
query = query.eq('user_type', params.user_type)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (params?.status) {
|
|
|
|
|
query = query.eq('status', params.status)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { data, error, count } = await query
|
|
|
|
|
.range(
|
|
|
|
|
((params?.page || 1) - 1) * (params?.limit || 10),
|
|
|
|
|
(params?.page || 1) * (params?.limit || 10) - 1
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return { data, count }
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 获取单个用户
|
|
|
|
|
async getUser(id: string) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('users')
|
|
|
|
|
.select('*')
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 创建用户
|
|
|
|
|
async createUser(userData: any) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('users')
|
|
|
|
|
.insert([userData])
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 更新用户
|
|
|
|
|
async updateUser(id: string, userData: any) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('users')
|
|
|
|
|
.update(userData)
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 删除用户
|
|
|
|
|
async deleteUser(id: string) {
|
|
|
|
|
const { error } = await supabase
|
|
|
|
|
.from('users')
|
|
|
|
|
.delete()
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 翻译员相关API
|
|
|
|
|
export const interpreterAPI = {
|
|
|
|
|
// 获取翻译员列表
|
|
|
|
|
async getInterpreters(params?: {
|
|
|
|
|
page?: number
|
|
|
|
|
limit?: number
|
|
|
|
|
search?: string
|
|
|
|
|
status?: string
|
|
|
|
|
language?: string
|
|
|
|
|
}) {
|
|
|
|
|
let query = supabase
|
|
|
|
|
.from('interpreters')
|
|
|
|
|
.select('*', { count: 'exact' })
|
|
|
|
|
.order('created_at', { ascending: false })
|
|
|
|
|
|
|
|
|
|
if (params?.search) {
|
|
|
|
|
query = query.or(`name.ilike.%${params.search}%,email.ilike.%${params.search}%`)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (params?.status) {
|
|
|
|
|
query = query.eq('status', params.status)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (params?.language) {
|
|
|
|
|
query = query.contains('languages', [params.language])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { data, error, count } = await query
|
|
|
|
|
.range(
|
|
|
|
|
((params?.page || 1) - 1) * (params?.limit || 10),
|
|
|
|
|
(params?.page || 1) * (params?.limit || 10) - 1
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return { data, count }
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 获取单个翻译员
|
|
|
|
|
async getInterpreter(id: string) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('interpreters')
|
|
|
|
|
.select('*')
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 创建翻译员
|
|
|
|
|
async createInterpreter(interpreterData: any) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('interpreters')
|
|
|
|
|
.insert([interpreterData])
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 更新翻译员
|
|
|
|
|
async updateInterpreter(id: string, interpreterData: any) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('interpreters')
|
|
|
|
|
.update(interpreterData)
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 删除翻译员
|
|
|
|
|
async deleteInterpreter(id: string) {
|
|
|
|
|
const { error } = await supabase
|
|
|
|
|
.from('interpreters')
|
|
|
|
|
.delete()
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 订单相关API
|
|
|
|
|
export const orderAPI = {
|
|
|
|
|
// 获取订单列表
|
|
|
|
|
async getOrders(params?: {
|
|
|
|
|
page?: number
|
|
|
|
|
limit?: number
|
|
|
|
|
search?: string
|
|
|
|
|
status?: string
|
|
|
|
|
service_type?: string
|
|
|
|
|
}) {
|
|
|
|
|
let query = supabase
|
|
|
|
|
.from('orders')
|
|
|
|
|
.select('*', { count: 'exact' })
|
|
|
|
|
.order('created_at', { ascending: false })
|
|
|
|
|
|
|
|
|
|
if (params?.search) {
|
|
|
|
|
query = query.or(`order_number.ilike.%${params.search}%,user_name.ilike.%${params.search}%,user_email.ilike.%${params.search}%`)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (params?.status) {
|
|
|
|
|
query = query.eq('status', params.status)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (params?.service_type) {
|
|
|
|
|
query = query.eq('service_type', params.service_type)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { data, error, count } = await query
|
|
|
|
|
.range(
|
|
|
|
|
((params?.page || 1) - 1) * (params?.limit || 10),
|
|
|
|
|
(params?.page || 1) * (params?.limit || 10) - 1
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return { data, count }
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 获取单个订单
|
|
|
|
|
async getOrder(id: string) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('orders')
|
|
|
|
|
.select('*')
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 创建订单
|
|
|
|
|
async createOrder(orderData: any) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('orders')
|
|
|
|
|
.insert([orderData])
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 更新订单
|
|
|
|
|
async updateOrder(id: string, orderData: any) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('orders')
|
|
|
|
|
.update(orderData)
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 删除订单
|
|
|
|
|
async deleteOrder(id: string) {
|
|
|
|
|
const { error } = await supabase
|
|
|
|
|
.from('orders')
|
|
|
|
|
.delete()
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 通话记录相关API
|
|
|
|
|
export const callAPI = {
|
|
|
|
|
// 获取通话记录列表
|
|
|
|
|
async getCalls(params?: {
|
|
|
|
|
page?: number
|
|
|
|
|
limit?: number
|
|
|
|
|
search?: string
|
|
|
|
|
status?: string
|
|
|
|
|
service_type?: string
|
|
|
|
|
}) {
|
|
|
|
|
let query = supabase
|
|
|
|
|
.from('calls')
|
|
|
|
|
.select(`
|
|
|
|
|
*,
|
|
|
|
|
users(name, email),
|
|
|
|
|
interpreters(name, email)
|
|
|
|
|
`, { count: 'exact' })
|
|
|
|
|
.order('created_at', { ascending: false })
|
|
|
|
|
|
|
|
|
|
if (params?.status) {
|
|
|
|
|
query = query.eq('status', params.status)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (params?.service_type) {
|
|
|
|
|
query = query.eq('service_type', params.service_type)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { data, error, count } = await query
|
|
|
|
|
.range(
|
|
|
|
|
((params?.page || 1) - 1) * (params?.limit || 10),
|
|
|
|
|
(params?.page || 1) * (params?.limit || 10) - 1
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return { data, count }
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 获取单个通话记录
|
|
|
|
|
async getCall(id: string) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('calls')
|
|
|
|
|
.select(`
|
|
|
|
|
*,
|
|
|
|
|
users(name, email),
|
|
|
|
|
interpreters(name, email)
|
|
|
|
|
`)
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 创建通话记录
|
|
|
|
|
async createCall(callData: any) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('calls')
|
|
|
|
|
.insert([callData])
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 更新通话记录
|
|
|
|
|
async updateCall(id: string, callData: any) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('calls')
|
|
|
|
|
.update(callData)
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 发票相关API
|
|
|
|
|
export const invoiceAPI = {
|
|
|
|
|
// 获取发票列表
|
|
|
|
|
async getInvoices(params?: {
|
|
|
|
|
page?: number
|
|
|
|
|
limit?: number
|
|
|
|
|
search?: string
|
|
|
|
|
status?: string
|
|
|
|
|
invoice_type?: string
|
|
|
|
|
}) {
|
|
|
|
|
let query = supabase
|
|
|
|
|
.from('invoices')
|
|
|
|
|
.select('*', { count: 'exact' })
|
|
|
|
|
.order('created_at', { ascending: false })
|
|
|
|
|
|
|
|
|
|
if (params?.search) {
|
|
|
|
|
query = query.or(`invoice_number.ilike.%${params.search}%,user_name.ilike.%${params.search}%,user_email.ilike.%${params.search}%`)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (params?.status) {
|
|
|
|
|
query = query.eq('status', params.status)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (params?.invoice_type) {
|
|
|
|
|
query = query.eq('invoice_type', params.invoice_type)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { data, error, count } = await query
|
|
|
|
|
.range(
|
|
|
|
|
((params?.page || 1) - 1) * (params?.limit || 10),
|
|
|
|
|
(params?.page || 1) * (params?.limit || 10) - 1
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return { data, count }
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 获取单个发票
|
|
|
|
|
async getInvoice(id: string) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('invoices')
|
|
|
|
|
.select('*')
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 创建发票
|
|
|
|
|
async createInvoice(invoiceData: any) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('invoices')
|
|
|
|
|
.insert([invoiceData])
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 更新发票
|
|
|
|
|
async updateInvoice(id: string, invoiceData: any) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('invoices')
|
|
|
|
|
.update(invoiceData)
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 删除发票
|
|
|
|
|
async deleteInvoice(id: string) {
|
|
|
|
|
const { error } = await supabase
|
|
|
|
|
.from('invoices')
|
|
|
|
|
.delete()
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 文档相关API
|
|
|
|
|
export const documentAPI = {
|
|
|
|
|
// 获取文档列表
|
|
|
|
|
async getDocuments(params?: {
|
|
|
|
|
page?: number
|
|
|
|
|
limit?: number
|
|
|
|
|
search?: string
|
|
|
|
|
status?: string
|
|
|
|
|
file_type?: string
|
|
|
|
|
}) {
|
|
|
|
|
let query = supabase
|
|
|
|
|
.from('documents')
|
|
|
|
|
.select('*', { count: 'exact' })
|
|
|
|
|
.order('created_at', { ascending: false })
|
|
|
|
|
|
|
|
|
|
if (params?.search) {
|
|
|
|
|
query = query.or(`filename.ilike.%${params.search}%,original_name.ilike.%${params.search}%`)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (params?.status) {
|
|
|
|
|
query = query.eq('status', params.status)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (params?.file_type) {
|
|
|
|
|
query = query.eq('file_type', params.file_type)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { data, error, count } = await query
|
|
|
|
|
.range(
|
|
|
|
|
((params?.page || 1) - 1) * (params?.limit || 10),
|
|
|
|
|
(params?.page || 1) * (params?.limit || 10) - 1
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return { data, count }
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 获取单个文档
|
|
|
|
|
async getDocument(id: string) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('documents')
|
|
|
|
|
.select('*')
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 创建文档
|
|
|
|
|
async createDocument(documentData: any) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('documents')
|
|
|
|
|
.insert([documentData])
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 更新文档
|
|
|
|
|
async updateDocument(id: string, documentData: any) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('documents')
|
|
|
|
|
.update(documentData)
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 删除文档
|
|
|
|
|
async deleteDocument(id: string) {
|
|
|
|
|
const { error } = await supabase
|
|
|
|
|
.from('documents')
|
|
|
|
|
.delete()
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 企业相关API
|
|
|
|
|
export const enterpriseAPI = {
|
|
|
|
|
// 获取企业列表
|
|
|
|
|
async getEnterprises(params?: {
|
|
|
|
|
page?: number
|
|
|
|
|
limit?: number
|
|
|
|
|
search?: string
|
|
|
|
|
status?: string
|
|
|
|
|
}) {
|
|
|
|
|
let query = supabase
|
|
|
|
|
.from('enterprises')
|
|
|
|
|
.select('*', { count: 'exact' })
|
|
|
|
|
.order('created_at', { ascending: false })
|
|
|
|
|
|
|
|
|
|
if (params?.search) {
|
|
|
|
|
query = query.or(`name.ilike.%${params.search}%,contact_email.ilike.%${params.search}%`)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (params?.status) {
|
|
|
|
|
query = query.eq('status', params.status)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { data, error, count } = await query
|
|
|
|
|
.range(
|
|
|
|
|
((params?.page || 1) - 1) * (params?.limit || 10),
|
|
|
|
|
(params?.page || 1) * (params?.limit || 10) - 1
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return { data, count }
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 获取单个企业
|
|
|
|
|
async getEnterprise(id: string) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('enterprises')
|
|
|
|
|
.select('*')
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 创建企业
|
|
|
|
|
async createEnterprise(enterpriseData: any) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('enterprises')
|
|
|
|
|
.insert([enterpriseData])
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 更新企业
|
|
|
|
|
async updateEnterprise(id: string, enterpriseData: any) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('enterprises')
|
|
|
|
|
.update(enterpriseData)
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 删除企业
|
|
|
|
|
async deleteEnterprise(id: string) {
|
|
|
|
|
const { error } = await supabase
|
|
|
|
|
.from('enterprises')
|
|
|
|
|
.delete()
|
|
|
|
|
.eq('id', id)
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 统计数据API
|
|
|
|
|
export const statsAPI = {
|
|
|
|
|
// 获取仪表盘统计数据
|
|
|
|
|
async getDashboardStats() {
|
|
|
|
|
const [
|
|
|
|
|
{ count: totalUsers },
|
|
|
|
|
{ count: totalInterpreters },
|
|
|
|
|
{ count: totalOrders },
|
|
|
|
|
{ count: totalCalls },
|
|
|
|
|
{ count: activeUsers },
|
|
|
|
|
{ count: activeCalls },
|
|
|
|
|
{ data: recentOrders },
|
|
|
|
|
{ data: recentCalls }
|
|
|
|
|
] = await Promise.all([
|
|
|
|
|
supabase.from('users').select('*', { count: 'exact', head: true }),
|
|
|
|
|
supabase.from('interpreters').select('*', { count: 'exact', head: true }),
|
|
|
|
|
supabase.from('orders').select('*', { count: 'exact', head: true }),
|
|
|
|
|
supabase.from('calls').select('*', { count: 'exact', head: true }),
|
|
|
|
|
supabase.from('users').select('*', { count: 'exact', head: true }).eq('status', 'active'),
|
|
|
|
|
supabase.from('calls').select('*', { count: 'exact', head: true }).eq('status', 'connected'),
|
|
|
|
|
supabase.from('orders').select('*').order('created_at', { ascending: false }).limit(10),
|
|
|
|
|
supabase.from('calls').select(`
|
|
|
|
|
*,
|
|
|
|
|
users(name, email),
|
|
|
|
|
interpreters(name, email)
|
|
|
|
|
`).order('created_at', { ascending: false }).limit(10)
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
totalUsers: totalUsers || 0,
|
|
|
|
|
totalInterpreters: totalInterpreters || 0,
|
|
|
|
|
totalOrders: totalOrders || 0,
|
|
|
|
|
totalCalls: totalCalls || 0,
|
|
|
|
|
activeUsers: activeUsers || 0,
|
|
|
|
|
activeCalls: activeCalls || 0,
|
|
|
|
|
recentOrders: recentOrders || [],
|
|
|
|
|
recentCalls: recentCalls || []
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 系统设置API
|
|
|
|
|
export const settingsAPI = {
|
|
|
|
|
// 获取系统设置
|
|
|
|
|
async getSettings() {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('system_settings')
|
|
|
|
|
.select('*')
|
|
|
|
|
.order('key')
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 获取单个设置
|
|
|
|
|
async getSetting(key: string) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('system_settings')
|
|
|
|
|
.select('*')
|
|
|
|
|
.eq('key', key)
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 更新设置
|
|
|
|
|
async updateSetting(key: string, value: string, description?: string) {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('system_settings')
|
|
|
|
|
.upsert([{ key, value, description }])
|
|
|
|
|
.select()
|
|
|
|
|
.single()
|
|
|
|
|
|
|
|
|
|
if (error) throw error
|
|
|
|
|
return data
|
|
|
|
|
}
|
|
|
|
|
}
|