diff --git a/src/Jiaowu.Api/Controllers/BaseDataController.cs b/src/Jiaowu.Api/Controllers/BaseDataController.cs index ee90cc4..60ac840 100644 --- a/src/Jiaowu.Api/Controllers/BaseDataController.cs +++ b/src/Jiaowu.Api/Controllers/BaseDataController.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using Jiaowu.Api.Contracts; using Jiaowu.Api.Domain.Academic; using Jiaowu.Api.Domain.Common; using Jiaowu.Api.Domain.Identity; @@ -232,8 +233,40 @@ public sealed class BaseDataController(AppDbContext db, IAppCache cache) : Contr } [HttpGet("classes")] - public async Task> GetClasses(CancellationToken cancellationToken) + public async Task> GetClasses( + int? page, + int? pageSize, + string? keyword, + CancellationToken cancellationToken) { + if (page.HasValue || pageSize.HasValue) + { + if (page is < 1 || pageSize is < 1 or > 100) + return ValidationProblem("页码必须大于 0,且每页条数应在 1 至 100 之间。"); + + var source = db.AdministrativeClasses.AsNoTracking(); + if (!string.IsNullOrWhiteSpace(keyword)) + { + keyword = keyword.Trim(); + source = source.Where(x => + x.Code.Contains(keyword) || x.Name.Contains(keyword) || + x.Major!.Name.Contains(keyword) || + x.Major.College!.Name.Contains(keyword)); + } + var total = await source.CountAsync(cancellationToken); + var items = await source + .OrderByDescending(x => x.Grade).ThenBy(x => x.Code) + .Skip((page!.Value - 1) * pageSize!.Value) + .Take(pageSize.Value) + .Select(x => new AdministrativeClassListItem( + x.Id, x.Code, x.Name, x.MajorId, x.Major!.Name, + x.Major.College!.Name, x.Grade, x.CounselorUserId, + x.CounselorName, x.IsEnabled, x.SortOrder)) + .ToListAsync(cancellationToken); + return Ok(new PagedResult( + items, total, page.Value, pageSize.Value)); + } + var result = await cache.GetOrCreateAsync( AppCacheKeys.BaseData("classes"), token => db.AdministrativeClasses.AsNoTracking() @@ -474,8 +507,41 @@ public sealed class BaseDataController(AppDbContext db, IAppCache cache) : Contr } [HttpGet("classrooms")] - public async Task> GetClassrooms(CancellationToken cancellationToken) + public async Task> GetClassrooms( + int? page, + int? pageSize, + string? keyword, + CancellationToken cancellationToken) { + if (page.HasValue || pageSize.HasValue) + { + if (page is < 1 || pageSize is < 1 or > 100) + return ValidationProblem("页码必须大于 0,且每页条数应在 1 至 100 之间。"); + + var source = db.Classrooms.AsNoTracking(); + if (!string.IsNullOrWhiteSpace(keyword)) + { + keyword = keyword.Trim(); + source = source.Where(x => + x.Code.Contains(keyword) || x.Name.Contains(keyword) || + x.Building!.Name.Contains(keyword) || + x.Building.Campus!.Name.Contains(keyword)); + } + var total = await source.CountAsync(cancellationToken); + var items = await source + .OrderBy(x => x.Building!.Campus!.SortOrder).ThenBy(x => x.Code) + .Skip((page!.Value - 1) * pageSize!.Value) + .Take(pageSize.Value) + .Select(x => new ClassroomListItem( + x.Id, x.Code, x.Name, x.BuildingId, x.Building!.CampusId, + x.Building.Name, x.Building.Campus!.Name, x.Capacity, + x.RoomType, x.TeachingVenueNature, x.Equipment, + x.IsEnabled, x.SortOrder)) + .ToListAsync(cancellationToken); + return Ok(new PagedResult( + items, total, page.Value, pageSize.Value)); + } + var result = await cache.GetOrCreateAsync( AppCacheKeys.BaseData("classrooms"), token => db.Classrooms.AsNoTracking() diff --git a/web/src/views/BaseDataView.vue b/web/src/views/BaseDataView.vue index 2106aa8..904a1c5 100644 --- a/web/src/views/BaseDataView.vue +++ b/web/src/views/BaseDataView.vue @@ -92,10 +92,16 @@ const filteredRows = computed(() => { }) const currentPage = ref(1) const pageSize = ref(20) -const pagedRows = computed(() => filteredRows.value.slice( - (currentPage.value - 1) * pageSize.value, - currentPage.value * pageSize.value, -)) +const total = ref(0) +const serverPaged = computed(() => + active.value === 'classes' || active.value === 'classrooms') +let keywordTimer: ReturnType | undefined +const pagedRows = computed(() => serverPaged.value + ? filteredRows.value + : filteredRows.value.slice( + (currentPage.value - 1) * pageSize.value, + currentPage.value * pageSize.value, + )) const venueNatureOptions = [ { value: 1, label: '普通教室' }, { value: 2, label: '实验室' }, @@ -138,11 +144,30 @@ function resetForm(row?: Row) { } } -async function load() { +async function load(resetPage = true) { loading.value = true - currentPage.value = 1 + if (resetPage) currentPage.value = 1 try { - rows.value = (await http.get(`/base-data/${active.value}`)).data + const response = await http.get(`/base-data/${active.value}`, { + params: serverPaged.value + ? { + page: currentPage.value, + pageSize: pageSize.value, + keyword: keyword.value.trim() || undefined, + } + : undefined, + }) + if (serverPaged.value) { + rows.value = response.data.items + total.value = response.data.total + if (rows.value.length === 0 && currentPage.value > 1) { + currentPage.value-- + await load(false) + } + } else { + rows.value = response.data + total.value = rows.value.length + } } catch (error) { ElMessage.error(apiErrorMessage(error)) } finally { @@ -308,7 +333,13 @@ onMounted(async () => { watch( () => keyword.value, - () => { currentPage.value = 1 }, + () => { + currentPage.value = 1 + if (keywordTimer) clearTimeout(keywordTimer) + if (serverPaged.value) { + keywordTimer = setTimeout(() => { void load(false) }, 250) + } + }, ) watch( @@ -357,7 +388,7 @@ watch(
- 刷新 + 刷新 - 共 {{ filteredRows.length }} 条 + 共 {{ serverPaged ? total : filteredRows.length }} 条