feat: 完成口译服务管理后台核心功能开发
This commit is contained in:
@@ -0,0 +1,742 @@
|
||||
// 演示模式的模拟数据
|
||||
export const demoUsers = [
|
||||
{
|
||||
id: '1',
|
||||
email: 'john.doe@example.com',
|
||||
full_name: '张三',
|
||||
avatar_url: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150',
|
||||
user_type: 'individual' as const,
|
||||
phone: '+86 138 0000 0001',
|
||||
created_at: '2024-01-15T08:00:00Z',
|
||||
updated_at: '2024-01-20T10:30:00Z',
|
||||
is_active: true,
|
||||
last_login: '2024-01-20T10:30:00Z',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
email: 'jane.smith@company.com',
|
||||
full_name: '李四',
|
||||
avatar_url: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=150',
|
||||
user_type: 'enterprise' as const,
|
||||
phone: '+86 138 0000 0002',
|
||||
created_at: '2024-01-10T09:15:00Z',
|
||||
updated_at: '2024-01-19T14:20:00Z',
|
||||
is_active: true,
|
||||
last_login: '2024-01-19T14:20:00Z',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
email: 'mike.wilson@example.com',
|
||||
full_name: '王五',
|
||||
avatar_url: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150',
|
||||
user_type: 'individual' as const,
|
||||
phone: '+86 138 0000 0003',
|
||||
created_at: '2024-01-12T11:45:00Z',
|
||||
updated_at: '2024-01-18T16:10:00Z',
|
||||
is_active: false,
|
||||
last_login: '2024-01-18T16:10:00Z',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
email: 'sarah.johnson@enterprise.com',
|
||||
full_name: '赵六',
|
||||
avatar_url: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=150',
|
||||
user_type: 'enterprise' as const,
|
||||
phone: '+86 138 0000 0004',
|
||||
created_at: '2024-01-08T13:20:00Z',
|
||||
updated_at: '2024-01-17T09:45:00Z',
|
||||
is_active: true,
|
||||
last_login: '2024-01-17T09:45:00Z',
|
||||
},
|
||||
];
|
||||
|
||||
export const demoCalls = [
|
||||
{
|
||||
id: '1',
|
||||
user_id: '1',
|
||||
interpreter_id: '101',
|
||||
from_language: 'zh',
|
||||
to_language: 'en',
|
||||
status: 'active' as const,
|
||||
start_time: new Date(Date.now() - 15 * 60 * 1000).toISOString(), // 15分钟前开始
|
||||
created_at: new Date(Date.now() - 16 * 60 * 1000).toISOString(),
|
||||
cost: 45.50,
|
||||
duration: 15 * 60, // 15分钟
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
user_id: '2',
|
||||
interpreter_id: '102',
|
||||
from_language: 'en',
|
||||
to_language: 'zh',
|
||||
status: 'active' as const,
|
||||
start_time: new Date(Date.now() - 8 * 60 * 1000).toISOString(), // 8分钟前开始
|
||||
created_at: new Date(Date.now() - 10 * 60 * 1000).toISOString(),
|
||||
cost: 32.00,
|
||||
duration: 8 * 60, // 8分钟
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
user_id: '1',
|
||||
interpreter_id: '103',
|
||||
from_language: 'zh',
|
||||
to_language: 'ja',
|
||||
status: 'ended' as const,
|
||||
start_time: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(), // 2小时前
|
||||
end_time: new Date(Date.now() - 90 * 60 * 1000).toISOString(), // 1.5小时前结束
|
||||
created_at: new Date(Date.now() - 125 * 60 * 1000).toISOString(),
|
||||
cost: 89.75,
|
||||
duration: 30 * 60, // 30分钟
|
||||
},
|
||||
];
|
||||
|
||||
export const demoInterpreters = [
|
||||
{
|
||||
id: '101',
|
||||
name: '翻译员A',
|
||||
avatar_url: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150',
|
||||
languages: ['zh', 'en'],
|
||||
rating: 4.9,
|
||||
status: 'busy' as 'online' | 'offline' | 'busy',
|
||||
specialties: ['商务', '法律'],
|
||||
},
|
||||
{
|
||||
id: '102',
|
||||
name: '翻译员B',
|
||||
avatar_url: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150',
|
||||
languages: ['en', 'zh', 'ja'],
|
||||
rating: 4.8,
|
||||
status: 'busy' as 'online' | 'offline' | 'busy',
|
||||
specialties: ['技术', '医疗'],
|
||||
},
|
||||
{
|
||||
id: '103',
|
||||
name: '翻译员C',
|
||||
avatar_url: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=150',
|
||||
languages: ['zh', 'ja', 'ko'],
|
||||
rating: 4.7,
|
||||
status: 'online' as 'online' | 'offline' | 'busy',
|
||||
specialties: ['旅游', '教育'],
|
||||
},
|
||||
{
|
||||
id: '104',
|
||||
name: '翻译员D',
|
||||
avatar_url: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=150',
|
||||
languages: ['en', 'fr', 'es'],
|
||||
rating: 4.9,
|
||||
status: 'online' as 'online' | 'offline' | 'busy',
|
||||
specialties: ['商务', '艺术'],
|
||||
},
|
||||
];
|
||||
|
||||
export const demoStats = {
|
||||
todayCalls: 12,
|
||||
activeCalls: 2,
|
||||
onlineInterpreters: 8,
|
||||
todayRevenue: 1250.75,
|
||||
avgResponseTime: 45, // 秒
|
||||
};
|
||||
|
||||
// 订单演示数据
|
||||
const demoOrders = [
|
||||
{
|
||||
id: 'order-1',
|
||||
order_number: 'ORD-2024-001',
|
||||
user_id: 'user-1',
|
||||
user_name: '张三',
|
||||
user_email: 'zhangsan@email.com',
|
||||
service_type: 'ai_voice_translation' as const,
|
||||
service_name: 'AI语音翻译',
|
||||
source_language: '中文',
|
||||
target_language: '英文',
|
||||
duration: 30,
|
||||
status: 'completed' as const,
|
||||
priority: 'normal' as const,
|
||||
cost: 180.00,
|
||||
currency: 'CNY',
|
||||
scheduled_at: '2024-01-15T14:00:00Z',
|
||||
started_at: '2024-01-15T14:00:00Z',
|
||||
completed_at: '2024-01-15T14:30:00Z',
|
||||
created_at: '2024-01-15T10:00:00Z',
|
||||
updated_at: '2024-01-15T14:30:00Z',
|
||||
notes: '客户会议翻译'
|
||||
},
|
||||
{
|
||||
id: 'order-2',
|
||||
order_number: 'ORD-2024-002',
|
||||
user_id: 'user-2',
|
||||
user_name: '李四',
|
||||
user_email: 'lisi@alibaba.com',
|
||||
service_type: 'human_interpretation' as const,
|
||||
service_name: '人工口译',
|
||||
source_language: '中文',
|
||||
target_language: '英文',
|
||||
duration: 240,
|
||||
status: 'processing' as const,
|
||||
priority: 'high' as const,
|
||||
cost: 2400.00,
|
||||
currency: 'CNY',
|
||||
scheduled_at: '2024-01-20T09:00:00Z',
|
||||
started_at: '2024-01-20T09:00:00Z',
|
||||
created_at: '2024-01-18T16:00:00Z',
|
||||
updated_at: '2024-01-20T10:30:00Z',
|
||||
interpreter_id: 'interpreter-1',
|
||||
interpreter_name: '王译员',
|
||||
notes: '重要商务谈判'
|
||||
},
|
||||
{
|
||||
id: 'order-3',
|
||||
order_number: 'ORD-2024-003',
|
||||
user_id: 'user-3',
|
||||
user_name: '王五',
|
||||
user_email: 'wangwu@tencent.com',
|
||||
service_type: 'document_translation' as const,
|
||||
service_name: '文档翻译',
|
||||
source_language: '中文',
|
||||
target_language: '英文',
|
||||
pages: 20,
|
||||
status: 'pending' as const,
|
||||
priority: 'normal' as const,
|
||||
cost: 1200.00,
|
||||
currency: 'CNY',
|
||||
created_at: '2024-01-25T11:00:00Z',
|
||||
updated_at: '2024-01-25T11:00:00Z',
|
||||
notes: '技术文档翻译'
|
||||
},
|
||||
{
|
||||
id: 'order-4',
|
||||
order_number: 'ORD-2024-004',
|
||||
user_id: 'user-4',
|
||||
user_name: '赵六',
|
||||
user_email: 'zhaoliu@bytedance.com',
|
||||
service_type: 'ai_video_translation' as const,
|
||||
service_name: 'AI视频翻译',
|
||||
source_language: '中文',
|
||||
target_language: '英文',
|
||||
duration: 90,
|
||||
status: 'completed' as const,
|
||||
priority: 'urgent' as const,
|
||||
cost: 3600.00,
|
||||
currency: 'CNY',
|
||||
scheduled_at: '2024-01-18T13:00:00Z',
|
||||
started_at: '2024-01-18T13:00:00Z',
|
||||
completed_at: '2024-01-18T14:30:00Z',
|
||||
created_at: '2024-01-18T10:00:00Z',
|
||||
updated_at: '2024-01-18T14:30:00Z',
|
||||
notes: '产品发布会视频翻译'
|
||||
},
|
||||
{
|
||||
id: 'order-5',
|
||||
order_number: 'ORD-2024-005',
|
||||
user_id: 'user-5',
|
||||
user_name: '孙七',
|
||||
user_email: 'sunqi@email.com',
|
||||
service_type: 'sign_language_translation' as const,
|
||||
service_name: '手语翻译',
|
||||
source_language: '中文',
|
||||
target_language: '手语',
|
||||
duration: 90,
|
||||
status: 'cancelled' as const,
|
||||
priority: 'low' as const,
|
||||
cost: 450.00,
|
||||
currency: 'CNY',
|
||||
created_at: '2024-01-22T13:00:00Z',
|
||||
updated_at: '2024-01-23T09:00:00Z',
|
||||
interpreter_id: 'interpreter-2',
|
||||
interpreter_name: '李手语师',
|
||||
notes: '客户取消服务'
|
||||
},
|
||||
{
|
||||
id: 'order-6',
|
||||
order_number: 'ORD-2024-006',
|
||||
user_id: 'user-6',
|
||||
user_name: '周八',
|
||||
user_email: 'zhouba@email.com',
|
||||
service_type: 'ai_voice_translation' as const,
|
||||
service_name: 'AI语音翻译',
|
||||
source_language: '英文',
|
||||
target_language: '中文',
|
||||
duration: 45,
|
||||
status: 'failed' as const,
|
||||
priority: 'normal' as const,
|
||||
cost: 270.00,
|
||||
currency: 'CNY',
|
||||
scheduled_at: '2024-01-28T16:00:00Z',
|
||||
started_at: '2024-01-28T16:00:00Z',
|
||||
created_at: '2024-01-28T15:00:00Z',
|
||||
updated_at: '2024-01-28T16:30:00Z',
|
||||
notes: '音频质量问题导致翻译失败'
|
||||
}
|
||||
];
|
||||
|
||||
// 企业合同演示数据
|
||||
const demoEnterpriseContracts = [
|
||||
{
|
||||
id: 'contract-001',
|
||||
enterprise_id: 'ent-001',
|
||||
enterprise_name: '阿里巴巴集团',
|
||||
contract_number: 'ALI-2024-001',
|
||||
contract_type: 'annual' as const,
|
||||
start_date: '2024-01-01T00:00:00Z',
|
||||
end_date: '2024-12-31T23:59:59Z',
|
||||
total_amount: 500000,
|
||||
currency: 'CNY',
|
||||
status: 'active' as const,
|
||||
service_rates: {
|
||||
ai_voice: 1.8, // 企业优惠价格
|
||||
ai_video: 2.5,
|
||||
sign_language: 4.0,
|
||||
human_interpreter: 6.5,
|
||||
document_translation: 0.08,
|
||||
},
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
updated_at: '2024-01-01T00:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 'contract-002',
|
||||
enterprise_id: 'ent-002',
|
||||
enterprise_name: '腾讯科技',
|
||||
contract_number: 'TX-2024-002',
|
||||
contract_type: 'monthly' as const,
|
||||
start_date: '2024-02-01T00:00:00Z',
|
||||
end_date: '2024-07-31T23:59:59Z',
|
||||
total_amount: 120000,
|
||||
currency: 'CNY',
|
||||
status: 'active' as const,
|
||||
service_rates: {
|
||||
ai_voice: 1.9,
|
||||
ai_video: 2.7,
|
||||
sign_language: 4.2,
|
||||
human_interpreter: 7.0,
|
||||
document_translation: 0.09,
|
||||
},
|
||||
created_at: '2024-02-01T00:00:00Z',
|
||||
updated_at: '2024-02-01T00:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 'contract-003',
|
||||
enterprise_id: 'ent-003',
|
||||
enterprise_name: '字节跳动',
|
||||
contract_number: 'BD-2024-003',
|
||||
contract_type: 'annual' as const,
|
||||
start_date: '2024-03-01T00:00:00Z',
|
||||
end_date: '2025-02-28T23:59:59Z',
|
||||
total_amount: 800000,
|
||||
currency: 'CNY',
|
||||
status: 'active' as const,
|
||||
service_rates: {
|
||||
ai_voice: 1.6, // 大客户更优惠的价格
|
||||
ai_video: 2.3,
|
||||
sign_language: 3.8,
|
||||
human_interpreter: 6.0,
|
||||
document_translation: 0.07,
|
||||
},
|
||||
created_at: '2024-03-01T00:00:00Z',
|
||||
updated_at: '2024-03-01T00:00:00Z'
|
||||
}
|
||||
];
|
||||
|
||||
// 企业员工演示数据
|
||||
const demoEnterpriseEmployees = [
|
||||
{
|
||||
id: 'emp-001',
|
||||
enterprise_id: 'ent-001',
|
||||
enterprise_name: '阿里巴巴集团',
|
||||
name: '张三',
|
||||
email: 'zhangsan@alibaba.com',
|
||||
department: '技术部',
|
||||
position: '高级工程师',
|
||||
status: 'active' as const,
|
||||
total_calls: 45,
|
||||
total_cost: 1350.00,
|
||||
created_at: '2024-01-15T08:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 'emp-002',
|
||||
enterprise_id: 'ent-001',
|
||||
enterprise_name: '阿里巴巴集团',
|
||||
name: '李四',
|
||||
email: 'lisi@alibaba.com',
|
||||
department: '产品部',
|
||||
position: '产品经理',
|
||||
status: 'active' as const,
|
||||
total_calls: 32,
|
||||
total_cost: 960.00,
|
||||
created_at: '2024-01-20T09:30:00Z'
|
||||
},
|
||||
{
|
||||
id: 'emp-003',
|
||||
enterprise_id: 'ent-002',
|
||||
enterprise_name: '腾讯科技',
|
||||
name: '王五',
|
||||
email: 'wangwu@tencent.com',
|
||||
department: '运营部',
|
||||
position: '运营专员',
|
||||
status: 'inactive' as const,
|
||||
total_calls: 18,
|
||||
total_cost: 540.00,
|
||||
created_at: '2024-02-01T10:15:00Z'
|
||||
},
|
||||
{
|
||||
id: 'emp-004',
|
||||
enterprise_id: 'ent-003',
|
||||
enterprise_name: '字节跳动',
|
||||
name: '赵六',
|
||||
email: 'zhaoliu@bytedance.com',
|
||||
department: '市场部',
|
||||
position: '市场总监',
|
||||
status: 'active' as const,
|
||||
total_calls: 67,
|
||||
total_cost: 2010.00,
|
||||
created_at: '2024-02-10T11:45:00Z'
|
||||
}
|
||||
];
|
||||
|
||||
// 企业结算记录演示数据
|
||||
const demoEnterpriseBilling = [
|
||||
{
|
||||
id: '1',
|
||||
enterprise_id: 'ent_001',
|
||||
enterprise_name: '华为技术有限公司',
|
||||
period: '2024年1月',
|
||||
total_calls: 128,
|
||||
total_duration: 7680,
|
||||
total_amount: 6400.00,
|
||||
currency: 'CNY',
|
||||
status: 'paid' as const,
|
||||
due_date: '2024-02-15',
|
||||
paid_date: '2024-02-10',
|
||||
created_at: '2024-02-01T00:00:00Z'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
enterprise_id: 'ent_002',
|
||||
enterprise_name: '腾讯科技有限公司',
|
||||
period: '2024年1月',
|
||||
total_calls: 85,
|
||||
total_duration: 5100,
|
||||
total_amount: 4250.00,
|
||||
currency: 'CNY',
|
||||
status: 'pending' as const,
|
||||
due_date: '2024-02-15',
|
||||
created_at: '2024-02-01T00:00:00Z'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
enterprise_id: 'ent_003',
|
||||
enterprise_name: '阿里巴巴集团',
|
||||
period: '2023年12月',
|
||||
total_calls: 156,
|
||||
total_duration: 9360,
|
||||
total_amount: 7800.00,
|
||||
currency: 'CNY',
|
||||
status: 'overdue' as const,
|
||||
due_date: '2024-01-15',
|
||||
created_at: '2024-01-01T00:00:00Z'
|
||||
}
|
||||
];
|
||||
|
||||
// 文档演示数据
|
||||
const demoDocuments = [
|
||||
{
|
||||
id: '1',
|
||||
user_id: 'user_001',
|
||||
original_name: '商业合同_中英对照.pdf',
|
||||
file_size: 2048576,
|
||||
file_type: 'pdf',
|
||||
source_language: '中文',
|
||||
target_language: '英文',
|
||||
status: 'completed' as const,
|
||||
progress: 100,
|
||||
translated_url: '/documents/translated/商业合同_中英对照_translated.pdf',
|
||||
cost: 150.00,
|
||||
created_at: '2024-01-15T10:30:00Z',
|
||||
updated_at: '2024-01-15T11:45:00Z',
|
||||
user_name: '张三'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
user_id: 'user_002',
|
||||
original_name: '技术文档_API说明.docx',
|
||||
file_size: 1536000,
|
||||
file_type: 'docx',
|
||||
source_language: '英文',
|
||||
target_language: '中文',
|
||||
status: 'processing' as const,
|
||||
progress: 65,
|
||||
cost: 120.00,
|
||||
created_at: '2024-01-16T09:15:00Z',
|
||||
updated_at: '2024-01-16T10:30:00Z',
|
||||
user_name: '李四'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
user_id: 'user_003',
|
||||
original_name: '产品说明书_多语言版本.txt',
|
||||
file_size: 512000,
|
||||
file_type: 'txt',
|
||||
source_language: '中文',
|
||||
target_language: '日文',
|
||||
status: 'pending' as const,
|
||||
progress: 0,
|
||||
cost: 80.00,
|
||||
created_at: '2024-01-17T14:20:00Z',
|
||||
updated_at: '2024-01-17T14:20:00Z',
|
||||
user_name: '王五'
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
user_id: 'user_004',
|
||||
original_name: '财务报告_季度总结.xlsx',
|
||||
file_size: 3072000,
|
||||
file_type: 'xlsx',
|
||||
source_language: '中文',
|
||||
target_language: '英文',
|
||||
status: 'failed' as const,
|
||||
progress: 0,
|
||||
cost: 200.00,
|
||||
created_at: '2024-01-18T08:45:00Z',
|
||||
updated_at: '2024-01-18T09:00:00Z',
|
||||
user_name: '赵六'
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
user_id: 'user_005',
|
||||
original_name: '营销方案_品牌推广.pptx',
|
||||
file_size: 4096000,
|
||||
file_type: 'pptx',
|
||||
source_language: '中文',
|
||||
target_language: '韩文',
|
||||
status: 'completed' as const,
|
||||
progress: 100,
|
||||
translated_url: '/documents/translated/营销方案_品牌推广_translated.pptx',
|
||||
cost: 250.00,
|
||||
created_at: '2024-01-19T16:30:00Z',
|
||||
updated_at: '2024-01-19T18:15:00Z',
|
||||
user_name: '钱七'
|
||||
}
|
||||
];
|
||||
|
||||
// 发票演示数据
|
||||
const demoInvoices = [
|
||||
{
|
||||
id: 'invoice-1',
|
||||
invoice_number: 'INV-2024-001',
|
||||
user_id: 'user-1',
|
||||
user_name: '张三',
|
||||
user_email: 'zhangsan@email.com',
|
||||
order_id: 'order-1',
|
||||
invoice_type: 'individual' as const,
|
||||
personal_name: '张三',
|
||||
subtotal: 180.00,
|
||||
tax_amount: 32.40,
|
||||
total_amount: 212.40,
|
||||
currency: 'CNY',
|
||||
status: 'paid' as const,
|
||||
issue_date: '2024-01-15T10:00:00Z',
|
||||
due_date: '2024-02-15T23:59:59Z',
|
||||
paid_date: '2024-01-16T14:30:00Z',
|
||||
items: [
|
||||
{
|
||||
service_type: 'ai_voice_translation',
|
||||
service_name: 'AI语音翻译',
|
||||
quantity: 30,
|
||||
unit: '分钟',
|
||||
unit_price: 6.00,
|
||||
amount: 180.00
|
||||
}
|
||||
],
|
||||
created_at: '2024-01-15T09:00:00Z',
|
||||
updated_at: '2024-01-16T14:30:00Z'
|
||||
},
|
||||
{
|
||||
id: 'invoice-2',
|
||||
invoice_number: 'INV-2024-002',
|
||||
user_id: 'user-2',
|
||||
user_name: '李四',
|
||||
user_email: 'lisi@alibaba.com',
|
||||
order_id: 'order-2',
|
||||
invoice_type: 'enterprise' as const,
|
||||
company_name: '阿里巴巴集团',
|
||||
tax_number: '91330000MA27XF6Q2X',
|
||||
company_address: '杭州市余杭区文一西路969号',
|
||||
company_phone: '0571-85022088',
|
||||
bank_name: '中国工商银行杭州分行',
|
||||
bank_account: '1202026209900012345',
|
||||
subtotal: 2400.00,
|
||||
tax_amount: 432.00,
|
||||
total_amount: 2832.00,
|
||||
currency: 'CNY',
|
||||
status: 'issued' as const,
|
||||
issue_date: '2024-01-20T15:00:00Z',
|
||||
due_date: '2024-02-20T23:59:59Z',
|
||||
items: [
|
||||
{
|
||||
service_type: 'human_interpretation',
|
||||
service_name: '人工口译',
|
||||
quantity: 4,
|
||||
unit: '小时',
|
||||
unit_price: 600.00,
|
||||
amount: 2400.00
|
||||
}
|
||||
],
|
||||
created_at: '2024-01-20T14:00:00Z',
|
||||
updated_at: '2024-01-20T15:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 'invoice-3',
|
||||
invoice_number: 'INV-2024-003',
|
||||
user_id: 'user-3',
|
||||
user_name: '王五',
|
||||
user_email: 'wangwu@tencent.com',
|
||||
order_id: 'order-3',
|
||||
invoice_type: 'enterprise' as const,
|
||||
company_name: '腾讯科技',
|
||||
tax_number: '91440300708461136T',
|
||||
company_address: '深圳市南山区科技园',
|
||||
company_phone: '0755-86013388',
|
||||
bank_name: '招商银行深圳分行',
|
||||
bank_account: '755987654321098765',
|
||||
subtotal: 1200.00,
|
||||
tax_amount: 216.00,
|
||||
total_amount: 1416.00,
|
||||
currency: 'CNY',
|
||||
status: 'draft' as const,
|
||||
items: [
|
||||
{
|
||||
service_type: 'document_translation',
|
||||
service_name: '文档翻译',
|
||||
quantity: 20,
|
||||
unit: '页',
|
||||
unit_price: 60.00,
|
||||
amount: 1200.00
|
||||
}
|
||||
],
|
||||
created_at: '2024-01-25T11:00:00Z',
|
||||
updated_at: '2024-01-25T11:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 'invoice-4',
|
||||
invoice_number: 'INV-2024-004',
|
||||
user_id: 'user-4',
|
||||
user_name: '赵六',
|
||||
user_email: 'zhaoliu@bytedance.com',
|
||||
order_id: 'order-4',
|
||||
invoice_type: 'enterprise' as const,
|
||||
company_name: '字节跳动',
|
||||
tax_number: '91110108396826581T',
|
||||
company_address: '北京市海淀区知春路63号',
|
||||
company_phone: '010-82600000',
|
||||
bank_name: '中国银行北京分行',
|
||||
bank_account: '104100123456789012',
|
||||
subtotal: 3600.00,
|
||||
tax_amount: 648.00,
|
||||
total_amount: 4248.00,
|
||||
currency: 'CNY',
|
||||
status: 'paid' as const,
|
||||
issue_date: '2024-01-18T16:00:00Z',
|
||||
due_date: '2024-02-18T23:59:59Z',
|
||||
paid_date: '2024-01-19T10:15:00Z',
|
||||
items: [
|
||||
{
|
||||
service_type: 'ai_video_translation',
|
||||
service_name: 'AI视频翻译',
|
||||
quantity: 90,
|
||||
unit: '分钟',
|
||||
unit_price: 40.00,
|
||||
amount: 3600.00
|
||||
}
|
||||
],
|
||||
created_at: '2024-01-18T15:00:00Z',
|
||||
updated_at: '2024-01-19T10:15:00Z'
|
||||
},
|
||||
{
|
||||
id: 'invoice-5',
|
||||
invoice_number: 'INV-2024-005',
|
||||
user_id: 'user-5',
|
||||
user_name: '孙七',
|
||||
user_email: 'sunqi@email.com',
|
||||
order_id: 'order-5',
|
||||
invoice_type: 'individual' as const,
|
||||
personal_name: '孙七',
|
||||
subtotal: 450.00,
|
||||
tax_amount: 81.00,
|
||||
total_amount: 531.00,
|
||||
currency: 'CNY',
|
||||
status: 'cancelled' as const,
|
||||
items: [
|
||||
{
|
||||
service_type: 'sign_language_translation',
|
||||
service_name: '手语翻译',
|
||||
quantity: 1.5,
|
||||
unit: '小时',
|
||||
unit_price: 300.00,
|
||||
amount: 450.00
|
||||
}
|
||||
],
|
||||
created_at: '2024-01-22T13:00:00Z',
|
||||
updated_at: '2024-01-23T09:00:00Z'
|
||||
}
|
||||
];
|
||||
|
||||
// 演示模式的数据获取函数
|
||||
export const getDemoData = {
|
||||
users: (filters?: any) => {
|
||||
let filteredUsers = [...demoUsers];
|
||||
|
||||
if (filters?.search) {
|
||||
const search = filters.search.toLowerCase();
|
||||
filteredUsers = filteredUsers.filter(user =>
|
||||
user.full_name.toLowerCase().includes(search) ||
|
||||
user.email.toLowerCase().includes(search)
|
||||
);
|
||||
}
|
||||
|
||||
if (filters?.userType && filters.userType !== 'all') {
|
||||
filteredUsers = filteredUsers.filter(user => user.user_type === filters.userType);
|
||||
}
|
||||
|
||||
if (filters?.status && filters.status !== 'all') {
|
||||
const isActive = filters.status === 'active';
|
||||
filteredUsers = filteredUsers.filter(user => user.is_active === isActive);
|
||||
}
|
||||
|
||||
return Promise.resolve({
|
||||
data: filteredUsers,
|
||||
total: filteredUsers.length,
|
||||
page: 1,
|
||||
limit: 10,
|
||||
has_more: false,
|
||||
});
|
||||
},
|
||||
|
||||
calls: () => Promise.resolve(demoCalls),
|
||||
interpreters: () => Promise.resolve(demoInterpreters),
|
||||
orders: async () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
return demoOrders;
|
||||
},
|
||||
stats: () => Promise.resolve(demoStats),
|
||||
|
||||
// 企业服务数据
|
||||
enterprise: async () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 500)); // 模拟网络延迟
|
||||
return {
|
||||
contracts: demoEnterpriseContracts,
|
||||
employees: demoEnterpriseEmployees,
|
||||
billing: demoEnterpriseBilling
|
||||
};
|
||||
},
|
||||
|
||||
// 文档数据
|
||||
documents: async () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 500)); // 模拟网络延迟
|
||||
return demoDocuments;
|
||||
},
|
||||
|
||||
// 发票管理
|
||||
invoices: async () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
return demoInvoices;
|
||||
}
|
||||
};
|
||||
+290
@@ -0,0 +1,290 @@
|
||||
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 <T>(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 <T>(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 <T>(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 <T>(
|
||||
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);
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user