def card(title, value, subtitle, bgcolor, color): return { 'widgettype': 'VBox', 'options': {'bgcolor': bgcolor, 'padding': '16px', 'width': '25%', 'border': '1px solid ' + color, 'borderRadius': '8px'}, 'subwidgets': [ {'widgettype': 'Text', 'options': {'text': title, 'cfontsize': 0.7, 'color': '#64748b'}}, {'widgettype': 'Text', 'options': {'text': value, 'cfontsize': 2, 'fontWeight': 'bold', 'color': color}}, {'widgettype': 'Text', 'options': {'text': subtitle, 'cfontsize': 0.7, 'color': '#94a3b8'}} ] } pool_cards = [] cluster_cards = [] storage_txt = '' image_txt = '' # 算力池统计 try: async with DBPools().sqlorContext(get_module_dbname('pcpool')) as sor: pools = await sor.R('compute_pool', {}) total_pools = len(pools or []) active = sum(1 for p in (pools or []) if str(getattr(p,'status','')) == '1') total_cpu = 0; total_gpu = 0; total_mem = 0 alloc_cpu = 0; alloc_gpu = 0; alloc_mem = 0 for p in (pools or []): nodes = await sor.R('compute_node', {'pool_id': p.id}) for n in (nodes or []): cpu = int(getattr(n,'cpu_cores',0) or 0) gpu = int(getattr(n,'gpu_count',0) or 0) mem = int(getattr(n,'memory_gb',0) or 0) total_cpu += cpu; total_gpu += gpu; total_mem += mem if getattr(n,'status','') == 'allocated': alloc_cpu += cpu; alloc_gpu += gpu; alloc_mem += mem pool_cards = [ card('算力池', str(total_pools) + ' 个', str(active) + ' 运行中', '#eff6ff', '#2563eb'), card('CPU', str(total_cpu) + ' 核', '已分配 ' + str(alloc_cpu) + ' 核', '#f5f3ff', '#7c3aed'), card('GPU', str(total_gpu) + ' 个', '已分配 ' + str(alloc_gpu) + ' 个', '#ecfdf5', '#059669'), card('内存', str(total_mem) + ' GB', '已分配 ' + str(alloc_mem) + ' GB', '#fff7ed', '#ea580c') ] except: pool_cards = [card('算力池', '0', '加载失败', '#f1f5f9', '#94a3b8') for _ in range(4)] # 集群统计 try: async with DBPools().sqlorContext(get_module_dbname('pcc')) as sor: clusters = await sor.R('cluster', {}) total = len(clusters or []) running = sum(1 for c in (clusters or []) if getattr(c,'status','') == 'running') deploying = sum(1 for c in (clusters or []) if getattr(c,'status','') == 'deploying') stopped = sum(1 for c in (clusters or []) if getattr(c,'status','') == 'stopped') total_nodes = 0; total_cpu = 0; total_gpu = 0; total_mem = 0 for c in (clusters or []): nodes = await sor.R('cluster_node', {'cluster_id': c.id}) total_nodes += len(nodes or []) for n in (nodes or []): total_cpu += int(getattr(n,'cpu_cores',0) or 0) total_gpu += int(getattr(n,'gpu_count',0) or 0) total_mem += int(getattr(n,'memory_gb',0) or 0) cluster_cards = [ card('集群', str(total) + ' 个', str(running) + '运行/' + str(deploying) + '部署/' + str(stopped) + '停', '#eff6ff', '#2563eb'), card('节点', str(total_nodes) + ' 个', '已加入集群', '#f5f3ff', '#7c3aed'), card('CPU', str(total_cpu) + ' 核', '集群总核数', '#ecfdf5', '#059669'), card('GPU/内存', str(total_gpu) + ' GPU', str(total_mem) + ' GB 内存', '#fff7ed', '#ea580c') ] except: cluster_cards = [card('集群', '0', '加载失败', '#f1f5f9', '#94a3b8') for _ in range(4)] # 存储统计 try: async with DBPools().sqlorContext(get_module_dbname('storage_mgr')) as sor: servers = await sor.R('storage_server', {}) exports = await sor.R('storage_export', {}) storage_txt = '存储: ' + str(len(servers or [])) + ' 服务器, ' + str(len(exports or [])) + ' 导出' except: storage_txt = '存储: 加载失败' # 镜像统计 try: async with DBPools().sqlorContext(get_module_dbname('image_mgr')) as sor: registries = await sor.R('image_registry', {}) images = await sor.R('container_image', {}) image_txt = '镜像: ' + str(len(registries or [])) + ' 仓库, ' + str(len(images or [])) + ' 镜像' except: image_txt = '镜像: 加载失败' return { 'widgettype': 'VBox', 'options': {'padding': '24px', 'spacing': '24px', 'bgcolor': '#f8fafc'}, 'subwidgets': [ {'widgettype': 'Text', 'options': {'text': '资源概览', 'cfontsize': 1.3, 'fontWeight': 'bold', 'color': '#1e293b'}}, {'widgettype': 'Text', 'options': {'text': '算力池', 'cfontsize': 0.9, 'fontWeight': 'bold', 'color': '#64748b'}}, {'widgettype': 'HBox', 'options': {'gap': '16px'}, 'subwidgets': pool_cards}, {'widgettype': 'Text', 'options': {'text': '集群', 'cfontsize': 0.9, 'fontWeight': 'bold', 'color': '#64748b'}}, {'widgettype': 'HBox', 'options': {'gap': '16px'}, 'subwidgets': cluster_cards}, {'widgettype': 'Text', 'options': {'text': '存储与镜像', 'cfontsize': 0.9, 'fontWeight': 'bold', 'color': '#64748b'}}, {'widgettype': 'HBox', 'options': {'gap': '16px'}, 'subwidgets': [ {'widgettype': 'Text', 'options': {'text': storage_txt, 'cfontsize': 0.9, 'color': '#1e293b'}}, {'widgettype': 'Text', 'options': {'text': image_txt, 'cfontsize': 0.9, 'color': '#1e293b'}} ]} ] }