- P3 考试/作业/成绩 mutation + 详情页 + 批改界面 + 乐观更新 + 多 Tab 同步 - P4 知识图谱 SVG 可视化 + 学情分析仪表盘 + parent-portal Remote - P5 WebSocket 通知中心 + AI 出题(SSE) + AI 教案 + AI 学情报告 - P6 可观测性硬化:Sentry + WebVitals + OTel + A11y + 性能配置 + Cookie 迁移 - P7 参考项目差距闭环:新增 35 个页面覆盖 13 个缺失模块 - attendance(考勤 4 页)/questions(题库)/textbooks(教材 2 页) - classes/[id] 详情 + classes/schedule 课表 - course-plans(2 页)/diagnostic(2 页)/error-book/practice - exams/[id]/build 组卷 + exams/[id]/analytics 考后分析 - exams/[id]/edit-rich 富文本编辑 + exams/[id]/proctoring 监考 - grades/entry 批量录入 + grades/stats 统计 + grades/analytics 分析 + grades/report-card 报告卡 - homework/submissions 列表 + assignments/[id]/submissions 批量批改 - homework/submissions/[submissionId] 单份批改 + scan-grading 扫描批改 - lesson-plans 编辑器 + library + calendar + heatmap 5 页 - elective 选修课 3 页 /leave 请假 /schedule-changes 调课 - P7 基础设施:61 GraphQL operations + 5 handlers + 13 fixtures + 11 viewports - 集成 browser.ts/server.ts 注册所有 p7 handlers(fallthrough 顺序) - viewports.ts 扩展 11 个新导航项 - 验证:tsc --noEmit 零错误 + eslint 零错误 - 文档:workline.md 新增 §5 P7 参考项目差距闭环(含完整文件清单)
91 lines
2.6 KiB
TypeScript
91 lines
2.6 KiB
TypeScript
"use client";
|
||
|
||
/**
|
||
* ParentPortalRemote - parent-portal MF Remote 接入组件
|
||
*
|
||
* 职责(ARB-002 §2.3):
|
||
* - NEXT_PUBLIC_MF_ENABLED=true:通过 Module Federation 动态加载 parent-portal Remote
|
||
* - NEXT_PUBLIC_MF_ENABLED=false:展示"需启用微前端模式"提示
|
||
* - 使用 next/dynamic 懒加载(ssr: false,Remote 仅 CSR)
|
||
* - ErrorBoundary 兜底:Remote 加载/渲染失败时降级展示
|
||
*
|
||
* 维护者:ai13(teacher-portal)
|
||
*/
|
||
|
||
import dynamic from "next/dynamic";
|
||
import { ErrorBoundary } from "@edu/ui-components";
|
||
|
||
const MF_ENABLED = process.env.NEXT_PUBLIC_MF_ENABLED === "true";
|
||
|
||
/** 动态加载 parent-portal Remote(仅 CSR,加载失败返回降级组件) */
|
||
const ParentRemote = dynamic(
|
||
() =>
|
||
import("parent/ParentApp")
|
||
.then((mod) => mod.default)
|
||
.catch(() => FallbackRemote),
|
||
{
|
||
ssr: false,
|
||
loading: () => (
|
||
<p className="text-sm text-ink-muted p-6">正在加载家长端视图…</p>
|
||
),
|
||
},
|
||
);
|
||
|
||
/** Remote 加载失败时的降级组件 */
|
||
function FallbackRemote(): React.ReactNode {
|
||
return (
|
||
<div className="p-8 text-center">
|
||
<p className="text-lg font-serif text-ink">家长端视图加载失败</p>
|
||
<p className="mt-2 text-sm text-ink-muted">
|
||
请确认 parent-portal 服务已启动(端口 4002)并已暴露 ParentApp
|
||
</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
/** MF 未启用时的提示 */
|
||
function MfDisabledNotice(): React.ReactNode {
|
||
return (
|
||
<div className="p-8 border border-rule rounded-card bg-surface text-center">
|
||
<p className="text-lg font-serif text-ink">
|
||
家长端视图需启用微前端模式
|
||
</p>
|
||
<p className="mt-2 text-sm text-ink-muted">
|
||
设置环境变量 NEXT_PUBLIC_MF_ENABLED=true 后重启服务,
|
||
并确保 parent-portal 已在 next.config.js remotes 中注册。
|
||
</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default function ParentPortalRemote(): React.ReactNode {
|
||
if (!MF_ENABLED) {
|
||
return <MfDisabledNotice />;
|
||
}
|
||
|
||
return (
|
||
<ErrorBoundary
|
||
fallback={(error, reset) => (
|
||
<div
|
||
role="alert"
|
||
className="flex flex-col items-center justify-center gap-4 p-8"
|
||
>
|
||
<h2 className="text-lg font-serif text-ink">
|
||
家长端视图渲染异常
|
||
</h2>
|
||
<p className="text-sm text-ink-muted">{error.message}</p>
|
||
<button
|
||
type="button"
|
||
onClick={reset}
|
||
className="px-4 py-2 text-sm text-ink-on-accent bg-accent rounded-button hover:bg-accent-hover"
|
||
>
|
||
重试
|
||
</button>
|
||
</div>
|
||
)}
|
||
>
|
||
<ParentRemote />
|
||
</ErrorBoundary>
|
||
);
|
||
}
|