"use client"; import Link from "next/link"; import { ArrowLeft, Plus, Save, Trash2, Wand2 } from "lucide-react"; import { useEffect, useMemo, useState } from "react"; import useSWR from "swr"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Switch } from "@/components/ui/switch"; import { Textarea } from "@/components/ui/textarea"; import { fetcher } from "@/lib/utils"; import { STYLE_PRO_CONFIG_KEY, defaultStyleProConfig, normalizeStyleProConfig, type StyleProCategory, type StyleProConfig, type StyleProCustomField, type StyleProCustomFieldType, type StyleProOption, } from "@/lib/style-pro/config"; type SettingsResponse = { setting?: { value?: unknown; }; }; type AiModelOption = { id: string; modelId: string; displayName: string; supportsImageGen?: boolean; isEnabled?: boolean; isHidden?: boolean; }; type AiModelsResponse = { models?: AiModelOption[]; }; const AUTO_MODEL_VALUE = "__auto__"; function getId(prefix: string) { if (typeof crypto !== "undefined" && "randomUUID" in crypto) { return `${prefix}-${crypto.randomUUID().slice(0, 8)}`; } return `${prefix}-${Date.now().toString(36)}`; } function reindexCategories(categories: StyleProCategory[]) { return categories.map((category, index) => ({ ...category, order: (index + 1) * 10, customFields: reindexCustomFields(category.customFields || []), options: category.options.map((option, optionIndex) => ({ ...option, order: (optionIndex + 1) * 10, })), })); } function reindexCustomFields(fields: StyleProCustomField[]) { return fields.map((field, index) => ({ ...field, order: (index + 1) * 10, })); } function createCategory(): StyleProCategory { const id = getId("category"); return { id, title: "新分类", description: "", required: true, minSelections: 1, maxSelections: 1, enabled: true, order: 999, customFields: [], options: [createOption(id)], }; } function createCustomField(prefix = "custom"): StyleProCustomField { return { id: getId(`${prefix}-field`), label: "自定义要求", description: "", type: "text", placeholder: "请输入自定义要求...", defaultValue: "", promptTemplate: "{{fieldLabel}}:{{value}}", required: false, enabled: true, order: 999, maxLength: 160, }; } function createOption(categoryId: string): StyleProOption { return { id: getId("option"), label: "新按钮", description: "", prompt: "请填写这个按钮对应的隐藏提示词。", jsonKey: categoryId, enabled: true, order: 999, }; } function modelLabel(model: AiModelOption) { const name = model.displayName || model.modelId || model.id; const id = model.modelId && model.modelId !== name ? ` · ${model.modelId}` : ""; return `${name}${id}${model.isHidden ? " · 前端隐藏" : ""}`; } function ColorSettingField({ label, value, onChange, }: { label: string; value: string; onChange: (value: string) => void; }) { const shortHex = value.match(/^#([0-9a-fA-F]{3})$/); const pickerValue = /^#[0-9a-fA-F]{6}$/.test(value) ? value : shortHex ? `#${shortHex[1] .split("") .map((char) => `${char}${char}`) .join("")}` : "#000000"; return (
onChange(event.target.value)} type="color" value={pickerValue} /> onChange(event.target.value)} placeholder="#2563eb" value={value} />
); } function CustomFieldEditor({ field, onChange, onRemove, }: { field: StyleProCustomField; onChange: (updates: Partial) => void; onRemove: () => void; }) { const fieldTypeOptions: Array<{ value: StyleProCustomFieldType; label: string }> = [ { value: "text", label: "单行文本" }, { value: "textarea", label: "多行文本" }, { value: "color", label: "颜色选择" }, ]; return (
{field.label || "未命名自定义项"}
{field.type === "color" ? "颜色选择" : field.type === "textarea" ? "多行文本" : "单行文本"}
onChange({ enabled })} />
onChange({ label: event.target.value })} value={field.label} />
onChange({ id: event.target.value })} value={field.id} />
onChange({ maxLength: Number(event.target.value) || 160 }) } type="number" value={field.maxLength || (field.type === "textarea" ? 800 : 160)} />
{field.type === "color" ? ( onChange({ defaultValue: event.target.value })} type="color" value={ /^#[0-9a-fA-F]{6}$/.test(field.defaultValue || "") ? field.defaultValue : "#ffffff" } /> ) : null} onChange({ defaultValue: event.target.value })} placeholder={field.type === "color" ? "#FFFFFF" : "可留空"} value={field.defaultValue || ""} />
onChange({ placeholder: event.target.value })} placeholder="请输入自定义要求..." value={field.placeholder || ""} />
onChange({ description: event.target.value })} value={field.description || ""} />