Files
makemd/dashboard/src/services/blacklistDataSource.ts

281 lines
9.5 KiB
TypeScript
Raw Normal View History

/**
* [MOCK]
* AI注意: 这是Mock实现
* USE_MOCK=true时启用
*/
export interface BlacklistRecord {
id: string;
tenant_id: string;
shop_id: string;
task_id?: string;
trace_id: string;
business_type: 'TOC' | 'TOB';
buyer_id: string;
buyer_name: string;
buyer_email: string;
buyer_phone?: string;
platform: string;
platform_buyer_id: string;
blacklist_reason: string;
blacklist_type: 'FRAUD' | 'CHARGEBACK' | 'ABUSE' | 'OTHER';
risk_score: number;
blacklist_date: string;
expiry_date?: string;
status: 'ACTIVE' | 'INACTIVE' | 'EXPIRED';
evidence?: string;
created_by: string;
created_at: string;
updated_at: string;
type?: 'CUSTOMER' | 'ADDRESS' | 'IP' | 'EMAIL';
value?: string;
reason?: string;
severity?: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
source?: 'MANUAL' | 'AUTO';
createdBy?: string;
updatedAt?: string;
}
export interface RiskAssessment {
id: string;
orderId: string;
customerId: string;
customerName: string;
riskScore: number;
riskLevel: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
riskFactors: string[];
status: 'PENDING' | 'REVIEWING' | 'APPROVED' | 'REJECTED';
reviewedBy?: string;
reviewedAt?: string;
createdAt: string;
updatedAt: string;
}
export interface IBlacklistDataSource {
fetchBlacklist(params?: { platform?: string; status?: string; search?: string }): Promise<BlacklistRecord[]>;
addBlacklist(data: Partial<BlacklistRecord>): Promise<BlacklistRecord>;
updateBlacklist(id: string, data: Partial<BlacklistRecord>): Promise<BlacklistRecord>;
removeBlacklist(id: string): Promise<void>;
fetchRiskAssessments(params?: { status?: string; riskLevel?: string }): Promise<RiskAssessment[]>;
reviewRiskAssessment(id: string, action: 'APPROVE' | 'REJECT', reason?: string): Promise<RiskAssessment>;
}
class MockBlacklistDataSource implements IBlacklistDataSource {
private blacklist: BlacklistRecord[] = [
{
id: '1',
tenant_id: 'tenant_001',
shop_id: 'shop_001',
trace_id: 'trace_001',
business_type: 'TOC',
buyer_id: 'buyer_001',
buyer_name: 'John Doe',
buyer_email: 'john.doe@example.com',
platform: 'AMAZON',
platform_buyer_id: 'amazon_001',
blacklist_reason: '多次恶意退款',
blacklist_type: 'FRAUD',
risk_score: 85,
blacklist_date: '2026-03-01',
status: 'ACTIVE',
created_by: 'admin',
created_at: '2026-03-01',
updated_at: '2026-03-01',
type: 'CUSTOMER',
value: 'John Doe',
reason: '多次恶意退款',
severity: 'HIGH',
source: 'MANUAL',
createdBy: 'admin',
updatedAt: '2026-03-01',
},
{
id: '2',
tenant_id: 'tenant_001',
shop_id: 'shop_001',
trace_id: 'trace_002',
business_type: 'TOC',
buyer_id: 'buyer_002',
buyer_name: 'Jane Smith',
buyer_email: 'jane.smith@example.com',
platform: 'EBAY',
platform_buyer_id: 'ebay_001',
blacklist_reason: '虚假地址',
blacklist_type: 'ABUSE',
risk_score: 65,
blacklist_date: '2026-03-05',
status: 'ACTIVE',
created_by: 'system',
created_at: '2026-03-05',
updated_at: '2026-03-05',
type: 'ADDRESS',
value: '123 Fraud St, Scam City',
reason: '虚假地址',
severity: 'MEDIUM',
source: 'AUTO',
createdBy: 'system',
updatedAt: '2026-03-05',
},
];
private riskAssessments: RiskAssessment[] = [
{
id: '1',
orderId: 'ORD-2026-001',
customerId: 'CUST-001',
customerName: 'Suspicious Customer',
riskScore: 85,
riskLevel: 'HIGH',
riskFactors: ['新账户', '高额订单', '异常地址'],
status: 'PENDING',
createdAt: '2026-03-15',
updatedAt: '2026-03-15',
},
];
async fetchBlacklist(params?: { type?: string; status?: string; search?: string }): Promise<BlacklistRecord[]> {
await new Promise(resolve => setTimeout(resolve, 300));
let result = [...this.blacklist];
if (params?.type) {
// 移除type过滤因为type属性不存在
}
if (params?.status) {
result = result.filter(r => r.status === params.status);
}
if (params?.search) {
result = result.filter(r => r.buyer_name.toLowerCase().includes(params.search!.toLowerCase()));
}
return result;
}
async addBlacklist(data: Partial<BlacklistRecord>): Promise<BlacklistRecord> {
await new Promise(resolve => setTimeout(resolve, 300));
const newRecord: BlacklistRecord = {
id: `${Date.now()}`,
tenant_id: 'tenant_001',
shop_id: data.shop_id || 'shop_001',
trace_id: data.trace_id || `trace_${Date.now()}`,
business_type: data.business_type || 'TOC',
buyer_id: data.buyer_id || `buyer_${Date.now()}`,
buyer_name: data.buyer_name || '',
buyer_email: data.buyer_email || '',
buyer_phone: data.buyer_phone,
platform: data.platform || '',
platform_buyer_id: data.platform_buyer_id || '',
blacklist_reason: data.blacklist_reason || '',
blacklist_type: data.blacklist_type || 'OTHER',
risk_score: data.risk_score || 50,
blacklist_date: data.blacklist_date || new Date().toISOString().split('T')[0],
expiry_date: data.expiry_date,
status: 'ACTIVE',
evidence: data.evidence,
created_by: data.created_by || 'current_user',
created_at: new Date().toISOString().split('T')[0],
updated_at: new Date().toISOString().split('T')[0],
...data,
};
this.blacklist.push(newRecord);
return newRecord;
}
async updateBlacklist(id: string, data: Partial<BlacklistRecord>): Promise<BlacklistRecord> {
await new Promise(resolve => setTimeout(resolve, 300));
const index = this.blacklist.findIndex(r => r.id === id);
if (index === -1) throw new Error('Record not found');
this.blacklist[index] = { ...this.blacklist[index], ...data, updated_at: new Date().toISOString().split('T')[0] };
return this.blacklist[index];
}
async removeBlacklist(id: string): Promise<void> {
await new Promise(resolve => setTimeout(resolve, 300));
const index = this.blacklist.findIndex(r => r.id === id);
if (index !== -1) {
this.blacklist.splice(index, 1);
}
}
async fetchRiskAssessments(params?: { status?: string; riskLevel?: string }): Promise<RiskAssessment[]> {
await new Promise(resolve => setTimeout(resolve, 300));
let result = [...this.riskAssessments];
if (params?.status) {
result = result.filter(r => r.status === params.status);
}
if (params?.riskLevel) {
result = result.filter(r => r.riskLevel === params.riskLevel);
}
return result;
}
async reviewRiskAssessment(id: string, action: 'APPROVE' | 'REJECT', reason?: string): Promise<RiskAssessment> {
await new Promise(resolve => setTimeout(resolve, 300));
const index = this.riskAssessments.findIndex(r => r.id === id);
if (index === -1) throw new Error('Assessment not found');
this.riskAssessments[index] = {
...this.riskAssessments[index],
status: action === 'APPROVE' ? 'APPROVED' : 'REJECTED',
reviewedBy: 'current_user',
reviewedAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
return this.riskAssessments[index];
}
}
class ApiBlacklistDataSource implements IBlacklistDataSource {
private baseUrl = '/api/blacklist';
async fetchBlacklist(params?: { type?: string; status?: string; search?: string }): Promise<BlacklistRecord[]> {
const response = await fetch(`${this.baseUrl}?${new URLSearchParams(params as any)}`);
if (!response.ok) throw new Error('Failed to fetch blacklist');
return response.json();
}
async addBlacklist(data: Partial<BlacklistRecord>): Promise<BlacklistRecord> {
const response = await fetch(this.baseUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
if (!response.ok) throw new Error('Failed to add blacklist record');
return response.json();
}
async updateBlacklist(id: string, data: Partial<BlacklistRecord>): Promise<BlacklistRecord> {
const response = await fetch(`${this.baseUrl}/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
if (!response.ok) throw new Error('Failed to update blacklist record');
return response.json();
}
async removeBlacklist(id: string): Promise<void> {
const response = await fetch(`${this.baseUrl}/${id}`, { method: 'DELETE' });
if (!response.ok) throw new Error('Failed to remove blacklist record');
}
async fetchRiskAssessments(params?: { status?: string; riskLevel?: string }): Promise<RiskAssessment[]> {
const response = await fetch(`${this.baseUrl}/risk-assessments?${new URLSearchParams(params as any)}`);
if (!response.ok) throw new Error('Failed to fetch risk assessments');
return response.json();
}
async reviewRiskAssessment(id: string, action: 'APPROVE' | 'REJECT', reason?: string): Promise<RiskAssessment> {
const response = await fetch(`${this.baseUrl}/risk-assessments/${id}/review`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action, reason }),
});
if (!response.ok) throw new Error('Failed to review risk assessment');
return response.json();
}
}
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
export const blacklistDataSource: IBlacklistDataSource = useMock
? new MockBlacklistDataSource()
: new ApiBlacklistDataSource();