97 lines
3.3 KiB
TypeScript
97 lines
3.3 KiB
TypeScript
import { useRouter, useSearchParams } from "next/navigation";
|
|
import { useState, useEffect, useCallback, useRef } from "react";
|
|
|
|
import {
|
|
POST_MESSAGE_TYPES,
|
|
RECEIVE_MESSAGE_TYPES,
|
|
isSelectedSkillMessage,
|
|
sendToParent,
|
|
} from "@/core/iframe-messages";
|
|
|
|
// Skill 数据类型
|
|
interface SkillData {
|
|
skill_id: string;
|
|
title: string;
|
|
}
|
|
|
|
// Hook 返回类型
|
|
interface UseIframeSkillReturn {
|
|
selectedSkill: SkillData | null;
|
|
sendSelectSkill: (skill_id: string) => void;
|
|
openSkillDialog: () => void;
|
|
clearSkill: () => void;
|
|
}
|
|
|
|
export function useIframeSkill(): UseIframeSkillReturn {
|
|
const router = useRouter();
|
|
const searchParams = useSearchParams();
|
|
const skillIdFromQuery = searchParams.get("skill_id");
|
|
const titleFromQuery = searchParams.get("title");
|
|
const threadIdFromQuery = searchParams.get("thread_id");
|
|
const showReuseWelcomeFromQuery = searchParams.get("show_reuse_welcome");
|
|
const lastThreadIdRef = useRef<string | null>(null);
|
|
|
|
const [selectedSkill, setSelectedSkill] = useState<SkillData | null>(null);
|
|
|
|
// 1. 监听 query 参数变化
|
|
useEffect(() => {
|
|
if (skillIdFromQuery && titleFromQuery) {
|
|
setSelectedSkill({ skill_id: skillIdFromQuery, title: titleFromQuery });
|
|
}
|
|
}, [skillIdFromQuery, titleFromQuery]);
|
|
|
|
// 0. 监听 query 中 show_reuse_welcome=false 且带 thread_id 时跳转到 thread 页面
|
|
useEffect(() => {
|
|
if (!threadIdFromQuery) return;
|
|
if (showReuseWelcomeFromQuery !== "false") return;
|
|
if (lastThreadIdRef.current === threadIdFromQuery) return;
|
|
lastThreadIdRef.current = threadIdFromQuery;
|
|
router.replace(`/workspace/chats/${threadIdFromQuery}`);
|
|
}, [router, showReuseWelcomeFromQuery, threadIdFromQuery]);
|
|
|
|
// 2. 监听宿主页 postMessage
|
|
useEffect(() => {
|
|
const handleMessage = (event: MessageEvent) => {
|
|
if (event.data?.type !== RECEIVE_MESSAGE_TYPES.SELECTED_SKILL) {
|
|
return;
|
|
}
|
|
if (!isSelectedSkillMessage(event.data)) {
|
|
console.warn("[useIframeSkill] 忽略非法 selectedSkill 消息", event.data);
|
|
return;
|
|
}
|
|
const { id, title } = event.data;
|
|
setSelectedSkill({ skill_id: String(id), title });
|
|
};
|
|
window.addEventListener("message", handleMessage);
|
|
return () => window.removeEventListener("message", handleMessage);
|
|
}, []);
|
|
|
|
// 发送选择预定义 skill
|
|
const sendSelectSkill = useCallback((skill_id: string) => {
|
|
const message = { type: POST_MESSAGE_TYPES.SELECT_SKILL, skill_id };
|
|
console.log("[useIframeSkill] sendSelectSkill:", message);
|
|
sendToParent(message);
|
|
}, []);
|
|
|
|
// 打开 skill 选择对话框
|
|
const openSkillDialog = useCallback(() => {
|
|
const message = {
|
|
type: POST_MESSAGE_TYPES.OPEN_SKILL_DIALOG,
|
|
openSkillDialog: true,
|
|
} as const;
|
|
console.log("[useIframeSkill] openSkillDialog:", message);
|
|
sendToParent(message);
|
|
}, []);
|
|
|
|
// 清除选中并发送 skill_id=0 给主页
|
|
const clearSkill = useCallback(() => {
|
|
setSelectedSkill(null);
|
|
// 发送 skill_id=0 给主页,通知取消选择
|
|
const message = { type: POST_MESSAGE_TYPES.SELECT_SKILL, skill_id: "0" };
|
|
console.log("[useIframeSkill] clearSkill, sending skill_id=0:", message);
|
|
sendToParent(message);
|
|
}, []);
|
|
|
|
return { selectedSkill, sendSelectSkill, openSkillDialog, clearSkill };
|
|
}
|