feat(dashboard): 实现所有长期问题修复(P2-1/P2-5/P2-7/P2-9)

P2-9: TeacherSchedule 重复渲染优化
- 将移动端(lg:hidden)和桌面端(hidden lg:block)的双实例渲染改为单实例
- 使用 CSS flex order + grid col-start/row-start 实现响应式布局重排序
- 消除服务端 HTML 负载翻倍问题

P2-5: StudentTodayScheduleCard 时间过时修复
- 新增 useCurrentTime hook(src/shared/hooks/use-current-time.ts)
- 每分钟自动更新当前时间,useMemo 依赖 [items, now] 确保徽章不过时
- SSR 安全:初始渲染用 new Date(),挂载后 setInterval 更新

P2-1: 流式/Suspense 架构改造
- 新增 getAdminDashboardStreams(streams.ts):返回各独立数据源的未解析 Promise
- Admin dashboard:7 个分区组件用 React use() 独立消费 Promise,各 Suspense 边界独立流式渲染
- Teacher/Student/Parent dashboard:传入未解析 Promise,视图用 use() 消费,启用 Suspense 流式
- 页面外壳(标题 + 快捷操作)立即渲染,数据到达后各分区按各自速度填充

P2-7: 组件测试 + 路由测试修复
- 修复 dashboard-routing.test.ts:移除误导性的 permissions 字段(实际用 resolvePermissions(roles))
- 新增 fallback 路由测试(未知角色 → teacher dashboard)
- 新增 DashboardSection 组件测试(6 个测试:骨架屏变体 + 错误边界 + 正常渲染)
- 新增 useCurrentTime hook 测试(3 个测试:初始值 + 间隔更新 + 清理)

同步更新:
- docs/architecture/005_architecture_data.json 新增 7 个流式组件 + useCurrentTime hook + getAdminDashboardStreams 条目
This commit is contained in:
SpecialX
2026-06-23 09:04:40 +08:00
parent e2e0487a3b
commit 2c0f81391b
16 changed files with 649 additions and 230 deletions

View File

@@ -1,11 +1,19 @@
import type { Metadata } from "next"
import type { JSX } from "react"
import { getTranslations } from "next-intl/server"
import { use } from "react"
import { Users } from "lucide-react"
import { getParentDashboardAction } from "@/modules/dashboard/actions"
import { ParentDashboard } from "@/modules/parent/components/parent-dashboard"
import { ParentNoChildrenPage } from "@/modules/parent/components/parent-children-data-page"
import { Users } from "lucide-react"
import type { ActionState } from "@/shared/types/action-state"
import type { ParentDashboardData } from "@/modules/parent/types"
type ParentDashboardResult = ActionState<{
data: ParentDashboardData | null
hasChildren: boolean
}>
export const dynamic = "force-dynamic"
@@ -18,8 +26,27 @@ export async function generateMetadata(): Promise<Metadata> {
}
export default async function ParentDashboardPage(): Promise<JSX.Element> {
// 传入未解析的 Promise视图内用 React `use()` 消费,启用 Suspense 流式渲染
const dataPromise = getParentDashboardAction()
return <ParentDashboardResolver dataPromise={dataPromise} />
}
function ParentDashboardResolver({ dataPromise }: { dataPromise: Promise<ParentDashboardResult> }) {
const result = use(dataPromise)
if (!result.success || !result.data) {
throw new Error(result.message ?? "Failed to load parent dashboard")
}
return <ParentDashboardBody data={result.data.data} hasChildren={result.data.hasChildren} />
}
async function ParentDashboardBody({
data,
hasChildren,
}: {
data: ParentDashboardData | null
hasChildren: boolean
}) {
const t = await getTranslations("dashboard")
const { data, hasChildren } = await getParentDashboardAction()
if (!data || !hasChildren) {
return (