refactor(frontend): 将复用欢迎态路由参数统一为 show_reuse_welcome

This commit is contained in:
肖应宇 2026-04-08 10:30:28 +08:00
parent d91e1ea999
commit 4e95838f1f
7 changed files with 40 additions and 35 deletions

View File

@ -63,7 +63,7 @@ export default function ChatPage() {
showWelcomeStyle, showWelcomeStyle,
} = useThreadChat(); } = useThreadChat();
// 新逻辑:历史渲染和新会话仅由路由 /chats/new 控制,不再读取 isnew/xclaw_used 参数。 // 新逻辑:历史渲染和新会话仅由路由 /chats/new 控制,不再读取 isnew/show_reuse_welcome 参数。
const shouldRenderHistory = !showWelcomeStyle; const shouldRenderHistory = !showWelcomeStyle;
const createNewSession = useMemo(() => isNewThread, [isNewThread]); const createNewSession = useMemo(() => isNewThread, [isNewThread]);
@ -485,8 +485,8 @@ export default function ChatPage() {
} }
setShowExitDialog(false); setShowExitDialog(false);
sendToParent({ sendToParent({
type: POST_MESSAGE_TYPES.XCLAW_USED, type: POST_MESSAGE_TYPES.SHOW_REUSE_WELCOME,
XClawUsed: false, showReuseWelcome: true,
}); });
resetNewSessionState(); resetNewSessionState();
// 始终复用 query 中的 thread_id。 // 始终复用 query 中的 thread_id。

View File

@ -9,6 +9,11 @@ export function useThreadChat() {
const params = useParams<{ thread_id: string }>(); const params = useParams<{ thread_id: string }>();
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const threadIdFromSearchParams = searchParams.get("thread_id")?.trim(); const threadIdFromSearchParams = searchParams.get("thread_id")?.trim();
// showWelcomeStyle的子判断
const showReuseWelcomeFromQuery = (() => {
const showReuseWelcome = searchParams.get("show_reuse_welcome");
return showReuseWelcome === "true";
})();
// 兜底:当 params 还未就绪时,从 pathname 解析 thread_id。 // 兜底:当 params 还未就绪时,从 pathname 解析 thread_id。
const threadIdFromPathname = (() => { const threadIdFromPathname = (() => {
const parts = pathname.split("?")[0]?.split("/") ?? []; const parts = pathname.split("?")[0]?.split("/") ?? [];
@ -72,7 +77,7 @@ export function useThreadChat() {
const [isNewThread, setIsNewThread] = useState(() => isNewRoute); const [isNewThread, setIsNewThread] = useState(() => isNewRoute);
const [showWelcomeStyle, setShowWelcomeStyle] = useState(() => { const [showWelcomeStyle, setShowWelcomeStyle] = useState(() => {
return isNewRoute|| searchParams.get("xclaw_used") === "true"; return isNewRoute || showReuseWelcomeFromQuery;
}); });
// console.log("[useThreadChat] effectiveThreadIdFromPath", effectiveThreadIdFromPath); // console.log("[useThreadChat] effectiveThreadIdFromPath", effectiveThreadIdFromPath);
@ -89,12 +94,13 @@ export function useThreadChat() {
setIsNewThread(isNewRoute); setIsNewThread(isNewRoute);
// Prefer path thread id, fall back to query thread_id when path is /new. // Prefer path thread id, fall back to query thread_id when path is /new.
setThreadId(threadIdFromPathOrParams); setThreadId(threadIdFromPathOrParams);
setShowWelcomeStyle(isNewRoute || searchParams.get("xclaw_used") === "true"); setShowWelcomeStyle(isNewRoute || showReuseWelcomeFromQuery);
}, [ }, [
isNewRoute, isNewRoute,
normalizeThreadId, normalizeThreadId,
pathname, pathname,
searchParams, searchParams,
showReuseWelcomeFromQuery,
threadId, threadId,
threadIdFromPathOrParams, threadIdFromPathOrParams,
]); ]);

View File

@ -76,12 +76,12 @@ export function IframeTestPanel() {
addLog(`copyToClipboard → "${testText.slice(0, 30)}..."`); addLog(`copyToClipboard → "${testText.slice(0, 30)}..."`);
} }
function handleSendXClawUsed(used: boolean) { function handleSendShowReuseWelcome(showReuseWelcome: boolean) {
sendToParent({ sendToParent({
type: POST_MESSAGE_TYPES.XCLAW_USED, type: POST_MESSAGE_TYPES.SHOW_REUSE_WELCOME,
XClawUsed: used, showReuseWelcome: showReuseWelcome,
}); });
addLog(`postMessage → XClawUsed (${used})`); addLog(`postMessage → show_reuse_welcome (${showReuseWelcome})`);
} }
function handlePointerDown(event: ReactPointerEvent<HTMLDivElement>) { function handlePointerDown(event: ReactPointerEvent<HTMLDivElement>) {
@ -327,27 +327,27 @@ export function IframeTestPanel() {
</div> </div>
</div> </div>
{/* 场景 5XClaw 使用状态 */} {/* 场景 5show_reuse_welcome */}
<div> <div>
<div className="mb-1 text-xs font-semibold text-gray-500"> <div className="mb-1 text-xs font-semibold text-gray-500">
XClaw 使 show_reuse_welcome
</div> </div>
<div className="flex gap-2"> <div className="flex gap-2">
<Button <Button
size="sm" size="sm"
className="flex-1 bg-emerald-50 text-xs text-emerald-700 hover:bg-emerald-100" className="flex-1 bg-emerald-50 text-xs text-emerald-700 hover:bg-emerald-100"
variant="ghost" variant="ghost"
onClick={() => handleSendXClawUsed(true)} onClick={() => handleSendShowReuseWelcome(true)}
> >
used=true true
</Button> </Button>
<Button <Button
size="sm" size="sm"
className="flex-1 bg-slate-50 text-xs text-slate-700 hover:bg-slate-100" className="flex-1 bg-slate-50 text-xs text-slate-700 hover:bg-slate-100"
variant="ghost" variant="ghost"
onClick={() => handleSendXClawUsed(false)} onClick={() => handleSendShowReuseWelcome(false)}
> >
used=false false
</Button> </Button>
</div> </div>
</div> </div>

View File

@ -213,8 +213,8 @@ export function InputBox({
setIsFocused(false); setIsFocused(false);
if (showWelcomeStyle) { if (showWelcomeStyle) {
sendToParent({ sendToParent({
type: POST_MESSAGE_TYPES.XCLAW_USED, type: POST_MESSAGE_TYPES.SHOW_REUSE_WELCOME,
XClawUsed: true, showReuseWelcome: false,
}); });
} }
onSubmit?.(message); onSubmit?.(message);

View File

@ -9,8 +9,8 @@
export const POST_MESSAGE_TYPES = { export const POST_MESSAGE_TYPES = {
// 全屏切换 // 全屏切换
FULLSCREEN: "fullscreen", FULLSCREEN: "fullscreen",
// XClaw 使用状 // 是否展示复用欢迎
XCLAW_USED: "XClawUsed", SHOW_REUSE_WELCOME: "showReuseWelcome",
// 选择预定义 skill // 选择预定义 skill
SELECT_SKILL: "selectSkill", SELECT_SKILL: "selectSkill",
// 打开 skill 选择对话框 // 打开 skill 选择对话框
@ -35,9 +35,9 @@ export interface FullscreenMessage {
fullscreen: boolean; fullscreen: boolean;
} }
export interface XClawUsedMessage { export interface ShowReuseWelcomeMessage {
type: typeof POST_MESSAGE_TYPES.XCLAW_USED; type: typeof POST_MESSAGE_TYPES.SHOW_REUSE_WELCOME;
XClawUsed: boolean; showReuseWelcome: boolean;
} }
export interface SelectSkillMessage { export interface SelectSkillMessage {
@ -79,7 +79,7 @@ export function isSelectedSkillMessage(value: unknown): value is SelectedSkillMe
export function sendToParent( export function sendToParent(
message: message:
| FullscreenMessage | FullscreenMessage
| XClawUsedMessage | ShowReuseWelcomeMessage
| SelectSkillMessage | SelectSkillMessage
| OpenSkillDialogMessage, | OpenSkillDialogMessage,
): void { ): void {

View File

@ -28,7 +28,7 @@ export function useIframeSkill(): UseIframeSkillReturn {
const skillIdFromQuery = searchParams.get("skill_id"); const skillIdFromQuery = searchParams.get("skill_id");
const titleFromQuery = searchParams.get("title"); const titleFromQuery = searchParams.get("title");
const threadIdFromQuery = searchParams.get("thread_id"); const threadIdFromQuery = searchParams.get("thread_id");
const xClawUsedFromQuery = searchParams.get("xclaw_used"); const showReuseWelcomeFromQuery = searchParams.get("show_reuse_welcome");
const lastThreadIdRef = useRef<string | null>(null); const lastThreadIdRef = useRef<string | null>(null);
const [selectedSkill, setSelectedSkill] = useState<SkillData | null>(null); const [selectedSkill, setSelectedSkill] = useState<SkillData | null>(null);
@ -40,15 +40,14 @@ export function useIframeSkill(): UseIframeSkillReturn {
} }
}, [skillIdFromQuery, titleFromQuery]); }, [skillIdFromQuery, titleFromQuery]);
// 0. 监听 query 中 XClawUsed=true 且带 thread_id 时跳转并清理 query // 0. 监听 query 中 show_reuse_welcome=false 且带 thread_id 时跳转到 thread 页面
useEffect(() => { useEffect(() => {
if (!threadIdFromQuery) return; if (!threadIdFromQuery) return;
if (xClawUsedFromQuery !== "true") return; if (showReuseWelcomeFromQuery !== "false") return;
if (lastThreadIdRef.current === threadIdFromQuery) return; if (lastThreadIdRef.current === threadIdFromQuery) return;
lastThreadIdRef.current = threadIdFromQuery; lastThreadIdRef.current = threadIdFromQuery;
router.replace(`/workspace/chats/${threadIdFromQuery}`); router.replace(`/workspace/chats/${threadIdFromQuery}`);
}, [router, threadIdFromQuery, xClawUsedFromQuery]); }, [router, showReuseWelcomeFromQuery, threadIdFromQuery]);
// 2. 监听宿主页 postMessage // 2. 监听宿主页 postMessage
useEffect(() => { useEffect(() => {

View File

@ -29,11 +29,11 @@ export function skipIfMissingThread(
export function buildChatUrl({ export function buildChatUrl({
pathThreadId, pathThreadId,
xclawUsed, showReuseWelcome,
threadId, threadId,
}: { }: {
pathThreadId?: string; pathThreadId?: string;
xclawUsed: boolean; showReuseWelcome: boolean;
threadId: string; threadId: string;
}) { }) {
const resolvedThreadId = threadId ?? pathThreadId; const resolvedThreadId = threadId ?? pathThreadId;
@ -42,7 +42,7 @@ export function buildChatUrl({
} }
const query = new URLSearchParams(); const query = new URLSearchParams();
query.set("xclaw_used", String(xclawUsed)); query.set("show_reuse_welcome", String(showReuseWelcome));
if (resolvedThreadId) { if (resolvedThreadId) {
query.set("thread_id", resolvedThreadId); query.set("thread_id", resolvedThreadId);
} }
@ -55,20 +55,20 @@ export function buildChatUrl({
export function invalidNewChatUrl() { export function invalidNewChatUrl() {
const query = new URLSearchParams(); const query = new URLSearchParams();
query.set("xclaw_used", "false"); query.set("show_reuse_welcome", "true");
return `/workspace/chats/new?${query.toString()}`; return `/workspace/chats/new?${query.toString()}`;
} }
export function newChatEntry(threadId: string) { export function newChatEntry(threadId: string) {
return buildChatUrl({ return buildChatUrl({
xclawUsed: false, showReuseWelcome: true,
threadId, threadId,
}); });
} }
export function reuseThreadWelcomeEntry(threadId: string) { export function reuseThreadWelcomeEntry(threadId: string) {
return buildChatUrl({ return buildChatUrl({
xclawUsed: false, showReuseWelcome: true,
threadId, threadId,
}); });
} }
@ -76,7 +76,7 @@ export function reuseThreadWelcomeEntry(threadId: string) {
export function reuseThreadChatEntry(threadId: string) { export function reuseThreadChatEntry(threadId: string) {
return buildChatUrl({ return buildChatUrl({
pathThreadId: threadId, pathThreadId: threadId,
xclawUsed: true, showReuseWelcome: false,
threadId, threadId,
}); });
} }