diff --git a/app/(admin)/settings/admin-settings-client.tsx b/app/(admin)/settings/admin-settings-client.tsx index d1d4d82d1..00672d276 100644 --- a/app/(admin)/settings/admin-settings-client.tsx +++ b/app/(admin)/settings/admin-settings-client.tsx @@ -91,6 +91,7 @@ import { } from "@/lib/payment/dulupay-config"; import { DEFAULT_CANVAS_SKILL_TAGS, + DEFAULT_CANVAS_SKILL_TAGS_TITLE, normalizeCanvasSkillTags, type CanvasSkillTag, } from "@/lib/canvas-skill-tags"; @@ -1002,6 +1003,9 @@ export function AdminSettingsClient() { // 快捷短语状态 const [questions, setQuestions] = useState([]); const { data: questionsData, mutate: mutateQuestions } = useSWR("/api/starter-questions", fetcher); + const [canvasSkillTagsTitle, setCanvasSkillTagsTitle] = useState( + DEFAULT_CANVAS_SKILL_TAGS_TITLE + ); const [canvasSkillTagsEnabled, setCanvasSkillTagsEnabled] = useState(true); const [canvasSkillTags, setCanvasSkillTags] = useState( DEFAULT_CANVAS_SKILL_TAGS @@ -1009,6 +1013,7 @@ export function AdminSettingsClient() { const [canvasSkillTagUploadingId, setCanvasSkillTagUploadingId] = useState(null); const { data: canvasSkillTagsData, mutate: mutateCanvasSkillTags } = useSWR<{ enabled?: boolean; + title?: string; tags?: CanvasSkillTag[]; }>("/api/canvas-skill-tags", fetcher); @@ -1054,6 +1059,9 @@ export function AdminSettingsClient() { useEffect(() => { if (canvasSkillTagsData) { setCanvasSkillTagsEnabled(canvasSkillTagsData.enabled !== false); + setCanvasSkillTagsTitle( + String(canvasSkillTagsData.title || "").trim() || DEFAULT_CANVAS_SKILL_TAGS_TITLE + ); setCanvasSkillTags(normalizeCanvasSkillTags(canvasSkillTagsData.tags)); } }, [canvasSkillTagsData]); @@ -1151,12 +1159,20 @@ export function AdminSettingsClient() { const res = await fetch("/api/canvas-skill-tags", { method: "PUT", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ enabled: canvasSkillTagsEnabled, tags: payload }), + body: JSON.stringify({ + enabled: canvasSkillTagsEnabled, + title: canvasSkillTagsTitle, + tags: payload, + }), }); if (!res.ok) throw new Error("Failed"); const data = await res.json().catch(() => ({})); setCanvasSkillTagsEnabled(data?.enabled !== false); + setCanvasSkillTagsTitle( + String(data?.title || canvasSkillTagsTitle || "").trim() || + DEFAULT_CANVAS_SKILL_TAGS_TITLE + ); setCanvasSkillTags(normalizeCanvasSkillTags(data?.tags ?? payload)); toast.success("快捷标签已更新"); mutateCanvasSkillTags(); @@ -5763,6 +5779,14 @@ export function AdminSettingsClient() { onCheckedChange={setCanvasSkillTagsEnabled} /> +
+ + setCanvasSkillTagsTitle(event.target.value)} + placeholder={DEFAULT_CANVAS_SKILL_TAGS_TITLE} + /> +
{canvasSkillTags.map((tag, index) => { const TagIcon = getCanvasSkillIconComponent(tag.iconName); return ( diff --git a/app/api/canvas-skill-tags/route.ts b/app/api/canvas-skill-tags/route.ts index c96ab1bb4..6820bba4e 100644 --- a/app/api/canvas-skill-tags/route.ts +++ b/app/api/canvas-skill-tags/route.ts @@ -6,7 +6,6 @@ import { systemSettings } from "@/lib/db/schema"; import { CANVAS_SKILL_TAGS_SETTING_KEY, normalizeCanvasSkillTagSettings, - normalizeCanvasSkillTags, } from "@/lib/canvas-skill-tags"; export async function GET() { @@ -33,10 +32,11 @@ export async function PUT(request: NextRequest) { } const body = await request.json(); - const rawTags = Array.isArray(body) ? body : body?.tags; - const tags = normalizeCanvasSkillTags(rawTags); - const enabled = Array.isArray(body) ? true : body?.enabled !== false; - const nextValue = { enabled, tags }; + const normalized = normalizeCanvasSkillTagSettings(body); + const enabled = normalized.enabled; + const title = normalized.title; + const tags = normalized.tags; + const nextValue = { enabled, title, tags }; const [existing] = await db .select() @@ -61,7 +61,7 @@ export async function PUT(request: NextRequest) { }); } - return NextResponse.json({ success: true, enabled, tags }); + return NextResponse.json({ success: true, enabled, title, tags }); } catch (error) { console.error("[CanvasSkillTags API] Update error:", error); return NextResponse.json({ error: "Failed to update" }, { status: 500 }); diff --git a/components/canvas/CanvasChatPanel.tsx b/components/canvas/CanvasChatPanel.tsx index 179be9e4a..669aff636 100644 --- a/components/canvas/CanvasChatPanel.tsx +++ b/components/canvas/CanvasChatPanel.tsx @@ -48,7 +48,11 @@ import { import { buildImageProxyUrl } from "@/lib/image-delivery"; import type { Attachment, ChatMessage } from "@/lib/types"; import { type CanvasLaunchPayload, getCanvasLaunchStorageKey } from "@/lib/canvas-launch"; -import { normalizeCanvasSkillTags, type CanvasSkillTag } from "@/lib/canvas-skill-tags"; +import { + DEFAULT_CANVAS_SKILL_TAGS_TITLE, + normalizeCanvasSkillTags, + type CanvasSkillTag, +} from "@/lib/canvas-skill-tags"; import { getCanvasSkillIconComponent } from "@/components/canvas/canvas-skill-icons"; import { ImageParamsBar, type ImageGenerationParams } from "@/components/image-params-bar"; import { VideoParamsBar, type VideoGenerationParams } from "@/components/video-params-bar"; @@ -2250,7 +2254,11 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF canvasAutoModeDefaultModelId?: string | null; canvasDetailDefaultModelId?: string | null; }>("/api/site-settings", fetcher); - const { data: canvasSkillTagsData } = useSWR<{ enabled?: boolean; tags?: CanvasSkillTag[] }>( + const { data: canvasSkillTagsData } = useSWR<{ + enabled?: boolean; + title?: string; + tags?: CanvasSkillTag[]; + }>( "/api/canvas-skill-tags", fetcher ); @@ -2287,6 +2295,8 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF const totalGeneratedImages = Number(userImageStats?.totalImages ?? NaN); const aiDetailGenerationEnabled = siteSettings?.aiDetailGenerationEnabled === true; const canvasSkillTagsEnabled = canvasSkillTagsData?.enabled !== false; + const canvasSkillTagsTitle = + String(canvasSkillTagsData?.title || "").trim() || DEFAULT_CANVAS_SKILL_TAGS_TITLE; const canvasSkillTags = useMemo( () => (canvasSkillTagsEnabled ? normalizeCanvasSkillTags(canvasSkillTagsData?.tags) : []), [canvasSkillTagsData?.tags, canvasSkillTagsEnabled] @@ -6362,7 +6372,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF {canvasSkillTags.length > 0 && (
-

试试这些 Skills

+

{canvasSkillTagsTitle}

{canvasSkillTags.map((tag) => { diff --git a/lib/canvas-skill-tags.ts b/lib/canvas-skill-tags.ts index 73b8b8b60..7d23ea449 100644 --- a/lib/canvas-skill-tags.ts +++ b/lib/canvas-skill-tags.ts @@ -1,7 +1,9 @@ export const CANVAS_SKILL_TAGS_SETTING_KEY = "canvas_skill_tags"; +export const DEFAULT_CANVAS_SKILL_TAGS_TITLE = "试试这些 Skills"; export type CanvasSkillTagSettings = { enabled: boolean; + title: string; tags: CanvasSkillTag[]; }; @@ -120,20 +122,24 @@ export function normalizeCanvasSkillTagSettings( if (Array.isArray(value)) { return { enabled: true, + title: DEFAULT_CANVAS_SKILL_TAGS_TITLE, tags: normalizeCanvasSkillTags(value), }; } if (value && typeof value === "object") { const row = value as Record; + const title = normalizeString(row.title) || DEFAULT_CANVAS_SKILL_TAGS_TITLE; return { enabled: row.enabled !== false, + title, tags: normalizeCanvasSkillTags(row.tags), }; } return { enabled: true, + title: DEFAULT_CANVAS_SKILL_TAGS_TITLE, tags: normalizeCanvasSkillTags(null), }; }