实验视图
This commit is contained in:
@@ -94,13 +94,18 @@ public sealed class ExperimentGradesController(
|
|||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
var projects = await source
|
var projects = await source
|
||||||
.Where(x => taskIds.Contains(x.TeachingTaskId))
|
.Where(x => taskIds.Contains(x.TeachingTaskId))
|
||||||
.OrderBy(x => x.Code)
|
.OrderBy(x => x.ScheduleWeek ?? int.MaxValue)
|
||||||
|
.ThenBy(x => x.ScheduleEntry == null ? int.MaxValue : x.ScheduleEntry.DayOfWeek)
|
||||||
|
.ThenBy(x => x.ScheduleEntry == null ? int.MaxValue : x.ScheduleEntry.StartPeriod)
|
||||||
|
.ThenBy(x => x.StartDate)
|
||||||
|
.ThenBy(x => x.Code)
|
||||||
.Select(x => new
|
.Select(x => new
|
||||||
{
|
{
|
||||||
x.Id,
|
x.Id,
|
||||||
x.Code,
|
x.Code,
|
||||||
x.Name,
|
x.Name,
|
||||||
x.ArrangementMode,
|
x.ArrangementMode,
|
||||||
|
x.ScheduleWeek,
|
||||||
ProjectStatus = x.Status,
|
ProjectStatus = x.Status,
|
||||||
x.TeachingTaskId,
|
x.TeachingTaskId,
|
||||||
x.TeachingTask!.TaskNumber,
|
x.TeachingTask!.TaskNumber,
|
||||||
@@ -113,6 +118,14 @@ public sealed class ExperimentGradesController(
|
|||||||
TeacherNames = x.TeachingTask.Teachers
|
TeacherNames = x.TeachingTask.Teachers
|
||||||
.OrderByDescending(item => item.IsPrimary)
|
.OrderByDescending(item => item.IsPrimary)
|
||||||
.Select(item => item.Teacher!.Name),
|
.Select(item => item.Teacher!.Name),
|
||||||
|
ScheduleEntry = x.ScheduleEntry == null
|
||||||
|
? null
|
||||||
|
: new
|
||||||
|
{
|
||||||
|
x.ScheduleEntry.DayOfWeek,
|
||||||
|
x.ScheduleEntry.StartPeriod,
|
||||||
|
x.ScheduleEntry.PeriodCount
|
||||||
|
},
|
||||||
Sheet = x.GradeSheet == null
|
Sheet = x.GradeSheet == null
|
||||||
? null
|
? null
|
||||||
: new
|
: new
|
||||||
@@ -356,6 +369,15 @@ public sealed class ExperimentGradesController(
|
|||||||
ProjectCode = x.ExperimentProject!.Code,
|
ProjectCode = x.ExperimentProject!.Code,
|
||||||
ProjectName = x.ExperimentProject.Name,
|
ProjectName = x.ExperimentProject.Name,
|
||||||
x.ExperimentProject.ArrangementMode,
|
x.ExperimentProject.ArrangementMode,
|
||||||
|
x.ExperimentProject.ScheduleWeek,
|
||||||
|
ScheduleEntry = x.ExperimentProject.ScheduleEntry == null
|
||||||
|
? null
|
||||||
|
: new
|
||||||
|
{
|
||||||
|
x.ExperimentProject.ScheduleEntry.DayOfWeek,
|
||||||
|
x.ExperimentProject.ScheduleEntry.StartPeriod,
|
||||||
|
x.ExperimentProject.ScheduleEntry.PeriodCount
|
||||||
|
},
|
||||||
x.ExperimentProject.TeachingTaskId,
|
x.ExperimentProject.TeachingTaskId,
|
||||||
x.ExperimentProject.TeachingTask!.TaskNumber,
|
x.ExperimentProject.TeachingTask!.TaskNumber,
|
||||||
TaskName = x.ExperimentProject.TeachingTask.Name,
|
TaskName = x.ExperimentProject.TeachingTask.Name,
|
||||||
|
|||||||
@@ -215,6 +215,89 @@ public sealed class ExperimentGradesControllerTests
|
|||||||
Assert.Equal(1, Property<int>(filtered.Value, "Total"));
|
Assert.Equal(1, Property<int>(filtered.Value, "Total"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ManagementList_OrdersProjectsByScheduledWeekAndPeriod()
|
||||||
|
{
|
||||||
|
await using var fixture = await ExperimentGradeFixture.CreateAsync();
|
||||||
|
var plan = new SchedulePlan
|
||||||
|
{
|
||||||
|
AcademicTermId = fixture.Term.Id,
|
||||||
|
Name = "实验课表",
|
||||||
|
Version = "v1",
|
||||||
|
Status = SchedulePlanStatus.Published
|
||||||
|
};
|
||||||
|
var laterEntry = new ScheduleEntry
|
||||||
|
{
|
||||||
|
SchedulePlanId = plan.Id,
|
||||||
|
TeachingTaskId = fixture.Task.Id,
|
||||||
|
ClassroomId = fixture.Classroom.Id,
|
||||||
|
Kind = ScheduleEntryKind.Experiment,
|
||||||
|
DayOfWeek = 4,
|
||||||
|
StartPeriod = 5,
|
||||||
|
PeriodCount = 2,
|
||||||
|
StartWeek = 5,
|
||||||
|
EndWeek = 5,
|
||||||
|
WeekPattern = WeekPattern.All
|
||||||
|
};
|
||||||
|
var earlierEntry = new ScheduleEntry
|
||||||
|
{
|
||||||
|
SchedulePlanId = plan.Id,
|
||||||
|
TeachingTaskId = fixture.Task.Id,
|
||||||
|
ClassroomId = fixture.Classroom.Id,
|
||||||
|
Kind = ScheduleEntryKind.Experiment,
|
||||||
|
DayOfWeek = 2,
|
||||||
|
StartPeriod = 3,
|
||||||
|
PeriodCount = 2,
|
||||||
|
StartWeek = 2,
|
||||||
|
EndWeek = 2,
|
||||||
|
WeekPattern = WeekPattern.All
|
||||||
|
};
|
||||||
|
fixture.Db.AddRange(plan, laterEntry, earlierEntry);
|
||||||
|
fixture.Db.AddRange(
|
||||||
|
new ExperimentProject
|
||||||
|
{
|
||||||
|
TeachingTaskId = fixture.Task.Id,
|
||||||
|
ScheduleEntryId = laterEntry.Id,
|
||||||
|
ScheduleWeek = 5,
|
||||||
|
Code = "LAB-A",
|
||||||
|
Name = "后面的实验",
|
||||||
|
ArrangementMode = ExperimentArrangementMode.Centralized,
|
||||||
|
StartDate = fixture.Term.StartDate,
|
||||||
|
EndDate = fixture.Term.EndDate,
|
||||||
|
Status = ExperimentProjectStatus.Published
|
||||||
|
},
|
||||||
|
new ExperimentProject
|
||||||
|
{
|
||||||
|
TeachingTaskId = fixture.Task.Id,
|
||||||
|
ScheduleEntryId = earlierEntry.Id,
|
||||||
|
ScheduleWeek = 2,
|
||||||
|
Code = "LAB-Z",
|
||||||
|
Name = "前面的实验",
|
||||||
|
ArrangementMode = ExperimentArrangementMode.Centralized,
|
||||||
|
StartDate = fixture.Term.StartDate,
|
||||||
|
EndDate = fixture.Term.EndDate,
|
||||||
|
Status = ExperimentProjectStatus.Published
|
||||||
|
});
|
||||||
|
await fixture.Db.SaveChangesAsync();
|
||||||
|
fixture.Db.ChangeTracker.Clear();
|
||||||
|
|
||||||
|
var result = Assert.IsType<OkObjectResult>(await fixture.ExperimentGrades(
|
||||||
|
fixture.AdminScope).GetManagement(
|
||||||
|
fixture.Term.Id, null, null, null, 1, 10, CancellationToken.None));
|
||||||
|
var course = Assert.Single(Property<System.Collections.IEnumerable>(
|
||||||
|
result.Value, "Items").Cast<object>());
|
||||||
|
var projects = Property<System.Collections.IEnumerable>(course, "Projects")
|
||||||
|
.Cast<object>()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
Assert.Equal(["前面的实验", "后面的实验"],
|
||||||
|
projects.Select(project => Property<string>(project, "Name")));
|
||||||
|
var schedule = Property<object>(projects[0], "ScheduleEntry");
|
||||||
|
Assert.Equal(2, Property<int>(projects[0], "ScheduleWeek"));
|
||||||
|
Assert.Equal(2, Property<int>(schedule, "DayOfWeek"));
|
||||||
|
Assert.Equal(3, Property<int>(schedule, "StartPeriod"));
|
||||||
|
}
|
||||||
|
|
||||||
private static T Property<T>(object? value, string name) =>
|
private static T Property<T>(object? value, string name) =>
|
||||||
Assert.IsAssignableFrom<T>(
|
Assert.IsAssignableFrom<T>(
|
||||||
value!.GetType().GetProperty(name)!.GetValue(value));
|
value!.GetType().GetProperty(name)!.GetValue(value));
|
||||||
|
|||||||
@@ -90,6 +90,18 @@ const modeLabels: Record<string, string> = {
|
|||||||
Centralized: '集中安排',
|
Centralized: '集中安排',
|
||||||
SelfScheduled: '自主预约',
|
SelfScheduled: '自主预约',
|
||||||
}
|
}
|
||||||
|
const weekdayLabels = ['', '周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||||
|
|
||||||
|
function projectScheduleLabel(project: any) {
|
||||||
|
const entry = project.scheduleEntry
|
||||||
|
if (!entry) return modeLabels[project.arrangementMode] ?? '待安排'
|
||||||
|
const week = project.scheduleWeek ?? '—'
|
||||||
|
const endPeriod = entry.startPeriod + entry.periodCount - 1
|
||||||
|
const periods = entry.periodCount === 1
|
||||||
|
? `第 ${entry.startPeriod} 节`
|
||||||
|
: `第 ${entry.startPeriod}—${endPeriod} 节`
|
||||||
|
return `第 ${week} 周 · ${weekdayLabels[entry.dayOfWeek] ?? `周${entry.dayOfWeek}`} · ${periods}`
|
||||||
|
}
|
||||||
|
|
||||||
const schemeWeightTotal = computed(() =>
|
const schemeWeightTotal = computed(() =>
|
||||||
schemeForm.items.reduce((sum, item) => sum + Number(item.weight || 0), 0),
|
schemeForm.items.reduce((sum, item) => sum + Number(item.weight || 0), 0),
|
||||||
@@ -583,7 +595,7 @@ onMounted(async () => {
|
|||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="course-project-name">
|
<div class="course-project-name">
|
||||||
<b>{{ row.code }} · {{ row.name }}</b>
|
<b>{{ row.code }} · {{ row.name }}</b>
|
||||||
<small>{{ modeLabels[row.arrangementMode] }}</small>
|
<small>{{ projectScheduleLabel(row) }}</small>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -680,6 +692,7 @@ onMounted(async () => {
|
|||||||
<span>{{ detail.projectCode }} · {{ modeLabels[detail.arrangementMode] }}</span>
|
<span>{{ detail.projectCode }} · {{ modeLabels[detail.arrangementMode] }}</span>
|
||||||
<h3>{{ detail.projectName }}</h3>
|
<h3>{{ detail.projectName }}</h3>
|
||||||
<p>{{ detail.courseCode }} · {{ detail.courseName }} · {{ detail.termName }}</p>
|
<p>{{ detail.courseCode }} · {{ detail.courseName }} · {{ detail.termName }}</p>
|
||||||
|
<p class="project-schedule">{{ projectScheduleLabel(detail) }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="workbench-status">
|
<div class="workbench-status">
|
||||||
<el-tag :type="statusTypes[detail.status] as any" effect="dark">{{ statusLabels[detail.status] }}</el-tag>
|
<el-tag :type="statusTypes[detail.status] as any" effect="dark">{{ statusLabels[detail.status] }}</el-tag>
|
||||||
|
|||||||
Reference in New Issue
Block a user