<!-- SPEC: PJ2026-010405 云端控制台 / Dashboard. -->
<!-- Implementation reference: draft-2026-07-13-p0-cloud-console. -->
<!-- Responsibility: 聚合 typed summary，并以非嵌套交互入口呈现领域状态。 -->

<script setup lang="ts">
import { BadgeCheck, LayoutDashboard, ListChecks, Workflow } from "lucide-vue-next";
import { computed, type Component } from "vue";
import { RouterLink } from "vue-router";
import EntityCard from "@/components/common/EntityCard.vue";
import ResourceCollection from "@/components/common/ResourceCollection.vue";
import SectionFrame from "@/components/layout/SectionFrame.vue";
import StatusStrip from "@/components/layout/StatusStrip.vue";
import type { DashboardSummaryResponse } from "@/types";

export interface DashboardEntry {
  id: string;
  title: string;
  description: string;
  path: string;
  icon: Component;
}

const props = defineProps<{
  summary: DashboardSummaryResponse;
  entries: DashboardEntry[];
  actorName: string;
  error: string | null;
}>();

const issues = computed(() => props.summary.issues ?? []);
const continuations = computed(() => props.summary.work.continuations ?? []);
const statusItems = computed(() => [
  { id: "actor", label: "Actor", value: props.summary.actor.displayName || props.actorName },
  { id: "status", label: "Status", value: props.summary.status || "unknown", tone: props.error ? "warn" as const : "ok" as const },
  { id: "observed", label: "Observed", value: displayTime(props.summary.observedAt) },
  { id: "issues", label: "Issues", value: issues.value.length, tone: issues.value.length ? "warn" as const : "ok" as const }
]);

function displayNumber(value: number | null | undefined): string {
  return value == null ? "-" : new Intl.NumberFormat("zh-CN").format(value);
}

function displayTime(value: string | null | undefined): string {
  if (!value) return "-";
  const date = new Date(value);
  return Number.isNaN(date.getTime()) ? value : date.toLocaleString("zh-CN");
}
</script>

<template>
  <div class="dashboard-workspace">
    <StatusStrip :items="statusItems" label="当前控制台上下文" live="polite" />
    <p v-if="error" class="stale-warning" role="status">{{ error }}；保留上次成功摘要与当前 ACL 入口。</p>

    <SectionFrame title="领域状态" description="各领域状态和 authority 均来自 Dashboard typed summary。" :body-padding="false">
      <ResourceCollection
        :items="summary.sources || []"
        :item-key="(source) => source.id"
        :item-title="(source) => source.label"
        :item-subtitle="(source) => source.reason || source.authority"
        :item-status="(source) => source.state"
        view="list"
        density="compact"
        :show-controls="false"
        aria-label="领域状态"
      >
        <template #list="{ item }"><RouterLink class="industrial-card-link" :to="item.href"><EntityCard :title="item.label" :subtitle="item.reason || item.authority" :status="item.state" :icon="LayoutDashboard" :interactive="false" /></RouterLink></template>
      </ResourceCollection>
    </SectionFrame>

    <SectionFrame v-if="issues.length" title="需要处理" :description="`${issues.length} 个聚合异常`" tone="inset" :body-padding="false">
      <ResourceCollection :items="issues" :item-key="(issue) => issue.id" :item-title="(issue) => issue.title" :item-subtitle="(issue) => issue.summary" :item-status="(issue) => issue.severity" view="list" density="compact" :show-controls="false" aria-label="主要异常">
        <template #list="{ item }"><RouterLink class="industrial-card-link" :to="item.action.href"><EntityCard :title="item.title" :subtitle="item.summary" :status="item.severity" :icon="BadgeCheck" :interactive="false"><template #meta><code>{{ item.code }}</code><span>{{ item.action.label }}</span></template></EntityCard></RouterLink></template>
      </ResourceCollection>
    </SectionFrame>

    <div class="dashboard-workspace-grid">
      <SectionFrame title="继续项目与任务" :description="`${displayNumber(summary.work.projectCount)} projects / ${displayNumber(summary.work.taskCounts.blocked)} blocked`" :body-padding="false">
        <ResourceCollection :items="continuations" :item-key="(task) => task.taskRef" :item-title="(task) => task.title" :item-subtitle="(task) => `${task.taskId} · ${task.projectId || task.sourceId}`" :item-status="(task) => task.status" view="list" density="compact" :show-controls="false" empty-text="当前没有可继续的 open / in_progress 任务。" aria-label="可继续任务">
          <template #list="{ item }"><RouterLink class="industrial-card-link" :to="item.href"><EntityCard :title="item.title" :subtitle="`${item.taskId} · ${item.projectId || item.sourceId}`" :status="item.status" :icon="ListChecks" :interactive="false" /></RouterLink></template>
        </ResourceCollection>
      </SectionFrame>

      <SectionFrame title="实时业务摘要" description="聚合 DTO 不替代各领域 authority。">
        <dl class="industrial-fact-row dashboard-facts">
          <div><dt>任务</dt><dd>{{ displayNumber(summary.work.taskCounts.open) }} open / {{ displayNumber(summary.work.taskCounts.inProgress) }} active</dd></div>
          <div><dt>HWPOD Node</dt><dd>{{ displayNumber(summary.hwpod.onlineNodeCount) }} / {{ displayNumber(summary.hwpod.nodeCount) }} online</dd></div>
          <div><dt>设备</dt><dd>{{ displayNumber(summary.hwpod.availableDeviceCount) }} available / {{ displayNumber(summary.hwpod.busyDeviceCount) }} busy</dd></div>
          <div><dt>Plan</dt><dd>{{ summary.billing.plan?.displayName || summary.billing.plan?.id || '-' }}</dd></div>
          <div><dt>Available credits</dt><dd>{{ displayNumber(summary.billing.credits?.available) }}</dd></div>
        </dl>
      </SectionFrame>
    </div>

    <SectionFrame title="全部入口" description="由当前 session 的 navId ACL 过滤。" :body-padding="false">
      <ResourceCollection :items="entries" :item-key="(entry) => entry.id" :item-title="(entry) => entry.title" :item-subtitle="(entry) => entry.description" view="cards" density="compact" :show-controls="false" aria-label="可用工作入口">
        <template #card="{ item }"><RouterLink class="industrial-card-link" :to="item.path"><EntityCard :title="item.title" :subtitle="item.description" :icon="item.icon" :interactive="false"><template #meta><code>{{ item.id }}</code><Workflow :size="14" aria-hidden="true" /></template></EntityCard></RouterLink></template>
      </ResourceCollection>
    </SectionFrame>
  </div>
</template>

<style scoped>
.dashboard-workspace { display: grid; gap: 12px; min-width: 0; }
.dashboard-workspace-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(280px, 360px); gap: 12px; min-width: 0; }
.dashboard-facts { grid-template-columns: 1fr; }
@media (max-width: 900px) { .dashboard-workspace-grid { grid-template-columns: 1fr; } }
</style>
