fix: overview cards render text not otext

This commit is contained in:
pccs 2026-08-13 11:45:43 +08:00
parent a0ea121602
commit 469f89e1fc
2 changed files with 103 additions and 2 deletions

View File

@ -109,7 +109,7 @@
"name": "dashboard", "name": "dashboard",
"label": "📊 概览", "label": "📊 概览",
"icon": "", "icon": "",
"url": "{{entire_url('/pccs/overview.ui')}}", "url": "{{entire_url('/pccs/overview.dspy')}}",
"target": "app.pccs_main_content" "target": "app.pccs_main_content"
}, },
{ {
@ -204,7 +204,7 @@
{ {
"widgettype": "urlwidget", "widgettype": "urlwidget",
"options": { "options": {
"url": "{{entire_url('/pccs/overview.ui')}}", "url": "{{entire_url('/pccs/overview.dspy')}}",
"width": "100%", "width": "100%",
"height": "100%" "height": "100%"
} }

101
wwwroot/overview.dspy Normal file
View File

@ -0,0 +1,101 @@
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'}}
]}
]
}