背景:用户选定方案 A 主从分栏,A4 需要落地字典与配置页。\n改动:新增 /system/dicts、/system/dicts/:type、/system/settings;主从类型列表 + 三层合并 + 树/词表切换 + 条目/类型弹层;6 组配置 + 命名预览 + 阈值二次确认 + 变更记录;客户字段上限改读 effective config;路由/样式/OpenAPI 类型同步。\n影响面:管理中心新增两个菜单页;客户页上限显示改为配置读取(fallback 共享常量)。\n回滚:回滚本提交并恢复 AppLayout / routes / main 样式 import。\n验证:web typecheck/lint/build;单测 154;浏览器自检 1440/1024 无溢出。
109 lines
3.4 KiB
TypeScript
109 lines
3.4 KiB
TypeScript
/**
|
|
* A4 系统配置查询与写操作。
|
|
*
|
|
* R-26:阈值 / 上限只存系统配置一处。`useEffectiveConfigsQuery` 供业务页读取前端上限,
|
|
* 读取失败或未登录时由调用方回退到 shared 常量(仅作展示兜底,后端仍做最终校验)。
|
|
*/
|
|
import {
|
|
CUSTOMER_BASE_FIELD_LIMIT,
|
|
CUSTOMER_GEN_FIELD_LIMIT,
|
|
type SystemConfig,
|
|
type SystemConfigChange,
|
|
type SystemConfigHistoryQuery,
|
|
type SystemConfigValue,
|
|
type UpdateSystemConfigsInput,
|
|
} from '@lingxi/shared';
|
|
import {
|
|
useMutation,
|
|
type UseMutationResult,
|
|
useQuery,
|
|
useQueryClient,
|
|
type UseQueryResult,
|
|
} from '@tanstack/react-query';
|
|
|
|
import {
|
|
fetchEffectiveSystemConfigs,
|
|
fetchSystemConfigHistory,
|
|
fetchSystemConfigs,
|
|
updateSystemConfigs,
|
|
} from '@/api/configs';
|
|
import { queryKeys } from '@/api/query-keys';
|
|
|
|
export function useSystemConfigsQuery(): UseQueryResult<{ items: SystemConfig[] }> {
|
|
return useQuery({
|
|
queryKey: queryKeys.systemConfigs,
|
|
queryFn: fetchSystemConfigs,
|
|
staleTime: 10_000,
|
|
});
|
|
}
|
|
|
|
/** 生效配置:key → value(仅登录可读,失败不阻塞业务页) */
|
|
export function useEffectiveConfigsQuery(): UseQueryResult<Record<string, SystemConfigValue>> {
|
|
return useQuery({
|
|
queryKey: queryKeys.systemConfigsEffective,
|
|
queryFn: fetchEffectiveSystemConfigs,
|
|
select: (data) => {
|
|
const values: Record<string, SystemConfigValue> = {};
|
|
for (const item of data.items) {
|
|
values[item.key] = item.value;
|
|
}
|
|
return values;
|
|
},
|
|
staleTime: 60_000,
|
|
retry: 1,
|
|
});
|
|
}
|
|
|
|
/** 读取单个数值型生效配置;缺失 / 非数字时回退 shared 常量 */
|
|
export function useEffectiveNumberConfig(key: string, fallback: number): number {
|
|
const effective = useEffectiveConfigsQuery();
|
|
const value = effective.data?.[key];
|
|
return typeof value === 'number' ? value : fallback;
|
|
}
|
|
|
|
export interface CustomerFieldLimits {
|
|
baseFieldLimit: number;
|
|
genFieldLimit: number;
|
|
}
|
|
|
|
/** 客户基础字段 / 进入生成字段上限(A3 客户页与表单校验共用,R-26) */
|
|
export function useCustomerFieldLimits(): CustomerFieldLimits {
|
|
const effective = useEffectiveConfigsQuery();
|
|
const base = effective.data?.['limit.customer.base_field'];
|
|
const gen = effective.data?.['limit.customer.gen_field'];
|
|
return {
|
|
baseFieldLimit: typeof base === 'number' ? base : CUSTOMER_BASE_FIELD_LIMIT,
|
|
genFieldLimit: typeof gen === 'number' ? gen : CUSTOMER_GEN_FIELD_LIMIT,
|
|
};
|
|
}
|
|
|
|
export function useSystemConfigHistoryQuery(
|
|
query: Partial<SystemConfigHistoryQuery> = {},
|
|
options: { enabled?: boolean } = {},
|
|
): UseQueryResult<{ items: SystemConfigChange[]; next_cursor: string | null }> {
|
|
return useQuery({
|
|
queryKey: queryKeys.systemConfigHistory(query),
|
|
queryFn: () => fetchSystemConfigHistory(query),
|
|
enabled: options.enabled ?? true,
|
|
staleTime: 5_000,
|
|
});
|
|
}
|
|
|
|
export function useUpdateSystemConfigsMutation(): UseMutationResult<
|
|
{ items: SystemConfig[] },
|
|
Error,
|
|
UpdateSystemConfigsInput
|
|
> {
|
|
const queryClient = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: updateSystemConfigs,
|
|
onSuccess: async () => {
|
|
await Promise.all([
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.systemConfigs }),
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.systemConfigsEffective }),
|
|
queryClient.invalidateQueries({ queryKey: ['system-configs', 'history'] }),
|
|
]);
|
|
},
|
|
});
|
|
}
|