|  |  | <template>
 | 
						
						
						
							|  |  |   <div>
 | 
						
						
						
							|  |  |     <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" />-->
 | 
						
						
						
							|  |  |       <!--          </el-radio-group>-->
 | 
						
						
						
							|  |  |       <!--        </el-form-item>-->
 | 
						
						
						
							|  |  |       <!--      </template>-->
 | 
						
						
						
							|  |  |     </back-header>
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     <block-box class="node-block">
 | 
						
						
						
							|  |  |       <div class="node-detail">
 | 
						
						
						
							|  |  |         <div class="node-detail-left">
 | 
						
						
						
							|  |  |           <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>
 | 
						
						
						
							|  |  |     </block-box>
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     <block-box>
 | 
						
						
						
							|  |  |       <ul class="card-gauges">
 | 
						
						
						
							|  |  |         <li v-for="(item, index) in gaugeConfig.slice(0, 4)" :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" />
 | 
						
						
						
							|  |  |           </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" />
 | 
						
						
						
							|  |  |           </template>
 | 
						
						
						
							|  |  |         </li>
 | 
						
						
						
							|  |  |       </ul>
 | 
						
						
						
							|  |  |     </block-box>
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     <div class="line-box">
 | 
						
						
						
							|  |  |       <block-box title="资源分配趋势(%)">
 | 
						
						
						
							|  |  |         <template #extra>
 | 
						
						
						
							|  |  |           <time-picker v-model="times" type="datetimerange" size="small" />
 | 
						
						
						
							|  |  |         </template>
 | 
						
						
						
							|  |  |         <div style="height: 200px">
 | 
						
						
						
							|  |  |           <echarts-plus :options="getRangeOptions({
 | 
						
						
						
							|  |  |             cpu: gaugeConfig[7].data,
 | 
						
						
						
							|  |  |             internal: gaugeConfig[8].data,
 | 
						
						
						
							|  |  |             core: gaugeConfig[4].data,
 | 
						
						
						
							|  |  |             memory: gaugeConfig[5].data,
 | 
						
						
						
							|  |  |           })
 | 
						
						
						
							|  |  |             " />
 | 
						
						
						
							|  |  |         </div>
 | 
						
						
						
							|  |  |       </block-box>
 | 
						
						
						
							|  |  |       <block-box title="资源使用趋势(%)">
 | 
						
						
						
							|  |  |         <template #extra>
 | 
						
						
						
							|  |  |           <time-picker v-model="times" type="datetimerange" size="small" />
 | 
						
						
						
							|  |  |         </template>
 | 
						
						
						
							|  |  |         <div style="height: 200px">
 | 
						
						
						
							|  |  |           <echarts-plus :options="getRangeOptions({
 | 
						
						
						
							|  |  |             cpu: gaugeConfig[0].data,
 | 
						
						
						
							|  |  |             internal: gaugeConfig[1].data,
 | 
						
						
						
							|  |  |             core: gaugeConfig[6].data,
 | 
						
						
						
							|  |  |             memory: gaugeConfig[3].data,
 | 
						
						
						
							|  |  |           })
 | 
						
						
						
							|  |  |             " />
 | 
						
						
						
							|  |  |         </div>
 | 
						
						
						
							|  |  |       </block-box>
 | 
						
						
						
							|  |  |     </div>
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     <block-box title="显卡列表">
 | 
						
						
						
							|  |  |       <CardList :hideTitle="true" :filters="{ nodeUid: detail.uid }" />
 | 
						
						
						
							|  |  |     </block-box>
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     <block-box title="任务列表">
 | 
						
						
						
							|  |  |       <template v-if="detail.isExternal">
 | 
						
						
						
							|  |  |         <el-alert title="由于节点未纳管,无法获取到任务数据" show-icon type="warning" :closable="false" />
 | 
						
						
						
							|  |  |         <el-empty description="暂无任务数据" :image-size="100" />
 | 
						
						
						
							|  |  |       </template>
 | 
						
						
						
							|  |  |       <template v-else>
 | 
						
						
						
							|  |  |         <TaskList :hideTitle="true" :filters="{ nodeUid: detail.uid }" />
 | 
						
						
						
							|  |  |       </template>
 | 
						
						
						
							|  |  |     </block-box>
 | 
						
						
						
							|  |  |   </div>
 | 
						
						
						
							|  |  | </template>
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | <script setup lang="jsx">
 | 
						
						
						
							|  |  | import BackHeader from '@/components/BackHeader.vue';
 | 
						
						
						
							|  |  | import { useRoute, useRouter } from 'vue-router';
 | 
						
						
						
							|  |  | import BlockBox from '@/components/BlockBox.vue';
 | 
						
						
						
							|  |  | import { computed, onMounted, ref, watch } from 'vue';
 | 
						
						
						
							|  |  | import { Tools } from '@element-plus/icons-vue';
 | 
						
						
						
							|  |  | import CardList from '~/vgpu/views/card/admin/index.vue';
 | 
						
						
						
							|  |  | import TaskList from '~/vgpu/views/task/admin/index.vue';
 | 
						
						
						
							|  |  | import Gauge from '~/vgpu/components/gauge.vue';
 | 
						
						
						
							|  |  | import useInstantVector from '~/vgpu/hooks/useInstantVector';
 | 
						
						
						
							|  |  | import EchartsPlus from '@/components/Echarts-plus.vue';
 | 
						
						
						
							|  |  | import TimeSelect from '~/vgpu/components/timeSelect.vue';
 | 
						
						
						
							|  |  | import nodeApi from '~/vgpu/api/node';
 | 
						
						
						
							|  |  | import { getLineOptions } from '~/vgpu/views/monitor/overview/getOptions';
 | 
						
						
						
							|  |  | import { ElMessage, ElMessageBox } from 'element-plus';
 | 
						
						
						
							|  |  | import api from '~/vgpu/api/task';
 | 
						
						
						
							|  |  | import { getRangeOptions } from './getOptions';
 | 
						
						
						
							|  |  | import { bytesToGB } from "@/utils";
 | 
						
						
						
							|  |  | import useParentAction from '~/vgpu/hooks/useParentAction';
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | const { sendRouteChange } = useParentAction();
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | const route = useRoute();
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | const detail = ref({});
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | const end = new Date();
 | 
						
						
						
							|  |  | const start = new Date();
 | 
						
						
						
							|  |  | start.setTime(start.getTime() - 3600 * 1000);
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | const times = ref([start, end]);
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | const isSchedulable = ref(true);
 | 
						
						
						
							|  |  | const tempSchedulable = ref(isSchedulable.value);
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | const cp = useInstantVector(
 | 
						
						
						
							|  |  |   [
 | 
						
						
						
							|  |  |     {
 | 
						
						
						
							|  |  |       label: 'vGPU 超配',
 | 
						
						
						
							|  |  |       count: '0',
 | 
						
						
						
							|  |  |       query: `avg(hami_vgpu_count{node=~"$node"})`,
 | 
						
						
						
							|  |  |     },
 | 
						
						
						
							|  |  |     {
 | 
						
						
						
							|  |  |       label: '算力超配',
 | 
						
						
						
							|  |  |       count: '0',
 | 
						
						
						
							|  |  |       query: `avg(hami_vcore_scaling{node=~"$node"})`,
 | 
						
						
						
							|  |  |     },
 | 
						
						
						
							|  |  |     {
 | 
						
						
						
							|  |  |       label: '显存超配',
 | 
						
						
						
							|  |  |       count: '1.5',
 | 
						
						
						
							|  |  |       query: `avg(hami_vmemory_scaling{node=~"$node"})`,
 | 
						
						
						
							|  |  |     },
 | 
						
						
						
							|  |  |   ],
 | 
						
						
						
							|  |  |   (query) => query.replaceAll('$node', detail.value.name),
 | 
						
						
						
							|  |  | );
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | 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: '算力分配率',
 | 
						
						
						
							|  |  |       percent: 0,
 | 
						
						
						
							|  |  |       query: `avg(sum(hami_container_vcore_allocated{node=~"$node"}) by (instance))`,
 | 
						
						
						
							|  |  |       totalQuery: `avg(sum(hami_core_size{node=~"$node"}) by (instance))`,
 | 
						
						
						
							|  |  |       percentQuery: `avg(sum(hami_container_vcore_allocated{node=~"$node"}) by (instance)) / avg(sum(hami_core_size{node=~"$node"}) by (instance)) *100`,
 | 
						
						
						
							|  |  |       total: 0,
 | 
						
						
						
							|  |  |       used: 0,
 | 
						
						
						
							|  |  |       unit: ' ',
 | 
						
						
						
							|  |  |     },
 | 
						
						
						
							|  |  |     {
 | 
						
						
						
							|  |  |       title: '显存分配率',
 | 
						
						
						
							|  |  |       percent: 0,
 | 
						
						
						
							|  |  |       query: `avg(sum(hami_container_vmemory_allocated{node=~"$node"}) by (instance)) / 1024`,
 | 
						
						
						
							|  |  |       totalQuery: `avg(sum(hami_memory_size{node=~"$node"}) by (instance)) / 1024`,
 | 
						
						
						
							|  |  |       percentQuery: `(avg(sum(hami_container_vmemory_allocated{node=~"$node"}) by (instance)) / 1024) /(avg(sum(hami_memory_size{node=~"$node"}) by (instance)) / 1024) *100`,
 | 
						
						
						
							|  |  |       total: 0,
 | 
						
						
						
							|  |  |       used: 0,
 | 
						
						
						
							|  |  |       unit: 'GiB',
 | 
						
						
						
							|  |  |     },
 | 
						
						
						
							|  |  |     {
 | 
						
						
						
							|  |  |       title: '算力使用率',
 | 
						
						
						
							|  |  |       percent: 0,
 | 
						
						
						
							|  |  |       query: `avg(sum(hami_core_util{node=~"$node"}) by (instance))`,
 | 
						
						
						
							|  |  |       percentQuery: `avg(sum(hami_core_util_avg{node=~"$node"}) by (instance))`,
 | 
						
						
						
							|  |  |       totalQuery: `avg(sum(hami_core_size{node=~"$node"}) by (instance))`,
 | 
						
						
						
							|  |  |       total: 100,
 | 
						
						
						
							|  |  |       used: 0,
 | 
						
						
						
							|  |  |       unit: ' ',
 | 
						
						
						
							|  |  |     },
 | 
						
						
						
							|  |  |     {
 | 
						
						
						
							|  |  |       title: 'CPU 分配率',
 | 
						
						
						
							|  |  |       percent: 0,
 | 
						
						
						
							|  |  |       query: ``,
 | 
						
						
						
							|  |  |       totalQuery: ``,
 | 
						
						
						
							|  |  |       percentQuery: `avg(sum(hami_core_used{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_memory_used{node=~"$node"}) by (instance) / sum(hami_memory_size{node=~"$node"}) by (instance) * 100)`,
 | 
						
						
						
							|  |  |       total: 0,
 | 
						
						
						
							|  |  |       used: 0,
 | 
						
						
						
							|  |  |       unit: 'GiB',
 | 
						
						
						
							|  |  |     },
 | 
						
						
						
							|  |  |   ],
 | 
						
						
						
							|  |  |   (query) => query.replaceAll(`$node`, detail.value.name),
 | 
						
						
						
							|  |  |   times,
 | 
						
						
						
							|  |  | );
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | const detailColumns = [
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: '节点状态',
 | 
						
						
						
							|  |  |     value: 'status',
 | 
						
						
						
							|  |  |     width: 100,
 | 
						
						
						
							|  |  |     render: ({ isSchedulable, isExternal }) => {
 | 
						
						
						
							|  |  |       if (detail.value && detail.value.isSchedulable !== undefined) {
 | 
						
						
						
							|  |  |         return (
 | 
						
						
						
							|  |  |           <el-tag disable-transitions type={isExternal ? 'warning' : (isSchedulable ? 'success' : 'danger')}>
 | 
						
						
						
							|  |  |             {isExternal ? '未纳管' : (isSchedulable ? '可调度' : '禁止调度')}
 | 
						
						
						
							|  |  |           </el-tag>
 | 
						
						
						
							|  |  |         );
 | 
						
						
						
							|  |  |       } else {
 | 
						
						
						
							|  |  |         return <el-tag disable-transitions size="small" type="info">加载中...</el-tag>;
 | 
						
						
						
							|  |  |       }
 | 
						
						
						
							|  |  |     },
 | 
						
						
						
							|  |  |   },
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: '节点 IP 地址',
 | 
						
						
						
							|  |  |     value: 'ip',
 | 
						
						
						
							|  |  |     render: ({ ip }) => <text-plus text={ip} copy />,
 | 
						
						
						
							|  |  |   },
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: '节点 UUID',
 | 
						
						
						
							|  |  |     value: 'uid',
 | 
						
						
						
							|  |  |     render: ({ uid }) => <text-plus text={uid} copy />,
 | 
						
						
						
							|  |  |   },
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: '操作系统类型',
 | 
						
						
						
							|  |  |     value: 'operatingSystem',
 | 
						
						
						
							|  |  |     render: ({ operatingSystem }) => (
 | 
						
						
						
							|  |  |       <span>
 | 
						
						
						
							|  |  |         {operatingSystem === '' ? '--' : operatingSystem}
 | 
						
						
						
							|  |  |       </span>
 | 
						
						
						
							|  |  |     ),
 | 
						
						
						
							|  |  |   },
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: '系统架构',
 | 
						
						
						
							|  |  |     value: 'architecture',
 | 
						
						
						
							|  |  |     render: ({ architecture }) => (
 | 
						
						
						
							|  |  |       <span>
 | 
						
						
						
							|  |  |         {architecture === '' ? '--' : architecture}
 | 
						
						
						
							|  |  |       </span>
 | 
						
						
						
							|  |  |     ),
 | 
						
						
						
							|  |  |   },
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: 'kubelet 版本',
 | 
						
						
						
							|  |  |     value: 'kubeletVersion',
 | 
						
						
						
							|  |  |     render: ({ kubeletVersion }) => (
 | 
						
						
						
							|  |  |       <span>
 | 
						
						
						
							|  |  |         {kubeletVersion === '' ? '--' : kubeletVersion}
 | 
						
						
						
							|  |  |       </span>
 | 
						
						
						
							|  |  |     ),
 | 
						
						
						
							|  |  |   },
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: '操作系统版本',
 | 
						
						
						
							|  |  |     value: 'osImage',
 | 
						
						
						
							|  |  |     render: ({ osImage }) => (
 | 
						
						
						
							|  |  |       <span>
 | 
						
						
						
							|  |  |         {osImage === '' ? '--' : osImage}
 | 
						
						
						
							|  |  |       </span>
 | 
						
						
						
							|  |  |     ),
 | 
						
						
						
							|  |  |   },
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: '内核版本',
 | 
						
						
						
							|  |  |     value: 'kernelVersion',
 | 
						
						
						
							|  |  |     render: ({ kernelVersion }) => (
 | 
						
						
						
							|  |  |       <span>
 | 
						
						
						
							|  |  |         {kernelVersion === '' ? '--' : kernelVersion}
 | 
						
						
						
							|  |  |       </span>
 | 
						
						
						
							|  |  |     ),
 | 
						
						
						
							|  |  |   },
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: 'kube-proxy 版本',
 | 
						
						
						
							|  |  |     value: 'kubeProxyVersion',
 | 
						
						
						
							|  |  |     render: ({ kubeProxyVersion }) => (
 | 
						
						
						
							|  |  |       <span>
 | 
						
						
						
							|  |  |         {kubeProxyVersion === '' ? '--' : kubeProxyVersion}
 | 
						
						
						
							|  |  |       </span>
 | 
						
						
						
							|  |  |     ),
 | 
						
						
						
							|  |  |   },
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: 'CPU大小',
 | 
						
						
						
							|  |  |     value: 'cpuCores',
 | 
						
						
						
							|  |  |     render: ({ cpuCores }) => (
 | 
						
						
						
							|  |  |       <span>
 | 
						
						
						
							|  |  |         {`${cpuCores}核`}
 | 
						
						
						
							|  |  |       </span>
 | 
						
						
						
							|  |  |     ),
 | 
						
						
						
							|  |  |   },
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: '内存大小',
 | 
						
						
						
							|  |  |     value: 'totalMemory',
 | 
						
						
						
							|  |  |     render: ({ totalMemory }) => (
 | 
						
						
						
							|  |  |       <span>
 | 
						
						
						
							|  |  |         {`${bytesToGB(totalMemory)}GiB`}
 | 
						
						
						
							|  |  |       </span>
 | 
						
						
						
							|  |  |     ),
 | 
						
						
						
							|  |  |   },
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: '磁盘大小',
 | 
						
						
						
							|  |  |     value: 'diskSize',
 | 
						
						
						
							|  |  |     render: ({ diskSize }) => (
 | 
						
						
						
							|  |  |       <span>
 | 
						
						
						
							|  |  |         {`${bytesToGB(diskSize)}GiB`}
 | 
						
						
						
							|  |  |       </span>
 | 
						
						
						
							|  |  |     ),
 | 
						
						
						
							|  |  |   },
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: '容器运行时',
 | 
						
						
						
							|  |  |     value: 'containerRuntimeVersion',
 | 
						
						
						
							|  |  |     render: ({ containerRuntimeVersion }) => (
 | 
						
						
						
							|  |  |       <span>
 | 
						
						
						
							|  |  |         {containerRuntimeVersion === '' ? '--' : containerRuntimeVersion}
 | 
						
						
						
							|  |  |       </span>
 | 
						
						
						
							|  |  |     ),
 | 
						
						
						
							|  |  |   },
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: '显卡数量',
 | 
						
						
						
							|  |  |     value: 'cardCnt',
 | 
						
						
						
							|  |  |     render: ({ cardCnt }) => (
 | 
						
						
						
							|  |  |       <span>
 | 
						
						
						
							|  |  |         {cardCnt === '' ? '--' : cardCnt}
 | 
						
						
						
							|  |  |       </span>
 | 
						
						
						
							|  |  |     ),
 | 
						
						
						
							|  |  |   },
 | 
						
						
						
							|  |  |   {
 | 
						
						
						
							|  |  |     label: '创建时间',
 | 
						
						
						
							|  |  |     value: 'creationTimestamp',
 | 
						
						
						
							|  |  |     render: ({ creationTimestamp }) => (
 | 
						
						
						
							|  |  |       <span>
 | 
						
						
						
							|  |  |         {creationTimestamp === '' ? '--' : creationTimestamp}
 | 
						
						
						
							|  |  |       </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 () => {
 | 
						
						
						
							|  |  |   detail.value = await nodeApi.getNodeDetail({ uid: route.params.uid });
 | 
						
						
						
							|  |  |   isSchedulable.value = detail.value.isSchedulable;
 | 
						
						
						
							|  |  | };
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | onMounted(async () => {
 | 
						
						
						
							|  |  |   await refresh();
 | 
						
						
						
							|  |  | });
 | 
						
						
						
							|  |  | </script>
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | <style lang="scss">
 | 
						
						
						
							|  |  | .node-detail {
 | 
						
						
						
							|  |  |   display: flex;
 | 
						
						
						
							|  |  |   height: 100%;
 | 
						
						
						
							|  |  |   //gap: 50px;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |   ul {
 | 
						
						
						
							|  |  |     margin: 0;
 | 
						
						
						
							|  |  |     padding: 0;
 | 
						
						
						
							|  |  |     list-style: none;
 | 
						
						
						
							|  |  |   }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |   .title {
 | 
						
						
						
							|  |  |     color: #1d2b3a;
 | 
						
						
						
							|  |  |     font-family: 'PingFang SC';
 | 
						
						
						
							|  |  |     font-size: 14px;
 | 
						
						
						
							|  |  |     font-style: normal;
 | 
						
						
						
							|  |  |     font-weight: 500;
 | 
						
						
						
							|  |  |     //line-height: 20px;
 | 
						
						
						
							|  |  |     margin-bottom: 20px;
 | 
						
						
						
							|  |  |   }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |   //.node-detail-left {
 | 
						
						
						
							|  |  |   //  min-width: 800px;
 | 
						
						
						
							|  |  |   //}
 | 
						
						
						
							|  |  |   .node-detail-info {
 | 
						
						
						
							|  |  |     gap: 15px;
 | 
						
						
						
							|  |  |     font-size: 12px;
 | 
						
						
						
							|  |  |     display: grid;
 | 
						
						
						
							|  |  |     grid-template-columns: repeat(3, 1fr);
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     .label {
 | 
						
						
						
							|  |  |       display: inline-block;
 | 
						
						
						
							|  |  |       width: 100px;
 | 
						
						
						
							|  |  |       height: 20px;
 | 
						
						
						
							|  |  |       color: #939ea9;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     .set {
 | 
						
						
						
							|  |  |       :hover {
 | 
						
						
						
							|  |  |         cursor: pointer;
 | 
						
						
						
							|  |  |         color: #324558;
 | 
						
						
						
							|  |  |       }
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     .cp {
 | 
						
						
						
							|  |  |       display: flex;
 | 
						
						
						
							|  |  |       gap: 25px;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  |   }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |   .gauges {
 | 
						
						
						
							|  |  |     flex: 1;
 | 
						
						
						
							|  |  |     display: flex;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     li {
 | 
						
						
						
							|  |  |       flex: 1;
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  |   }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | .card-gauges {
 | 
						
						
						
							|  |  |   margin: 0;
 | 
						
						
						
							|  |  |   padding: 0;
 | 
						
						
						
							|  |  |   list-style: none;
 | 
						
						
						
							|  |  |   display: flex;
 | 
						
						
						
							|  |  |   height: 200px;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |   li {
 | 
						
						
						
							|  |  |     flex: 0.25;
 | 
						
						
						
							|  |  |   }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | .line-box {
 | 
						
						
						
							|  |  |   display: grid;
 | 
						
						
						
							|  |  |   grid-template-columns: repeat(2, 1fr);
 | 
						
						
						
							|  |  |   column-gap: 20px;
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | .node-block {
 | 
						
						
						
							|  |  |   display: flex;
 | 
						
						
						
							|  |  |   flex-direction: column;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |   .home-block-content {
 | 
						
						
						
							|  |  |     flex: 1;
 | 
						
						
						
							|  |  |   }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | </style>
 |