diff --git a/frontend/src/pages/Resource/K8s/List/components/DeploymentRow.tsx b/frontend/src/pages/Resource/K8s/List/components/DeploymentRow.tsx index 0d7aca0c..1e936eb0 100644 --- a/frontend/src/pages/Resource/K8s/List/components/DeploymentRow.tsx +++ b/frontend/src/pages/Resource/K8s/List/components/DeploymentRow.tsx @@ -35,7 +35,7 @@ import { PodRowSkeleton } from './PodRowSkeleton'; import { YamlViewerDialog } from './YamlViewerDialog'; import { restartK8sDeployment, scaleK8sDeployment, deleteK8sDeployment } from '../service'; import type { K8sDeploymentResponse, K8sPodResponse } from '../types'; -import { getDeploymentHealth, HealthStatusLabels } from '../types'; +import { getDeploymentHealth } from '../types'; import { getK8sPodsByDeployment } from '../service'; import { useAutoRefresh } from '../hooks/useAutoRefresh'; import { formatCpuPair } from '../utils/resourceFormatter'; @@ -64,6 +64,7 @@ export const DeploymentRow: React.FC = ({ const { toast } = useToast(); const [pods, setPods] = useState([]); const [initialLoading, setInitialLoading] = useState(true); + const [restartDialogOpen, setRestartDialogOpen] = useState(false); const [scaleDialogOpen, setScaleDialogOpen] = useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [yamlDialogOpen, setYamlDialogOpen] = useState(false); @@ -130,6 +131,7 @@ export const DeploymentRow: React.FC = ({ }); } finally { setLoading(false); + setRestartDialogOpen(false); } }; @@ -292,8 +294,7 @@ export const DeploymentRow: React.FC = ({ + + + + + {/* 扩缩容对话框 */} diff --git a/frontend/src/pages/Resource/K8s/List/utils/resourceFormatter.ts b/frontend/src/pages/Resource/K8s/List/utils/resourceFormatter.ts new file mode 100644 index 00000000..e72fab86 --- /dev/null +++ b/frontend/src/pages/Resource/K8s/List/utils/resourceFormatter.ts @@ -0,0 +1,129 @@ +/** + * 解析CPU值为核数 + * @param value CPU字符串,如 "500m" 或 "1" 或 "1.5" + * @returns 核数(浮点数) + */ +export function parseCpu(value: string): number { + if (!value) return 0; + + const trimmed = value.trim(); + + // 处理毫核(如 "500m") + if (trimmed.endsWith('m')) { + const milliCores = parseFloat(trimmed.slice(0, -1)); + return milliCores / 1000; + } + + // 处理纯数字(如 "1" 或 "1.5") + return parseFloat(trimmed); +} + +/** + * 解析内存值为字节数 + * @param value 内存字符串,如 "512Mi" 或 "1Gi" + * @returns 字节数 + */ +export function parseMemory(value: string): number { + if (!value) return 0; + + const trimmed = value.trim(); + const units: Record = { + 'Ki': 1024, + 'Mi': 1024 * 1024, + 'Gi': 1024 * 1024 * 1024, + 'Ti': 1024 * 1024 * 1024 * 1024, + 'K': 1000, + 'M': 1000 * 1000, + 'G': 1000 * 1000 * 1000, + 'T': 1000 * 1000 * 1000 * 1000, + }; + + for (const [unit, multiplier] of Object.entries(units)) { + if (trimmed.endsWith(unit)) { + const value = parseFloat(trimmed.slice(0, -unit.length)); + return value * multiplier; + } + } + + // 纯数字,默认为字节 + return parseFloat(trimmed); +} + +/** + * 格式化CPU显示(智能统一单位) + * @param request CPU请求值 + * @param limit CPU限制值 + * @returns 格式化后的字符串,如 "0.5 / 1" 或 "500m / 800m" + */ +export function formatCpuPair(request?: string, limit?: string): string { + if (!request && !limit) return '- / -'; + if (!request) return `- / ${limit}`; + if (!limit) return `${request} / -`; + + const reqCores = parseCpu(request); + const limitCores = parseCpu(limit); + + // 如果都小于1核,使用毫核显示 + if (reqCores < 1 && limitCores < 1) { + const reqMilli = Math.round(reqCores * 1000); + const limitMilli = Math.round(limitCores * 1000); + return `${reqMilli}m / ${limitMilli}m`; + } + + // 否则统一使用核数显示 + const formatCore = (cores: number) => { + // 如果是整数,不显示小数点 + if (cores === Math.floor(cores)) { + return cores.toString(); + } + // 保留最多2位小数 + return cores.toFixed(2).replace(/\.?0+$/, ''); + }; + + return `${formatCore(reqCores)} / ${formatCore(limitCores)}`; +} + +/** + * 格式化内存显示(智能统一单位) + * @param request 内存请求值 + * @param limit 内存限制值 + * @returns 格式化后的字符串,如 "0.5Gi / 1Gi" 或 "512Mi / 1024Mi" + */ +export function formatMemoryPair(request?: string, limit?: string): string { + if (!request && !limit) return '- / -'; + if (!request) return `- / ${limit}`; + if (!limit) return `${request} / -`; + + const reqBytes = parseMemory(request); + const limitBytes = parseMemory(limit); + + const units = [ + { name: 'Ti', value: 1024 * 1024 * 1024 * 1024 }, + { name: 'Gi', value: 1024 * 1024 * 1024 }, + { name: 'Mi', value: 1024 * 1024 }, + { name: 'Ki', value: 1024 }, + ]; + + // 选择合适的单位(以较大值为准) + const maxBytes = Math.max(reqBytes, limitBytes); + let selectedUnit = units[units.length - 1]; // 默认Ki + + for (const unit of units) { + if (maxBytes >= unit.value) { + selectedUnit = unit; + break; + } + } + + const formatValue = (bytes: number) => { + const value = bytes / selectedUnit.value; + // 如果是整数,不显示小数点 + if (value === Math.floor(value)) { + return value.toString(); + } + // 保留最多2位小数 + return value.toFixed(2).replace(/\.?0+$/, ''); + }; + + return `${formatValue(reqBytes)}${selectedUnit.name} / ${formatValue(limitBytes)}${selectedUnit.name}`; +}