From 9225414a87bd4dceb43cf83802d2cb7bf60e66d4 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Tue, 16 Dec 2025 10:54:54 +0800 Subject: [PATCH] =?UTF-8?q?1.33=20=E6=97=A5=E5=BF=97=E9=80=9A=E7=94=A8?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dashboard/hooks/usePendingApproval.ts | 19 +- frontend/src/pages/Dashboard/index.tsx | 12 ++ .../List/components/DockerRuntimeConfig.tsx | 85 ++++++++ .../Team/List/components/K8sRuntimeConfig.tsx | 197 ++++++++++++++++++ .../List/components/RuntimeConfigSection.tsx | 114 ++++++++++ .../List/components/ServerRuntimeConfig.tsx | 88 ++++++++ .../List/components/TeamApplicationDialog.tsx | 132 +++++++++++- .../TeamApplicationManageDialog.tsx | 171 ++++++++++++--- frontend/src/pages/Deploy/Team/List/types.ts | 39 ++++ 9 files changed, 825 insertions(+), 32 deletions(-) create mode 100644 frontend/src/pages/Deploy/Team/List/components/DockerRuntimeConfig.tsx create mode 100644 frontend/src/pages/Deploy/Team/List/components/K8sRuntimeConfig.tsx create mode 100644 frontend/src/pages/Deploy/Team/List/components/RuntimeConfigSection.tsx create mode 100644 frontend/src/pages/Deploy/Team/List/components/ServerRuntimeConfig.tsx diff --git a/frontend/src/pages/Dashboard/hooks/usePendingApproval.ts b/frontend/src/pages/Dashboard/hooks/usePendingApproval.ts index ca925613..a5dcbb60 100644 --- a/frontend/src/pages/Dashboard/hooks/usePendingApproval.ts +++ b/frontend/src/pages/Dashboard/hooks/usePendingApproval.ts @@ -6,6 +6,7 @@ interface UsePendingApprovalOptions { teams: DeployTeam[]; currentTeamId?: number | null; // 当前选中的团队ID currentEnvId?: number | null; // 当前选中的环境ID + canApprove?: boolean; // 当前用户是否有审批权限 pollingEnabled?: boolean; pollingInterval?: number; // 轮询间隔,默认30秒 } @@ -20,6 +21,7 @@ export function usePendingApproval({ teams, currentTeamId, currentEnvId, + canApprove = false, pollingEnabled = true, pollingInterval = 30000 // 默认30秒 }: UsePendingApprovalOptions) { @@ -41,7 +43,9 @@ export function usePendingApproval({ // 加载待审批数量 - 使用 useCallback 避免重复创建 const loadPendingApprovalCount = useCallback(async () => { - if (!pollingEnabled || workflowDefinitionKeys.length === 0) { + // 只有当用户有审批权限时才调用接口 + if (!canApprove || !pollingEnabled || workflowDefinitionKeys.length === 0) { + setPendingApprovalCount(0); return; } @@ -59,11 +63,18 @@ export function usePendingApproval({ // 静默失败,不影响主页面 console.error('Failed to load pending approval count:', error); } - }, [workflowDefinitionKeys, currentTeamId, currentEnvId, pollingEnabled]); + }, [canApprove, workflowDefinitionKeys, currentTeamId, currentEnvId, pollingEnabled]); // 轮询待审批数量 useEffect(() => { - if (!pollingEnabled || workflowDefinitionKeys.length === 0) { + // 只有当用户有审批权限时才启动轮询 + if (!canApprove || !pollingEnabled || workflowDefinitionKeys.length === 0) { + // 清除计数并停止轮询 + setPendingApprovalCount(0); + if (intervalRef.current) { + clearInterval(intervalRef.current); + intervalRef.current = null; + } return; } @@ -83,7 +94,7 @@ export function usePendingApproval({ clearInterval(intervalRef.current); } }; - }, [loadPendingApprovalCount, pollingEnabled, workflowDefinitionKeys.length, pollingInterval]); + }, [canApprove, loadPendingApprovalCount, pollingEnabled, workflowDefinitionKeys.length, pollingInterval]); return { approvalModalOpen, diff --git a/frontend/src/pages/Dashboard/index.tsx b/frontend/src/pages/Dashboard/index.tsx index 34f8e2ff..f7ca8358 100644 --- a/frontend/src/pages/Dashboard/index.tsx +++ b/frontend/src/pages/Dashboard/index.tsx @@ -55,10 +55,22 @@ const Dashboard: React.FC = () => { } }); + // 计算当前用户是否有审批权限(需要在 usePendingApproval 之前计算) + const currentCanApprove = React.useMemo(() => { + if (!deploymentData.currentTeam || !deploymentData.currentEnvId) { + return false; + } + const currentEnv = deploymentData.currentTeam.environments.find( + env => env.environmentId === deploymentData.currentEnvId + ); + return currentEnv?.canApprove === true; + }, [deploymentData.currentTeam, deploymentData.currentEnvId]); + const approvalData = usePendingApproval({ teams: deploymentData.teams, currentTeamId: deploymentData.currentTeamId, currentEnvId: deploymentData.currentEnvId, + canApprove: currentCanApprove, pollingEnabled: !deploymentData.loading }); diff --git a/frontend/src/pages/Deploy/Team/List/components/DockerRuntimeConfig.tsx b/frontend/src/pages/Deploy/Team/List/components/DockerRuntimeConfig.tsx new file mode 100644 index 00000000..1929955d --- /dev/null +++ b/frontend/src/pages/Deploy/Team/List/components/DockerRuntimeConfig.tsx @@ -0,0 +1,85 @@ +import React, { useEffect, useState } from 'react'; +import { Label } from '@/components/ui/label'; +import { Input } from '@/components/ui/input'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { getServerList } from '@/pages/Resource/Server/List/service'; +import type { ServerResponse } from '@/pages/Resource/Server/List/types'; + +interface DockerRuntimeConfigProps { + dockerServerId: number | null; + dockerContainerName: string; + onDockerServerChange: (serverId: number | null) => void; + onDockerContainerNameChange: (containerName: string) => void; +} + +export const DockerRuntimeConfig: React.FC = ({ + dockerServerId, + dockerContainerName, + onDockerServerChange, + onDockerContainerNameChange, +}) => { + const [servers, setServers] = useState([]); + const [loading, setLoading] = useState(false); + + useEffect(() => { + loadServers(); + }, []); + + const loadServers = async () => { + setLoading(true); + try { + const result = await getServerList(); + setServers(result || []); + } catch (error) { + console.error('加载服务器列表失败:', error); + setServers([]); + } finally { + setLoading(false); + } + }; + + return ( +
+
+ + +
+ +
+ + onDockerContainerNameChange(e.target.value)} + /> +
+
+ ); +}; diff --git a/frontend/src/pages/Deploy/Team/List/components/K8sRuntimeConfig.tsx b/frontend/src/pages/Deploy/Team/List/components/K8sRuntimeConfig.tsx new file mode 100644 index 00000000..e3a041ca --- /dev/null +++ b/frontend/src/pages/Deploy/Team/List/components/K8sRuntimeConfig.tsx @@ -0,0 +1,197 @@ +import React, { useState, useEffect } from 'react'; +import { Label } from '@/components/ui/label'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { Loader2 } from 'lucide-react'; +import { getExternalSystemList } from '@/pages/Resource/External/List/service'; +import { getK8sNamespaceList, getK8sDeploymentByNamespace } from '@/pages/Resource/K8s/List/service'; + +interface K8sRuntimeConfigProps { + k8sSystemId: number | null; + k8sNamespaceId: number | null; + k8sDeploymentId: number | null; + onK8sSystemChange: (systemId: number | null) => void; + onK8sNamespaceChange: (namespaceId: number | null) => void; + onK8sDeploymentIdChange: (deploymentId: number | null) => void; +} + +export const K8sRuntimeConfig: React.FC = ({ + k8sSystemId, + k8sNamespaceId, + k8sDeploymentId, + onK8sSystemChange, + onK8sNamespaceChange, + onK8sDeploymentIdChange, +}) => { + const [k8sSystems, setK8sSystems] = useState([]); + const [namespaces, setNamespaces] = useState([]); + const [deployments, setDeployments] = useState([]); + const [loadingNamespaces, setLoadingNamespaces] = useState(false); + const [loadingDeployments, setLoadingDeployments] = useState(false); + + // 加载K8S系统列表 + useEffect(() => { + const loadK8sSystems = async () => { + try { + const systems = await getExternalSystemList({ type: 'K8S' }); + setK8sSystems(systems || []); + } catch (error) { + console.error('加载K8S系统失败:', error); + setK8sSystems([]); + } + }; + loadK8sSystems(); + }, []); + + // 加载Namespace列表 + useEffect(() => { + const loadNamespaces = async () => { + if (!k8sSystemId) { + setNamespaces([]); + return; + } + + setLoadingNamespaces(true); + try { + const data = await getK8sNamespaceList(k8sSystemId); + setNamespaces(data || []); + } catch (error) { + console.error('加载Namespace失败:', error); + setNamespaces([]); + } finally { + setLoadingNamespaces(false); + } + }; + loadNamespaces(); + }, [k8sSystemId]); + + // 加载Deployment列表 + useEffect(() => { + const loadDeployments = async () => { + if (!k8sSystemId || !k8sNamespaceId) { + setDeployments([]); + return; + } + + setLoadingDeployments(true); + try { + const data = await getK8sDeploymentByNamespace(k8sSystemId, k8sNamespaceId); + setDeployments(data || []); + } catch (error) { + console.error('加载Deployment失败:', error); + setDeployments([]); + } finally { + setLoadingDeployments(false); + } + }; + loadDeployments(); + }, [k8sSystemId, k8sNamespaceId]); + + return ( +
+
+
+ Kubernetes 配置 +
+ + {/* K8S系统选择 */} +
+ + +
+ + {/* Namespace选择 */} +
+ + +
+ + {/* Deployment选择 */} +
+ + +
+
+ ); +}; diff --git a/frontend/src/pages/Deploy/Team/List/components/RuntimeConfigSection.tsx b/frontend/src/pages/Deploy/Team/List/components/RuntimeConfigSection.tsx new file mode 100644 index 00000000..fbc42583 --- /dev/null +++ b/frontend/src/pages/Deploy/Team/List/components/RuntimeConfigSection.tsx @@ -0,0 +1,114 @@ +import React from 'react'; +import { Label } from '@/components/ui/label'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { K8sRuntimeConfig } from './K8sRuntimeConfig'; +import { DockerRuntimeConfig } from './DockerRuntimeConfig'; +import { ServerRuntimeConfig } from './ServerRuntimeConfig'; +import type { RuntimeType } from '../types'; +import { RUNTIME_TYPE_OPTIONS } from '../types'; + +interface RuntimeConfigSectionProps { + runtimeType: RuntimeType | null; + onRuntimeTypeChange: (type: RuntimeType | null) => void; + // K8S配置 + k8sSystemId: number | null; + k8sNamespaceId: number | null; + k8sDeploymentId: number | null; + onK8sSystemChange: (systemId: number | null) => void; + onK8sNamespaceChange: (namespaceId: number | null) => void; + onK8sDeploymentIdChange: (deploymentId: number | null) => void; + // Docker配置(预留) + dockerServerId?: number | null; + dockerContainerName?: string; + onDockerServerChange?: (serverId: number | null) => void; + onDockerContainerNameChange?: (containerName: string) => void; + // Server配置(预留) + serverId?: number | null; + logQueryCommand?: string; + onServerChange?: (serverId: number | null) => void; + onLogQueryCommandChange?: (command: string) => void; +} + +export const RuntimeConfigSection: React.FC = ({ + runtimeType, + onRuntimeTypeChange, + k8sSystemId, + k8sNamespaceId, + k8sDeploymentId, + onK8sSystemChange, + onK8sNamespaceChange, + onK8sDeploymentIdChange, + dockerServerId, + dockerContainerName, + onDockerServerChange, + onDockerContainerNameChange, + serverId, + logQueryCommand, + onServerChange, + onLogQueryCommandChange, +}) => { + return ( +
+ {/* 运行时类型选择 */} +
+ + +

+ 选择应用的运行时环境类型,用于日志查询和监控 +

+
+ + {/* 根据运行时类型显示对应的配置 */} + {runtimeType === 'K8S' && ( + + )} + + {runtimeType === 'DOCKER' && ( + {})} + onDockerContainerNameChange={onDockerContainerNameChange || (() => {})} + /> + )} + + {runtimeType === 'SERVER' && ( + {})} + onLogQueryCommandChange={onLogQueryCommandChange || (() => {})} + /> + )} +
+ ); +}; diff --git a/frontend/src/pages/Deploy/Team/List/components/ServerRuntimeConfig.tsx b/frontend/src/pages/Deploy/Team/List/components/ServerRuntimeConfig.tsx new file mode 100644 index 00000000..1db6f98b --- /dev/null +++ b/frontend/src/pages/Deploy/Team/List/components/ServerRuntimeConfig.tsx @@ -0,0 +1,88 @@ +import React, { useEffect, useState } from 'react'; +import { Label } from '@/components/ui/label'; +import { Input } from '@/components/ui/input'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { getServerList } from '@/pages/Resource/Server/List/service'; +import type { ServerResponse } from '@/pages/Resource/Server/List/types'; + +interface ServerRuntimeConfigProps { + serverId: number | null; + logQueryCommand: string; + onServerChange: (serverId: number | null) => void; + onLogQueryCommandChange: (command: string) => void; +} + +export const ServerRuntimeConfig: React.FC = ({ + serverId, + logQueryCommand, + onServerChange, + onLogQueryCommandChange, +}) => { + const [servers, setServers] = useState([]); + const [loading, setLoading] = useState(false); + + useEffect(() => { + loadServers(); + }, []); + + const loadServers = async () => { + setLoading(true); + try { + const result = await getServerList(); + setServers(result || []); + } catch (error) { + console.error('加载服务器列表失败:', error); + setServers([]); + } finally { + setLoading(false); + } + }; + + return ( +
+
+ + +
+ +
+ + onLogQueryCommandChange(e.target.value)} + /> +

+ 用于查询应用日志的Shell命令 +

+
+
+ ); +}; diff --git a/frontend/src/pages/Deploy/Team/List/components/TeamApplicationDialog.tsx b/frontend/src/pages/Deploy/Team/List/components/TeamApplicationDialog.tsx index bca766ff..75ab5133 100644 --- a/frontend/src/pages/Deploy/Team/List/components/TeamApplicationDialog.tsx +++ b/frontend/src/pages/Deploy/Team/List/components/TeamApplicationDialog.tsx @@ -26,8 +26,10 @@ import type { TeamApplication, Application, BuildType, + RuntimeType, } from '../types'; import { BUILD_TYPE_OPTIONS } from '../types'; +import { RuntimeConfigSection } from './RuntimeConfigSection'; import type { RepositoryBranchResponse } from '@/pages/Resource/Git/List/types'; import type { WorkflowDefinition } from '@/pages/Workflow/Definition/List/types'; import { getExternalSystemList } from '@/pages/Resource/External/List/service'; @@ -57,9 +59,18 @@ interface TeamApplicationDialogProps { workflowDefinitionId: number | null; sourceGitSystemId: number | null; sourceGitProjectId: number | null; - targetGitSystemId: number | null; // 🆕 目标Git系统ID - targetGitProjectId: number | null; // 🆕 目标Git项目ID - targetBranch: string; // 🆕 目标分支 + targetGitSystemId: number | null; + targetGitProjectId: number | null; + targetBranch: string; + // 运行时配置 + runtimeType: RuntimeType | null; + k8sSystemId: number | null; + k8sNamespaceId: number | null; + k8sDeploymentId: number | null; + dockerServerId: number | null; + dockerContainerName: string; + serverId: number | null; + logQueryCommand: string; }) => Promise; onLoadBranches: (appId: number, app: Application) => Promise; onLoadJenkinsJobs: (systemId: number) => Promise; @@ -97,6 +108,15 @@ const TeamApplicationDialog: React.FC = ({ targetGitSystemId: null as number | null, // 目标Git系统ID targetGitProjectId: null as number | null, // 目标Git项目ID targetBranch: '', // 目标分支名称 + // 运行时配置 + runtimeType: null as RuntimeType | null, // 运行时类型 + k8sSystemId: null as number | null, // K8S系统ID + k8sNamespaceId: null as number | null, // K8S命名空间ID + k8sDeploymentId: null as number | null, // K8S Deployment ID + dockerServerId: null as number | null, // Docker服务器ID + dockerContainerName: '', // Docker容器名称 + serverId: null as number | null, // 服务器ID + logQueryCommand: '', // 日志查询命令 }); // 加载状态 @@ -137,6 +157,15 @@ const TeamApplicationDialog: React.FC = ({ targetGitSystemId: application.targetGitSystemId || null, targetGitProjectId: application.targetGitProjectId || null, targetBranch: application.targetBranch || '', + // 运行时配置 + runtimeType: application.runtimeType || null, + k8sSystemId: application.k8sSystemId || null, + k8sNamespaceId: application.k8sNamespaceId || null, + k8sDeploymentId: application.k8sDeploymentId || null, + dockerServerId: application.dockerServerId || null, + dockerContainerName: application.dockerContainerName || '', + serverId: application.serverId || null, + logQueryCommand: application.logQueryCommand || '', }); // 加载源仓库项目 @@ -184,6 +213,15 @@ const TeamApplicationDialog: React.FC = ({ targetGitSystemId: null, targetGitProjectId: null, targetBranch: '', + // 运行时配置 + runtimeType: null, + k8sSystemId: null, + k8sNamespaceId: null, + k8sDeploymentId: null, + dockerServerId: null, + dockerContainerName: '', + serverId: null, + logQueryCommand: '', }); setBranches([]); setJenkinsJobs([]); @@ -279,6 +317,15 @@ const TeamApplicationDialog: React.FC = ({ targetGitSystemId: null, targetGitProjectId: null, targetBranch: '', + // 保留运行时配置 + runtimeType: formData.runtimeType, + k8sSystemId: formData.k8sSystemId, + k8sNamespaceId: formData.k8sNamespaceId, + k8sDeploymentId: formData.k8sDeploymentId, + dockerServerId: formData.dockerServerId, + dockerContainerName: formData.dockerContainerName, + serverId: formData.serverId, + logQueryCommand: formData.logQueryCommand, }); // 清空分支列表(分支现在基于代码源,不基于应用) setBranches([]); @@ -435,6 +482,34 @@ const TeamApplicationDialog: React.FC = ({ } } + // 运行时配置验证 + if (formData.runtimeType === 'K8S') { + if (!formData.k8sSystemId) { + toast({ + variant: 'destructive', + title: '请选择K8S系统', + description: '已选择K8S运行时类型,必须配置K8S系统', + }); + return; + } + if (!formData.k8sNamespaceId) { + toast({ + variant: 'destructive', + title: '请选择Namespace', + description: '已选择K8S运行时类型,必须配置Namespace', + }); + return; + } + if (!formData.k8sDeploymentId) { + toast({ + variant: 'destructive', + title: '请选择Deployment', + description: '已选择K8S运行时类型,必须配置Deployment', + }); + return; + } + } + setSaving(true); try { await onSave({ @@ -450,6 +525,15 @@ const TeamApplicationDialog: React.FC = ({ targetGitSystemId: formData.targetGitSystemId, targetGitProjectId: formData.targetGitProjectId, targetBranch: formData.targetBranch, + // 运行时配置 + runtimeType: formData.runtimeType, + k8sSystemId: formData.k8sSystemId, + k8sNamespaceId: formData.k8sNamespaceId, + k8sDeploymentId: formData.k8sDeploymentId, + dockerServerId: formData.dockerServerId, + dockerContainerName: formData.dockerContainerName, + serverId: formData.serverId, + logQueryCommand: formData.logQueryCommand, }); toast({ @@ -783,6 +867,48 @@ const TeamApplicationDialog: React.FC = ({
+ + {/* 运行时配置 */} + { + setFormData({ + ...formData, + runtimeType: type, + // 切换类型时清空所有运行时配置 + k8sSystemId: null, + k8sNamespaceId: null, + k8sDeploymentId: null, + dockerServerId: null, + dockerContainerName: '', + serverId: null, + logQueryCommand: '', + }); + }} + k8sSystemId={formData.k8sSystemId} + k8sNamespaceId={formData.k8sNamespaceId} + k8sDeploymentId={formData.k8sDeploymentId} + onK8sSystemChange={(systemId) => setFormData(prev => ({ + ...prev, + k8sSystemId: systemId, + k8sNamespaceId: null, + k8sDeploymentId: null + }))} + onK8sNamespaceChange={(namespaceId) => setFormData(prev => ({ + ...prev, + k8sNamespaceId: namespaceId, + k8sDeploymentId: null + }))} + onK8sDeploymentIdChange={(deploymentId) => setFormData(prev => ({ ...prev, k8sDeploymentId: deploymentId }))} + dockerServerId={formData.dockerServerId} + dockerContainerName={formData.dockerContainerName} + onDockerServerChange={(serverId) => setFormData(prev => ({ ...prev, dockerServerId: serverId }))} + onDockerContainerNameChange={(containerName) => setFormData(prev => ({ ...prev, dockerContainerName: containerName }))} + serverId={formData.serverId} + logQueryCommand={formData.logQueryCommand} + onServerChange={(serverId) => setFormData(prev => ({ ...prev, serverId: serverId }))} + onLogQueryCommandChange={(command) => setFormData(prev => ({ ...prev, logQueryCommand: command }))} + /> diff --git a/frontend/src/pages/Deploy/Team/List/components/TeamApplicationManageDialog.tsx b/frontend/src/pages/Deploy/Team/List/components/TeamApplicationManageDialog.tsx index fdf55f30..81000fbf 100644 --- a/frontend/src/pages/Deploy/Team/List/components/TeamApplicationManageDialog.tsx +++ b/frontend/src/pages/Deploy/Team/List/components/TeamApplicationManageDialog.tsx @@ -12,7 +12,7 @@ import { Button } from '@/components/ui/button'; import { useToast } from '@/components/ui/use-toast'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; import { PaginatedTable, type ColumnDef, type PaginatedTableRef } from '@/components/ui/paginated-table'; -import { Plus, Edit, Trash2, GitBranch } from 'lucide-react'; +import { Plus, Edit, Trash2, GitBranch, Hammer, Box, Container, Server } from 'lucide-react'; import type { Environment } from '@/pages/Deploy/Environment/List/types'; import type { TeamApplication, Application } from '../types'; import type { WorkflowDefinition } from '@/pages/Workflow/Definition/List/types'; @@ -129,9 +129,18 @@ export const TeamApplicationManageDialog: React.FC< workflowDefinitionId: number | null; sourceGitSystemId: number | null; sourceGitProjectId: number | null; - targetGitSystemId: number | null; // 🆕 目标Git系统ID - targetGitProjectId: number | null; // 🆕 目标Git项目ID - targetBranch: string; // 🆕 目标分支 + targetGitSystemId: number | null; + targetGitProjectId: number | null; + targetBranch: string; + // 运行时配置 + runtimeType: 'K8S' | 'DOCKER' | 'SERVER' | null; + k8sSystemId: number | null; + k8sNamespaceId: number | null; + k8sDeploymentId: number | null; + dockerServerId: number | null; + dockerContainerName: string; + serverId: number | null; + logQueryCommand: string; }) => { if (!editingEnvironment) return; @@ -147,10 +156,19 @@ export const TeamApplicationManageDialog: React.FC< workflowDefinitionId: data.workflowDefinitionId || undefined, sourceGitSystemId: data.sourceGitSystemId || undefined, sourceGitProjectId: data.sourceGitProjectId || undefined, - // 🆕 目标Git相关字段 + // 目标Git相关字段 targetGitSystemId: data.targetGitSystemId || undefined, targetGitProjectId: data.targetGitProjectId || undefined, targetBranch: data.targetBranch || undefined, + // 运行时配置字段 + runtimeType: data.runtimeType || undefined, + k8sSystemId: data.k8sSystemId || undefined, + k8sNamespaceId: data.k8sNamespaceId || undefined, + k8sDeploymentId: data.k8sDeploymentId || undefined, + dockerServerId: data.dockerServerId || undefined, + dockerContainerName: data.dockerContainerName || undefined, + serverId: data.serverId || undefined, + logQueryCommand: data.logQueryCommand || undefined, }; if (appDialogMode === 'edit' && data.id) { @@ -295,26 +313,50 @@ export const TeamApplicationManageDialog: React.FC< }, }, { - key: 'buildType', - title: '构建类型', - width: '120px', - render: (_, app) => - app.buildType === 'JENKINS' ? 'Jenkins构建' : app.buildType === 'NATIVE' ? '脚本部署' : '-', - }, - { - 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: 'buildConfig', + title: '构建配置', + width: '250px', + render: (_, app) => { + if (!app.buildType) { + return -; + } + + // Jenkins 构建 + if (app.buildType === 'JENKINS') { + return ( +
+
+ + + Jenkins构建 + +
+
+ {app.deploySystemName || '-'} +
+ {app.deployJob && ( +
+ {app.deployJob} +
+ )} +
+ ); + } + + // 脚本部署 + if (app.buildType === 'NATIVE') { + return ( +
+ + + 脚本部署 + +
+ ); + } + + return -; + }, }, { key: 'workflowDefinitionName', @@ -323,6 +365,85 @@ export const TeamApplicationManageDialog: React.FC< width: '180px', render: (value) => value || '-', }, + { + key: 'runtimeConfig', + title: '运行时配置', + width: '250px', + render: (_, app) => { + if (!app.runtimeType) { + return -; + } + + // K8S 运行时配置 + if (app.runtimeType === 'K8S') { + const k8sPath = [ + app.k8sSystemName, + app.k8sNamespaceName, + app.k8sDeploymentName + ].filter(Boolean).join(' / ') || '-'; + + return ( +
+
+ + + Kubernetes + +
+
+ {k8sPath} +
+
+ ); + } + + // Docker 运行时配置 + if (app.runtimeType === 'DOCKER') { + return ( +
+
+ + + Docker + +
+
+ {app.dockerServerName || '-'} +
+ {app.dockerContainerName && ( +
+ {app.dockerContainerName} +
+ )} +
+ ); + } + + // Server 运行时配置 + if (app.runtimeType === 'SERVER') { + return ( +
+
+ + + 服务器 + +
+
+ {app.serverName || '-'} +
+ {app.logQueryCommand && ( +
+ {app.logQueryCommand} +
+ )} +
+ ); + } + + return -; + }, + }, { key: 'actions', title: '操作', diff --git a/frontend/src/pages/Deploy/Team/List/types.ts b/frontend/src/pages/Deploy/Team/List/types.ts index c478d3bf..6eb596e5 100644 --- a/frontend/src/pages/Deploy/Team/List/types.ts +++ b/frontend/src/pages/Deploy/Team/List/types.ts @@ -172,6 +172,20 @@ export const BUILD_TYPE_OPTIONS = [ { value: 'NATIVE', label: '脚本部署' }, ] as const; +/** + * 运行时类型枚举 + */ +export type RuntimeType = 'K8S' | 'DOCKER' | 'SERVER'; + +/** + * 运行时类型选项 + */ +export const RUNTIME_TYPE_OPTIONS = [ + { value: 'K8S', label: 'Kubernetes' }, + { value: 'DOCKER', label: 'Docker' }, + { value: 'SERVER', label: '服务器' }, +] as const; + /** * 团队应用关联响应 */ @@ -189,6 +203,16 @@ export interface TeamApplication extends BaseResponse { targetGitSystemId?: number; // 目标Git系统ID(仅SYNC_MODE) targetGitProjectId?: number; // 目标Git项目ID targetBranch?: string; // 目标分支名称 + // 运行时配置字段 + runtimeType?: RuntimeType; // 运行时类型 + k8sSystemId?: number; // K8S系统ID + k8sNamespaceId?: number; // K8S命名空间ID + k8sDeploymentId?: number; // K8S Deployment ID + dockerServerId?: number; // Docker服务器ID + dockerContainerName?: string; // Docker容器名称 + serverId?: number; // 服务器ID + logQueryCommand?: string; // 日志查询命令(Server类型使用) + // 关联数据 teamName?: string; applicationName?: string; applicationCode?: string; @@ -199,6 +223,12 @@ export interface TeamApplication extends BaseResponse { sourceGitProjectName?: string; // 源Git项目名称 targetGitSystemName?: string; // 目标Git系统名称 targetGitProjectName?: string; // 目标Git项目名称 + // 运行时配置关联数据 + k8sSystemName?: string; // K8S系统名称 + k8sNamespaceName?: string; // K8S命名空间名称 + k8sDeploymentName?: string; // K8S Deployment名称 + dockerServerName?: string; // Docker服务器名称 + serverName?: string; // 服务器名称 } /** @@ -218,5 +248,14 @@ export interface TeamApplicationRequest { targetGitSystemId?: number; // 目标Git系统ID(仅SYNC_MODE) targetGitProjectId?: number; // 目标Git项目ID targetBranch?: string; // 目标分支名称 + // 运行时配置字段 + runtimeType?: RuntimeType; // 运行时类型 + k8sSystemId?: number; // K8S系统ID + k8sNamespaceId?: number; // K8S命名空间ID + k8sDeploymentId?: number; // K8S Deployment ID + dockerServerId?: number; // Docker服务器ID + dockerContainerName?: string; // Docker容器名称 + serverId?: number; // 服务器ID + logQueryCommand?: string; // 日志查询命令(Server类型使用) }