<!-- SPEC: PJ2026-010405 云端控制台. -->
<script setup lang="ts">
import { computed, onMounted, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { systemAPI } from "@/api";
import ApiErrorDiagnostic from "@/components/common/ApiErrorDiagnostic.vue";
import AsyncBoundary from "@/components/common/AsyncBoundary.vue";
import GateWorkspace from "@/components/gate/GateWorkspace.vue";
import PageCommandBar from "@/components/layout/PageCommandBar.vue";
import { useTableLoader } from "@/composables/useTableLoader";
import type { GateDiagnosticRow, GateDiagnosticsResponse } from "@/types";

const payload = ref<GateDiagnosticsResponse | null>(null);
const route = useRoute();
const router = useRouter();
const query = ref(typeof route.query.q === "string" ? route.query.q : "");
const statusFilter = ref(typeof route.query.filter === "string" ? route.query.filter : "all");
const selectedRow = ref<GateDiagnosticRow | null>(null);
const page = ref(1);
const table = useTableLoader<GateDiagnosticRow>(async () => { const response = await systemAPI.gateDiagnostics(); if (!response.ok) throw response; payload.value = response.data; return response.data?.rows ?? []; });
const rows = computed(() => table.rows.value);
const asyncState = computed(() => table.loading.value ? rows.value.length ? "refreshing" : "initial-loading" : table.error.value ? rows.value.length ? "partial" : "error" : rows.value.length ? "ready" : "empty");
watch([query, statusFilter], () => { page.value = 1; void syncViewState(); });
watch(() => route.query, () => { const routeQuery = typeof route.query.q === "string" ? route.query.q : ""; const routeFilter = typeof route.query.filter === "string" ? route.query.filter : "all"; if (query.value !== routeQuery) query.value = routeQuery; if (statusFilter.value !== routeFilter) statusFilter.value = routeFilter; restoreSelectedRow(); });
onMounted(async () => { await table.reload(); restoreSelectedRow(); });
function rowKey(row: GateDiagnosticRow): string { return `${row.category ?? "category"}:${row.check ?? "check"}`; }
function openDetail(row: GateDiagnosticRow): void { selectedRow.value = row; void replaceQuery({ detail: rowKey(row) }); }
function closeDetail(): void { selectedRow.value = null; void replaceQuery({ detail: undefined }); }
function restoreSelectedRow(): void { const detail = typeof route.query.detail === "string" ? route.query.detail : ""; selectedRow.value = detail ? rows.value.find((row) => rowKey(row) === detail) ?? null : null; }
async function syncViewState(): Promise<void> { await replaceQuery({ q: query.value.trim() || undefined, filter: statusFilter.value === "all" ? undefined : statusFilter.value }); }
async function replaceQuery(patch: Record<string, string | undefined>): Promise<void> { const next = { ...route.query }; for (const [key, value] of Object.entries(patch)) { if (value) next[key] = value; else delete next[key]; } await router.replace({ query: next }); }
</script>

<template>
  <section class="route-stack system-page gate-page">
    <PageCommandBar eyebrow="System" title="内部复核" description="Gate diagnostics 直接读取 live 聚合结果，用共享表格、筛选和 Inspector 展示失败归因。" />
    <AsyncBoundary :state="asyncState" :has-content="Boolean(rows.length)" label="加载 Gate diagnostics" empty-title="暂无 Gate diagnostics" empty-description="诊断 API 当前未返回检查项。" @retry="table.reload">
      <template #error><ApiErrorDiagnostic :error="table.error.value || '请求未完成'" :api-error="table.apiError.value" :diagnostic="table.diagnostic.value" /></template>
      <GateWorkspace v-model:query="query" v-model:status-filter="statusFilter" v-model:page="page" v-model:selected-row="selectedRow" :payload="payload" :rows="rows" :loading="table.loading.value" @refresh="table.reload" @select="openDetail" @close="closeDetail" />
    </AsyncBoundary>
  </section>
</template>
