feat: improve citation display and skill persistence
This commit is contained in:
1 parent
b671b49725
commit
8b2f398015
12 files changed
+721
-136
No files matched your search
@@ -2,9 +2,11 @@
|
||||
|
||||
import { MoonIcon, SunIcon } from "lucide-react";
|
||||
import { useMemo, type ComponentType, type SVGProps } from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { useTheme } from "@/contexts/ThemeContext";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -14,9 +16,15 @@ import {
|
||||
} from "@/components/ui/select";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { getStoredAuth } from "@/core/auth";
|
||||
import { enUS, isLocale, zhCN, type Locale } from "@/core/i18n";
|
||||
import { useI18n } from "@/core/i18n/hooks";
|
||||
import { useLocalSettings } from "@/core/settings";
|
||||
import {
|
||||
useAppearanceSettings,
|
||||
useUpdateAppearanceSettings,
|
||||
} from "@/core/system-settings/hooks";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
import { SettingsSection } from "./settings-section";
|
||||
@@ -31,6 +39,24 @@ export function AppearanceSettingsPage() {
|
||||
const { theme, setTheme } = useTheme();
|
||||
const currentTheme = theme;
|
||||
const [settings, setSettings] = useLocalSettings();
|
||||
const isAdmin = getStoredAuth()?.system_role === "admin";
|
||||
const { data: appearance } = useAppearanceSettings();
|
||||
const updateAppearance = useUpdateAppearanceSettings();
|
||||
const globalDefault = appearance?.default_theme ?? "light";
|
||||
|
||||
const handleSetGlobalDefault = async (value: "light" | "dark") => {
|
||||
if (value === globalDefault) return;
|
||||
try {
|
||||
await updateAppearance.mutateAsync({ default_theme: value });
|
||||
toast.success(
|
||||
value === "light"
|
||||
? "已将系统默认主题设置为浅色"
|
||||
: "已将系统默认主题设置为深色",
|
||||
);
|
||||
} catch (e) {
|
||||
toast.error(e instanceof Error ? e.message : "保存失败");
|
||||
}
|
||||
};
|
||||
|
||||
const themeOptions = useMemo(
|
||||
() => [
|
||||
@@ -76,6 +102,43 @@ export function AppearanceSettingsPage() {
|
||||
</div>
|
||||
</SettingsSection>
|
||||
|
||||
{isAdmin && (
|
||||
<>
|
||||
<Separator />
|
||||
<SettingsSection
|
||||
title="系统默认主题(管理员)"
|
||||
description="给所有还没有手动切换过主题的用户的默认主题;已经自己切换过的用户保留其个人设置不受影响。"
|
||||
>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant={globalDefault === "light" ? "default" : "outline"}
|
||||
size="sm"
|
||||
onClick={() => void handleSetGlobalDefault("light")}
|
||||
disabled={updateAppearance.isPending}
|
||||
>
|
||||
<SunIcon className="mr-1.5 size-4" />
|
||||
浅色
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant={globalDefault === "dark" ? "default" : "outline"}
|
||||
size="sm"
|
||||
onClick={() => void handleSetGlobalDefault("dark")}
|
||||
disabled={updateAppearance.isPending}
|
||||
>
|
||||
<MoonIcon className="mr-1.5 size-4" />
|
||||
深色
|
||||
</Button>
|
||||
<p className="text-muted-foreground ml-2 text-xs">
|
||||
当前系统默认:
|
||||
{globalDefault === "light" ? "浅色" : "深色"}
|
||||
</p>
|
||||
</div>
|
||||
</SettingsSection>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Separator />
|
||||
|
||||
<SettingsSection
|
||||
@@ -124,26 +187,49 @@ export function AppearanceSettingsPage() {
|
||||
}
|
||||
aria-label="回答速度指示器"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-start justify-between gap-4 rounded-lg border p-4">
|
||||
<div>
|
||||
<div className="text-sm font-medium">RAG 引用模式</div>
|
||||
<p className="text-muted-foreground mt-1 max-w-md text-xs leading-relaxed">
|
||||
开启后,已配置展示适配的技能结果会在问答中渲染为编号引用或列表,并支持点击跳转。
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
checked={settings.display.ragModeEnabled}
|
||||
onCheckedChange={(checked) =>
|
||||
setSettings("display", { ragModeEnabled: checked })
|
||||
}
|
||||
aria-label="RAG 引用模式"
|
||||
/>
|
||||
</div>
|
||||
</SettingsSection>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</div>
|
||||
<div className="flex items-start justify-between gap-4 rounded-lg border p-4">
|
||||
<div>
|
||||
<div className="text-sm font-medium">RAG 引用模式</div>
|
||||
<p className="text-muted-foreground mt-1 max-w-md text-xs leading-relaxed">
|
||||
开启后,已配置展示适配的技能结果会在问答中渲染为编号引用或列表,并支持点击跳转。
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
checked={settings.display.ragModeEnabled}
|
||||
onCheckedChange={(checked) =>
|
||||
setSettings("display", { ragModeEnabled: checked })
|
||||
}
|
||||
aria-label="RAG 引用模式"
|
||||
/>
|
||||
</div>
|
||||
{isAdmin && (
|
||||
<div className="rounded-lg border p-4">
|
||||
<div className="mb-3">
|
||||
<div className="text-sm font-medium">参考文献去除词</div>
|
||||
<p className="text-muted-foreground mt-1 max-w-2xl text-xs leading-relaxed">
|
||||
管理员配置。每行一个词或短句,参考文献卡片和详情弹框会自动移除这些广告词、导航词或免责声明。
|
||||
</p>
|
||||
</div>
|
||||
<Textarea
|
||||
value={(settings.display.citationCleanupWords ?? []).join("\n")}
|
||||
onChange={(event) =>
|
||||
setSettings("display", {
|
||||
citationCleanupWords: event.currentTarget.value
|
||||
.split(/\r?\n/)
|
||||
.map((item) => item.trim())
|
||||
.filter(Boolean),
|
||||
})
|
||||
}
|
||||
placeholder={"广告\n点击下载APP\n打开客户端\n免责声明\n责任编辑"}
|
||||
className="min-h-32 text-sm"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</SettingsSection>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ThemePreviewCard({
|
||||
icon: Icon,
|
||||
|
||||
Reference in new issue
Block a user