feat: 如果请求失败不要写入localstorage,且不要展示失败的skill

This commit is contained in:
肖应宇 2026-04-09 11:52:38 +08:00
parent 576a3c37b6
commit 9d82ed43d9
1 changed files with 50 additions and 1 deletions

View File

@ -49,6 +49,12 @@ function parseStoredSkills(raw: string | null): SkillData[] {
}
}
function removeSkillsByIdsFromList(skills: SkillData[], skillIds: string[]): SkillData[] {
if (skillIds.length === 0) return skills;
const idSet = new Set(skillIds.map((id) => String(id)));
return skills.filter((skill) => !idSet.has(String(skill.skill_id)));
}
// Hook 返回类型
interface UseIframeSkillReturn {
selectedSkill: SkillData | null;
@ -81,6 +87,45 @@ export function useIframeSkill(
const [selectedSkills, setSelectedSkills] = useState<SkillData[]>([]);
const [isBootstrapping, setIsBootstrapping] = useState(false);
const removeFailedSkills = useCallback(
(skillIds: string[]) => {
if (skillIds.length === 0) return;
// 1) 回滚内存状态:移除失败 skill避免展示错误 tag
setSelectedSkills((prev) => {
const next = removeSkillsByIdsFromList(prev, skillIds);
setSelectedSkill(next[0] ?? null);
return next;
});
// 2) 回滚 localStoragelatest + thread
const latestSkills = parseStoredSkills(
window.localStorage.getItem(STORAGE_KEYS.latest),
);
const nextLatestSkills = removeSkillsByIdsFromList(latestSkills, skillIds);
if (nextLatestSkills.length > 0) {
window.localStorage.setItem(
STORAGE_KEYS.latest,
JSON.stringify(nextLatestSkills),
);
} else {
window.localStorage.removeItem(STORAGE_KEYS.latest);
}
const threadKey = getThreadStorageKey(threadId);
if (threadKey) {
const threadSkills = parseStoredSkills(window.localStorage.getItem(threadKey));
const nextThreadSkills = removeSkillsByIdsFromList(threadSkills, skillIds);
if (nextThreadSkills.length > 0) {
window.localStorage.setItem(threadKey, JSON.stringify(nextThreadSkills));
} else {
window.localStorage.removeItem(threadKey);
}
}
},
[threadId],
);
// 1. 监听 query 参数变化(临时禁用)
// TODO: 当前 skill 仅通过 iframe postMessage 传递,暂不从 URL 读取 skill_id/title。
// useEffect(() => {
@ -223,6 +268,8 @@ export function useIframeSkill(
toast.dismiss("suggest-skill-bootstrap");
if (!result.success) {
const failedIds = selectedSkills.map((item) => String(item.id).trim());
removeFailedSkills(failedIds);
toast.error(`技能「${title}」加载失败`, {
description: result.message || "未知错误",
});
@ -243,6 +290,8 @@ export function useIframeSkill(
return true;
} catch (error) {
const failedIds = selectedSkills.map((item) => String(item.id).trim());
removeFailedSkills(failedIds);
toast.dismiss("suggest-skill-bootstrap");
const message =
error instanceof Error ? error.message : "网络请求失败";
@ -254,7 +303,7 @@ export function useIframeSkill(
setIsBootstrapping(false);
}
},
[searchParams, sendSelectSkill, threadId],
[removeFailedSkills, searchParams, sendSelectSkill, threadId],
);
// 打开 skill 选择对话框