diff --git a/frontend/src/components/ui/sheet.tsx b/frontend/src/components/ui/sheet.tsx index 477bc982..bdc84642 100644 --- a/frontend/src/components/ui/sheet.tsx +++ b/frontend/src/components/ui/sheet.tsx @@ -49,12 +49,14 @@ const sheetVariants = cva( interface SheetContentProps extends React.ComponentPropsWithoutRef, - VariantProps {} + VariantProps { + showClose?: boolean +} const SheetContent = React.forwardRef< React.ElementRef, SheetContentProps ->(({ side = "right", className, children, ...props }, ref) => ( +>(({ side = "right", className, children, showClose = true, ...props }, ref) => ( {children} - - - Close - + {showClose && ( + + + Close + + )} )) diff --git a/frontend/src/pages/Deploy/Environment/List/index.tsx b/frontend/src/pages/Deploy/Environment/List/index.tsx index 29aa93cc..b54e0892 100644 --- a/frontend/src/pages/Deploy/Environment/List/index.tsx +++ b/frontend/src/pages/Deploy/Environment/List/index.tsx @@ -163,12 +163,14 @@ const EnvironmentList: React.FC = () => {
- +
环境编码 环境名称 - 环境描述 + 环境描述 + 团队数 + 应用数 排序 状态 操作 @@ -177,7 +179,7 @@ const EnvironmentList: React.FC = () => { {list.length === 0 ? ( - + 暂无数据 @@ -187,7 +189,21 @@ const EnvironmentList: React.FC = () => { {item.envCode} {item.envName} - {item.envDesc || '-'} + {item.envDesc || '-'} + +
+ + {item.teamCount || 0} + +
+
+ +
+ + {item.applicationCount || 0} + +
+
{item.sort} diff --git a/frontend/src/pages/Deploy/Environment/List/types.ts b/frontend/src/pages/Deploy/Environment/List/types.ts index 4e753859..b34c0941 100644 --- a/frontend/src/pages/Deploy/Environment/List/types.ts +++ b/frontend/src/pages/Deploy/Environment/List/types.ts @@ -7,6 +7,8 @@ export interface Environment extends BaseResponse { envName: string; envDesc?: string; sort: number; + teamCount?: number; + applicationCount?: number; } // 创建环境请求参数 diff --git a/frontend/src/pages/Deploy/ScheduleJob/List/index.tsx b/frontend/src/pages/Deploy/ScheduleJob/List/index.tsx index 874a485f..9d8bef2b 100644 --- a/frontend/src/pages/Deploy/ScheduleJob/List/index.tsx +++ b/frontend/src/pages/Deploy/ScheduleJob/List/index.tsx @@ -12,7 +12,7 @@ import { Clock, Activity, CheckCircle2, XCircle, FolderKanban, PlayCircle, FileText, BarChart3, List, Ban } from 'lucide-react'; import {useToast} from '@/components/ui/use-toast'; -import {getScheduleJobs, getJobCategoryList, startJob, pauseJob, resumeJob, stopJob, triggerJob, disableJob, deleteScheduleJob, enableJob} from './service'; +import {getScheduleJobs, getJobCategoryList, pauseJob, resumeJob, triggerJob, disableJob, deleteScheduleJob, enableJob} from './service'; import type {ScheduleJobResponse, ScheduleJobQuery, JobCategoryResponse, JobStatus} from './types'; import type {Page} from '@/types/base'; import {DEFAULT_PAGE_SIZE, DEFAULT_CURRENT} from '@/utils/page'; @@ -141,25 +141,6 @@ const ScheduleJobList: React.FC = () => { } }; - // 启动任务 - const handleStart = async (record: ScheduleJobResponse) => { - try { - await startJob(record.id); - toast({ - title: '启动成功', - description: `任务 "${record.jobName}" 已启动`, - }); - loadData(); - } catch (error) { - console.error('启动失败:', error); - toast({ - variant: 'destructive', - title: '启动失败', - description: error instanceof Error ? error.message : '未知错误', - }); - } - }; - // 暂停任务 const handlePause = async (record: ScheduleJobResponse) => { try { @@ -198,25 +179,6 @@ const ScheduleJobList: React.FC = () => { } }; - // 停止任务 - const handleStop = async (record: ScheduleJobResponse) => { - try { - await stopJob(record.id); - toast({ - title: '停止成功', - description: `任务 "${record.jobName}" 已停止`, - }); - loadData(); - } catch (error) { - console.error('停止失败:', error); - toast({ - variant: 'destructive', - title: '停止失败', - description: error instanceof Error ? error.message : '未知错误', - }); - } - }; - // 立即触发任务 const handleTrigger = async (record: ScheduleJobResponse) => { try { diff --git a/frontend/src/pages/Deploy/Server/List/components/ServerCard.tsx b/frontend/src/pages/Deploy/Server/List/components/ServerCard.tsx index 482af3fc..83f3dac5 100644 --- a/frontend/src/pages/Deploy/Server/List/components/ServerCard.tsx +++ b/frontend/src/pages/Deploy/Server/List/components/ServerCard.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { - Server, Cpu, HardDrive, MemoryStick, @@ -62,7 +61,7 @@ export const ServerCard: React.FC = ({ server.status === 'OFFLINE' ? 'bg-red-500/10 text-red-700 border-red-500/30 dark:text-red-400' : 'bg-gray-500/10 text-gray-700 border-gray-500/30 dark:text-gray-400' }`}> - {ServerStatusLabels[server.status]?.label || server.status} + {(server.status && ServerStatusLabels[server.status]?.label) || server.status || '-'} {server.categoryName && ( @@ -94,7 +93,7 @@ export const ServerCard: React.FC = ({ )} {server.osType && (
- {OsTypeLabels[server.osType]?.label || server.osType} + {(server.osType && OsTypeLabels[server.osType]?.label) || server.osType || '-'} {server.osVersion && ` ${server.osVersion}`}
)} @@ -175,7 +174,7 @@ export const ServerCard: React.FC = ({
+ + + 应用名称 + 分支 + 操作 + + + + {envApps(currentConfigEnvId).map((app) => ( + + + {app.applicationName} + + + + {app.branch || '-'} + + + + + + + ))} + + {/* 添加行 */} + {getAvailableApplications(currentConfigEnvId).length > 0 && ( + + + + + + { + setAddForms({ + ...addForms, + [currentConfigEnvId]: { + ...addForms[currentConfigEnvId], + branch: e.target.value, + }, + }); + }} + /> + + + + + + )} + + {envApps(currentConfigEnvId).length === 0 && getAvailableApplications(currentConfigEnvId).length === 0 && ( + + + 所有应用已添加 + + + )} + +
+ )} + + + + ); + })()} +
+ + )} + + {/* Step 3: 配置预览 */} + {currentStep === 3 && ( + + + 配置预览 +

+ 请检查所有配置,确认无误后点击"完成配置" +

+
+ +
+ {selectedEnvs.map((envId) => { + const env = environments.find((e) => e.id === envId); + if (!env) return null; + const config = envConfigs[envId] || { approvalRequired: false, approverUserIds: [] }; + const apps = envApps(envId); + + return ( + + +
+
+ {getEnvIcon(env.envCode)} + {env.envName} +
+ +
+
+ + {/* 审批配置信息 */} +
+ +
+ {config.approvalRequired ? ( + <> + 需要审批 + {config.approverUserIds.length > 0 && ( + + 审批人: + {config.approverUserIds + .map((userId) => { + const user = users.find((u) => u.id === userId); + return user?.nickname || user?.username; + }) + .filter(Boolean) + .join('、')} + + )} + + ) : ( + 无需审批 + )} +
+
+ + {/* 应用配置信息 */} +
+ + {apps.length > 0 ? ( +
+ {apps.map((app) => ( +
+ {app.applicationName} + + {app.branch || '-'} + +
+ ))} +
+ ) : ( +

暂无应用配置

+ )} +
+
+
+ ); + })} +
+
+
+ )} + + + + {/* 底部导航按钮 */} + + + +
+ {currentStep === 2 && ( + + )} + {currentStep < 3 ? ( + + ) : ( + + )} +
+
+ + )} + + + ); +}; + +export default TeamConfigSheet; + diff --git a/frontend/src/pages/Deploy/Team/List/index.tsx b/frontend/src/pages/Deploy/Team/List/index.tsx index 38c7881b..27638569 100644 --- a/frontend/src/pages/Deploy/Team/List/index.tsx +++ b/frontend/src/pages/Deploy/Team/List/index.tsx @@ -5,11 +5,11 @@ import type { TeamResponse, TeamQuery } from './types'; import TeamModal from './components/TeamModal'; import DeleteDialog from './components/DeleteDialog'; import MemberManageDialog from './components/MemberManageDialog'; -import ApplicationManageDialog from './components/ApplicationManageDialog'; import { getUserList } from '@/pages/System/User/service'; import type { UserResponse } from '@/pages/System/User/types'; -import { getApplicationList } from '@/pages/Deploy/Application/List/service'; -import type { Application } from '@/pages/Deploy/Application/List/types'; +import { getEnvironmentList, getApplicationList } from './service'; +import type { Environment, Application } from './types'; +import TeamConfigSheet from './components/TeamConfigSheet'; import { Table, TableHeader, @@ -50,7 +50,7 @@ import { Activity, Server, Database, - Package, + Settings, } from 'lucide-react'; type Column = { @@ -73,8 +73,9 @@ const TeamList: React.FC = () => { const [currentTeam, setCurrentTeam] = useState(); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [memberDialogOpen, setMemberDialogOpen] = useState(false); - const [applicationDialogOpen, setApplicationDialogOpen] = useState(false); + const [configDialogOpen, setConfigDialogOpen] = useState(false); const [users, setUsers] = useState([]); + const [environments, setEnvironments] = useState([]); const [applications, setApplications] = useState([]); const form = useForm({ @@ -119,9 +120,10 @@ const TeamList: React.FC = () => { } }; - // 加载用户列表和应用列表(仅一次) + // 加载基础数据(仅一次) useEffect(() => { loadUsers(); + loadEnvironments(); loadApplications(); }, []); @@ -136,6 +138,17 @@ const TeamList: React.FC = () => { } }; + const loadEnvironments = async () => { + try { + const response = await getEnvironmentList(); + if (response) { + setEnvironments(response); + } + } catch (error) { + console.error('加载环境列表失败:', error); + } + }; + const loadApplications = async () => { try { const response = await getApplicationList(); @@ -175,9 +188,9 @@ const TeamList: React.FC = () => { setMemberDialogOpen(true); }; - const handleManageApplications = (record: TeamResponse) => { + const handleConfig = (record: TeamResponse) => { setCurrentTeam(record); - setApplicationDialogOpen(true); + setConfigDialogOpen(true); }; const handleModalClose = () => { @@ -214,7 +227,7 @@ const TeamList: React.FC = () => { { id: 'memberCount', header: '成员数量', - size: 120, + size: 100, cell: ({ row }) => (
{row.original.memberCount || 0} @@ -222,12 +235,26 @@ const TeamList: React.FC = () => { ), }, { - id: 'applicationCount', - header: '应用数量', - size: 120, + id: 'environmentCount', + header: '环境数量', + size: 100, cell: ({ row }) => (
- {row.original.applicationCount || 0} + + {row.original.environmentCount || 0} + +
+ ), + }, + { + id: 'applicationCount', + header: '应用数量', + size: 100, + cell: ({ row }) => ( +
+ + {row.original.applicationCount || 0} +
), }, @@ -256,9 +283,9 @@ const TeamList: React.FC = () => { 成员 -