Files
Edu/packages/shared-ts/contracts/graphql/teacher-bff.schema.graphql

2366 lines
44 KiB
GraphQL
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.
# teacher-bff GraphQL Schema (SDL-first, president §2.17)
# 版本v2ARB-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 字段经 DataLoaderP4 全量接入)
# 4. 复杂度限制depth ≤ 7query cost ≤ 1000
# 5. admin 扁平命名ARB-001 裁决admin 字段直接挂载根 Query/Mutation
#
# 错误响应格式GraphQL errors 数组 + extensions.code = BFF_TEACHER_* + extensions.traceId
# 降级模式 Bpresident §2.6success=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!
}
# ============ Query41 个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 扩展 Queryteacher-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 QueryARB-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!
}
# ============ Mutation20 个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 扩展 Mutationteacher-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 MutationARB-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!
}