131 lines
3.3 KiB
JavaScript
131 lines
3.3 KiB
JavaScript
const { createApp } = Vue;
|
|
|
|
createApp({
|
|
data() {
|
|
return {
|
|
loading: false,
|
|
error: "",
|
|
filter: "all",
|
|
keyword: "",
|
|
payload: {
|
|
updatedAt: "",
|
|
summary: {
|
|
total: 0,
|
|
ok: 0,
|
|
down: 0,
|
|
hostTotal: 0,
|
|
hostMetricOk: 0,
|
|
hostMetricDown: 0,
|
|
},
|
|
hosts: [],
|
|
},
|
|
timer: null,
|
|
};
|
|
},
|
|
computed: {
|
|
summary() {
|
|
return this.payload.summary || {
|
|
total: 0,
|
|
ok: 0,
|
|
down: 0,
|
|
hostTotal: 0,
|
|
hostMetricOk: 0,
|
|
hostMetricDown: 0,
|
|
};
|
|
},
|
|
formattedUpdatedAt() {
|
|
if (!this.payload.updatedAt) {
|
|
return "-";
|
|
}
|
|
const date = new Date(this.payload.updatedAt);
|
|
return Number.isNaN(date.getTime()) ? this.payload.updatedAt : date.toLocaleString();
|
|
},
|
|
groupedHosts() {
|
|
const keyword = this.keyword.trim().toLowerCase();
|
|
|
|
return (this.payload.hosts || [])
|
|
.map((host) => {
|
|
const items = (host.items || []).filter((item) => {
|
|
if (this.filter === "down" && item.ok) {
|
|
return false;
|
|
}
|
|
if (this.filter === "java" && item.kind !== "java") {
|
|
return false;
|
|
}
|
|
if (this.filter === "golang" && item.kind !== "golang") {
|
|
return false;
|
|
}
|
|
if (!keyword) {
|
|
return true;
|
|
}
|
|
return [item.host, item.ip, item.service, item.kind, item.group]
|
|
.join(" ")
|
|
.toLowerCase()
|
|
.includes(keyword);
|
|
});
|
|
|
|
return {
|
|
...host,
|
|
groupLabel: this.groupLabel(host.group),
|
|
items,
|
|
downCount: items.filter((item) => !item.ok).length,
|
|
};
|
|
})
|
|
.filter((host) => host.items.length > 0 || !keyword);
|
|
},
|
|
},
|
|
methods: {
|
|
groupLabel(group) {
|
|
return {
|
|
app: "应用节点",
|
|
pay: "支付节点",
|
|
gateway: "网关节点",
|
|
}[group] || group;
|
|
},
|
|
formatPercent(value) {
|
|
if (value == null || Number.isNaN(Number(value))) {
|
|
return "-";
|
|
}
|
|
return `${Number(value).toFixed(2)}%`;
|
|
},
|
|
formatGb(used, total) {
|
|
if (used == null || total == null) {
|
|
return "-";
|
|
}
|
|
return `${Number(used).toFixed(2)} / ${Number(total).toFixed(2)} GB`;
|
|
},
|
|
async refresh() {
|
|
this.loading = true;
|
|
this.error = "";
|
|
try {
|
|
const response = await fetch("/api/monitor/services", { cache: "no-store" });
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}`);
|
|
}
|
|
this.payload = await response.json();
|
|
} catch (error) {
|
|
this.error = error instanceof Error ? error.message : String(error);
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
},
|
|
},
|
|
mounted() {
|
|
const root = document.getElementById("app");
|
|
const bootIndicator = document.getElementById("boot-indicator");
|
|
if (root) {
|
|
root.removeAttribute("v-cloak");
|
|
}
|
|
if (bootIndicator) {
|
|
bootIndicator.hidden = true;
|
|
}
|
|
this.refresh();
|
|
this.timer = window.setInterval(() => this.refresh(), 10000);
|
|
},
|
|
beforeUnmount() {
|
|
if (this.timer) {
|
|
window.clearInterval(this.timer);
|
|
}
|
|
},
|
|
}).mount("#app");
|