| | |
| | | import com.tourguide.common.exception.BusinessException; |
| | | import com.tourguide.modules.system.dto.GuideNotificationResponse; |
| | | import com.tourguide.modules.system.entity.GuideNoticeRead; |
| | | import com.tourguide.modules.system.entity.GuideNotification; |
| | | import com.tourguide.modules.system.entity.SystemNotice; |
| | | import com.tourguide.modules.system.mapper.GuideNotificationMapper; |
| | | import com.tourguide.modules.system.mapper.GuideNoticeReadMapper; |
| | | import com.tourguide.modules.system.mapper.SystemNoticeMapper; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.Collections; |
| | | import java.util.Comparator; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | |
| | | public class GuideNotificationService { |
| | | private final SystemNoticeMapper noticeMapper; |
| | | private final GuideNoticeReadMapper readMapper; |
| | | private final GuideNotificationMapper guideNotificationMapper; |
| | | |
| | | public GuideNotificationService(SystemNoticeMapper noticeMapper, GuideNoticeReadMapper readMapper) { |
| | | public GuideNotificationService(SystemNoticeMapper noticeMapper, GuideNoticeReadMapper readMapper, |
| | | GuideNotificationMapper guideNotificationMapper) { |
| | | this.noticeMapper = noticeMapper; |
| | | this.readMapper = readMapper; |
| | | this.guideNotificationMapper = guideNotificationMapper; |
| | | } |
| | | |
| | | public long unreadCount(Long guideId) { |
| | | List<SystemNotice> notices = publishedNotices(); |
| | | if (notices.isEmpty()) return 0L; |
| | | Set<Long> readIds = readNoticeIds(guideId, notices); |
| | | return notices.stream().filter(notice -> !readIds.contains(notice.getId())).count(); |
| | | long systemUnread = notices.stream().filter(notice -> !readIds.contains(notice.getId())).count(); |
| | | Long personalUnread = guideNotificationMapper.selectCount(new LambdaQueryWrapper<GuideNotification>() |
| | | .eq(GuideNotification::getGuideId, guideId) |
| | | .isNull(GuideNotification::getReadAt)); |
| | | return systemUnread + personalUnread; |
| | | } |
| | | |
| | | public List<GuideNotificationResponse> list(Long guideId) { |
| | | List<SystemNotice> notices = publishedNotices(); |
| | | Set<Long> readIds = readNoticeIds(guideId, notices); |
| | | return notices.stream() |
| | | List<GuideNotificationResponse> responses = notices.stream() |
| | | .map(notice -> new GuideNotificationResponse(notice, readIds.contains(notice.getId()))) |
| | | .collect(Collectors.toList()); |
| | | responses.addAll(guideNotificationMapper.selectList(new LambdaQueryWrapper<GuideNotification>() |
| | | .eq(GuideNotification::getGuideId, guideId) |
| | | .orderByDesc(GuideNotification::getCreatedAt)) |
| | | .stream().map(GuideNotificationResponse::new).collect(Collectors.toList())); |
| | | responses.sort(Comparator.comparing(GuideNotificationResponse::getTime, |
| | | Comparator.nullsLast(Comparator.reverseOrder()))); |
| | | return responses; |
| | | } |
| | | |
| | | public void markRead(Long guideId, Long noticeId) { |
| | | public void markRead(Long guideId, String notificationId) { |
| | | if (notificationId != null && notificationId.startsWith("guide:")) { |
| | | markPersonalRead(guideId, parseId(notificationId, "guide:")); |
| | | return; |
| | | } |
| | | Long noticeId = parseId(notificationId, "system:"); |
| | | SystemNotice notice = noticeMapper.selectOne(new LambdaQueryWrapper<SystemNotice>() |
| | | .eq(SystemNotice::getId, noticeId) |
| | | .eq(SystemNotice::getStatus, 1) |
| | |
| | | readMapper.insert(read); |
| | | } |
| | | |
| | | public void notifyOrderAssigned(com.tourguide.modules.order.entity.TourOrder order) { |
| | | if (order == null || order.getGuideId() == null) return; |
| | | create(order.getGuideId(), "ORDER_ASSIGNED", "接单提醒", "您有一个新的讲解订单,请查看", |
| | | order.getId(), "/pages/order-detail/index?id=" + order.getId()); |
| | | } |
| | | |
| | | public void notifyOrderCancelled(com.tourguide.modules.order.entity.TourOrder order) { |
| | | if (order == null || order.getGuideId() == null) return; |
| | | create(order.getGuideId(), "ORDER_CANCELLED", "取消提醒", "您有一个被取消的讲解订单,请查看", |
| | | order.getId(), "/pages/order-detail/index?id=" + order.getId()); |
| | | } |
| | | |
| | | public void notifyAuditResult(Long guideId, boolean approved) { |
| | | create(guideId, approved ? "AUDIT_APPROVED" : "AUDIT_REJECTED", "【名导精讲】", |
| | | approved ? "您的资料审核已通过,请前往应用查看。" : "您的资料审核未通过,请前往应用更新提交。", |
| | | null, null); |
| | | } |
| | | |
| | | private void create(Long guideId, String type, String title, String content, Long orderId, String targetUrl) { |
| | | if (guideId == null) return; |
| | | GuideNotification notification = new GuideNotification(); |
| | | notification.setGuideId(guideId); |
| | | notification.setNotificationType(type); |
| | | notification.setTitle(title); |
| | | notification.setContent(content); |
| | | notification.setOrderId(orderId); |
| | | notification.setTargetUrl(targetUrl); |
| | | notification.setCreatedAt(LocalDateTime.now()); |
| | | guideNotificationMapper.insert(notification); |
| | | } |
| | | |
| | | private void markPersonalRead(Long guideId, Long notificationId) { |
| | | GuideNotification notification = guideNotificationMapper.selectOne(new LambdaQueryWrapper<GuideNotification>() |
| | | .eq(GuideNotification::getId, notificationId) |
| | | .eq(GuideNotification::getGuideId, guideId) |
| | | .last("LIMIT 1")); |
| | | if (notification == null) throw new BusinessException(404, "Notification not found"); |
| | | if (notification.getReadAt() != null) return; |
| | | notification.setReadAt(LocalDateTime.now()); |
| | | guideNotificationMapper.updateById(notification); |
| | | } |
| | | |
| | | private Long parseId(String value, String prefix) { |
| | | String raw = value == null ? "" : value; |
| | | if (raw.startsWith(prefix)) raw = raw.substring(prefix.length()); |
| | | try { |
| | | return Long.valueOf(raw); |
| | | } catch (NumberFormatException exception) { |
| | | throw new BusinessException(400, "Notification id is invalid"); |
| | | } |
| | | } |
| | | |
| | | private List<SystemNotice> publishedNotices() { |
| | | return noticeMapper.selectList(new LambdaQueryWrapper<SystemNotice>() |
| | | .eq(SystemNotice::getStatus, 1) |