2026-04-22 00:31:57 +08:00

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");