114 lines
3.6 KiB
JavaScript
114 lines
3.6 KiB
JavaScript
const { createApp } = Vue;
|
|
|
|
createApp({
|
|
data() {
|
|
return {
|
|
loading: false,
|
|
error: "",
|
|
filter: "all",
|
|
keyword: "",
|
|
payload: {
|
|
updatedAt: "",
|
|
summary: { total: 0, ok: 0, down: 0 },
|
|
items: [],
|
|
},
|
|
timer: null,
|
|
};
|
|
},
|
|
computed: {
|
|
summary() {
|
|
return this.payload.summary || { total: 0, ok: 0, down: 0 };
|
|
},
|
|
formattedUpdatedAt() {
|
|
if (!this.payload.updatedAt) {
|
|
return "-";
|
|
}
|
|
const date = new Date(this.payload.updatedAt);
|
|
return Number.isNaN(date.getTime()) ? this.payload.updatedAt : date.toLocaleString();
|
|
},
|
|
filteredItems() {
|
|
const keyword = this.keyword.toLowerCase();
|
|
return (this.payload.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);
|
|
});
|
|
},
|
|
groupedHosts() {
|
|
const map = new Map();
|
|
for (const item of this.filteredItems) {
|
|
if (!map.has(item.host)) {
|
|
map.set(item.host, {
|
|
host: item.host,
|
|
ip: item.ip,
|
|
group: item.group,
|
|
groupLabel: this.groupLabel(item.group),
|
|
downCount: 0,
|
|
items: [],
|
|
});
|
|
}
|
|
const group = map.get(item.host);
|
|
group.items.push(item);
|
|
if (!item.ok) {
|
|
group.downCount += 1;
|
|
}
|
|
}
|
|
return [...map.values()];
|
|
},
|
|
},
|
|
methods: {
|
|
groupLabel(group) {
|
|
return {
|
|
app: "应用节点",
|
|
pay: "支付节点",
|
|
gateway: "网关节点",
|
|
}[group] || group;
|
|
},
|
|
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");
|