Files
Edu/apps/parent-portal/src/lib/graphql/operations.ts
SpecialX 5661938cc0 feat(parent-portal): 完整实现 P4+P5+P6 家长端微前端
实现内容(仲裁裁决驱动,首次即最终方案):

P4 核心功能
- 认证:localStorage token 存储(F12)+ REST 登录(ISSUE-004)+ refreshAccessToken 竞态防护
- 子女切换:ChildSwitcher(Tab ≤3 / 下拉 ≥4)+ Zustand store(ISSUE-009 纯前端切换)
- 数据查询:urql GraphQL 消费 parent-bff(F9)+ TanStack Query 缓存
- 通知中心:NotificationFeed + 已读/全部已读 mutations
- 通知偏好:三维矩阵 + ISSUE-033 localStorage 降级
- 5 层状态管理:URL/Server/Client/Global UI/Form
- 跨标签同步:BroadcastChannel + storage 事件

P5 实时推送
- WebSocket 连接 push-gateway + 指数退避重连
- HTTP 轮询降级(60s)+ 实时通知 Hook

P6 硬化
- Web Vitals 上报 + OTel trace
- i18n 5 语言(zh-CN/en-US/zh-TW/ja-JP/ar-SA 含 RTL)
- PWA manifest + Service Worker
- CSP 安全头 + 权限点 F7 命名 + 设计令牌三层

测试与构建
- Vitest 92 测试全通过(utils/auth/child-store/ChildSwitcher/NotificationFeed/login)
- MSW mock 未就绪上游(parent-bff GraphQL + iam REST + iam GetChildrenByParent P0 阻塞用 fixtures)
- Dockerfile 多阶段构建(G1,端口 4002,HEALTHCHECK /api/health)
- typecheck + lint 零错误

经验沉淀
- known-issues.md §2.13 追加 12 条实现期经验(无 AI 身份标注)
- arch.db 已更新(15 TS 模块 / 482 符号 / 138 proto)

依据:02-architecture-design.md(回写总裁裁决)、coord-final-decisions.md、
president-final-rulings.md、parent-portal_workline.md、parent-portal_contract.md
2026-07-10 17:40:27 +08:00

211 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// GraphQL operations 文档
// 依据02-architecture-design.md §4.2 GraphQL 接入、F9 裁决(首次即 GraphQL
// 端点POST /api/v1/parent/graphql
// 命名:查询 PascalCaseCurrentUser / MyChildren / ChildSummary ...
//
// 所有查询/变更与 parent-bff 契约对齐:
// - 查询currentUser / myChildren / childSummary / childGrades / childAttendance /
// childHomework / childWeakness / childTrend / myNotifications / myNotificationPreferences
// - 变更markAsRead / markAllAsRead / updateNotificationPreferences
import { gql } from "urql";
// ===== 查询 =====
export const CURRENT_USER = gql`
query CurrentUser {
currentUser {
id
email
name
roles
permissions
dataScope
schoolId
}
}
`;
export const MY_CHILDREN = gql`
query MyChildren {
myChildren {
id
name
avatar
grade
schoolName
classId
className
isArchived
}
}
`;
export const CHILD_SUMMARY = gql`
query ChildSummary($childId: ID!) {
childSummary(childId: $childId) {
childId
avgScore
classRank
classSize
attendanceRate
pendingHomeworkCount
recentGradeTrend
recentScores {
examId
examName
examDate
subject
studentScore
classAverage
classMax
classMin
gradeLevel
}
upcomingEvents {
id
type
title
dueDate
}
}
}
`;
export const CHILD_GRADES = gql`
query ChildGrades($childId: ID!, $subject: String, $limit: Int) {
childGrades(childId: $childId, subject: $subject, limit: $limit) {
examId
examName
examDate
subject
studentScore
classAverage
classMax
classMin
gradeLevel
}
}
`;
export const CHILD_ATTENDANCE = gql`
query ChildAttendance($childId: ID!, $startDate: String!, $endDate: String!) {
childAttendance(
childId: $childId
startDate: $startDate
endDate: $endDate
) {
id
date
status
note
}
}
`;
export const CHILD_HOMEWORK = gql`
query ChildHomework($childId: ID!, $status: String) {
childHomework(childId: $childId, status: $status) {
id
title
subject
className
assignedDate
dueDate
status
score
maxScore
feedback
}
}
`;
export const CHILD_WEAKNESS = gql`
query ChildWeakness($childId: ID!) {
childWeakness(childId: $childId) {
id
knowledgePoint
masteryLevel
subject
recommendation
}
}
`;
export const CHILD_TREND = gql`
query ChildTrend($childId: ID!, $period: TrendPeriod!) {
childTrend(childId: $childId, period: $period) {
childId
period
dataPoints {
date
score
subject
}
}
}
`;
export const MY_NOTIFICATIONS = gql`
query MyNotifications($unreadOnly: Boolean, $limit: Int) {
myNotifications(unreadOnly: $unreadOnly, limit: $limit) {
id
childId
eventType
title
body
read
createdAt
actionUrl
pinned
}
}
`;
export const MY_NOTIFICATION_PREFERENCES = gql`
query MyNotificationPreferences {
myNotificationPreferences {
parentId
preferences
defaults
updatedAt
}
}
`;
// ===== 变更 =====
export const MARK_AS_READ = gql`
mutation MarkAsRead($notificationId: ID!) {
markAsRead(notificationId: $notificationId) {
id
read
}
}
`;
export const MARK_ALL_AS_READ = gql`
mutation MarkAllAsRead {
markAllAsRead {
count
}
}
`;
export const UPDATE_NOTIFICATION_PREFERENCES = gql`
mutation UpdateNotificationPreferences(
$parentId: ID!
$preferences: JSON!
$defaults: JSON!
) {
updateNotificationPreferences(
parentId: $parentId
preferences: $preferences
defaults: $defaults
) {
parentId
updatedAt
}
}
`;