package com.ruoyi.collaborativeApproval.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.github.xiaoymin.knife4j.core.util.StrUtil; import com.ruoyi.approve.pojo.ApproveProcess; import com.ruoyi.collaborativeApproval.dto.MeetSummaryDto; import com.ruoyi.collaborativeApproval.dto.MeetUseDto; import com.ruoyi.collaborativeApproval.dto.MeetingItem; import com.ruoyi.collaborativeApproval.dto.MeetingSimpleDto; import com.ruoyi.collaborativeApproval.mapper.MeetApplicationMapper; import com.ruoyi.collaborativeApproval.mapper.MeetDraftMapper; import com.ruoyi.collaborativeApproval.mapper.MeetingMinutesMapper; import com.ruoyi.collaborativeApproval.mapper.MeetingRoomMapper; import com.ruoyi.collaborativeApproval.pojo.MeetApplication; import com.ruoyi.collaborativeApproval.pojo.MeetDraft; import com.ruoyi.collaborativeApproval.pojo.MeetingMinutes; import com.ruoyi.collaborativeApproval.pojo.MeetingRoom; import com.ruoyi.collaborativeApproval.service.MeetingService; import com.ruoyi.collaborativeApproval.vo.SearchMeetingApplicationVo; import com.ruoyi.collaborativeApproval.vo.SearchMeetingDraftVo; import com.ruoyi.collaborativeApproval.vo.SearchMeetingRoomVo; import com.ruoyi.collaborativeApproval.vo.SearchMeetingUseVo; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.framework.web.domain.R; import com.ruoyi.project.system.domain.SysPost; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysPostMapper; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.project.system.service.ISysNoticeService; import com.ruoyi.staff.mapper.StaffOnJobMapper; import com.ruoyi.staff.pojo.StaffOnJob; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class MeetingServiceImpl extends ServiceImpl implements MeetingService { private final MeetingRoomMapper meetingRoomMapper; private final MeetDraftMapper meetDraftMapper; private final MeetApplicationMapper meetApplicationMapper; private final StaffOnJobMapper staffOnJobMapper; private final MeetingMinutesMapper meetingMinutesMapper; private final SysUserMapper userMapper; private final SysPostMapper sysPostMapper; private final ISysNoticeService sysNoticeService; @Override public IPage getMeetingRoomList(SearchMeetingRoomVo vo) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); if (StrUtil.isNotBlank(vo.getName())) { queryWrapper.like(MeetingRoom::getName, vo.getName()); } if (StrUtil.isNotBlank(vo.getLocation())) { queryWrapper.like(MeetingRoom::getLocation, vo.getLocation()); } queryWrapper.orderByDesc(MeetingRoom::getId); return meetingRoomMapper.selectPage(new Page(vo.getCurrent(), vo.getSize()), queryWrapper); } @Override public void saveMeetRoom(MeetingRoom meetingRoom) { if (meetingRoom.getId() != null) { meetingRoomMapper.updateById(meetingRoom); } else { meetingRoomMapper.insert(meetingRoom); } } @Override public MeetingRoom findMeetRoomById(Long id) { return meetingRoomMapper.selectById(id); } @Override @Transactional(rollbackFor = Exception.class) public void deleteMeetingRoom(Long id) { if (id == null){ throw new ServiceException("删除会议室失败,会议室ID不能为空"); } LocalDateTime now = LocalDateTime.now(); List meetApplicationList = meetApplicationMapper.selectList(Wrappers.lambdaQuery() .eq(MeetApplication::getRoomId, id) .gt(MeetApplication::getEndTime, now) .in(MeetApplication::getStatus, Arrays.asList(0, 1))); if (!meetApplicationList.isEmpty()){ throw new ServiceException("删除会议室失败,该会议室尚有未开始或进行中的有效会议预约"); } meetingRoomMapper.deleteById(id); } @Override public List getRoomEnum() { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.select(MeetingRoom::getName, MeetingRoom::getId, MeetingRoom::getLocation); queryWrapper.eq(MeetingRoom::getStatus, 1); queryWrapper.orderByDesc(MeetingRoom::getId); return meetingRoomMapper.selectList(queryWrapper); } @Override public IPage getMeetingDraftList(SearchMeetingDraftVo vo) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); if (StrUtil.isNotBlank(vo.getTitle())) { queryWrapper.like(MeetDraft::getTitle, vo.getTitle()); } if (Objects.nonNull(vo.getMeetingDate())) { queryWrapper.eq(MeetDraft::getMeetingDate, vo.getMeetingDate()); } queryWrapper.orderByDesc(MeetDraft::getId); return meetDraftMapper.selectPage(new Page<>(vo.getCurrent(), vo.getSize()), queryWrapper); } @Override public void saveMeetDraft(MeetDraft meetDraft) { if (meetDraft.getId() != null) { meetDraftMapper.updateById(meetDraft); } else { meetDraftMapper.insert(meetDraft); } } @Override public void deleteMeetingDraft(Long id) { meetDraftMapper.deleteById(id); } @Override public R saveMeetApplication(MeetApplication meetApplication) { meetApplication.setApplicant(SecurityUtils.getUsername()); // 时间冲突校验 LambdaQueryWrapper meetApplicationLambdaQueryWrapper = Wrappers.lambdaQuery() .eq(MeetApplication::getRoomId, meetApplication.getRoomId()) // 如果id不为null则排除自己 .ne(meetApplication.getId() != null, MeetApplication::getId, meetApplication.getId()) // 时间冲突判断 .lt(MeetApplication::getStartTime, meetApplication.getEndTime()) .gt(MeetApplication::getEndTime, meetApplication.getStartTime()); Long count = meetApplicationMapper.selectCount(meetApplicationLambdaQueryWrapper); if (count > 0) { return R.fail("所选会议室在该时间段已有其他会议,请调整时间或更换会议室"); } if (meetApplication.getId() != null) { // 更新 meetApplicationMapper.updateById(meetApplication); } else { // 新增 meetApplicationMapper.insert(meetApplication); } /*会议发布的消息通知*/ //参会人员id(人员台账和用户表通过人员编号和用户名称(登录账号)做匹配) if (Integer.valueOf(1).equals(meetApplication.getPublishStatus())) { MeetApplication application = meetApplicationMapper.selectById(meetApplication.getId()); String cleanStr = application.getParticipants() .replaceAll("^\\[|\\]$", "") .trim(); List userIds = Arrays.stream(cleanStr.split(",")) .map(String::trim) .filter(s -> !s.isEmpty()) .map(Long::valueOf) .map(staffId -> { StaffOnJob record = staffOnJobMapper.selectById(staffId); if (record == null) { return null; } return userMapper.selectOne( Wrappers.lambdaQuery() .eq(SysUser::getUserName, record.getStaffNo()) ); }) .filter(Objects::nonNull) .map(SysUser::getUserId) .collect(Collectors.toList()); if (!userIds.isEmpty()) { sysNoticeService.simpleNoticeByUser( "会议通知", "会议主题:" + application.getTitle() + "\t" + "会议时间:" + application.getStartTime() + "-" + application.getEndTime() + "\t" + "发起人:" + application.getApplicant(), userIds, "" ); } } return R.ok(); } @Override public IPage getMeetingApplicationList(SearchMeetingApplicationVo vo) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(MeetApplication::getApplicationType, "approval", "department"); if (StrUtil.isNotBlank(vo.getTitle())) { queryWrapper.like(MeetApplication::getTitle, vo.getTitle()); } if (StrUtil.isNotBlank(vo.getApplicant())) { queryWrapper.like(MeetApplication::getApplicant, vo.getApplicant()); } if (StrUtil.isNotBlank(vo.getStatus())) { queryWrapper.eq(MeetApplication::getStatus, vo.getStatus()); } queryWrapper.orderByDesc(MeetApplication::getId); return meetApplicationMapper.selectPage(new Page<>(vo.getCurrent(), vo.getSize()), queryWrapper); } @Override public List meetingUseList(SearchMeetingUseVo vo) { // 查询会议列表 LambdaQueryWrapper alWrapper = new LambdaQueryWrapper<>(); alWrapper.and(wrapper -> { wrapper.eq(MeetApplication::getStatus, 1) .or() .eq(MeetApplication::getApplicationType, "notification"); }); if (Objects.nonNull(vo.getDate())) { alWrapper.and(wrapper -> { wrapper.eq(MeetApplication::getMeetingDate, vo.getDate()); }); } alWrapper.orderByAsc(MeetApplication::getStartTime); List meetApplicationList = meetApplicationMapper.selectList(alWrapper); // 根据 roomId 进行分组 Map> roomGroup = meetApplicationList.stream().collect(Collectors.groupingBy(MeetApplication::getRoomId)); // 查询room信息 List roomList = meetingRoomMapper.selectList(new LambdaUpdateWrapper().orderByAsc(MeetingRoom::getId)); List meetUseDtoList = new ArrayList<>(); roomList.forEach(r -> { MeetUseDto dto = new MeetUseDto(); MeetingRoom meetingRoom = roomList.stream().filter(room -> room.getId().equals(r.getId())).findFirst().orElse(new MeetingRoom()); dto.setId(meetingRoom.getId()); dto.setName(meetingRoom.getName()); List collect = roomGroup.getOrDefault(r.getId(), new ArrayList<>()).stream().map(it -> { MeetingItem item = new MeetingItem(); item.setId(it.getId()); item.setHost(it.getHost()); item.setStatus(1); item.setTitle(it.getTitle()); item.setStartTime(it.getStartTime().format(DateTimeFormatter.ofPattern("HH:mm"))); item.setEndTime(it.getEndTime().format(DateTimeFormatter.ofPattern("HH:mm"))); item.setTime(item.getStartTime() + "~" + item.getEndTime()); item.setParticipants(it.getParticipants().split(",").length); item.setDescription(it.getDescription()); item.setRoom(meetingRoom.getName() + "(" + meetingRoom.getLocation() + ")"); return item; }).collect(Collectors.toList()); dto.setMeetings(collect); meetUseDtoList.add(dto); }); return meetUseDtoList; } @Override public IPage getMeetingPublishList(SearchMeetingApplicationVo vo) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); if (StrUtil.isNotBlank(vo.getTitle())) { queryWrapper.like(MeetApplication::getTitle, vo.getTitle()); } if (StrUtil.isNotBlank(vo.getApplicant())) { queryWrapper.like(MeetApplication::getApplicant, vo.getApplicant()); } if (StrUtil.isNotBlank(vo.getStatus())) { queryWrapper.eq(MeetApplication::getPublishStatus, vo.getStatus()); } queryWrapper.and(wrapper -> { wrapper.eq(MeetApplication::getStatus, 1) .or() .eq(MeetApplication::getApplicationType, "notification"); }); queryWrapper.orderByDesc(MeetApplication::getId); return meetApplicationMapper.selectPage(new Page<>(vo.getCurrent(), vo.getSize()), queryWrapper); } @Override public MeetingMinutes getMeetingMinutesById(Long id) { return meetingMinutesMapper.selectOne(new LambdaUpdateWrapper().eq(MeetingMinutes::getMeetingId,id)); } @Override public void saveMeetingMinutes(MeetingMinutes meetingMinutes) { if (meetingMinutes.getId() != null){ meetingMinutesMapper.updateById(meetingMinutes); }else { meetingMinutesMapper.insert(meetingMinutes); } } @Override public MeetSummaryDto getMeetSummary() { return meetApplicationMapper.getMeetSummary(); } @Override public List getMeetSummaryItems() { return meetApplicationMapper.getMeetSummaryItems(); } @Override public List getUpcomingMeetingReminders() { List reminders = new ArrayList<>(); LocalDateTime now = LocalDateTime.now(); List meetings = meetApplicationMapper.selectList( Wrappers.lambdaQuery() .eq(MeetApplication::getPublishStatus, 1) .gt(MeetApplication::getStartTime, now) .le(MeetApplication::getStartTime, now.plusHours(1)) .orderByAsc(MeetApplication::getStartTime)); if (meetings == null || meetings.isEmpty()) { return reminders; } Long currentUserId = SecurityUtils.getLoginUser().getUserId(); Map postCache = new HashMap<>(); for (MeetApplication meeting : meetings) { if (meeting.getStartTime() == null) { continue; } List staffIds = parseParticipantStaffIds(meeting.getParticipants()); if (staffIds.isEmpty()) { continue; } List staffs = staffOnJobMapper.selectBatchIds(staffIds); Map staffMap = (staffs == null) ? new HashMap<>() : staffs.stream().collect(Collectors.toMap(StaffOnJob::getId, s -> s, (a, b) -> a)); boolean isParticipant = false; List participantNames = new ArrayList<>(); for (Long staffId : staffIds) { StaffOnJob staff = staffMap.get(staffId); if (staff == null) { continue; } String display = staff.getStaffName() == null ? "" : staff.getStaffName(); if (staff.getSysPostId() != null) { SysPost post = postCache.get(staff.getSysPostId()); if (post == null) { post = sysPostMapper.selectPostById(staff.getSysPostId().longValue()); if (post != null) { postCache.put(staff.getSysPostId(), post); } } if (post != null && post.getPostName() != null && !post.getPostName().isEmpty()) { display = display + " (" + post.getPostName() + ")"; } } if (!display.isEmpty()) { participantNames.add(display); } if (!isParticipant && staff.getStaffNo() != null) { SysUser user = userMapper.selectOne( Wrappers.lambdaQuery().eq(SysUser::getUserName, staff.getStaffNo())); if (user != null && currentUserId.equals(user.getUserId())) { isParticipant = true; } } } if (!isParticipant) { continue; } String roomName = "会议"; if (meeting.getRoomId() != null) { MeetingRoom room = meetingRoomMapper.selectById(meeting.getRoomId()); if (room != null && room.getName() != null && !room.getName().isEmpty()) { roomName = room.getName(); } } ApproveProcess ap = new ApproveProcess(); ap.setId(100000000L + meeting.getId()); ap.setApproveId("会议提醒"); ap.setApproveDeptName(roomName); String reason = "会议《" + meeting.getTitle() + "》将于 " + meeting.getStartTime().format(DateTimeFormatter.ofPattern("HH:mm")) + " 开始"; if (!participantNames.isEmpty()) { reason += ";参会人员:" + String.join("、", participantNames); } ap.setApproveReason(reason); ap.setApproveUserName(meeting.getApplicant()); ap.setApproveTime(java.sql.Timestamp.valueOf(meeting.getStartTime())); ap.setApproveTypeName("会议提醒"); reminders.add(ap); } return reminders; } private List parseParticipantStaffIds(String participants) { List ids = new ArrayList<>(); if (participants == null || participants.trim().isEmpty()) { return ids; } String cleanStr = participants.replaceAll("^\\[|\\]$", "").trim(); if (cleanStr.isEmpty()) { return ids; } for (String s : cleanStr.split(",")) { String val = s.trim(); if (val.isEmpty()) { continue; } try { ids.add(Long.valueOf(val)); } catch (NumberFormatException ignored) { } } return ids; } }