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,