You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
91 lines
2.8 KiB
91 lines
2.8 KiB
/**
|
|
* 评分权重设置 hook:拉取维度与预设模板,提供权重调整、模板应用与保存能力。
|
|
* 业务规则(权重总和校验)放在 api 层,本层只负责本地编辑态与远端数据的合并。
|
|
*/
|
|
import { useCallback, useMemo, useState } from 'react';
|
|
import { fetchWeightSettings, saveWeightSettings } from '../api';
|
|
import type { WeightDimension, WeightSettings } from '../types';
|
|
import { useAsyncData } from './useAsyncData';
|
|
|
|
export interface WeightSettingsState {
|
|
/** 远端原始设置(含预设模板) */
|
|
settings: WeightSettings | null;
|
|
/** 当前生效的维度列表(本地编辑态优先,未编辑时回退远端) */
|
|
dimensions: WeightDimension[];
|
|
/** 各维度权重总和,正常应为 100 */
|
|
totalWeight: number;
|
|
loading: boolean;
|
|
error: Error | null;
|
|
saving: boolean;
|
|
refresh: () => void;
|
|
/** 调整单个维度权重 */
|
|
updateWeight: (id: string, weight: number) => void;
|
|
/** 应用预设模板(按维度名称匹配权重) */
|
|
applyTemplate: (templateId: string) => void;
|
|
/** 保存当前维度列表 */
|
|
save: () => Promise<void>;
|
|
}
|
|
|
|
export function useWeightSettings(): WeightSettingsState {
|
|
const fetcher = useCallback(() => fetchWeightSettings(), []);
|
|
const { data, loading, error, refresh } = useAsyncData<WeightSettings>(fetcher);
|
|
|
|
const [localDimensions, setLocalDimensions] = useState<WeightDimension[] | null>(null);
|
|
const [saving, setSaving] = useState(false);
|
|
|
|
const remoteDimensions = data?.dimensions ?? [];
|
|
const dimensions = localDimensions ?? remoteDimensions;
|
|
|
|
const totalWeight = useMemo(
|
|
() => dimensions.reduce((sum, item) => sum + item.weight, 0),
|
|
[dimensions],
|
|
);
|
|
|
|
const updateWeight = useCallback(
|
|
(id: string, weight: number) => {
|
|
setLocalDimensions((prev) => {
|
|
const base = prev ?? remoteDimensions;
|
|
return base.map((item) => (item.id === id ? { ...item, weight } : item));
|
|
});
|
|
},
|
|
[remoteDimensions],
|
|
);
|
|
|
|
const applyTemplate = useCallback(
|
|
(templateId: string) => {
|
|
const template = data?.templates.find((item) => item.id === templateId);
|
|
if (!template) return;
|
|
setLocalDimensions((prev) => {
|
|
const base = prev ?? remoteDimensions;
|
|
return base.map((item) => ({
|
|
...item,
|
|
weight: template.weights[item.name] ?? item.weight,
|
|
}));
|
|
});
|
|
},
|
|
[data, remoteDimensions],
|
|
);
|
|
|
|
const save = useCallback(async () => {
|
|
setSaving(true);
|
|
try {
|
|
const saved = await saveWeightSettings(dimensions);
|
|
setLocalDimensions(saved);
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
}, [dimensions]);
|
|
|
|
return {
|
|
settings: data ?? null,
|
|
dimensions,
|
|
totalWeight,
|
|
loading,
|
|
error,
|
|
saving,
|
|
refresh,
|
|
updateWeight,
|
|
applyTemplate,
|
|
save,
|
|
};
|
|
}
|
|
|