feat: 新增日志中心、功能优化与代码重构

- 新增 log_datasource.go / log_proxy.go / user_api_token.go 后端控制器
- 新增 log_datasource.go model
- 新增 monitor/log-center.ts API 模块
- 新增 LogCenter 前端组件及页面
- 重构 deployment 相关组件 (HPDA/UpdateImageModal/bundle-yaml 等)
- 新增 ResetPasswordDialog / code-snippet-block / copy-button 等 UI 组件
- 重构多个 k8s 相关组件 (TopologyView/ResourceVisualEditor/PodFileBrowser 等)
- 更新多个 API 和工具函数 (auth.ts/monitor/index.ts/request.ts 等)
- 更新静态资源 (index.html + 新 JS/CSS bundle)
- 删除废弃静态资源文件
This commit is contained in:
Logan committed 2026-06-26 23:18:05 +08:00
1 parent 5ca0e6d83a
commit 8d46e8f352
197 files changed
+5014 -815

No files matched your search

@@ -0,0 +1,100 @@
// Deployment 多文档 YAML(Deployment + 关联 Service)加载与保存 // Logan.Li
import { kubernetesApi } from '@/api';
import {
manifestToEditableYaml,
parseEditableManifest,
parseEditableManifests,
prepareManifestForSave,
} from './k8s-manifest-utils';
const toArray = (v: unknown) => (Array.isArray(v) ? v : ((v as Record<string, any>)?.list || (v as Record<string, any>)?.items || (v as Record<string, any>)?.data || []));
/** Service selector 是否匹配 Deployment 标签 // Logan.Li */
export function selectorMatches(
depSelector: Record<string, string>,
svcSelector: Record<string, string>,
): boolean {
if (Object.keys(svcSelector).length === 0) return false;
return Object.entries(svcSelector).every(([k, v]) => depSelector[k] === v);
}
/** 查找与 Deployment 关联的 Service 名称 // Logan.Li */
export function findMatchedServiceNames(
deploymentName: string,
depSelector: Record<string, string>,
services: any[],
): string[] {
const names = new Set<string>();
for (const svc of services) {
const svcName = svc.name || svc.metadata?.name || '';
if (!svcName) continue;
const svcSelector = svc.spec?.selector || svc.selector || {};
if (svcName === deploymentName || selectorMatches(depSelector, svcSelector)) {
names.add(svcName);
}
}
return [...names].sort();
}
/** 加载 Deployment + 关联 Service 的多文档 YAML // Logan.Li */
export async function loadDeploymentBundleYaml(
clusterCode: string,
namespace: string,
deploymentName: string,
): Promise<string> {
const depYaml = await kubernetesApi.getResourceYaml(clusterCode, namespace, 'deployments', deploymentName);
const { manifest: depManifest } = await parseEditableManifest(depYaml);
const depSelector = depManifest?.spec?.selector?.matchLabels
|| depManifest?.spec?.template?.metadata?.labels
|| {};
const svcListRes = await kubernetesApi.getNamespaceServices(clusterCode, namespace).catch(() => []);
const matchedSvcNames = findMatchedServiceNames(deploymentName, depSelector, toArray(svcListRes));
const docs: string[] = [];
if (depManifest) {
docs.push(await manifestToEditableYaml(depManifest));
} else {
const { yaml: stripped } = await parseEditableManifest(depYaml);
if (stripped.trim()) docs.push(stripped);
}
for (const svcName of matchedSvcNames) {
try {
const svcYaml = await kubernetesApi.getResourceYaml(clusterCode, namespace, 'services', svcName);
const { yaml: stripped } = await parseEditableManifest(svcYaml);
if (stripped.trim()) docs.push(stripped);
} catch {
// 单个 Service 拉取失败时跳过 // Logan.Li
}
}
return docs.join('\n---\n');
}
/** 保存多文档 YAML(Deployment + Service 等)// Logan.Li */
export async function saveDeploymentBundleYaml(
clusterCode: string,
namespace: string,
yamlText: string,
): Promise<void> {
const { manifests } = await parseEditableManifests(yamlText);
if (manifests.length === 0) throw new Error('YAML 内容为空或解析失败');
for (const manifest of manifests) {
const kind = String(manifest.kind || '').toLowerCase();
const name = String(manifest.metadata?.name || '').trim();
if (!kind || !name) throw new Error('每个 YAML 文档必须包含 kind 和 metadata.name');
const docYaml = await prepareManifestForSave(manifest);
if (kind === 'deployment') {
await kubernetesApi.updateResourceYaml(clusterCode, namespace, 'deployments', name, docYaml);
continue;
}
if (kind === 'service') {
await kubernetesApi.applyYAML(clusterCode, docYaml);
continue;
}
throw new Error(`不支持的资源类型: ${manifest.kind}(仅支持 Deployment / Service)`);
}
}