From 6ef802ae8c979739a0850a3d790e3bfcecd2be67 Mon Sep 17 00:00:00 2001 From: zjf <1799650030@qq.com> Date: Tue, 17 Jun 2025 17:59:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=9A=E8=AE=AE=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/meeting/app/MeetingPageDto.java | 7 + .../vo/meeting/app/MeetingBookingReqVo.java | 33 ++++ .../integrated/vo/meeting/app/TimeSlotVo.java | 30 ++++ .../controller/MeetingRoomController.java | 152 +++++++++++++++++- .../entity/MeetingBookingEntity.java | 14 +- .../mapper/MeetingBookingMapper.java | 3 +- .../resources/mapper/MeetingBookingMapper.xml | 5 +- .../service/impl/SmErpSpuServiceImpl.java | 2 +- 8 files changed, 238 insertions(+), 8 deletions(-) create mode 100644 pjcloud-integrated/pjcloud-integrated-api/src/main/java/com/bsd/pjcloud/integrated/dto/meeting/app/MeetingPageDto.java create mode 100644 pjcloud-integrated/pjcloud-integrated-api/src/main/java/com/bsd/pjcloud/integrated/vo/meeting/app/MeetingBookingReqVo.java create mode 100644 pjcloud-integrated/pjcloud-integrated-api/src/main/java/com/bsd/pjcloud/integrated/vo/meeting/app/TimeSlotVo.java diff --git a/pjcloud-integrated/pjcloud-integrated-api/src/main/java/com/bsd/pjcloud/integrated/dto/meeting/app/MeetingPageDto.java b/pjcloud-integrated/pjcloud-integrated-api/src/main/java/com/bsd/pjcloud/integrated/dto/meeting/app/MeetingPageDto.java new file mode 100644 index 000000000..57af05a5c --- /dev/null +++ b/pjcloud-integrated/pjcloud-integrated-api/src/main/java/com/bsd/pjcloud/integrated/dto/meeting/app/MeetingPageDto.java @@ -0,0 +1,7 @@ +package com.bsd.pjcloud.integrated.dto.meeting.app; + +import lombok.Data; + +@Data +public class MeetingPageDto { +} diff --git a/pjcloud-integrated/pjcloud-integrated-api/src/main/java/com/bsd/pjcloud/integrated/vo/meeting/app/MeetingBookingReqVo.java b/pjcloud-integrated/pjcloud-integrated-api/src/main/java/com/bsd/pjcloud/integrated/vo/meeting/app/MeetingBookingReqVo.java new file mode 100644 index 000000000..35e12e16e --- /dev/null +++ b/pjcloud-integrated/pjcloud-integrated-api/src/main/java/com/bsd/pjcloud/integrated/vo/meeting/app/MeetingBookingReqVo.java @@ -0,0 +1,33 @@ +package com.bsd.pjcloud.integrated.vo.meeting.app; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; + +@Data +@Schema(description = "会议室预约请求") +public class MeetingBookingReqVo { + + @Schema(description = "会议主题") + private String title; + + @Schema(description = "会议说明") + private String description; + + @Schema(description = "预约日期") + @NotNull + private String date; + + @Schema(description = "开始时间") + @NotNull + private String startTime; + + @Schema(description = "结束时间") + @NotNull + private String endTime; + + @Schema(description = "参会人员ID列表") + private List attendees; +} \ No newline at end of file diff --git a/pjcloud-integrated/pjcloud-integrated-api/src/main/java/com/bsd/pjcloud/integrated/vo/meeting/app/TimeSlotVo.java b/pjcloud-integrated/pjcloud-integrated-api/src/main/java/com/bsd/pjcloud/integrated/vo/meeting/app/TimeSlotVo.java new file mode 100644 index 000000000..a098cccbf --- /dev/null +++ b/pjcloud-integrated/pjcloud-integrated-api/src/main/java/com/bsd/pjcloud/integrated/vo/meeting/app/TimeSlotVo.java @@ -0,0 +1,30 @@ +package com.bsd.pjcloud.integrated.vo.meeting.app; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "会议室时间段") +public class TimeSlotVo { + + @Schema(description = "开始时间") + private String startTime; + + @Schema(description = "结束时间") + private String endTime; + + @Schema(description = "状态:free-空闲,booked-已预约,disabled-不可用") + private String status; + + @Schema(description = "预约人信息") + private BookedByVo bookedBy; + + @Data + public static class BookedByVo { + @Schema(description = "用户ID") + private String userId; + + @Schema(description = "用户名称") + private String userName; + } +} \ No newline at end of file diff --git a/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/controller/MeetingRoomController.java b/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/controller/MeetingRoomController.java index 4e3065fe5..f0b01e082 100644 --- a/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/controller/MeetingRoomController.java +++ b/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/controller/MeetingRoomController.java @@ -9,11 +9,17 @@ import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum; import com.bsd.pjcloud.common.core.util.R; import com.bsd.pjcloud.common.log.annotation.SysLog; import com.bsd.pjcloud.common.security.util.SecurityUtils; +import com.bsd.pjcloud.flow.task.constant.TaskCheckStatusEnum; +import com.bsd.pjcloud.integrated.dto.meeting.app.MeetingPageDto; +import com.bsd.pjcloud.integrated.entity.MeetingBookingEntity; import com.bsd.pjcloud.integrated.entity.MeetingRoomEntity; import com.bsd.pjcloud.integrated.entity.MeetingRoomEquipmentEntity; +import com.bsd.pjcloud.integrated.service.MeetingBookingService; import com.bsd.pjcloud.integrated.service.MeetingRoomEquipmentService; import com.bsd.pjcloud.integrated.service.MeetingRoomService; +import com.bsd.pjcloud.integrated.vo.meeting.app.MeetingBookingReqVo; import com.bsd.pjcloud.integrated.vo.meeting.app.MeetingRoomPageVo; +import com.bsd.pjcloud.integrated.vo.meeting.app.TimeSlotVo; import org.springframework.security.access.prepost.PreAuthorize; import com.bsd.pjcloud.common.excel.annotation.ResponseExcel; import io.swagger.v3.oas.annotations.security.SecurityRequirement; @@ -27,6 +33,11 @@ import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Objects; +import java.time.LocalTime; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.time.LocalDateTime; /** * 会议室信息表 @@ -45,6 +56,8 @@ public class MeetingRoomController { private final MeetingRoomEquipmentService meetingRoomEquipmentService; + private final MeetingBookingService meetingBookingService; + /** * 分页查询 * @param page 分页对象 @@ -144,7 +157,7 @@ public class MeetingRoomController { /**---------------------------APP------------------------------*/ @GetMapping("/app/page") - public R> appList(@ParameterObject Page page, @ParameterObject MeetingRoomEntity meetingRoom) { + public R> appList(@ParameterObject Page page, @ParameterObject MeetingPageDto meetingRoom) { LambdaQueryWrapper meetingRoomEntityLambdaQueryWrapper = new LambdaQueryWrapper<>(); meetingRoomEntityLambdaQueryWrapper.eq(MeetingRoomEntity::getStatus, YesNoEnum.NO.getCode()); meetingRoomEntityLambdaQueryWrapper.orderByDesc(MeetingRoomEntity::getSort).orderByDesc(MeetingRoomEntity::getId); @@ -154,4 +167,141 @@ public class MeetingRoomController { return R.ok(pageData); } + + + /** + * 时间段 + * @param date + * @param roomId + * @return + */ + @GetMapping("/{roomId}/time-slots") + public R> timeSlots(@RequestParam(value = "date") String date, @PathVariable("roomId") Long roomId) { + // 生成30分钟间隔的时间段 + List timeSlots = new ArrayList<>(); + LocalTime startTime = LocalTime.of(8, 0); + LocalTime endTime = LocalTime.of(18, 0); + + while (startTime.isBefore(endTime)) { + TimeSlotVo slot = new TimeSlotVo(); + slot.setStartTime(startTime.format(DateTimeFormatter.ofPattern("HH:mm"))); + slot.setEndTime(startTime.plusMinutes(30).format(DateTimeFormatter.ofPattern("HH:mm"))); + slot.setStatus("free"); + timeSlots.add(slot); + startTime = startTime.plusMinutes(30); + } + + // 获取当天的预约记录 + LocalDate bookingDate = LocalDate.parse(date); + List bookings = meetingBookingService.list( + Wrappers.lambdaQuery() + .eq(MeetingBookingEntity::getRoomId, roomId) + .eq(MeetingBookingEntity::getBookingDate, bookingDate) + .eq(MeetingBookingEntity::getCheckStatus, TaskCheckStatusEnum.RESULT.getCode()) // 已通过的预约 + ); + + // 标记已预约的时间段 + for (MeetingBookingEntity booking : bookings) { + LocalTime bookingStart = booking.getStartTime(); + LocalTime bookingEnd = booking.getEndTime(); + + for (TimeSlotVo slot : timeSlots) { + LocalTime slotStart = LocalTime.parse(slot.getStartTime(), DateTimeFormatter.ofPattern("HH:mm")); + LocalTime slotEnd = LocalTime.parse(slot.getEndTime(), DateTimeFormatter.ofPattern("HH:mm")); + + // 修改判断逻辑:只要时间段有重叠就标记为已预约 + if (!(slotEnd.isBefore(bookingStart) || slotStart.isAfter(bookingEnd))) { + slot.setStatus("booked"); + TimeSlotVo.BookedByVo bookedBy = new TimeSlotVo.BookedByVo(); + bookedBy.setUserId(String.valueOf(booking.getApplicantId())); + // TODO: 从用户服务获取用户名 + bookedBy.setUserName("用户" + booking.getApplicantId()); + slot.setBookedBy(bookedBy); + } + } + } + + // 标记不可用的时间段(12:00-13:00 午休时间) + for (TimeSlotVo slot : timeSlots) { + LocalTime slotStart = LocalTime.parse(slot.getStartTime(), DateTimeFormatter.ofPattern("HH:mm")); + if (slotStart.isAfter(LocalTime.of(11, 59)) && slotStart.isBefore(LocalTime.of(13, 0))) { + slot.setStatus("disabled"); + } + } + + return R.ok(timeSlots); + } + + + @PostMapping("/{roomId}/book") + @Operation(summary = "预约会议室", description = "预约会议室") + public R bookMeetingRoom(@PathVariable("roomId") Long roomId, @RequestBody MeetingBookingReqVo reqVo) { + // 1. 验证会议室是否存在 + MeetingRoomEntity room = meetingRoomService.getById(roomId); + if (room == null) { + return R.failed("会议室不存在"); + } + + // 2. 验证会议室状态 + if (!YesNoEnum.NO.getCode().equals(room.getStatus())) { + return R.failed("会议室当前不可用"); + } + + // 3. 转换时间格式 + LocalDate bookingDate = LocalDate.parse(reqVo.getDate()); + LocalTime startTime = LocalTime.parse(reqVo.getStartTime()); + LocalTime endTime = LocalTime.parse(reqVo.getEndTime()); + + // 4. 验证时间是否合法 + if (startTime.isAfter(endTime)) { + return R.failed("开始时间不能晚于结束时间"); + } + + // 5. 验证是否在可用时间段内 + LocalTime availableStart = LocalTime.of(8, 0); + LocalTime availableEnd = LocalTime.of(18, 0); + if (startTime.isBefore(availableStart) || endTime.isAfter(availableEnd)) { + return R.failed("预约时间必须在8:00-18:00之间"); + } + + // 6. 验证是否在午休时间 + if ((startTime.isAfter(LocalTime.of(11, 59)) && startTime.isBefore(LocalTime.of(13, 0))) || + (endTime.isAfter(LocalTime.of(11, 59)) && endTime.isBefore(LocalTime.of(13, 0)))) { + return R.failed("不能预约午休时间(12:00-13:00)"); + } + + // 7. 检查时间段是否已被预约 + List existingBookings = meetingBookingService.list( + Wrappers.lambdaQuery() + .eq(MeetingBookingEntity::getRoomId, roomId) + .eq(MeetingBookingEntity::getBookingDate, bookingDate) + .eq(MeetingBookingEntity::getCheckStatus, TaskCheckStatusEnum.RESULT.getCode()) + ); + + for (MeetingBookingEntity booking : existingBookings) { + LocalTime bookingStart = booking.getStartTime(); + LocalTime bookingEnd = booking.getEndTime(); + + // 修改判断逻辑:只要时间段有重叠就表示冲突 + if (!(endTime.isBefore(bookingStart) || startTime.isAfter(bookingEnd))) { + return R.failed("该时间段已被预约"); + } + } + + // 8. 创建预约记录 + MeetingBookingEntity booking = new MeetingBookingEntity(); + booking.setTitle(reqVo.getTitle()); + booking.setDescription(reqVo.getDescription()); + booking.setRoomId(roomId); + booking.setApplicantId(SecurityUtils.getUser().getId()); + booking.setDeptId(SecurityUtils.getUser().getDeptId()); + booking.setBookingDate(bookingDate); + booking.setStartTime(startTime); + booking.setEndTime(endTime); + booking.setCheckStatus(TaskCheckStatusEnum.RESULT.getCode()); + + boolean success = meetingBookingService.save(booking); + return R.ok(success); + } + } \ No newline at end of file diff --git a/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/entity/MeetingBookingEntity.java b/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/entity/MeetingBookingEntity.java index 8a8237345..75273e7ca 100644 --- a/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/entity/MeetingBookingEntity.java +++ b/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/entity/MeetingBookingEntity.java @@ -6,7 +6,10 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import com.bsd.pjcloud.common.core.util.TenantTable; + +import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; /** * 会议室预约 @@ -51,7 +54,7 @@ public class MeetingBookingEntity extends Model { * 审批状态 */ @Schema(description="审批状态") - private String meetingStatus; + private String checkStatus; /** * 部门id @@ -75,13 +78,13 @@ public class MeetingBookingEntity extends Model { * 开始时间 */ @Schema(description="开始时间") - private LocalDateTime startTime; + private LocalTime startTime; /** * 结束时间 */ @Schema(description="结束时间") - private LocalDateTime endTime; + private LocalTime endTime; /** * 创建者 @@ -124,4 +127,9 @@ public class MeetingBookingEntity extends Model { */ @Schema(description="租户编号") private Long tenantId; + + + @Schema(description = "预约日期") + private LocalDate bookingDate; + } \ No newline at end of file diff --git a/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/mapper/MeetingBookingMapper.java b/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/mapper/MeetingBookingMapper.java index 52a02d75e..5d6de3185 100644 --- a/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/mapper/MeetingBookingMapper.java +++ b/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/mapper/MeetingBookingMapper.java @@ -3,6 +3,7 @@ package com.bsd.pjcloud.integrated.mapper; import com.bsd.pjcloud.common.data.datascope.PjcloudBaseMapper; import com.bsd.pjcloud.integrated.entity.MeetingBookingEntity; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import java.time.LocalDate; import java.util.List; @@ -13,5 +14,5 @@ public interface MeetingBookingMapper extends PjcloudBaseMapper findByRoomIdAndDate(Long roomId, LocalDate date); + List findByRoomIdAndDate(Long roomId, @Param("date") LocalDate date); } \ No newline at end of file diff --git a/pjcloud-integrated/pjcloud-integrated-biz/src/main/resources/mapper/MeetingBookingMapper.xml b/pjcloud-integrated/pjcloud-integrated-biz/src/main/resources/mapper/MeetingBookingMapper.xml index 6a0536664..8dcf287ec 100644 --- a/pjcloud-integrated/pjcloud-integrated-biz/src/main/resources/mapper/MeetingBookingMapper.xml +++ b/pjcloud-integrated/pjcloud-integrated-biz/src/main/resources/mapper/MeetingBookingMapper.xml @@ -8,7 +8,7 @@ - + @@ -20,8 +20,9 @@ + \ No newline at end of file diff --git a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpSpuServiceImpl.java b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpSpuServiceImpl.java index 97160f01a..57fc9b4e0 100644 --- a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpSpuServiceImpl.java +++ b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmErpSpuServiceImpl.java @@ -126,7 +126,7 @@ public class SmErpSpuServiceImpl extends ServiceImpl unitCollect = smErpUnitEntityList.stream().filter(smErpUnitEntity -> smErpUnitEntity.getPackageNum() <= 0).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(unitCollect)){ - return R.failed("包装类型内装数量不能小于等于0!"); + return R.failed("包装类型内装数.量不能小于等于0!"); } if (CollectionUtils.isNotEmpty(smErpUnitEntityList)) { smErpUnitEntityList.forEach(supermarketUnitEntity -> supermarketUnitEntity.setSpuId(supermarketSpu.getId()));