feat(agents): 智能体归属/发布操作前增加「账号已切换」提醒

- 新增 useLiveAccount 钩子:跟踪「实时」登录账号(随 storage/focus 刷新),
  并与组件挂载时捕获的账号对比;token 存 localStorage 会被同浏览器其他标签页
  共享,另一标签页登录会静默替换本页 API 所用账号
- agent-card / agent-detail-panel / publish-square-picker-dialog / NewAgentPage
  接入该钩子,切换账号后对归属/发布类操作做提醒,避免误归属

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
吉鑫升andClaude Opus 4.8 committed 2026-06-22 11:30:15 +08:00
1 parent 2b6424b3ff
commit 16ba5deb0e
5 files changed
+221 -7

No files matched your search

+50 -2
View File
@@ -48,6 +48,7 @@ import {
updateAgent,
} from "@/core/agents/api";
import { getStoredAuth } from "@/core/auth";
import { useLiveAccount } from "@/core/auth/use-live-account";
import { useI18n } from "@/core/i18n/hooks";
import { useModels } from "@/core/models/hooks";
import { isAgentSkillCandidate, type Skill } from "@/core/skills";
@@ -96,6 +97,10 @@ export default function NewAgentPage() {
const { skills, isLoading: isSkillsLoading } = useSkills();
const { models, isLoading: isModelsLoading } = useModels();
// 创建请求的归属账号取自「实时」token(apiFetch 每次都重读 localStorage),而非
// 本页加载时缓存的身份 —— 用 live 账号提示归属并检测账号是否在会话中途被切换。
const live = useLiveAccount();
// 可配置的技能限定为「内置 + 自己的 + 已发布到广场的」,
// 其他用户未发布的自定义技能不可选。
const storedAuth = useMemo(() => getStoredAuth(), []);
@@ -287,13 +292,37 @@ export default function NewAgentPage() {
]);
const handleSaveAgent = useCallback(async () => {
// 新建时归属账号 = 创建请求所用的实时 token 对应账号。若本页加载后登录被切换
// (常见于另一标签页登录了别的账号),现在创建会把智能体静默归到新账号名下。
// 先弹确认,避免「用 A 账号创建却归到 B 账号」。更新已有智能体不改归属,故跳过。
if (!agentId && live.switched) {
const ok = window.confirm(
`当前登录账号已从「${live.mountDisplayName}」切换为「${live.displayName}」。\n` +
`现在创建将把该智能体归属到「${live.displayName}」名下。\n` +
`如需归属「${live.mountDisplayName}」,请取消并刷新页面后重新登录。\n\n仍要以「${live.displayName}」创建吗?`,
);
if (!ok) {
return;
}
}
const saved = await ensureAgent();
if (!saved) {
return;
}
toast.success(`智能体「${saved.name}」已保存`);
toast.success(
agentId
? `智能体「${saved.name}」已保存`
: `智能体「${saved.name}」已创建(归属账号:${live.displayName})`,
);
router.push("/page/workspace/agents");
}, [ensureAgent, router]);
}, [
agentId,
ensureAgent,
live.displayName,
live.mountDisplayName,
live.switched,
router,
]);
const handleChatSubmit = useCallback(
async (text: string) => {
@@ -661,6 +690,25 @@ export default function NewAgentPage() {
<p className="text-destructive text-sm">{formError}</p>
) : null}
<div className="rounded-md border px-3 py-2 text-xs dark:border-[#1B477E] dark:bg-[#022248]">
<p className="text-muted-foreground">
{agentId ? "当前登录账号:" : "创建后归属账号:"}
<span className="text-foreground font-medium">
「{live.displayName}」
</span>
</p>
{live.switched && (
<p className="text-destructive mt-1">
⚠ 本页加载时为「{live.mountDisplayName}」,现已切换为「
{live.displayName}」。
{agentId
? "继续保存将以当前账号执行。"
: `继续创建将归属「${live.displayName}」。`}
建议刷新页面确认账号。
</p>
)}
</div>
<Button
className="w-full"
onClick={() => void handleSaveAgent()}