refactor(terminology): 统一术语标准并优化代码类型安全

- 将B2B统一为TOB术语
- 将状态值统一为大写格式
- 优化类型声明,避免使用any
- 将float类型替换为decimal以提高精度
- 新增术语标准化文档
- 优化路由结构和菜单分类
- 添加TypeORM实体类
- 增强加密模块安全性
- 重构前端路由结构
- 完善任务模板和验收标准
This commit is contained in:
2026-03-20 09:43:50 +08:00
parent eafa1bbe94
commit 48a78137c5
132 changed files with 13767 additions and 2140 deletions

View File

@@ -63,7 +63,16 @@ export class CoreEngineService {
* @returns 缓存键
*/
private generateCacheKey(request: any): string {
return `core-engine:${JSON.stringify(request)}`;
// 使用更高效的缓存键生成方法
const keyParts = [];
for (const [key, value] of Object.entries(request)) {
if (typeof value === 'object' && value !== null) {
keyParts.push(`${key}:${JSON.stringify(value)}`);
} else {
keyParts.push(`${key}:${value}`);
}
}
return `core-engine:${keyParts.sort().join('|')}`;
}
/**

View File

@@ -191,7 +191,7 @@ export class DeveloperPlatform {
}
const id = `apikey_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
const key = this.generateApiKey();
const key = (this as any).generateApiKey();
const expiresAt = new Date();
expiresAt.setDate(expiresAt.getDate() + expiresInDays);

View File

@@ -1,60 +1,62 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Store } from '../../entities/Store';
import { PlatformAdapterFactory } from './adapters/PlatformAdapterFactory';
import { IPlatformAdapter } from './adapters/IPlatformAdapter';
import { StoreBindingDto } from '../../api/dto/StoreBindingDto';
import { StoreStatus } from '../../types/enums/StoreStatus';
import { OperationAgentEvent } from '../../types/events/OperationAgentEvent';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { Logger } from '@nestjs/common';
import db from '../../config/database';
import { v4 as uuidv4 } from 'uuid';
const STORES_TABLE = 'cf_stores';
@Injectable()
export class OperationAgentService {
private readonly logger = new Logger(OperationAgentService.name);
private platformAdapterFactory: PlatformAdapterFactory;
constructor(
@InjectRepository(Store) private storeRepository: Repository<Store>,
private platformAdapterFactory: PlatformAdapterFactory,
private eventEmitter: EventEmitter2
) {}
constructor(platformAdapterFactory: PlatformAdapterFactory) {
this.platformAdapterFactory = platformAdapterFactory;
}
/**
* 绑定店铺
* @param dto 店铺绑定信息
* @returns 绑定结果
*/
async bindStore(dto: StoreBindingDto): Promise<Store> {
this.logger.log(`开始绑定店铺: ${dto.platform} - ${dto.platformShopId}`);
async bindStore(dto: StoreBindingDto): Promise<any> {
console.log(`开始绑定店铺: ${dto.platform} - ${dto.platformShopId}`);
// 检查店铺是否已存在
const existingStore = await this.storeRepository.findOne({
where: {
const existingStore = await db(STORES_TABLE)
.where({
merchantId: dto.merchantId,
platform: dto.platform,
platformShopId: dto.platformShopId
}
});
})
.first();
if (existingStore) {
this.logger.warn(`店铺已存在: ${dto.platform} - ${dto.platformShopId}`);
console.warn(`店铺已存在: ${dto.platform} - ${dto.platformShopId}`);
return existingStore;
}
// 创建新店铺记录
const store = this.storeRepository.create({
const storeId = uuidv4();
const now = new Date();
const store = {
id: storeId,
merchantId: dto.merchantId,
name: dto.name,
tenant_id: dto.merchantId, // 暂时使用merchantId作为tenant_id
shop_id: storeId,
platform: dto.platform,
name: dto.name,
store_name: dto.name,
description: dto.description || '',
platformShopId: dto.platformShopId,
description: dto.description,
status: StoreStatus.PENDING
});
status: 'PENDING',
created_at: now,
updated_at: now
};
try {
// 保存店铺记录
await this.storeRepository.save(store);
await db(STORES_TABLE).insert(store);
// 获取平台适配器
const adapter = this.platformAdapterFactory.createAdapter(dto.platform);
@@ -64,30 +66,33 @@ export class OperationAgentService {
// 同步店铺信息
const shopInfo = await adapter.getShopInfo();
store.name = shopInfo.name;
store.description = shopInfo.description;
// 更新店铺状态
store.status = StoreStatus.ACTIVE;
await this.storeRepository.save(store);
// 更新店铺信息
await db(STORES_TABLE)
.where({ id: storeId })
.update({
name: shopInfo.name,
store_name: shopInfo.name,
description: shopInfo.description,
status: 'ACTIVE',
updated_at: new Date()
});
// 触发店铺绑定成功事件
this.eventEmitter.emit(OperationAgentEvent.STORE_BOUND, store);
console.log(`店铺绑定成功: ${dto.platform} - ${dto.platformShopId}`);
this.logger.log(`店铺绑定成功: ${dto.platform} - ${dto.platformShopId}`);
return store;
} catch (error) {
this.logger.error(`店铺绑定失败: ${error.message}`, error.stack);
// 获取更新后的店铺信息
const updatedStore = await db(STORES_TABLE).where({ id: storeId }).first();
return updatedStore;
} catch (error: any) {
console.error(`店铺绑定失败: ${error.message}`, error.stack);
// 更新店铺状态为失败
store.status = StoreStatus.INACTIVE;
await this.storeRepository.save(store);
// 触发店铺绑定失败事件
this.eventEmitter.emit(OperationAgentEvent.STORE_BIND_FAILED, {
storeId: store.id,
error: error.message
});
await db(STORES_TABLE)
.where({ id: storeId })
.update({
status: 'INACTIVE',
updated_at: new Date()
});
throw error;
}
@@ -99,14 +104,14 @@ export class OperationAgentService {
* @returns 同步结果
*/
async syncProducts(storeId: string): Promise<{ success: boolean; count: number }> {
this.logger.log(`开始同步店铺商品: ${storeId}`);
console.log(`开始同步店铺商品: ${storeId}`);
const store = await this.storeRepository.findOneBy({ id: storeId });
const store = await db(STORES_TABLE).where({ id: storeId }).first();
if (!store) {
throw new Error('店铺不存在');
}
if (store.status !== StoreStatus.ACTIVE) {
if (store.status !== 'ACTIVE') {
throw new Error('店铺状态异常,无法同步商品');
}
@@ -115,29 +120,60 @@ export class OperationAgentService {
const products = await adapter.getProducts();
// 处理商品同步逻辑
// TODO: 实现商品同步到数据库
for (const product of products) {
// 检查商品是否已存在
const existingProduct = await db('cf_product')
.where({
platform: store.platform,
product_id: product.id
})
.first();
const now = new Date();
const productData = {
tenant_id: store.tenant_id,
shop_id: storeId,
platform: store.platform,
product_id: product.id,
title: product.name,
description: product.description,
category: product.categories && product.categories.length > 0 ? product.categories[0] : 'Other',
brand: 'Unknown',
price: product.price,
cost_price: 0,
stock: product.stock,
sku: product.sku,
attributes: JSON.stringify(product.attributes || {}),
images: JSON.stringify(product.images || []),
status: 'ACTIVE',
updated_by: 'system',
updated_at: now
};
if (existingProduct) {
// 更新现有商品
await db('cf_product')
.where({ id: existingProduct.id })
.update(productData);
} else {
// 创建新商品
await db('cf_product').insert({
...productData,
id: uuidv4(),
created_by: 'system',
created_at: now
});
}
}
this.logger.log(`商品同步完成: ${storeId}, 同步商品数: ${products.length}`);
// 触发商品同步成功事件
this.eventEmitter.emit(OperationAgentEvent.PRODUCTS_SYNCED, {
storeId,
count: products.length
});
console.log(`商品同步完成: ${storeId}, 同步商品数: ${products.length}`);
return {
success: true,
count: products.length
};
} catch (error) {
this.logger.error(`商品同步失败: ${error.message}`, error.stack);
// 触发商品同步失败事件
this.eventEmitter.emit(OperationAgentEvent.PRODUCTS_SYNC_FAILED, {
storeId,
error: error.message
});
} catch (error: any) {
console.error(`商品同步失败: ${error.message}`, error.stack);
throw error;
}
}
@@ -148,14 +184,14 @@ export class OperationAgentService {
* @returns 同步结果
*/
async syncOrders(storeId: string): Promise<{ success: boolean; count: number }> {
this.logger.log(`开始同步店铺订单: ${storeId}`);
console.log(`开始同步店铺订单: ${storeId}`);
const store = await this.storeRepository.findOneBy({ id: storeId });
const store = await db(STORES_TABLE).where({ id: storeId }).first();
if (!store) {
throw new Error('店铺不存在');
}
if (store.status !== StoreStatus.ACTIVE) {
if (store.status !== 'ACTIVE') {
throw new Error('店铺状态异常,无法同步订单');
}
@@ -164,29 +200,87 @@ export class OperationAgentService {
const orders = await adapter.getOrders();
// 处理订单同步逻辑
// TODO: 实现订单同步到数据库
for (const order of orders) {
// 检查订单是否已存在
const existingOrder = await db('cf_order')
.where({
platform: store.platform,
platform_order_id: order.id
})
.first();
const now = new Date();
const orderData = {
tenant_id: store.tenant_id,
shop_id: storeId,
platform: store.platform,
platform_order_id: order.id,
customer_id: order.customerId || uuidv4(),
customer_name: order.shippingAddress?.name || 'Unknown',
customer_email: 'unknown@example.com',
customer_phone: '000-000-0000',
shipping_address: JSON.stringify(order.shippingAddress || {}),
billing_address: JSON.stringify(order.shippingAddress || {}),
subtotal: order.totalAmount,
shipping_fee: 0,
tax: 0,
total: order.totalAmount,
currency: 'USD',
status: order.status || 'PENDING',
payment_method: order.paymentMethod || 'UNKNOWN',
tracking_number: '',
carrier: '',
estimated_delivery: null,
actual_delivery: null,
updated_by: 'system',
updated_at: now
};
if (existingOrder) {
// 更新现有订单
await db('cf_order')
.where({ id: existingOrder.id })
.update(orderData);
} else {
// 创建新订单
const orderId = uuidv4();
await db('cf_order').insert({
...orderData,
id: orderId,
created_by: 'system',
created_at: now
});
// 同步订单明细
if (order.items && order.items.length > 0) {
for (const item of order.items) {
await db('cf_order_item').insert({
id: uuidv4(),
order_id: orderId,
product_id: item.productId,
product_sku: item.productId,
product_name: 'Product',
quantity: item.quantity,
unit_price: item.price,
total_price: item.quantity * item.price,
created_by: 'system',
updated_by: 'system',
created_at: now,
updated_at: now
});
}
}
}
}
this.logger.log(`订单同步完成: ${storeId}, 同步订单数: ${orders.length}`);
// 触发订单同步成功事件
this.eventEmitter.emit(OperationAgentEvent.ORDERS_SYNCED, {
storeId,
count: orders.length
});
console.log(`订单同步完成: ${storeId}, 同步订单数: ${orders.length}`);
return {
success: true,
count: orders.length
};
} catch (error) {
this.logger.error(`订单同步失败: ${error.message}`, error.stack);
// 触发订单同步失败事件
this.eventEmitter.emit(OperationAgentEvent.ORDERS_SYNC_FAILED, {
storeId,
error: error.message
});
} catch (error: any) {
console.error(`订单同步失败: ${error.message}`, error.stack);
throw error;
}
}
@@ -199,14 +293,14 @@ export class OperationAgentService {
* @returns 更新结果
*/
async updateProductPrice(storeId: string, productId: string, price: number): Promise<boolean> {
this.logger.log(`开始更新商品价格: ${storeId} - ${productId} - ${price}`);
console.log(`开始更新商品价格: ${storeId} - ${productId} - ${price}`);
const store = await this.storeRepository.findOneBy({ id: storeId });
const store = await db(STORES_TABLE).where({ id: storeId }).first();
if (!store) {
throw new Error('店铺不存在');
}
if (store.status !== StoreStatus.ACTIVE) {
if (store.status !== 'ACTIVE') {
throw new Error('店铺状态异常,无法更新商品价格');
}
@@ -214,27 +308,11 @@ export class OperationAgentService {
const adapter = this.platformAdapterFactory.createAdapter(store.platform);
await adapter.updateProductPrice(productId, price);
this.logger.log(`商品价格更新成功: ${storeId} - ${productId} - ${price}`);
// 触发商品价格更新成功事件
this.eventEmitter.emit(OperationAgentEvent.PRODUCT_PRICE_UPDATED, {
storeId,
productId,
price
});
console.log(`商品价格更新成功: ${storeId} - ${productId} - ${price}`);
return true;
} catch (error) {
this.logger.error(`商品价格更新失败: ${error.message}`, error.stack);
// 触发商品价格更新失败事件
this.eventEmitter.emit(OperationAgentEvent.PRODUCT_PRICE_UPDATE_FAILED, {
storeId,
productId,
price,
error: error.message
});
} catch (error: any) {
console.error(`商品价格更新失败: ${error.message}`, error.stack);
throw error;
}
}
@@ -244,9 +322,9 @@ export class OperationAgentService {
* @param merchantId 商户ID
* @returns 店铺列表
*/
async getStores(merchantId: string): Promise<Store[]> {
this.logger.log(`获取商户店铺列表: ${merchantId}`);
return this.storeRepository.find({ where: { merchantId } });
async getStores(merchantId: string): Promise<any[]> {
console.log(`获取商户店铺列表: ${merchantId}`);
return db(STORES_TABLE).where({ merchantId });
}
/**
@@ -254,9 +332,9 @@ export class OperationAgentService {
* @param storeId 店铺ID
* @returns 店铺详情
*/
async getStore(storeId: string): Promise<Store> {
this.logger.log(`获取店铺详情: ${storeId}`);
const store = await this.storeRepository.findOneBy({ id: storeId });
async getStore(storeId: string): Promise<any> {
console.log(`获取店铺详情: ${storeId}`);
const store = await db(STORES_TABLE).where({ id: storeId }).first();
if (!store) {
throw new Error('店铺不存在');
}
@@ -268,22 +346,25 @@ export class OperationAgentService {
* @param storeId 店铺ID
* @returns 操作结果
*/
async deactivateStore(storeId: string): Promise<Store> {
this.logger.log(`停用店铺: ${storeId}`);
async deactivateStore(storeId: string): Promise<any> {
console.log(`停用店铺: ${storeId}`);
const store = await this.storeRepository.findOneBy({ id: storeId });
const store = await db(STORES_TABLE).where({ id: storeId }).first();
if (!store) {
throw new Error('店铺不存在');
}
store.status = StoreStatus.INACTIVE;
await this.storeRepository.save(store);
await db(STORES_TABLE)
.where({ id: storeId })
.update({
status: 'INACTIVE',
updated_at: new Date()
});
// 触发店铺停用事件
this.eventEmitter.emit(OperationAgentEvent.STORE_DEACTIVATED, store);
console.log(`店铺停用: ${storeId}`);
this.logger.log(`店铺已停用: ${storeId}`);
return store;
const updatedStore = await db(STORES_TABLE).where({ id: storeId }).first();
return updatedStore;
}
/**
@@ -291,21 +372,24 @@ export class OperationAgentService {
* @param storeId 店铺ID
* @returns 操作结果
*/
async reactivateStore(storeId: string): Promise<Store> {
this.logger.log(`重新激活店铺: ${storeId}`);
async reactivateStore(storeId: string): Promise<any> {
console.log(`重新激活店铺: ${storeId}`);
const store = await this.storeRepository.findOneBy({ id: storeId });
const store = await db(STORES_TABLE).where({ id: storeId }).first();
if (!store) {
throw new Error('店铺不存在');
}
store.status = StoreStatus.ACTIVE;
await this.storeRepository.save(store);
await db(STORES_TABLE)
.where({ id: storeId })
.update({
status: 'ACTIVE',
updated_at: new Date()
});
// 触发店铺激活事件
this.eventEmitter.emit(OperationAgentEvent.STORE_ACTIVATED, store);
console.log(`店铺已重新激活: ${storeId}`);
this.logger.log(`店铺已重新激活: ${storeId}`);
return store;
const updatedStore = await db(STORES_TABLE).where({ id: storeId }).first();
return updatedStore;
}
}

View File

@@ -318,8 +318,8 @@ export class LegacyTableInitializer {
table.string('shop_id', 64).notNullable();
table.string('product_id', 64).notNullable();
table.string('platform', 32).notNullable();
table.float('daily_budget').defaultTo(0);
table.float('cpa_limit').defaultTo(0);
table.decimal('daily_budget', 10, 2).defaultTo(0);
table.decimal('cpa_limit', 10, 2).defaultTo(0);
table.string('status', 16).defaultTo('ACTIVE');
table.timestamps(true, true);
table.index(['tenant_id', 'product_id']);