'use client'; import { zodResolver } from '@hookform/resolvers/zod'; import { useMutation } from '@tanstack/react-query'; import { useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { Drawer } from '@/components/ui/drawer'; import { createProxyRoute } from '@/features/proxy-routes/api/proxy-routes'; import { buildOriginUrl, getErrorMessage, linesFromTextarea, parseOriginUrl, parseOriginUrls, validateDomains, } from '@/features/proxy-routes/helpers'; import type { ProxyRouteItem } from '@/features/proxy-routes/types'; import { PrimaryButton, ResourceField, ResourceTextarea, ToggleField, } from '@/features/shared/components/resource-primitives'; const createWebsiteSchema = z .object({ site_name: z.string().trim().max(255, '站点标识不能超过 255 个字符'), domains_text: z.string().trim().min(1, '请至少填写一个域名'), origin_urls_text: z.string().trim().min(1, '请至少填写一个上游地址'), enabled: z.boolean(), remark: z.string().max(255, '备注不能超过 255 个字符'), }) .superRefine((value, context) => { const domains = linesFromTextarea(value.domains_text).map((item) => item.toLowerCase(), ); const domainError = validateDomains(domains); if (domainError) { context.addIssue({ code: z.ZodIssueCode.custom, path: ['domains_text'], message: domainError, }); } const { error } = parseOriginUrls(value.origin_urls_text); if (error) { context.addIssue({ code: z.ZodIssueCode.custom, path: ['origin_urls_text'], message: error, }); } }); type CreateWebsiteFormValues = z.infer; const defaultValues: CreateWebsiteFormValues = { site_name: '', domains_text: '', origin_urls_text: '', enabled: true, remark: '', }; export function ProxyRouteCreateDrawer({ open, onOpenChange, onCreated, }: { open: boolean; onOpenChange: (open: boolean) => void; onCreated: (route: ProxyRouteItem) => void; }) { const form = useForm({ resolver: zodResolver(createWebsiteSchema), defaultValues, }); const createMutation = useMutation({ mutationFn: async (values: CreateWebsiteFormValues) => { const domains = linesFromTextarea(values.domains_text).map((item) => item.toLowerCase(), ); const { urls } = parseOriginUrls(values.origin_urls_text); const primaryOrigin = parseOriginUrl(urls[0]); return createProxyRoute({ site_name: values.site_name.trim() || domains[0], domain: domains[0], domains, origin_id: null, origin_url: buildOriginUrl( primaryOrigin.scheme, primaryOrigin.address, primaryOrigin.port, primaryOrigin.uri, ), origin_scheme: primaryOrigin.scheme, origin_address: primaryOrigin.address, origin_port: primaryOrigin.port, origin_uri: primaryOrigin.uri, origin_host: '', upstreams: urls.slice(1), enabled: values.enabled, enable_https: false, cert_id: null, redirect_http: false, limit_conn_per_server: 0, limit_conn_per_ip: 0, limit_rate: '', cache_enabled: false, cache_policy: 'url', cache_rules: [], custom_headers: [], remark: values.remark.trim(), }); }, onSuccess: (route) => { form.reset(defaultValues); onOpenChange(false); onCreated(route); }, }); useEffect(() => { if (!open) { form.reset(defaultValues); } }, [form, open]); return ( {createMutation.isPending ? '创建中...' : '创建并进入配置'} } >
createMutation.mutate(values))} > form.setValue('enabled', checked, { shouldDirty: true }) } /> {createMutation.isError ? (

{getErrorMessage(createMutation.error)}

) : null}
); }