feat(settings): 轻应用登录参数与界面模式管理员默认

- 登录时从路由参数 yUserId/access_token 获取并存入 userInfo
- 轻应用管理页路由参数新增 userName/gateDepartName/typeName 选项
- 添加系统默认界面模式设置(管理员可指定全量/简洁)
- useLayoutMode hook 支持优先级:用户自选 > 管理员默认 > 会话级

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
董宏凯andClaude Haiku 4.5 committed 2026-06-15 11:39:02 +08:00
1 parent ab22b50faf
commit 01012ff300
11 files changed
+150 -23

No files matched your search

@@ -26,6 +26,7 @@ import { useLocalSettings } from "@/core/settings";
import {
useAppearanceSettings,
useCitationDisplaySettings,
useLayoutMode,
useUpdateAppearanceSettings,
useUpdateCitationDisplaySettings,
} from "@/core/system-settings/hooks";
@@ -57,6 +58,9 @@ export function AppearanceSettingsPage({ onClose }: { onClose?: () => void }) {
const globalDefault = appearance?.default_theme ?? "light";
const globalSkillView = appearance?.default_skill_view ?? "list";
const globalAgentView = appearance?.default_agent_view ?? "card";
const globalLayoutMode = appearance?.default_layout_mode ?? "full";
// 有效界面模式:用户自己选过则以其为准,否则跟随管理员系统默认(再否则会话级回退)。
const [effectiveLayoutMode, setLayoutMode] = useLayoutMode();
const cleanupWords =
citationDisplay?.cleanup_words ?? settings.display.citationCleanupWords ?? [];
@@ -74,6 +78,18 @@ export function AppearanceSettingsPage({ onClose }: { onClose?: () => void }) {
}
};
const handleSetDefaultLayoutMode = async (value: "full" | "compact") => {
if (value === globalLayoutMode) return;
try {
await updateAppearance.mutateAsync({ default_layout_mode: value });
toast.success(
`已将系统默认界面模式设置为${value === "full" ? "全量模式" : "简洁模式"}`,
);
} catch (e) {
toast.error(e instanceof Error ? e.message : "保存失败");
}
};
const handleSetDefaultView = async (
kind: "skill" | "agent",
value: "card" | "list",
@@ -156,10 +172,10 @@ export function AppearanceSettingsPage({ onClose }: { onClose?: () => void }) {
<div className="flex gap-2">
<Button
type="button"
variant={settings.display.layoutMode !== "compact" ? "default" : "outline"}
variant={effectiveLayoutMode !== "compact" ? "default" : "outline"}
size="sm"
onClick={() => {
setSettings("display", { layoutMode: "full" });
setLayoutMode("full");
onClose?.();
navigate("/page/workspace/chats/new");
}}
@@ -169,10 +185,10 @@ export function AppearanceSettingsPage({ onClose }: { onClose?: () => void }) {
</Button>
<Button
type="button"
variant={settings.display.layoutMode === "compact" ? "default" : "outline"}
variant={effectiveLayoutMode === "compact" ? "default" : "outline"}
size="sm"
onClick={() => {
setSettings("display", { layoutMode: "compact" });
setLayoutMode("compact");
onClose?.();
navigate("/page/workspace/chats/new");
}}
@@ -183,6 +199,43 @@ export function AppearanceSettingsPage({ onClose }: { onClose?: () => void }) {
</div>
</SettingsSection>
{isAdmin && (
<>
<Separator />
<SettingsSection
title="系统默认界面模式(管理员)"
description="给所有还没有手动切换过界面模式的用户的默认;已经自己切换过的用户保留其个人选择不受影响。"
>
<div className="flex flex-wrap items-center gap-2">
<Button
type="button"
variant={globalLayoutMode === "full" ? "default" : "outline"}
size="sm"
onClick={() => void handleSetDefaultLayoutMode("full")}
disabled={updateAppearance.isPending}
>
<PanelLeftIcon className="mr-1.5 size-4" />
全量模式
</Button>
<Button
type="button"
variant={globalLayoutMode === "compact" ? "default" : "outline"}
size="sm"
onClick={() => void handleSetDefaultLayoutMode("compact")}
disabled={updateAppearance.isPending}
>
<LayoutIcon className="mr-1.5 size-4" />
简洁模式
</Button>
<p className="text-muted-foreground ml-2 text-xs">
当前系统默认:
{globalLayoutMode === "full" ? "全量模式" : "简洁模式"}
</p>
</div>
</SettingsSection>
</>
)}
{isAdmin && (
<>
<Separator />