已修复:

新增不受 100 条分页限制的课程选项接口。
培养方案、教学任务全部改用新接口。
教师课程申报使用独立接口,可查看全部启用课程。
学院教务仍只能使用公共课和本院专业课,不会越权看到外院专业课。
实际接口验证:
校级教务:152 门,其中公共课 29 门。
学院教务:40 门,其中公共课 29 门,其余为本院专业课。
教师申报:152 门,其中公共课 29 门。
This commit is contained in:
2026-07-24 20:44:06 +08:00 Unverified
parent 20ca205080
commit 6619179acc
5 changed files with 67 additions and 8 deletions
@@ -97,6 +97,46 @@ public sealed class CoursesController(
return Ok(new PagedResult<object>(items, total, page, pageSize));
}
[HttpGet("options")]
public async Task<ActionResult<object>> 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<ActionResult> Create(
@@ -21,6 +21,27 @@ public sealed class TeacherCourseApplicationsController(
SystemRoles.AcademicAdmin + "," +
SystemRoles.CollegeAdmin;
[HttpGet("course-options")]
[Authorize(Roles = SystemRoles.Teacher)]
public async Task<ActionResult> 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<ActionResult> GetMine(
+2 -2
View File
@@ -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
}
+2 -4
View File
@@ -111,13 +111,11 @@ async function review() {
onMounted(async () => {
const requests: Promise<any>[] = [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()
})
+2 -2
View File
@@ -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