refactor: 优化代码结构并修复类型问题
- 移除未使用的TabPane组件 - 修复类型定义和导入方式 - 优化mock数据源的环境变量判断逻辑 - 更新文档结构并归档旧文件 - 添加新的UI组件和Memo组件 - 调整API路径和响应处理
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
/**
|
||||
* [MOCK] A/B测试数据源
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启用
|
||||
*/
|
||||
* [MOCK] A/B测试数据<EFBFBD><EFBFBD>? * AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启<E697B6><E590AF>? */
|
||||
|
||||
export interface TestVariant {
|
||||
id: string;
|
||||
@@ -246,7 +244,7 @@ class ApiABTestDataSource implements IABTestDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const abTestDataSource: IABTestDataSource = useMock
|
||||
? new MockABTestDataSource()
|
||||
: new ApiABTestDataSource();
|
||||
|
||||
@@ -106,10 +106,8 @@ class ApiAdOptimizationDataSource implements IAdOptimizationDataSource {
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* [MOCK] Ad Optimization Mock数据源
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在REACT_APP_USE_MOCK=true时启用
|
||||
*/
|
||||
* [MOCK] Ad Optimization Mock数据<EFBFBD><EFBFBD>? * AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在REACT_APP_USE_MOCK=true时启<E697B6><E590AF>? */
|
||||
class MockAdOptimizationDataSource implements IAdOptimizationDataSource {
|
||||
readonly __MOCK__ = true as const;
|
||||
readonly __MOCK_NAME__ = 'MockAdOptimizationDataSource';
|
||||
@@ -256,10 +254,9 @@ class MockAdOptimizationDataSource implements IAdOptimizationDataSource {
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 导出数据源实例
|
||||
// ============================================
|
||||
// 导出数据源实<EFBFBD><EFBFBD>?// ============================================
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
|
||||
export const adOptimizationDataSource: IAdOptimizationDataSource = useMock
|
||||
? new MockAdOptimizationDataSource()
|
||||
|
||||
@@ -187,10 +187,8 @@ class ApiAfterSalesDataSource implements IAfterSalesDataSource {
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* [MOCK] AfterSales Mock数据源
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在REACT_APP_USE_MOCK=true时启用
|
||||
*/
|
||||
* [MOCK] AfterSales Mock数据<EFBFBD><EFBFBD>? * AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在REACT_APP_USE_MOCK=true时启<E697B6><E590AF>? */
|
||||
class MockAfterSalesDataSource implements IAfterSalesDataSource {
|
||||
readonly __MOCK__ = true as const;
|
||||
readonly __MOCK_NAME__ = 'MockAfterSalesDataSource';
|
||||
@@ -360,10 +358,9 @@ class MockAfterSalesDataSource implements IAfterSalesDataSource {
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 导出数据源实例
|
||||
// ============================================
|
||||
// 导出数据源实<EFBFBD><EFBFBD>?// ============================================
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
|
||||
export const afterSalesDataSource: IAfterSalesDataSource = useMock
|
||||
? new MockAfterSalesDataSource()
|
||||
|
||||
@@ -9,10 +9,6 @@
|
||||
|
||||
import { IDataSource } from '@/types/datasource';
|
||||
|
||||
// ============================================
|
||||
// 类型定义
|
||||
// ============================================
|
||||
|
||||
export interface MetricData {
|
||||
key: string;
|
||||
label: string;
|
||||
@@ -128,10 +124,6 @@ export interface AnalyticsData {
|
||||
dashboards: Dashboard[];
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Analytics专用接口
|
||||
// ============================================
|
||||
|
||||
export interface IAnalyticsDataSource {
|
||||
fetchAllData(params?: AnalyticsQueryParams): Promise<AnalyticsData>;
|
||||
fetchMetrics(): Promise<MetricData[]>;
|
||||
@@ -148,10 +140,6 @@ export interface IAnalyticsDataSource {
|
||||
toggleAlertRule(id: string, enabled: boolean): Promise<void>;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// API实现
|
||||
// ============================================
|
||||
|
||||
class ApiAnalyticsDataSource implements IAnalyticsDataSource {
|
||||
async fetchAllData(params?: AnalyticsQueryParams): Promise<AnalyticsData> {
|
||||
const [metrics, chartData, productAnalytics, orderAnalytics, profitAnalytics, realtimeMetrics, alertRules, dashboards] = await Promise.all([
|
||||
@@ -248,15 +236,6 @@ class ApiAnalyticsDataSource implements IAnalyticsDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Mock实现
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* [MOCK] Analytics Mock数据源
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在REACT_APP_USE_MOCK=true时启用
|
||||
*/
|
||||
class MockAnalyticsDataSource implements IAnalyticsDataSource {
|
||||
readonly __MOCK__ = true as const;
|
||||
readonly __MOCK_NAME__ = 'MockAnalyticsDataSource';
|
||||
@@ -407,29 +386,9 @@ class MockAnalyticsDataSource implements IAnalyticsDataSource {
|
||||
private simulateDelay(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
// Mock特定方法
|
||||
reset(): void {
|
||||
this.mockMetrics = [
|
||||
{ key: '1', label: '总销售额', value: 1285000, unit: '¥', change: 12.5, changeType: 'up', icon: 'DollarOutlined', color: '#52c41a' },
|
||||
{ key: '2', label: '订单数量', value: 3256, unit: '单', change: 8.3, changeType: 'up', icon: 'ShoppingCartOutlined', color: '#1890ff' },
|
||||
{ key: '3', label: '访客数量', value: 45680, unit: '人', change: -2.1, changeType: 'down', icon: 'TeamOutlined', color: '#722ed1' },
|
||||
{ key: '4', label: '转化率', value: 7.12, unit: '%', change: 0.5, changeType: 'up', icon: 'FundOutlined', color: '#fa8c16' },
|
||||
{ key: '5', label: '平均客单价', value: 394.5, unit: '¥', change: 3.8, changeType: 'up', icon: 'BarChartOutlined', color: '#13c2c2' },
|
||||
{ key: '6', label: '净利润', value: 285600, unit: '¥', change: 15.2, changeType: 'up', icon: 'LineChartOutlined', color: '#eb2f96' },
|
||||
];
|
||||
}
|
||||
|
||||
getMockData(): MetricData[] {
|
||||
return this.mockMetrics;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 导出数据源实例
|
||||
// ============================================
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
|
||||
export const analyticsDataSource: IAnalyticsDataSource = useMock
|
||||
? new MockAnalyticsDataSource()
|
||||
|
||||
57
dashboard/src/services/api/dashboard.ts
Normal file
57
dashboard/src/services/api/dashboard.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import http from '../http';
|
||||
|
||||
export const dashboardApi = {
|
||||
getDashboardData: async (params: {
|
||||
shop: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
}) => {
|
||||
try {
|
||||
// 实际项目中,这里应该调用真实的API
|
||||
// const response = await http.get('/dashboard/data', { params });
|
||||
// return response.data;
|
||||
|
||||
// 模拟数据
|
||||
return {
|
||||
kpiData: [
|
||||
{
|
||||
title: '总销售额',
|
||||
value: '¥128,500',
|
||||
change: 12.5,
|
||||
status: 'up',
|
||||
},
|
||||
{
|
||||
title: '订单数',
|
||||
value: '2,850',
|
||||
change: 8.2,
|
||||
status: 'up',
|
||||
},
|
||||
{
|
||||
title: '转化率',
|
||||
value: '4.8%',
|
||||
change: -1.2,
|
||||
status: 'down',
|
||||
},
|
||||
{
|
||||
title: '平均订单价值',
|
||||
value: '¥45.1',
|
||||
change: 3.5,
|
||||
status: 'up',
|
||||
},
|
||||
],
|
||||
trendData: [
|
||||
{ date: '2024-01-01', sales: 12000, orders: 200 },
|
||||
{ date: '2024-01-02', sales: 15000, orders: 250 },
|
||||
{ date: '2024-01-03', sales: 18000, orders: 300 },
|
||||
{ date: '2024-01-04', sales: 16000, orders: 280 },
|
||||
{ date: '2024-01-05', sales: 20000, orders: 320 },
|
||||
{ date: '2024-01-06', sales: 22000, orders: 350 },
|
||||
{ date: '2024-01-07', sales: 19000, orders: 310 },
|
||||
],
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching dashboard data:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
export { userApi } from './user';
|
||||
export { productApi } from './product';
|
||||
export { orderApi } from './order';
|
||||
export { orderApi } from './order';
|
||||
export { dashboardApi } from './dashboard';
|
||||
@@ -1,8 +1,6 @@
|
||||
/**
|
||||
* [MOCK-ARBITRAGE] 跨平台套利数据源抽象层
|
||||
* 通过环境变量自动切换Mock/真实API
|
||||
* AI注意: 这是唯一入口,业务代码必须调用此层
|
||||
*
|
||||
* [MOCK-ARBITRAGE] 跨平台套利数据源抽象<EFBFBD><EFBFBD>? * 通过环境变量自动切换Mock/真实API
|
||||
* AI注意: 这是唯一入口,业务代码必须调用此<E794A8><E6ADA4>? *
|
||||
* @module services/arbitrageDataSource
|
||||
* @author AI-Agent-1
|
||||
* @created 2026-03-19
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/**
|
||||
* [MOCK] AI决策自动化配置数据源
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启用
|
||||
*/
|
||||
* 仅在USE_MOCK=true时启<EFBFBD>? */
|
||||
|
||||
export type AutomationLevel = 'L1' | 'L2' | 'L3' | 'L4';
|
||||
export type RiskLevel = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
|
||||
@@ -419,7 +418,7 @@ class MockAutoExecutionDataSource implements IAutoExecutionDataSource {
|
||||
}
|
||||
|
||||
class ApiAutoExecutionDataSource implements IAutoExecutionDataSource {
|
||||
private baseUrl = '/api/auto-execution';
|
||||
private baseUrl = '/api/v1/auto-execution';
|
||||
|
||||
async fetchConfigs(tenantId: string, shopId?: string): Promise<AutoExecutionConfig[]> {
|
||||
const params = new URLSearchParams({ tenant_id: tenantId });
|
||||
@@ -512,7 +511,7 @@ class ApiAutoExecutionDataSource implements IAutoExecutionDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const autoExecutionDataSource: IAutoExecutionDataSource = useMock
|
||||
? new MockAutoExecutionDataSource()
|
||||
: new ApiAutoExecutionDataSource();
|
||||
|
||||
@@ -238,9 +238,9 @@ class ApiB2BTradeDataSource implements IB2BTradeDataSource {
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* [MOCK] B2B Trade Mock数据源
|
||||
* [MOCK] B2B Trade Mock数据<EFBFBD><EFBFBD>?
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在REACT_APP_USE_MOCK=true时启用
|
||||
* 仅在REACT_APP_USE_MOCK=true时启<EFBFBD><EFBFBD>?
|
||||
*/
|
||||
class MockB2BTradeDataSource implements IB2BTradeDataSource {
|
||||
readonly __MOCK__ = true as const;
|
||||
@@ -483,10 +483,10 @@ class MockB2BTradeDataSource implements IB2BTradeDataSource {
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 导出数据源实例
|
||||
// 导出数据源实<EFBFBD><EFBFBD>?
|
||||
// ============================================
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
|
||||
export const b2bTradeDataSource: IB2BTradeDataSource = useMock
|
||||
? new MockB2BTradeDataSource()
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/**
|
||||
* [MOCK] 黑名单管理数据源
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启用
|
||||
*/
|
||||
* 仅在USE_MOCK=true时启<EFBFBD>? */
|
||||
|
||||
export interface BlacklistRecord {
|
||||
id: string;
|
||||
@@ -36,6 +35,29 @@ export interface BlacklistRecord {
|
||||
updatedAt?: string;
|
||||
}
|
||||
|
||||
export interface BlacklistRule {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
condition: string;
|
||||
condition_type?: 'TRANSACTION' | 'BEHAVIOR' | 'COMPLIANCE';
|
||||
blacklist_type?: 'FRAUD' | 'CHARGEBACK' | 'ABUSE' | 'OTHER';
|
||||
risk_score?: number;
|
||||
auto_blacklist?: boolean;
|
||||
expiry_days?: number;
|
||||
platforms?: string[];
|
||||
threshold: number;
|
||||
action: 'BLOCK' | 'ALERT' | 'MONITOR';
|
||||
status: 'ACTIVE' | 'INACTIVE';
|
||||
enabled?: boolean;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
createdBy: string;
|
||||
created_by?: string;
|
||||
}
|
||||
|
||||
export interface RiskAssessment {
|
||||
id: string;
|
||||
orderId: string;
|
||||
@@ -79,7 +101,7 @@ class MockBlacklistDataSource implements IBlacklistDataSource {
|
||||
buyer_email: 'john.doe@example.com',
|
||||
platform: 'AMAZON',
|
||||
platform_buyer_id: 'amazon_001',
|
||||
blacklist_reason: '多次恶意退款',
|
||||
blacklist_reason: '多次恶意退货',
|
||||
blacklist_type: 'FRAUD',
|
||||
risk_score: 85,
|
||||
blacklist_date: '2026-03-01',
|
||||
@@ -89,7 +111,7 @@ class MockBlacklistDataSource implements IBlacklistDataSource {
|
||||
updated_at: '2026-03-01',
|
||||
type: 'CUSTOMER',
|
||||
value: 'John Doe',
|
||||
reason: '多次恶意退款',
|
||||
reason: '多次恶意退货',
|
||||
severity: 'HIGH',
|
||||
source: 'MANUAL',
|
||||
createdBy: 'admin',
|
||||
@@ -279,7 +301,7 @@ class ApiBlacklistDataSource implements IBlacklistDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const blacklistDataSource: IBlacklistDataSource = useMock
|
||||
? new MockBlacklistDataSource()
|
||||
: new ApiBlacklistDataSource();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* [MOCK-002] 证书数据源抽象层
|
||||
* 通过环境变量自动切换Mock/真实API
|
||||
* AI注意: 这是唯一入口,业务代码必须调用此层
|
||||
* AI注意: 这是唯一入口,业务代码必须调用此文件
|
||||
*
|
||||
* @module services/certificateDataSource
|
||||
* @author AI-Frontend-Team
|
||||
@@ -15,25 +15,11 @@ import { BaseDataSource, BaseMockDataSource, DataSourceFactory } from './dataSou
|
||||
export type { Certificate } from '@/types/certificate';
|
||||
export { CertificateStatus, CertificateType };
|
||||
|
||||
// ============================================
|
||||
// 真实API实现
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 证书API数据源
|
||||
* 调用真实后端API
|
||||
*/
|
||||
class ApiCertificateDataSource extends BaseDataSource<Certificate, CertificateQueryParams> {
|
||||
constructor() {
|
||||
super('/api/v1/certificate/certificates');
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新证书状态(审核)
|
||||
* @param id 证书ID
|
||||
* @param status 新状态
|
||||
* @param approvedBy 审核人
|
||||
*/
|
||||
async updateStatus(id: string, status: string, approvedBy?: string): Promise<Certificate> {
|
||||
const response = await fetch(`${this.baseUrl}/${id}/status`, {
|
||||
method: 'PUT',
|
||||
@@ -44,33 +30,18 @@ class ApiCertificateDataSource extends BaseDataSource<Certificate, CertificateQu
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`API Error: ${response.status}`);
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
// 更新成功后获取完整数据
|
||||
const updated = await this.detail(id);
|
||||
if (updated) return updated;
|
||||
|
||||
return result.data;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Mock实现 (完全独立文件)
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* [MOCK] 证书Mock数据源
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在REACT_APP_USE_MOCK=true时启用
|
||||
*/
|
||||
class MockCertificateDataSource extends BaseMockDataSource<Certificate, CertificateQueryParams> {
|
||||
/** Mock数据源名称 */
|
||||
class MockCertificateDataSource extends BaseMockDataSource<Certificate, CertificateQueryParams> implements IDataSource<Certificate, CertificateQueryParams> {
|
||||
readonly __MOCK__ = true as const;
|
||||
readonly __MOCK_NAME__ = 'MockCertificateDataSource';
|
||||
|
||||
/** Mock数据 */
|
||||
protected mockData: Certificate[] = [
|
||||
{
|
||||
id: '1',
|
||||
@@ -156,12 +127,6 @@ class MockCertificateDataSource extends BaseMockDataSource<Certificate, Certific
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 更新证书状态(审核)
|
||||
* @param id 证书ID
|
||||
* @param status 新状态
|
||||
* @param approvedBy 审核人
|
||||
*/
|
||||
async updateStatus(id: string, status: string, approvedBy?: string): Promise<Certificate> {
|
||||
await this.delay(300);
|
||||
|
||||
@@ -184,10 +149,6 @@ class MockCertificateDataSource extends BaseMockDataSource<Certificate, Certific
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 导出数据源
|
||||
// ============================================
|
||||
|
||||
export const certificateDataSource = DataSourceFactory.createWithMethods<
|
||||
Certificate,
|
||||
CertificateQueryParams,
|
||||
@@ -199,8 +160,4 @@ export const certificateDataSource = DataSourceFactory.createWithMethods<
|
||||
mockDataSource: MockCertificateDataSource,
|
||||
});
|
||||
|
||||
/**
|
||||
* Mock状态标记
|
||||
* 用于调试和开发环境识别
|
||||
*/
|
||||
export { __MOCK__, __DATA_SOURCE_TYPE__ } from './dataSourceFactory';
|
||||
|
||||
@@ -185,7 +185,7 @@ class ApiCrossBorderIntegrationDataSource implements ICrossBorderIntegrationData
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const crossBorderIntegrationDataSource: ICrossBorderIntegrationDataSource = useMock
|
||||
? new MockCrossBorderIntegrationDataSource()
|
||||
: new ApiCrossBorderIntegrationDataSource();
|
||||
|
||||
@@ -204,7 +204,7 @@ class MockDynamicPricingDataSource implements IDynamicPricingDataSource {
|
||||
const products = [
|
||||
{ id: 'prod-001', name: '无线蓝牙耳机' },
|
||||
{ id: 'prod-002', name: '智能手表' },
|
||||
{ id: 'prod-003', name: '便携充电宝' },
|
||||
{ id: 'prod-003', name: '便携充电器' },
|
||||
{ id: 'prod-004', name: '手机壳' },
|
||||
{ id: 'prod-005', name: '数据线' },
|
||||
];
|
||||
@@ -464,7 +464,7 @@ class MockDynamicPricingDataSource implements IDynamicPricingDataSource {
|
||||
}
|
||||
|
||||
class ApiDynamicPricingDataSource implements IDynamicPricingDataSource {
|
||||
private baseUrl = '/api/pricing';
|
||||
private baseUrl = '/api/v1/pricing';
|
||||
|
||||
async generatePricingDecision(productId: string, strategy?: PricingStrategy): Promise<PricingDecision> {
|
||||
const response = await fetch(`${this.baseUrl}/decisions/generate`, {
|
||||
@@ -565,7 +565,7 @@ class ApiDynamicPricingDataSource implements IDynamicPricingDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const dynamicPricingDataSource: IDynamicPricingDataSource = useMock
|
||||
? new MockDynamicPricingDataSource()
|
||||
: new ApiDynamicPricingDataSource();
|
||||
|
||||
@@ -97,5 +97,5 @@ class ApiFinanceDataSource implements IFinanceDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const financeDataSource: IFinanceDataSource = useMock ? new MockFinanceDataSource() : new ApiFinanceDataSource();
|
||||
|
||||
@@ -202,10 +202,8 @@ class ApiIndependentSiteDataSource implements IIndependentSiteDataSource {
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* [MOCK] IndependentSite Mock数据源
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在REACT_APP_USE_MOCK=true时启用
|
||||
*/
|
||||
* [MOCK] IndependentSite Mock数据<EFBFBD><EFBFBD>? * AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在REACT_APP_USE_MOCK=true时启<E697B6><E590AF>? */
|
||||
class MockIndependentSiteDataSource implements IIndependentSiteDataSource, IMockDataSource<IndependentSite> {
|
||||
readonly __MOCK__ = true as const;
|
||||
readonly __MOCK_NAME__ = 'MockIndependentSiteDataSource';
|
||||
@@ -373,10 +371,9 @@ class MockIndependentSiteDataSource implements IIndependentSiteDataSource, IMock
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 导出数据源实例
|
||||
// ============================================
|
||||
// 导出数据源实<EFBFBD><EFBFBD>?// ============================================
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
|
||||
export const independentSiteDataSource: IIndependentSiteDataSource = useMock
|
||||
? new MockIndependentSiteDataSource()
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/**
|
||||
* [MOCK-010] 库存模块DataSource
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启用
|
||||
*/
|
||||
* 仅在USE_MOCK=true时启<EFBFBD>? */
|
||||
|
||||
import { Inventory, InventoryStatus } from '../types/inventory';
|
||||
|
||||
|
||||
@@ -40,18 +40,16 @@ export interface ILeaderboardDataSource {
|
||||
|
||||
class ApiLeaderboardDataSource extends BaseDataSource<any, any> implements ILeaderboardDataSource {
|
||||
constructor() {
|
||||
super('/api/leaderboard');
|
||||
super('/api/v1/leaderboard');
|
||||
}
|
||||
|
||||
async fetchLeaderboard(period: 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'ALL_TIME'): Promise<LeaderboardData> {
|
||||
// 使用baseUrl属性
|
||||
const response = await fetch(`${this.baseUrl}?period=${period}`);
|
||||
if (!response.ok) throw new Error('Failed to fetch leaderboard');
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async fetchMyRank(period: 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'ALL_TIME'): Promise<MyRank> {
|
||||
// 使用baseUrl属性
|
||||
const response = await fetch(`${this.baseUrl}/my-rank?period=${period}`);
|
||||
if (!response.ok) throw new Error('Failed to fetch my rank');
|
||||
return response.json();
|
||||
@@ -59,10 +57,8 @@ class ApiLeaderboardDataSource extends BaseDataSource<any, any> implements ILead
|
||||
}
|
||||
|
||||
class MockLeaderboardDataSource extends BaseMockDataSource<any, any> implements ILeaderboardDataSource {
|
||||
/** Mock数据源名称 */
|
||||
readonly __MOCK_NAME__ = 'MockLeaderboardDataSource';
|
||||
|
||||
/** Mock数据 */
|
||||
protected mockData: any[] = [];
|
||||
|
||||
private generateRankings(count: number, type: 'revenue' | 'roi' | 'growth'): LeaderboardEntry[] {
|
||||
@@ -82,7 +78,6 @@ class MockLeaderboardDataSource extends BaseMockDataSource<any, any> implements
|
||||
}
|
||||
|
||||
async fetchLeaderboard(period: 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'ALL_TIME'): Promise<LeaderboardData> {
|
||||
// 使用delay方法
|
||||
await this.delay(500);
|
||||
return {
|
||||
revenue: { rankings: this.generateRankings(10, 'revenue'), total: 100 },
|
||||
@@ -94,7 +89,6 @@ class MockLeaderboardDataSource extends BaseMockDataSource<any, any> implements
|
||||
}
|
||||
|
||||
async fetchMyRank(period: 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'ALL_TIME'): Promise<MyRank> {
|
||||
// 使用delay方法
|
||||
await this.delay(300);
|
||||
return {
|
||||
revenue: { rank: 15, percentile: 85 },
|
||||
@@ -104,7 +98,6 @@ class MockLeaderboardDataSource extends BaseMockDataSource<any, any> implements
|
||||
};
|
||||
}
|
||||
|
||||
// 重写delay方法,使其可访问
|
||||
protected async delay(ms: number): Promise<void> {
|
||||
return super.delay(ms);
|
||||
}
|
||||
@@ -119,8 +112,4 @@ export const leaderboardDataSource = DataSourceFactory.createWithMethods<
|
||||
mockDataSource: MockLeaderboardDataSource,
|
||||
});
|
||||
|
||||
/**
|
||||
* Mock状态标记
|
||||
* 用于调试和开发环境识别
|
||||
*/
|
||||
export { __MOCK__, __DATA_SOURCE_TYPE__ } from './dataSourceFactory';
|
||||
export { __MOCK__, __DATA_SOURCE_TYPE__ } from './dataSourceFactory';
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/**
|
||||
* [MOCK] 物流管理数据源
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启用
|
||||
*/
|
||||
* [MOCK] 物流管理数据<EFBFBD><EFBFBD>? * AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启<E697B6><E590AF>? */
|
||||
|
||||
export interface LogisticsProvider {
|
||||
id: string;
|
||||
@@ -262,7 +260,7 @@ class ApiLogisticsDataSource implements ILogisticsDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const logisticsDataSource: ILogisticsDataSource = useMock
|
||||
? new MockLogisticsDataSource()
|
||||
: new ApiLogisticsDataSource();
|
||||
|
||||
@@ -111,5 +111,5 @@ class ApiMarketingDataSource implements IMarketingDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const marketingDataSource: IMarketingDataSource = useMock ? new MockMarketingDataSource() : new ApiMarketingDataSource();
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/**
|
||||
* [MOCK] 商户管理数据源
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启用
|
||||
*/
|
||||
* [MOCK] 商户管理数据<EFBFBD><EFBFBD>? * AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启<E697B6><E590AF>? */
|
||||
|
||||
export interface Merchant {
|
||||
id: string;
|
||||
@@ -369,7 +367,7 @@ class ApiMerchantDataSource implements IMerchantDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const merchantDataSource: IMerchantDataSource = useMock
|
||||
? new MockMerchantDataSource()
|
||||
: new ApiMerchantDataSource();
|
||||
|
||||
@@ -122,7 +122,7 @@ class ApiOmnichannelCommunicationDataSource implements IOmnichannelCommunication
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const omnichannelCommunicationDataSource: IOmnichannelCommunicationDataSource = useMock
|
||||
? new MockOmnichannelCommunicationDataSource()
|
||||
: new ApiOmnichannelCommunicationDataSource();
|
||||
|
||||
@@ -131,7 +131,7 @@ class ApiOmnichannelMarketingDataSource implements IOmnichannelMarketingDataSour
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const omnichannelMarketingDataSource: IOmnichannelMarketingDataSource = useMock
|
||||
? new MockOmnichannelMarketingDataSource()
|
||||
: new ApiOmnichannelMarketingDataSource();
|
||||
|
||||
@@ -1,95 +1,344 @@
|
||||
/**
|
||||
* [MOCK] OperationAgent Mock数据源
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true或开发环境时启用
|
||||
*/
|
||||
|
||||
import { Store, StoreBindingData, SyncResult, IOperationAgentService, Task, TaskCreateData, TaskType, TaskPriority, TaskStatus } from './operationAgentTypes';
|
||||
import { http } from './http';
|
||||
|
||||
export interface StoreBindingData {
|
||||
merchantId: string;
|
||||
platform: string;
|
||||
platformShopId: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
authInfo: Record<string, any>;
|
||||
const MOCK_STORES: Store[] = [
|
||||
{
|
||||
id: 'store-001',
|
||||
merchantId: 'merchant-1',
|
||||
name: 'Amazon US Store',
|
||||
platform: 'amazon',
|
||||
platformShopId: 'AMZ-US-001',
|
||||
description: 'Amazon美国站点主店铺',
|
||||
status: 'active',
|
||||
created_at: '2024-01-15T08:00:00Z',
|
||||
updated_at: '2024-03-20T10:30:00Z',
|
||||
},
|
||||
{
|
||||
id: 'store-002',
|
||||
merchantId: 'merchant-1',
|
||||
name: 'Shopee SG Store',
|
||||
platform: 'shopee',
|
||||
platformShopId: 'SHP-SG-001',
|
||||
description: 'Shopee新加坡站点',
|
||||
status: 'active',
|
||||
created_at: '2024-02-10T09:00:00Z',
|
||||
updated_at: '2024-03-18T14:20:00Z',
|
||||
},
|
||||
{
|
||||
id: 'store-003',
|
||||
merchantId: 'merchant-1',
|
||||
name: 'AliExpress Store',
|
||||
platform: 'aliexpress',
|
||||
platformShopId: 'AE-001',
|
||||
description: 'AliExpress主店铺',
|
||||
status: 'pending',
|
||||
created_at: '2024-03-01T10:00:00Z',
|
||||
updated_at: '2024-03-15T16:45:00Z',
|
||||
},
|
||||
{
|
||||
id: 'store-004',
|
||||
merchantId: 'merchant-2',
|
||||
name: 'TikTok Shop US',
|
||||
platform: 'tiktok',
|
||||
platformShopId: 'TT-US-001',
|
||||
description: 'TikTok美国小店',
|
||||
status: 'active',
|
||||
created_at: '2024-02-20T11:00:00Z',
|
||||
updated_at: '2024-03-19T09:15:00Z',
|
||||
},
|
||||
];
|
||||
|
||||
const MOCK_TASKS: Task[] = [
|
||||
{
|
||||
id: 'task-001',
|
||||
merchantId: 'merchant-1',
|
||||
storeId: 'store-001',
|
||||
taskType: 'PRICING',
|
||||
targetProducts: ['prod-001', 'prod-002', 'prod-003'],
|
||||
constraints: { maxPrice: 100, minROI: 0.3, maxQuantity: 1000 },
|
||||
priority: 'HIGH',
|
||||
status: 'COMPLETED',
|
||||
progress: 100,
|
||||
description: '优化Amazon店铺商品定价',
|
||||
logs: [
|
||||
'任务开始: 2024-03-20T08:00:00Z',
|
||||
'正在分析商品价格: 2024-03-20T08:05:00Z',
|
||||
'正在优化定价策略: 2024-03-20T08:10:00Z',
|
||||
'任务完成: 2024-03-20T08:15:00Z',
|
||||
],
|
||||
created_at: '2024-03-20T08:00:00Z',
|
||||
updated_at: '2024-03-20T08:15:00Z',
|
||||
completed_at: '2024-03-20T08:15:00Z',
|
||||
},
|
||||
{
|
||||
id: 'task-002',
|
||||
merchantId: 'merchant-1',
|
||||
storeId: 'store-002',
|
||||
taskType: 'LISTING',
|
||||
targetProducts: ['prod-004', 'prod-005'],
|
||||
constraints: { maxPrice: 50, maxQuantity: 500 },
|
||||
priority: 'MEDIUM',
|
||||
status: 'RUNNING',
|
||||
progress: 60,
|
||||
description: 'Shopee店铺商品上架',
|
||||
logs: [
|
||||
'任务开始: 2024-03-21T10:00:00Z',
|
||||
'正在准备商品数据: 2024-03-21T10:05:00Z',
|
||||
'正在上传商品信息: 2024-03-21T10:10:00Z',
|
||||
],
|
||||
created_at: '2024-03-21T10:00:00Z',
|
||||
updated_at: '2024-03-21T10:20:00Z',
|
||||
},
|
||||
{
|
||||
id: 'task-003',
|
||||
merchantId: 'merchant-1',
|
||||
storeId: 'store-001',
|
||||
taskType: 'AD_OPTIMIZATION',
|
||||
targetProducts: ['prod-001', 'prod-003'],
|
||||
constraints: { minROI: 0.4 },
|
||||
priority: 'LOW',
|
||||
status: 'FAILED',
|
||||
progress: 30,
|
||||
description: '优化Amazon广告策略',
|
||||
error: '广告API调用失败',
|
||||
logs: [
|
||||
'任务开始: 2024-03-21T14:00:00Z',
|
||||
'正在获取广告数据: 2024-03-21T14:05:00Z',
|
||||
'正在分析广告效果: 2024-03-21T14:10:00Z',
|
||||
'发生错误: 2024-03-21T14:15:00Z',
|
||||
],
|
||||
created_at: '2024-03-21T14:00:00Z',
|
||||
updated_at: '2024-03-21T14:15:00Z',
|
||||
},
|
||||
{
|
||||
id: 'task-004',
|
||||
merchantId: 'merchant-2',
|
||||
storeId: 'store-004',
|
||||
taskType: 'PRICING',
|
||||
targetProducts: ['prod-006', 'prod-007'],
|
||||
constraints: { maxPrice: 80, minROI: 0.25 },
|
||||
priority: 'MEDIUM',
|
||||
status: 'PENDING',
|
||||
progress: 0,
|
||||
description: 'TikTok店铺商品定价优化',
|
||||
created_at: '2024-03-22T09:00:00Z',
|
||||
updated_at: '2024-03-22T09:00:00Z',
|
||||
},
|
||||
];
|
||||
|
||||
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
class MockOperationAgentService implements IOperationAgentService {
|
||||
private stores: Store[] = [...MOCK_STORES];
|
||||
private tasks: Task[] = [...MOCK_TASKS];
|
||||
|
||||
async bindStore(data: StoreBindingData): Promise<Store> {
|
||||
await delay(500);
|
||||
const newStore: Store = {
|
||||
id: `store-${Date.now()}`,
|
||||
merchantId: data.merchantId,
|
||||
name: data.name,
|
||||
platform: data.platform,
|
||||
platformShopId: data.platformShopId,
|
||||
description: data.description || '',
|
||||
status: 'pending',
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
};
|
||||
this.stores.push(newStore);
|
||||
return newStore;
|
||||
}
|
||||
|
||||
async getStores(merchantId: string): Promise<Store[]> {
|
||||
await delay(300);
|
||||
return this.stores.filter(s => s.merchantId === merchantId);
|
||||
}
|
||||
|
||||
async getStore(storeId: string): Promise<Store> {
|
||||
await delay(200);
|
||||
const store = this.stores.find(s => s.id === storeId);
|
||||
if (!store) {
|
||||
throw new Error('Store not found');
|
||||
}
|
||||
return store;
|
||||
}
|
||||
|
||||
async syncProducts(storeId: string): Promise<SyncResult> {
|
||||
await delay(1000);
|
||||
return {
|
||||
success: true,
|
||||
count: Math.floor(Math.random() * 100) + 50,
|
||||
};
|
||||
}
|
||||
|
||||
async syncOrders(storeId: string): Promise<SyncResult> {
|
||||
await delay(800);
|
||||
return {
|
||||
success: true,
|
||||
count: Math.floor(Math.random() * 50) + 20,
|
||||
};
|
||||
}
|
||||
|
||||
async updateProductPrice(storeId: string, productId: string, price: number): Promise<boolean> {
|
||||
await delay(300);
|
||||
return true;
|
||||
}
|
||||
|
||||
async deactivateStore(storeId: string): Promise<Store> {
|
||||
await delay(300);
|
||||
const store = this.stores.find(s => s.id === storeId);
|
||||
if (store) {
|
||||
store.status = 'inactive';
|
||||
store.updated_at = new Date().toISOString();
|
||||
}
|
||||
return store!;
|
||||
}
|
||||
|
||||
async reactivateStore(storeId: string): Promise<Store> {
|
||||
await delay(300);
|
||||
const store = this.stores.find(s => s.id === storeId);
|
||||
if (store) {
|
||||
store.status = 'active';
|
||||
store.updated_at = new Date().toISOString();
|
||||
}
|
||||
return store!;
|
||||
}
|
||||
|
||||
// 任务相关方法
|
||||
async getTasks(merchantId: string): Promise<Task[]> {
|
||||
await delay(300);
|
||||
return this.tasks.filter(t => t.merchantId === merchantId);
|
||||
}
|
||||
|
||||
async getTask(taskId: string): Promise<Task> {
|
||||
await delay(200);
|
||||
const task = this.tasks.find(t => t.id === taskId);
|
||||
if (!task) {
|
||||
throw new Error('Task not found');
|
||||
}
|
||||
return task;
|
||||
}
|
||||
|
||||
async createTask(data: TaskCreateData): Promise<Task> {
|
||||
await delay(500);
|
||||
const newTask: Task = {
|
||||
id: `task-${Date.now()}`,
|
||||
merchantId: data.merchantId,
|
||||
storeId: data.storeId,
|
||||
taskType: data.taskType,
|
||||
targetProducts: data.targetProducts,
|
||||
constraints: data.constraints,
|
||||
priority: data.priority,
|
||||
status: 'PENDING',
|
||||
progress: 0,
|
||||
description: data.description,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
};
|
||||
this.tasks.push(newTask);
|
||||
return newTask;
|
||||
}
|
||||
|
||||
async cancelTask(taskId: string): Promise<boolean> {
|
||||
await delay(300);
|
||||
const task = this.tasks.find(t => t.id === taskId);
|
||||
if (task) {
|
||||
task.status = 'CANCELLED';
|
||||
task.updated_at = new Date().toISOString();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async retryTask(taskId: string): Promise<boolean> {
|
||||
await delay(300);
|
||||
const task = this.tasks.find(t => t.id === taskId);
|
||||
if (task) {
|
||||
task.status = 'PENDING';
|
||||
task.progress = 0;
|
||||
task.error = undefined;
|
||||
task.updated_at = new Date().toISOString();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export interface Store {
|
||||
id: string;
|
||||
merchantId: string;
|
||||
name: string;
|
||||
platform: string;
|
||||
platformShopId: string;
|
||||
description: string;
|
||||
status: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface SyncResult {
|
||||
success: boolean;
|
||||
count: number;
|
||||
}
|
||||
|
||||
export class OperationAgentService {
|
||||
/**
|
||||
* 绑定店铺
|
||||
*/
|
||||
class ApiOperationAgentService implements IOperationAgentService {
|
||||
async bindStore(data: StoreBindingData): Promise<Store> {
|
||||
const response = await http.post<Store>('/api/operation-agent/stores', data);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商户的店铺列表
|
||||
*/
|
||||
async getStores(merchantId: string): Promise<Store[]> {
|
||||
const response = await http.get<Store[]>(`/api/operation-agent/stores/${merchantId}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取店铺详情
|
||||
*/
|
||||
async getStore(storeId: string): Promise<Store> {
|
||||
const response = await http.get<Store>(`/api/operation-agent/stores/detail/${storeId}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步店铺商品
|
||||
*/
|
||||
async syncProducts(storeId: string): Promise<SyncResult> {
|
||||
const response = await http.post<SyncResult>(`/api/operation-agent/stores/${storeId}/products/sync`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步店铺订单
|
||||
*/
|
||||
async syncOrders(storeId: string): Promise<SyncResult> {
|
||||
const response = await http.post<SyncResult>(`/api/operation-agent/stores/${storeId}/orders/sync`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新商品价格
|
||||
*/
|
||||
async updateProductPrice(storeId: string, productId: string, price: number): Promise<boolean> {
|
||||
const response = await http.put<boolean>(`/api/operation-agent/stores/${storeId}/products/${productId}/price`, { price });
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 停用店铺
|
||||
*/
|
||||
async deactivateStore(storeId: string): Promise<Store> {
|
||||
const response = await http.put<Store>(`/api/operation-agent/stores/${storeId}/deactivate`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新激活店铺
|
||||
*/
|
||||
async reactivateStore(storeId: string): Promise<Store> {
|
||||
const response = await http.put<Store>(`/api/operation-agent/stores/${storeId}/reactivate`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// 任务相关方法
|
||||
async getTasks(merchantId: string): Promise<Task[]> {
|
||||
const response = await http.get<Task[]>(`/api/operation-agent/tasks/${merchantId}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async getTask(taskId: string): Promise<Task> {
|
||||
const response = await http.get<Task>(`/api/operation-agent/tasks/detail/${taskId}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async createTask(data: TaskCreateData): Promise<Task> {
|
||||
const response = await http.post<Task>('/api/operation-agent/tasks', data);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async cancelTask(taskId: string): Promise<boolean> {
|
||||
const response = await http.put<boolean>(`/api/operation-agent/tasks/${taskId}/cancel`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async retryTask(taskId: string): Promise<boolean> {
|
||||
const response = await http.put<boolean>(`/api/operation-agent/tasks/${taskId}/retry`);
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const operationAgentService = new OperationAgentService();
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const operationAgentService: IOperationAgentService = useMock
|
||||
? new MockOperationAgentService()
|
||||
: new ApiOperationAgentService();
|
||||
|
||||
export type { Store, StoreBindingData, SyncResult, Task, TaskType, TaskPriority, TaskStatus };
|
||||
|
||||
84
dashboard/src/services/operationAgentTypes.ts
Normal file
84
dashboard/src/services/operationAgentTypes.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* OperationAgent类型定义
|
||||
*/
|
||||
|
||||
export interface StoreBindingData {
|
||||
merchantId: string;
|
||||
platform: string;
|
||||
platformShopId: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
authInfo: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface Store {
|
||||
id: string;
|
||||
merchantId: string;
|
||||
name: string;
|
||||
platform: string;
|
||||
platformShopId: string;
|
||||
description: string;
|
||||
status: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface SyncResult {
|
||||
success: boolean;
|
||||
count: number;
|
||||
}
|
||||
|
||||
export type TaskType = 'PRICING' | 'LISTING' | 'AD_OPTIMIZATION';
|
||||
export type TaskPriority = 'HIGH' | 'MEDIUM' | 'LOW';
|
||||
export type TaskStatus = 'PENDING' | 'RUNNING' | 'COMPLETED' | 'FAILED' | 'CANCELLED';
|
||||
|
||||
export interface TaskConstraints {
|
||||
maxPrice?: number;
|
||||
minROI?: number;
|
||||
maxQuantity?: number;
|
||||
}
|
||||
|
||||
export interface Task {
|
||||
id: string;
|
||||
merchantId: string;
|
||||
storeId: string;
|
||||
taskType: TaskType;
|
||||
targetProducts: string[];
|
||||
constraints: TaskConstraints;
|
||||
priority: TaskPriority;
|
||||
status: TaskStatus;
|
||||
progress: number;
|
||||
description?: string;
|
||||
logs?: string[];
|
||||
error?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
completed_at?: string;
|
||||
}
|
||||
|
||||
export interface TaskCreateData {
|
||||
merchantId: string;
|
||||
storeId: string;
|
||||
taskType: TaskType;
|
||||
targetProducts: string[];
|
||||
constraints: TaskConstraints;
|
||||
priority: TaskPriority;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface IOperationAgentService {
|
||||
bindStore(data: StoreBindingData): Promise<Store>;
|
||||
getStores(merchantId: string): Promise<Store[]>;
|
||||
getStore(storeId: string): Promise<Store>;
|
||||
syncProducts(storeId: string): Promise<SyncResult>;
|
||||
syncOrders(storeId: string): Promise<SyncResult>;
|
||||
updateProductPrice(storeId: string, productId: string, price: number): Promise<boolean>;
|
||||
deactivateStore(storeId: string): Promise<Store>;
|
||||
reactivateStore(storeId: string): Promise<Store>;
|
||||
// 任务相关方法
|
||||
getTasks(merchantId: string): Promise<Task[]>;
|
||||
getTask(taskId: string): Promise<Task>;
|
||||
createTask(data: TaskCreateData): Promise<Task>;
|
||||
cancelTask(taskId: string): Promise<boolean>;
|
||||
retryTask(taskId: string): Promise<boolean>;
|
||||
}
|
||||
168
dashboard/src/services/platformAuthDataSource.ts
Normal file
168
dashboard/src/services/platformAuthDataSource.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
import { http } from './http';
|
||||
import { PlatformAccount, PlatformAccountStats } from '@/types/platform';
|
||||
|
||||
export interface PlatformAuthDataSource {
|
||||
list(filters?: { platform?: string; status?: string; shopId?: string }): Promise<PlatformAccount[]>;
|
||||
getById(id: string): Promise<PlatformAccount | null>;
|
||||
connect(data: { platform: string; accountName: string; accountId: string; shopId?: string; config?: Record<string, any> }): Promise<{ account: PlatformAccount; authUrl: string }>;
|
||||
refresh(id: string): Promise<{ success: boolean; message: string }>;
|
||||
disconnect(id: string): Promise<void>;
|
||||
delete(id: string): Promise<void>;
|
||||
getStats(): Promise<PlatformAccountStats>;
|
||||
}
|
||||
|
||||
export class PlatformAuthApiDataSource implements PlatformAuthDataSource {
|
||||
async list(filters?: { platform?: string; status?: string; shopId?: string }): Promise<PlatformAccount[]> {
|
||||
const params = new URLSearchParams();
|
||||
if (filters?.platform) params.append('platform', filters.platform);
|
||||
if (filters?.status) params.append('status', filters.status);
|
||||
if (filters?.shopId) params.append('shopId', filters.shopId);
|
||||
|
||||
const response = await http.get(`/api/platform-auth/list?${params.toString()}`);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
async getById(id: string): Promise<PlatformAccount | null> {
|
||||
const response = await http.get(`/api/platform-auth/${id}`);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
async connect(data: { platform: string; accountName: string; accountId: string; shopId?: string; config?: Record<string, any> }): Promise<{ account: PlatformAccount; authUrl: string }> {
|
||||
const response = await http.post('/api/platform-auth/connect', data);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
async refresh(id: string): Promise<{ success: boolean; message: string }> {
|
||||
const response = await http.post(`/api/platform-auth/refresh/${id}`);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
async disconnect(id: string): Promise<void> {
|
||||
await http.post(`/api/platform-auth/disconnect/${id}`);
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await http.delete(`/api/platform-auth/${id}`);
|
||||
}
|
||||
|
||||
async getStats(): Promise<PlatformAccountStats> {
|
||||
const response = await http.get('/api/platform-auth/stats');
|
||||
return response.data.data;
|
||||
}
|
||||
}
|
||||
|
||||
export class PlatformAuthMockDataSource implements PlatformAuthDataSource {
|
||||
private mockAccounts: PlatformAccount[] = [
|
||||
{
|
||||
id: '1',
|
||||
tenantId: 'tenant_1',
|
||||
platform: 'AMAZON',
|
||||
accountName: 'My Amazon Store',
|
||||
accountId: 'amazon_123',
|
||||
status: 'ACTIVE',
|
||||
lastSyncAt: '2024-01-15T10:30:00Z',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
updatedAt: '2024-01-15T10:30:00Z',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
tenantId: 'tenant_1',
|
||||
platform: 'SHOPIFY',
|
||||
accountName: 'my-shop.myshopify.com',
|
||||
accountId: 'shopify_456',
|
||||
status: 'ACTIVE',
|
||||
lastSyncAt: '2024-01-15T09:15:00Z',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
updatedAt: '2024-01-15T09:15:00Z',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
tenantId: 'tenant_1',
|
||||
platform: 'SHOPEE',
|
||||
accountName: 'My Shopee Shop',
|
||||
accountId: 'shopee_789',
|
||||
status: 'EXPIRED',
|
||||
lastSyncAt: '2023-12-01T08:00:00Z',
|
||||
createdAt: '2023-06-01T00:00:00Z',
|
||||
updatedAt: '2024-01-01T08:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
tenantId: 'tenant_1',
|
||||
platform: 'EBAY',
|
||||
accountName: 'My eBay Store',
|
||||
accountId: 'ebay_101',
|
||||
status: 'INACTIVE',
|
||||
createdAt: '2024-01-10T00:00:00Z',
|
||||
updatedAt: '2024-01-10T00:00:00Z',
|
||||
},
|
||||
];
|
||||
|
||||
async list(filters?: { platform?: string; status?: string; shopId?: string }): Promise<PlatformAccount[]> {
|
||||
let result = [...this.mockAccounts];
|
||||
if (filters?.platform) {
|
||||
result = result.filter(a => a.platform === filters.platform);
|
||||
}
|
||||
if (filters?.status) {
|
||||
result = result.filter(a => a.status === filters.status);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async getById(id: string): Promise<PlatformAccount | null> {
|
||||
return this.mockAccounts.find(a => a.id === id) || null;
|
||||
}
|
||||
|
||||
async connect(data: { platform: string; accountName: string; accountId: string; shopId?: string; config?: Record<string, any> }): Promise<{ account: PlatformAccount; authUrl: string }> {
|
||||
const account: PlatformAccount = {
|
||||
id: Date.now().toString(),
|
||||
tenantId: 'tenant_1',
|
||||
platform: data.platform,
|
||||
accountName: data.accountName,
|
||||
accountId: data.accountId,
|
||||
status: 'INACTIVE',
|
||||
shopId: data.shopId,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
this.mockAccounts.push(account);
|
||||
return {
|
||||
account,
|
||||
authUrl: `https://example.com/oauth/authorize?platform=${data.platform}`,
|
||||
};
|
||||
}
|
||||
|
||||
async refresh(id: string): Promise<{ success: boolean; message: string }> {
|
||||
const account = this.mockAccounts.find(a => a.id === id);
|
||||
if (account) {
|
||||
account.status = 'ACTIVE';
|
||||
account.lastSyncAt = new Date().toISOString();
|
||||
}
|
||||
return { success: true, message: 'Token refreshed successfully' };
|
||||
}
|
||||
|
||||
async disconnect(id: string): Promise<void> {
|
||||
const account = this.mockAccounts.find(a => a.id === id);
|
||||
if (account) {
|
||||
account.status = 'INACTIVE';
|
||||
}
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
this.mockAccounts = this.mockAccounts.filter(a => a.id !== id);
|
||||
}
|
||||
|
||||
async getStats(): Promise<PlatformAccountStats> {
|
||||
return {
|
||||
total: this.mockAccounts.length,
|
||||
active: this.mockAccounts.filter(a => a.status === 'ACTIVE').length,
|
||||
inactive: this.mockAccounts.filter(a => a.status === 'INACTIVE').length,
|
||||
expired: this.mockAccounts.filter(a => a.status === 'EXPIRED').length,
|
||||
error: this.mockAccounts.filter(a => a.status === 'ERROR').length,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const platformAuthDataSource = process.env.REACT_APP_USE_MOCK === 'true'
|
||||
? new PlatformAuthMockDataSource()
|
||||
: new PlatformAuthApiDataSource();
|
||||
@@ -7,6 +7,23 @@
|
||||
import { Product, ProductStatus } from '@/types/product';
|
||||
import { IDataSource, IMockDataSource } from '@/types/datasource';
|
||||
|
||||
export type Platform = 'Amazon' | 'eBay' | 'Shopee' | 'TikTok' | 'Shopify';
|
||||
|
||||
export interface PlatformStatus {
|
||||
platform: Platform;
|
||||
status: 'LIVE' | 'PENDING' | 'SYNCING' | 'LISTED' | 'FAILED' | 'OFFLINE';
|
||||
platformProductId?: string;
|
||||
lastSyncAt?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface ProductWithPlatform extends Product {
|
||||
platformStatus: Record<Platform, PlatformStatus['status']>;
|
||||
costPrice: number;
|
||||
profit: number;
|
||||
roi: number;
|
||||
}
|
||||
|
||||
export interface ProfitMonitor {
|
||||
id: string;
|
||||
productId: string;
|
||||
@@ -35,6 +52,21 @@ export interface ROIAnalysis {
|
||||
status: 'ACTIVE' | 'COMPLETED' | 'PAUSED';
|
||||
}
|
||||
|
||||
export interface PlatformSyncResult {
|
||||
platform: Platform;
|
||||
success: boolean;
|
||||
platformProductId?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface ProductDataSource extends IDataSource<ProductWithPlatform> {
|
||||
listByPlatform(platform: Platform): Promise<ProductWithPlatform[]>;
|
||||
listUnpublished(): Promise<ProductWithPlatform[]>;
|
||||
syncToPlatform(productId: string, platform: Platform): Promise<PlatformSyncResult>;
|
||||
syncToMultiplePlatforms(productId: string, platforms: Platform[]): Promise<Record<Platform, PlatformSyncResult>>;
|
||||
getPlatformStats(): Promise<Record<Platform | 'all' | 'unpublished', { total: number; live: number; pending: number; failed: number }>>;
|
||||
}
|
||||
|
||||
export class ProductApiDataSource implements IDataSource<Product> {
|
||||
async list(): Promise<Product[]> {
|
||||
return [];
|
||||
@@ -65,54 +97,143 @@ export class ProductApiDataSource implements IDataSource<Product> {
|
||||
}
|
||||
}
|
||||
|
||||
export class ProductMockDataSource implements IMockDataSource<Product> {
|
||||
private mockProducts: Product[] = [
|
||||
export class ProductMockDataSource implements IMockDataSource<ProductWithPlatform>, ProductDataSource {
|
||||
private mockProducts: ProductWithPlatform[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: '智能手机',
|
||||
sku: 'PHONE-001',
|
||||
description: '最新款智能手机',
|
||||
price: 5999.99,
|
||||
categories: ['电子产品'],
|
||||
name: '工业温度传感器Pro',
|
||||
sku: 'TP-TEMP-001',
|
||||
description: '高精度工业温度传感器',
|
||||
price: 89.99,
|
||||
costPrice: 45.00,
|
||||
profit: 44.99,
|
||||
roi: 99.98,
|
||||
categories: ['工业自动化'],
|
||||
status: 'active',
|
||||
stock: 100,
|
||||
images: ['https://example.com/phone1.jpg', 'https://example.com/phone2.jpg'],
|
||||
createdAt: new Date('2026-03-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
stock: 256,
|
||||
images: ['https://via.placeholder.com/80x80?text=Product'],
|
||||
platformStatus: { Amazon: 'LIVE', eBay: 'LIVE', Shopee: 'PENDING', TikTok: 'OFFLINE', Shopify: 'OFFLINE' },
|
||||
createdAt: new Date('2025-12-15'),
|
||||
updatedAt: new Date('2026-03-18'),
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: '笔记本电脑',
|
||||
sku: 'LAPTOP-001',
|
||||
description: '高性能笔记本电脑',
|
||||
price: 8999.99,
|
||||
categories: ['电子产品'],
|
||||
name: '压力传感器Digital',
|
||||
sku: 'TP-PRES-002',
|
||||
description: '数字压力传感器',
|
||||
price: 129.99,
|
||||
costPrice: 65.00,
|
||||
profit: 64.99,
|
||||
roi: 99.98,
|
||||
categories: ['工业自动化'],
|
||||
status: 'active',
|
||||
stock: 50,
|
||||
images: ['https://example.com/laptop1.jpg', 'https://example.com/laptop2.jpg'],
|
||||
createdAt: new Date('2026-03-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
stock: 128,
|
||||
images: ['https://via.placeholder.com/80x80?text=Product'],
|
||||
platformStatus: { Amazon: 'OFFLINE', eBay: 'OFFLINE', Shopee: 'OFFLINE', TikTok: 'OFFLINE', Shopify: 'OFFLINE' },
|
||||
createdAt: new Date('2026-03-10'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: '运动鞋',
|
||||
sku: 'SHOE-001',
|
||||
description: '轻便透气运动鞋',
|
||||
price: 89.99,
|
||||
categories: ['服装'],
|
||||
name: '流量计Ultra',
|
||||
sku: 'TP-FLOW-003',
|
||||
description: '超声波流量计',
|
||||
price: 299.99,
|
||||
costPrice: 150.00,
|
||||
profit: 149.99,
|
||||
roi: 99.99,
|
||||
categories: ['仪器仪表'],
|
||||
status: 'active',
|
||||
stock: 150,
|
||||
images: ['https://example.com/shoe1.jpg', 'https://example.com/shoe2.jpg'],
|
||||
createdAt: new Date('2026-03-03'),
|
||||
updatedAt: new Date('2026-03-12'),
|
||||
stock: 64,
|
||||
images: ['https://via.placeholder.com/80x80?text=Product'],
|
||||
platformStatus: { Amazon: 'OFFLINE', eBay: 'OFFLINE', Shopee: 'OFFLINE', TikTok: 'OFFLINE', Shopify: 'OFFLINE' },
|
||||
createdAt: new Date('2026-03-15'),
|
||||
updatedAt: new Date('2026-03-16'),
|
||||
},
|
||||
];
|
||||
|
||||
async list(): Promise<Product[]> {
|
||||
async list(): Promise<ProductWithPlatform[]> {
|
||||
return this.mockProducts;
|
||||
}
|
||||
|
||||
async detail(id: string): Promise<Product> {
|
||||
async listByPlatform(platform: Platform): Promise<ProductWithPlatform[]> {
|
||||
return this.mockProducts.filter(p => p.platformStatus[platform] && p.platformStatus[platform] !== 'OFFLINE');
|
||||
}
|
||||
|
||||
async listUnpublished(): Promise<ProductWithPlatform[]> {
|
||||
return this.mockProducts.filter(p =>
|
||||
Object.values(p.platformStatus).every(status => status === 'OFFLINE')
|
||||
);
|
||||
}
|
||||
|
||||
async syncToPlatform(productId: string, platform: Platform): Promise<PlatformSyncResult> {
|
||||
const product = this.mockProducts.find(p => p.id === productId);
|
||||
if (!product) {
|
||||
return { platform, success: false, error: 'Product not found' };
|
||||
}
|
||||
|
||||
product.platformStatus[platform] = 'SYNCING';
|
||||
product.updatedAt = new Date();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
const success = Math.random() > 0.2;
|
||||
if (success) {
|
||||
product.platformStatus[platform] = 'LIVE';
|
||||
return { platform, success: true, platformProductId: `${platform}-${productId}` };
|
||||
} else {
|
||||
product.platformStatus[platform] = 'FAILED';
|
||||
return { platform, success: false, error: 'Sync failed' };
|
||||
}
|
||||
}
|
||||
|
||||
async syncToMultiplePlatforms(productId: string, platforms: Platform[]): Promise<Record<Platform, PlatformSyncResult>> {
|
||||
const results: Record<Platform, PlatformSyncResult> = {} as any;
|
||||
for (const platform of platforms) {
|
||||
results[platform] = await this.syncToPlatform(productId, platform);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
async getPlatformStats(): Promise<Record<Platform | 'all' | 'unpublished', { total: number; live: number; pending: number; failed: number }>> {
|
||||
const stats: any = {
|
||||
all: { total: this.mockProducts.length, live: 0, pending: 0, failed: 0 },
|
||||
unpublished: { total: 0, live: 0, pending: 0, failed: 0 },
|
||||
};
|
||||
|
||||
const platforms: Platform[] = ['Amazon', 'eBay', 'Shopee', 'TikTok', 'Shopify'];
|
||||
platforms.forEach(p => {
|
||||
stats[p] = { total: 0, live: 0, pending: 0, failed: 0 };
|
||||
});
|
||||
|
||||
this.mockProducts.forEach(product => {
|
||||
const hasPlatform = Object.values(product.platformStatus).some(s => s !== 'OFFLINE');
|
||||
if (!hasPlatform) {
|
||||
stats.unpublished.total++;
|
||||
}
|
||||
|
||||
platforms.forEach(platform => {
|
||||
const status = product.platformStatus[platform];
|
||||
if (status && status !== 'OFFLINE') {
|
||||
stats[platform].total++;
|
||||
if (status === 'LIVE') {
|
||||
stats[platform].live++;
|
||||
stats.all.live++;
|
||||
} else if (['PENDING', 'SYNCING', 'LISTED'].includes(status)) {
|
||||
stats[platform].pending++;
|
||||
stats.all.pending++;
|
||||
} else if (['FAILED', 'SYNC_FAILED'].includes(status)) {
|
||||
stats[platform].failed++;
|
||||
stats.all.failed++;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
async detail(id: string): Promise<ProductWithPlatform> {
|
||||
const product = this.mockProducts.find(p => p.id === id);
|
||||
if (!product) {
|
||||
throw new Error('Product not found');
|
||||
@@ -120,17 +241,21 @@ export class ProductMockDataSource implements IMockDataSource<Product> {
|
||||
return product;
|
||||
}
|
||||
|
||||
async create(data: Partial<Product>): Promise<Product> {
|
||||
const newProduct: Product = {
|
||||
async create(data: Partial<ProductWithPlatform>): Promise<ProductWithPlatform> {
|
||||
const newProduct: ProductWithPlatform = {
|
||||
id: `${this.mockProducts.length + 1}`,
|
||||
name: data.name || '',
|
||||
sku: data.sku || `SKU-${Date.now()}`,
|
||||
description: data.description || '',
|
||||
price: data.price || 0,
|
||||
costPrice: data.costPrice || 0,
|
||||
profit: data.profit || 0,
|
||||
roi: data.roi || 0,
|
||||
categories: data.categories || [],
|
||||
status: data.status || 'active',
|
||||
stock: data.stock || 0,
|
||||
images: data.images || [],
|
||||
platformStatus: data.platformStatus || { Amazon: 'OFFLINE', eBay: 'OFFLINE', Shopee: 'OFFLINE', TikTok: 'OFFLINE', Shopify: 'OFFLINE' },
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
@@ -138,7 +263,7 @@ export class ProductMockDataSource implements IMockDataSource<Product> {
|
||||
return newProduct;
|
||||
}
|
||||
|
||||
async update(id: string, data: Partial<Product>): Promise<Product> {
|
||||
async update(id: string, data: Partial<ProductWithPlatform>): Promise<ProductWithPlatform> {
|
||||
const index = this.mockProducts.findIndex(p => p.id === id);
|
||||
if (index === -1) {
|
||||
throw new Error('Product not found');
|
||||
@@ -159,17 +284,17 @@ export class ProductMockDataSource implements IMockDataSource<Product> {
|
||||
this.mockProducts.splice(index, 1);
|
||||
}
|
||||
|
||||
async getByCategory(category: string): Promise<Product[]> {
|
||||
async getByCategory(category: string): Promise<ProductWithPlatform[]> {
|
||||
return this.mockProducts.filter(p => p.categories?.includes(category));
|
||||
}
|
||||
|
||||
async updateStatus(id: string, status: ProductStatus): Promise<Product | null> {
|
||||
async updateStatus(id: string, status: ProductStatus): Promise<ProductWithPlatform | null> {
|
||||
const existingProduct = this.mockProducts.find(p => p.id === id);
|
||||
if (!existingProduct) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedProduct: Product = {
|
||||
const updatedProduct: ProductWithPlatform = {
|
||||
...existingProduct,
|
||||
status,
|
||||
updatedAt: new Date(),
|
||||
@@ -187,47 +312,25 @@ export class ProductMockDataSource implements IMockDataSource<Product> {
|
||||
this.mockProducts = [
|
||||
{
|
||||
id: '1',
|
||||
name: '智能手机',
|
||||
sku: 'PHONE-001',
|
||||
description: '最新款智能手机',
|
||||
price: 5999.99,
|
||||
categories: ['电子产品'],
|
||||
status: 'active',
|
||||
stock: 100,
|
||||
images: ['https://example.com/phone1.jpg', 'https://example.com/phone2.jpg'],
|
||||
createdAt: new Date('2026-03-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: '笔记本电脑',
|
||||
sku: 'LAPTOP-001',
|
||||
description: '高性能笔记本电脑',
|
||||
price: 8999.99,
|
||||
categories: ['电子产品'],
|
||||
status: 'active',
|
||||
stock: 50,
|
||||
images: ['https://example.com/laptop1.jpg', 'https://example.com/laptop2.jpg'],
|
||||
createdAt: new Date('2026-03-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: '运动鞋',
|
||||
sku: 'SHOE-001',
|
||||
description: '轻便透气运动鞋',
|
||||
name: '工业温度传感器Pro',
|
||||
sku: 'TP-TEMP-001',
|
||||
description: '高精度工业温度传感器',
|
||||
price: 89.99,
|
||||
categories: ['服装'],
|
||||
costPrice: 45.00,
|
||||
profit: 44.99,
|
||||
roi: 99.98,
|
||||
categories: ['工业自动化'],
|
||||
status: 'active',
|
||||
stock: 150,
|
||||
images: ['https://example.com/shoe1.jpg', 'https://example.com/shoe2.jpg'],
|
||||
createdAt: new Date('2026-03-03'),
|
||||
updatedAt: new Date('2026-03-12'),
|
||||
stock: 256,
|
||||
images: ['https://via.placeholder.com/80x80?text=Product'],
|
||||
platformStatus: { Amazon: 'LIVE', eBay: 'LIVE', Shopee: 'PENDING', TikTok: 'OFFLINE', Shopify: 'OFFLINE' },
|
||||
createdAt: new Date('2025-12-15'),
|
||||
updatedAt: new Date('2026-03-18'),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
getMockData(): Product[] {
|
||||
getMockData(): ProductWithPlatform[] {
|
||||
return this.mockProducts;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/**
|
||||
* [MOCK-010] 自动选品数据源抽象层
|
||||
* 通过环境变量自动切换Mock/真实API
|
||||
* AI注意: 这是唯一入口,业务代码必须调用此层
|
||||
*
|
||||
* AI注意: 这是唯一入口,业务代码必须调用此<EFBFBD><EFBFBD>? *
|
||||
* @module services/productSelectionDataSource
|
||||
* @author AI-Frontend-33
|
||||
* @created 2026-03-20
|
||||
@@ -512,10 +511,10 @@ class MockProductSelectionDataSource {
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 导出数据源实例 (环境变量控制)
|
||||
// 导出数据源实<EFBFBD><EFBFBD>?(环境变量控制)
|
||||
// ============================================
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
|
||||
export const productSelectionDataSource = useMock
|
||||
? new MockProductSelectionDataSource()
|
||||
|
||||
@@ -100,5 +100,5 @@ class ApiReportsDataSource implements IReportsDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const reportsDataSource: IReportsDataSource = useMock ? new MockReportsDataSource() : new ApiReportsDataSource();
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/**
|
||||
* [MOCK] 退货管理数据源
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启用
|
||||
*/
|
||||
* 仅在USE_MOCK=true时启<EFBFBD><EFBFBD>? */
|
||||
|
||||
export interface SKUData {
|
||||
id: string;
|
||||
@@ -229,7 +228,7 @@ class ApiReturnDataSource implements IReturnDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const returnDataSource: IReturnDataSource = useMock
|
||||
? new MockReturnDataSource()
|
||||
: new ApiReturnDataSource();
|
||||
|
||||
173
dashboard/src/services/serviceManagerDataSource.ts
Normal file
173
dashboard/src/services/serviceManagerDataSource.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
import { http } from './http';
|
||||
|
||||
export interface ServiceInfo {
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
initialized: boolean;
|
||||
error?: string;
|
||||
config?: {
|
||||
name: string;
|
||||
category: string;
|
||||
description: string;
|
||||
enabled: boolean;
|
||||
memoryImpact: 'low' | 'medium' | 'high';
|
||||
};
|
||||
}
|
||||
|
||||
export interface ServiceStats {
|
||||
total: number;
|
||||
enabled: number;
|
||||
disabled: number;
|
||||
initialized: number;
|
||||
failed: number;
|
||||
byCategory: Record<string, { total: number; enabled: number; initialized: number }>;
|
||||
byMemoryImpact: {
|
||||
low: { total: number; enabled: number };
|
||||
medium: { total: number; enabled: number };
|
||||
high: { total: number; enabled: number };
|
||||
};
|
||||
}
|
||||
|
||||
export interface ServicePreset {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
serviceCount: number;
|
||||
}
|
||||
|
||||
export interface ServiceManagerDataSource {
|
||||
list(): Promise<{ services: ServiceInfo[]; groupedServices: Record<string, ServiceInfo[]>; stats: ServiceStats }>;
|
||||
getStats(): Promise<ServiceStats>;
|
||||
toggle(name: string, enabled: boolean): Promise<{ name: string; enabled: boolean; message: string }>;
|
||||
batchToggle(services: string[], enabled: boolean): Promise<{ results: Array<{ name: string; success: boolean; error?: string }>; message: string }>;
|
||||
applyPreset(preset: string): Promise<{ preset: string; enabledCount: number; message: string }>;
|
||||
getPresets(): Promise<ServicePreset[]>;
|
||||
getCategories(): Promise<Record<string, { label: string; color: string }>>;
|
||||
}
|
||||
|
||||
class ServiceManagerApiDataSource implements ServiceManagerDataSource {
|
||||
async list() {
|
||||
const response = await http.get('/api/service-manager/list');
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
async getStats() {
|
||||
const response = await http.get('/api/service-manager/stats');
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
async toggle(name: string, enabled: boolean) {
|
||||
const response = await http.post(`/api/service-manager/toggle/${name}`, { enabled });
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
async batchToggle(services: string[], enabled: boolean) {
|
||||
const response = await http.post('/api/service-manager/batch-toggle', { services, enabled });
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
async applyPreset(preset: string) {
|
||||
const response = await http.post(`/api/service-manager/apply-preset/${preset}`);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
async getPresets() {
|
||||
const response = await http.get('/api/service-manager/presets');
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
async getCategories() {
|
||||
const response = await http.get('/api/service-manager/categories');
|
||||
return response.data.data;
|
||||
}
|
||||
}
|
||||
|
||||
class ServiceManagerMockDataSource implements ServiceManagerDataSource {
|
||||
private mockServices: ServiceInfo[] = [
|
||||
{ name: 'AuthService', enabled: true, initialized: true, config: { name: 'AuthService', category: 'CORE', description: '用户认证服务', enabled: true, memoryImpact: 'low' } },
|
||||
{ name: 'TurboGateway', enabled: true, initialized: true, config: { name: 'TurboGateway', category: 'CORE', description: 'API网关与缓存', enabled: true, memoryImpact: 'medium' } },
|
||||
{ name: 'ProductService', enabled: true, initialized: true, config: { name: 'ProductService', category: 'BUSINESS', description: '商品管理服务', enabled: true, memoryImpact: 'medium' } },
|
||||
{ name: 'MemoryWatchdog', enabled: false, initialized: false, config: { name: 'MemoryWatchdog', category: 'TELEMETRY', description: '内存监控服务', enabled: false, memoryImpact: 'medium' } },
|
||||
{ name: 'FederatedNode', enabled: false, initialized: false, config: { name: 'FederatedNode', category: 'NETWORK', description: '联邦节点服务', enabled: false, memoryImpact: 'high' } },
|
||||
{ name: 'P2PConnection', enabled: false, initialized: false, config: { name: 'P2PConnection', category: 'NETWORK', description: 'P2P连接服务', enabled: false, memoryImpact: 'high' } },
|
||||
{ name: 'AgentSwarm', enabled: false, initialized: false, config: { name: 'AgentSwarm', category: 'AI', description: 'Agent集群服务', enabled: false, memoryImpact: 'high' } },
|
||||
{ name: 'ChatBot', enabled: false, initialized: false, config: { name: 'ChatBot', category: 'AI', description: 'AI聊天机器人', enabled: false, memoryImpact: 'high' } },
|
||||
];
|
||||
|
||||
async list() {
|
||||
const groupedServices = this.mockServices.reduce((acc, service) => {
|
||||
const category = service.config?.category || 'BUSINESS';
|
||||
if (!acc[category]) acc[category] = [];
|
||||
acc[category].push(service);
|
||||
return acc;
|
||||
}, {} as Record<string, ServiceInfo[]>);
|
||||
|
||||
return {
|
||||
services: this.mockServices,
|
||||
groupedServices,
|
||||
stats: {
|
||||
total: this.mockServices.length,
|
||||
enabled: this.mockServices.filter(s => s.enabled).length,
|
||||
disabled: this.mockServices.filter(s => !s.enabled).length,
|
||||
initialized: this.mockServices.filter(s => s.initialized).length,
|
||||
failed: this.mockServices.filter(s => s.error).length,
|
||||
byCategory: {},
|
||||
byMemoryImpact: { low: { total: 0, enabled: 0 }, medium: { total: 0, enabled: 0 }, high: { total: 0, enabled: 0 } },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async getStats(): Promise<ServiceStats> {
|
||||
return {
|
||||
total: this.mockServices.length,
|
||||
enabled: this.mockServices.filter(s => s.enabled).length,
|
||||
disabled: this.mockServices.filter(s => !s.enabled).length,
|
||||
initialized: this.mockServices.filter(s => s.initialized).length,
|
||||
failed: this.mockServices.filter(s => s.error).length,
|
||||
byCategory: {},
|
||||
byMemoryImpact: { low: { total: 0, enabled: 0 }, medium: { total: 0, enabled: 0 }, high: { total: 0, enabled: 0 } },
|
||||
};
|
||||
}
|
||||
|
||||
async toggle(name: string, enabled: boolean) {
|
||||
const service = this.mockServices.find(s => s.name === name);
|
||||
if (service) service.enabled = enabled;
|
||||
return { name, enabled, message: `服务 "${name}" 已${enabled ? '启用' : '禁用'}` };
|
||||
}
|
||||
|
||||
async batchToggle(services: string[], enabled: boolean) {
|
||||
return {
|
||||
results: services.map(name => ({ name, success: true })),
|
||||
message: `已${enabled ? '启用' : '禁用'} ${services.length} 个服务`,
|
||||
};
|
||||
}
|
||||
|
||||
async applyPreset(preset: string) {
|
||||
return { preset, enabledCount: 5, message: `已应用 "${preset}" 预设` };
|
||||
}
|
||||
|
||||
async getPresets(): Promise<ServicePreset[]> {
|
||||
return [
|
||||
{ id: 'minimal', name: '最小模式', description: '仅启动核心服务', serviceCount: 10 },
|
||||
{ id: 'standard', name: '标准模式', description: '启动默认启用的服务', serviceCount: 20 },
|
||||
{ id: 'development', name: '开发模式', description: '核心+业务服务', serviceCount: 30 },
|
||||
{ id: 'full', name: '完整模式', description: '启动所有服务', serviceCount: 100 },
|
||||
];
|
||||
}
|
||||
|
||||
async getCategories() {
|
||||
return {
|
||||
CORE: { label: '核心服务', color: 'blue' },
|
||||
BUSINESS: { label: '业务服务', color: 'green' },
|
||||
TELEMETRY: { label: '遥测服务', color: 'orange' },
|
||||
SECURITY: { label: '安全服务', color: 'red' },
|
||||
NETWORK: { label: '网络服务', color: 'purple' },
|
||||
AI: { label: 'AI服务', color: 'cyan' },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const serviceManagerDataSource: ServiceManagerDataSource = useMock
|
||||
? new ServiceManagerMockDataSource()
|
||||
: new ServiceManagerApiDataSource();
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* [MOCK-SETTINGS] Settings模块DataSource
|
||||
* AI注意: 这是DataSource抽象层实现
|
||||
* 仅在USE_MOCK=true时启用Mock
|
||||
* AI注意: 这是DataSource抽象层实<EFBFBD>? * 仅在USE_MOCK=true时启用Mock
|
||||
*/
|
||||
|
||||
export interface CostTemplate {
|
||||
@@ -146,7 +145,37 @@ export interface User {
|
||||
parentId?: string;
|
||||
createdAt: string;
|
||||
lastLoginAt?: string;
|
||||
lastLogin?: string; // 与 lastLoginAt 同义
|
||||
lastLogin?: string;
|
||||
}
|
||||
|
||||
export interface ConfigCategory {
|
||||
id: string;
|
||||
name: string;
|
||||
key: string;
|
||||
description?: string;
|
||||
parentId?: string | null;
|
||||
order: number;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface ConfigChangeLog {
|
||||
id: string;
|
||||
configKey: string;
|
||||
oldValue: string;
|
||||
newValue: string;
|
||||
changedBy: string;
|
||||
changedAt: string;
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
export interface Tenant {
|
||||
id: string;
|
||||
name: string;
|
||||
key: string;
|
||||
status: 'active' | 'inactive';
|
||||
plan: string;
|
||||
createdAt: string;
|
||||
expiresAt?: string;
|
||||
}
|
||||
|
||||
export interface ISettingsDataSource {
|
||||
@@ -422,5 +451,5 @@ class ApiSettingsDataSource implements ISettingsDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const settingsDataSource: ISettingsDataSource = useMock ? new MockSettingsDataSource() : new ApiSettingsDataSource();
|
||||
|
||||
@@ -149,7 +149,6 @@ class MockShopReportDataSource implements IShopReportDataSource {
|
||||
{ id: 'shop-005', name: '店铺E', platform: 'TIKTOK' },
|
||||
];
|
||||
|
||||
// 生成模拟报表
|
||||
const reportTypes: ReportType[] = ['SALES', 'PROFIT', 'ORDER'];
|
||||
const timeDimensions: TimeDimension[] = ['DAILY', 'WEEKLY', 'MONTHLY'];
|
||||
|
||||
@@ -323,7 +322,7 @@ class MockShopReportDataSource implements IShopReportDataSource {
|
||||
}
|
||||
|
||||
class ApiShopReportDataSource implements IShopReportDataSource {
|
||||
private baseUrl = '/api/shop-reports';
|
||||
private baseUrl = '/api/v1/shop-reports';
|
||||
|
||||
async generateReport(params: {
|
||||
tenant_id: string;
|
||||
@@ -386,7 +385,7 @@ class ApiShopReportDataSource implements IShopReportDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const shopReportDataSource: IShopReportDataSource = useMock
|
||||
? new MockShopReportDataSource()
|
||||
: new ApiShopReportDataSource();
|
||||
|
||||
@@ -289,7 +289,7 @@ class ApiStoreCreationDataSource implements IStoreCreationDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const storeCreationDataSource: IStoreCreationDataSource = useMock
|
||||
? new MockStoreCreationDataSource()
|
||||
: new ApiStoreCreationDataSource();
|
||||
|
||||
@@ -100,5 +100,5 @@ class ApiSuppliersDataSource implements ISuppliersDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const suppliersDataSource: ISuppliersDataSource = useMock ? new MockSuppliersDataSource() : new ApiSuppliersDataSource();
|
||||
|
||||
@@ -86,5 +86,5 @@ class ApiTaskCenterDataSource implements ITaskCenterDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const taskCenterDataSource: ITaskCenterDataSource = useMock ? new MockTaskCenterDataSource() : new ApiTaskCenterDataSource();
|
||||
|
||||
@@ -147,7 +147,7 @@ class ApiUnifiedFulfillmentDataSource implements IUnifiedFulfillmentDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const unifiedFulfillmentDataSource: IUnifiedFulfillmentDataSource = useMock
|
||||
? new MockUnifiedFulfillmentDataSource()
|
||||
: new ApiUnifiedFulfillmentDataSource();
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/**
|
||||
* [MOCK] 用户资产数据源
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启用
|
||||
*/
|
||||
* [MOCK] 用户资产数据<EFBFBD><EFBFBD>? * AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启<E697B6><E590AF>? */
|
||||
|
||||
export type MemberLevel = 'BRONZE' | 'SILVER' | 'GOLD' | 'PLATINUM' | 'DIAMOND';
|
||||
|
||||
@@ -12,15 +10,15 @@ export interface UserAsset {
|
||||
userId: string;
|
||||
userName: string;
|
||||
email: string;
|
||||
userEmail?: string; // 与 email 同义
|
||||
userEmail?: string; // <EFBFBD><EFBFBD>?email 同义
|
||||
memberLevel: MemberLevel;
|
||||
points: number;
|
||||
memberScore?: number; // 与 points 同义
|
||||
memberScore?: number; // <EFBFBD><EFBFBD>?points 同义
|
||||
totalSpent: number;
|
||||
availableBalance: number;
|
||||
availablePoints?: number; // 与 availableBalance 同义
|
||||
availablePoints?: number; // <EFBFBD><EFBFBD>?availableBalance 同义
|
||||
frozenBalance: number;
|
||||
frozenPoints?: number; // 与 frozenBalance 同义
|
||||
frozenPoints?: number; // <EFBFBD><EFBFBD>?frozenBalance 同义
|
||||
cashbackBalance?: number;
|
||||
couponCount?: number;
|
||||
totalOrders: number;
|
||||
@@ -63,13 +61,13 @@ export interface PointsRecord {
|
||||
source: string;
|
||||
description: string;
|
||||
createdAt: string;
|
||||
// 额外字段,用于 PointsManage 页面
|
||||
// 额外字段,用<EFBFBD><EFBFBD>?PointsManage 页面
|
||||
tenantId?: string;
|
||||
shopId?: string;
|
||||
traceId?: string;
|
||||
businessType?: 'TOC' | 'TOB';
|
||||
points?: number; // 与 amount 同义
|
||||
sourceType?: string; // 与 source 同义
|
||||
points?: number; // <EFBFBD><EFBFBD>?amount 同义
|
||||
sourceType?: string; // <EFBFBD><EFBFBD>?source 同义
|
||||
status?: 'PENDING' | 'CONFIRMED' | 'FROZEN' | 'EXPIRED' | 'CANCELLED';
|
||||
expiredAt?: string;
|
||||
sourceId?: string;
|
||||
@@ -295,7 +293,7 @@ class ApiUserAssetDataSource implements IUserAssetDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
const useMock = process.env.NODE_ENV === 'development' || process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const userAssetDataSource: IUserAssetDataSource = useMock
|
||||
? new MockUserAssetDataSource()
|
||||
: new ApiUserAssetDataSource();
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
import { User } from '../types/user';
|
||||
|
||||
// 用户数据接口
|
||||
export interface UserDataSource {
|
||||
list(params?: {
|
||||
page?: number;
|
||||
@@ -39,7 +38,6 @@ export interface UserDataSource {
|
||||
} | null>;
|
||||
}
|
||||
|
||||
// 用户DataSource实现
|
||||
export class UserDataSourceImpl implements UserDataSource {
|
||||
async list(params?: {
|
||||
page?: number;
|
||||
@@ -47,8 +45,6 @@ export class UserDataSourceImpl implements UserDataSource {
|
||||
role?: string;
|
||||
status?: string;
|
||||
}): Promise<{ data: User[]; total: number }> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockUsers: User[] = [
|
||||
{
|
||||
id: 'cust_1',
|
||||
@@ -105,8 +101,6 @@ export class UserDataSourceImpl implements UserDataSource {
|
||||
}
|
||||
|
||||
async get(id: string): Promise<User | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockUsers: User[] = [
|
||||
{
|
||||
id: 'cust_1',
|
||||
@@ -145,8 +139,6 @@ export class UserDataSourceImpl implements UserDataSource {
|
||||
}
|
||||
|
||||
async create(user: Omit<User, 'id' | 'createdAt' | 'updatedAt'>): Promise<User> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const newUser: User = {
|
||||
...user,
|
||||
id: `user_${Date.now()}`,
|
||||
@@ -158,8 +150,6 @@ export class UserDataSourceImpl implements UserDataSource {
|
||||
}
|
||||
|
||||
async update(id: string, user: Partial<User>): Promise<User | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const existingUser = await this.get(id);
|
||||
if (!existingUser) {
|
||||
return null;
|
||||
@@ -175,14 +165,10 @@ export class UserDataSourceImpl implements UserDataSource {
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<boolean> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
return true;
|
||||
}
|
||||
|
||||
async updateStatus(id: string, status: string): Promise<User | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const existingUser = await this.get(id);
|
||||
if (!existingUser) {
|
||||
return null;
|
||||
@@ -198,8 +184,6 @@ export class UserDataSourceImpl implements UserDataSource {
|
||||
}
|
||||
|
||||
async search(keyword: string): Promise<User[]> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockUsers: User[] = [
|
||||
{
|
||||
id: 'cust_1',
|
||||
@@ -241,8 +225,6 @@ export class UserDataSourceImpl implements UserDataSource {
|
||||
}
|
||||
|
||||
async getByRole(role: string): Promise<User[]> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockUsers: User[] = [
|
||||
{
|
||||
id: 'cust_1',
|
||||
@@ -287,8 +269,6 @@ export class UserDataSourceImpl implements UserDataSource {
|
||||
lastLogin: Date;
|
||||
};
|
||||
} | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const user = await this.get(userId);
|
||||
if (!user) {
|
||||
return null;
|
||||
@@ -307,5 +287,4 @@ export class UserDataSourceImpl implements UserDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
// 导出DataSource实例
|
||||
export const userDataSource = new UserDataSourceImpl();
|
||||
|
||||
Reference in New Issue
Block a user