feat(teacher-portal): 完成参考项目差距闭环 P3-P7 全量实现
- 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 参考项目差距闭环(含完整文件清单)
This commit is contained in:
@@ -26,6 +26,10 @@ import { usePermission } from "@edu/hooks";
|
||||
import { ViewportsQuery, MeQuery } from "@/lib/graphql";
|
||||
import type { ViewportItem, User } from "@/lib/graphql";
|
||||
import { getToken, getUser, logout } from "@/lib/auth";
|
||||
import {
|
||||
useCrossTabSync,
|
||||
broadcastCrossTabEvent,
|
||||
} from "@/hooks/use-cross-tab-sync";
|
||||
|
||||
/**
|
||||
* 权限上下文:从 localStorage 读取(登录时由 iam 返回并存储)。
|
||||
@@ -54,6 +58,9 @@ export default function AppShell({ children }: { children: React.ReactNode }) {
|
||||
}
|
||||
}, [router]);
|
||||
|
||||
// 多 Tab 会话同步:监听 logout / role-change / token-refresh 事件
|
||||
useCrossTabSync();
|
||||
|
||||
// GraphQL: viewports query(替代 REST /api/v1/teacher/viewports)
|
||||
const [viewportsResult] = useQuery({
|
||||
query: ViewportsQuery,
|
||||
@@ -95,6 +102,12 @@ export default function AppShell({ children }: { children: React.ReactNode }) {
|
||||
</p>
|
||||
) : null;
|
||||
|
||||
// 退出登录:先广播给其他 Tab,再执行本地登出
|
||||
const handleLogout = () => {
|
||||
broadcastCrossTabEvent("logout");
|
||||
logout();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex bg-paper">
|
||||
{/* 左侧栏:导航树 */}
|
||||
@@ -140,7 +153,7 @@ export default function AppShell({ children }: { children: React.ReactNode }) {
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
onClick={logout}
|
||||
onClick={handleLogout}
|
||||
className="text-tiny uppercase tracking-wide text-ink-muted hover:opacity-70"
|
||||
>
|
||||
退出登录
|
||||
|
||||
Reference in New Issue
Block a user