2366 lines
44 KiB
GraphQL
2366 lines
44 KiB
GraphQL
# teacher-bff GraphQL Schema (SDL-first, president §2.17)
|
||
# 版本:v2(ARB-001 扁平命名重构,admin 字段直接挂载根 Query/Mutation)
|
||
# 负责人:ai03
|
||
# 关联:contracts/teacher-bff_contract.md §1.3、workline §3.1
|
||
#
|
||
# 设计原则(02-architecture-design.md §5.1):
|
||
# 1. 按教学场景域组织(不按角色分),教导主任/教研组长复用同一 schema
|
||
# 2. Query 为主,Mutation 谨慎(BFF 偏读多写少)
|
||
# 3. N+1 防御:所有 list 字段经 DataLoader(P4 全量接入)
|
||
# 4. 复杂度限制:depth ≤ 7,query cost ≤ 1000
|
||
# 5. admin 扁平命名(ARB-001 裁决:admin 字段直接挂载根 Query/Mutation)
|
||
#
|
||
# 错误响应格式:GraphQL errors 数组 + extensions.code = BFF_TEACHER_* + extensions.traceId
|
||
# 降级模式 B(president §2.6):success=true + error=null + data 内 degraded 字段
|
||
|
||
scalar DateTime
|
||
|
||
# ============ Teacher 域类型 ============
|
||
|
||
type User {
|
||
id: ID!
|
||
email: String!
|
||
name: String!
|
||
roles: [String!]!
|
||
permissions: [String!]!
|
||
dataScope: DataScope!
|
||
}
|
||
|
||
enum DataScope {
|
||
SELF
|
||
SUBJECT
|
||
CLASS
|
||
GRADE
|
||
SCHOOL
|
||
ALL
|
||
}
|
||
|
||
type ViewportItem {
|
||
key: String!
|
||
label: String!
|
||
route: String!
|
||
icon: String
|
||
sortOrder: String!
|
||
requiredPermission: String
|
||
}
|
||
|
||
type Class {
|
||
id: ID!
|
||
name: String!
|
||
gradeId: String!
|
||
exams: [Exam!]!
|
||
homework: [Homework!]!
|
||
}
|
||
|
||
type Exam {
|
||
id: ID!
|
||
title: String!
|
||
classId: ID!
|
||
status: ExamStatus!
|
||
publishedAt: DateTime
|
||
grades: [Grade!]!
|
||
}
|
||
|
||
enum ExamStatus {
|
||
DRAFT
|
||
PUBLISHED
|
||
IN_PROGRESS
|
||
GRADING
|
||
SCORED
|
||
ARCHIVED
|
||
}
|
||
|
||
type Homework {
|
||
id: ID!
|
||
title: String!
|
||
classId: ID!
|
||
dueDate: DateTime!
|
||
status: String
|
||
submissions: [Submission!]!
|
||
}
|
||
|
||
type Submission {
|
||
id: ID!
|
||
studentId: ID!
|
||
submittedAt: DateTime!
|
||
status: SubmissionStatus!
|
||
}
|
||
|
||
enum SubmissionStatus {
|
||
NOT_SUBMITTED
|
||
SUBMITTED
|
||
GRADED
|
||
}
|
||
|
||
type Grade {
|
||
id: ID!
|
||
examId: ID!
|
||
studentId: ID!
|
||
score: Float!
|
||
rank: Int
|
||
submittedAt: DateTime!
|
||
}
|
||
|
||
type DashboardStats {
|
||
totalExams: Int
|
||
pendingGrading: Int
|
||
todayHomework: Int
|
||
}
|
||
|
||
type DashboardData {
|
||
user: User
|
||
classes: [Class!]!
|
||
viewports: [ViewportItem!]!
|
||
stats: DashboardStats
|
||
}
|
||
|
||
type KnowledgePath {
|
||
knowledgePointId: ID!
|
||
name: String!
|
||
prerequisites: [KnowledgePoint!]!
|
||
}
|
||
|
||
type KnowledgePoint {
|
||
id: ID!
|
||
name: String!
|
||
subject: String!
|
||
}
|
||
|
||
type ClassPerformance {
|
||
classId: ID!
|
||
averageScore: Float!
|
||
passRate: Float!
|
||
weaknessTopics: [String!]!
|
||
}
|
||
|
||
type StudentWeakness {
|
||
studentId: ID!
|
||
weakTopics: [String!]!
|
||
recommendedExercises: [String!]!
|
||
}
|
||
|
||
type LearningTrend {
|
||
studentId: ID!
|
||
trend: [TrendPoint!]!
|
||
}
|
||
|
||
type TrendPoint {
|
||
date: DateTime!
|
||
score: Float!
|
||
}
|
||
|
||
type Notification {
|
||
id: ID!
|
||
type: NotificationType!
|
||
title: String!
|
||
content: String!
|
||
read: Boolean!
|
||
createdAt: DateTime!
|
||
}
|
||
|
||
enum NotificationType {
|
||
SYSTEM
|
||
EXAM
|
||
HOMEWORK
|
||
GRADE
|
||
ATTENDANCE
|
||
}
|
||
|
||
type GeneratedQuestion {
|
||
id: ID!
|
||
subject: String!
|
||
difficulty: String!
|
||
content: String!
|
||
answer: String!
|
||
}
|
||
|
||
# ============ Admin 域类型(ARB-001 扁平命名)============
|
||
|
||
type AdminUser {
|
||
id: ID!
|
||
email: String!
|
||
name: String!
|
||
roles: [AdminRoleRef!]!
|
||
status: String!
|
||
dataScope: String
|
||
organizationId: ID
|
||
schoolName: String
|
||
lastLoginAt: DateTime
|
||
createdAt: DateTime!
|
||
updatedAt: DateTime!
|
||
}
|
||
|
||
type AdminRoleRef {
|
||
id: ID!
|
||
name: String!
|
||
code: String!
|
||
}
|
||
|
||
type AdminUserPage {
|
||
items: [AdminUser!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
hasNext: Boolean!
|
||
}
|
||
|
||
type AdminRole {
|
||
id: ID!
|
||
name: String!
|
||
code: String!
|
||
description: String
|
||
permissions: [AdminPermission!]!
|
||
userCount: Int!
|
||
dataScope: String
|
||
isSystem: Boolean!
|
||
createdAt: DateTime!
|
||
updatedAt: DateTime!
|
||
}
|
||
|
||
type AdminPermission {
|
||
id: ID!
|
||
code: String!
|
||
name: String!
|
||
description: String
|
||
resource: String!
|
||
action: String!
|
||
isSystem: Boolean!
|
||
}
|
||
|
||
type AdminViewport {
|
||
id: ID!
|
||
key: String!
|
||
label: String!
|
||
route: String!
|
||
icon: String
|
||
sortOrder: String!
|
||
requiredPermission: String
|
||
scope: String!
|
||
isVisible: Boolean!
|
||
}
|
||
|
||
type AdminOrganization {
|
||
id: ID!
|
||
name: String!
|
||
type: String!
|
||
parentId: ID
|
||
childrenCount: Int!
|
||
sortOrder: Int!
|
||
}
|
||
|
||
type AdminClass {
|
||
id: ID!
|
||
name: String!
|
||
gradeName: String!
|
||
schoolName: String!
|
||
headTeacherName: String
|
||
studentCount: Int!
|
||
createdAt: DateTime!
|
||
}
|
||
|
||
type AdminClassPage {
|
||
items: [AdminClass!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
hasNext: Boolean!
|
||
}
|
||
|
||
type AdminTeacher {
|
||
id: ID!
|
||
email: String!
|
||
name: String!
|
||
schoolName: String
|
||
subjects: [String!]!
|
||
classCount: Int!
|
||
status: String!
|
||
lastLoginAt: DateTime
|
||
}
|
||
|
||
type AdminTeacherPage {
|
||
items: [AdminTeacher!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
hasNext: Boolean!
|
||
}
|
||
|
||
type AdminStudent {
|
||
id: ID!
|
||
email: String!
|
||
name: String!
|
||
className: String
|
||
gradeName: String
|
||
schoolName: String
|
||
guardianName: String
|
||
guardianPhone: String
|
||
status: String!
|
||
}
|
||
|
||
type AdminStudentPage {
|
||
items: [AdminStudent!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
hasNext: Boolean!
|
||
}
|
||
|
||
type AuditLogEntry {
|
||
id: ID!
|
||
eventId: String!
|
||
occurredAt: DateTime!
|
||
actorUserId: ID!
|
||
actorName: String
|
||
action: String!
|
||
resourceType: String!
|
||
resourceId: ID
|
||
ip: String
|
||
userAgent: String
|
||
beforeState: String
|
||
afterState: String
|
||
traceId: String
|
||
}
|
||
|
||
type AuditLogPage {
|
||
items: [AuditLogEntry!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
hasNext: Boolean!
|
||
}
|
||
|
||
type AdminDashboard {
|
||
totalTeachers: Int!
|
||
totalStudents: Int!
|
||
totalClasses: Int!
|
||
totalSchools: Int!
|
||
schoolAvgScore: Float!
|
||
activeUsersToday: Int!
|
||
auditEventsToday: Int!
|
||
trend: [AdminDashboardTrendPoint!]!
|
||
serviceHealth: [ServiceHealthItem!]!
|
||
}
|
||
|
||
type AdminDashboardTrendPoint {
|
||
date: String!
|
||
teachers: Int!
|
||
students: Int!
|
||
avgScore: Float!
|
||
}
|
||
|
||
type ServiceHealthItem {
|
||
serviceName: String!
|
||
status: String!
|
||
latencyMs: Int!
|
||
}
|
||
|
||
type SystemSettings {
|
||
schoolName: String!
|
||
schoolCode: String!
|
||
academicYear: String!
|
||
semester: String!
|
||
contactEmail: String!
|
||
contactPhone: String!
|
||
address: String!
|
||
timezone: String!
|
||
locale: String!
|
||
}
|
||
|
||
type AuditOverviewStats {
|
||
totalEvents: Int!
|
||
todayEvents: Int!
|
||
uniqueActors: Int!
|
||
failedActions: Int!
|
||
topActions: [AuditActionCount!]!
|
||
topResources: [AuditResourceCount!]!
|
||
}
|
||
|
||
type AuditActionCount {
|
||
action: String!
|
||
count: Int!
|
||
}
|
||
|
||
type AuditResourceCount {
|
||
resource: String!
|
||
count: Int!
|
||
}
|
||
|
||
type AuditTrendPoint {
|
||
date: String!
|
||
count: Int!
|
||
action: String!
|
||
}
|
||
|
||
type DataChangeLog {
|
||
id: ID!
|
||
occurredAt: DateTime!
|
||
actorUserId: ID!
|
||
actorName: String
|
||
tableName: String!
|
||
action: String!
|
||
recordId: ID
|
||
beforeState: String
|
||
afterState: String
|
||
ip: String
|
||
}
|
||
|
||
type DataChangeLogPage {
|
||
items: [DataChangeLog!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
hasNext: Boolean!
|
||
}
|
||
|
||
type LoginLog {
|
||
id: ID!
|
||
occurredAt: DateTime!
|
||
userId: ID!
|
||
userName: String
|
||
action: String!
|
||
status: String!
|
||
ip: String
|
||
userAgent: String
|
||
failureReason: String
|
||
}
|
||
|
||
type LoginLogPage {
|
||
items: [LoginLog!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
hasNext: Boolean!
|
||
}
|
||
|
||
type AdminSchool {
|
||
id: ID!
|
||
name: String!
|
||
code: String!
|
||
address: String
|
||
contactPhone: String
|
||
contactEmail: String
|
||
principalName: String
|
||
gradeCount: Int!
|
||
classCount: Int!
|
||
studentCount: Int!
|
||
teacherCount: Int!
|
||
createdAt: DateTime!
|
||
}
|
||
|
||
type AdminGrade {
|
||
id: ID!
|
||
name: String!
|
||
schoolId: ID!
|
||
schoolName: String!
|
||
directorName: String
|
||
classCount: Int!
|
||
studentCount: Int!
|
||
sortOrder: Int!
|
||
createdAt: DateTime!
|
||
}
|
||
|
||
type AdminGradeInsights {
|
||
gradeId: ID!
|
||
gradeName: String!
|
||
schoolWideSummary: SchoolWideSummary!
|
||
homeworkTimeline: [HomeworkTimelineItem!]!
|
||
classRankings: [ClassRankingItem!]!
|
||
}
|
||
|
||
type SchoolWideSummary {
|
||
totalStudents: Int!
|
||
totalClasses: Int!
|
||
avgScore: Float!
|
||
passingRate: Float!
|
||
}
|
||
|
||
type HomeworkTimelineItem {
|
||
homeworkId: ID!
|
||
title: String!
|
||
className: String!
|
||
avgScore: Float!
|
||
submittedCount: Int!
|
||
totalCount: Int!
|
||
dueDate: DateTime!
|
||
}
|
||
|
||
type ClassRankingItem {
|
||
classId: ID!
|
||
className: String!
|
||
avgScore: Float!
|
||
rank: Int!
|
||
delta: Float!
|
||
}
|
||
|
||
type AdminDepartment {
|
||
id: ID!
|
||
name: String!
|
||
schoolId: ID!
|
||
schoolName: String!
|
||
leaderName: String
|
||
memberCount: Int!
|
||
subject: String
|
||
createdAt: DateTime!
|
||
}
|
||
|
||
type AdminAcademicYear {
|
||
id: ID!
|
||
name: String!
|
||
startDate: DateTime!
|
||
endDate: DateTime!
|
||
firstSemesterStart: DateTime!
|
||
firstSemesterEnd: DateTime!
|
||
secondSemesterStart: DateTime!
|
||
secondSemesterEnd: DateTime!
|
||
isCurrent: Boolean!
|
||
createdAt: DateTime!
|
||
}
|
||
|
||
type AdminAnnouncement {
|
||
id: ID!
|
||
title: String!
|
||
content: String!
|
||
status: String!
|
||
audience: String!
|
||
authorName: String
|
||
isPinned: Boolean!
|
||
readCount: Int!
|
||
totalCount: Int!
|
||
publishedAt: DateTime
|
||
createdAt: DateTime!
|
||
updatedAt: DateTime!
|
||
}
|
||
|
||
type AdminAnnouncementPage {
|
||
items: [AdminAnnouncement!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
hasNext: Boolean!
|
||
}
|
||
|
||
type AdminInvitationCode {
|
||
id: ID!
|
||
code: String!
|
||
status: String!
|
||
roleId: ID!
|
||
roleName: String
|
||
classId: ID
|
||
className: String
|
||
email: String
|
||
batchId: String!
|
||
usedBy: ID
|
||
usedByName: String
|
||
usedAt: DateTime
|
||
createdAt: DateTime!
|
||
expiresAt: DateTime!
|
||
}
|
||
|
||
type AdminInvitationCodePage {
|
||
items: [AdminInvitationCode!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
hasNext: Boolean!
|
||
}
|
||
|
||
type AdminFile {
|
||
id: ID!
|
||
filename: String!
|
||
mimeType: String!
|
||
size: Int!
|
||
url: String!
|
||
entityType: String
|
||
entityId: ID
|
||
uploadedByName: String
|
||
createdAt: DateTime!
|
||
}
|
||
|
||
type AdminFilePage {
|
||
items: [AdminFile!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
hasNext: Boolean!
|
||
}
|
||
|
||
type AdminFileStats {
|
||
totalFiles: Int!
|
||
totalSize: Int!
|
||
byMimeType: [FileMimeTypeStat!]!
|
||
byEntityType: [FileEntityTypeStat!]!
|
||
}
|
||
|
||
type FileMimeTypeStat {
|
||
mimeType: String!
|
||
count: Int!
|
||
size: Int!
|
||
}
|
||
|
||
type FileEntityTypeStat {
|
||
entityType: String!
|
||
count: Int!
|
||
}
|
||
|
||
type AiProvider {
|
||
id: ID!
|
||
name: String!
|
||
type: String!
|
||
model: String!
|
||
apiKey: String!
|
||
baseUrl: String
|
||
isEnabled: Boolean!
|
||
createdAt: DateTime!
|
||
updatedAt: DateTime!
|
||
}
|
||
|
||
type AiUsage {
|
||
totalRequests: Int!
|
||
totalTokens: Int!
|
||
totalCost: Float!
|
||
byProvider: [AiProviderUsage!]!
|
||
byDay: [AiDayUsage!]!
|
||
}
|
||
|
||
type AiProviderUsage {
|
||
providerId: ID!
|
||
providerName: String!
|
||
requests: Int!
|
||
tokens: Int!
|
||
cost: Float!
|
||
}
|
||
|
||
type AiDayUsage {
|
||
date: String!
|
||
requests: Int!
|
||
tokens: Int!
|
||
cost: Float!
|
||
}
|
||
|
||
type GenerateInvitationCodesResult {
|
||
codes: [String!]!
|
||
batchId: String!
|
||
}
|
||
|
||
# ============ Query(41 个:teacher 域 13 + admin 域 28)============
|
||
|
||
type Query {
|
||
# ===== Teacher 域(13 Query)=====
|
||
|
||
dashboard: DashboardData!
|
||
viewports: [ViewportItem!]!
|
||
me: User!
|
||
classes: [Class!]!
|
||
class(id: ID!): Class
|
||
exams(classId: ID!): [Exam!]!
|
||
homework(classId: ID!): [Homework!]!
|
||
grades(examId: ID!): [Grade!]!
|
||
knowledgePath(knowledgePointId: ID!): KnowledgePath!
|
||
classPerformance(classId: ID!): ClassPerformance!
|
||
studentWeakness(studentId: ID!): StudentWeakness!
|
||
learningTrend(studentId: ID!, dateRange: DateRangeInput): LearningTrend!
|
||
notifications(unreadOnly: Boolean): [Notification!]!
|
||
|
||
# ===== P3-P5 扩展 Query(teacher-portal 期望)=====
|
||
|
||
classStudents(classId: ID!): [Student!]!
|
||
examDetail(id: ID!): ExamDetail
|
||
homeworkDetail(id: ID!): HomeworkDetail
|
||
classExams(classId: ID!): [Exam!]!
|
||
classHomework(classId: ID!): [Homework!]!
|
||
examGrades(examId: ID!): [Grade!]!
|
||
|
||
# ===== P4 扩展 Query =====
|
||
|
||
knowledgeGraph(classId: ID, subject: String): KnowledgeGraph!
|
||
classAnalytics(classId: ID!): ClassAnalytics!
|
||
studentAnalytics(studentId: ID!): StudentAnalytics!
|
||
|
||
# ===== P5 扩展 Query =====
|
||
|
||
myNotifications(unreadOnly: Boolean): [Notification!]!
|
||
|
||
# ===== P7 扩展 Query(全部降级返回空/null)=====
|
||
|
||
attendanceList(filter: AttendanceListFilterInput): AttendanceListPage!
|
||
attendanceSheet(classId: ID!, date: String!): [AttendanceSheetItem!]!
|
||
attendanceStats(classId: ID!, startDate: String!, endDate: String!): AttendanceStats!
|
||
attendanceClassComparison(startDate: String!, endDate: String!): [AttendanceClassComparisonItem!]!
|
||
attendanceWarnings(classId: ID!, startDate: String!, endDate: String!): [AttendanceWarning!]!
|
||
attendanceReport(classId: ID!, reportType: AttendanceReportType!, startDate: String!, endDate: String!): AttendanceReport!
|
||
classDetail(id: ID!): ClassDetail
|
||
classSchedule(classId: ID): [ClassScheduleItem!]!
|
||
leaveRequests(filter: LeaveRequestsFilterInput): LeaveRequestPage!
|
||
scheduleChanges(page: Int, pageSize: Int): ScheduleChangePage!
|
||
electiveCourses(status: String, subject: String): [ElectiveCourse!]!
|
||
electiveCourseDetail(id: ID!): ElectiveCourse
|
||
examRichEditor(examId: ID!): ExamRichContent
|
||
proctoringStatus(examId: ID!): ProctoringStatus!
|
||
|
||
# ===== P7-exams 扩展 Query =====
|
||
|
||
examBuild(examId: ID!, candidatePage: Int, candidatePageSize: Int, filter: QuestionsLibraryFilter): ExamBuild!
|
||
examAnalytics(examId: ID!): ExamAnalytics!
|
||
questionsLibrary(filter: QuestionsLibraryFilter): QuestionsLibraryPage!
|
||
questionBatchExport(filter: QuestionsLibraryFilter): QuestionBatchExportResult!
|
||
textbooks(filter: TextbooksFilter): TextbooksPage!
|
||
textbookDetail(id: ID!): TextbookDetail
|
||
|
||
# ===== P7-grades 扩展 Query =====
|
||
|
||
gradeEntry(examId: ID!, classId: ID!): [GradeEntryItem!]!
|
||
gradeStats(classId: ID!, subject: String): GradeStats!
|
||
gradeAnalytics(classId: ID!, semester: String, examType: String): GradeAnalytics!
|
||
reportCard(studentId: ID!, academicYear: String, semester: String): ReportCard!
|
||
homeworkSubmissions(classId: ID, status: String): [HomeworkSubmissionSummary!]!
|
||
homeworkAssignmentSubmissions(homeworkId: ID!): HomeworkAssignmentSubmissions!
|
||
aiBatchGrading(homeworkId: ID!): [AiBatchGradingItem!]!
|
||
|
||
# ===== P7-insights 扩展 Query =====
|
||
|
||
lessonPlans(subject: String): [LessonPlan!]!
|
||
lessonPlanDetail(planId: ID!): LessonPlanDetail
|
||
lessonPlanLibrary(subject: String, grade: String): [LessonPlanLibraryItem!]!
|
||
lessonPlanCalendar(year: Int!, month: Int!): LessonPlanCalendar!
|
||
lessonPlanHeatmap: LessonPlanHeatmap!
|
||
coursePlans(status: CoursePlanStatus): [CoursePlan!]!
|
||
coursePlanDetail(id: ID!): CoursePlanDetail
|
||
diagnosticReports(type: DiagnosticReportType, status: DiagnosticReportStatus): [DiagnosticReport!]!
|
||
classDiagnostic(classId: ID!): ClassDiagnostic!
|
||
studentDiagnostic(studentId: ID!): StudentDiagnostic!
|
||
errorBook(subject: String!, classId: String): ErrorBook!
|
||
practiceAnalytics(classId: String): PracticeAnalytics!
|
||
|
||
# ===== Admin 域(28 Query,ARB-001 扁平命名)=====
|
||
|
||
currentUser: User!
|
||
adminUsers(filter: AdminUserFilterInput): AdminUserPage!
|
||
adminUser(id: ID!): AdminUser
|
||
adminRoles: [AdminRole!]!
|
||
adminPermissions: [AdminPermission!]!
|
||
adminViewports(scope: String): [AdminViewport!]!
|
||
adminOrganization(parentId: ID): [AdminOrganization!]!
|
||
adminClasses(filter: AdminClassFilterInput): AdminClassPage!
|
||
adminTeachers(filter: AdminTeacherFilterInput): AdminTeacherPage!
|
||
adminStudents(filter: AdminStudentFilterInput): AdminStudentPage!
|
||
auditLogs(filter: AuditLogFilterInput): AuditLogPage!
|
||
auditOverviewStats: AuditOverviewStats!
|
||
auditTrend(days: Int): [AuditTrendPoint!]!
|
||
dataChangeLogs(filter: DataChangeLogFilterInput): DataChangeLogPage!
|
||
loginLogs(filter: LoginLogFilterInput): LoginLogPage!
|
||
adminDashboard: AdminDashboard!
|
||
systemSettings: SystemSettings!
|
||
adminSchools: [AdminSchool!]!
|
||
adminGrades(schoolId: ID): [AdminGrade!]!
|
||
adminGradeInsights(gradeId: ID!): AdminGradeInsights!
|
||
adminDepartments(schoolId: ID): [AdminDepartment!]!
|
||
adminAcademicYears: [AdminAcademicYear!]!
|
||
adminAnnouncements(filter: AnnouncementFilterInput): AdminAnnouncementPage!
|
||
adminInvitationCodes(filter: InvitationCodeFilterInput): AdminInvitationCodePage!
|
||
adminFiles(filter: FileFilterInput): AdminFilePage!
|
||
adminFileStats: AdminFileStats!
|
||
aiProviders: [AiProvider!]!
|
||
aiUsage: AiUsage!
|
||
}
|
||
|
||
# ============ Mutation(20 个:teacher 域 5 + admin 域 15)============
|
||
|
||
type Mutation {
|
||
# ===== Teacher 域(5 Mutation)=====
|
||
|
||
createExam(input: CreateExamInput!): Exam!
|
||
assignHomework(input: AssignHomeworkInput!): Homework!
|
||
recordGrade(input: RecordGradeInput!): Grade!
|
||
generateQuestion(input: GenerateQuestionInput!): GeneratedQuestion!
|
||
markNotificationAsRead(id: ID!): Notification!
|
||
|
||
# ===== P3-P5 扩展 Mutation(teacher-portal 期望)=====
|
||
|
||
updateUser(id: ID, input: UpdateUserInput!): User!
|
||
markAsRead(id: ID!): Notification!
|
||
generateLessonPlan(input: GenerateLessonPlanInput!): GeneratedLessonPlan!
|
||
generateReport(input: GenerateReportInput!): GeneratedReport!
|
||
|
||
# ===== P7 扩展 Mutation(全部降级返回默认 success)=====
|
||
|
||
saveAttendanceSheet(input: SaveAttendanceSheetInput!): SaveAttendanceSheetResult!
|
||
approveLeaveRequest(input: ApproveLeaveRequestInput!): ApproveLeaveRequestResult!
|
||
submitLeaveRequest(input: SubmitLeaveRequestInput!): SubmitLeaveRequestResult!
|
||
submitScheduleChange(input: SubmitScheduleChangeInput!): SubmitScheduleChangeResult!
|
||
createElectiveCourse(input: CreateElectiveCourseInput!): ElectiveCourse!
|
||
updateElectiveCourse(input: UpdateElectiveCourseInput!): ElectiveCourse!
|
||
publishElectiveCourse(id: ID!): ElectiveCourse!
|
||
cancelElectiveCourse(id: ID!): ElectiveCourse!
|
||
saveExamRichContent(input: SaveExamRichContentInput!): SaveExamRichContentResult!
|
||
proctoringEvent(input: ProctoringEventInput!): ProctoringEventResult!
|
||
saveScanGrading(input: SaveScanGradingInput!): SaveScanGradingResult!
|
||
|
||
# ===== P7-exams 扩展 Mutation =====
|
||
|
||
saveExamBuild(input: SaveExamBuildInput!): SaveExamBuildResult!
|
||
questionCreate(input: QuestionCreateInput!): Question!
|
||
questionUpdate(input: QuestionUpdateInput!): Question!
|
||
questionDelete(questionId: ID!): QuestionDeleteResult!
|
||
questionBatchImport(input: QuestionBatchImportInput!): QuestionBatchImportResult!
|
||
textbookCreate(input: TextbookCreateInput!): TextbookItem!
|
||
|
||
# ===== P7-grades 扩展 Mutation =====
|
||
|
||
saveGradeEntries(input: SaveGradeEntriesInput!): SaveGradeEntriesResult!
|
||
gradeSubmission(input: GradeSubmissionInput!): GradeSubmissionResult!
|
||
|
||
# ===== P7-insights 扩展 Mutation =====
|
||
|
||
createLessonPlan(input: CreateLessonPlanInput!): LessonPlan!
|
||
updateLessonPlan(input: UpdateLessonPlanInput!): LessonPlan!
|
||
aiGenerateLessonPlan(input: AIGenerateLessonPlanInput!): AIGenerateLessonPlanResult!
|
||
forkLessonPlan(planId: ID!): LessonPlan!
|
||
createCoursePlan(input: CreateCoursePlanInput!): CoursePlan!
|
||
updateCoursePlan(input: UpdateCoursePlanInput!): CoursePlan!
|
||
|
||
# ===== Admin 域(15 Mutation,ARB-001 扁平命名)=====
|
||
|
||
createUser(input: CreateUserInput!): AdminUser!
|
||
toggleUserStatus(id: ID!, status: String!): AdminUser!
|
||
createRole(input: CreateRoleInput!): AdminRole!
|
||
updateRolePermissions(roleId: ID!, permissionCodes: [String!]!): AdminRole!
|
||
updateViewport(id: ID!, input: UpdateViewportInput!): AdminViewport!
|
||
updateSystemSettings(input: SystemSettingsInput!): SystemSettings!
|
||
createAnnouncement(input: CreateAnnouncementInput!): AdminAnnouncement!
|
||
publishAnnouncement(id: ID!): AdminAnnouncement!
|
||
archiveAnnouncement(id: ID!): AdminAnnouncement!
|
||
toggleAnnouncementPin(id: ID!): AdminAnnouncement!
|
||
generateInvitationCodes(input: GenerateInvitationCodesInput!): GenerateInvitationCodesResult!
|
||
deleteInvitationCodes(ids: [ID!]!): Boolean!
|
||
deleteFiles(ids: [ID!]!): Boolean!
|
||
updateAiProvider(id: ID!, input: UpdateAiProviderInput!): AiProvider!
|
||
}
|
||
|
||
# ============ Input 类型 ============
|
||
|
||
input DateRangeInput {
|
||
start: DateTime!
|
||
end: DateTime!
|
||
}
|
||
|
||
input CreateExamInput {
|
||
classId: ID!
|
||
title: String!
|
||
subject: String!
|
||
scheduledAt: DateTime!
|
||
}
|
||
|
||
input AssignHomeworkInput {
|
||
classId: ID!
|
||
title: String!
|
||
dueDate: DateTime!
|
||
}
|
||
|
||
input RecordGradeInput {
|
||
examId: ID!
|
||
studentId: ID!
|
||
score: Float!
|
||
}
|
||
|
||
input GenerateQuestionInput {
|
||
subject: String!
|
||
gradeLevel: String!
|
||
difficulty: String!
|
||
knowledgePointIds: [ID!]!
|
||
}
|
||
|
||
input AdminUserFilterInput {
|
||
keyword: String
|
||
status: String
|
||
roleId: ID
|
||
page: Int = 1
|
||
pageSize: Int = 20
|
||
}
|
||
|
||
input AdminClassFilterInput {
|
||
keyword: String
|
||
schoolId: ID
|
||
gradeId: ID
|
||
page: Int = 1
|
||
pageSize: Int = 20
|
||
}
|
||
|
||
input AdminTeacherFilterInput {
|
||
keyword: String
|
||
schoolId: ID
|
||
subject: String
|
||
page: Int = 1
|
||
pageSize: Int = 20
|
||
}
|
||
|
||
input AdminStudentFilterInput {
|
||
keyword: String
|
||
schoolId: ID
|
||
gradeId: ID
|
||
classId: ID
|
||
page: Int = 1
|
||
pageSize: Int = 20
|
||
}
|
||
|
||
input AuditLogFilterInput {
|
||
actorUserId: ID
|
||
action: String
|
||
resourceType: String
|
||
resourceId: ID
|
||
startDate: DateTime
|
||
endDate: DateTime
|
||
page: Int = 1
|
||
pageSize: Int = 20
|
||
}
|
||
|
||
input DataChangeLogFilterInput {
|
||
actorUserId: ID
|
||
tableName: String
|
||
action: String
|
||
startDate: DateTime
|
||
endDate: DateTime
|
||
page: Int = 1
|
||
pageSize: Int = 20
|
||
}
|
||
|
||
input LoginLogFilterInput {
|
||
userId: ID
|
||
status: String
|
||
startDate: DateTime
|
||
endDate: DateTime
|
||
page: Int = 1
|
||
pageSize: Int = 20
|
||
}
|
||
|
||
input AnnouncementFilterInput {
|
||
status: String
|
||
audience: String
|
||
keyword: String
|
||
page: Int = 1
|
||
pageSize: Int = 20
|
||
}
|
||
|
||
input InvitationCodeFilterInput {
|
||
status: String
|
||
roleId: ID
|
||
batchId: String
|
||
page: Int = 1
|
||
pageSize: Int = 20
|
||
}
|
||
|
||
input FileFilterInput {
|
||
entityType: String
|
||
entityId: ID
|
||
mimeType: String
|
||
page: Int = 1
|
||
pageSize: Int = 20
|
||
}
|
||
|
||
input CreateUserInput {
|
||
email: String!
|
||
name: String!
|
||
password: String!
|
||
roleIds: [ID!]!
|
||
schoolId: ID
|
||
}
|
||
|
||
input UpdateUserInput {
|
||
name: String
|
||
roleIds: [ID!]
|
||
status: String
|
||
schoolId: ID
|
||
}
|
||
|
||
input CreateRoleInput {
|
||
name: String!
|
||
code: String!
|
||
description: String
|
||
permissions: [String!]!
|
||
}
|
||
|
||
input UpdateViewportInput {
|
||
label: String
|
||
icon: String
|
||
sortOrder: String
|
||
isVisible: Boolean
|
||
}
|
||
|
||
input SystemSettingsInput {
|
||
schoolName: String
|
||
schoolCode: String
|
||
academicYear: String
|
||
semester: String
|
||
contactEmail: String
|
||
contactPhone: String
|
||
address: String
|
||
timezone: String
|
||
locale: String
|
||
}
|
||
|
||
input CreateAnnouncementInput {
|
||
title: String!
|
||
content: String!
|
||
audience: String!
|
||
}
|
||
|
||
input GenerateInvitationCodesInput {
|
||
count: Int!
|
||
roleId: ID!
|
||
classId: ID
|
||
email: String
|
||
expiresInDays: Int
|
||
}
|
||
|
||
input UpdateAiProviderInput {
|
||
name: String
|
||
apiKey: String
|
||
baseUrl: String
|
||
isEnabled: Boolean
|
||
}
|
||
|
||
# ============ P3-P5 扩展类型 ============
|
||
|
||
type Student {
|
||
id: ID!
|
||
name: String!
|
||
email: String!
|
||
avatarUrl: String
|
||
}
|
||
|
||
type ExamQuestion {
|
||
id: ID!
|
||
examId: ID!
|
||
title: String!
|
||
type: String!
|
||
score: Float!
|
||
order: Int!
|
||
}
|
||
|
||
type ExamDetail {
|
||
id: ID!
|
||
classId: ID!
|
||
title: String!
|
||
description: String
|
||
examDate: DateTime!
|
||
duration: Int!
|
||
totalScore: Float!
|
||
status: ExamStatus!
|
||
questions: [ExamQuestion!]!
|
||
}
|
||
|
||
type HomeworkSubmission {
|
||
id: ID!
|
||
homeworkId: ID!
|
||
studentId: ID!
|
||
studentName: String!
|
||
status: SubmissionStatus!
|
||
score: Float
|
||
feedback: String
|
||
submittedAt: DateTime
|
||
}
|
||
|
||
type HomeworkDetail {
|
||
id: ID!
|
||
classId: ID!
|
||
title: String!
|
||
description: String
|
||
dueDate: DateTime!
|
||
status: SubmissionStatus!
|
||
submissions: [HomeworkSubmission!]!
|
||
}
|
||
|
||
type GeneratedLessonPlan {
|
||
id: ID!
|
||
content: String!
|
||
summary: String!
|
||
degraded: Boolean
|
||
degradedReason: String
|
||
}
|
||
|
||
type GeneratedReport {
|
||
id: ID!
|
||
content: String!
|
||
summary: String!
|
||
recommendations: [String!]!
|
||
degraded: Boolean
|
||
degradedReason: String
|
||
}
|
||
|
||
# ============ P4 扩展类型 ============
|
||
|
||
type KnowledgeGraphNode {
|
||
id: ID!
|
||
name: String!
|
||
subject: String!
|
||
description: String
|
||
masteryLevel: Int!
|
||
}
|
||
|
||
type KnowledgeGraphEdge {
|
||
from: ID!
|
||
to: ID!
|
||
type: String!
|
||
}
|
||
|
||
type KnowledgeGraph {
|
||
nodes: [KnowledgeGraphNode!]!
|
||
edges: [KnowledgeGraphEdge!]!
|
||
}
|
||
|
||
type ClassAnalytics {
|
||
classId: ID!
|
||
className: String!
|
||
avgScore: Float!
|
||
passRate: Float!
|
||
avgTrend: [Float!]!
|
||
topStudents: [StudentAnalytics!]!
|
||
weakPoints: [String!]!
|
||
}
|
||
|
||
type StudentAnalytics {
|
||
studentId: ID!
|
||
studentName: String!
|
||
avgScore: Float!
|
||
trend: [Float!]!
|
||
weakPoints: [String!]!
|
||
strongPoints: [String!]!
|
||
masteryRate: Float!
|
||
}
|
||
|
||
# ============ P7-admin 扩展类型 ============
|
||
|
||
type AttendanceRecord {
|
||
id: ID!
|
||
classId: ID!
|
||
className: String!
|
||
studentId: ID!
|
||
studentName: String!
|
||
studentNo: String!
|
||
date: String!
|
||
status: String!
|
||
note: String
|
||
}
|
||
|
||
type AttendanceListPage {
|
||
items: [AttendanceRecord!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
totalPages: Int!
|
||
}
|
||
|
||
type AttendanceSheetItem {
|
||
studentId: ID!
|
||
studentName: String!
|
||
studentNo: String!
|
||
date: String!
|
||
status: String
|
||
note: String
|
||
}
|
||
|
||
type AttendanceTrendPoint {
|
||
date: String!
|
||
presentRate: Float!
|
||
lateRate: Float!
|
||
absentRate: Float!
|
||
}
|
||
|
||
type AttendanceStats {
|
||
classId: ID!
|
||
className: String!
|
||
startDate: String!
|
||
endDate: String!
|
||
totalRecords: Int!
|
||
presentCount: Int!
|
||
absentCount: Int!
|
||
lateCount: Int!
|
||
earlyLeaveCount: Int!
|
||
leaveCount: Int!
|
||
presentRate: Float!
|
||
lateRate: Float!
|
||
earlyLeaveRate: Float!
|
||
leaveRate: Float!
|
||
warningCount: Int!
|
||
trend: [AttendanceTrendPoint!]!
|
||
}
|
||
|
||
type AttendanceClassComparisonItem {
|
||
classId: ID!
|
||
className: String!
|
||
presentRate: Float!
|
||
lateRate: Float!
|
||
absentRate: Float!
|
||
}
|
||
|
||
type AttendanceWarning {
|
||
studentId: ID!
|
||
studentName: String!
|
||
studentNo: String!
|
||
className: String!
|
||
presentRate: Float!
|
||
absentCount: Int!
|
||
lateCount: Int!
|
||
}
|
||
|
||
enum AttendanceReportType {
|
||
WEEKLY
|
||
MONTHLY
|
||
}
|
||
|
||
type AttendanceReportSummary {
|
||
totalRecords: Int!
|
||
presentRate: Float!
|
||
lateRate: Float!
|
||
earlyLeaveRate: Float!
|
||
leaveRate: Float!
|
||
warningCount: Int!
|
||
}
|
||
|
||
type AttendanceReportDetail {
|
||
studentId: ID!
|
||
studentName: String!
|
||
studentNo: String!
|
||
presentCount: Int!
|
||
absentCount: Int!
|
||
lateCount: Int!
|
||
earlyLeaveCount: Int!
|
||
leaveCount: Int!
|
||
presentRate: Float!
|
||
}
|
||
|
||
type AttendanceReport {
|
||
classId: ID!
|
||
className: String!
|
||
reportType: AttendanceReportType!
|
||
startDate: String!
|
||
endDate: String!
|
||
generatedAt: String!
|
||
summary: AttendanceReportSummary!
|
||
details: [AttendanceReportDetail!]!
|
||
}
|
||
|
||
type ClassDetail {
|
||
id: ID!
|
||
name: String!
|
||
gradeId: String!
|
||
subject: String!
|
||
studentCount: Int!
|
||
homeroomTeacher: String!
|
||
room: String
|
||
schoolName: String!
|
||
}
|
||
|
||
type ClassScheduleItem {
|
||
id: ID!
|
||
classId: ID!
|
||
className: String!
|
||
dayOfWeek: Int!
|
||
period: Int!
|
||
subject: String!
|
||
teacherName: String!
|
||
room: String!
|
||
startTime: String!
|
||
endTime: String!
|
||
}
|
||
|
||
type LeaveRequest {
|
||
id: ID!
|
||
applicantId: ID!
|
||
applicantName: String!
|
||
applicantRole: String!
|
||
type: String!
|
||
startDate: String!
|
||
endDate: String!
|
||
reason: String!
|
||
status: String!
|
||
submittedAt: String!
|
||
reviewedAt: String
|
||
reviewerId: ID
|
||
reviewerName: String
|
||
reviewComment: String
|
||
}
|
||
|
||
type LeaveRequestPage {
|
||
items: [LeaveRequest!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
}
|
||
|
||
type ScheduleChange {
|
||
id: ID!
|
||
requesterId: ID!
|
||
requesterName: String!
|
||
classId: ID!
|
||
className: String!
|
||
originalDate: String!
|
||
originalPeriod: Int!
|
||
originalSubject: String!
|
||
adjustedDate: String!
|
||
adjustedPeriod: Int!
|
||
adjustedSubject: String!
|
||
substituteTeacherId: ID
|
||
substituteTeacherName: String
|
||
type: String!
|
||
reason: String!
|
||
status: String!
|
||
submittedAt: String!
|
||
reviewedAt: String
|
||
reviewComment: String
|
||
}
|
||
|
||
type ScheduleChangePage {
|
||
items: [ScheduleChange!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
}
|
||
|
||
type ElectiveStudent {
|
||
studentId: ID!
|
||
studentName: String!
|
||
studentNo: String!
|
||
enrolledAt: String!
|
||
status: String!
|
||
}
|
||
|
||
type ElectiveCourse {
|
||
id: ID!
|
||
title: String!
|
||
subject: String!
|
||
grade: String!
|
||
capacity: Int!
|
||
enrolledCount: Int!
|
||
teacherId: ID!
|
||
teacherName: String!
|
||
semester: String!
|
||
status: String!
|
||
description: String
|
||
students: [ElectiveStudent!]
|
||
createdAt: String
|
||
updatedAt: String
|
||
}
|
||
|
||
# ============ P7-advanced 扩展类型 ============
|
||
|
||
type ExamRichContent {
|
||
examId: ID!
|
||
title: String!
|
||
totalScore: Float!
|
||
questionCount: Int!
|
||
content: String!
|
||
updatedAt: String!
|
||
}
|
||
|
||
type ProctoringSummary {
|
||
examId: ID!
|
||
expectedCount: Int!
|
||
onlineCount: Int!
|
||
submittedCount: Int!
|
||
flaggedCount: Int!
|
||
isProctoring: Boolean!
|
||
startedAt: String
|
||
}
|
||
|
||
type ProctoringStudent {
|
||
studentId: ID!
|
||
studentName: String!
|
||
studentNo: String!
|
||
status: String!
|
||
lastEventAt: String
|
||
ipAddress: String
|
||
}
|
||
|
||
type ProctoringEventItem {
|
||
eventId: ID!
|
||
examId: ID!
|
||
studentId: ID!
|
||
studentName: String!
|
||
studentNo: String!
|
||
eventType: String!
|
||
note: String
|
||
createdAt: String!
|
||
}
|
||
|
||
type ProctoringStatus {
|
||
summary: ProctoringSummary!
|
||
students: [ProctoringStudent!]!
|
||
recentEvents: [ProctoringEventItem!]!
|
||
}
|
||
|
||
type ProctoringEventResult {
|
||
eventId: ID!
|
||
createdAt: String!
|
||
}
|
||
|
||
type SaveScanGradingResult {
|
||
submissionId: ID!
|
||
totalScore: Float!
|
||
savedAt: String!
|
||
}
|
||
|
||
# ============ P7-exams 扩展类型 ============
|
||
|
||
type ExamBuildNode {
|
||
questionId: ID!
|
||
score: Float!
|
||
sortOrder: Int!
|
||
content: String!
|
||
type: String!
|
||
difficulty: String!
|
||
}
|
||
|
||
type ExamBuild {
|
||
examId: ID!
|
||
title: String!
|
||
totalScore: Float!
|
||
passScore: Float!
|
||
duration: Int!
|
||
selected: [ExamBuildNode!]!
|
||
candidates: QuestionsLibraryPage!
|
||
}
|
||
|
||
type SaveExamBuildResult {
|
||
examId: ID!
|
||
totalScore: Float!
|
||
questionCount: Int!
|
||
savedAt: String!
|
||
}
|
||
|
||
type ExamAnalyticsSummary {
|
||
expectedCount: Int!
|
||
attendedCount: Int!
|
||
avgScore: Float!
|
||
maxScore: Float!
|
||
minScore: Float!
|
||
passRate: Float!
|
||
}
|
||
|
||
type ExamScoreBand {
|
||
label: String!
|
||
min: Float!
|
||
max: Float!
|
||
count: Int!
|
||
}
|
||
|
||
type ExamQuestionAccuracy {
|
||
questionId: ID!
|
||
questionTitle: String!
|
||
order: Int!
|
||
correctRate: Float!
|
||
avgScore: Float!
|
||
maxScore: Float!
|
||
}
|
||
|
||
type ExamKpMastery {
|
||
knowledgePoint: String!
|
||
mastery: Float!
|
||
}
|
||
|
||
type ExamClassComparison {
|
||
classId: ID!
|
||
className: String!
|
||
avg: Float!
|
||
significant: Boolean!
|
||
}
|
||
|
||
type ExamHistoryTrend {
|
||
examTitle: String!
|
||
examDate: String!
|
||
avg: Float!
|
||
}
|
||
|
||
type ExamStudentRank {
|
||
rank: Int!
|
||
studentId: ID!
|
||
studentName: String!
|
||
studentNo: String!
|
||
totalScore: Float!
|
||
level: String!
|
||
}
|
||
|
||
type ExamAnalytics {
|
||
examId: ID!
|
||
examTitle: String!
|
||
summary: ExamAnalyticsSummary!
|
||
distribution: [ExamScoreBand!]!
|
||
questionAccuracy: [ExamQuestionAccuracy!]!
|
||
knowledgeMastery: [ExamKpMastery!]!
|
||
classComparison: [ExamClassComparison!]!
|
||
historyTrend: [ExamHistoryTrend!]!
|
||
rankings: [ExamStudentRank!]!
|
||
}
|
||
|
||
type Question {
|
||
questionId: ID!
|
||
content: String!
|
||
type: String!
|
||
difficulty: String!
|
||
textbookId: ID
|
||
textbookName: String
|
||
chapterId: ID
|
||
chapterName: String
|
||
kpId: ID
|
||
kpName: String
|
||
score: Float!
|
||
answer: String!
|
||
analysis: String!
|
||
createdAt: String!
|
||
updatedAt: String!
|
||
}
|
||
|
||
type QuestionsLibraryPage {
|
||
items: [Question!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
}
|
||
|
||
type QuestionBatchExportResult {
|
||
items: [Question!]!
|
||
exportedAt: String!
|
||
}
|
||
|
||
type QuestionDeleteResult {
|
||
questionId: ID!
|
||
deleted: Boolean!
|
||
}
|
||
|
||
type QuestionBatchImportResult {
|
||
importedCount: Int!
|
||
failedCount: Int!
|
||
errors: [String!]!
|
||
}
|
||
|
||
type TextbookItem {
|
||
id: ID!
|
||
title: String!
|
||
subject: String!
|
||
grade: String!
|
||
version: String!
|
||
coverUrl: String
|
||
chapterCount: Int!
|
||
createdAt: String!
|
||
}
|
||
|
||
type TextbooksPage {
|
||
items: [TextbookItem!]!
|
||
total: Int!
|
||
page: Int!
|
||
pageSize: Int!
|
||
}
|
||
|
||
type TextbookKp {
|
||
id: ID!
|
||
name: String!
|
||
description: String
|
||
}
|
||
|
||
type TextbookChapter {
|
||
id: ID!
|
||
textbookId: ID!
|
||
title: String!
|
||
order: Int!
|
||
content: String!
|
||
parentId: ID
|
||
knowledgePoints: [TextbookKp!]!
|
||
}
|
||
|
||
type TextbookDetail {
|
||
id: ID!
|
||
title: String!
|
||
subject: String!
|
||
grade: String!
|
||
version: String!
|
||
coverUrl: String
|
||
chapters: [TextbookChapter!]!
|
||
}
|
||
|
||
# ============ P7-grades 扩展类型 ============
|
||
|
||
type GradeEntryItem {
|
||
studentId: ID!
|
||
studentName: String!
|
||
studentNo: String!
|
||
score: Float
|
||
feedback: String
|
||
}
|
||
|
||
type GradeRanking {
|
||
rank: Int!
|
||
studentId: ID!
|
||
studentName: String!
|
||
studentNo: String!
|
||
totalScore: Float!
|
||
level: String!
|
||
}
|
||
|
||
type GradeStats {
|
||
classId: ID!
|
||
className: String!
|
||
subject: String!
|
||
avg: Float!
|
||
median: Float!
|
||
max: Float!
|
||
min: Float!
|
||
passRate: Float!
|
||
stdDev: Float!
|
||
totalCount: Int!
|
||
rankings: [GradeRanking!]!
|
||
}
|
||
|
||
type GradeTrendPoint {
|
||
month: String!
|
||
avg: Float!
|
||
max: Float!
|
||
min: Float!
|
||
}
|
||
|
||
type GradeDistributionBand {
|
||
label: String!
|
||
min: Float!
|
||
max: Float!
|
||
count: Int!
|
||
}
|
||
|
||
type SubjectComparisonItem {
|
||
subject: String!
|
||
avg: Float!
|
||
}
|
||
|
||
type ClassComparisonItem {
|
||
classId: ID!
|
||
className: String!
|
||
avg: Float!
|
||
significant: Boolean!
|
||
}
|
||
|
||
type KnowledgeMasteryItem {
|
||
knowledgePoint: String!
|
||
mastery: Float!
|
||
}
|
||
|
||
type GradeAnalytics {
|
||
classId: ID!
|
||
className: String!
|
||
trend: [GradeTrendPoint!]!
|
||
distribution: [GradeDistributionBand!]!
|
||
subjectComparison: [SubjectComparisonItem!]!
|
||
classComparison: [ClassComparisonItem!]!
|
||
knowledgeMastery: [KnowledgeMasteryItem!]!
|
||
}
|
||
|
||
type ReportCardSubject {
|
||
subject: String!
|
||
score: Float!
|
||
rank: Int!
|
||
teacherName: String!
|
||
}
|
||
|
||
type ReportCard {
|
||
studentId: ID!
|
||
studentName: String!
|
||
studentNo: String!
|
||
className: String!
|
||
academicYear: String!
|
||
semester: String!
|
||
subjects: [ReportCardSubject!]!
|
||
totalScore: Float!
|
||
classRank: Int!
|
||
classSize: Int!
|
||
gradeRank: Int!
|
||
gradeSize: Int!
|
||
teacherComment: String!
|
||
}
|
||
|
||
type HomeworkSubmissionSummary {
|
||
homeworkId: ID!
|
||
title: String!
|
||
classId: ID!
|
||
className: String!
|
||
status: String!
|
||
dueDate: String!
|
||
totalCount: Int!
|
||
submittedCount: Int!
|
||
gradedCount: Int!
|
||
avgScore: Float
|
||
}
|
||
|
||
type SubmissionAnswer {
|
||
questionId: ID!
|
||
questionTitle: String!
|
||
questionType: String!
|
||
maxScore: Float!
|
||
studentAnswer: String!
|
||
correctAnswer: String!
|
||
score: Float
|
||
feedback: String
|
||
aiSuggestion: String
|
||
}
|
||
|
||
type HomeworkSubmissionDetail {
|
||
submissionId: ID!
|
||
homeworkId: ID!
|
||
homeworkTitle: String!
|
||
classId: ID!
|
||
className: String!
|
||
studentId: ID!
|
||
studentName: String!
|
||
studentNo: String!
|
||
status: String!
|
||
submittedAt: String!
|
||
totalScore: Float
|
||
answers: [SubmissionAnswer!]!
|
||
prevSubmissionId: ID
|
||
nextSubmissionId: ID
|
||
}
|
||
|
||
type HomeworkAssignmentSubmissions {
|
||
submissionId: ID!
|
||
homeworkId: ID!
|
||
homeworkTitle: String!
|
||
classId: ID!
|
||
className: String!
|
||
studentId: ID!
|
||
studentName: String!
|
||
studentNo: String!
|
||
status: String!
|
||
submittedAt: String!
|
||
totalScore: Float
|
||
answers: [SubmissionAnswer!]!
|
||
prevSubmissionId: ID
|
||
nextSubmissionId: ID
|
||
}
|
||
|
||
type AiBatchGradingItem {
|
||
submissionId: ID!
|
||
suggestedScore: Float!
|
||
suggestion: String!
|
||
}
|
||
|
||
type SaveGradeEntriesResult {
|
||
examId: ID!
|
||
classId: ID!
|
||
savedCount: Int!
|
||
}
|
||
|
||
type GradeSubmissionResult {
|
||
submissionId: ID!
|
||
status: String!
|
||
totalScore: Float!
|
||
feedback: String
|
||
}
|
||
|
||
# ============ P7-insights 扩展类型 ============
|
||
|
||
type LessonPlanAIHistoryItem {
|
||
id: ID!
|
||
prompt: String!
|
||
generatedAt: String!
|
||
model: String!
|
||
}
|
||
|
||
type LessonPlan {
|
||
id: ID!
|
||
title: String!
|
||
subject: String!
|
||
grade: String!
|
||
chapter: String!
|
||
status: String!
|
||
textbookId: ID
|
||
textbookTitle: String
|
||
classIds: [String!]!
|
||
updatedAt: String!
|
||
}
|
||
|
||
type LessonPlanDetail {
|
||
id: ID!
|
||
title: String!
|
||
subject: String!
|
||
grade: String!
|
||
chapter: String!
|
||
content: String!
|
||
status: String!
|
||
textbookId: ID
|
||
textbookTitle: String
|
||
classIds: [String!]!
|
||
aiHistory: [LessonPlanAIHistoryItem!]!
|
||
updatedAt: String!
|
||
createdAt: String!
|
||
}
|
||
|
||
type LessonPlanLibraryItem {
|
||
id: ID!
|
||
title: String!
|
||
author: String!
|
||
subject: String!
|
||
grade: String!
|
||
chapter: String!
|
||
rating: Float!
|
||
forkCount: Int!
|
||
updatedAt: String!
|
||
}
|
||
|
||
type LessonPlanCalendarDay {
|
||
date: String!
|
||
planCount: Int!
|
||
planTitles: [String!]!
|
||
}
|
||
|
||
type LessonPlanCalendar {
|
||
year: Int!
|
||
month: Int!
|
||
days: [LessonPlanCalendarDay!]!
|
||
}
|
||
|
||
type LessonPlanHeatmapCell {
|
||
textbookKp: String!
|
||
planIds: [String!]!
|
||
covered: Boolean!
|
||
}
|
||
|
||
type LessonPlanHeatmap {
|
||
rows: [String!]!
|
||
cols: [String!]!
|
||
cells: [LessonPlanHeatmapCell!]!
|
||
}
|
||
|
||
enum CoursePlanStatus {
|
||
DRAFT
|
||
PUBLISHED
|
||
ARCHIVED
|
||
}
|
||
|
||
type CoursePlanChapter {
|
||
id: ID!
|
||
title: String!
|
||
hours: Int!
|
||
objectives: String!
|
||
keyPoints: String!
|
||
activities: String!
|
||
}
|
||
|
||
type CoursePlan {
|
||
id: ID!
|
||
title: String!
|
||
subject: String!
|
||
grade: String!
|
||
academicYear: String!
|
||
semester: String!
|
||
totalHours: Int!
|
||
status: CoursePlanStatus!
|
||
textbookId: ID
|
||
updatedAt: String!
|
||
}
|
||
|
||
type CoursePlanDetail {
|
||
id: ID!
|
||
title: String!
|
||
subject: String!
|
||
grade: String!
|
||
academicYear: String!
|
||
semester: String!
|
||
totalHours: Int!
|
||
status: CoursePlanStatus!
|
||
textbookId: ID
|
||
textbookTitle: String
|
||
homeworkCount: Int!
|
||
chapters: [CoursePlanChapter!]!
|
||
updatedAt: String!
|
||
}
|
||
|
||
enum DiagnosticReportType {
|
||
INDIVIDUAL
|
||
CLASS
|
||
GRADE
|
||
}
|
||
|
||
enum DiagnosticReportStatus {
|
||
DRAFT
|
||
PUBLISHED
|
||
ARCHIVED
|
||
}
|
||
|
||
type DiagnosticReport {
|
||
id: ID!
|
||
title: String!
|
||
type: DiagnosticReportType!
|
||
targetType: String!
|
||
status: DiagnosticReportStatus!
|
||
createdAt: String!
|
||
}
|
||
|
||
type DiagnosticKpDistribution {
|
||
mastered: Int!
|
||
partial: Int!
|
||
weak: Int!
|
||
}
|
||
|
||
type DiagnosticKpMastery {
|
||
knowledgePoint: String!
|
||
avg: Float!
|
||
median: Float!
|
||
studentCount: Int!
|
||
distribution: DiagnosticKpDistribution!
|
||
}
|
||
|
||
type DiagnosticStudentRank {
|
||
rank: Int!
|
||
studentId: ID!
|
||
studentName: String!
|
||
masteryAvg: Float!
|
||
}
|
||
|
||
type ClassDiagnostic {
|
||
classId: ID!
|
||
className: String!
|
||
studentCount: Int!
|
||
summary: [DiagnosticSummaryItem!]!
|
||
kpMastery: [DiagnosticKpMastery!]!
|
||
rankings: [DiagnosticStudentRank!]!
|
||
}
|
||
|
||
type DiagnosticSummaryItem {
|
||
knowledgePoint: String!
|
||
avg: Float!
|
||
}
|
||
|
||
type DiagnosticRadarPoint {
|
||
axis: String!
|
||
value: Float!
|
||
classAvg: Float!
|
||
}
|
||
|
||
type StudentDiagnosticReport {
|
||
id: ID!
|
||
title: String!
|
||
createdAt: String!
|
||
status: DiagnosticReportStatus!
|
||
}
|
||
|
||
type StudentDiagnostic {
|
||
studentId: ID!
|
||
studentName: String!
|
||
radar: [DiagnosticRadarPoint!]!
|
||
reports: [StudentDiagnosticReport!]!
|
||
}
|
||
|
||
type ErrorBookSummary {
|
||
totalErrors: Int!
|
||
highFreqErrors: Int!
|
||
weakKpCount: Int!
|
||
avgErrorRate: Float!
|
||
trendUp: Boolean!
|
||
}
|
||
|
||
type ErrorBookClassComparison {
|
||
classId: ID!
|
||
className: String!
|
||
errorCount: Int!
|
||
}
|
||
|
||
type ErrorBookChapterWeakness {
|
||
chapter: String!
|
||
errorCount: Int!
|
||
}
|
||
|
||
type ErrorBookKpWeakness {
|
||
knowledgePoint: String!
|
||
errorRate: Float!
|
||
}
|
||
|
||
type ErrorBookTopError {
|
||
questionId: ID!
|
||
content: String!
|
||
errorRate: Float!
|
||
}
|
||
|
||
type ErrorBookStudentGroup {
|
||
studentId: ID!
|
||
studentName: String!
|
||
errorCount: Int!
|
||
topErrors: [ErrorBookTopError!]!
|
||
}
|
||
|
||
type ErrorBookTopQuestion {
|
||
questionId: ID!
|
||
content: String!
|
||
errorRate: Float!
|
||
subject: String!
|
||
}
|
||
|
||
type ErrorBook {
|
||
subject: String!
|
||
classId: String!
|
||
summary: ErrorBookSummary!
|
||
classComparison: [ErrorBookClassComparison!]!
|
||
chapterWeakness: [ErrorBookChapterWeakness!]!
|
||
kpWeakness: [ErrorBookKpWeakness!]!
|
||
studentGroups: [ErrorBookStudentGroup!]!
|
||
topQuestions: [ErrorBookTopQuestion!]!
|
||
}
|
||
|
||
type PracticeSummary {
|
||
totalSessions: Int!
|
||
completionRate: Float!
|
||
avgAccuracy: Float!
|
||
weakKpCount: Int!
|
||
participationRate: Float!
|
||
}
|
||
|
||
type PracticeClassComparison {
|
||
classId: ID!
|
||
className: String!
|
||
totalSessions: Int!
|
||
completionRate: Float!
|
||
avgAccuracy: Float!
|
||
participationRate: Float!
|
||
weakKpCount: Int!
|
||
}
|
||
|
||
type PracticeTypeBreakdown {
|
||
type: String!
|
||
count: Int!
|
||
ratio: Float!
|
||
}
|
||
|
||
type PracticeKpWeakness {
|
||
knowledgePoint: String!
|
||
accuracy: Float!
|
||
}
|
||
|
||
type PracticeStudentRank {
|
||
rank: Int!
|
||
studentId: ID!
|
||
studentName: String!
|
||
studentNo: String!
|
||
totalSessions: Int!
|
||
accuracy: Float!
|
||
weakKp: String!
|
||
}
|
||
|
||
type PracticeInactiveStudent {
|
||
studentId: ID!
|
||
studentName: String!
|
||
lastActiveDays: Int!
|
||
}
|
||
|
||
type PracticeAnalytics {
|
||
classId: String!
|
||
summary: PracticeSummary!
|
||
classComparison: [PracticeClassComparison!]!
|
||
typeBreakdown: [PracticeTypeBreakdown!]!
|
||
kpWeakness: [PracticeKpWeakness!]!
|
||
rankings: [PracticeStudentRank!]!
|
||
inactiveStudents: [PracticeInactiveStudent!]!
|
||
}
|
||
|
||
type SaveAttendanceSheetResult {
|
||
classId: ID!
|
||
date: String!
|
||
savedCount: Int!
|
||
savedAt: String!
|
||
}
|
||
|
||
type SaveExamRichContentResult {
|
||
examId: ID!
|
||
updatedAt: String!
|
||
}
|
||
|
||
type ApproveLeaveRequestResult {
|
||
requestId: ID!
|
||
status: String!
|
||
reviewedAt: String!
|
||
reviewerId: ID!
|
||
reviewerName: String!
|
||
reviewComment: String
|
||
}
|
||
|
||
type SubmitLeaveRequestResult {
|
||
requestId: ID!
|
||
status: String!
|
||
submittedAt: String!
|
||
}
|
||
|
||
type SubmitScheduleChangeResult {
|
||
requestId: ID!
|
||
status: String!
|
||
submittedAt: String!
|
||
}
|
||
|
||
type AIGenerateLessonPlanResult {
|
||
id: ID!
|
||
content: String!
|
||
summary: String!
|
||
model: String!
|
||
generatedAt: String!
|
||
}
|
||
|
||
# ============ P7 扩展 Input 类型 ============
|
||
|
||
input GenerateLessonPlanInput {
|
||
classId: String!
|
||
subject: String!
|
||
topic: String!
|
||
objectives: String!
|
||
}
|
||
|
||
input GenerateReportInput {
|
||
classId: String!
|
||
reportType: String!
|
||
studentId: String
|
||
}
|
||
|
||
input AttendanceListFilterInput {
|
||
classId: ID
|
||
startDate: String
|
||
endDate: String
|
||
statuses: [String!]
|
||
page: Int
|
||
pageSize: Int
|
||
}
|
||
|
||
input SaveAttendanceRecordInput {
|
||
studentId: ID!
|
||
status: String!
|
||
note: String
|
||
}
|
||
|
||
input SaveAttendanceSheetInput {
|
||
classId: ID!
|
||
date: String!
|
||
records: [SaveAttendanceRecordInput!]!
|
||
}
|
||
|
||
input LeaveRequestsFilterInput {
|
||
dataScope: String
|
||
status: String
|
||
page: Int
|
||
pageSize: Int
|
||
}
|
||
|
||
input ApproveLeaveRequestInput {
|
||
requestId: ID!
|
||
action: String!
|
||
comment: String
|
||
}
|
||
|
||
input SubmitLeaveRequestInput {
|
||
type: String!
|
||
startDate: String!
|
||
endDate: String!
|
||
reason: String!
|
||
}
|
||
|
||
input SubmitScheduleChangeInput {
|
||
classId: ID!
|
||
originalDate: String!
|
||
originalPeriod: Int!
|
||
originalSubject: String!
|
||
adjustedDate: String!
|
||
adjustedPeriod: Int!
|
||
adjustedSubject: String!
|
||
substituteTeacherId: ID
|
||
type: String!
|
||
reason: String!
|
||
}
|
||
|
||
input CreateElectiveCourseInput {
|
||
title: String!
|
||
subject: String!
|
||
grade: String!
|
||
capacity: Int!
|
||
semester: String!
|
||
description: String
|
||
}
|
||
|
||
input UpdateElectiveCourseInput {
|
||
id: ID!
|
||
title: String
|
||
subject: String
|
||
grade: String
|
||
capacity: Int
|
||
semester: String
|
||
description: String
|
||
}
|
||
|
||
input SaveExamRichContentInput {
|
||
examId: ID!
|
||
content: String!
|
||
}
|
||
|
||
input ProctoringEventInput {
|
||
examId: ID!
|
||
studentId: ID!
|
||
eventType: String!
|
||
note: String
|
||
}
|
||
|
||
input SaveScanGradingItem {
|
||
questionId: ID!
|
||
score: Float!
|
||
feedback: String
|
||
}
|
||
|
||
input SaveScanGradingInput {
|
||
submissionId: ID!
|
||
items: [SaveScanGradingItem!]!
|
||
}
|
||
|
||
input QuestionsLibraryFilter {
|
||
q: String
|
||
type: String
|
||
difficulty: String
|
||
kp: String
|
||
textbook: String
|
||
chapter: String
|
||
page: Int
|
||
pageSize: Int
|
||
}
|
||
|
||
input QuestionCreateInput {
|
||
content: String!
|
||
type: String!
|
||
difficulty: String!
|
||
textbookId: ID
|
||
chapterId: ID
|
||
kpId: ID
|
||
score: Float!
|
||
answer: String!
|
||
analysis: String
|
||
}
|
||
|
||
input QuestionUpdateInput {
|
||
questionId: ID!
|
||
content: String
|
||
type: String
|
||
difficulty: String
|
||
textbookId: ID
|
||
chapterId: ID
|
||
kpId: ID
|
||
score: Float
|
||
answer: String
|
||
analysis: String
|
||
}
|
||
|
||
input QuestionBatchImportItem {
|
||
content: String!
|
||
type: String!
|
||
difficulty: String!
|
||
textbookId: ID
|
||
chapterId: ID
|
||
kpId: ID
|
||
score: Float!
|
||
answer: String!
|
||
analysis: String
|
||
}
|
||
|
||
input QuestionBatchImportInput {
|
||
items: [QuestionBatchImportItem!]!
|
||
}
|
||
|
||
input TextbooksFilter {
|
||
q: String
|
||
subject: String
|
||
grade: String
|
||
page: Int
|
||
pageSize: Int
|
||
}
|
||
|
||
input TextbookCreateInput {
|
||
title: String!
|
||
subject: String!
|
||
grade: String!
|
||
version: String!
|
||
coverUrl: String
|
||
}
|
||
|
||
input SaveExamBuildNodeInput {
|
||
questionId: ID!
|
||
score: Float!
|
||
sortOrder: Int!
|
||
}
|
||
|
||
input SaveExamBuildInput {
|
||
examId: ID!
|
||
questions: [SaveExamBuildNodeInput!]!
|
||
}
|
||
|
||
input SaveGradeEntryInput {
|
||
studentId: ID!
|
||
score: Float!
|
||
feedback: String
|
||
}
|
||
|
||
input SaveGradeEntriesInput {
|
||
examId: ID!
|
||
classId: ID!
|
||
entries: [SaveGradeEntryInput!]!
|
||
}
|
||
|
||
input GradeSubmissionQuestionScore {
|
||
questionId: ID!
|
||
score: Float!
|
||
feedback: String
|
||
}
|
||
|
||
input GradeSubmissionInput {
|
||
submissionId: ID!
|
||
score: Float!
|
||
feedback: String
|
||
aiAssisted: Boolean
|
||
questionScores: [GradeSubmissionQuestionScore!]
|
||
}
|
||
|
||
input CreateLessonPlanInput {
|
||
title: String!
|
||
subject: String!
|
||
grade: String!
|
||
chapter: String!
|
||
textbookId: ID
|
||
template: String!
|
||
}
|
||
|
||
input UpdateLessonPlanInput {
|
||
planId: ID!
|
||
title: String
|
||
content: String
|
||
status: String
|
||
textbookId: ID
|
||
chapter: String
|
||
classIds: [String!]
|
||
}
|
||
|
||
input AIGenerateLessonPlanInput {
|
||
subject: String!
|
||
grade: String!
|
||
chapter: String!
|
||
prompt: String!
|
||
}
|
||
|
||
input CreateCoursePlanInput {
|
||
title: String!
|
||
subject: String!
|
||
grade: String!
|
||
academicYear: String!
|
||
semester: String!
|
||
totalHours: Int!
|
||
textbookId: ID
|
||
}
|
||
|
||
input UpdateCoursePlanInput {
|
||
id: ID!
|
||
title: String
|
||
status: CoursePlanStatus
|
||
chapters: [CoursePlanChapterInput!]
|
||
}
|
||
|
||
input CoursePlanChapterInput {
|
||
id: ID
|
||
title: String!
|
||
hours: Int!
|
||
objectives: String!
|
||
keyPoints: String!
|
||
activities: String!
|
||
}
|