From 6619179acc600e1e9471f189519f255fa1dd308e Mon Sep 17 00:00:00 2001 From: biss Date: Fri, 24 Jul 2026 20:44:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B7=B2=E4=BF=AE=E5=A4=8D=EF=BC=9A=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=B8=8D=E5=8F=97=20100=20=E6=9D=A1=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E9=99=90=E5=88=B6=E7=9A=84=E8=AF=BE=E7=A8=8B=E9=80=89?= =?UTF-8?q?=E9=A1=B9=E6=8E=A5=E5=8F=A3=E3=80=82=20=E5=9F=B9=E5=85=BB?= =?UTF-8?q?=E6=96=B9=E6=A1=88=E3=80=81=E6=95=99=E5=AD=A6=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=85=A8=E9=83=A8=E6=94=B9=E7=94=A8=E6=96=B0=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E3=80=82=20=E6=95=99=E5=B8=88=E8=AF=BE=E7=A8=8B=E7=94=B3?= =?UTF-8?q?=E6=8A=A5=E4=BD=BF=E7=94=A8=E7=8B=AC=E7=AB=8B=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=8C=E5=8F=AF=E6=9F=A5=E7=9C=8B=E5=85=A8=E9=83=A8=E5=90=AF?= =?UTF-8?q?=E7=94=A8=E8=AF=BE=E7=A8=8B=E3=80=82=20=E5=AD=A6=E9=99=A2?= =?UTF-8?q?=E6=95=99=E5=8A=A1=E4=BB=8D=E5=8F=AA=E8=83=BD=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=85=AC=E5=85=B1=E8=AF=BE=E5=92=8C=E6=9C=AC=E9=99=A2=E4=B8=93?= =?UTF-8?q?=E4=B8=9A=E8=AF=BE=EF=BC=8C=E4=B8=8D=E4=BC=9A=E8=B6=8A=E6=9D=83?= =?UTF-8?q?=E7=9C=8B=E5=88=B0=E5=A4=96=E9=99=A2=E4=B8=93=E4=B8=9A=E8=AF=BE?= =?UTF-8?q?=E3=80=82=20=E5=AE=9E=E9=99=85=E6=8E=A5=E5=8F=A3=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=EF=BC=9A=20=E6=A0=A1=E7=BA=A7=E6=95=99=E5=8A=A1?= =?UTF-8?q?=EF=BC=9A152=20=E9=97=A8=EF=BC=8C=E5=85=B6=E4=B8=AD=E5=85=AC?= =?UTF-8?q?=E5=85=B1=E8=AF=BE=2029=20=E9=97=A8=E3=80=82=20=E5=AD=A6?= =?UTF-8?q?=E9=99=A2=E6=95=99=E5=8A=A1=EF=BC=9A40=20=E9=97=A8=EF=BC=8C?= =?UTF-8?q?=E5=85=B6=E4=B8=AD=E5=85=AC=E5=85=B1=E8=AF=BE=2029=20=E9=97=A8?= =?UTF-8?q?=EF=BC=8C=E5=85=B6=E4=BD=99=E4=B8=BA=E6=9C=AC=E9=99=A2=E4=B8=93?= =?UTF-8?q?=E4=B8=9A=E8=AF=BE=E3=80=82=20=E6=95=99=E5=B8=88=E7=94=B3?= =?UTF-8?q?=E6=8A=A5=EF=BC=9A152=20=E9=97=A8=EF=BC=8C=E5=85=B6=E4=B8=AD?= =?UTF-8?q?=E5=85=AC=E5=85=B1=E8=AF=BE=2029=20=E9=97=A8=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/CoursesController.cs | 40 +++++++++++++++++++ .../TeacherCourseApplicationsController.cs | 21 ++++++++++ web/src/views/CurriculumView.vue | 4 +- web/src/views/TeachingPreferencesView.vue | 6 +-- web/src/views/TeachingTasksView.vue | 4 +- 5 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/Jiaowu.Api/Controllers/CoursesController.cs b/src/Jiaowu.Api/Controllers/CoursesController.cs index c7b58d5..4ee00ab 100644 --- a/src/Jiaowu.Api/Controllers/CoursesController.cs +++ b/src/Jiaowu.Api/Controllers/CoursesController.cs @@ -97,6 +97,46 @@ public sealed class CoursesController( return Ok(new PagedResult(items, total, page, pageSize)); } + [HttpGet("options")] + public async Task> GetOptions( + Guid? collegeId = null, + CourseNature? nature = null, + string? keyword = null, + CancellationToken cancellationToken = default) + { + var source = ScopedCourses().AsNoTracking().Where(x => x.IsEnabled); + if (collegeId.HasValue) + source = source.Where(x => x.CollegeId == collegeId.Value); + if (nature.HasValue) + source = source.Where(x => x.Nature == nature.Value); + if (!string.IsNullOrWhiteSpace(keyword)) + { + keyword = keyword.Trim(); + source = source.Where(x => + x.Code.Contains(keyword) || + x.Name.Contains(keyword) || + (x.EnglishName != null && x.EnglishName.Contains(keyword))); + } + + return Ok(await source + .OrderBy(x => x.SortOrder) + .ThenBy(x => x.Code) + .Select(x => new + { + x.Id, + x.Code, + x.Name, + x.CollegeId, + CollegeName = x.College!.Name, + x.CourseCategoryId, + CategoryName = x.CourseCategory != null ? x.CourseCategory.Name : null, + x.Credits, + x.Nature, + x.AssessmentMethod + }) + .ToListAsync(cancellationToken)); + } + [HttpPost] [Authorize(Roles = WriteRoles)] public async Task Create( diff --git a/src/Jiaowu.Api/Controllers/TeacherCourseApplicationsController.cs b/src/Jiaowu.Api/Controllers/TeacherCourseApplicationsController.cs index 30b141b..4be9a3f 100644 --- a/src/Jiaowu.Api/Controllers/TeacherCourseApplicationsController.cs +++ b/src/Jiaowu.Api/Controllers/TeacherCourseApplicationsController.cs @@ -21,6 +21,27 @@ public sealed class TeacherCourseApplicationsController( SystemRoles.AcademicAdmin + "," + SystemRoles.CollegeAdmin; + [HttpGet("course-options")] + [Authorize(Roles = SystemRoles.Teacher)] + public async Task GetCourseOptions(CancellationToken cancellationToken) + { + return Ok(await db.Courses.AsNoTracking() + .Where(x => x.IsEnabled) + .OrderBy(x => x.SortOrder) + .ThenBy(x => x.Code) + .Select(x => new + { + x.Id, + x.Code, + x.Name, + x.CollegeId, + CollegeName = x.College!.Name, + x.Credits, + x.Nature + }) + .ToListAsync(cancellationToken)); + } + [HttpGet("mine")] [Authorize(Roles = SystemRoles.Teacher)] public async Task GetMine( diff --git a/web/src/views/CurriculumView.vue b/web/src/views/CurriculumView.vue index 027e977..781dbcf 100644 --- a/web/src/views/CurriculumView.vue +++ b/web/src/views/CurriculumView.vue @@ -294,12 +294,12 @@ async function deleteCourse(moduleId: string, item: any) { onMounted(async () => { const [optionRes, courseRes] = await Promise.all([ http.get('/curriculum-plans/filter-options'), - http.get('/courses', { params: { page: 1, pageSize: 100, isEnabled: true } }), + http.get('/courses/options'), ]) colleges.value = optionRes.data.colleges majors.value = optionRes.data.majors grades.value = optionRes.data.grades - courses.value = courseRes.data.items + courses.value = courseRes.data if (isCollegeAdmin.value && auth.user?.collegeId) { query.collegeId = auth.user.collegeId } diff --git a/web/src/views/TeachingPreferencesView.vue b/web/src/views/TeachingPreferencesView.vue index 8d47e63..c19d4a1 100644 --- a/web/src/views/TeachingPreferencesView.vue +++ b/web/src/views/TeachingPreferencesView.vue @@ -111,13 +111,11 @@ async function review() { onMounted(async () => { const requests: Promise[] = [http.get('/base-data/terms')] if (isTeacher.value) { - requests.push(http.get('/courses', { - params: { page: 1, pageSize: 100, isEnabled: true }, - })) + requests.push(http.get('/teacher-course-applications/course-options')) } const [termRes, courseRes] = await Promise.all(requests) terms.value = termRes.data - courses.value = courseRes?.data.items ?? [] + courses.value = courseRes?.data ?? [] filters.academicTermId = terms.value.find((item) => item.isCurrent)?.id await load() }) diff --git a/web/src/views/TeachingTasksView.vue b/web/src/views/TeachingTasksView.vue index 73b447e..2ede0e0 100644 --- a/web/src/views/TeachingTasksView.vue +++ b/web/src/views/TeachingTasksView.vue @@ -300,13 +300,13 @@ async function generatePublicTasks() { onMounted(async () => { const [termRes, courseRes, teacherRes, classRes, majorRes] = await Promise.all([ http.get('/base-data/terms'), - http.get('/courses', { params: { page: 1, pageSize: 100, isEnabled: true } }), + http.get('/courses/options'), http.get('/personnel/teachers', { params: { page: 1, pageSize: 100, teacherStatus: 'Active' } }), http.get('/base-data/classes'), http.get('/base-data/majors'), ]) terms.value = termRes.data - courses.value = courseRes.data.items + courses.value = courseRes.data teachers.value = teacherRes.data.items classes.value = classRes.data majors.value = majorRes.data