fix(web): keep refresh buttons steady during polling (#2647)

Co-authored-by: 225284228a-droid <239500008+225284228a-droid@users.noreply.github.com>
This commit is contained in:
刚刚and225284228a-droid authored and GitHub committed 2026-10-09 23:04:22 +08:00
1 parent 7fdfe90291
commit 2583d867c3
2 files changed
+27 -16

No files matched your search

@@ -12,17 +12,24 @@ const devices = ref<Utils.DeviceInfo[]>();
const networks = ref<CentralNetworkSummary[]>();
const loadError = ref(false);
const refreshing = ref(false);
let requestInFlight = false;
const loadSummary = async () => {
if (refreshing.value) return;
refreshing.value = true;
const results = await Promise.allSettled([
props.api.get_summary().then(value => { summary.value = value; }),
props.api.list_machines().then(value => { devices.value = value.map(Utils.buildDeviceInfo); }),
...(props.centralEnabled ? [props.api.list_networks().then(value => { networks.value = value; })] : []),
]);
loadError.value = results.some(result => result.status === 'rejected');
refreshing.value = false;
const loadSummary = async (manual = false) => {
// A manual refresh can show progress for an already running background request.
if (manual) refreshing.value = true;
if (requestInFlight) return;
requestInFlight = true;
try {
const results = await Promise.allSettled([
props.api.get_summary().then(value => { summary.value = value; }),
props.api.list_machines().then(value => { devices.value = value.map(Utils.buildDeviceInfo); }),
...(props.centralEnabled ? [props.api.list_networks().then(value => { networks.value = value; })] : []),
]);
loadError.value = results.some(result => result.status === 'rejected');
} finally {
requestInFlight = false;
refreshing.value = false;
}
};
watch(() => props.centralEnabled, () => loadSummary());
const periodFunc = new Utils.PeriodicTask(loadSummary, 2000);
@@ -45,7 +52,7 @@ const stats = computed(() => [
<div class="console-page">
<header class="page-heading">
<div><h1>{{ t('web.main.dashboard') }}</h1></div>
<Button icon="pi pi-refresh" :label="t('web.console.refresh')" severity="secondary" outlined :loading="refreshing" @click="loadSummary" />
<Button icon="pi pi-refresh" :label="t('web.console.refresh')" severity="secondary" outlined :loading="refreshing" @click="loadSummary(true)" />
</header>
<Message v-if="loadError" severity="warn" :closable="false">{{ t('web.console.load_failed') }}</Message>
<section class="console-panel summary-strip" :aria-label="t('web.main.dashboard')">
@@ -27,6 +27,7 @@ const deviceList = ref<Array<Utils.DeviceInfo> | undefined>(undefined);
const search = ref('');
const loadError = ref(false);
const refreshing = ref(false);
let requestInFlight = false;
const expandedRows = ref({});
// 桌面端可在表格与卡片视图之间切换,选择持久化;移动端始终使用紧凑列表
@@ -57,9 +58,11 @@ const copyEnrollCommand = async () => {
}
};
const loadDevices = async () => {
if (refreshing.value) return;
refreshing.value = true;
const loadDevices = async (manual = false) => {
// A manual refresh can show progress for an already running background request.
if (manual) refreshing.value = true;
if (requestInFlight) return;
requestInFlight = true;
try {
const resp = await api?.list_machines();
deviceList.value = (resp || []).map(Utils.buildDeviceInfo);
@@ -68,6 +71,7 @@ const loadDevices = async () => {
loadError.value = true;
console.error(e);
} finally {
requestInFlight = false;
refreshing.value = false;
}
};
@@ -214,7 +218,7 @@ const locationText = (device: Utils.DeviceInfo) => {
</template>
</SelectButton>
<Button icon="pi pi-refresh" text severity="secondary" :aria-label="t('web.console.refresh')"
:loading="refreshing" @click="loadDevices" />
:loading="refreshing" @click="loadDevices(true)" />
</div>
</div>
<div v-if="deviceList === undefined && !loadError" class="loading-rows">
@@ -223,7 +227,7 @@ const locationText = (device: Utils.DeviceInfo) => {
<div v-else-if="loadError" class="console-empty-state">
<i class="pi pi-exclamation-triangle" aria-hidden="true"></i>
<h2>{{ t('web.console.load_failed') }}</h2>
<Button :label="t('web.console.retry')" icon="pi pi-refresh" @click="loadDevices" />
<Button :label="t('web.console.retry')" icon="pi pi-refresh" @click="loadDevices(true)" />
</div>
<div v-else-if="sortedDeviceList.length === 0" class="console-empty-state">
<i class="pi pi-server" aria-hidden="true"></i>