diff --git a/service/src/main/java/cn/edu/bit/ruixin/community/service/impl/AppointmentServiceImpl.java b/service/src/main/java/cn/edu/bit/ruixin/community/service/impl/AppointmentServiceImpl.java index 7972a0b..98bacb4 100644 --- a/service/src/main/java/cn/edu/bit/ruixin/community/service/impl/AppointmentServiceImpl.java +++ b/service/src/main/java/cn/edu/bit/ruixin/community/service/impl/AppointmentServiceImpl.java @@ -16,6 +16,7 @@ import cn.edu.bit.ruixin.community.repository.UserRepository; import cn.edu.bit.ruixin.community.service.AppointmentService; import cn.edu.bit.ruixin.community.service.WechatService; +import cn.edu.bit.ruixin.community.service.RoomService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -29,10 +30,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; /** @@ -62,6 +60,9 @@ public class AppointmentServiceImpl implements AppointmentService { @Autowired private RoomsRepository roomsRepository; + @Autowired + private RoomService roomService; + private Log logger = LogFactory.getLog(AppointmentService.class); @Transactional(readOnly = true) @@ -82,42 +83,46 @@ public Appointment getAppointmentById(Integer id) { @Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class) @Override public void addANewAppointment(Appointment appointment) { - // 基于起始时间段和结束时间段 + // 获取用户预约请求中包含的字段 String launcher = appointment.getLauncher(); -// getAppointment = appointmentRepository.findAppointmentByLauncherEqualsAndRoomIdEqualsAndExecDateEqualsAndLaunchTimeEqualsAndStatusEquals(launcher, roomId, execDate, launchTime, AppointmentStatus.NEW.getStatus()); - // 用户有新发起待批准、已批准通过、已签到的预约时不可再预约 - Appointment myAppointment = appointmentRepository.findAppointmentByLauncherWithStatus(launcher, AppointmentStatus.NEW.getStatus(), AppointmentStatus.RECEIVE.getStatus(), AppointmentStatus.SIGNED.getStatus()); - if (myAppointment != null) { - throw new AppointmentDaoException("你有正在执行的预约,请等待审批!"); - } - - // 判断该房间所预约时间段是否空闲,比较房间ID,预约的日期,预约的时间段,不能对含有预约记录状态为receive、Signed Integer roomId = appointment.getRoomId(); -// Integer launchTime = appointment.getLaunchTime(); + Date execDate = appointment.getExecDate(); Integer appointmentBegin = appointment.getBegin(); Integer appointmentEnd = appointment.getEnd(); - Date execDate = appointment.getExecDate(); -// Appointment getAppointment = appointmentRepository.findReceivedAppointment(roomId, execDate, launchTime, AppointmentStatus.RECEIVE.getStatus(), AppointmentStatus.SIGNED.getStatus()); - Appointment getAppointment = appointmentRepository.findReceivedAppointment(roomId, execDate, appointmentBegin, appointmentEnd, AppointmentStatus.RECEIVE.getStatus(), AppointmentStatus.SIGNED.getStatus()); + // 用户有新发起待批准、已批准通过、已签到的预约(任何房间任何时间段)时不可再预约 + Appointment myAppointment = appointmentRepository.findAppointmentByLauncherWithStatus(launcher, AppointmentStatus.NEW.getStatus(), AppointmentStatus.RECEIVE.getStatus(), AppointmentStatus.SIGNED.getStatus()); + if (myAppointment != null) { + throw new AppointmentDaoException("你有正在执行的预约,请等待审批!"); + } - if (getAppointment != null) { - throw new AppointmentDaoException("该房间此时间段已被占用!"); - } else { - appointment.setStatus(AppointmentStatus.NEW.getStatus()); - Date launchDate = new Date(); - // 还应该保证预约发起时间早于要预约的时间段的起始 - Schedule schedule = scheduleRepository.getOne(appointmentBegin); - String begin = schedule.getBegin(); - Date executeDate = getExecDate(execDate,begin); - if (launchDate.before(executeDate)) { - appointment.setLaunchDate(launchDate); - appointmentRepository.save(appointment); - } else { - throw new AppointmentDaoException("该时间段已过,不可预约!"); + // 获取各时间段状态 + String dateStr = new SimpleDateFormat("yyyy-MM-dd").format(execDate); + Map>scheduleListMap = roomService.getRoomFreeTime(roomId, launcher, dateStr); + + // 检查用户新发起的预约是否与已有预约冲突 + ListbusyTime = scheduleListMap.get("busyTime"); + SetbusyTimeId = new HashSet<>(); + busyTime.forEach(schedule -> busyTimeId.add(schedule.getId())); + for(int scheduleNum = appointmentBegin; scheduleNum <= appointmentEnd; scheduleNum++) { + if(busyTimeId.contains(scheduleNum)) { + throw new AppointmentDaoException("该房间此时间段已被占用!"); } } + + // 检查用户的预约时段是否已过 + ListpassTime = scheduleListMap.get("passTime"); + SetpassTimeId = new HashSet<>(); + passTime.forEach(schedule -> passTimeId.add(schedule.getId())); + if(passTimeId.contains(appointmentBegin)) { + throw new AppointmentDaoException("该时间段已过,不可预约!"); + } + + // 检查通过则执行预约 + appointment.setLaunchDate(new Date()); + appointment.setStatus(AppointmentStatus.NEW.getStatus()); + appointmentRepository.save(appointment); } @Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class) @@ -139,38 +144,52 @@ public List addNewAppointmentsByAdmin(List appointment throw new AppointmentDaoException("管理员预约的格式有误,审核者不为管理员!"); } - // 查找发生冲突的管理员预约管理员 + // 获取管理员预约请求中包含的字段 Integer roomId = appointment.getRoomId(); + String conductor = appointment.getConductor(); Integer appointmentBegin = appointment.getBegin(); Integer appointmentEnd = appointment.getEnd(); Date execDate = appointment.getExecDate(); - List conflictingAppointments = appointmentRepository.findConflictingAppointmentsAppointedByAdmin(roomId, execDate, appointmentBegin, appointmentEnd, AppointmentStatus.RECEIVE.getStatus(), AppointmentStatus.SIGNED.getStatus()); - if (conflictingAppointments != null && conflictingAppointments.size() > 0) { - throw new AppointmentDaoException("该房间此时间段已被其他管理员的预约占用!"); - } else { - // 预约时间检查 - // 保证预约发起时间早于要预约的时间段的起始 - Date launchDate = new Date(); - Schedule schedule = scheduleRepository.getOne(appointmentBegin); - String begin = schedule.getBegin(); - Date executeDate = getExecDate(execDate,begin); - if (launchDate.after(executeDate)) { - throw new AppointmentDaoException("该时间段已过,不可预约!"); - } else { - appointment.setLaunchDate(launchDate); + + // 获取各时间段状态 + String dateStr = new SimpleDateFormat("yyyy-MM-dd").format(execDate); + Map> scheduleListMap = roomService.getRoomFreeTimeByAdmin(roomId, conductor, dateStr); + + Map scheduleIdMap = new HashMap<>(); // + // 占用状态包括所有管理员(包括当前管理员)的预约 + scheduleListMap.get("busyTime").forEach(schedule -> scheduleIdMap.put(schedule.getId(), true)); + scheduleListMap.get("myTime").forEach(schedule -> scheduleIdMap.put(schedule.getId(), true)); + scheduleListMap.get("passTime").forEach(schedule -> scheduleIdMap.put(schedule.getId(), false)); + + boolean scheduleOccupied = false; + boolean scheduleAvailable = true; + for(int scheduleIdNum = appointmentBegin; scheduleIdNum <= appointmentEnd; scheduleIdNum++) { + if(scheduleIdMap.get(scheduleIdNum) != null) { + scheduleOccupied = scheduleIdMap.get(scheduleIdNum); + scheduleAvailable = scheduleIdMap.get(scheduleIdNum); + break; } } + + if(scheduleOccupied) { + throw new AppointmentDaoException("预约时间段已被管理员占用!"); + } + + if(!scheduleAvailable) { + throw new AppointmentDaoException("已过时间段不可预约!"); + } } List result = new ArrayList<>(); + // 执行管理员预约 for (Appointment appointment : appointments) { + + appointment.setLaunchDate(new Date()); appointment.setStatus(AppointmentStatus.RECEIVE.getStatus()); - Integer roomId = appointment.getRoomId(); - Integer appointmentBegin = appointment.getBegin(); - Integer appointmentEnd = appointment.getEnd(); - Date execDate = appointment.getExecDate(); - List conflictingAppointments = appointmentRepository.findConflictingAppointmentsAppointedByUser(roomId, execDate, appointmentBegin, appointmentEnd, AppointmentStatus.NEW.getStatus(), AppointmentStatus.RECEIVE.getStatus(), AppointmentStatus.SIGNED.getStatus()); + + List conflictingAppointments = appointmentRepository.findConflictingAppointmentsAppointedByUser(appointment.getRoomId(), appointment.getExecDate(), appointment.getBegin(), appointment.getEnd(), AppointmentStatus.NEW.getStatus(), AppointmentStatus.RECEIVE.getStatus(), AppointmentStatus.SIGNED.getStatus()); if (conflictingAppointments != null && conflictingAppointments.size() > 0) { + //管理员预约覆盖冲突的用户预约 conflictingAppointments.stream().forEach(a -> { a.setStatus(AppointmentStatus.REJECT.getStatus()); notifyUserChange(a); @@ -337,16 +356,15 @@ public Page getAppointmentsBySchoolId(Pageable pageable, String sch /** * 根据预约执行的日期和当天的时间来生成预约执行的时间 * @param execDate - * @param begin 预约开始的时间,应为某一个时间段的begin或end属性 + * @param timeStr 预约的时间,应为某一个时间段的begin或end属性 * @return * @throws AppointmentDaoException */ - private Date getExecDate(Date execDate,String begin) throws AppointmentDaoException{ - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - String date = dateFormat.format(execDate); - String dateTime = date + " " + begin; + private Date getExecDate(Date execDate,String timeStr) throws AppointmentDaoException{ + String execDateStr = new SimpleDateFormat("yyyy-MM-dd").format(execDate); + String dateTimeStr = execDateStr + " " + timeStr; try { - return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(dateTime); + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateTimeStr); } catch (ParseException e) { throw new AppointmentDaoException("实际执行预约使用的时间格式有误!"); } diff --git a/service/src/main/java/cn/edu/bit/ruixin/community/service/impl/RoomServiceImpl.java b/service/src/main/java/cn/edu/bit/ruixin/community/service/impl/RoomServiceImpl.java index 85c1dfa..1c8b534 100644 --- a/service/src/main/java/cn/edu/bit/ruixin/community/service/impl/RoomServiceImpl.java +++ b/service/src/main/java/cn/edu/bit/ruixin/community/service/impl/RoomServiceImpl.java @@ -170,99 +170,68 @@ public Room updateRoomInfoById(Room room) { public Map> getRoomFreeTime(Integer roomId, String username, String date) { Date nowDate = new Date(); - - SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + Date execDate = getExecDate(date); List allTime = scheduleRepository.findAll(); - List pastTime = new ArrayList<>(); - - List busyTime = new ArrayList<>(); - - List freeTime = new ArrayList<>(); - - List myTime = new ArrayList<>(); + List pastTime; + List busyTime; + List freeTime; + List myTime; - int i = 0; + Set passTimeId = new HashSet<>(); + SetbusyTimeId = new HashSet<>(); + SetmyTimeId = new HashSet<>(); - for (i = 0; i < allTime.size(); i++) { - String dateTime = date + " " + allTime.get(i).getBegin(); - Date execDateTime = null; - try { - execDateTime = dateTimeFormat.parse(dateTime); - } catch (ParseException e) { - throw new GlobalParamException("日期格式有误!"); - } - if (execDateTime.before(nowDate)) { - pastTime.add(allTime.get(i)); - } else { - break; - } - } + // 获取所有已过时间段 + pastTime = allTime.stream() + .filter(schedule -> getExecDateTime(date, schedule.getEnd()).before(nowDate)) + .collect(Collectors.toList()); - Date execDate = null; - try { - execDate = dateFormat.parse(date); - } catch (ParseException e) { - throw new GlobalParamException("日期格式有误!"); - } + pastTime.forEach(schedule -> passTimeId.add(schedule.getId())); + // 某房间某日期的预约记录(预约状态:已预约未签到、已签到未签退) List appointments = appointmentRepository.findLaunchTimeByRoomIdAndExecuteDateAndStatus(roomId, execDate, AppointmentStatus.RECEIVE.getStatus(), AppointmentStatus.SIGNED.getStatus()); - // 获取所有占用时间段 - List busyTimeId = new ArrayList<>(); - if (appointments != null) { - for (Appointment appointment : - appointments) { - for (int j = appointment.getBegin(); j <= appointment.getEnd(); j++) { - busyTimeId.add(j); + appointments.forEach(appointment -> { + int scheduleNum; + if(username.equals(appointment.getLauncher())) { + for(scheduleNum = appointment.getBegin(); scheduleNum <= appointment.getEnd(); scheduleNum++) { + myTimeId.add(scheduleNum); + } + } else { // 管理员预约(发起者为空)或其他用户预约(username与launcher不一致) + for(scheduleNum = appointment.getBegin(); scheduleNum <= appointment.getEnd(); scheduleNum++) { + busyTimeId.add(scheduleNum); } } - Collections.sort(busyTimeId); - } - - for (int k = 0; k < busyTimeId.size() && i < allTime.size(); ) { - if (busyTimeId.get(k) == allTime.get(i).getId()) { - busyTime.add(allTime.get(i)); - k++; - i++; - } else if (busyTimeId.get(k) < allTime.get(i).getId()) { - k++; - } else { - i++; - } - } - + }); - Appointment appointment = appointmentRepository.findLaunchTimeByRoomIdAndLauncherAndExecuteDateAndStatus(roomId, username, execDate, AppointmentStatus.NEW.getStatus()); - ArrayList myTimeId = new ArrayList<>(); + // 获取被他人占用的时间段(不包含已过时间段) + busyTime = allTime.stream() + .filter(schedule -> busyTimeId.contains(schedule.getId()) + && !passTimeId.contains(schedule.getId())) + .collect(Collectors.toList()); - if (appointment != null) { - for (int j = appointment.getBegin(); j <= appointment.getEnd(); j++) { - myTimeId.add(j); + // 当前用户发起的未审批的预约 + Appointment myNewAppointment = appointmentRepository.findLaunchTimeByRoomIdAndLauncherAndExecuteDateAndStatus(roomId, username, execDate, AppointmentStatus.NEW.getStatus()); + if(myNewAppointment != null) { + for(int scheduleIdNum = myNewAppointment.getBegin(); scheduleIdNum <= myNewAppointment.getEnd(); scheduleIdNum++) { + myTimeId.add(scheduleIdNum); } - for (Integer id : - myTimeId) { - for (Schedule schedule : - allTime) { - if (schedule.getId() == id) { - myTime.add(schedule); - } - } - } - - // 需保证同一时间段被审批后,其余所有申请都驳回 - myTime = myTime.stream() - .filter(schedule -> (!pastTime.contains(schedule) && !busyTime.contains(schedule))) - .collect(Collectors.toList()); } - List finalMyTime = myTime; - freeTime = allTime.stream() - .filter(schedule -> (!pastTime.contains(schedule) && !busyTime.contains(schedule) && !finalMyTime.contains(schedule))) + // 当前用户预约的时间段(状态:未审批、已预约未签到、已签到,且不包含已过时间段) + myTime = allTime.stream() + .filter(schedule -> myTimeId.contains(schedule.getId()) + && !passTimeId.contains(schedule.getId()) + && !busyTimeId.contains(schedule.getId())) .collect(Collectors.toList()); + freeTime = allTime.stream() + .filter(schedule -> !myTimeId.contains(schedule.getId()) + && !passTimeId.contains(schedule.getId()) + && !busyTimeId.contains(schedule.getId())) + .collect(Collectors.toList()); Map> map = new HashMap<>(); map.put("passTime", pastTime); @@ -276,66 +245,55 @@ public Map> getRoomFreeTime(Integer roomId, String userna @Override @Transactional(readOnly = true) public Map> getRoomFreeTimeByAdmin(Integer roomId, String conductor, String date) { - Date nowDate = new Date(); - SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + Date execDate = getExecDate(date); + Date nowDate = new Date(); List allTime = scheduleRepository.findAll(); + List passTime; + List busyTime; + List freeTime; + List myTime; + // <时段,是否被预约> 标记被占用的时段 Map scheduleMap = new HashMap<>(); - // 已过时间段 - List passTime = allTime.stream() + // 获取已过时间段列表 + passTime = allTime.stream() .filter(schedule -> { - String dateTime = date + " " + schedule.getBegin(); - Date execDateTime = null; - try { - execDateTime = dateTimeFormat.parse(dateTime); - } catch (ParseException e) { - throw new GlobalParamException("日期格式有误!"); - } + Date execDateTime = getExecDateTime(date, schedule.getEnd()); return execDateTime.before(nowDate); }).collect(Collectors.toList()); - passTime.forEach(schedule -> scheduleMap.put(schedule.getId(), false)); - - Date execDate = null; - try { - execDate = dateFormat.parse(date); - } catch (ParseException e) { - throw new GlobalParamException("日期格式有误!"); - } + passTime.forEach(schedule -> scheduleMap.put(schedule.getId(), false)); + // 其他管理员的预约(不包括当前管理员) List conflictingAppointments = appointmentRepository.findConflictingAppointmentsAppointedByAdminThroughConductor(roomId, conductor, execDate, AppointmentStatus.RECEIVE.getStatus(), AppointmentStatus.SIGNED.getStatus()); + conflictingAppointments.forEach(appointment -> { - scheduleMap.putIfAbsent(appointment.getBegin(), true); - scheduleMap.putIfAbsent(appointment.getEnd(), true); + for(int i = appointment.getBegin(); i <= appointment.getEnd(); i++) { + scheduleMap.putIfAbsent(i, true); // 排除已过时间段 + } }); - // 被其他管理员占用的时间段 - List busyTime = allTime.stream() + busyTime = allTime.stream() .filter(schedule -> scheduleMap.get(schedule.getId()) != null && scheduleMap.get(schedule.getId())) .collect(Collectors.toList()); - passTime.forEach(schedule -> scheduleMap.put(schedule.getId(), true)); + // 管理员自己占用的时间段(不包含已过时间段) + passTime.forEach(schedule -> scheduleMap.put(schedule.getId(), true)); List adminAppointments = appointmentRepository.findAppointmentAppointedByAdminThroughAdminAndRoomIdAndExecDate(conductor, roomId, execDate, AppointmentStatus.RECEIVE.getStatus(), AppointmentStatus.SIGNED.getStatus()); adminAppointments.forEach(appointment -> { - scheduleMap.put(appointment.getBegin(), false); - scheduleMap.put(appointment.getEnd(), false); + for(int i = appointment.getBegin(); i <= appointment.getEnd(); i++) { + scheduleMap.putIfAbsent(i, false); // 排除已过时间段 + } }); - - // 管理员自己占用的时间段 - List myTime = allTime.stream() + myTime = allTime.stream() .filter(schedule -> scheduleMap.get(schedule.getId()) != null && !scheduleMap.get(schedule.getId())) .collect(Collectors.toList()); - adminAppointments.forEach(appointment -> { - scheduleMap.put(appointment.getBegin(), true); - scheduleMap.put(appointment.getEnd(), true); - }); // 可用时间段 - List freeTime = allTime.stream() + freeTime = allTime.stream() .filter(schedule -> scheduleMap.get(schedule.getId()) == null) .collect(Collectors.toList()); @@ -346,4 +304,34 @@ public Map> getRoomFreeTimeByAdmin(Integer roomId, String map.put("freeTime", freeTime); return map; } -} \ No newline at end of file + + /** + * 将指定格式的日期字符串转换为Date对象 + * @param dateStr + * @return + * @throws GlobalParamException + */ + private Date getExecDate(String dateStr) throws GlobalParamException { + try { + return new SimpleDateFormat("yyyy-MM-dd").parse(dateStr); + } catch (ParseException e) { + throw new GlobalParamException("日期格式有误!"); + } + } + + /** + * 根据日期和时间字符串生成Date对象 + * @param dateStr + * @param timeStr + * @return + * @throws GlobalParamException + */ + private Date getExecDateTime(String dateStr, String timeStr) throws GlobalParamException { + String dateTimeStr = dateStr + " " + timeStr; + try { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateTimeStr); + } catch (ParseException e) { + throw new GlobalParamException("时间格式有误!"); + } + } +}