diff --git a/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/guildhall/controller/GuildHallController.java b/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/guildhall/controller/GuildHallController.java index c1a18844..fac4e4c0 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/guildhall/controller/GuildHallController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/guildhall/controller/GuildHallController.java @@ -7,7 +7,9 @@ import com.budwk.app.base.page.Pagination; import com.budwk.app.base.param.PageForm; import com.budwk.app.base.result.Result; import com.budwk.app.zhgh.democratic.teachercongress.guildhall.models.GuildHall; +import com.budwk.app.zhgh.democratic.teachercongress.guildhall.models.GuildHallMeeting; import com.budwk.app.zhgh.democratic.teachercongress.guildhall.models.GuildHallSeat; +import com.budwk.app.zhgh.democratic.teachercongress.guildhall.models.GuildHallSeatSelect; import com.budwk.app.zhgh.democratic.teachercongress.guildhall.service.GuildHallService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -21,7 +23,10 @@ import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Param; +import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; @Api("会议厅管理") @IocBean @@ -114,13 +119,73 @@ public class GuildHallController { @ApiOperation("保存座位") @Aop(TransAop.READ_COMMITTED) public Result saveSeat(String hallId, @Param("seats") GuildHallSeat[] seats) { + Date now = new Date(); + List meetings = dao.query(GuildHallMeeting.class, + Cnd.where(GuildHallMeeting::getHallId, "=", hallId) + .and(GuildHallMeeting::getEndTime, ">=", now)); + Map newSeatMap = new HashMap<>(); + for (GuildHallSeat seat : seats) { + newSeatMap.put(seatKey(seat.getRowNumber(), seat.getColNumber()), seat); + } + + for (GuildHallMeeting meeting : meetings) { + List meetingSeats = dao.query(GuildHallSeatSelect.class, + Cnd.where("meetingId", "=", meeting.getId())); + for (GuildHallSeatSelect meetingSeat : meetingSeats) { + GuildHallSeat newSeat = newSeatMap.get(seatKey(meetingSeat.getRowNumber(), meetingSeat.getColNumber())); + if (meetingSeat.getUserId() != null + && (newSeat == null || Boolean.FALSE.equals(newSeat.getEnable()))) { + return Result.error("会议“" + meeting.getName() + "”的第" + meetingSeat.getRowNumber() + + "排第" + meetingSeat.getColNumber() + "列已被选择,不能删除或停用"); + } + } + } + dao.clear(GuildHallSeat.class, Cnd.where(GuildHallSeat::getHallId, "=", hallId)); for (GuildHallSeat seat : seats) { seat.setHallId(hallId); } dao.insert(seats); + + for (GuildHallMeeting meeting : meetings) { + List meetingSeats = dao.query(GuildHallSeatSelect.class, + Cnd.where("meetingId", "=", meeting.getId())); + Map meetingSeatMap = new HashMap<>(); + for (GuildHallSeatSelect meetingSeat : meetingSeats) { + meetingSeatMap.put(seatKey(meetingSeat.getRowNumber(), meetingSeat.getColNumber()), meetingSeat); + } + + for (GuildHallSeat seat : seats) { + String key = seatKey(seat.getRowNumber(), seat.getColNumber()); + GuildHallSeatSelect meetingSeat = meetingSeatMap.remove(key); + if (meetingSeat == null) { + meetingSeat = new GuildHallSeatSelect(); + meetingSeat.setId(null); + meetingSeat.setHallId(hallId); + meetingSeat.setMeetingId(meeting.getId()); + meetingSeat.setRowNumber(seat.getRowNumber()); + meetingSeat.setColNumber(seat.getColNumber()); + meetingSeat.setSeatNumber(seat.getSeatNumber()); + meetingSeat.setEnable(seat.getEnable()); + dao.insert(meetingSeat); + } else { + meetingSeat.setHallId(hallId); + meetingSeat.setSeatNumber(seat.getSeatNumber()); + meetingSeat.setEnable(seat.getEnable()); + dao.update(meetingSeat); + } + } + + for (GuildHallSeatSelect removedSeat : meetingSeatMap.values()) { + dao.delete(GuildHallSeatSelect.class, removedSeat.getId()); + } + } return Result.success(); } + private String seatKey(Integer rowNumber, Integer colNumber) { + return rowNumber + "_" + colNumber; + } + } diff --git a/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/guildhall/controller/GuildHallMeetingController.java b/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/guildhall/controller/GuildHallMeetingController.java index e00e073e..c4d30b58 100644 --- a/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/guildhall/controller/GuildHallMeetingController.java +++ b/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/guildhall/controller/GuildHallMeetingController.java @@ -1,7 +1,6 @@ package com.budwk.app.zhgh.democratic.teachercongress.guildhall.controller; import cn.dev33.satoken.annotation.SaCheckPermission; -import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import com.budwk.app.base.annotation.SLog; @@ -29,7 +28,11 @@ import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; import java.util.ArrayList; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; @Api("会议厅会议") @IocBean @@ -63,6 +66,29 @@ public class GuildHallMeetingController { return Result.success(pagination); } + @At + @SaCheckPermission("guildHall.meeting") + @ApiOperation("会议厅已占用时间列表") + public Result occupiedTimes(PageForm pageForm, String hallId, Date startTime, Date endTime, Boolean includeFree) { + Cnd cnd = Cnd.NEW(); + cnd.andEX(GuildHallMeeting::getHallId, "=", hallId); + if (startTime != null) { + cnd.and(GuildHallMeeting::getEndTime, ">=", startTime); + } + if (endTime != null) { + cnd.and(GuildHallMeeting::getStartTime, "<=", endTime); + } + cnd.asc(GuildHallMeeting::getStartTime); + List occupiedTimes = buildOccupiedTimes(dao.query(GuildHallMeeting.class, cnd), Boolean.TRUE.equals(includeFree)); + int pageNumber = pageForm.getPageNumber() == null ? 1 : pageForm.getPageNumber(); + int pageSize = pageForm.getPageSize() == null ? 10 : pageForm.getPageSize(); + int totalCount = occupiedTimes.size(); + int fromIndex = Math.min((pageNumber - 1) * pageSize, totalCount); + int toIndex = Math.min(fromIndex + pageSize, totalCount); + return Result.success(new Pagination<>(pageNumber, pageSize, totalCount, + occupiedTimes.subList(fromIndex, toIndex))); + } + @At @SaCheckPermission("guildHall.meeting") @@ -70,13 +96,12 @@ public class GuildHallMeetingController { @ApiOperation("保存会议厅会议") @Aop(TransAop.READ_COMMITTED) public Result save(GuildHallMeeting meeting) { + Result timeCheckResult = checkMeetingTime(meeting); + if (timeCheckResult != null) { + return timeCheckResult; + } dao.insert(meeting); - List seats = dao.query(GuildHallSeat.class, Cnd.where("hallId", "=", meeting.getHallId())); - List selects = BeanUtil.copyToList(seats, GuildHallSeatSelect.class); - for (GuildHallSeatSelect select : selects) { - select.setMeetingId(meeting.getId()); - } - dao.insert(selects); + initMeetingSeats(meeting.getId(), meeting.getHallId()); return Result.success(); } @@ -86,14 +111,19 @@ public class GuildHallMeetingController { @ApiOperation("修改会议厅会议") @Aop(TransAop.READ_COMMITTED) public Result update(GuildHallMeeting meeting) { + GuildHallMeeting oldMeeting = dao.fetch(GuildHallMeeting.class, meeting.getId()); + if (oldMeeting == null) { + return Result.error("会议不存在或已删除"); + } + Result timeCheckResult = checkMeetingTime(meeting); + if (timeCheckResult != null) { + return timeCheckResult; + } dao.update(meeting); - dao.clear(GuildHallSeatSelect.class, Cnd.where("hallId", "=", meeting.getHallId())); - List seats = dao.query(GuildHallSeat.class, Cnd.where("hallId", "=", meeting.getHallId())); - List selects = BeanUtil.copyToList(seats, GuildHallSeatSelect.class); - for (GuildHallSeatSelect select : selects) { - select.setMeetingId(meeting.getId()); - } - dao.insert(selects); + if (!StrUtil.equals(oldMeeting.getHallId(), meeting.getHallId())) { + dao.clear(GuildHallSeatSelect.class, Cnd.where("meetingId", "=", meeting.getId())); + initMeetingSeats(meeting.getId(), meeting.getHallId()); + } return Result.success(); } @@ -101,11 +131,116 @@ public class GuildHallMeetingController { @SaCheckPermission("guildHall.meeting") @SLog(tag = "会议厅会议", msg = "删除会议厅会议") @ApiOperation("删除会议厅会议") + @Aop(TransAop.READ_COMMITTED) public Result delete(String id) { + dao.clear(GuildHallSeatSelect.class, Cnd.where("meetingId", "=", id)); dao.delete(GuildHallMeeting.class, id); return Result.success(); } + private void initMeetingSeats(String meetingId, String hallId) { + List seats = dao.query(GuildHallSeat.class, Cnd.where("hallId", "=", hallId)); + List selects = new ArrayList<>(); + for (GuildHallSeat seat : seats) { + GuildHallSeatSelect select = new GuildHallSeatSelect(); + select.setId(null); + select.setHallId(hallId); + select.setRowNumber(seat.getRowNumber()); + select.setColNumber(seat.getColNumber()); + select.setSeatNumber(seat.getSeatNumber()); + select.setEnable(seat.getEnable()); + select.setMeetingId(meetingId); + selects.add(select); + } + if (!selects.isEmpty()) { + dao.insert(selects); + } + } + + private Result checkMeetingTime(GuildHallMeeting meeting) { + if (meeting.getStartTime() == null || meeting.getEndTime() == null) { + return Result.error("会议开始时间和结束时间不能为空"); + } + if (!meeting.getStartTime().before(meeting.getEndTime())) { + return Result.error("会议结束时间必须大于开始时间"); + } + + Cnd conflictCnd = Cnd.where(GuildHallMeeting::getHallId, "=", meeting.getHallId()) + .and(GuildHallMeeting::getStartTime, "<=", meeting.getEndTime()) + .and(GuildHallMeeting::getEndTime, ">=", meeting.getStartTime()); + if (StrUtil.isNotBlank(meeting.getId())) { + conflictCnd.and(GuildHallMeeting::getId, "!=", meeting.getId()); + } + List conflicts = dao.query(GuildHallMeeting.class, + conflictCnd.asc(GuildHallMeeting::getStartTime)); + if (conflicts.isEmpty()) { + return null; + } + + Cnd occupiedCnd = Cnd.where(GuildHallMeeting::getHallId, "=", meeting.getHallId()); + if (StrUtil.isNotBlank(meeting.getId())) { + occupiedCnd.and(GuildHallMeeting::getId, "!=", meeting.getId()); + } + List occupiedMeetings = dao.query(GuildHallMeeting.class, + occupiedCnd.asc(GuildHallMeeting::getStartTime)); + List occupiedTimes = buildOccupiedTimes(occupiedMeetings, false); + + return Result.error("会议时间冲突,请查看该会议厅已占用时间").addData(occupiedTimes); + } + + private List buildOccupiedTimes(List meetings, boolean includeFree) { + List occupiedTimes = new ArrayList<>(); + Map> meetingsByHall = new HashMap<>(); + for (GuildHallMeeting meeting : meetings) { + meetingsByHall.computeIfAbsent(meeting.getHallId(), key -> new ArrayList<>()).add(meeting); + } + List halls = dao.query(GuildHall.class, Cnd.NEW().asc(GuildHall::getSortCode)); + for (GuildHall hall : halls) { + List hallMeetings = meetingsByHall.remove(hall.getId()); + if (hallMeetings != null) { + appendHallTimes(occupiedTimes, hall.getId(), hall.getName(), hallMeetings, includeFree); + } + } + for (Map.Entry> entry : meetingsByHall.entrySet()) { + appendHallTimes(occupiedTimes, entry.getKey(), "", entry.getValue(), includeFree); + } + return occupiedTimes; + } + + private void appendHallTimes(List occupiedTimes, String hallId, String hallName, + List meetings, boolean includeFree) { + meetings.sort(Comparator.comparing(GuildHallMeeting::getStartTime).reversed()); + GuildHallMeeting previousMeeting = null; + for (GuildHallMeeting meeting : meetings) { + if (includeFree && previousMeeting != null) { + Date freeStartTime = new Date(meeting.getEndTime().getTime() + 1000); + Date freeEndTime = new Date(previousMeeting.getStartTime().getTime() - 1000); + if (!freeStartTime.after(freeEndTime)) { + occupiedTimes.add(NutMap.NEW() + .addv("hallId", hallId) + .addv("hallName", hallName) + .addv("name", "无会议") + .addv("startTime", freeStartTime) + .addv("endTime", freeEndTime) + .addv("available", true)); + } + } + occupiedTimes.add(NutMap.NEW() + .addv("id", meeting.getId()) + .addv("hallId", hallId) + .addv("hallName", hallName) + .addv("name", displayMeetingName(meeting)) + .addv("startTime", meeting.getStartTime()) + .addv("endTime", meeting.getEndTime()) + .addv("available", false)); + previousMeeting = meeting; + } + } + + private String displayMeetingName(GuildHallMeeting meeting) { + return StrUtil.equals(meeting.getCreatedBy(), SecurityUtil.getUserId()) ? meeting.getName() : "****会议"; + } + @At @ApiOperation("查询会议") public Result selectList() { diff --git a/src/main/resources/views/platform/zhgh/democratic/teachercongress/guildhall/meeting/index.html b/src/main/resources/views/platform/zhgh/democratic/teachercongress/guildhall/meeting/index.html index 7605aa7f..2aa1efa2 100644 --- a/src/main/resources/views/platform/zhgh/democratic/teachercongress/guildhall/meeting/index.html +++ b/src/main/resources/views/platform/zhgh/democratic/teachercongress/guildhall/meeting/index.html @@ -23,6 +23,46 @@ layout("/layouts/platform.html"){ min-height: 0; overflow-y: auto; } + + .occupied-time-dialog { + height: calc(100vh - 40px); + max-height: 900px; + margin: 0 !important; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + display: flex; + flex-direction: column; + } + + .occupied-time-dialog .el-dialog__header, + .occupied-time-dialog .el-dialog__footer { + flex-shrink: 0; + } + + .occupied-time-dialog .el-dialog__body { + flex: 1; + min-height: 0; + overflow-y: auto; + } + + .occupied-filter-form { + display: flex; + align-items: center; + flex-wrap: nowrap; + } + + .occupied-filter-form .occupied-free-switch-item { + margin-left: auto; + } + + .occupied-free-switch-label { + margin-right: 8px; + color: #606266; + font-size: 14px; + font-weight: 500; + }
@@ -39,6 +79,7 @@ layout("/layouts/platform.html"){ + 会议厅占用情况 新增 @@ -103,6 +144,66 @@ layout("/layouts/platform.html"){
+ + + + + + + + + + + + + + + 查询 + 重置 + + + 展开空闲会议 + + + + + + + + + + + + + + + + + + + + + + + + +