重构消息通知弹窗

This commit is contained in:
dengqichen 2025-11-28 17:37:42 +08:00
parent 763d14f3d3
commit f66524bac6
2 changed files with 111 additions and 112 deletions

View File

@ -174,6 +174,7 @@ export function ConfirmDialog<T = any>({
const handleCancel = () => { const handleCancel = () => {
onCancel?.(); onCancel?.();
onOpenChange(false);
}; };
// 按钮样式映射 // 按钮样式映射

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState, useMemo, useRef } from 'react';
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@ -7,23 +7,16 @@ import {
DialogFooter, DialogFooter,
DialogBody, DialogBody,
} from '@/components/ui/dialog'; } from '@/components/ui/dialog';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import { ConfirmDialog } from '@/components/ui/confirm-dialog'; import { ConfirmDialog } from '@/components/ui/confirm-dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { useToast } from '@/components/ui/use-toast'; import { useToast } from '@/components/ui/use-toast';
import { Plus, Edit, Trash2, Loader2 } from 'lucide-react'; import { PaginatedTable, type ColumnDef, type PaginatedTableRef } from '@/components/ui/paginated-table';
import { Plus, Edit, Trash2 } from 'lucide-react';
import type { Environment } from '@/pages/Deploy/Environment/List/types'; import type { Environment } from '@/pages/Deploy/Environment/List/types';
import type { TeamApplication, Application } from '../types'; import type { TeamApplication, Application } from '../types';
import type { WorkflowDefinition } from '@/pages/Workflow/Definition/List/types'; import type { WorkflowDefinition } from '@/pages/Workflow/Definition/List/types';
import { import {
getTeamApplications, getTeamApplicationsPage,
deleteTeamApplication, deleteTeamApplication,
getApplicationList, getApplicationList,
getJenkinsSystems, getJenkinsSystems,
@ -48,7 +41,7 @@ export const TeamApplicationManageDialog: React.FC<
TeamApplicationManageDialogProps TeamApplicationManageDialogProps
> = ({ open, onOpenChange, teamId, environmentId, environments, onSuccess }) => { > = ({ open, onOpenChange, teamId, environmentId, environments, onSuccess }) => {
const { toast } = useToast(); const { toast } = useToast();
const [loading, setLoading] = useState(false); const tableRef = useRef<PaginatedTableRef<TeamApplication>>(null);
const [teamApplications, setTeamApplications] = useState<TeamApplication[]>([]); const [teamApplications, setTeamApplications] = useState<TeamApplication[]>([]);
// 如果从环境管理进入,只显示该环境的应用;否则显示所有应用 // 如果从环境管理进入,只显示该环境的应用;否则显示所有应用
const selectedEnvironmentId = environmentId || null; const selectedEnvironmentId = environmentId || null;
@ -68,13 +61,12 @@ export const TeamApplicationManageDialog: React.FC<
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [deletingApp, setDeletingApp] = useState<TeamApplication | null>(null); const [deletingApp, setDeletingApp] = useState<TeamApplication | null>(null);
// 加载基础数据和应用列表 // 加载基础数据
useEffect(() => { useEffect(() => {
if (open) { if (open) {
loadTeamApplications();
loadBaseData(); loadBaseData();
} }
}, [open, teamId, selectedEnvironmentId]); }, [open]);
const loadBaseData = async () => { const loadBaseData = async () => {
try { try {
@ -95,23 +87,15 @@ export const TeamApplicationManageDialog: React.FC<
} }
}; };
// 后端已经根据 selectedEnvironmentId 筛选了数据,前端不需要再次筛选 // 包装 fetchFn
const fetchData = async (query: any) => {
const loadTeamApplications = async () => { const result = await getTeamApplicationsPage({
setLoading(true); ...query,
try { teamId,
// 如果指定了环境ID只加载该环境的应用否则加载所有 environmentId: selectedEnvironmentId || undefined,
const data = await getTeamApplications(teamId, selectedEnvironmentId || undefined);
setTeamApplications(data);
} catch (error: any) {
toast({
title: '加载失败',
description: error.message || '无法加载应用列表',
variant: 'destructive',
}); });
} finally { setTeamApplications(result.content || []);
setLoading(false); return result;
}
}; };
const handleOpenAddAppDialog = () => { const handleOpenAddAppDialog = () => {
@ -166,7 +150,7 @@ export const TeamApplicationManageDialog: React.FC<
} }
// 刷新应用列表 // 刷新应用列表
await loadTeamApplications(); tableRef.current?.refresh();
}; };
const handleLoadBranches = async (_appId: number, app: Application) => { const handleLoadBranches = async (_appId: number, app: Application) => {
@ -202,6 +186,90 @@ export const TeamApplicationManageDialog: React.FC<
); );
}; };
// 列定义
const columns: ColumnDef<TeamApplication>[] = useMemo(() => [
{
key: 'applicationName',
title: '应用名称',
width: '200px',
render: (_, app) => (
<span className="font-medium">
{app.applicationName && app.applicationCode
? `${app.applicationName}${app.applicationCode}`
: app.applicationName || app.applicationCode || `应用 ${app.applicationId}`}
</span>
),
},
{
key: 'environmentId',
title: '环境',
width: '100px',
render: (_, app) => getEnvironmentName(app.environmentId),
},
{
key: 'buildType',
title: '构建类型',
width: '120px',
render: (_, app) =>
app.buildType === 'JENKINS' ? 'Jenkins构建' : app.buildType === 'NATIVE' ? '脚本部署' : '-',
},
{
key: 'branch',
title: '分支',
dataIndex: 'branch',
width: '100px',
render: (value) => value || '-',
},
{
key: 'deploySystemName',
title: 'Jenkins系统',
width: '150px',
render: (_, app) =>
app.buildType === 'JENKINS'
? (app.deploySystemName || (app.deploySystemId ? `系统 ${app.deploySystemId}` : '-'))
: '-',
},
{
key: 'deployJob',
title: 'Jenkins Job',
width: '150px',
render: (_, app) => (app.buildType === 'JENKINS' ? (app.deployJob || '-') : '-'),
},
{
key: 'workflowDefinitionName',
title: '工作流',
dataIndex: 'workflowDefinitionName',
width: '180px',
render: (value) => value || '-',
},
{
key: 'actions',
title: '操作',
width: '100px',
sticky: true,
render: (_, app) => (
<div className="flex items-center justify-end gap-1">
<Button
variant="ghost"
size="sm"
className="h-8 w-8 p-0"
onClick={() => handleOpenEditAppDialog(app)}
>
<Edit className="h-3.5 w-3.5" />
</Button>
<Button
variant="ghost"
size="sm"
className="h-8 w-8 p-0"
onClick={() => handleOpenDeleteDialog(app)}
>
<Trash2 className="h-3.5 w-3.5 text-destructive" />
</Button>
</div>
),
},
], [environments]);
return ( return (
<> <>
<Dialog open={open} onOpenChange={onOpenChange}> <Dialog open={open} onOpenChange={onOpenChange}>
@ -221,84 +289,14 @@ export const TeamApplicationManageDialog: React.FC<
{/* 应用列表表格 */} {/* 应用列表表格 */}
<div className="border rounded-lg"> <div className="border rounded-lg">
{loading ? ( <PaginatedTable<TeamApplication, any>
<div className="flex items-center justify-center h-64"> ref={tableRef}
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" /> fetchFn={fetchData}
</div> columns={columns}
) : teamApplications.length === 0 ? ( rowKey="id"
<div className="flex flex-col items-center justify-center h-64 text-muted-foreground"> minWidth="1000px"
<p></p> pageSize={10}
<Button />
variant="link"
onClick={handleOpenAddAppDialog}
className="mt-2"
>
</Button>
</div>
) : (
<Table>
<TableHeader>
<TableRow>
<TableHead className="whitespace-nowrap" style={{ minWidth: '150px' }}></TableHead>
<TableHead className="whitespace-nowrap" style={{ minWidth: '80px' }}></TableHead>
<TableHead className="whitespace-nowrap" style={{ minWidth: '100px' }}></TableHead>
<TableHead className="whitespace-nowrap" style={{ minWidth: '80px' }}></TableHead>
<TableHead className="whitespace-nowrap" style={{ minWidth: '120px' }}>Jenkins系统</TableHead>
<TableHead className="whitespace-nowrap" style={{ minWidth: '120px' }}>Jenkins Job</TableHead>
<TableHead className="whitespace-nowrap" style={{ minWidth: '150px' }}></TableHead>
<TableHead className="text-right sticky right-0 bg-background" style={{ width: '80px' }}></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{teamApplications.map((app) => (
<TableRow key={app.id}>
<TableCell className="font-medium whitespace-nowrap">
{app.applicationName && app.applicationCode
? `${app.applicationName}${app.applicationCode}`
: app.applicationName || app.applicationCode || `应用 ${app.applicationId}`}
</TableCell>
<TableCell className="whitespace-nowrap">
{getEnvironmentName(app.environmentId)}
</TableCell>
<TableCell className="whitespace-nowrap">
{app.buildType === 'JENKINS' ? 'Jenkins构建' : app.buildType === 'NATIVE' ? '脚本部署' : '-'}
</TableCell>
<TableCell className="whitespace-nowrap">{app.branch || '-'}</TableCell>
<TableCell className="whitespace-nowrap">
{app.buildType === 'JENKINS'
? (app.deploySystemName || (app.deploySystemId ? `系统 ${app.deploySystemId}` : '-'))
: '-'}
</TableCell>
<TableCell className="whitespace-nowrap">
{app.buildType === 'JENKINS' ? (app.deployJob || '-') : '-'}
</TableCell>
<TableCell className="whitespace-nowrap">
{app.workflowDefinitionName || '-'}
</TableCell>
<TableCell className="text-right sticky right-0 bg-background">
<div className="flex items-center justify-end gap-2">
<Button
variant="ghost"
size="sm"
onClick={() => handleOpenEditAppDialog(app)}
>
<Edit className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => handleOpenDeleteDialog(app)}
>
<Trash2 className="h-4 w-4 text-destructive" />
</Button>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
)}
</div> </div>
</DialogBody> </DialogBody>
@ -353,7 +351,7 @@ export const TeamApplicationManageDialog: React.FC<
description: '应用配置已删除', description: '应用配置已删除',
}); });
setDeletingApp(null); setDeletingApp(null);
loadTeamApplications(); tableRef.current?.refresh();
onSuccess?.(); onSuccess?.();
}} }}
variant="destructive" variant="destructive"