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,2 @@
import{j as e,r as p}from"./vendor-codemirror-B1SGo4xl.js";import{C as ae,a as ce,b as Ke,c as Ge,d as Ze}from"./card-CdN7vcLa.js";import{g as qe,f as es,B as S,D as Ve,a as Ne,b as ve,c as Se,d as Ce,e as ss,t as N}from"./index-lgmWPQDG.js";import{I as Ee}from"./input-DBDfXZx0.js";import{L as re}from"./label-Bzhjv1tR.js";import{B as $e}from"./badge-Ca5YHtna.js";import{S as le,a as ie,b as de,c as pe,d as ee}from"./select-Bv_WioDg.js";import{T as ts}from"./textarea-ym7reYBG.js";import{k as _}from"./index-BW7A0O1o.js";import{h as _e,ad as Me,a4 as os,D as ns,N as as,B as cs,i as ue,G as rs,d as De,L as Le,R as ls,n as Re,P as is,ai as Ae,$ as ds,S as ps,T as ms}from"./vendor-icons-BlY7QrxS.js";import"./index-5FEebgvX.js";const me={cluster:"集群",loadbalancer:"Ingress",service:"Service",app:"Deployment",pod:"Pod",server:"Node",database:"数据库",external:"外部服务",custom:"自定义"},us=[{value:"database",label:"数据库",desc:"MySQL / Redis / PostgreSQL 等"},{value:"external",label:"外部服务",desc:"外部 API / CDN / DNS 等"},{value:"custom",label:"自定义",desc:"其他自定义节点"}],Q=x=>x.startsWith("custom-");function z(x,g="h-5 w-5"){switch(x){case"server":return e.jsx(_e,{"code-path":"src/components/kubernetes/topology-helpers.tsx:32:27",className:g});case"loadbalancer":return e.jsx(rs,{"code-path":"src/components/kubernetes/topology-helpers.tsx:33:33",className:g});case"cluster":return e.jsx(ue,{"code-path":"src/components/kubernetes/topology-helpers.tsx:34:28",className:g});case"app":return e.jsx(cs,{"code-path":"src/components/kubernetes/topology-helpers.tsx:35:24",className:g});case"service":return e.jsx(as,{"code-path":"src/components/kubernetes/topology-helpers.tsx:36:28",className:g});case"pod":return e.jsx(Me,{"code-path":"src/components/kubernetes/topology-helpers.tsx:37:24",className:g});case"database":return e.jsx(ns,{"code-path":"src/components/kubernetes/topology-helpers.tsx:38:29",className:g});case"external":return e.jsx(os,{"code-path":"src/components/kubernetes/topology-helpers.tsx:39:29",className:g});case"custom":return e.jsx(Me,{"code-path":"src/components/kubernetes/topology-helpers.tsx:40:27",className:g});default:return e.jsx(_e,{"code-path":"src/components/kubernetes/topology-helpers.tsx:41:21",className:g})}}function se(x){switch(x){case"server":return"bg-blue-500/20 text-blue-400 border-blue-500/30";case"loadbalancer":return"bg-purple-500/20 text-purple-400 border-purple-500/30";case"cluster":return"bg-cyan-500/20 text-cyan-400 border-cyan-500/30";case"app":return"bg-rose-500/20 text-rose-400 border-rose-500/30";case"service":return"bg-emerald-500/20 text-emerald-400 border-emerald-500/30";case"pod":return"bg-teal-500/20 text-teal-400 border-teal-500/30";case"database":return"bg-amber-500/20 text-amber-400 border-amber-500/30";case"external":return"bg-orange-500/20 text-orange-400 border-orange-500/30";case"custom":return"bg-slate-500/20 text-slate-400 border-slate-500/30";default:return"bg-slate-500/20 text-slate-400 border-slate-500/30"}}function hs(x,g,W,U,u,B=[]){const i=[],b=[],G=Math.max(1,g.length,W.length,U.length,B.length||u.length),d=Math.max(900,Math.min(G*140,2600)),T=[50,160,280,410,540,680],M=t=>{const r=Math.min(t,12);if(r===0)return[];if(r===1)return[d/2];const c=d/(r+1);return Array.from({length:r},(l,m)=>c*(m+1))},A=`cluster-${x.id}`;i.push({id:A,name:x.name||"集群",type:"cluster",x:d/2,y:T[0],data:{kind:"cluster",version:x.version,status:x.status,api_server:x.api_server,node_count:x.node_count,pod_count:x.pod_count}});const D=g.slice(0,12),te=M(D.length);D.forEach((t,r)=>{const c=`ingress-${t.id}`,l=Array.isArray(t.hosts)?t.hosts:t.hosts?JSON.parse(t.hosts):[],m=l.length?l.join(","):t.name||"",E=t.paths?t.paths:t.backend?`→${t.backend}`:"",J=E?`${m}
${E}`:m;i.push({id:c,name:J,type:"loadbalancer",x:te[r],y:T[1],data:{kind:"ingress",namespace:t.namespace,backend:t.backend,tls:t.tls,hosts:l}}),b.push({id:`e-${A}-${c}`,source:A,target:c,label:"route"})});const y=W.slice(0,12),Z=M(y.length);y.forEach((t,r)=>{const c=`service-${t.id}`;i.push({id:c,name:t.name,type:"service",x:Z[r],y:T[2],data:{kind:"service",namespace:t.namespace,type:t.type,cluster_ip:t.cluster_ip,external_ip:t.external_ip,selector:t.selector}})}),D.length>0&&y.length>0?D.forEach(t=>{const r=`ingress-${t.id}`,c=(t.backend||"").split(":")[0].trim();let l=y.filter(m=>m.name===c);l.length===0&&(l=y.filter(m=>m.namespace===t.namespace)),l.length===0&&(l=[y[0]]),l.forEach(m=>b.push({id:`e-${r}-service-${m.id}`,source:r,target:`service-${m.id}`,label:"→"}))}):y.length>0&&y.forEach(t=>b.push({id:`e-${A}-service-${t.id}`,source:A,target:`service-${t.id}`,label:"expose"}));const k=U.slice(0,12),oe=M(k.length);k.forEach((t,r)=>{const c=`deploy-${t.id}`;i.push({id:c,name:t.name,type:"app",x:oe[r],y:T[3],data:{kind:"deployment",namespace:t.namespace,replicas:t.replicas,ready_replicas:t.ready_replicas,available_replicas:t.available_replicas,image:t.image}})});const v=(B||[]).slice(0,12),j=M(v.length);v.forEach((t,r)=>{const c=`pod-${t.id||t.name}`;i.push({id:c,name:t.name||"pod",type:"pod",x:j[r],y:T[4],data:{kind:"pod",namespace:t.namespace,node:t.node_name||t.node,status:t.status,ip:t.ip}})}),k.length>0&&v.length>0&&k.forEach(t=>{const r=`deploy-${t.id}`;let c=v.filter(l=>l.namespace===t.namespace);c=c.filter(l=>(l.name||"").includes(t.name)||t.name&&(l.name||"").startsWith(t.name)),c.length===0&&(c=v.filter(l=>l.namespace===t.namespace).slice(0,3)),c.length===0&&(c=v.slice(0,2)),c.slice(0,3).forEach(l=>{const m=`pod-${l.id||l.name}`;b.push({id:`e-${r}-${m}`,source:r,target:m,label:"owns"})})}),y.length>0&&k.length>0&&y.forEach(t=>{const r=`service-${t.id}`;let c=[];try{const l=typeof t.selector=="string"?JSON.parse(t.selector||"{}"):t.selector||{},m=Object.entries(l);m.length>0&&(c=k.filter(E=>{let J={};try{J=typeof E.labels=="string"?JSON.parse(E.labels||"{}"):E.labels||{}}catch{}return m.every(([P,O])=>J[P]===O)}))}catch{}c.length===0&&(c=k.filter(l=>l.name===t.name)),c.length===0&&(c=k.filter(l=>l.namespace===t.namespace)),c.length===0&&(c=[k[0]]),c.slice(0,4).forEach(l=>b.push({id:`e-${r}-deploy-${l.id}`,source:r,target:`deploy-${l.id}`,label:"select"}))});const L=u.slice(0,12),V=M(L.length);L.forEach((t,r)=>{const c=`k8snode-${t.id}`;i.push({id:c,name:t.name,type:"server",x:V[r],y:T[5],data:{kind:"node",ip:t.ip,role:t.role,status:t.status,os:t.os,cpu:t.cpu,memory:t.memory,cpu_usage:t.cpu_usage,memory_usage:t.memory_usage,pod_count:t.pod_count}})});const I=L.filter(t=>(t.role||"").toLowerCase()==="worker"),C=I.length>0?I:L;return v.length>0&&C.length>0?v.forEach(t=>{const r=`pod-${t.id||t.name}`;C.slice(0,2).forEach(c=>b.push({id:`e-${r}-k8snode-${c.id}`,source:r,target:`k8snode-${c.id}`,label:"on"}))}):k.length>0&&C.length>0&&k.forEach(t=>{const r=`deploy-${t.id}`;C.slice(0,3).forEach(c=>b.push({id:`e-${r}-k8snode-${c.id}`,source:r,target:`k8snode-${c.id}`,label:"schedule"}))}),{nodes:i,edges:b}}function vs(){const{clusterCode:x}=qe(),g=es(),[W,U]=p.useState([]),[u,B]=p.useState(""),[i,b]=p.useState({nodes:[],edges:[]}),[F,G]=p.useState(!1),[d,T]=p.useState(null),[M,A]=p.useState(""),[D,te]=p.useState("all"),[y,Z]=p.useState(null),[k,oe]=p.useState({x:0,y:0}),v=p.useRef(null),[j,L]=p.useState(!1),[V,I]=p.useState(!1),[C,t]=p.useState(null),[,r]=p.useState(null),[c,l]=p.useState(!1),[m,E]=p.useState(1),[J,P]=p.useState(!1),[O,he]=p.useState(null),[w,H]=p.useState({name:"",type:"database",note:""}),xe=p.useCallback(async()=>{try{const n=(await _.getClusters())?.list||[];if(U(n),!u)if(x){const o=n.find(a=>(a.code||String(a.id))===x);o&&B(String(o.id))}else n.length>0&&B(String(n[0].id))}catch{U([])}},[x]);p.useEffect(()=>{xe()},[xe]);const ge=p.useCallback(async s=>{try{const o=await _.getTopology(s);if(o?.layout_data){const a=JSON.parse(o.layout_data);if(r(a),a.customNodes?.length>0){const h=Math.max(...a.customNodes.map(f=>{const R=f.id.match(/custom-(\d+)/);return R?parseInt(R[1]):0}));E(h+1)}return a}}catch{}return r(null),null},[]),K=p.useCallback(async()=>{if(u){G(!0);try{const s=$=>Array.isArray($)?$:$?.list||[],[n,o,a,h,f]=await Promise.all([_.getNodes(u).catch(()=>[]),_.getServices(u).catch(()=>[]),_.getDeployments(u).catch(()=>[]),_.getIngresses(u).catch(()=>[]),_.getPods(u).catch(()=>[])]),R=W.find($=>String($.id)===u)||{},X=hs(R,s(h),s(o),s(a),s(n),s(f)),Y=await ge(u);Y&&(Y.positions&&(X.nodes=X.nodes.map($=>{const ne=Y.positions[$.id];return ne?{...$,x:ne.x,y:ne.y}:$})),Y.customNodes&&(X.nodes=[...X.nodes,...Y.customNodes]),Y.customEdges&&(X.edges=[...X.edges,...Y.customEdges])),b(X)}catch{b({nodes:[],edges:[]})}finally{G(!1)}}},[u,W,ge]);p.useEffect(()=>{K()},[K]);const q=i.nodes.filter(s=>s.name.toLowerCase().includes(M.toLowerCase())&&(D==="all"||s.type===D)),be=new Set(q.map(s= Line truncated