From 971ea46da57fdc51bda8ae558bca0978901f73ba Mon Sep 17 00:00:00 2001 From: liweijie Date: Thu, 17 Sep 2026 18:20:48 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E6=B7=BB=E5=8A=A0=E5=AE=9E=E6=96=BD?= =?UTF-8?q?=E8=AE=A1=E5=88=92=E7=BB=9F=E8=AE=A1=E5=88=86=E6=9E=90=EF=BC=9B?= =?UTF-8?q?=202=E3=80=81=E6=B7=BB=E5=8A=A0=E5=8D=95=E8=AF=BE=E7=A8=8B?= =?UTF-8?q?=E5=AE=9E=E6=96=BD=E8=AE=A1=E5=88=92=E5=88=97=E8=A1=A8=EF=BC=9B?= =?UTF-8?q?=203=E3=80=81=E6=81=A2=E5=A4=8D=E5=90=8C=E6=AD=A5=E7=8F=AD?= =?UTF-8?q?=E5=8E=86=EF=BC=9B=204=E3=80=81=E5=86=B2=E7=AA=81=E9=A1=B9?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=A2=9C=E8=89=B2=E5=88=86=E7=BA=A7=EF=BC=9B?= =?UTF-8?q?=205=E3=80=81=E6=A0=A1=E5=8E=86=E8=A1=A5=E4=B8=8A=E6=AD=A3?= =?UTF-8?q?=E8=AF=BE=EF=BC=9B=206=E3=80=81=E6=B7=BB=E5=8A=A0=E6=95=99?= =?UTF-8?q?=E5=AD=A6=E5=9C=BA=E5=9C=B0=E6=80=BB=E8=A7=88=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jwgl/mapper/SemesterCalendarMapper.xml | 3 +- .../impl/ClassSemesterServiceImpl.java | 57 ++-- .../impl/CourseRunningImportServiceImpl.java | 77 ++++- .../impl/TimetableConflictServiceImpl.java | 75 ++++- .../courserunning/TeachingPlanLessonVO.java | 15 + .../src/api/teachBusiness/courseRunning.js | 82 +++++ .../teachBusiness/operationAnalysis/index.vue | 304 ++++++++++++++++++ .../teachBusiness/schedulingWindow/index.vue | 12 +- .../teachBusiness/teachingPlan/index.vue | 252 +++++++++++++++ .../teachBusiness/timetableConflict/index.vue | 65 +++- .../src/views/teachBusiness/venue/index.vue | 79 +++++ 11 files changed, 973 insertions(+), 48 deletions(-) create mode 100644 frontend/src/views/teachBusiness/operationAnalysis/index.vue create mode 100644 frontend/src/views/teachBusiness/teachingPlan/index.vue diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SemesterCalendarMapper.xml b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SemesterCalendarMapper.xml index 9c9089d7..a081fa7b 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SemesterCalendarMapper.xml +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/mapper/SemesterCalendarMapper.xml @@ -13,10 +13,11 @@ + - 编号, 年度, 假期时间, 假期名称, 加粗, 备注, 可排课, 备注显示, 自动排课, 节次 + 编号, 年度, 假期时间, 假期名称, 加粗, 备注, 可排课, 备注显示, 自动排课, 节次, 正课 diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/ClassSemesterServiceImpl.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/ClassSemesterServiceImpl.java index aeef0f05..d164d48f 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/ClassSemesterServiceImpl.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/ClassSemesterServiceImpl.java @@ -59,6 +59,12 @@ public class ClassSemesterServiceImpl implements ClassSemesterService { @Resource private SemesterMapper semesterMapper; + @Resource + private com.roomroot.jwgl.mapper.JQBMapper jqbMapper; + + @Resource + private com.roomroot.jwgl.service.ClassEventCalendarService classEventCalendarService; + @Transactional(rollbackFor = Exception.class) @Override public void add(XYDNDXQJBXXB xydndxqjbxxb) { @@ -247,46 +253,23 @@ public class ClassSemesterServiceImpl implements ClassSemesterService { } // 更新日期范围 - xydndxqjbxxb.setKxrq(LocalDate.parse(xqkssj)); - xydndxqjbxxb.setJsrq(LocalDate.parse(xqjssj)); + LocalDate kxrq = LocalDate.parse(xqkssj); + LocalDate jsrq = LocalDate.parse(xqjssj); + xydndxqjbxxb.setKxrq(kxrq); + xydndxqjbxxb.setJsrq(jsrq); classSemesterMapper.updateById(xydndxqjbxxb); count++; -// // 删除日期范围之外的日历记录 -// classSemesterCalendarMapper.deleteOutsideDateRange(bh, xqkssj, xqjssj); -// -// // 查询现有任务记录 -// List existingCalendar = classSemesterCalendarMapper.selectByBcxqbhAndDateRange(bh, xqkssj, xqjssj); -// -// // 查询学期校历,用于补充缺少的记录 -// String kxrqStr = xydndxqjbxxb.getKxrq() != null ? xydndxqjbxxb.getKxrq().toString() : xqkssj; -// String jsrqStr = xydndxqjbxxb.getJsrq() != null ? xydndxqjbxxb.getJsrq().toString() : xqjssj; -// List xqxlbs = semesterCalendarMapper.selectByNdAndJqsjRange(xydndxqjbxxb.getNd(), kxrqStr, jsrqStr); -// -// if (!CollectionUtils.isEmpty(xqxlbs)) { -// // 提取已有编号 -// java.util.Set existingBhs = new java.util.HashSet<>(); -// for (XYDRWB cal : existingCalendar) { -// existingBhs.add(cal.getBh()); -// } -// -// // 补充缺少的记录 -// for (XQXLB xqxlb : xqxlbs) { -// XYDRWB xydrwb = new XYDRWB(); -// String newBh = UuidUtil.getUUID(); -// if (!existingBhs.contains(newBh)) { -// xydrwb.setBh(newBh); -// xydrwb.setNd(xydndxqjbxxb.getNd()); -// xydrwb.setXydbh(xydndxqjbxxb.getXydbh()); -// xydrwb.setXqdc(xydndxqjbxxb.getXqdc()); -// xydrwb.setXydxqbh(bh); -// xydrwb.setDelFlag(0); -// classSemesterCalendarMapper.insert(xydrwb); -// } -// } -// } -// -// count++; + // 同步班历(假期表 JQB):删除新范围之外的格子,再按校历补齐范围内缺失的格子。 + // JQB.假期时间 存的是 yyyyMMdd 整数(与班历写入口径一致)。 + int start = Integer.parseInt(kxrq.format(DateTimeFormatter.ofPattern("yyyyMMdd"))); + int end = Integer.parseInt(jsrq.format(DateTimeFormatter.ofPattern("yyyyMMdd"))); + jqbMapper.delete(new LambdaQueryWrapper() + .eq(com.roomroot.jwgl.entity.JQB::getXydxqbh, bh) + .and(w -> w.lt(com.roomroot.jwgl.entity.JQB::getJqsj, start) + .or().gt(com.roomroot.jwgl.entity.JQB::getJqsj, end))); + // 只补缺失格、不覆盖人工改动(与班历弹窗「同步校历」同一口径) + classEventCalendarService.resync(bh, true); } return count; diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/CourseRunningImportServiceImpl.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/CourseRunningImportServiceImpl.java index aac3829c..6d7c62a5 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/CourseRunningImportServiceImpl.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/CourseRunningImportServiceImpl.java @@ -29,8 +29,12 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; /** * 教学运行数据导入服务实现类。 @@ -190,6 +194,9 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic @Resource private OperationAnalysisMapper operationAnalysisMapper; + @Resource + private com.roomroot.jwgl.mapper.ClassRoomMapper classRoomMapper; + /** * 教员表数据访问接口,用于审批时根据教员编号查询教研室代号。 */ @@ -569,7 +576,10 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic query.getTxzt() ); - // 步骤5:封装分页结果并返回 + // 步骤5:回填主讲/辅讲教员与上课场地(按本页课次批量查,避免逐行查库) + fillLessonTeachersAndRooms(resultPage.getRecords()); + + // 步骤6:封装分页结果并返回 return new PageResult<>( resultPage.getRecords(), resultPage.getTotal(), @@ -578,6 +588,71 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic ); } + /** + * 回填课次的主讲/辅讲教员姓名与场地名称。 + *

主讲 = 实施_课程表_辅助教员.主教员=1;其余为辅讲。场地取 实施_课程表_教室 关联的教室名称。

+ */ + private void fillLessonTeachersAndRooms(List records) { + if (records == null || records.isEmpty()) { + return; + } + List lessonBhs = records.stream() + .map(TeachingPlanLessonVO::getSskcbbh) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + if (lessonBhs.isEmpty()) { + return; + } + Map> mainTeachers = new HashMap<>(); + Map> subTeachers = new HashMap<>(); + Set jybhSet = new HashSet<>(); + for (SSKCBFZJY link : sskcbfzjymMapper.selectList(new LambdaQueryWrapper() + .in(SSKCBFZJY::getSskcbbh, lessonBhs))) { + if (link.getFzjybh() == null || link.getFzjybh().isEmpty()) { + continue; + } + jybhSet.add(link.getFzjybh()); + (link.getZjy() != null && link.getZjy() == 1 ? mainTeachers : subTeachers) + .computeIfAbsent(link.getSskcbbh(), k -> new ArrayList<>()) + .add(link.getFzjybh()); + } + Map teacherNames = jybhSet.isEmpty() ? new HashMap<>() + : jybMapper.selectList(new LambdaQueryWrapper() + .in(com.roomroot.jwgl.entity.JYB::getJybh, jybhSet)) + .stream() + .filter(Objects::nonNull) + .collect(Collectors.toMap(com.roomroot.jwgl.entity.JYB::getJybh, + j -> j.getJyxm() == null ? j.getJybh() : j.getJyxm(), (a, b) -> a)); + Map> rooms = new HashMap<>(); + Set jsbhSet = new HashSet<>(); + for (SSKCBJS link : sskcbjsMapper.selectList(new LambdaQueryWrapper() + .in(SSKCBJS::getSskcbbh, lessonBhs))) { + if (link.getJsbh() == null || link.getJsbh().isEmpty()) { + continue; + } + jsbhSet.add(link.getJsbh()); + rooms.computeIfAbsent(link.getSskcbbh(), k -> new ArrayList<>()).add(link.getJsbh()); + } + Map roomNames = jsbhSet.isEmpty() ? new HashMap<>() + : classRoomMapper.selectList(new LambdaQueryWrapper() + .in(com.roomroot.jwgl.entity.JSB::getJsbh, jsbhSet) + .eq(com.roomroot.jwgl.entity.JSB::getDelFlag, 0)) + .stream() + .filter(Objects::nonNull) + .collect(Collectors.toMap(com.roomroot.jwgl.entity.JSB::getJsbh, + j -> j.getJsmc() == null ? j.getJsbh() : j.getJsmc(), (a, b) -> a)); + for (TeachingPlanLessonVO vo : records) { + String bh = vo.getSskcbbh(); + vo.setZjyxm(mainTeachers.getOrDefault(bh, List.of()).stream() + .map(b2 -> teacherNames.getOrDefault(b2, b2)).collect(Collectors.joining("、"))); + vo.setFjyxm(subTeachers.getOrDefault(bh, List.of()).stream() + .map(b2 -> teacherNames.getOrDefault(b2, b2)).collect(Collectors.joining("、"))); + vo.setJsmc(rooms.getOrDefault(bh, List.of()).stream() + .map(b2 -> roomNames.getOrDefault(b2, b2)).collect(Collectors.joining("、"))); + } + } + /** * 按查询条件导出课次数据为 Excel 文件。 * diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/TimetableConflictServiceImpl.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/TimetableConflictServiceImpl.java index 259ea5ef..b1a58be8 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/TimetableConflictServiceImpl.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/service/impl/TimetableConflictServiceImpl.java @@ -280,9 +280,14 @@ public class TimetableConflictServiceImpl implements TimetableConflictService { case EVENT_CONFLICT -> checkEventConflicts(nd); case GUARANTEE_CONFLICT -> Collections.emptyList(); }; - // 本检查器的维度全部为硬冲突(双占 / 三类历不可排);软提示由排课窗实时计算 + // 未显式标注级别的明细默认硬冲突(双占 / 三类历不可排); + // checkEventConflicts 中"非正课时段"已标 soft,不在此覆盖 if (details != null) { - details.forEach(d -> d.setLevel("hard")); + details.forEach(d -> { + if (d.getLevel() == null || d.getLevel().isEmpty()) { + d.setLevel("hard"); + } + }); } } catch (Exception e) { log.error("[课表冲突检查][维度:{}][年度:{}] 执行SQL失败: {}", @@ -589,6 +594,72 @@ public class TimetableConflictServiceImpl implements TimetableConflictService { } } } + + // ---- 软提示:非正课时段(正课=0 但可排课)已有课次 → 橙色提示,不算硬冲突 ---- + Set hardSchoolKeys = new HashSet<>(); + for (XQXLB grid : schoolUnavailable) { + for (Integer jc : PeriodUtil.parsePeriods(grid.getCourseClass())) { + hardSchoolKeys.add(grid.getJqsj() + "#" + jc); + } + } + List schoolSoft = semesterCalendarMapper.selectList(new LambdaQueryWrapper() + .eq(XQXLB::getNd, nd) + .eq(XQXLB::getZk, false) + .ne(XQXLB::getKpk, false)); + for (XQXLB grid : schoolSoft) { + for (Integer jc : PeriodUtil.parsePeriods(grid.getCourseClass())) { + if (hardSchoolKeys.contains(grid.getJqsj() + "#" + jc)) { + continue; + } + List hits = byGrid.get(grid.getJqsj() + "#" + jc); + if (hits != null && !hits.isEmpty()) { + TimetableConflictDetailVO d = buildEventDetail( + "SOFT_SCHOOL|" + grid.getJqsj() + "#" + jc, "非正课时段", + grid.getJqsj(), jc, hits, courseNames, + "校历标记该日期节次为非正课时段,但已有课次安排"); + d.setLevel("soft"); + result.add(d); + } + } + } + { + List classSoft = semesterBhs.isEmpty() ? Collections.emptyList() + : jqbMapper.selectList(new LambdaQueryWrapper() + .in(JQB::getXydxqbh, semesterBhs) + .eq(JQB::getZk, 0) + .ne(JQB::getKpk, 0)); + if (!classSoft.isEmpty()) { + Map lessonByBh = lessons.stream() + .collect(Collectors.toMap(SSKCB::getBh, l -> l, (a, b) -> a)); + List links = sskcxydMapper.selectList(new LambdaQueryWrapper() + .in(SSKCXYD::getSskcbh, lessonByBh.keySet())); + Map teamNames = xydbMapper.selectList(new LambdaQueryWrapper<>()).stream() + .collect(Collectors.toMap(XYDB::getXydbh, XYDB::getXydmc, (a, b) -> a)); + Map> teamsOfLesson = new HashMap<>(); + for (SSKCXYD link : links) { + teamsOfLesson.computeIfAbsent(link.getSskcbh(), k -> new ArrayList<>()).add(link.getXydbh()); + } + for (JQB grid : classSoft) { + if (grid.getJqsj() == null || grid.getCourseClass() == null) continue; + String dateStr = intDateToString(grid.getJqsj()); + for (Integer jc : PeriodUtil.parsePeriods(grid.getCourseClass())) { + for (Map.Entry> e : teamsOfLesson.entrySet()) { + if (!e.getValue().contains(grid.getXydbh())) continue; + SSKCB lesson = lessonByBh.get(e.getKey()); + if (lesson == null || lesson.getRq() == null || lesson.getJc() == null) continue; + if (!dateStr.equals(lesson.getRq().toLocalDate().toString()) || lesson.getJc() != jc) continue; + TimetableConflictDetailVO d = buildEventDetail( + "SOFT_CLASS|" + grid.getXydbh() + "|" + dateStr + "#" + jc, "非正课时段", + dateStr, jc, List.of(lesson), courseNames, + "班历标记该日期节次对该学员队为非正课时段,但已有课次安排"); + d.setLevel("soft"); + d.setXydNames(teamNames.getOrDefault(grid.getXydbh(), grid.getXydbh())); + result.add(d); + } + } + } + } + } return result; } diff --git a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/TeachingPlanLessonVO.java b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/TeachingPlanLessonVO.java index 80311104..91061dc9 100644 --- a/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/TeachingPlanLessonVO.java +++ b/backend/roomroot-jwgl/src/main/java/com/roomroot/jwgl/vo/courserunning/TeachingPlanLessonVO.java @@ -59,6 +59,21 @@ public class TeachingPlanLessonVO { */ private String jxff; + /** + * 主讲教员姓名(课次辅讲教员表中 主教员=1 的教员)。 + */ + private String zjyxm; + + /** + * 辅讲教员姓名(多个用「、」连接)。 + */ + private String fjyxm; + + /** + * 上课场地名称(课次教室关联,多个用「、」连接)。 + */ + private String jsmc; + /** * 填写状态:0-未填写,1-已填写,2-已提交。 */ diff --git a/frontend/src/api/teachBusiness/courseRunning.js b/frontend/src/api/teachBusiness/courseRunning.js index beae5bb5..c44470c3 100644 --- a/frontend/src/api/teachBusiness/courseRunning.js +++ b/frontend/src/api/teachBusiness/courseRunning.js @@ -108,3 +108,85 @@ export function cancelScheduleAdjust(params) { params }) } + +// ==================== 运行分析 /course-running/analysis ==================== +// 接口依据:CourseRunningController 五个 analysis 端点(POST,body 为 OperationAnalysisQueryDTO) + +/** + * 教学运行概览指标 + * POST /course-running/analysis/overview + * 请求体:{ nd, xqd, jxxbh, startDate, endDate, dimension } + * 返回:OperationOverviewVO(排课完成率/缺勤率/场地使用率/周均课时/调课数等) + */ +export function getAnalysisOverview(data) { + return request({ + url: '/course-running/analysis/overview', + method: 'post', + data + }) +} + +/** + * 各教学系排课完成率 + * POST /course-running/analysis/course-completion + * 返回:List(jxxbh/jxxmc/completionRate/completedCount/totalCount) + */ +export function getCourseCompletion(data) { + return request({ + url: '/course-running/analysis/course-completion', + method: 'post', + data + }) +} + +/** + * 场地使用率分布 + * POST /course-running/analysis/venue-usage + * 返回:List(cdlybh/cdlymc/usageRate/usageCount/totalCount) + */ +export function getVenueUsage(data) { + return request({ + url: '/course-running/analysis/venue-usage', + method: 'post', + data + }) +} + +/** + * 调课频次趋势 + * POST /course-running/analysis/adjust-trend + * 返回:List(period/periodName/adjustCount) + */ +export function getAdjustTrend(data) { + return request({ + url: '/course-running/analysis/adjust-trend', + method: 'post', + data + }) +} + +/** + * 导出运行分析报表(四个 sheet:概览/系别完成率/场地使用率/调课趋势) + * POST /course-running/analysis/export + */ +export function exportAnalysisReport(data) { + return request({ + url: '/course-running/analysis/export', + method: 'post', + data, + responseType: 'blob' + }) +} + +/** + * 导出教学实施计划课次列表 + * GET /course-running/plan/export(参数同 listTeachingPlan,无分页) + */ +export function exportTeachingPlan(params) { + return request({ + url: '/course-running/plan/export', + method: 'get', + params, + responseType: 'blob' + }) +} diff --git a/frontend/src/views/teachBusiness/operationAnalysis/index.vue b/frontend/src/views/teachBusiness/operationAnalysis/index.vue new file mode 100644 index 00000000..9440659c --- /dev/null +++ b/frontend/src/views/teachBusiness/operationAnalysis/index.vue @@ -0,0 +1,304 @@ + + + + + diff --git a/frontend/src/views/teachBusiness/schedulingWindow/index.vue b/frontend/src/views/teachBusiness/schedulingWindow/index.vue index eff66a32..927177ae 100644 --- a/frontend/src/views/teachBusiness/schedulingWindow/index.vue +++ b/frontend/src/views/teachBusiness/schedulingWindow/index.vue @@ -1578,8 +1578,8 @@ export default { } &.is-warn { - background: #fdf8e8; - box-shadow: inset 0 0 0 1px #e6c974; + background: #fdf6ec; + box-shadow: inset 0 0 0 1px #e6a23c; } &.is-picked { @@ -1708,14 +1708,14 @@ export default { font-size: 12px; } -/* 冲突格着色(橙色,按所选冲突维度命中) */ +/* 冲突格着色(深红=硬冲突,与冲突明细页色板统一;橙色仅用于软提示) */ .tb-slot.is-conflict { - background: #fdece0; - box-shadow: inset 0 0 0 2px #d97706; + background: #fde2e2; + box-shadow: inset 0 0 0 2px #f56c6c; } .dot-cur { background: #f7c9d8; border: 1px solid #c2477a; } -.dot-conflict { background: #fdece0; border: 1px solid #d97706; } +.dot-conflict { background: #fde2e2; border: 1px solid #f56c6c; } /* 全学期视图:每周一段,可跨周框选 */ .timetable.is-overview .tb-weekline { diff --git a/frontend/src/views/teachBusiness/teachingPlan/index.vue b/frontend/src/views/teachBusiness/teachingPlan/index.vue new file mode 100644 index 00000000..624435f3 --- /dev/null +++ b/frontend/src/views/teachBusiness/teachingPlan/index.vue @@ -0,0 +1,252 @@ + + + + + diff --git a/frontend/src/views/teachBusiness/timetableConflict/index.vue b/frontend/src/views/teachBusiness/timetableConflict/index.vue index 98f77b29..ba8027bc 100644 --- a/frontend/src/views/teachBusiness/timetableConflict/index.vue +++ b/frontend/src/views/teachBusiness/timetableConflict/index.vue @@ -61,8 +61,27 @@ 共 {{ detailTotal }} 条记录 @@ -218,6 +260,7 @@ import { listAllClassroom } from '@/api/teachBusiness/classroom' import { listAllBuild } from '@/api/teachBusiness/build' +import { venueSchedule } from '@/api/teachBusiness/venueCalendar' import VenueCalendarEditor from './calendarEditor.vue' export default { @@ -250,6 +293,11 @@ export default { // 场地历编辑弹窗 calendarVisible: false, calendarVenue: null, + // 场地占用总览 + scheduleVisible: false, + scheduleLoading: false, + scheduleQuery: { rq: '', jc: undefined }, + scheduleList: [], rules: { jsmc: [{ required: true, message: '请输入教室名称', trigger: 'blur' }] } @@ -277,6 +325,37 @@ export default { const base = [item.jxldh, item.jxlmc].filter(Boolean).join(' ') return base || item.id }, + + /* ---------- 场地占用总览 ---------- */ + openScheduleOverview() { + this.scheduleVisible = true + if (!this.scheduleQuery.rq) { + const now = new Date() + const p = n => String(n).padStart(2, '0') + this.scheduleQuery.rq = `${now.getFullYear()}-${p(now.getMonth() + 1)}-${p(now.getDate())}` + } + this.loadScheduleOverview() + }, + loadScheduleOverview() { + if (!this.scheduleQuery.rq || !this.scheduleQuery.jc) { + this.scheduleList = [] + return + } + this.scheduleLoading = true + venueSchedule(this.scheduleQuery.rq + ' 00:00:00', this.scheduleQuery.jc).then(response => { + this.scheduleList = response.data || [] + }).catch(() => { + this.scheduleList = [] + }).finally(() => { + this.scheduleLoading = false + }) + }, + scheduleStatusText(status) { + return { free: '空闲', unavailable: '不可用', occupied: '已占用', noted: '有备注' }[status] || status || '-' + }, + scheduleStatusTag(status) { + return { free: 'success', unavailable: 'danger', occupied: 'warning', noted: 'info' }[status] || 'info' + }, /** * 独立加载全部场地类型,避免查询结果收窄后下拉候选项同步丢失。 */