From 85e23ccee3754a944b990a1571e882f221719618 Mon Sep 17 00:00:00 2001 From: kongkx Date: Thu, 10 Sep 2026 14:21:10 +0800 Subject: [PATCH] feat(studio): manage style presets --- src/api/modules/studio.ts | 5 ++++ .../studio/style-preset-edit-sheet.tsx | 25 +++++++++++++++++++ src/routes/_authed/studio/style-presets.tsx | 24 ++++++++++++------ 3 files changed, 46 insertions(+), 8 deletions(-) create mode 100644 src/features/studio/style-preset-edit-sheet.tsx diff --git a/src/api/modules/studio.ts b/src/api/modules/studio.ts index 70b6a4b..d19183e 100644 --- a/src/api/modules/studio.ts +++ b/src/api/modules/studio.ts @@ -107,6 +107,11 @@ export const deleteCategoryBrief = (id: string) => export const fetchStylePresets = (params: ListParams) => api.get>(`${BASE}/style-presets`, params) +export interface StylePresetPayload { type?: StudioStylePreset['type']; name?: string; payload?: Record | null } +export const createStylePreset = (payload: StylePresetPayload) => api.post>(`${BASE}/style-presets`, payload) +export const updateStylePreset = (id: string, payload: StylePresetPayload) => api.put>(`${BASE}/style-presets/${id}`, payload) +export const deleteStylePreset = (id: string) => api.delete>(`${BASE}/style-presets/${id}`) + export const updateRobotAuthor = (id: string, payload: Partial) => api.put>(`${BASE}/robot-authors/${id}`, payload) diff --git a/src/features/studio/style-preset-edit-sheet.tsx b/src/features/studio/style-preset-edit-sheet.tsx new file mode 100644 index 0000000..15fd26d --- /dev/null +++ b/src/features/studio/style-preset-edit-sheet.tsx @@ -0,0 +1,25 @@ +import { useEffect } from 'react' +import { zodResolver } from '@hookform/resolvers/zod' +import { Controller, useForm } from 'react-hook-form' +import { toast } from 'sonner' +import { z } from 'zod' +import { createStylePreset, updateStylePreset } from '@/api/modules/studio' +import type { StudioStylePreset } from '@/api/types' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' +import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet' +import { Textarea } from '@/components/ui/textarea' +import { handleApiError } from '@/lib/errors' + +const schema = z.object({ type: z.enum(['article', 'image', 'bundle']), name: z.string().trim().min(1, '请填写名称').max(255), payload: z.string().refine((value) => { if (!value.trim()) return true; try { const parsed = JSON.parse(value); return parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed) } catch { return false } }, '必须是 JSON 对象') }) +type FormValues = z.infer +interface Props { preset: StudioStylePreset | null; creating: boolean; onOpenChange: (open: boolean) => void; onSaved: () => void } +export function StylePresetEditSheet({ preset, creating, onOpenChange, onSaved }: Props) { + const form = useForm({ resolver: zodResolver(schema), defaultValues: { type: 'article', name: '', payload: '' } }) + useEffect(() => { form.reset({ type: preset?.type ?? 'article', name: preset?.name ?? '', payload: preset?.payload ? JSON.stringify(preset.payload, null, 2) : '' }) }, [preset, creating, form]) + const submit = async (values: FormValues) => { const payload = { type: values.type, name: values.name.trim(), payload: values.payload.trim() ? JSON.parse(values.payload) as Record : null }; try { if (preset) await updateStylePreset(preset.id, payload); else await createStylePreset(payload); toast.success(preset ? '风格预设已更新' : '风格预设已创建'); onSaved(); onOpenChange(false) } catch (error) { handleApiError(error, form.setError) } } + return {preset ? '编辑风格预设' : '新建风格预设'}
} />