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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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