chore(frontend): 删除未使用 selected skill 监听 hook
This commit is contained in:
parent
4bd2591a03
commit
105802d6c1
|
|
@ -1,152 +0,0 @@
|
||||||
import { useSearchParams } from "next/navigation";
|
|
||||||
import { useEffect, useCallback, useState, useRef } from "react";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
|
|
||||||
import { bootstrapRemoteSkill } from "@/core/skills/api";
|
|
||||||
|
|
||||||
/** 宿主页发过来的 selectedSkill 消息结构 */
|
|
||||||
interface SelectedSkillMessage {
|
|
||||||
type: "selectedSkill";
|
|
||||||
id: number | string;
|
|
||||||
title: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 技能基础数据 */
|
|
||||||
interface SkillData {
|
|
||||||
skill_id: string;
|
|
||||||
title: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 错误信息状态 */
|
|
||||||
interface SkillError {
|
|
||||||
title: string;
|
|
||||||
message: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UseSelectedSkillListenerOptions {
|
|
||||||
/** 当前会话 thread_id,用于调用 bootstrapRemoteSkill */
|
|
||||||
threadId: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UseSelectedSkillListenerReturn {
|
|
||||||
/** 当前选中的技能数据(用于 UI 展示,如 Badge) */
|
|
||||||
selectedSkill: SkillData | null;
|
|
||||||
/** 当前错误信息,不为 null 时展示 DevDialog */
|
|
||||||
skillError: SkillError | null;
|
|
||||||
/** 清除错误信息(关闭 DevDialog 时调用) */
|
|
||||||
clearSkillError: () => void;
|
|
||||||
/** 是否正在加载(处理 skill 中) */
|
|
||||||
isBootstrapping: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 监听宿主页通过 postMessage 发送的 selectedSkill 消息或 URL 中的 skill 参数,
|
|
||||||
* 收到后自动调用 bootstrapRemoteSkill 接口:
|
|
||||||
* - 成功:使用 toast 提示
|
|
||||||
* - 失败:返回 skillError 供 DevDialog 显示
|
|
||||||
*/
|
|
||||||
export function useSelectedSkillListener({
|
|
||||||
threadId,
|
|
||||||
}: UseSelectedSkillListenerOptions): UseSelectedSkillListenerReturn {
|
|
||||||
const searchParams = useSearchParams();
|
|
||||||
const [selectedSkill, setSelectedSkill] = useState<SkillData | null>(null);
|
|
||||||
const [skillError, setSkillError] = useState<SkillError | null>(null);
|
|
||||||
const [isBootstrapping, setIsBootstrapping] = useState(false);
|
|
||||||
|
|
||||||
const isFirstLoadRef = useRef(false);
|
|
||||||
const skillBootstrappedKeyRef = useRef<string | null>(null);
|
|
||||||
|
|
||||||
const performBootstrap = useCallback(
|
|
||||||
async (id: number | string, title: string) => {
|
|
||||||
if (!threadId) return;
|
|
||||||
|
|
||||||
const languageTypeRaw =
|
|
||||||
searchParams.get("languageType")?.trim() ??
|
|
||||||
searchParams.get("language_type")?.trim();
|
|
||||||
const languageType = languageTypeRaw ? Number(languageTypeRaw) : 0;
|
|
||||||
|
|
||||||
const initKey = `${threadId}:${id}:${languageType}`;
|
|
||||||
if (skillBootstrappedKeyRef.current === initKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
`[useSelectedSkillListener] 开始初始化技能: ${title} (${id})`,
|
|
||||||
);
|
|
||||||
setIsBootstrapping(true);
|
|
||||||
toast.loading(`正在加载技能「${title}」...`, { id: "skill-bootstrap" });
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await bootstrapRemoteSkill({
|
|
||||||
thread_id: threadId,
|
|
||||||
content_id: Number(id),
|
|
||||||
language_type: languageType,
|
|
||||||
target_dir: "/mnt/user-data/uploads/skill",
|
|
||||||
clear_target: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
toast.dismiss("skill-bootstrap");
|
|
||||||
|
|
||||||
if (result.success) {
|
|
||||||
skillBootstrappedKeyRef.current = initKey;
|
|
||||||
toast.success(`技能「${title}」加载成功`, {
|
|
||||||
description:
|
|
||||||
result.message || `已创建 ${result.created_files} 个文件`,
|
|
||||||
duration: 4000,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setSkillError({
|
|
||||||
title: `技能「${title}」加载失败`,
|
|
||||||
message: result.message || "未知错误",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
toast.dismiss("skill-bootstrap");
|
|
||||||
const message = err instanceof Error ? err.message : "网络请求失败";
|
|
||||||
setSkillError({ title: `技能「${title}」加载出错`, message });
|
|
||||||
} finally {
|
|
||||||
setIsBootstrapping(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[threadId, searchParams],
|
|
||||||
);
|
|
||||||
|
|
||||||
// 1. URL 初始化集成
|
|
||||||
useEffect(() => {
|
|
||||||
if (!threadId || isFirstLoadRef.current) return;
|
|
||||||
|
|
||||||
const skillIdFromQuery = searchParams.get("skill_id");
|
|
||||||
const titleFromQuery = searchParams.get("title");
|
|
||||||
if (skillIdFromQuery && titleFromQuery) {
|
|
||||||
isFirstLoadRef.current = true;
|
|
||||||
setSelectedSkill({ skill_id: skillIdFromQuery, title: titleFromQuery });
|
|
||||||
void performBootstrap(skillIdFromQuery, titleFromQuery);
|
|
||||||
}
|
|
||||||
}, [threadId, searchParams, performBootstrap]);
|
|
||||||
|
|
||||||
const handleMessage = useCallback(
|
|
||||||
(event: MessageEvent) => {
|
|
||||||
const data = event.data as SelectedSkillMessage;
|
|
||||||
if (data?.type !== "selectedSkill") return;
|
|
||||||
|
|
||||||
const { id, title } = data;
|
|
||||||
console.log(
|
|
||||||
"[useSelectedSkillListener] 收到 postMessage selectedSkill:",
|
|
||||||
data,
|
|
||||||
);
|
|
||||||
|
|
||||||
setSelectedSkill({ skill_id: String(id), title });
|
|
||||||
void performBootstrap(id, title);
|
|
||||||
},
|
|
||||||
[performBootstrap],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
window.addEventListener("message", handleMessage);
|
|
||||||
return () => window.removeEventListener("message", handleMessage);
|
|
||||||
}, [handleMessage]);
|
|
||||||
|
|
||||||
const clearSkillError = useCallback(() => setSkillError(null), []);
|
|
||||||
|
|
||||||
return { selectedSkill, skillError, clearSkillError, isBootstrapping };
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue