Files
makemd/server/src/services/ConfigService.ts
wurenzhi 5cfd0c4c89 feat: 实现服务层核心功能与文档更新
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)
2026-03-18 12:35:52 +08:00

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
};
}
}