背景:A4 需要字典三层合并、配置单一来源与阈值同源。\n改动:新增 catalog 模块(类型/条目/三层合并/编码不可改/快照工具);platform 新增 SystemConfigService/Controller、NamingService 与配置版本历史;roles/users/customers/customer-fields 改为读 system_configs 上限。\n影响面:新增 13 个 REST 端点与 4 个模块注入;system_configs 写入走事务/乐观锁/版本历史;OpenAPI 快照更新。\n回滚:回滚本提交并恢复 shared 契约;新增表可保留。\n验证:api typecheck/build;单测 137;集成 58;OpenAPI diff 无破坏性变更。
79 lines
2.4 KiB
TypeScript
79 lines
2.4 KiB
TypeScript
/**
|
||
* 系统配置 Prisma 行 -> 共享 DTO 映射(A4-BE-02)。
|
||
*
|
||
* 元数据(标签 / 说明 / 影响面 / 类型 / 上下限 / 是否公开)唯一来源是
|
||
* `SYSTEM_CONFIG_DEFINITIONS`;`system_configs` 只提供当前值与版本。
|
||
* DB 缺行时用定义默认值 + version 1 兜底,不写库。
|
||
*/
|
||
import {
|
||
type SystemConfig,
|
||
type SystemConfigChange,
|
||
type SystemConfigDefinition,
|
||
type SystemConfigValue,
|
||
systemConfigValueType,
|
||
} from '@lingxi/shared';
|
||
import type { Prisma } from '@prisma/client';
|
||
import type {
|
||
SystemConfig as PrismaSystemConfig,
|
||
SystemConfigVersion as PrismaSystemConfigVersion,
|
||
} from '@prisma/client';
|
||
|
||
/** 从未落库的配置:用 epoch 表示「未更新过」,避免伪造读取时间 */
|
||
const NEVER_UPDATED_AT = new Date(0).toISOString();
|
||
|
||
/** Prisma JsonB 只应存原始值;异常结构回退配置默认值,避免脏数据打穿前端 schema */
|
||
export function normalizeConfigValue(
|
||
raw: Prisma.JsonValue | undefined,
|
||
fallback: SystemConfigValue,
|
||
): SystemConfigValue {
|
||
if (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') {
|
||
return raw;
|
||
}
|
||
return fallback;
|
||
}
|
||
|
||
export function toSystemConfig(
|
||
definition: SystemConfigDefinition,
|
||
row: PrismaSystemConfig | undefined,
|
||
updatedByName?: string | null,
|
||
): SystemConfig {
|
||
return {
|
||
key: definition.key,
|
||
group: definition.group,
|
||
label: definition.label,
|
||
description: definition.description,
|
||
impact: definition.impact,
|
||
type: definition.type,
|
||
value: normalizeConfigValue(row?.configValue, definition.defaultValue),
|
||
valueType: systemConfigValueType(definition),
|
||
unit: definition.unit ?? null,
|
||
version: row?.version ?? 1,
|
||
updatedAt: row === undefined ? NEVER_UPDATED_AT : row.updatedAt.toISOString(),
|
||
updatedBy: updatedByName ?? row?.updatedBy ?? null,
|
||
editable: definition.editable,
|
||
isPublic: definition.public,
|
||
min: definition.min ?? null,
|
||
max: definition.max ?? null,
|
||
step: definition.step ?? null,
|
||
maxLength: definition.maxLength ?? null,
|
||
};
|
||
}
|
||
|
||
export function toSystemConfigChange(
|
||
row: PrismaSystemConfigVersion,
|
||
label: string,
|
||
operator: string | null,
|
||
): SystemConfigChange {
|
||
return {
|
||
key: row.configKey,
|
||
label,
|
||
version: row.version,
|
||
oldValue: row.oldValue,
|
||
newValue: row.newValue,
|
||
reason: row.reason,
|
||
operator,
|
||
changedAt: row.changedAt.toISOString(),
|
||
result: '已生效',
|
||
};
|
||
}
|