225 lines
5.8 KiB
TypeScript
225 lines
5.8 KiB
TypeScript
import { Form, FormInstance } from "antd";
|
|
|
|
import { Input } from "@/components/ui/input";
|
|
import { FormDialog } from "@/components/FormDialog";
|
|
import { countryCodeMap } from "@/data";
|
|
import { DIALOGTYPE } from "../../index";
|
|
|
|
import "./index.scss";
|
|
import { DefaultLink } from "./pathChoose";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Switch } from "@/components/ui/switch";
|
|
|
|
export interface DialogConfig {
|
|
title: string;
|
|
desc: string;
|
|
successText: string;
|
|
}
|
|
|
|
|
|
const IpPortInput = ({
|
|
value,
|
|
onChange,
|
|
}: {
|
|
value?: { port: string; ip: string };
|
|
onChange?: (data: { port: string; ip: string }) => void;
|
|
}) => {
|
|
const [ipAndPort, setIpAndPort] = useState<{
|
|
port: string;
|
|
ip: string;
|
|
}>(value ? value : { port: "", ip: "" });
|
|
const handleChagne = ({ key, val }: { key: "port" | "ip"; val: string }) => {
|
|
const newValue = value ? { ...value } : { port: "", ip: "" };
|
|
newValue[key] = val;
|
|
onChange?.(newValue);
|
|
};
|
|
useEffect(() => {
|
|
if (value) {
|
|
setIpAndPort(value);
|
|
}
|
|
}, [value]);
|
|
return (
|
|
<div className="flex items-center gap-1.5">
|
|
<Input
|
|
className="data-[state=checked]:bg-[#1E3A8A] flex-shrink-0 !w-[600px]"
|
|
placeholder="请输入IP"
|
|
value={ipAndPort?.ip}
|
|
onChange={(e) => {
|
|
handleChagne?.({ key: "ip", val: e.target.value });
|
|
}}
|
|
/>
|
|
<Input
|
|
className="data-[state=checked]:bg-[#1E3A8A] "
|
|
placeholder="请输入端口"
|
|
type="number"
|
|
min={0}
|
|
max={65535}
|
|
value={ipAndPort?.port}
|
|
onChange={(e) => {
|
|
handleChagne?.({ key: "port", val: e.target.value });
|
|
}}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const SwitchComponent = ({
|
|
value,
|
|
onChange,
|
|
}: {
|
|
value?: boolean;
|
|
onChange?: (data: boolean) => void;
|
|
}) => {
|
|
const [checked, setChecked] = useState(value);
|
|
|
|
return (
|
|
<div className="flex items-center">
|
|
<Switch
|
|
className="data-[state=checked]:bg-[#1E3A8A]"
|
|
checked={checked}
|
|
onCheckedChange={(e) => {
|
|
setChecked(e);
|
|
onChange?.(e);
|
|
}}
|
|
/>
|
|
<div className="ml-2 text-zinc-900 text-sm font-medium leading-tight">
|
|
是否为出口节点
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const NodeForm = ({ form }: { form: FormInstance }) => {
|
|
return (
|
|
<Form
|
|
className="-mt-1"
|
|
form={form}
|
|
name="dynamic_form_nest_item"
|
|
autoComplete="off"
|
|
layout="vertical"
|
|
>
|
|
{/* <Form.Item name="uid" className="hidden">
|
|
<div className="hidden">uid</div>
|
|
</Form.Item> */}
|
|
<Form.Item name="name" label="节点名称" rules={[{ required: true, message: '请输入节点名称' }]}>
|
|
<Input
|
|
className="link_name_input placeholder:text-base placeholder:text-zinc-400 text-[16px]"
|
|
placeholder="节点名称"
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item name="private_key" label="私钥" rules={[{ required: true, message: '请输入私钥' }]}>
|
|
<Input
|
|
className="link_name_input placeholder:text-base placeholder:text-zinc-400 text-[16px]"
|
|
placeholder="私钥"
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item name="public_key" label="公钥" rules={[{ required: true, message: '请输入公钥' }]}>
|
|
<Input
|
|
className="link_name_input placeholder:text-base placeholder:text-zinc-400 text-[16px]"
|
|
placeholder="公钥"
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item name="ipAndPort" label="IP+端口" rules={[{ required: true, message: '请输入IP+端口' }]}>
|
|
<IpPortInput />
|
|
</Form.Item>
|
|
<Form.Item name="exit">
|
|
<SwitchComponent />
|
|
</Form.Item>
|
|
</Form>
|
|
);
|
|
};
|
|
|
|
const NetworkForm = ({ form }: { form: FormInstance }) => {
|
|
return (
|
|
<Form
|
|
className="-mt-1"
|
|
form={form}
|
|
name="dynamic_form_nest_item"
|
|
autoComplete="off"
|
|
layout="vertical"
|
|
>
|
|
<Form.Item
|
|
name="inbound"
|
|
label="入口节点"
|
|
rules={[{ required: true, message: "请选择入口节点" }]}
|
|
>
|
|
<DefaultLink
|
|
des="入口节点"
|
|
type="entry"
|
|
countries={Object.keys(countryCodeMap)
|
|
// .splice(0, 50)
|
|
.map((key) => key)}
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="outbound"
|
|
label="出口节点"
|
|
rules={[{ required: true, message: "请选择出口节点" }]}
|
|
>
|
|
<DefaultLink
|
|
des="出口节点"
|
|
type="exit"
|
|
countries={Object.keys(countryCodeMap)
|
|
// .splice(0, 50)
|
|
.map((key) => key)}
|
|
/>
|
|
</Form.Item>
|
|
</Form>
|
|
);
|
|
};
|
|
|
|
export const FormAlertDialog = ({
|
|
open,
|
|
setOpen,
|
|
successHandle,
|
|
dialogLoading,
|
|
form,
|
|
type,
|
|
canSubmit,
|
|
handleSelectFile,
|
|
}: {
|
|
open: boolean;
|
|
setOpen: (open: boolean) => void;
|
|
successHandle: () => void;
|
|
dialogLoading: boolean;
|
|
canSubmit: boolean;
|
|
form: FormInstance;
|
|
type: DialogConfig;
|
|
handleSelectFile: () => void;
|
|
}) => {
|
|
const showDialog = (open: boolean) => {
|
|
setOpen(open);
|
|
};
|
|
|
|
return (
|
|
<FormDialog
|
|
open={open}
|
|
openChange={showDialog}
|
|
title={type.title}
|
|
describe={type.desc}
|
|
successText={type.successText}
|
|
successHandle={successHandle}
|
|
submitLoading={dialogLoading}
|
|
form={form}
|
|
contentClass="w-[850px] flex flex-col max-h-[calc(100vh-100px)] overflow-y-hidden "
|
|
successStyle={
|
|
canSubmit
|
|
? "bg-[#1E3A8A] hover:bg-[#1D4ED8] active:bg-[#1E40AF]"
|
|
: "bg-[#1E3A8A] hover:bg-[#1E3A8A] opacity-50"
|
|
}
|
|
>
|
|
<Button
|
|
className="absolute top-3 right-12 bg-transparent text-zinc-900 border border-zinc-200"
|
|
onClick={() => handleSelectFile()}
|
|
>
|
|
批量导入
|
|
</Button>
|
|
{open && type.title === DIALOGTYPE.ADDNode.title ? (
|
|
<NodeForm form={form} />
|
|
) : (
|
|
<NetworkForm form={form} />
|
|
)}
|
|
</FormDialog>
|
|
);
|
|
};
|