增加团队管理增删改差

This commit is contained in:
dengqichen 2025-10-29 10:54:32 +08:00
parent 0a5c60b888
commit d7d555f1ee
5 changed files with 21 additions and 133 deletions

View File

@ -1,7 +1,7 @@
import React, {useEffect, useState} from 'react'; import React, {useEffect, useState} from 'react';
import type {Application, RepositoryGroup, RepositoryProject} from '../types'; import type {Application, RepositoryProject} from '../types';
import {DevelopmentLanguageTypeEnum} from '../types'; import {DevelopmentLanguageTypeEnum} from '../types';
import {createApplication, updateApplication, getRepositoryGroupList, getRepositoryProjects} from '../service'; import {createApplication, updateApplication, getRepositoryProjectsBySystem} from '../service';
import type {ExternalSystemResponse} from '@/pages/Deploy/External/types'; import type {ExternalSystemResponse} from '@/pages/Deploy/External/types';
import {SystemType} from '@/pages/Deploy/External/types'; import {SystemType} from '@/pages/Deploy/External/types';
import {getExternalSystems} from '@/pages/Deploy/External/service'; import {getExternalSystems} from '@/pages/Deploy/External/service';
@ -63,7 +63,6 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
}) => { }) => {
const [categories, setCategories] = useState<ApplicationCategoryResponse[]>([]); const [categories, setCategories] = useState<ApplicationCategoryResponse[]>([]);
const [externalSystems, setExternalSystems] = useState<ExternalSystemResponse[]>([]); const [externalSystems, setExternalSystems] = useState<ExternalSystemResponse[]>([]);
const [repositoryGroups, setRepositoryGroups] = useState<RepositoryGroup[]>([]);
const [repositoryProjects, setRepositoryProjects] = useState<RepositoryProject[]>([]); const [repositoryProjects, setRepositoryProjects] = useState<RepositoryProject[]>([]);
const {toast} = useToast(); const {toast} = useToast();
const isEdit = !!initialValues?.id; const isEdit = !!initialValues?.id;
@ -79,7 +78,6 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
enabled: true, enabled: true,
sort: 0, sort: 0,
externalSystemId: undefined, externalSystemId: undefined,
repoGroupId: undefined,
repoProjectId: undefined, repoProjectId: undefined,
}, },
}); });
@ -136,41 +134,28 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
enabled: initialValues.enabled, enabled: initialValues.enabled,
sort: initialValues.sort, sort: initialValues.sort,
externalSystemId: initialValues.externalSystemId, externalSystemId: initialValues.externalSystemId,
repoGroupId: initialValues.repoGroupId,
repoProjectId: initialValues.repoProjectId repoProjectId: initialValues.repoProjectId
}); });
// 如果有外部系统ID加载仓库 // 如果有外部系统ID加载仓库项目
if (initialValues.externalSystemId) { if (initialValues.externalSystemId) {
fetchRepositoryGroups(initialValues.externalSystemId); fetchRepositoryProjects(initialValues.externalSystemId);
}
// 如果有仓库组ID加载仓库项目
if (initialValues.repoGroupId) {
fetchRepositoryProjects(initialValues.repoGroupId);
} }
} }
}, [initialValues]); }, [initialValues]);
// 当选择外部系统时,获取对应的仓库列表 // 当选择外部系统时,获取对应的仓库项目列表
const handleExternalSystemChange = (externalSystemId: number | undefined) => { const handleExternalSystemChange = (externalSystemId: number | undefined) => {
form.setValue('repoGroupId', undefined);
form.setValue('repoProjectId', undefined); form.setValue('repoProjectId', undefined);
setRepositoryProjects([]); setRepositoryProjects([]);
if (externalSystemId) { if (externalSystemId) {
fetchRepositoryGroups(externalSystemId); fetchRepositoryProjects(externalSystemId);
} }
}; };
const fetchRepositoryGroups = async (externalSystemId: number | undefined) => { const fetchRepositoryProjects = async (externalSystemId: number | undefined) => {
if (!externalSystemId) return; if (!externalSystemId) return;
const response = await getRepositoryGroupList(externalSystemId); const response = await getRepositoryProjectsBySystem(externalSystemId);
setRepositoryGroups(response || []);
};
const fetchRepositoryProjects = async (repoGroupId: number | undefined) => {
if (!repoGroupId) return;
const response = await getRepositoryProjects(repoGroupId);
setRepositoryProjects(response || []); setRepositoryProjects(response || []);
}; };
@ -352,106 +337,6 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
)} )}
/> />
<FormField
control={form.control}
name="repoGroupId"
render={({field}) => {
const [searchValue, setSearchValue] = React.useState("");
const [open, setOpen] = React.useState(false);
const filteredGroups = repositoryGroups.filter(group =>
group.name.toLowerCase().includes(searchValue.toLowerCase())
);
return (
<FormItem>
<FormLabel></FormLabel>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<FormControl>
<Button
variant="outline"
role="combobox"
disabled={!form.watch('externalSystemId')}
className={cn(
"w-full justify-between",
!field.value && "text-muted-foreground"
)}
>
{field.value
? repositoryGroups.find(
(group) => group.repoGroupId === field.value
)?.fullName || "请选择代码仓库组"
: !form.watch('externalSystemId')
? "请先选择外部系统"
: "请选择代码仓库组"}
<ChevronDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-[--radix-popover-trigger-width] p-0">
<div className="flex items-center border-b px-3">
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<input
placeholder="搜索代码仓库组..."
className="flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
/>
</div>
<div className="relative">
<ScrollArea className="h-[200px] w-full">
<div className="p-1">
{filteredGroups.length === 0 ? (
<div className="p-4 text-center text-sm text-muted-foreground">
</div>
) : (
filteredGroups.map((group) => (
<div
key={group.repoGroupId}
className={cn(
"relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground",
group.repoGroupId === field.value && "bg-accent text-accent-foreground"
)}
onClick={() => {
const groupId = group.repoGroupId;
form.setValue("repoGroupId", groupId);
form.setValue("repoProjectId", undefined as any);
setRepositoryProjects([]);
fetchRepositoryProjects(groupId);
setSearchValue("");
setOpen(false);
}}
onWheel={(e) => {
const scrollArea = e.currentTarget.closest('[data-radix-scroll-area-viewport]');
if (scrollArea) {
scrollArea.scrollTop += e.deltaY;
}
}}
>
<div className="flex flex-col">
<span className="font-medium">{group.fullName}</span>
<span className="text-xs text-muted-foreground truncate">
{group.fullPath}
</span>
</div>
{group.repoGroupId === field.value && (
<Check className="ml-auto h-4 w-4" />
)}
</div>
))
)}
</div>
</ScrollArea>
</div>
</PopoverContent>
</Popover>
<FormMessage />
</FormItem>
);
}}
/>
<FormField <FormField
control={form.control} control={form.control}
name="repoProjectId" name="repoProjectId"
@ -471,7 +356,7 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
<Button <Button
variant="outline" variant="outline"
role="combobox" role="combobox"
disabled={!form.watch('repoGroupId')} disabled={!form.watch('externalSystemId')}
className={cn( className={cn(
"w-full justify-between", "w-full justify-between",
!field.value && "text-muted-foreground" !field.value && "text-muted-foreground"
@ -481,8 +366,8 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
? repositoryProjects.find( ? repositoryProjects.find(
(project) => project.repoProjectId === field.value (project) => project.repoProjectId === field.value
)?.name )?.name
: !form.watch('repoGroupId') : !form.watch('externalSystemId')
? "请先选择代码仓库组" ? "请先选择外部系统"
: "请选择项目"} : "请选择项目"}
<ChevronDown className="ml-2 h-4 w-4 shrink-0 opacity-50" /> <ChevronDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button> </Button>
@ -511,7 +396,7 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
key={project.repoProjectId} key={project.repoProjectId}
className={cn( className={cn(
"relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground", "relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground",
project.id === field.value && "bg-accent text-accent-foreground" project.repoProjectId === field.value && "bg-accent text-accent-foreground"
)} )}
onClick={() => { onClick={() => {
form.setValue("repoProjectId", project.repoProjectId); form.setValue("repoProjectId", project.repoProjectId);

View File

@ -207,7 +207,7 @@ const ApplicationList: React.FC = () => {
size: 120, size: 120,
cell: ({ row }) => ( cell: ({ row }) => (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span>{row.original.category?.name || '-'}</span> <span>{row.original.applicationCategory?.name || '-'}</span>
</div> </div>
), ),
}, },

View File

@ -17,7 +17,6 @@ export const applicationFormSchema = z.object({
invalid_type_error: '应用分类必须是数字', invalid_type_error: '应用分类必须是数字',
}), }),
externalSystemId: z.number().optional(), externalSystemId: z.number().optional(),
repoGroupId: z.number().optional(),
repoProjectId: z.number().optional(), repoProjectId: z.number().optional(),
language: z.nativeEnum(DevelopmentLanguageTypeEnum, { language: z.nativeEnum(DevelopmentLanguageTypeEnum, {
required_error: "请选择开发语言", required_error: "请选择开发语言",

View File

@ -45,8 +45,14 @@ export const getRepositoryGroupList = (externalSystemId: number) =>
params: { externalSystemId }, params: { externalSystemId },
}); });
// 获取项目列表 // 获取项目列表(根据仓库组)
export const getRepositoryProjects = (repoGroupId: number) => export const getRepositoryProjects = (repoGroupId: number) =>
request.get<RepositoryProject[]>(`${REPOSITORY_PROJECT_URL}/list`, { request.get<RepositoryProject[]>(`${REPOSITORY_PROJECT_URL}/list`, {
params: { repoGroupId: repoGroupId }, params: { repoGroupId: repoGroupId },
}); });
// 获取项目列表(根据外部系统)
export const getRepositoryProjectsBySystem = (externalSystemId: number) =>
request.get<RepositoryProject[]>(`${REPOSITORY_PROJECT_URL}/list`, {
params: { externalSystemId },
});

View File

@ -19,11 +19,9 @@ export interface Application extends BaseResponse {
sort: number; sort: number;
teamCount?: number; teamCount?: number;
applicationCategoryId: number; applicationCategoryId: number;
category?: ApplicationCategoryResponse; applicationCategory?: ApplicationCategoryResponse;
externalSystemId?: number; externalSystemId?: number;
externalSystem?: ExternalSystemResponse; externalSystem?: ExternalSystemResponse;
repoGroupId?: number;
repositoryGroup?: RepositoryGroup;
repoProjectId?: number; repoProjectId?: number;
repositoryProject?: RepositoryProject; repositoryProject?: RepositoryProject;
} }