refactor(ProductService): 修复createProduct方法和其他方法错误 fix(InventoryAgingService): 修复AGING_THRESHOLD_DAYS引用问题 fix(InventoryService): 修复predictSKUDemand方法 refactor(ChatBotController): 从tsoa风格改为Express风格 fix(CommandCenterController): 修复类型问题 fix(AdAutoService): 修复stock可能为undefined的问题 docs: 更新SERVICE_MAP、DOMAIN_MODEL等架构文档 chore: 启动前端服务(运行在http://localhost:8000)
124 lines
4.0 KiB
TypeScript
124 lines
4.0 KiB
TypeScript
import db from '../config/database';
|
|
import { RedisService } from '../utils/RedisService';
|
|
|
|
export interface AppConfig {
|
|
key: string;
|
|
value: any;
|
|
description?: string;
|
|
isEnabled: boolean;
|
|
version?: number;
|
|
tenantId?: string;
|
|
created_at?: Date;
|
|
updated_at?: Date;
|
|
}
|
|
|
|
export class ConfigService {
|
|
private static TABLE_NAME = 'cf_config';
|
|
private static HISTORY_TABLE = 'cf_config_history';
|
|
|
|
/**
|
|
* [CORE_DEV_06/16] 初始化配置表与历史表
|
|
*/
|
|
static async initTable() {
|
|
const exists = await db.schema.hasTable(this.TABLE_NAME);
|
|
if (!exists) {
|
|
await db.schema.createTable(this.TABLE_NAME, (table) => {
|
|
table.string('key').notNullable();
|
|
table.string('tenantId').defaultTo('SYSTEM').index();
|
|
table.json('value');
|
|
table.string('description');
|
|
table.boolean('isEnabled').defaultTo(true);
|
|
table.integer('version').defaultTo(1); // [CORE_DEV_16] 版本控制
|
|
table.timestamps(true, true);
|
|
table.primary(['key', 'tenantId']);
|
|
});
|
|
// ... (seed data remains same)
|
|
}
|
|
|
|
const historyExists = await db.schema.hasTable(this.HISTORY_TABLE);
|
|
if (!historyExists) {
|
|
await db.schema.createTable(this.HISTORY_TABLE, (table) => {
|
|
table.increments('id').primary();
|
|
table.string('key').notNullable();
|
|
table.string('tenantId').notNullable();
|
|
table.json('value');
|
|
table.integer('version').notNullable();
|
|
table.string('changeLog');
|
|
table.timestamp('created_at').defaultTo(db.fn.now());
|
|
table.index(['key', 'tenantId']);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* [CORE_DEV_16] 更新配置并保存历史版本
|
|
*/
|
|
static async updateConfig(key: string, data: Partial<AppConfig> & { changeLog?: string }, tenantId: string = 'SYSTEM') {
|
|
const current = await this.getConfig(key, tenantId);
|
|
const newVersion = (current?.version || 0) + 1;
|
|
|
|
const updateData: any = { ...data, version: newVersion };
|
|
delete updateData.changeLog;
|
|
|
|
if (data.value) updateData.value = JSON.stringify(data.value);
|
|
|
|
await db.transaction(async (trx) => {
|
|
// 1. 更新主表
|
|
await trx(this.TABLE_NAME).where({ key, tenantId }).update(updateData);
|
|
|
|
// 2. 插入历史记录
|
|
await trx(this.HISTORY_TABLE).insert({
|
|
key,
|
|
tenantId,
|
|
value: updateData.value || JSON.stringify(current?.value),
|
|
version: newVersion,
|
|
changeLog: data.changeLog || 'Automated update'
|
|
});
|
|
});
|
|
|
|
// [CORE_DEV_12] 分布式配置热更新通知
|
|
await RedisService.publishConfigChange(tenantId, key, data.value || data.isEnabled);
|
|
}
|
|
|
|
/**
|
|
* [CORE_DEV_16] 配置版本回滚
|
|
*/
|
|
static async rollbackConfig(key: string, version: number, tenantId: string = 'SYSTEM') {
|
|
const history = await db(this.HISTORY_TABLE).where({ key, tenantId, version }).first();
|
|
if (!history) throw new Error(`Version ${version} not found for config ${key}`);
|
|
|
|
await this.updateConfig(key, {
|
|
value: typeof history.value === 'string' ? JSON.parse(history.value) : history.value,
|
|
changeLog: `Rollback to version ${version}`
|
|
}, tenantId);
|
|
}
|
|
|
|
static async isFeatureEnabled(key: string, tenantId: string = 'SYSTEM'): Promise<boolean> {
|
|
const config = await this.getConfig(key, tenantId);
|
|
return config ? config.isEnabled : false;
|
|
}
|
|
|
|
/**
|
|
* 获取所有配置
|
|
*/
|
|
static async getAllConfigs(tenantId: string = 'SYSTEM'): Promise<AppConfig[]> {
|
|
const configs = await db(this.TABLE_NAME).where({ tenantId });
|
|
return configs.map(config => ({
|
|
...config,
|
|
value: typeof config.value === 'string' ? JSON.parse(config.value) : config.value
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* 获取单个配置
|
|
*/
|
|
static async getConfig(key: string, tenantId: string = 'SYSTEM'): Promise<AppConfig | null> {
|
|
const config = await db(this.TABLE_NAME).where({ key, tenantId }).first();
|
|
if (!config) return null;
|
|
return {
|
|
...config,
|
|
value: typeof config.value === 'string' ? JSON.parse(config.value) : config.value
|
|
};
|
|
}
|
|
}
|