245 lines
7.7 KiB
TypeScript
245 lines
7.7 KiB
TypeScript
"use client"
|
||
|
||
import { zodResolver } from "@hookform/resolvers/zod"
|
||
import { useState } from "react"
|
||
import { Controller, useForm } from "react-hook-form"
|
||
import z from "zod"
|
||
import { Button } from "@/components/ui/button"
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogFooter,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
DialogTrigger,
|
||
} from "@/components/ui/dialog"
|
||
import {
|
||
Field,
|
||
FieldError,
|
||
FieldGroup,
|
||
FieldLabel,
|
||
} from "@/components/ui/field"
|
||
import { Input } from "@/components/ui/input"
|
||
import {
|
||
Select,
|
||
SelectContent,
|
||
SelectItem,
|
||
SelectTrigger,
|
||
SelectValue,
|
||
} from "@/components/ui/select"
|
||
import { toast } from "sonner"
|
||
import { createGateway } from "@/actions/gateway"
|
||
|
||
const schema = z.object({
|
||
mac: z.string().regex(/^([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}$/, {
|
||
message: "MAC地址格式不正确,请使用如 00:11:22:AA:BB:CC 或 00-11-22-AA-BB-CC 的格式"
|
||
}),
|
||
ip: z.string().regex(/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/, {
|
||
message: "IP地址格式不正确,请使用如 192.168.1.1 的格式"
|
||
}),
|
||
host: z.string().regex(/^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/, {
|
||
message: "域名格式不正确,请使用如 example.com 的格式"
|
||
}).or(z.literal("")),
|
||
type: z.string().optional(),
|
||
status: z.string().optional(),
|
||
})
|
||
|
||
export default function CreatePage(props: { onSuccess?: () => void }) {
|
||
const [open, setOpen] = useState(false)
|
||
const [isLoading, setIsLoading] = useState(false)
|
||
const form = useForm({
|
||
resolver: zodResolver(schema),
|
||
defaultValues: {
|
||
mac: "",
|
||
ip: "",
|
||
host: "",
|
||
type: "1",
|
||
status: "0",
|
||
},
|
||
})
|
||
|
||
const onSubmit = async (data: z.infer<typeof schema>) => {
|
||
setIsLoading(true)
|
||
try {
|
||
const payload = {
|
||
mac: data.mac.trim(),
|
||
ip: data.ip.trim(),
|
||
host: data?.host.trim(),
|
||
type: data.type ? Number(data.type) : 0,
|
||
status: data.status ? Number(data.status) : 0,
|
||
}
|
||
|
||
const res = await createGateway(payload)
|
||
|
||
if (res.success) {
|
||
toast.success("添加网关成功")
|
||
setOpen(false)
|
||
props.onSuccess?.()
|
||
form.reset()
|
||
}else {
|
||
toast.error(res.message || "添加失败")
|
||
}
|
||
} catch (error) {
|
||
console.error("添加网关失败:", error)
|
||
const message = error instanceof Error ? error.message : error
|
||
toast.error(`添加失败: ${message}`)
|
||
} finally {
|
||
setIsLoading(false)
|
||
}
|
||
}
|
||
|
||
const handleCancel = () => {
|
||
setOpen(false)
|
||
form.reset()
|
||
}
|
||
|
||
const statusOptions = [
|
||
{ value: "0", label: "离线" },
|
||
{ value: "1", label: "在线" },
|
||
]
|
||
|
||
const typeOptions = [
|
||
{ value: "1", label: "自有" },
|
||
{ value: "2", label: "白银" },
|
||
]
|
||
|
||
return (
|
||
<Dialog
|
||
open={open}
|
||
onOpenChange={newOpen => {
|
||
setOpen(newOpen)
|
||
if (!newOpen) {
|
||
form.reset()
|
||
}
|
||
}}
|
||
>
|
||
<DialogTrigger asChild>
|
||
<Button>添加网关</Button>
|
||
</DialogTrigger>
|
||
<DialogContent>
|
||
<DialogHeader>
|
||
<DialogTitle>添加网关</DialogTitle>
|
||
</DialogHeader>
|
||
|
||
<form
|
||
id="gateway-create"
|
||
onSubmit={form.handleSubmit(onSubmit)}
|
||
>
|
||
<FieldGroup>
|
||
<Controller
|
||
control={form.control}
|
||
name="mac"
|
||
render={({ field, fieldState }) => (
|
||
<Field>
|
||
<FieldLabel htmlFor="gateway-create-mac">MAC地址:</FieldLabel>
|
||
<Input
|
||
id="gateway-create-mac"
|
||
placeholder="请输入MAC地址,如:00:11:22:33:44:55"
|
||
{...field}
|
||
aria-invalid={fieldState.invalid}
|
||
/>
|
||
{fieldState.invalid && fieldState.error && (
|
||
<FieldError errors={[fieldState.error]} />
|
||
)}
|
||
</Field>
|
||
)}
|
||
/>
|
||
<Controller
|
||
control={form.control}
|
||
name="ip"
|
||
render={({ field, fieldState }) => (
|
||
<Field>
|
||
<FieldLabel htmlFor="gateway-create-ip">IP地址:</FieldLabel>
|
||
<Input
|
||
id="gateway-create-ip"
|
||
placeholder="请输入IP地址,如:192.168.1.1"
|
||
{...field}
|
||
aria-invalid={fieldState.invalid}
|
||
/>
|
||
{fieldState.invalid && fieldState.error && (
|
||
<FieldError errors={[fieldState.error]} />
|
||
)}
|
||
</Field>
|
||
)}
|
||
/>
|
||
<Controller
|
||
control={form.control}
|
||
name="host"
|
||
render={({ field, fieldState }) => (
|
||
<Field>
|
||
<FieldLabel htmlFor="gateway-create-host">域名:</FieldLabel>
|
||
<Input
|
||
id="gateway-create-host"
|
||
placeholder="请输入域名,如:example.com"
|
||
{...field}
|
||
aria-invalid={fieldState.invalid}
|
||
/>
|
||
{fieldState.invalid && fieldState.error && (
|
||
<FieldError errors={[fieldState.error]} />
|
||
)}
|
||
</Field>
|
||
)}
|
||
/>
|
||
<Controller
|
||
control={form.control}
|
||
name="type"
|
||
render={({ field, fieldState }) => (
|
||
<Field data-invalid={fieldState.invalid}>
|
||
<FieldLabel>类型</FieldLabel>
|
||
<Select value={field.value} onValueChange={field.onChange}>
|
||
<SelectTrigger className="w-full h-9">
|
||
<SelectValue placeholder="请选择网关类型" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
{typeOptions.map(option => (
|
||
<SelectItem key={option.value} value={option.value}>
|
||
{option.label}
|
||
</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
{fieldState.invalid && fieldState.error && (
|
||
<FieldError>{fieldState.error?.message}</FieldError>
|
||
)}
|
||
</Field>
|
||
)}
|
||
/>
|
||
<Controller
|
||
control={form.control}
|
||
name="status"
|
||
render={({ field, fieldState }) => (
|
||
<Field data-invalid={fieldState.invalid}>
|
||
<FieldLabel>状态</FieldLabel>
|
||
<Select value={field.value} onValueChange={field.onChange}>
|
||
<SelectTrigger className="w-full h-9">
|
||
<SelectValue placeholder="请选择网关状态" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
{statusOptions.map(option => (
|
||
<SelectItem key={option.value} value={option.value}>
|
||
{option.label}
|
||
</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
{fieldState.invalid && fieldState.error && (
|
||
<FieldError>{fieldState.error?.message}</FieldError>
|
||
)}
|
||
</Field>
|
||
)}
|
||
/>
|
||
</FieldGroup>
|
||
</form>
|
||
|
||
<DialogFooter className="gap-2">
|
||
<Button variant="ghost" onClick={handleCancel} disabled={isLoading}>
|
||
取消
|
||
</Button>
|
||
<Button type="submit" form="gateway-create" disabled={isLoading}>
|
||
{isLoading ? "添加中..." : "添加"}
|
||
</Button>
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
)
|
||
} |