@ -1,49 +1,29 @@
< template >
< template >
< div >
< div >
< back -header >
< back -header >
节点管理 > { { detail . name } }
资源池详情
<!-- < template # extra > -- >
<!-- < el -form -item - - >
<!-- label = "节点调度" -- >
<!-- style = "margin-bottom: 0; margin-right: 20px" -- >
<!-- > -- >
<!-- < el -radio -group - - >
<!-- : disabled = "detail.isExternal" -- >
<!-- v - model = "tempSchedulable" -- >
<!-- size = "small" -- >
<!-- @ change = "onChangeSchedulable" -- >
<!-- > -- >
<!-- < el -radio -button label = "启用" :value ="true" / > -- >
<!-- < el -radio -button label = "禁用" :value ="false" / > -- >
<!-- < / e l - r a d i o - g r o u p > - - >
<!-- < / e l - f o r m - i t e m > - - >
<!-- < / template > -- >
< / b a c k - h e a d e r >
< / b a c k - h e a d e r >
< table -plus : api = "pollApi.getDetailNodeList({ pool_id: route.params.uid })" :columns ="columns"
< block -box class = "node-block" >
: rowAction = "rowAction" : hasPagination = "false" style = "margin-bottom: 15px;" hideTag ref = "table" staticPage
< div class = "node-detail" >
: hasActionBar = "false" >
< div class = "node-detail-left" >
< / t a b l e - p l u s >
< div class = "title" > 详细信息 < / div >
< ul class = "node-detail-info" >
< li v-for ="{ label, value, render } in detailColumns" :key ="label" >
< span class = "label" > { { label } } < / span >
< component v -if = " render " :is ="render(detail)" / >
< span v -else class = "value" > { { detail [ value ] } } < / span >
< / li >
< / ul >
< / div >
< / div >
< / b l o c k - b o x >
< block -box >
< block -box >
< ul class = "card-gauges" >
< ul class = "card-gauges" >
< li v-for ="(item, index) in gaugeConfig " :key ="index" >
< li v-for ="(item, index) in gaugeConfig.slice(0, 4)" :key ="index" >
< template v-if ="!detail.isExternal || i ndex >= 2 ">
< template v-if ="!detail.isExternal || item.title.includes('使用率')" >
< Gauge v -bind = " item " / >
< Gauge v -bind = " item " / >
< / template >
< / template >
< template v -else -if = " detail.isExternal & & index < 2 " >
< template v -else -if = " detail.isExternal & & item.title.includes ( ' 分 配 率 ' ) " >
< el -empty description = "暂无资源分配数据" :image-size ="90" / >
< / template >
< / li >
< / ul >
< ul class = "card-gauges" style = "margin-top: 20px;" >
< li v-for ="(item, index) in gaugeConfig.slice(4, 7)" :key ="index" >
< template v-if ="!detail.isExternal || item.title.includes('使用率')" >
< Gauge v -bind = " item " / >
< / template >
< template v -else -if = " detail.isExternal & & item.title.includes ( ' 分 配 率 ' ) " >
< el -empty description = "暂无资源分配数据" :image-size ="90" / >
< el -empty description = "暂无资源分配数据" :image-size ="90" / >
< / template >
< / template >
< / li >
< / li >
@ -56,14 +36,13 @@
< time -picker v -model = " times " type = "datetimerange" size = "small" / >
< time -picker v -model = " times " type = "datetimerange" size = "small" / >
< / template >
< / template >
< div style = "height: 200px" >
< div style = "height: 200px" >
< echarts -plus
< echarts -plus : options = " getRangeOptions ( {
: options = "
cpu : gaugeConfig [ 7 ] . data ,
getRangeOptions ( {
internal : gaugeConfig [ 8 ] . data ,
core : gaugeConfig [ 0 ] . data ,
core : gaugeConfig [ 4 ] . data ,
memory : gaugeConfig [ 1 ] . data ,
memory : gaugeConfig [ 5 ] . data ,
} )
} )
"
" / >
/ >
< / div >
< / div >
< / b l o c k - b o x >
< / b l o c k - b o x >
< block -box title = "资源使用趋势(%) " >
< block -box title = "资源使用趋势(%) " >
@ -71,14 +50,13 @@
< time -picker v -model = " times " type = "datetimerange" size = "small" / >
< time -picker v -model = " times " type = "datetimerange" size = "small" / >
< / template >
< / template >
< div style = "height: 200px" >
< div style = "height: 200px" >
< echarts -plus
< echarts -plus : options = " getRangeOptions ( {
: options = "
cpu : gaugeConfig [ 0 ] . data ,
getRangeOptions ( {
internal : gaugeConfig [ 1 ] . data ,
core : gaugeConfig [ 2 ] . data ,
core : gaugeConfig [ 6 ] . data ,
memory : gaugeConfig [ 3 ] . data ,
memory : gaugeConfig [ 3 ] . data ,
} )
} )
"
" / >
/ >
< / div >
< / div >
< / b l o c k - b o x >
< / b l o c k - b o x >
< / div >
< / div >
@ -103,7 +81,7 @@
import BackHeader from '@/components/BackHeader.vue' ;
import BackHeader from '@/components/BackHeader.vue' ;
import { useRoute , useRouter } from 'vue-router' ;
import { useRoute , useRouter } from 'vue-router' ;
import BlockBox from '@/components/BlockBox.vue' ;
import BlockBox from '@/components/BlockBox.vue' ;
import { computed , onMounted , ref , watch } from 'vue' ;
import { computed , onMounted , ref , watch } from 'vue' ;
import { Tools } from '@element-plus/icons-vue' ;
import { Tools } from '@element-plus/icons-vue' ;
import CardList from '~/vgpu/views/card/admin/index.vue' ;
import CardList from '~/vgpu/views/card/admin/index.vue' ;
import TaskList from '~/vgpu/views/task/admin/index.vue' ;
import TaskList from '~/vgpu/views/task/admin/index.vue' ;
@ -112,14 +90,19 @@ import useInstantVector from '~/vgpu/hooks/useInstantVector';
import EchartsPlus from '@/components/Echarts-plus.vue' ;
import EchartsPlus from '@/components/Echarts-plus.vue' ;
import TimeSelect from '~/vgpu/components/timeSelect.vue' ;
import TimeSelect from '~/vgpu/components/timeSelect.vue' ;
import nodeApi from '~/vgpu/api/node' ;
import nodeApi from '~/vgpu/api/node' ;
import pollApi from '~/vgpu/api/poll' ;
import { getLineOptions } from '~/vgpu/views/monitor/overview/getOptions' ;
import { getLineOptions } from '~/vgpu/views/monitor/overview/getOptions' ;
import { ElMessage , ElMessageBox } from 'element-plus' ;
import { ElMessage , ElMessageBox } from 'element-plus' ;
import api from '~/vgpu/api/task' ;
import api from '~/vgpu/api/task' ;
import { getRangeOptions } from './getOptions' ;
import { getRangeOptions } from './getOptions' ;
import { getDaysInRange } from "@/utils" ;
import { bytesToGB , roundToDecimal } from "@/utils" ;
import useParentAction from '~/vgpu/hooks/useParentAction' ;
const { sendRouteChange } = useParentAction ( ) ;
const route = useRoute ( ) ;
const route = useRoute ( ) ;
const router = useRouter ( ) ;
const table = ref ( ) ;
const detail = ref ( { } ) ;
const detail = ref ( { } ) ;
@ -132,6 +115,176 @@ const times = ref([start, end]);
const isSchedulable = ref ( true ) ;
const isSchedulable = ref ( true ) ;
const tempSchedulable = ref ( isSchedulable . value ) ;
const tempSchedulable = ref ( isSchedulable . value ) ;
const columns = [
{
title : '节点名称' ,
dataIndex : 'name' ,
render : ( { uid , name } ) => (
< text -plus text = { name } to = { ` /admin/vgpu/node/admin/ ${ uid } ?nodeName= ${ name } ` } / >
) ,
} ,
{
title : '节点 IP' ,
dataIndex : 'ip' ,
} ,
{
title : '节点状态' ,
dataIndex : 'isSchedulable' ,
render : ( { isSchedulable , isExternal } ) => (
< el -tag disable -transitions type = { isExternal ? 'warning' : ( isSchedulable ? 'success' : 'danger' ) } >
{ isExternal ? '未纳管' : ( isSchedulable ? '可调度' : '禁止调度' ) }
< / e l - t a g >
)
/ / f i l t e r s : [
/ / {
/ / t e x t : ' 可 调 度 ' ,
/ / v a l u e : ' t r u e ' ,
/ / } ,
/ / {
/ / t e x t : ' 禁 止 调 度 ' ,
/ / v a l u e : ' f a l s e ' ,
/ / } ,
/ / ] ,
} ,
{
title : '显卡型号' ,
dataIndex : 'type' ,
/ / f i l t e r s : ( d a t a ) = > {
/ / c o n s t r = d a t a . r e d u c e ( ( a l l , i t e m ) = > {
/ / r e t u r n u n i q ( [ . . . a l l , . . . i t e m . t y p e ] ) ;
/ / } , [ ] ) ;
/ /
/ / r e t u r n r . m a p ( ( i t e m ) = > ( { t e x t : i t e m , v a l u e : i t e m } ) ) ;
/ / } ,
} ,
{
title : 'CPU' ,
dataIndex : 'coreTotal' ,
render : ( { coreTotal } ) => ` ${ coreTotal } 核 ` ,
} ,
{
title : '内存' ,
dataIndex : 'memoryTotal' ,
render : ( { memoryTotal } ) => ` ${ bytesToGB ( memoryTotal ) } GiB ` ,
} ,
{
title : '磁盘' ,
dataIndex : 'diskSize' ,
render : ( { diskSize } ) => ` ${ bytesToGB ( diskSize ) } GiB ` ,
} ,
{
title : '所属资源池' ,
dataIndex : 'resourcePools' ,
render : ( { resourcePools } ) => ` ${ resourcePools . join ( '、' ) } ` ,
} ,
{
title : '显卡数量' ,
dataIndex : 'cardCnt' ,
} ,
{
title : 'vGPU' ,
dataIndex : 'used' ,
render : ( { vgpuTotal , vgpuUsed , isExternal } ) => (
< span >
{ isExternal ? '--' : vgpuUsed } / { isExternal ? '--' : vgpuTotal }
< / span >
) ,
} ,
{
title : '算力(已分配/总量)' ,
width : 120 ,
dataIndex : 'used' ,
render : ( { coreTotal , coreUsed , isExternal } ) => (
< span >
{ isExternal ? '--' : coreUsed } / { coreTotal }
< / span >
) ,
} ,
{
title : '显存(已分配/总量)' ,
dataIndex : 'w' ,
width : 120 ,
render : ( { memoryTotal , memoryUsed , isExternal } ) => (
< span >
{ isExternal ? '--' : roundToDecimal ( memoryUsed / 1024 , 1 ) } /
{ roundToDecimal ( memoryTotal / 1024 , 1 ) } GiB
< / span >
) ,
} ,
] ;
const rowAction = [
{
title : '查看详情' ,
onClick : ( row ) => {
sendRouteChange ( ` /admin/vgpu/node/admin/ ${ row . uid } ?nodeName= ${ row . name } ` ) ;
} ,
} ,
{
title : '禁用' ,
hidden : ( row ) => ! row . isSchedulable ,
onClick : async ( row ) => {
ElMessageBox . confirm ( ` 确认对该节点进行禁用操作? ` , '操作确认' , {
confirmButtonText : '确定' ,
cancelButtonText : '取消' ,
type : 'warning' ,
} )
. then ( async ( ) => {
try {
await nodeApi . stop (
{
nodeName : row . name ,
status : 'DISABLED'
}
) . then (
( ) => {
setTimeout ( ( ) => {
ElMessage . success ( '节点禁用成功' ) ;
table . value . fetchData ( ) ;
} , 500 ) ;
}
)
} catch ( error ) {
ElMessage . error ( error . message ) ;
}
} )
. catch ( ( ) => { } ) ;
} ,
} ,
{
title : '开启' ,
hidden : ( row ) => row . isSchedulable ,
disabled : ( row ) => row . isExternal ,
onClick : async ( row ) => {
ElMessageBox . confirm ( ` 确认对该节点进行开启调度操作? ` , '操作确认' , {
confirmButtonText : '确定' ,
cancelButtonText : '取消' ,
type : 'warning' ,
} )
. then ( async ( ) => {
try {
await nodeApi . stop (
{
nodeName : row . name ,
status : 'ENABLE'
}
) . then (
( ) => {
setTimeout ( ( ) => {
ElMessage . success ( '节点开启调度成功' ) ;
table . value . fetchData ( ) ;
} , 500 ) ;
}
)
} catch ( error ) {
ElMessage . error ( error . message ) ;
}
} )
. catch ( ( ) => { } ) ;
} ,
} ,
] ;
const cp = useInstantVector (
const cp = useInstantVector (
[
[
{
{
@ -155,6 +308,46 @@ const cp = useInstantVector(
const gaugeConfig = useInstantVector (
const gaugeConfig = useInstantVector (
[
[
{
title : 'CPU 使用率' ,
percent : 0 ,
query : ` count(node_cpu_seconds_total{mode="idle", instance=~" $ node"}) by (instance)*(1 - avg(rate(node_cpu_seconds_total{mode="idle", instance=~" $ node"}[5m])) by (instance)) ` ,
totalQuery : ` count(node_cpu_seconds_total{mode="idle", instance=~" $ node"}) by (instance) ` ,
percentQuery : ` 100 * (1 - avg by(instance)(irate(node_cpu_seconds_total{mode="idle", instance=~" $ node"}[1m]))) ` ,
total : 0 ,
used : 0 ,
unit : '核' ,
} ,
{
title : '内存 使用率' ,
percent : 0 ,
query : ` avg(node_memory_MemTotal_bytes{instance=~" $ node"} - node_memory_MemAvailable_bytes{instance=~" $ node"}) by (instance) / 1024 / 1024 / 1024 ` ,
totalQuery : ` avg(node_memory_MemTotal_bytes{instance=~" $ node"}) by (instance) / 1024 / 1024 / 1024 ` ,
percentQuery : ` 100 * (1 - node_memory_MemAvailable_bytes{instance=~" $ node"} / node_memory_MemTotal_bytes{instance=~" $ node"}) ` ,
total : 0 ,
used : 0 ,
unit : 'GiB' ,
} ,
{
title : '磁盘 使用率' ,
percent : 0 ,
query : ` sum(node_filesystem_size_bytes{instance=~" $ node", fstype=~"ext4|xfs", mountpoint!~"/var/lib/kubelet/pods.*"} - node_filesystem_free_bytes{instance=~" $ node", fstype=~"ext4|xfs", mountpoint!~"/var/lib/kubelet/pods.*"}) by (instance) / 1024 / 1024 / 1024 ` ,
totalQuery : ` sum(node_filesystem_size_bytes{instance=~" $ node", fstype=~"ext4|xfs", mountpoint!~"/var/lib/kubelet/pods.*"}) by (instance) / 1024 / 1024 / 1024 ` ,
percentQuery : ` ` ,
total : 0 ,
used : 0 ,
unit : 'GiB' ,
} ,
{
title : '显存使用率' ,
percent : 0 ,
query : ` avg(sum(hami_memory_used{node=~" $ node"}) by (instance)) / 1024 ` ,
totalQuery : ` avg(sum(hami_memory_size{node=~" $ node"}) by (instance))/1024 ` ,
percentQuery : ` (avg(sum(hami_memory_used{node=~" $ node"}) by (instance)) / 1024)/(avg(sum(hami_memory_size{node=~" $ node"}) by (instance))/1024)*100 ` ,
total : 0 ,
used : 0 ,
unit : 'GiB' ,
} ,
{
{
title : '算力分配率' ,
title : '算力分配率' ,
percent : 0 ,
percent : 0 ,
@ -186,11 +379,21 @@ const gaugeConfig = useInstantVector(
unit : ' ' ,
unit : ' ' ,
} ,
} ,
{
{
title : ' 显存使用 率',
title : ' CPU 分配 率',
percent : 0 ,
percent : 0 ,
query : ` avg(sum(hami_memory_used{node=~" $ node"}) by (instance)) / 1024 ` ,
query : ` ` ,
totalQuery : ` avg(sum(hami_memory_size{node=~" $ node"}) by (instance))/1024 ` ,
totalQuery : ` ` ,
percentQuery : ` (avg(sum(hami_memory_used{node=~" $ node"}) by (instance)) / 1024)/(avg(sum(hami_memory_size{node=~" $ node"}) by (instance))/1024)*100 ` ,
percentQuery : ` avg(sum(hami_container_vcore_allocated{node=~" $ node"}) by (instance) / sum(hami_core_size{node=~" $ node"}) by (instance) * 100) ` ,
total : 0 ,
used : 0 ,
unit : '核' ,
} ,
{
title : '内存 分配率' ,
percent : 0 ,
query : ` ` ,
totalQuery : ` ` ,
percentQuery : ` avg(sum(hami_container_memory_allocated{node=~" $ node"}) by (instance) / sum(hami_memory_size{node=~" $ node"}) by (instance) * 100) ` ,
total : 0 ,
total : 0 ,
used : 0 ,
used : 0 ,
unit : 'GiB' ,
unit : 'GiB' ,
@ -207,9 +410,9 @@ const detailColumns = [
render : ( { isSchedulable , isExternal } ) => {
render : ( { isSchedulable , isExternal } ) => {
if ( detail . value && detail . value . isSchedulable !== undefined ) {
if ( detail . value && detail . value . isSchedulable !== undefined ) {
return (
return (
< el -tag disable -transitions type = { isExternal ? 'warning' : ( isSchedulable ? 'success' : 'danger' ) } >
< el -tag disable -transitions type = { isExternal ? 'warning' : ( isSchedulable ? 'success' : 'danger' ) } >
{ isExternal ? '未纳管' : ( isSchedulable ? '可调度' : '禁止调度' ) }
{ isExternal ? '未纳管' : ( isSchedulable ? '可调度' : '禁止调度' ) }
< / e l - t a g >
< / e l - t a g >
) ;
) ;
} else {
} else {
return < el -tag disable -transitions size = "small" type = "info" > 加载中 ... < / e l - t a g > ;
return < el -tag disable -transitions size = "small" type = "info" > 加载中 ... < / e l - t a g > ;
@ -230,186 +433,96 @@ const detailColumns = [
label : '操作系统类型' ,
label : '操作系统类型' ,
value : 'operatingSystem' ,
value : 'operatingSystem' ,
render : ( { operatingSystem } ) => (
render : ( { operatingSystem } ) => (
< span >
< span >
{ operatingSystem === '' ? '--' : operatingSystem }
{ operatingSystem === '' ? '--' : operatingSystem }
< / span >
< / span >
) ,
) ,
} ,
} ,
{
{
label : '系统架构' ,
label : '系统架构' ,
value : 'architecture' ,
value : 'architecture' ,
render : ( { architecture } ) => (
render : ( { architecture } ) => (
< span >
< span >
{ architecture === '' ? '--' : architecture }
{ architecture === '' ? '--' : architecture }
< / span >
< / span >
) ,
) ,
} ,
} ,
{
{
label : 'kubelet 版本' ,
label : 'kubelet 版本' ,
value : 'kubeletVersion' ,
value : 'kubeletVersion' ,
render : ( { kubeletVersion } ) => (
render : ( { kubeletVersion } ) => (
< span >
< span >
{ kubeletVersion === '' ? '--' : kubeletVersion }
{ kubeletVersion === '' ? '--' : kubeletVersion }
< / span >
< / span >
) ,
) ,
} ,
} ,
{
{
label : '操作系统版本' ,
label : '操作系统版本' ,
value : 'osImage' ,
value : 'osImage' ,
render : ( { osImage } ) => (
render : ( { osImage } ) => (
< span >
< span >
{ osImage === '' ? '--' : osImage }
{ osImage === '' ? '--' : osImage }
< / span >
< / span >
) ,
) ,
} ,
} ,
{
{
label : '内核版本' ,
label : '内核版本' ,
value : 'kernelVersion' ,
value : 'kernelVersion' ,
render : ( { kernelVersion } ) => (
render : ( { kernelVersion } ) => (
< span >
< span >
{ kernelVersion === '' ? '--' : kernelVersion }
{ kernelVersion === '' ? '--' : kernelVersion }
< / span >
< / span >
) ,
) ,
} ,
} ,
{
{
label : 'kube-proxy 版本' ,
label : 'kube-proxy 版本' ,
value : 'kubeProxyVersion' ,
value : 'kubeProxyVersion' ,
render : ( { kubeProxyVersion } ) => (
render : ( { kubeProxyVersion } ) => (
< span >
< span >
{ kubeProxyVersion === '' ? '--' : kubeProxyVersion }
{ kubeProxyVersion === '' ? '--' : kubeProxyVersion }
< / span >
< / span >
) ,
) ,
} ,
} ,
{
{
label : '容器运行时' ,
label : '容器运行时' ,
value : 'containerRuntimeVersion' ,
value : 'containerRuntimeVersion' ,
render : ( { containerRuntimeVersion } ) => (
render : ( { containerRuntimeVersion } ) => (
< span >
< span >
{ containerRuntimeVersion === '' ? '--' : containerRuntimeVersion }
{ containerRuntimeVersion === '' ? '--' : containerRuntimeVersion }
< / span >
< / span >
) ,
) ,
} ,
} ,
{
{
label : '显卡数量' ,
label : '显卡数量' ,
value : 'cardCnt' ,
value : 'cardCnt' ,
render : ( { cardCnt } ) => (
render : ( { cardCnt } ) => (
< span >
< span >
{ cardCnt === '' ? '--' : cardCnt }
{ cardCnt === '' ? '--' : cardCnt }
< / span >
< / span >
) ,
) ,
} ,
} ,
{
{
label : '创建时间' ,
label : '创建时间' ,
value : 'creationTimestamp' ,
value : 'creationTimestamp' ,
render : ( { creationTimestamp } ) => (
render : ( { creationTimestamp } ) => (
< span >
< span >
{ creationTimestamp === '' ? '--' : creationTimestamp }
{ creationTimestamp === '' ? '--' : creationTimestamp }
< / span >
< / span >
) ,
) ,
} ,
} ,
] ;
] ;
const onChangeSchedulable = ( val ) => {
ElMessageBox . confirm (
` 确认对该节点进行 ${ val ? '启用' : '禁用' } 操作? ` ,
'操作确认' ,
{
confirmButtonText : '确定' ,
cancelButtonText : '取消' ,
type : 'warning' ,
} ,
)
. then ( async ( ) => {
try {
await nodeApi
. stop ( {
nodeName : detail . value . name ,
switch : val ? 'off' : 'on' ,
} )
. then ( ( ) => {
setTimeout ( ( ) => {
refresh ( ) ;
ElMessage . success ( ` ${ val ? '启用' : '禁用' } 成功 ` ) ;
} , 500 ) ;
} ) ;
} catch ( error ) {
ElMessage . error ( error . message ) ;
tempSchedulable . value = isSchedulable . value ;
}
} )
. catch ( ( ) => {
tempSchedulable . value = isSchedulable . value ;
} ) ;
} ;
const refresh = async ( ) => {
const refresh = async ( ) => {
detail . value = await nodeApi . getNodeDetail ( { uid : route . params . uid } ) ;
detail . value = await nodeApi . getNodeDetail ( { uid : route . params . uid } ) ;
isSchedulable . value = detail . value . isSchedulable ;
isSchedulable . value = detail . value . isSchedulable ;
} ;
} ;
onMounted ( async ( ) => {
onMounted ( async ( ) => {
await refresh ( ) ;
/ / a w a i t r e f r e s h ( ) ;
} ) ;
} ) ;
< / script >
< / script >
< style lang = "scss" >
< style scoped lang = "scss" >
. node - detail {
display : flex ;
height : 100 % ;
/ / g a p : 5 0 p x ;
ul {
margin : 0 ;
padding : 0 ;
list - style : none ;
}
. title {
color : # 1 d2b3a ;
font - family : 'PingFang SC' ;
font - size : 14 px ;
font - style : normal ;
font - weight : 500 ;
/ / l i n e - h e i g h t : 2 0 p x ;
margin - bottom : 20 px ;
}
/ / . n o d e - d e t a i l - l e f t {
/ / m i n - w i d t h : 8 0 0 p x ;
/ / }
. node - detail - info {
gap : 15 px ;
font - size : 12 px ;
display : grid ;
grid - template - columns : repeat ( 3 , 1 fr ) ;
. label {
display : inline - block ;
width : 100 px ;
height : 20 px ;
color : # 939 ea9 ;
}
. set {
: hover {
cursor : pointer ;
color : # 324558 ;
}
}
. cp {
display : flex ;
gap : 25 px ;
}
}
. gauges {
flex : 1 ;
display : flex ;
li {
flex : 1 ;
}
}
}
. card - gauges {
. card - gauges {
margin : 0 ;
margin : 0 ;
@ -417,8 +530,9 @@ onMounted(async () => {
list - style : none ;
list - style : none ;
display : flex ;
display : flex ;
height : 200 px ;
height : 200 px ;
li {
li {
flex : 1 ;
flex : 0.25 ;
}
}
}
}
@ -431,6 +545,7 @@ onMounted(async () => {
. node - block {
. node - block {
display : flex ;
display : flex ;
flex - direction : column ;
flex - direction : column ;
. home - block - content {
. home - block - content {
flex : 1 ;
flex : 1 ;
}
}