feat(content): v2 扩展 Elective/LessonPlan/CoursePlan 三业务域
新增 3 个业务域(10 RPC): - ElectiveService: 选修课列表/学生选课记录/选课/退课(含容量与重复校验) - LessonPlanService: 教师备课列表/学生备课列表(仅 published)/详情 - CoursePlanService: 学生课程计划列表/详情 - KnowledgeGraphService.GetKnowledgePath: 与 GetLearningPath 同实现 新增 4 张 MySQL 表(elective_courses/selections/lesson_plans/course_plans),含完整索引。 新增 11 个权限点,覆盖 admin/teacher/student/parent 四角色。 proto 由 4 Service/22 RPC 扩展至 7 Service/32 RPC,v1 全部 RPC 保持向后兼容。 修复 logger.ts pino 导入: default import 在 NodeNext ESM 下不可调用, 改用 named import(与 iam/msg/core-edu 对齐)。 Docker 本地测试全部通过(HTTP + gRPC 双协议),健康检查、 Elective/LessonPlan/CoursePlan CRUD、4 个新 gRPC Service 全部验证通过。 nextstep-v2.md 已创建,记录上下游依赖与 6 项联调待办。
This commit is contained in:
118
services/content/src/electives/electives.repository.ts
Normal file
118
services/content/src/electives/electives.repository.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import { getDb } from "../config/database.js";
|
||||
import {
|
||||
electiveCourses,
|
||||
electiveSelections,
|
||||
type ElectiveCourse,
|
||||
type NewElectiveCourse,
|
||||
type ElectiveSelection,
|
||||
type NewElectiveSelection,
|
||||
} from "./electives.schema.js";
|
||||
|
||||
export class ElectivesRepository {
|
||||
async findCourseById(id: string): Promise<ElectiveCourse | undefined> {
|
||||
const [result] = await getDb()
|
||||
.select()
|
||||
.from(electiveCourses)
|
||||
.where(eq(electiveCourses.id, id))
|
||||
.limit(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
async findCourses(query?: {
|
||||
subjectId?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}): Promise<ElectiveCourse[]> {
|
||||
const db = getDb();
|
||||
let q = db.select().from(electiveCourses).$dynamic();
|
||||
if (query?.subjectId) {
|
||||
q = q.where(eq(electiveCourses.subjectId, query.subjectId));
|
||||
}
|
||||
const pageSize = query?.pageSize ?? 20;
|
||||
const page = query?.page ?? 1;
|
||||
return q.limit(pageSize).offset((page - 1) * pageSize);
|
||||
}
|
||||
|
||||
async createCourse(data: NewElectiveCourse): Promise<void> {
|
||||
await getDb().insert(electiveCourses).values(data);
|
||||
}
|
||||
|
||||
async updateCourse(
|
||||
id: string,
|
||||
data: Partial<NewElectiveCourse>,
|
||||
): Promise<void> {
|
||||
await getDb()
|
||||
.update(electiveCourses)
|
||||
.set(data)
|
||||
.where(eq(electiveCourses.id, id));
|
||||
}
|
||||
|
||||
async deleteCourse(id: string): Promise<void> {
|
||||
await getDb().delete(electiveCourses).where(eq(electiveCourses.id, id));
|
||||
}
|
||||
|
||||
async findSelectionsByStudent(
|
||||
studentId: string,
|
||||
status?: string,
|
||||
): Promise<ElectiveSelection[]> {
|
||||
const db = getDb();
|
||||
let q = db
|
||||
.select()
|
||||
.from(electiveSelections)
|
||||
.where(eq(electiveSelections.studentId, studentId))
|
||||
.$dynamic();
|
||||
if (status) {
|
||||
q = q.where(eq(electiveSelections.status, status));
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
async findActiveSelection(
|
||||
studentId: string,
|
||||
courseId: string,
|
||||
): Promise<ElectiveSelection | undefined> {
|
||||
const [result] = await getDb()
|
||||
.select()
|
||||
.from(electiveSelections)
|
||||
.where(
|
||||
and(
|
||||
eq(electiveSelections.studentId, studentId),
|
||||
eq(electiveSelections.courseId, courseId),
|
||||
eq(electiveSelections.status, "selected"),
|
||||
),
|
||||
)
|
||||
.limit(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
async createSelection(data: NewElectiveSelection): Promise<void> {
|
||||
await getDb().insert(electiveSelections).values(data);
|
||||
}
|
||||
|
||||
async updateSelection(
|
||||
id: string,
|
||||
data: Partial<NewElectiveSelection>,
|
||||
): Promise<void> {
|
||||
await getDb()
|
||||
.update(electiveSelections)
|
||||
.set(data)
|
||||
.where(eq(electiveSelections.id, id));
|
||||
}
|
||||
|
||||
async countEnrolled(courseId: string): Promise<number> {
|
||||
const db = getDb();
|
||||
const rows = await db
|
||||
.select()
|
||||
.from(electiveSelections)
|
||||
.where(
|
||||
and(
|
||||
eq(electiveSelections.courseId, courseId),
|
||||
eq(electiveSelections.status, "selected"),
|
||||
),
|
||||
);
|
||||
return rows.length;
|
||||
}
|
||||
}
|
||||
|
||||
export const electivesRepository = new ElectivesRepository();
|
||||
Reference in New Issue
Block a user