refactor(admin): unify webui fetch/copy/format helpers; fix audit tab load and delete-group count

- apiFetch + shared needLogin (any 401 shows the login card) replaces six
  duplicated fetch/401/error-handling blocks in the admin composables
- useCopy composable: clipboard + execCommand fallback with timed reset,
  used by MembersPanel and WebhookPanel
- utils/format.ts (fmtTime/splitList/parseMatch) removes inline duplicates
  across SendLogs, AuditLog, RouteEditor and GroupEditor
- fix: load the audit log when the audit tab becomes active (client-side
  navigation never remounted the page, leaving the list empty on first visit)
- fix: fetch the real route count for a group before confirming deletion
  instead of reusing the currently open group's route list
This commit is contained in:
RhenCloud 2026-08-14 07:18:55 +08:00
parent c438fe96dc
commit e59b10f739
No known key found for this signature in database
GPG key ID: A574A617378C4E0B
16 changed files with 137 additions and 202 deletions

View file

@ -12,7 +12,7 @@
<span class="wh-label">{{ t("webhook.url") }}</span>
<code class="wh-value">{{ info.url }}</code>
<button class="btn btn-ghost btn-sm" @click="copy(info.url, 'url')">
{{ copiedUrl ? t("webhook.copied") : t("webhook.copy") }}
{{ copied === "url" ? t("webhook.copied") : t("webhook.copy") }}
</button>
</div>
@ -26,7 +26,7 @@
class="btn btn-ghost btn-sm"
@click="copy(info.secret!, 'secret')"
>
{{ copiedSecret ? t("webhook.copied") : t("webhook.copy") }}
{{ copied === "secret" ? t("webhook.copied") : t("webhook.copy") }}
</button>
</div>
<p v-if="info.hasSecret && !info.secret" class="hint">{{ t("webhook.secretHidden") }}</p>
@ -68,10 +68,9 @@ const props = defineProps<{ groupId: string; canEdit: boolean }>();
const api = useWebhookApi();
const info = ref<GroupWebhookInfo | null>(null);
const copiedUrl = ref(false);
const copiedSecret = ref(false);
const busy = ref(false);
const error = ref("");
const { copied, copy } = useCopy();
const maskedSecret = "••••••••••••••••";
const customExample = [
@ -112,7 +111,6 @@ async function onRegenerate(): Promise<void> {
error.value = "";
try {
info.value = await api.regenerate(props.groupId);
copiedSecret.value = false;
} catch (err) {
error.value = err instanceof Error ? err.message : String(err);
} finally {
@ -132,23 +130,4 @@ async function onDisable(): Promise<void> {
busy.value = false;
}
}
async function copy(text: string, which: "url" | "secret"): Promise<void> {
try {
await navigator.clipboard.writeText(text);
if (which === "url") {
copiedUrl.value = true;
window.setTimeout(() => {
copiedUrl.value = false;
}, 1500);
} else {
copiedSecret.value = true;
window.setTimeout(() => {
copiedSecret.value = false;
}, 1500);
}
} catch {
// ignore clipboard failures
}
}
</script>