This commit is contained in:
dengqichen 2025-01-20 13:45:58 +08:00
parent 3b9a65bcc8
commit a8c1d56e05
2 changed files with 275 additions and 66 deletions

View File

@ -2,11 +2,15 @@ import React, {useEffect, useState} from 'react';
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
DialogFooter,
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
DialogFooter,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import {Button} from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Separator } from "@/components/ui/separator";
import { ScrollArea } from "@/components/ui/scroll-area";
import { import {
Form, Form,
FormControl, FormControl,
@ -22,9 +26,10 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import {useForm} from "react-hook-form"; import {PlusCircle, X} from 'lucide-react';
import {useForm, useFieldArray} from "react-hook-form";
import {getApplicationList} from '../../../Application/List/service'; import {getApplicationList} from '../../../Application/List/service';
import {getExternalSystemList} from '../service'; import {getExternalSystemList, getJenkinsViewList, getJenkinsJobList} from '../service';
import type {ExternalSystem} from '@/pages/Deploy/External/types'; import type {ExternalSystem} from '@/pages/Deploy/External/types';
interface Application { interface Application {
@ -32,6 +37,29 @@ interface Application {
appName: string; appName: string;
} }
interface JenkinsView {
id: number;
viewName: string;
}
interface JenkinsJob {
id: number;
jobName: string;
}
interface EnvVariable {
key: string;
value: string;
}
interface FormValues {
applicationId?: number;
externalSystemId?: number;
viewId?: number;
jobId?: number;
envs: EnvVariable[];
}
interface DeploymentConfigModalProps { interface DeploymentConfigModalProps {
open: boolean; open: boolean;
onCancel: () => void; onCancel: () => void;
@ -41,13 +69,24 @@ interface DeploymentConfigModalProps {
const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({open, onCancel, onSuccess}) => { const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({open, onCancel, onSuccess}) => {
const [applications, setApplications] = useState<Application[]>([]); const [applications, setApplications] = useState<Application[]>([]);
const [externalSystems, setExternalSystems] = useState<ExternalSystem[]>([]); const [externalSystems, setExternalSystems] = useState<ExternalSystem[]>([]);
const form = useForm({ const [jenkinsViews, setJenkinsViews] = useState<JenkinsView[]>([]);
const [jenkinsJobs, setJenkinsJobs] = useState<JenkinsJob[]>([]);
const form = useForm<FormValues>({
defaultValues: { defaultValues: {
applicationId: undefined, applicationId: undefined,
externalSystemId: undefined, externalSystemId: undefined,
viewId: undefined,
jobId: undefined,
envs: [{key: '', value: ''}],
} }
}); });
const {fields, append, remove} = useFieldArray({
control: form.control,
name: "envs"
});
useEffect(() => { useEffect(() => {
if (open) { if (open) {
// 获取应用列表 // 获取应用列表
@ -61,78 +100,230 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({open, onCa
} }
}, [open]); }, [open]);
// 当选择外部系统时获取 View 列表
const handleExternalSystemChange = async (externalSystemId: number) => {
form.setValue('externalSystemId', externalSystemId);
form.setValue('viewId', undefined);
form.setValue('jobId', undefined);
setJenkinsJobs([]);
if (externalSystemId) {
const views = await getJenkinsViewList(externalSystemId);
setJenkinsViews(views);
} else {
setJenkinsViews([]);
}
};
// 当选择 View 时获取 Job 列表
const handleViewChange = async (viewId: number) => {
form.setValue('viewId', viewId);
form.setValue('jobId', undefined);
const externalSystemId = form.getValues('externalSystemId');
if (externalSystemId && viewId) {
const jobs = await getJenkinsJobList(externalSystemId, viewId);
setJenkinsJobs(jobs);
} else {
setJenkinsJobs([]);
}
};
const handleSubmit = form.handleSubmit((values) => { const handleSubmit = form.handleSubmit((values) => {
// 过滤掉空的环境变量
values.envs = values.envs.filter(env => env.key || env.value);
console.log('表单提交的值:', values); console.log('表单提交的值:', values);
onSuccess?.(); onSuccess?.();
}); });
return ( return (
<Dialog open={open} onOpenChange={(open) => !open && onCancel()}> <Dialog open={open} onOpenChange={(open) => !open && onCancel()}>
<DialogContent className="sm:max-w-[600px]"> <DialogContent className="sm:max-w-[600px] max-h-[80vh] overflow-hidden flex flex-col">
<DialogHeader> <DialogHeader>
<DialogTitle></DialogTitle> <DialogTitle></DialogTitle>
</DialogHeader> </DialogHeader>
<Form {...form}> <Form {...form}>
<form onSubmit={handleSubmit} className="space-y-4"> <ScrollArea className="flex-1">
<div className="grid grid-cols-2 gap-4"> <form onSubmit={handleSubmit} className="space-y-4 pr-6">
<FormField <div className="grid grid-cols-2 gap-4">
control={form.control} <FormField
name="applicationId" control={form.control}
render={({field}) => ( name="applicationId"
<FormItem> render={({field}) => (
<FormLabel></FormLabel> <FormItem>
<Select <FormLabel></FormLabel>
onValueChange={(value) => field.onChange(Number(value))} <Select
value={field.value?.toString()} onValueChange={(value) => field.onChange(Number(value))}
> value={field.value?.toString()}
<FormControl> >
<SelectTrigger> <FormControl>
<SelectValue placeholder="请选择应用" /> <SelectTrigger>
</SelectTrigger> <SelectValue placeholder="请选择应用" />
</FormControl> </SelectTrigger>
<SelectContent> </FormControl>
{applications.map((app) => ( <SelectContent>
<SelectItem key={app.id} value={String(app.id)}> {applications.map((app) => (
{app.appName} <SelectItem key={app.id} value={String(app.id)}>
</SelectItem> {app.appName}
))} </SelectItem>
</SelectContent> ))}
</Select> </SelectContent>
<FormMessage /> </Select>
</FormItem> <FormMessage />
)} </FormItem>
/> )}
<FormField />
control={form.control} <FormField
name="externalSystemId" control={form.control}
render={({field}) => ( name="externalSystemId"
<FormItem> render={({field}) => (
<FormLabel></FormLabel> <FormItem>
<Select <FormLabel></FormLabel>
onValueChange={(value) => field.onChange(Number(value))} <Select
value={field.value?.toString()} onValueChange={(value) => handleExternalSystemChange(Number(value))}
> value={field.value?.toString()}
<FormControl> >
<SelectTrigger> <FormControl>
<SelectValue placeholder="请选择三方系统" /> <SelectTrigger>
</SelectTrigger> <SelectValue placeholder="请选择三方系统" />
</FormControl> </SelectTrigger>
<SelectContent> </FormControl>
{externalSystems.map((system) => ( <SelectContent>
<SelectItem key={system.id} value={String(system.id)}> {externalSystems.map((system) => (
{system.name} <SelectItem key={system.id} value={String(system.id)}>
</SelectItem> {system.name}
))} </SelectItem>
</SelectContent> ))}
</Select> </SelectContent>
<FormMessage /> </Select>
</FormItem> <FormMessage />
)} </FormItem>
/> )}
</div> />
</form> </div>
<Separator className="my-4" />
<div className="grid grid-cols-2 gap-4">
<FormField
control={form.control}
name="viewId"
render={({field}) => (
<FormItem>
<FormLabel>Jenkins视图选择</FormLabel>
<Select
disabled={!form.getValues('externalSystemId')}
onValueChange={(value) => handleViewChange(Number(value))}
value={field.value?.toString()}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="请选择 View" />
</SelectTrigger>
</FormControl>
<SelectContent>
{jenkinsViews.map((view) => (
<SelectItem key={view.id} value={String(view.id)}>
{view.viewName}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="jobId"
render={({field}) => (
<FormItem>
<FormLabel>Jenkins任务选择</FormLabel>
<Select
disabled={!form.getValues('viewId')}
onValueChange={(value) => field.onChange(Number(value))}
value={field.value?.toString()}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="请选择 Job" />
</SelectTrigger>
</FormControl>
<SelectContent>
{jenkinsJobs.map((job) => (
<SelectItem key={job.id} value={String(job.id)}>
{job.jobName}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
</div>
<Separator className="my-4" />
<div className="space-y-4">
<div className="flex items-center justify-between bg-background z-10 py-2">
<FormLabel></FormLabel>
<Button
type="button"
variant="outline"
size="sm"
onClick={() => append({key: '', value: ''})}
>
<PlusCircle className="h-4 w-4 mr-2" />
</Button>
</div>
<ScrollArea className="h-[200px]">
<div className="space-y-4 pr-2">
{fields.map((field, index) => (
<div key={field.id} className="flex gap-4 items-start">
<FormField
control={form.control}
name={`envs.${index}.key`}
render={({field}) => (
<FormItem className="flex-1">
<FormControl>
<Input placeholder="变量名" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name={`envs.${index}.value`}
render={({field}) => (
<FormItem className="flex-1">
<FormControl>
<Input placeholder="变量值" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button
type="button"
variant="ghost"
size="icon"
onClick={() => remove(index)}
className="mt-2"
>
<X className="h-4 w-4" />
</Button>
</div>
))}
</div>
</ScrollArea>
</div>
</form>
</ScrollArea>
</Form> </Form>
<DialogFooter> <DialogFooter className="flex-shrink-0">
<Button variant="outline" onClick={onCancel}> <Button variant="outline" onClick={onCancel}>
</Button> </Button>

View File

@ -3,6 +3,16 @@ import type {DeploymentConfig, CreateDeploymentConfigRequest, UpdateDeploymentCo
import type {Page} from '@/types/base'; import type {Page} from '@/types/base';
import type {ExternalSystem} from '@/pages/Deploy/External/types'; import type {ExternalSystem} from '@/pages/Deploy/External/types';
interface JenkinsView {
id: number;
name: string;
}
interface JenkinsJob {
id: number;
name: string;
}
const BASE_URL = '/api/v1/deploy-app-config'; const BASE_URL = '/api/v1/deploy-app-config';
// 获取部署配置分页列表 // 获取部署配置分页列表
@ -36,3 +46,11 @@ export const getDeployConfigTemplates = () =>
// 获取外部系统列表 // 获取外部系统列表
export const getExternalSystemList = (type: string) => export const getExternalSystemList = (type: string) =>
request.get<ExternalSystem[]>('/api/v1/external-system/list', {params: {type}}); request.get<ExternalSystem[]>('/api/v1/external-system/list', {params: {type}});
// 获取 Jenkins View 列表
export const getJenkinsViewList = (externalSystemId: number) =>
request.get<JenkinsView[]>('/api/v1/jenkins-view/list', {params: {externalSystemId}});
// 获取 Jenkins Job 列表
export const getJenkinsJobList = (externalSystemId: number, viewId: number) =>
request.get<JenkinsJob[]>('/api/v1/jenkins-job/list', {params: {externalSystemId, viewId}});