会议接口

This commit is contained in:
zjf committed 2025-06-17 17:59:32 +08:00
1 parent de0ecc9f59
commit 6ef802ae8c
8 files changed
+238 -8

No files matched your search

@@ -0,0 +1,7 @@
package com.bsd.pjcloud.integrated.dto.meeting.app;
import lombok.Data;
@Data
public class MeetingPageDto {
}
@@ -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<Long> attendees;
}
@@ -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;
}
}
@@ -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<Page<MeetingRoomPageVo>> appList(@ParameterObject Page page, @ParameterObject MeetingRoomEntity meetingRoom) {
public R<Page<MeetingRoomPageVo>> appList(@ParameterObject Page page, @ParameterObject MeetingPageDto meetingRoom) {
LambdaQueryWrapper<MeetingRoomEntity> 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<List<TimeSlotVo>> timeSlots(@RequestParam(value = "date") String date, @PathVariable("roomId") Long roomId) {
// 生成30分钟间隔的时间段
List<TimeSlotVo> 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<MeetingBookingEntity> bookings = meetingBookingService.list(
Wrappers.<MeetingBookingEntity>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<Boolean> 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<MeetingBookingEntity> existingBookings = meetingBookingService.list(
Wrappers.<MeetingBookingEntity>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);
}
}
@@ -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<MeetingBookingEntity> {
* 审批状态
*/
@Schema(description="审批状态")
private String meetingStatus;
private String checkStatus;
/**
* 部门id
@@ -75,13 +78,13 @@ public class MeetingBookingEntity extends Model<MeetingBookingEntity> {
* 开始时间
*/
@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<MeetingBookingEntity> {
*/
@Schema(description="租户编号")
private Long tenantId;
@Schema(description = "预约日期")
private LocalDate bookingDate;
}
@@ -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<MeetingBookingEn
List<MeetingBookingEntity> findByRoomIdAndDate(Long roomId, LocalDate date);
List<MeetingBookingEntity> findByRoomIdAndDate(Long roomId, @Param("date") LocalDate date);
}
@@ -8,7 +8,7 @@
<result property="title" column="title"/>
<result property="roomId" column="room_id"/>
<result property="description" column="description"/>
<result property="meetingStatus" column="meeting_status"/>
<result property="checkStatus" column="meeting_status"/>
<result property="deptId" column="dept_id"/>
<result property="applicantId" column="applicant_id"/>
<result property="assigneeId" column="assignee_id"/>
@@ -20,8 +20,9 @@
<result property="updateTime" column="update_time"/>
<result property="delFlag" column="del_flag"/>
<result property="tenantId" column="tenant_id"/>
<result property="bookingDate" column="booking_date"/>
</resultMap>
<select id="findByRoomIdAndDate" resultType="com.bsd.pjcloud.integrated.entity.MeetingBookingEntity">
SELECT * FROM meeting_booking WHERE room_id = #{roomId} AND start_time >= #{startTime} AND start_time &lt;= #{endTime}
SELECT * FROM meeting_booking WHERE room_id = #{roomId} AND start_time >= #{date} AND start_time &lt;= #{date}
</select>
</mapper>
@@ -126,7 +126,7 @@ public class SmErpSpuServiceImpl extends ServiceImpl<SmErpSpuMapper, SmErpSpuEnt
}
List<SmErpUnitEntity> 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()));