k8s管理系统项目前端-summary
k8s管理系统项目前端-summary
<template>
<div class="demo-collapse">
<el-collapse v-model="activeNames" @change="handleChange">
<el-collapse-item title="集群资源" name="1">
<el-row :gutter="20">
<el-col :span="8">
<el-card class="box-card" shadow="hover">
<div ref="echartsRefNode" class="echarts-container"></div>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="box-card" shadow="hover">
<div ref="echartsRefPod" class="echarts-container"></div>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="box-card" shadow="hover">
<div ref="echartsRefDeployment" class="echarts-container"></div>
</el-card>
</el-col>
</el-row>
</el-collapse-item>
<el-collapse-item title="节点资源" name="2">
<el-row :gutter="20">
<el-col :span="8">
<el-card class="box-card" shadow="hover">
<div ref="echartsRefCpu" class="echarts-container"></div>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="box-card" shadow="hover">
<div ref="echartsRefMemory" class="echarts-container"></div>
</el-card>
</el-col>
</el-row>
</el-collapse-item>
<el-collapse-item title="资源统计" name="3">
<el-row :gutter="20">
<el-col :span="24">
<el-card class="box-cardnode" shadow="hover">
<div ref="echartsRefNamespacePodCount" class="echarts-container"></div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-card class="box-cardnode" shadow="hover">
<div ref="echartsRefNamespaceDeploymentCount" class="echarts-container"></div>
</el-card>
</el-col>
</el-row>
</el-collapse-item>
</el-collapse>
</div>
</template>
<script setup>
import { nextTick, onBeforeMount, reactive, ref, watch} from 'vue'
import * as echarts from 'echarts';
import {DEPLOYMENT_LIST, GET_NS_DEPLOYMENT_COUNT, GET_NS_PODS_COUNT, NODE_LIST, POD_LIST} from "../../../api/k8s.js";
const activeNames = ref(['1','2','3'])
const handleChange = (val) => {
console.log(val)
}
const echartsRefNode = ref(null);
const echartsRefPod = ref(null);
const echartsRefDeployment = ref(null);
const echartsRefCpu = ref(null);
const echartsRefMemory = ref(null);
const echartsRefNamespacePodCount = ref(null);
const echartsRefNamespaceDeploymentCount = ref(null);
// const echartsRefDeployment = ref(null);
let myCharts = [null,null,null];
// 初始化ECharts图表
const initChart = (echartsRef,index,optionData) => {
if (echartsRef.value) {
let chartInstance = myCharts[index];
if (!chartInstance) {
chartInstance = echarts.init(echartsRef.value);
myCharts[index] = chartInstance; // 将图表实例保存在数组中
}
chartInstance.setOption(optionData);
myCharts[index] = chartInstance; // 将图表实例保存在数组中
}
};
// 获取node信息
// 假设这些是从API或其他数据源中获取的值
let readyValue = ref(0);
let notReadyValue = ref(0);
const nodeParameters = reactive({
page_size: 200,
page_number: 1,
isMaster: 3,
})
let nodeCpuAllocatable= ref(0)
//cpu总量
let nodeCpuCapacity = ref(0)
//内存可分配
let nodeMemAllocatable = ref(0)
//内存总量
let nodeMemCapacity = ref(0)
var nodeCount = ref(0)
const getNodeData = async ()=>{
try {
const resp = await NODE_LIST(nodeParameters)
for (const respKey of resp.data.Items) {
console.log(respKey)
//计算node的cpu mem和pod的可分配及总容量数据
nodeCpuAllocatable.value = parseInt(respKey.status.allocatable.cpu) + nodeCpuAllocatable.value
nodeCpuCapacity.value = parseInt(respKey.status.capacity.cpu) + nodeCpuCapacity.value
nodeMemAllocatable.value = parseInt(respKey.status.allocatable.memory) + nodeMemAllocatable.value
nodeMemCapacity.value = parseInt(respKey.status.capacity.memory) + nodeMemCapacity.value
for (const status of respKey.status.conditions) {
console.log(status)
if (status.type == "Ready" && status.status =="True"){
readyValue.value ++
}
}
}
nodeCount = resp.data.total
notReadyValue.value = nodeCount - readyValue.value
const nodeOption = {
title: {
text: '集群节点数量:'+nodeCount,
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: '状态',
type: 'pie',
radius: '50%',
data: [
{
value: readyValue.value,
name: 'Ready',
itemStyle: { color: '#92CC76' } // 设置为绿色
},
{
value: notReadyValue.value,
name: 'NotReady',
itemStyle: { color: '#E64A3E' } // 设置为红色
},
// 其他状态数据
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
initChart(echartsRefNode,0,nodeOption)
updateNodeResourceCharts(); // 更新资源图表的函数
}catch (e){
console.log(e)
}
}
let namespacePodCountData = ref()
let namespaceDeploymentCountData = ref()
const updateNodeResourceCharts = () => {
// CPU资源饼图配置
const cpuOption = {
title: {
text: 'CPU 资源',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: 'CPU资源',
type: 'pie',
radius: '50%',
data: [
{ value: nodeCpuAllocatable.value, name: 'Allocatable' },
{ value: nodeCpuCapacity.value - nodeCpuAllocatable.value, name: 'Used' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
initChart(echartsRefCpu, 3, cpuOption); // 初始化CPU资源图表
// 内存资源饼图配置
const memoryOption = {
title: {
text: '内存资源',
subtext: '单位: GiB', // 添加单位说明
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: '内存资源',
type: 'pie',
radius: '50%',
data: [
{ value: bytesToGiB(nodeMemAllocatable.value), name: 'Allocatable' },
{ value: bytesToGiB(nodeMemCapacity.value - nodeMemAllocatable.value), name: 'Used' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
initChart(echartsRefMemory, 4, memoryOption); // 初始化内存资源图表
};
const bytesToGiB = (bytes) => {
let a = bytes / 1024 / 1024
//四舍五入保留小数点0位,也就是去除小数点
return a.toFixed(0)
};
const PodListParameters = reactive({
page_size: 2000000,
page_number: 1,
fileName:"",
namespace:"",
})
var PodCount = ref(0)
let RunningValue = ref(0);
let PendingValue = ref(0);
let FailedValue = ref(0);
let SucceededValue = ref(0);
const getPodListData = async ()=>{
try {
const resp = await POD_LIST(PodListParameters)
console.log(resp.data.items)
for (const respKey of resp.data.items) {
// console.log(respKey)
if (respKey.status.phase == "Running"){
RunningValue.value ++
}else if( respKey.status.phase =="Pending") {
PendingValue.value ++
}else if (respKey.status.phase =="Failed") {
FailedValue.value ++
}else if (respKey.status.phase == "Successed"){
SucceededValue.value ++
}
}
PodCount = resp.data.total
const podOption = {
title: {
text: 'Pod数量:'+PodCount,
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: '状态',
type: 'pie',
radius: '50%',
data: [
{ value: RunningValue.value, name: 'Running', itemStyle: { color: '#92CC76' }},
{ value: PendingValue.value, name: 'Pending',itemStyle: { color: '#EFA634' } },
{ value: FailedValue.value, name: 'Failed',itemStyle: { color: '#EF2D21' } },
{ value: SucceededValue.value, name: 'Succeeded',itemStyle: { color: '#2653EF' } }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
// initChart(echartsRefNode,0,)
initChart(echartsRefPod,1,podOption)
// initChart(echartsRefNs,2)
}catch (e){
console.log(e)
}
}
const DeploymentListParameters = reactive({
page_size: 2000000,
page_number: 1,
fileName:"",
namespace:"",
})
var DeploymentCount = ref(0)
// 假设的Deployment状态数据处理
let availableValue = ref(0);
let progressingValue = ref(0);
let failureValue = ref(0);
const NSPodsCountParameters = reactive({
namespace:"",
})
const getNSPodsCount = async ()=>{
try {
const resp = await GET_NS_PODS_COUNT(NSPodsCountParameters)
namespacePodCountData.value = resp
const option = {
title: {
text: '命名空间的 Pod 计数', // 标题文本
left: 'center', // 标题的水平位置
textStyle: {
color: '#333', // 标题的字体颜色
fontWeight: 'normal', // 标题的字体粗细
fontSize: 16 // 标题的字体大小
}
},
tooltip: {
trigger: 'axis', // 触发类型:坐标轴触发
axisPointer: {
type: 'cross', // 十字准星指示器,显示标线
crossStyle: {
color: '#999',
},
}
},
xAxis: {
type: 'category',
data: namespacePodCountData.value.data.map(ns => ns.namespace),
axisTick: {
alignWithLabel: true // 刻度线和标签对齐
}
},
yAxis: {
type: 'value',
axisLine: {
show: false // 不显示y轴线
},
axisTick: {
show: false // 不显示刻度
},
splitLine: { // 分割线
lineStyle: { // 使用深浅的间隔色
type: 'dashed'
}
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true // 包含标签
},
series: [{
data: namespacePodCountData.value.data.map(ns => {
return {
value: ns.podCount,
label: {
show: true,
position: 'top',
formatter: '{c}',
color: '#000'
}
};
}),
type: 'bar',
barWidth: '60%', // 柱图宽度
showBackground: true,
backgroundStyle: {
color: 'rgba(222, 222, 222, 0.2)'
},
itemStyle: { // 定制展示(如柱形图的颜色)
color: '#3398DB'
}
}]
};
initChart(echartsRefNamespacePodCount,5,option)
}catch (e){
console.log(e)
}
}
const getNSDeploymentCount = async ()=>{
try {
const resp = await GET_NS_DEPLOYMENT_COUNT(NSPodsCountParameters)
namespaceDeploymentCountData.value = resp
const option = {
title: {
text: '命名空间的 Deployment 计数', // 标题文本
left: 'center', // 标题的水平位置
textStyle: {
color: '#333', // 标题的字体颜色
fontWeight: 'normal', // 标题的字体粗细
fontSize: 16 // 标题的字体大小
}
},
tooltip: {
trigger: 'axis', // 触发类型:坐标轴触发
axisPointer: {
type: 'cross', // 十字准星指示器,显示标线
crossStyle: {
color: '#999',
},
}
},
xAxis: {
type: 'category',
data: namespaceDeploymentCountData.value.data.map(ns => ns.namespace),
axisTick: {
alignWithLabel: true // 刻度线和标签对齐
}
},
yAxis: {
type: 'value',
axisLine: {
show: false // 不显示y轴线
},
axisTick: {
show: false // 不显示刻度
},
splitLine: { // 分割线
lineStyle: { // 使用深浅的间隔色
type: 'dashed'
}
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true // 包含标签
},
series: [{
data: namespaceDeploymentCountData.value.data.map(ns => {
return {
value: ns.deploymentCount,
label: {
show: true,
position: 'top',
formatter: '{c}',
color: '#000'
}
};
}),
type: 'bar',
barWidth: '60%', // 柱图宽度
showBackground: true,
backgroundStyle: {
color: 'rgba(222, 222, 222, 0.2)'
},
itemStyle: { // 定制展示(如柱形图的颜色)
color: '#3398DB'
}
}]
};
initChart(echartsRefNamespaceDeploymentCount,6,option)
}catch (e){
console.log(e)
}
}
const getDeploymentListData = async ()=>{
try {
const resp = await DEPLOYMENT_LIST(DeploymentListParameters)
console.log(resp)
console.log(resp.data.Items)
// 假设你的API返回数据结构包含了Deployment的状态信息
for (const deployment of resp.data.Items) {
if (deployment.status.availableReplicas === deployment.spec.replicas) {
availableValue.value++;
}
if (deployment.status.unavailableReplicas > 0) {
failureValue.value++;
}
// 你可以添加更多的条件检查来更新progressingValue等
// 注意:你需要根据你的实际API响应格式来调整以上代码
}
DeploymentCount = resp.data.total
const deploymentOption = {
title: {
text: 'Deployment数量:'+DeploymentCount,
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: '状态',
type: 'pie',
radius: '50%',
data: [
{ value: availableValue.value, name: 'available', itemStyle: { color: '#92CC76' }},
{ value: failureValue.value, name: 'unavailable',itemStyle: { color: '#EFA634' } },
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
// initChart(echartsRefNode,0,)
initChart(echartsRefDeployment,2,deploymentOption)
// initChart(echartsRefNs,2)
}catch (e){
console.log(e)
}
}
// 使用 watchEffect 或 watch 监听 activeNames 的变化,并在相应的折叠面板打开时初始化图表
watch(activeNames, async (newActiveNames) => {
if (newActiveNames.includes('1')) {
// 使用 nextTick 确保 DOM 更新完成后再初始化图表
nextTick(() => {
initChart(echartsRefNode, 0);
initChart(echartsRefPod, 1);
initChart(echartsRefDeployment, 2);
});
}
if (newActiveNames.includes('2')) {
nextTick(() => {
if (myCharts[3]) myCharts[3].resize();
if (myCharts[4]) myCharts[4].resize();
});
}
if (newActiveNames.includes('3')) {
nextTick(() => {
initChart(echartsRefNamespacePodCount, 5);
initChart(echartsRefNamespaceDeploymentCount, 6);
});
}
});
onBeforeMount(async ()=> {
await Promise.all([getNodeData(),getPodListData(),getDeploymentListData(),getNSPodsCount(),getNSDeploymentCount()])
});
</script>
<style scoped>
.echarts-container {
width: 100%;
height: 300px; /* 或者您希望的高度 */
}
.box-card {
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
</style>
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 J.のblog!
评论