首页接口重构
This commit is contained in:
@@ -0,0 +1,13 @@
|
|||||||
|
package com.jeesite.modules.apps.Module;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class SystemInfo implements Serializable {
|
||||||
|
private String cpu; // CPU使用率
|
||||||
|
private String memory; // 内存
|
||||||
|
private String disk; // 磁盘
|
||||||
|
private String usage; // 使用率
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.jeesite.modules.apps.web.docker;
|
|||||||
|
|
||||||
import com.jeesite.modules.apps.Module.ContainerInfo;
|
import com.jeesite.modules.apps.Module.ContainerInfo;
|
||||||
import com.jeesite.modules.apps.Module.DockerResult;
|
import com.jeesite.modules.apps.Module.DockerResult;
|
||||||
|
import com.jeesite.modules.apps.Module.SystemInfo;
|
||||||
import com.jeesite.modules.biz.dao.MySftpAccountsDao;
|
import com.jeesite.modules.biz.dao.MySftpAccountsDao;
|
||||||
import com.jeesite.modules.biz.entity.MySftpAccounts;
|
import com.jeesite.modules.biz.entity.MySftpAccounts;
|
||||||
import com.jeesite.modules.utils.DockerUtil;
|
import com.jeesite.modules.utils.DockerUtil;
|
||||||
@@ -90,4 +91,16 @@ public class myContainerController {
|
|||||||
MySftpAccounts accounts = mySftpAccountsDao.get(mySftpAccounts);
|
MySftpAccounts accounts = mySftpAccountsDao.get(mySftpAccounts);
|
||||||
return DockerUtil.listContainers(accounts, true);
|
return DockerUtil.listContainers(accounts, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取CPU列表
|
||||||
|
*/
|
||||||
|
@RequestMapping(value = "systemInfo")
|
||||||
|
@ResponseBody
|
||||||
|
public SystemInfo systemInfo(ContainerInfo containerInfo){
|
||||||
|
MySftpAccounts mySftpAccounts = new MySftpAccounts();
|
||||||
|
mySftpAccounts.setAccountId(containerInfo.getAccountId());
|
||||||
|
MySftpAccounts accounts = mySftpAccountsDao.get(mySftpAccounts);
|
||||||
|
return DockerUtil.systemInfo(accounts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package com.jeesite.modules.apps.web.docker;
|
package com.jeesite.modules.apps.web.docker;
|
||||||
|
|
||||||
import com.jeesite.modules.apps.Module.ServerInfo;
|
import com.jeesite.modules.apps.Module.ServerInfo;
|
||||||
|
import com.jeesite.modules.apps.Module.SystemInfo;
|
||||||
import com.jeesite.modules.biz.dao.MySftpAccountsDao;
|
import com.jeesite.modules.biz.dao.MySftpAccountsDao;
|
||||||
import com.jeesite.modules.biz.entity.MySftpAccounts;
|
import com.jeesite.modules.biz.entity.MySftpAccounts;
|
||||||
|
import com.jeesite.modules.utils.DockerUtil;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.jeesite.modules.utils;
|
|||||||
import com.jcraft.jsch.*;
|
import com.jcraft.jsch.*;
|
||||||
import com.jeesite.modules.apps.Module.ContainerInfo;
|
import com.jeesite.modules.apps.Module.ContainerInfo;
|
||||||
import com.jeesite.modules.apps.Module.DockerResult;
|
import com.jeesite.modules.apps.Module.DockerResult;
|
||||||
|
import com.jeesite.modules.apps.Module.SystemInfo;
|
||||||
import com.jeesite.modules.biz.entity.MySftpAccounts;
|
import com.jeesite.modules.biz.entity.MySftpAccounts;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -14,7 +15,7 @@ import java.util.List;
|
|||||||
|
|
||||||
public class DockerUtil {
|
public class DockerUtil {
|
||||||
|
|
||||||
private static final int SSH_TIMEOUT = 30000;
|
private static final int SSH_TIMEOUT = 3000;
|
||||||
|
|
||||||
private static String runCommand(MySftpAccounts account, String cmd) {
|
private static String runCommand(MySftpAccounts account, String cmd) {
|
||||||
JSch jsch = new JSch();
|
JSch jsch = new JSch();
|
||||||
@@ -89,6 +90,7 @@ public class DockerUtil {
|
|||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DockerResult start(MySftpAccounts accounts, String containerId) {
|
public static DockerResult start(MySftpAccounts accounts, String containerId) {
|
||||||
String res = runCommand(accounts, "docker start " + containerId);
|
String res = runCommand(accounts, "docker start " + containerId);
|
||||||
return res != null ? DockerResult.ok(res) : DockerResult.fail("执行失败");
|
return res != null ? DockerResult.ok(res) : DockerResult.fail("执行失败");
|
||||||
@@ -120,36 +122,30 @@ public class DockerUtil {
|
|||||||
return res != null ? DockerResult.ok(res) : DockerResult.fail("查询详情失败");
|
return res != null ? DockerResult.ok(res) : DockerResult.fail("查询详情失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 获取 CPU 使用率
|
||||||
* 获取CPU使用率
|
|
||||||
*/
|
|
||||||
public static String getCpuUsage(MySftpAccounts accounts) {
|
public static String getCpuUsage(MySftpAccounts accounts) {
|
||||||
try {
|
// 1秒采样,输出纯数字百分比
|
||||||
return runCommand(accounts, "top -bn1 | grep Cpu | awk '{print 100 - $8}'");
|
return runCommand(accounts,
|
||||||
} catch (Exception e) {
|
"top -bn1 | grep 'Cpu(s)' | sed -n '1p' | awk '{printf \"%.1f\", 100 - $8}'");
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 获取内存使用率
|
||||||
* 获取内存使用情况
|
|
||||||
*/
|
|
||||||
public static String getMemoryUsage(MySftpAccounts accounts) {
|
public static String getMemoryUsage(MySftpAccounts accounts) {
|
||||||
try {
|
return runCommand(accounts,
|
||||||
return runCommand(accounts, "free -m | grep Mem | awk '{print $3\"MB / \"$2\"MB\"}'");
|
"free | grep Mem | awk '{printf \"%.1f\", $3/$2*100}'");
|
||||||
} catch (Exception e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 获取磁盘使用率
|
||||||
* 获取磁盘使用情况
|
|
||||||
*/
|
|
||||||
public static String getDiskUsage(MySftpAccounts accounts) {
|
public static String getDiskUsage(MySftpAccounts accounts) {
|
||||||
try {
|
return runCommand(accounts,
|
||||||
return runCommand(accounts, "df -h / | grep / | awk '{print $3\" / \"$2}\" \"$5}'");
|
"df -h / | grep / | awk '{gsub(/%/,\"\"); print $5}'");
|
||||||
} catch (Exception e) {
|
}
|
||||||
return null;
|
|
||||||
}
|
public static SystemInfo systemInfo(MySftpAccounts accounts) {
|
||||||
|
SystemInfo systemInfo = new SystemInfo();
|
||||||
|
systemInfo.setCpu(getCpuUsage(accounts));
|
||||||
|
systemInfo.setMemory(getMemoryUsage(accounts));
|
||||||
|
systemInfo.setDisk(getDiskUsage(accounts));
|
||||||
|
return systemInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,6 +18,13 @@ export interface ServerInfo extends BasicModel<ServerInfo> {
|
|||||||
containerId: string; // 容器ID
|
containerId: string; // 容器ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SystemInfo extends BasicModel<SystemInfo> {
|
||||||
|
cpu: string; // CPU使用率
|
||||||
|
memory: string; // 内存
|
||||||
|
disk: string; // 磁盘
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface ContainerInfo extends BasicModel<ContainerInfo> {
|
export interface ContainerInfo extends BasicModel<ContainerInfo> {
|
||||||
image: string; // 镜像名称
|
image: string; // 镜像名称
|
||||||
command: string; // 启动命令
|
command: string; // 启动命令
|
||||||
@@ -42,6 +49,9 @@ defHttp.get<ServerInfo[]>({ url: adminPath + '/docker/myServer/listAll' });
|
|||||||
export const myContainerInfo = (params?: ContainerInfo | any) =>
|
export const myContainerInfo = (params?: ContainerInfo | any) =>
|
||||||
defHttp.get<ContainerInfo[]>({ url: adminPath + '/docker/myContainer/listAll', params });
|
defHttp.get<ContainerInfo[]>({ url: adminPath + '/docker/myContainer/listAll', params });
|
||||||
|
|
||||||
|
export const mySystemInfo = (params?: ContainerInfo | any) =>
|
||||||
|
defHttp.get<SystemInfo>({ url: adminPath + '/docker/myContainer/systemInfo', params });
|
||||||
|
|
||||||
export const myDockerStop = (params?: ContainerInfo | any) =>
|
export const myDockerStop = (params?: ContainerInfo | any) =>
|
||||||
defHttp.get<DockerResult>({ url: adminPath + '/docker/myContainer/stop', params });
|
defHttp.get<DockerResult>({ url: adminPath + '/docker/myContainer/stop', params });
|
||||||
|
|
||||||
|
|||||||
@@ -18,15 +18,11 @@
|
|||||||
>
|
>
|
||||||
<div class="host-item__header">
|
<div class="host-item__header">
|
||||||
<div class="host-item__name">{{ item.hostName }}</div>
|
<div class="host-item__name">{{ item.hostName }}</div>
|
||||||
<el-tag size="small" :type="getServerStatus(item).type">
|
|
||||||
{{ getServerStatus(item).label }}
|
|
||||||
</el-tag>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="host-item__meta">{{ item.hostIp }}:{{ item.hostPort }}</div>
|
<div class="host-item__meta">{{ item.hostIp }}:{{ item.hostPort }}</div>
|
||||||
<div class="host-item__user">{{ item.username }}</div>
|
<div class="host-item__user">{{ item.username }}</div>
|
||||||
<div class="host-item__footer">
|
<div class="host-item__footer">
|
||||||
<span>账号 {{ item.accountId }}</span>
|
<span>账号 {{ item.accountId }}</span>
|
||||||
<span>{{ getServerStatus(item).label }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -41,55 +37,60 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="currentServer" class="docker-detail__body">
|
<div v-if="currentServer" class="docker-detail__body">
|
||||||
<div class="hero-card">
|
<transition name="detail-fade" mode="out-in">
|
||||||
<div class="hero-card__left">
|
<div v-if="detailLoading" key="detail-skeleton" class="detail-skeleton">
|
||||||
<div class="hero-card__title">{{ currentServer.hostName }}</div>
|
<div class="hero-card hero-card--skeleton">
|
||||||
<div class="hero-card__meta">{{ currentServer.hostIp }}:{{ currentServer.hostPort }}</div>
|
<div class="hero-card__skeleton-title"></div>
|
||||||
<div class="hero-card__meta">账号:{{ currentServer.username }}</div>
|
<div class="hero-card__skeleton-meta"></div>
|
||||||
|
<div class="hero-card__skeleton-meta hero-card__skeleton-meta--short"></div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-grid">
|
||||||
|
<div v-for="item in 3" :key="item" class="metric-card metric-card--skeleton">
|
||||||
|
<div class="metric-card__label"> </div>
|
||||||
|
<div class="metric-card__skeleton-value"></div>
|
||||||
|
<div class="metric-card__skeleton-bar"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hero-card__right">
|
<div v-else key="detail-content">
|
||||||
<div class="hero-card__badge">{{ getServerStatus(currentServer).label }}</div>
|
<div class="hero-card">
|
||||||
</div>
|
<div class="hero-card__left">
|
||||||
</div>
|
<div class="hero-card__title">{{ currentServer.hostName }}</div>
|
||||||
|
<div class="hero-card__meta">{{ currentServer.hostIp }}:{{ currentServer.hostPort }}</div>
|
||||||
|
<div class="hero-card__meta">账号:{{ currentServer.username }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="hero-card__right">
|
||||||
|
<div :class="['hero-card__badge', { 'hero-card__badge--offline': !systemOnline }]">
|
||||||
|
{{ systemOnline ? '在线' : '离线' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="metric-grid">
|
<div class="metric-grid">
|
||||||
<div class="metric-card metric-card--cpu">
|
<div class="metric-card metric-card--cpu">
|
||||||
<div class="metric-card__label">CPU</div>
|
<div class="metric-card__label">CPU</div>
|
||||||
<div class="metric-card__value">--</div>
|
<div class="metric-card__value">{{ formatPercentText(systemInfo?.cpu) }}</div>
|
||||||
<div class="metric-card__progress">
|
<div class="metric-card__progress">
|
||||||
<span :style="{ width: '0%' }"></span>
|
<span :style="{ width: normalizePercent(systemInfo?.cpu) }"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card metric-card--memory">
|
||||||
|
<div class="metric-card__label">内存</div>
|
||||||
|
<div class="metric-card__value">{{ formatPercentText(systemInfo?.memory) }}</div>
|
||||||
|
<div class="metric-card__progress">
|
||||||
|
<span :style="{ width: normalizePercent(systemInfo?.memory) }"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card metric-card--disk">
|
||||||
|
<div class="metric-card__label">磁盘</div>
|
||||||
|
<div class="metric-card__value">{{ formatPercentText(systemInfo?.disk) }}</div>
|
||||||
|
<div class="metric-card__progress">
|
||||||
|
<span :style="{ width: normalizePercent(systemInfo?.disk) }"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="metric-card metric-card--memory">
|
</transition>
|
||||||
<div class="metric-card__label">内存</div>
|
|
||||||
<div class="metric-card__value">--</div>
|
|
||||||
<div class="metric-card__progress">
|
|
||||||
<span :style="{ width: '0%' }"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="metric-card metric-card--disk">
|
|
||||||
<div class="metric-card__label">磁盘</div>
|
|
||||||
<div class="metric-card__value">--</div>
|
|
||||||
<div class="metric-card__progress">
|
|
||||||
<span :style="{ width: '0%' }"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="detail-grid">
|
|
||||||
<div class="detail-card">
|
|
||||||
<div class="detail-card__label">账号标识</div>
|
|
||||||
<div class="detail-card__value">{{ currentServer.accountId }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="detail-card">
|
|
||||||
<div class="detail-card__label">容器总数</div>
|
|
||||||
<div class="detail-card__value">{{ currentContainers.length }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="detail-card">
|
|
||||||
<div class="detail-card__label">运行中</div>
|
|
||||||
<div class="detail-card__value">{{ runningCount }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -228,6 +229,7 @@
|
|||||||
ContainerInfo,
|
ContainerInfo,
|
||||||
DockerResult,
|
DockerResult,
|
||||||
ServerInfo,
|
ServerInfo,
|
||||||
|
SystemInfo,
|
||||||
myContainerInfo,
|
myContainerInfo,
|
||||||
myDockerInspect,
|
myDockerInspect,
|
||||||
myDockerLogs,
|
myDockerLogs,
|
||||||
@@ -235,12 +237,16 @@
|
|||||||
myDockerStart,
|
myDockerStart,
|
||||||
myDockerStop,
|
myDockerStop,
|
||||||
myServerInfo,
|
myServerInfo,
|
||||||
|
mySystemInfo,
|
||||||
} from '@jeesite/biz/api/biz/myDocker';
|
} from '@jeesite/biz/api/biz/myDocker';
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const metricLoading = ref(false);
|
||||||
|
const detailLoading = ref(false);
|
||||||
const serverOptions = ref<ServerInfo[]>([]);
|
const serverOptions = ref<ServerInfo[]>([]);
|
||||||
const sourceData = ref<ContainerInfo[]>([]);
|
const sourceData = ref<ContainerInfo[]>([]);
|
||||||
const selectedAccountId = ref('');
|
const selectedAccountId = ref('');
|
||||||
|
const systemInfo = ref<SystemInfo | null>(null);
|
||||||
const resultVisible = ref(false);
|
const resultVisible = ref(false);
|
||||||
const resultTitle = ref('');
|
const resultTitle = ref('');
|
||||||
const resultContent = ref('');
|
const resultContent = ref('');
|
||||||
@@ -259,25 +265,22 @@
|
|||||||
() => serverOptions.value.find((item) => item.accountId === selectedAccountId.value) || null,
|
() => serverOptions.value.find((item) => item.accountId === selectedAccountId.value) || null,
|
||||||
);
|
);
|
||||||
const currentContainers = computed(() => sourceData.value);
|
const currentContainers = computed(() => sourceData.value);
|
||||||
|
const systemOnline = computed(() =>
|
||||||
|
Boolean(systemInfo.value && (systemInfo.value.cpu || systemInfo.value.memory || systemInfo.value.disk)),
|
||||||
|
);
|
||||||
const runningCount = computed(
|
const runningCount = computed(
|
||||||
() => sourceData.value.filter((item) => getStatusTagType(item.status) === 'success').length,
|
() => sourceData.value.filter((item) => getStatusTagType(item.status) === 'success').length,
|
||||||
);
|
);
|
||||||
|
|
||||||
function handleServerSelect(item: ServerInfo) {
|
function handleServerSelect(item: ServerInfo) {
|
||||||
const accountId = item.accountId || '';
|
const accountId = item.accountId || '';
|
||||||
|
detailLoading.value = true;
|
||||||
selectedAccountId.value = accountId;
|
selectedAccountId.value = accountId;
|
||||||
containerQueryParams.accountId = accountId;
|
containerQueryParams.accountId = accountId;
|
||||||
|
getSystemInfo(accountId);
|
||||||
getContainerList();
|
getContainerList();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getServerStatus(item?: ServerInfo | null) {
|
|
||||||
const online = Boolean(item?.accountId);
|
|
||||||
return {
|
|
||||||
label: online ? '在线' : '离线',
|
|
||||||
type: online ? 'success' : 'danger',
|
|
||||||
} as const;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStatusTagType(status?: string) {
|
function getStatusTagType(status?: string) {
|
||||||
const value = String(status || '').toLowerCase();
|
const value = String(status || '').toLowerCase();
|
||||||
if (value.includes('up') || value.includes('running')) return 'success';
|
if (value.includes('up') || value.includes('running')) return 'success';
|
||||||
@@ -286,6 +289,22 @@
|
|||||||
return 'info';
|
return 'info';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizePercent(value?: string) {
|
||||||
|
const numeric = Number(
|
||||||
|
String(value || '')
|
||||||
|
.replace('%', '')
|
||||||
|
.trim(),
|
||||||
|
);
|
||||||
|
if (Number.isNaN(numeric)) return '0%';
|
||||||
|
return `${Math.max(0, Math.min(100, numeric))}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatPercentText(value?: string) {
|
||||||
|
const text = String(value || '').trim();
|
||||||
|
if (!text) return '0';
|
||||||
|
return text.includes('%') ? text : `${text}%`;
|
||||||
|
}
|
||||||
|
|
||||||
function isContainerStopped(status?: string) {
|
function isContainerStopped(status?: string) {
|
||||||
const value = String(status || '').toLowerCase();
|
const value = String(status || '').toLowerCase();
|
||||||
return value.includes('exit') || value.includes('stop') || value.includes('dead');
|
return value.includes('exit') || value.includes('stop') || value.includes('dead');
|
||||||
@@ -297,7 +316,9 @@
|
|||||||
if (!selectedAccountId.value && serverOptions.value.length) {
|
if (!selectedAccountId.value && serverOptions.value.length) {
|
||||||
selectedAccountId.value = serverOptions.value[0].accountId || '';
|
selectedAccountId.value = serverOptions.value[0].accountId || '';
|
||||||
if (selectedAccountId.value) {
|
if (selectedAccountId.value) {
|
||||||
|
detailLoading.value = true;
|
||||||
containerQueryParams.accountId = selectedAccountId.value;
|
containerQueryParams.accountId = selectedAccountId.value;
|
||||||
|
getSystemInfo(selectedAccountId.value);
|
||||||
getContainerList();
|
getContainerList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -306,6 +327,30 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getSystemInfo(accountId = containerQueryParams.accountId) {
|
||||||
|
if (!accountId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
metricLoading.value = true;
|
||||||
|
detailLoading.value = true;
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
accountId,
|
||||||
|
};
|
||||||
|
const res = await mySystemInfo(params);
|
||||||
|
if (accountId === selectedAccountId.value) {
|
||||||
|
systemInfo.value = res;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
if (accountId === selectedAccountId.value) {
|
||||||
|
metricLoading.value = false;
|
||||||
|
detailLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function getContainerList() {
|
async function getContainerList() {
|
||||||
if (!containerQueryParams.accountId) {
|
if (!containerQueryParams.accountId) {
|
||||||
sourceData.value = [];
|
sourceData.value = [];
|
||||||
@@ -313,7 +358,10 @@
|
|||||||
}
|
}
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
sourceData.value = (await myContainerInfo(containerQueryParams)) || [];
|
const params = {
|
||||||
|
accountId: containerQueryParams.accountId,
|
||||||
|
};
|
||||||
|
sourceData.value = (await myContainerInfo(params)) || [];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
sourceData.value = [];
|
sourceData.value = [];
|
||||||
} finally {
|
} finally {
|
||||||
@@ -503,7 +551,7 @@
|
|||||||
|
|
||||||
.docker-main {
|
.docker-main {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 360px minmax(0, 1fr);
|
grid-template-rows: 270px minmax(0, 1fr);
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
@@ -556,11 +604,16 @@
|
|||||||
height: 32px;
|
height: 32px;
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: rgb(30 64 175);
|
background: rgb(220 252 231);
|
||||||
color: rgb(239 246 255);
|
color: rgb(21 128 61);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
|
|
||||||
|
&--offline {
|
||||||
|
background: rgb(254 226 226);
|
||||||
|
color: rgb(185 28 28);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -591,6 +644,29 @@
|
|||||||
color: rgb(30 41 59);
|
color: rgb(30 41 59);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__skeleton {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__skeleton-value,
|
||||||
|
&__skeleton-bar {
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(90deg, rgb(226 232 240) 25%, rgb(241 245 249) 50%, rgb(226 232 240) 75%);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
animation: metric-skeleton 1.2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__skeleton-value {
|
||||||
|
width: 56px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__skeleton-bar {
|
||||||
|
width: 100%;
|
||||||
|
height: 8px;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
&__progress {
|
&__progress {
|
||||||
height: 8px;
|
height: 8px;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
@@ -625,6 +701,25 @@
|
|||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.metric-fade-enter-active,
|
||||||
|
.metric-fade-leave-active {
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-fade-enter-from,
|
||||||
|
.metric-fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes metric-skeleton {
|
||||||
|
0% {
|
||||||
|
background-position: 200% 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: -200% 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.detail-card {
|
.detail-card {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
@@ -643,7 +738,82 @@
|
|||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
color: rgb(30 41 59);
|
color: rgb(30 41 59);
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
|
|
||||||
|
&--status {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgb(34 197 94);
|
||||||
|
|
||||||
|
&--offline {
|
||||||
|
background: rgb(239 68 68);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-skeleton {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-card--skeleton {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-card__skeleton-title,
|
||||||
|
.hero-card__skeleton-meta,
|
||||||
|
.detail-card__skeleton-label,
|
||||||
|
.detail-card__skeleton-value {
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(90deg, rgb(226 232 240) 25%, rgb(241 245 249) 50%, rgb(226 232 240) 75%);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
animation: metric-skeleton 1.2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-card__skeleton-title {
|
||||||
|
width: 160px;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-card__skeleton-meta {
|
||||||
|
width: 220px;
|
||||||
|
height: 14px;
|
||||||
|
|
||||||
|
&--short {
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-card__skeleton-label {
|
||||||
|
width: 80px;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-card__skeleton-value {
|
||||||
|
width: 70%;
|
||||||
|
height: 18px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-fade-enter-active,
|
||||||
|
.detail-fade-leave-active {
|
||||||
|
transition: opacity 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-fade-enter-from,
|
||||||
|
.detail-fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.docker-table {
|
.docker-table {
|
||||||
@@ -875,8 +1045,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__badge {
|
&__badge {
|
||||||
background: rgb(30 64 175 / 80%);
|
background: rgb(20 83 45 / 72%);
|
||||||
color: rgb(219 234 254);
|
color: rgb(187 247 208);
|
||||||
|
|
||||||
|
&--offline {
|
||||||
|
background: rgb(127 29 29 / 72%);
|
||||||
|
color: rgb(254 202 202);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -895,6 +1070,12 @@
|
|||||||
color: rgb(226 232 240);
|
color: rgb(226 232 240);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__skeleton-value,
|
||||||
|
&__skeleton-bar {
|
||||||
|
background: linear-gradient(90deg, rgb(51 65 85) 25%, rgb(71 85 105) 50%, rgb(51 65 85) 75%);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
}
|
||||||
|
|
||||||
&__progress {
|
&__progress {
|
||||||
background: rgb(51 65 85);
|
background: rgb(51 65 85);
|
||||||
}
|
}
|
||||||
@@ -910,6 +1091,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hero-card__skeleton-title,
|
||||||
|
.hero-card__skeleton-meta,
|
||||||
|
.detail-card__skeleton-label,
|
||||||
|
.detail-card__skeleton-value {
|
||||||
|
background: linear-gradient(90deg, rgb(51 65 85) 25%, rgb(71 85 105) 50%, rgb(51 65 85) 75%);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.docker-table {
|
.docker-table {
|
||||||
.el-table {
|
.el-table {
|
||||||
--el-table-header-bg-color: rgb(20, 20, 20);
|
--el-table-header-bg-color: rgb(20, 20, 20);
|
||||||
@@ -1041,7 +1230,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.docker-main {
|
.docker-main {
|
||||||
grid-template-rows: 400px minmax(0, 1fr);
|
grid-template-rows: 300px minmax(0, 1fr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user