From 25c444e83d1ca6250861a345932e989ce6edec52 Mon Sep 17 00:00:00 2001 From: MT-Mint <798521692@qq.com> Date: Thu, 9 Apr 2026 10:23:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20skill=E6=B8=85=E7=A9=BA=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E3=80=82=E5=9B=A0=E4=B8=BA=E5=90=8E=E7=AB=AF=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E4=B8=8D=E6=94=AF=E6=8C=81=E5=8F=96=E6=B6=88=E9=80=89?= =?UTF-8?q?=E6=8B=A9skill=EF=BC=8C=E6=89=80=E4=BB=A5=E6=9A=82=E6=97=B6?= =?UTF-8?q?=E7=A6=81=E7=94=A8=E5=8F=96=E6=B6=88=E9=80=89=E6=8B=A9=E6=8C=89?= =?UTF-8?q?=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workspace/iframe-test-panel.tsx | 17 +++++ .../src/components/workspace/input-box.tsx | 9 ++- frontend/src/hooks/use-iframe-skill.ts | 75 +++++++++++++++---- 3 files changed, 82 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/workspace/iframe-test-panel.tsx b/frontend/src/components/workspace/iframe-test-panel.tsx index e8d8c327..23623b78 100644 --- a/frontend/src/components/workspace/iframe-test-panel.tsx +++ b/frontend/src/components/workspace/iframe-test-panel.tsx @@ -313,6 +313,23 @@ export function IframeTestPanel() { > 📦 模拟 selectedSkills(数组 message) + + */} ))} diff --git a/frontend/src/hooks/use-iframe-skill.ts b/frontend/src/hooks/use-iframe-skill.ts index 33c5329b..10561850 100644 --- a/frontend/src/hooks/use-iframe-skill.ts +++ b/frontend/src/hooks/use-iframe-skill.ts @@ -60,7 +60,7 @@ interface UseIframeSkillReturn { title: string; }) => Promise; openSkillDialog: () => void; - clearSkill: () => void; + clearSkill: (skillId?: string) => void; } interface UseIframeSkillOptions { @@ -149,12 +149,18 @@ export function useIframeSkill( // 4. 选择变化时同步到 localStorage useEffect(() => { + const threadKey = getThreadStorageKey(threadId); if (selectedSkills.length === 0) { + // 空数组也要同步到存储,避免 UI 状态与缓存不一致 + window.localStorage.removeItem(STORAGE_KEYS.latest); + if (threadKey) { + window.localStorage.removeItem(threadKey); + } return; } + const payload = JSON.stringify(selectedSkills); window.localStorage.setItem(STORAGE_KEYS.latest, payload); - const threadKey = getThreadStorageKey(threadId); if (threadKey) { window.localStorage.setItem(threadKey, payload); } @@ -262,19 +268,58 @@ export function useIframeSkill( }, []); // 清除选中并发送空 selectedSkills 数组给主页 - const clearSkill = useCallback(() => { - setSelectedSkill(null); - setSelectedSkills([]); - window.localStorage.removeItem(STORAGE_KEYS.latest); - const threadKey = getThreadStorageKey(threadId); - if (threadKey) { - window.localStorage.removeItem(threadKey); - } - // 发送空数组给主页,通知取消选择 - const message = { type: POST_MESSAGE_TYPES.SELECT_SKILLS, selectedSkills: [] }; - console.log("[useIframeSkill] clearSkill, sending selectedSkills=[]:", message); - sendToParent(message); - }, [threadId]); + const clearSkill = useCallback( + (skillId?: string) => { + const removeAll = !skillId; + const nextSelectedSkills = removeAll + ? [] + : selectedSkills.filter((skill) => skill.skill_id !== String(skillId)); + + setSelectedSkills(nextSelectedSkills); + setSelectedSkill(nextSelectedSkills[0] ?? null); + + // 同步 latest 缓存:仅删除对应 skill(或全部清空) + const latestSkills = parseStoredSkills( + window.localStorage.getItem(STORAGE_KEYS.latest), + ); + const nextLatestSkills = removeAll + ? [] + : latestSkills.filter((skill) => skill.skill_id !== String(skillId)); + if (nextLatestSkills.length > 0) { + window.localStorage.setItem( + STORAGE_KEYS.latest, + JSON.stringify(nextLatestSkills), + ); + } else { + window.localStorage.removeItem(STORAGE_KEYS.latest); + } + + // 同步线程缓存:保存剩余数组,空则删除 key + const threadKey = getThreadStorageKey(threadId); + if (threadKey) { + if (nextSelectedSkills.length > 0) { + window.localStorage.setItem( + threadKey, + JSON.stringify(nextSelectedSkills), + ); + } else { + window.localStorage.removeItem(threadKey); + } + } + + // 通知宿主页当前剩余技能 + const message = { + type: POST_MESSAGE_TYPES.SELECT_SKILLS, + selectedSkills: nextSelectedSkills.map((skill) => ({ + id: skill.skill_id, + name: skill.title, + })), + } as const; + console.log("[useIframeSkill] clearSkill:", message); + sendToParent(message); + }, + [selectedSkills, threadId], + ); return { selectedSkill,