148 lines
4.1 KiB
TypeScript
148 lines
4.1 KiB
TypeScript
/**
|
||
* 优化建议页面数据获取 Hook
|
||
*
|
||
* 封装建议列表的 SWR 请求 + 重新生成/更新状态的 mutation,替代手动 useState + useEffect 模式。
|
||
* - 建议列表:依赖 brandId + 筛选条件
|
||
* - 重新生成:mutation
|
||
* - 更新状态:mutation
|
||
*/
|
||
|
||
import { useCallback } from "react";
|
||
import { useApi, useApiMutation } from "./use-api";
|
||
import { fetchWithAuth } from "@/lib/api/client";
|
||
import type { SWRConfiguration } from "swr";
|
||
import type { SuggestionListResponse, SuggestionStatus } from "@/types/suggestion";
|
||
|
||
export interface SuggestionsFilters {
|
||
type?: string;
|
||
priority?: string;
|
||
status?: string;
|
||
}
|
||
|
||
export interface UseSuggestionsDataOptions {
|
||
brandId?: string;
|
||
filters?: SuggestionsFilters;
|
||
/** SWR 配置(用于测试时禁用重试等) */
|
||
swrOptions?: SWRConfiguration;
|
||
}
|
||
|
||
export interface UseSuggestionsDataReturn {
|
||
/** 建议列表 */
|
||
suggestions: SuggestionListResponse["suggestions"] | undefined;
|
||
/** 是否正在加载 */
|
||
isLoading: boolean;
|
||
/** 错误信息 */
|
||
error: Error | undefined;
|
||
/** 刷新建议列表 */
|
||
refresh: () => void;
|
||
/** 重新生成建议 */
|
||
regenerate: () => Promise<SuggestionListResponse | null>;
|
||
/** 是否正在重新生成 */
|
||
isRegenerating: boolean;
|
||
/** 重新生成错误 */
|
||
regenerateError: Error | undefined;
|
||
/** 更新建议状态 */
|
||
updateStatus: (suggestionId: string, newStatus: string) => Promise<void>;
|
||
/** 是否正在更新状态 */
|
||
isUpdatingStatus: boolean;
|
||
}
|
||
|
||
function buildSuggestionsUrl(brandId: string, filters?: SuggestionsFilters): string | null {
|
||
if (!brandId) return null;
|
||
|
||
const params = new URLSearchParams();
|
||
if (filters?.type && filters.type !== "all") params.set("type", filters.type);
|
||
if (filters?.priority && filters.priority !== "all") params.set("priority", filters.priority);
|
||
if (filters?.status && filters.status !== "all") params.set("status", filters.status);
|
||
|
||
const qs = params.toString();
|
||
return `/api/v1/brands/${brandId}/suggestions${qs ? `?${qs}` : ""}`;
|
||
}
|
||
|
||
export function useSuggestionsData(
|
||
options?: UseSuggestionsDataOptions
|
||
): UseSuggestionsDataReturn {
|
||
const brandId = options?.brandId ?? "";
|
||
const filters = options?.filters;
|
||
const swrOptions = options?.swrOptions;
|
||
|
||
// 建议列表
|
||
const suggestionsUrl = buildSuggestionsUrl(brandId, filters);
|
||
const {
|
||
data: suggestionsResponse,
|
||
isLoading,
|
||
error,
|
||
refresh,
|
||
mutate,
|
||
} = useApi<SuggestionListResponse>(suggestionsUrl, swrOptions);
|
||
|
||
const suggestions = suggestionsResponse?.suggestions;
|
||
|
||
// 重新生成建议(mutation)
|
||
const {
|
||
trigger: regenerateTrigger,
|
||
isMutating: isRegenerating,
|
||
error: regenerateError,
|
||
} = useApiMutation<SuggestionListResponse>(
|
||
brandId ? `/api/v1/brands/${brandId}/suggestions/regenerate` : "",
|
||
"POST"
|
||
);
|
||
|
||
const regenerate = useCallback(async (): Promise<SuggestionListResponse | null> => {
|
||
const result = await regenerateTrigger();
|
||
if (result) {
|
||
// 用新数据更新 SWR 缓存
|
||
mutate(result);
|
||
}
|
||
return result;
|
||
}, [regenerateTrigger, mutate]);
|
||
|
||
// 更新建议状态(mutation)
|
||
const {
|
||
isMutating: isUpdatingStatus,
|
||
} = useApiMutation(
|
||
brandId ? `/api/v1/brands/${brandId}/suggestions` : "",
|
||
"PUT"
|
||
);
|
||
|
||
const updateStatus = useCallback(
|
||
async (suggestionId: string, newStatus: string) => {
|
||
await fetchWithAuth(
|
||
`/api/v1/brands/${brandId}/suggestions/${suggestionId}/status`,
|
||
{
|
||
method: "PUT",
|
||
body: JSON.stringify({ status: newStatus }),
|
||
}
|
||
);
|
||
// 乐观更新:直接修改本地缓存
|
||
mutate(
|
||
(current) => {
|
||
if (!current) return current;
|
||
return {
|
||
...current,
|
||
suggestions: current.suggestions.map((s) =>
|
||
s.id === suggestionId
|
||
? { ...s, status: newStatus as SuggestionStatus }
|
||
: s
|
||
),
|
||
};
|
||
},
|
||
{ revalidate: false }
|
||
);
|
||
},
|
||
[brandId, mutate]
|
||
);
|
||
|
||
return {
|
||
suggestions,
|
||
isLoading,
|
||
error,
|
||
refresh,
|
||
regenerate,
|
||
isRegenerating,
|
||
regenerateError,
|
||
updateStatus,
|
||
isUpdatingStatus,
|
||
};
|
||
}
|