295 lines
7.8 KiB
TypeScript
295 lines
7.8 KiB
TypeScript
|
|
/**
|
|||
|
|
* [MOCK-INSTANCE] 实例购买模块DataSource
|
|||
|
|
* AI注意: 这是Mock实现,不是真实业务逻辑
|
|||
|
|
* 仅在USE_MOCK=true时启用 */
|
|||
|
|
|
|||
|
|
import { BaseDataSource, DataSourceFactory } from './baseDataSource';
|
|||
|
|
|
|||
|
|
// ============================================// 类型定义// ============================================
|
|||
|
|
|
|||
|
|
export interface InstanceType {
|
|||
|
|
id: string;
|
|||
|
|
name: string;
|
|||
|
|
description: string;
|
|||
|
|
icon: string;
|
|||
|
|
defaultConfig: InstanceConfig;
|
|||
|
|
priceMultiplier: number;
|
|||
|
|
recommended: boolean;
|
|||
|
|
popular: boolean;
|
|||
|
|
category: 'mini' | 'small' | 'medium' | 'large' | 'xlarge';
|
|||
|
|
cupSize: '小杯' | '中杯' | '大杯' | '超大杯' | '特大杯';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export interface InstanceConfig {
|
|||
|
|
cpu: number; // CPU核心数
|
|||
|
|
memory: number; // 内存(GB)
|
|||
|
|
storage: number; // 存储(GB)
|
|||
|
|
bandwidth: number; // 带宽(Mbps)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export interface InstancePrice {
|
|||
|
|
monthly: number;
|
|||
|
|
yearly: number;
|
|||
|
|
discount: number;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export interface InstanceOrder {
|
|||
|
|
id: string;
|
|||
|
|
instanceType: string;
|
|||
|
|
config: InstanceConfig;
|
|||
|
|
billingCycle: 'monthly' | 'yearly';
|
|||
|
|
price: number;
|
|||
|
|
status: 'pending' | 'active' | 'cancelled';
|
|||
|
|
createdAt: string;
|
|||
|
|
expiresAt: string;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export interface InstanceDataSource {
|
|||
|
|
getInstanceTypes(): Promise<InstanceType[]>;
|
|||
|
|
getInstanceConfigOptions(): Promise<{
|
|||
|
|
cpuOptions: number[];
|
|||
|
|
memoryOptions: number[];
|
|||
|
|
storageOptions: number[];
|
|||
|
|
bandwidthOptions: number[];
|
|||
|
|
}>;
|
|||
|
|
calculatePrice(instanceType: string, config: InstanceConfig, billingCycle: 'monthly' | 'yearly'): Promise<InstancePrice>;
|
|||
|
|
createOrder(instanceType: string, config: InstanceConfig, billingCycle: 'monthly' | 'yearly', paymentMethod: string): Promise<InstanceOrder>;
|
|||
|
|
getOrders(): Promise<InstanceOrder[]>;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ============================================// Mock数据// ============================================
|
|||
|
|
|
|||
|
|
const MOCK_INSTANCE_TYPES: InstanceType[] = [
|
|||
|
|
{
|
|||
|
|
id: 'mini',
|
|||
|
|
name: '小杯实例',
|
|||
|
|
description: '适合个人开发者和小型应用',
|
|||
|
|
icon: '🖥️',
|
|||
|
|
defaultConfig: {
|
|||
|
|
cpu: 1,
|
|||
|
|
memory: 2,
|
|||
|
|
storage: 50,
|
|||
|
|
bandwidth: 10
|
|||
|
|
},
|
|||
|
|
priceMultiplier: 1,
|
|||
|
|
recommended: false,
|
|||
|
|
popular: false,
|
|||
|
|
category: 'mini',
|
|||
|
|
cupSize: '小杯'
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 'small',
|
|||
|
|
name: '中杯实例',
|
|||
|
|
description: '适合小型团队和中等应用',
|
|||
|
|
icon: '💻',
|
|||
|
|
defaultConfig: {
|
|||
|
|
cpu: 2,
|
|||
|
|
memory: 4,
|
|||
|
|
storage: 100,
|
|||
|
|
bandwidth: 20
|
|||
|
|
},
|
|||
|
|
priceMultiplier: 2,
|
|||
|
|
recommended: false,
|
|||
|
|
popular: false,
|
|||
|
|
category: 'small',
|
|||
|
|
cupSize: '中杯'
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 'medium',
|
|||
|
|
name: '大杯实例',
|
|||
|
|
description: '适合中型团队和大型应用',
|
|||
|
|
icon: '🚀',
|
|||
|
|
defaultConfig: {
|
|||
|
|
cpu: 4,
|
|||
|
|
memory: 8,
|
|||
|
|
storage: 200,
|
|||
|
|
bandwidth: 50
|
|||
|
|
},
|
|||
|
|
priceMultiplier: 4,
|
|||
|
|
recommended: true,
|
|||
|
|
popular: true,
|
|||
|
|
category: 'medium',
|
|||
|
|
cupSize: '大杯'
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 'large',
|
|||
|
|
name: '超大杯实例',
|
|||
|
|
description: '适合大型企业和高负载应用',
|
|||
|
|
icon: '🛰️',
|
|||
|
|
defaultConfig: {
|
|||
|
|
cpu: 8,
|
|||
|
|
memory: 16,
|
|||
|
|
storage: 400,
|
|||
|
|
bandwidth: 100
|
|||
|
|
},
|
|||
|
|
priceMultiplier: 8,
|
|||
|
|
recommended: false,
|
|||
|
|
popular: false,
|
|||
|
|
category: 'large',
|
|||
|
|
cupSize: '超大杯'
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 'xlarge',
|
|||
|
|
name: '特大杯实例',
|
|||
|
|
description: '适合超大型企业和极高负载应用',
|
|||
|
|
icon: '⚡',
|
|||
|
|
defaultConfig: {
|
|||
|
|
cpu: 16,
|
|||
|
|
memory: 32,
|
|||
|
|
storage: 800,
|
|||
|
|
bandwidth: 200
|
|||
|
|
},
|
|||
|
|
priceMultiplier: 16,
|
|||
|
|
recommended: false,
|
|||
|
|
popular: false,
|
|||
|
|
category: 'xlarge',
|
|||
|
|
cupSize: '特大杯'
|
|||
|
|
}
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
const MOCK_CONFIG_OPTIONS = {
|
|||
|
|
cpuOptions: [1, 2, 4, 8, 16],
|
|||
|
|
memoryOptions: [2, 4, 8, 16, 32, 64],
|
|||
|
|
storageOptions: [50, 100, 200, 400, 800, 1600],
|
|||
|
|
bandwidthOptions: [10, 20, 50, 100, 200]
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const BASE_PRICE = 99; // 小杯实例月付价格
|
|||
|
|
|
|||
|
|
// ============================================// 数据源实现// ============================================
|
|||
|
|
|
|||
|
|
export class InstanceDataSourceImpl extends BaseDataSource implements InstanceDataSource {
|
|||
|
|
async getInstanceTypes(): Promise<InstanceType[]> {
|
|||
|
|
try {
|
|||
|
|
await this.delay(300);
|
|||
|
|
return MOCK_INSTANCE_TYPES;
|
|||
|
|
} catch (error) {
|
|||
|
|
return this.handleError(error, []);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async getInstanceConfigOptions(): Promise<{
|
|||
|
|
cpuOptions: number[];
|
|||
|
|
memoryOptions: number[];
|
|||
|
|
storageOptions: number[];
|
|||
|
|
bandwidthOptions: number[];
|
|||
|
|
}> {
|
|||
|
|
try {
|
|||
|
|
await this.delay(200);
|
|||
|
|
return MOCK_CONFIG_OPTIONS;
|
|||
|
|
} catch (error) {
|
|||
|
|
return this.handleError(error, {
|
|||
|
|
cpuOptions: [],
|
|||
|
|
memoryOptions: [],
|
|||
|
|
storageOptions: [],
|
|||
|
|
bandwidthOptions: []
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async calculatePrice(instanceType: string, config: InstanceConfig, billingCycle: 'monthly' | 'yearly'): Promise<InstancePrice> {
|
|||
|
|
try {
|
|||
|
|
await this.delay(100);
|
|||
|
|
const instance = MOCK_INSTANCE_TYPES.find(t => t.id === instanceType);
|
|||
|
|
if (!instance) {
|
|||
|
|
throw new Error('Instance type not found');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 计算价格因子
|
|||
|
|
const cpuFactor = config.cpu / instance.defaultConfig.cpu;
|
|||
|
|
const memoryFactor = config.memory / instance.defaultConfig.memory;
|
|||
|
|
const storageFactor = config.storage / instance.defaultConfig.storage;
|
|||
|
|
const bandwidthFactor = config.bandwidth / instance.defaultConfig.bandwidth;
|
|||
|
|
|
|||
|
|
// 综合因子
|
|||
|
|
const totalFactor = (cpuFactor + memoryFactor + storageFactor + bandwidthFactor) / 4;
|
|||
|
|
const baseMonthlyPrice = BASE_PRICE * instance.priceMultiplier * totalFactor;
|
|||
|
|
|
|||
|
|
// 计算月付和年付价格
|
|||
|
|
const monthlyPrice = Math.round(baseMonthlyPrice);
|
|||
|
|
const yearlyPrice = Math.round(monthlyPrice * 12 * 0.8); // 年付8折
|
|||
|
|
const discount = 20; // 年付折扣百分比
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
monthly: monthlyPrice,
|
|||
|
|
yearly: yearlyPrice,
|
|||
|
|
discount
|
|||
|
|
};
|
|||
|
|
} catch (error) {
|
|||
|
|
return this.handleError(error, {
|
|||
|
|
monthly: 0,
|
|||
|
|
yearly: 0,
|
|||
|
|
discount: 0
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async createOrder(instanceType: string, config: InstanceConfig, billingCycle: 'monthly' | 'yearly', paymentMethod: string): Promise<InstanceOrder> {
|
|||
|
|
try {
|
|||
|
|
await this.delay(500);
|
|||
|
|
const price = await this.calculatePrice(instanceType, config, billingCycle);
|
|||
|
|
const orderId = `order-${Date.now()}`;
|
|||
|
|
const now = new Date();
|
|||
|
|
const expiresAt = new Date(now);
|
|||
|
|
expiresAt.setMonth(expiresAt.getMonth() + (billingCycle === 'yearly' ? 12 : 1));
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
id: orderId,
|
|||
|
|
instanceType,
|
|||
|
|
config,
|
|||
|
|
billingCycle,
|
|||
|
|
price: billingCycle === 'yearly' ? price.yearly : price.monthly,
|
|||
|
|
status: 'pending',
|
|||
|
|
createdAt: now.toISOString(),
|
|||
|
|
expiresAt: expiresAt.toISOString()
|
|||
|
|
};
|
|||
|
|
} catch (error) {
|
|||
|
|
throw error;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async getOrders(): Promise<InstanceOrder[]> {
|
|||
|
|
try {
|
|||
|
|
await this.delay(300);
|
|||
|
|
// 返回模拟订单数据
|
|||
|
|
return [
|
|||
|
|
{
|
|||
|
|
id: 'order-1',
|
|||
|
|
instanceType: 'medium',
|
|||
|
|
config: {
|
|||
|
|
cpu: 4,
|
|||
|
|
memory: 8,
|
|||
|
|
storage: 200,
|
|||
|
|
bandwidth: 50
|
|||
|
|
},
|
|||
|
|
billingCycle: 'monthly',
|
|||
|
|
price: 399,
|
|||
|
|
status: 'active',
|
|||
|
|
createdAt: '2026-02-01T00:00:00Z',
|
|||
|
|
expiresAt: '2026-03-01T00:00:00Z'
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 'order-2',
|
|||
|
|
instanceType: 'large',
|
|||
|
|
config: {
|
|||
|
|
cpu: 8,
|
|||
|
|
memory: 16,
|
|||
|
|
storage: 400,
|
|||
|
|
bandwidth: 100
|
|||
|
|
},
|
|||
|
|
billingCycle: 'yearly',
|
|||
|
|
price: 6384,
|
|||
|
|
status: 'active',
|
|||
|
|
createdAt: '2025-12-01T00:00:00Z',
|
|||
|
|
expiresAt: '2026-12-01T00:00:00Z'
|
|||
|
|
}
|
|||
|
|
];
|
|||
|
|
} catch (error) {
|
|||
|
|
return this.handleError(error, []);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export const instanceDataSource = new InstanceDataSourceImpl();
|
|||
|
|
DataSourceFactory.register('instance', instanceDataSource);
|