diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/back/NotificationsController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/back/NotificationsController.java new file mode 100644 index 0000000..2427e1d --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/back/NotificationsController.java @@ -0,0 +1,122 @@ +package com.ruoyi.web.controller.back; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.entity.Notifications; +import com.ruoyi.common.core.domain.entity.ShopUser; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.system.service.INotificationRecordsService; +import com.ruoyi.system.service.INotificationsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 【请填写功能名称】Controller + * + * @author ruoyi + * @date 2025-08-23 + */ +@RestController +@RequestMapping("/back/notifications") +public class NotificationsController extends BaseController +{ + @Autowired + private INotificationsService notificationsService; + @Autowired + private INotificationRecordsService recordsService; + + /** + * 查询【请填写功能名称】列表 + */ + @PreAuthorize("@ss.hasPermi('system:notifications:list')") + @GetMapping("/list") + public TableDataInfo list(Notifications notifications) + { + startPage(); + List list = notificationsService.selectNotificationsList(notifications); + return getDataTable(list); + } + + /** + * 导出【请填写功能名称】列表 + */ + @PreAuthorize("@ss.hasPermi('system:notifications:export')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, Notifications notifications) + { + List list = notificationsService.selectNotificationsList(notifications); + ExcelUtil util = new ExcelUtil(Notifications.class); + util.exportExcel(response, list, "【请填写功能名称】数据"); + } + + /** + * 绑定用户到通知 + */ + @Log(title = "绑定通知用户", businessType = BusinessType.OTHER) + @PostMapping("/bind") + public AjaxResult bind(@RequestParam Long id, @RequestBody List shopUsers){ + recordsService.bind(id, shopUsers); + return AjaxResult.success("绑定用户成功"); + } + + /** + * 获取通知已绑定的用户列表 + */ + @GetMapping("/bindUsers/{id}") + public AjaxResult getBindUsers(@PathVariable("id") Long id) { + List list = recordsService.getBindUsers(id); + return AjaxResult.success(list); + } + + /** + * 发布通知 + */ + @Log(title = "发布通知", businessType = BusinessType.OTHER) + @PostMapping("/publish/{id}") + public AjaxResult publish(@PathVariable("id") Long id) { + return notificationsService.publishNotification(id); + } + + /** + * 新增【请填写功能名称】 + */ + @PreAuthorize("@ss.hasPermi('system:notifications:add')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody Notifications notifications) + { + return toAjax(notificationsService.insertNotifications(notifications)); + } + + /** + * 修改【请填写功能名称】 + */ + @PreAuthorize("@ss.hasPermi('system:notifications:edit')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody Notifications notifications) + { + return toAjax(notificationsService.updateNotifications(notifications)); + } + + /** + * 删除【请填写功能名称】 + */ + @PreAuthorize("@ss.hasPermi('system:notifications:remove')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(notificationsService.deleteNotificationsByIds(ids)); + } + + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/NotificationRecords.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/NotificationRecords.java new file mode 100644 index 0000000..0d8cc64 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/NotificationRecords.java @@ -0,0 +1,148 @@ +package com.ruoyi.common.core.domain.entity; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.BaseEntity; + +/** + * 【请填写功能名称】对象 notification_records + * + * @author ruoyi + * @date 2025-08-23 + */ +public class NotificationRecords extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** $column.columnComment */ + private Long id; + + /** 关联通知内容ID */ + @Excel(name = "关联通知内容ID") + private Long notificationId; + + /** 接收用户ID(关联您现有用户表) */ + @Excel(name = "接收用户ID", readConverterExp = "关=联您现有用户表") + private Long userId; + + /** 发送渠道 'push', 'sms', 'email', 'in-app' */ + @Excel(name = "发送渠道 'push', 'sms', 'email', 'in-app'") + private String channel; + + /** 发送状态 'pending', 'sent', 'delivered', 'read', 'failed' */ + @Excel(name = "发送状态 'pending', 'sent', 'delivered', 'read', 'failed'") + private String status; + + /** 实际发送时间 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "实际发送时间", width = 30, dateFormat = "yyyy-MM-dd") + private Date sentTime; + + /** 用户阅读时间 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "用户阅读时间", width = 30, dateFormat = "yyyy-MM-dd") + private Date readTime; + + /** 失败原因 */ + @Excel(name = "失败原因") + private String failureReason; + + public void setId(Long id) + { + this.id = id; + } + + public Long getId() + { + return id; + } + + public void setNotificationId(Long notificationId) + { + this.notificationId = notificationId; + } + + public Long getNotificationId() + { + return notificationId; + } + + public void setUserId(Long userId) + { + this.userId = userId; + } + + public Long getUserId() + { + return userId; + } + + public void setChannel(String channel) + { + this.channel = channel; + } + + public String getChannel() + { + return channel; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getStatus() + { + return status; + } + + public void setSentTime(Date sentTime) + { + this.sentTime = sentTime; + } + + public Date getSentTime() + { + return sentTime; + } + + public void setReadTime(Date readTime) + { + this.readTime = readTime; + } + + public Date getReadTime() + { + return readTime; + } + + public void setFailureReason(String failureReason) + { + this.failureReason = failureReason; + } + + public String getFailureReason() + { + return failureReason; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("notificationId", getNotificationId()) + .append("userId", getUserId()) + .append("channel", getChannel()) + .append("status", getStatus()) + .append("sentTime", getSentTime()) + .append("readTime", getReadTime()) + .append("failureReason", getFailureReason()) + .append("createTime", getCreateTime()) + .append("updateTime", getUpdateTime()) + .toString(); + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/Notifications.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/Notifications.java new file mode 100644 index 0000000..f6c82a5 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/Notifications.java @@ -0,0 +1,56 @@ +package com.ruoyi.common.core.domain.entity; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.BaseEntity; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * 【请填写功能名称】对象 notifications + * + * @author ruoyi + * @date 2025-08-23 + */ +@Data +public class Notifications extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** $column.columnComment */ + private Long id; + + /** 通知标题 */ + @Excel(name = "通知标题") + private String title; + + /** 通知内容 */ + @Excel(name = "通知内容") + private String content; + + /** 通知类型 system */ + @Excel(name = "通知类型 system") + private String notificationType; + + /** 附加数据,如跳转链接、图片URL等 预留字段 */ + @Excel(name = "附加数据,如跳转链接、图片URL等 预留字段") + private String extraData; + + /** 创建者用户ID(关联您现有用户表) */ + @Excel(name = "创建者用户ID", readConverterExp = "关=联您现有用户表") + private String creator; + + /** $column.columnComment */ + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") + private Date updatedTime; + + /** 计划发送时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "计划发送时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date sendTime; + + private List shopUsers; + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/NotificationRecordsMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/NotificationRecordsMapper.java new file mode 100644 index 0000000..548d5b2 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/NotificationRecordsMapper.java @@ -0,0 +1,70 @@ +package com.ruoyi.system.mapper; + +import com.ruoyi.common.core.domain.entity.NotificationRecords; + +import java.util.List; + +/** + * 【请填写功能名称】Mapper接口 + * + * @author ruoyi + * @date 2025-08-23 + */ +public interface NotificationRecordsMapper +{ + /** + * 查询【请填写功能名称】 + * + * @param id 【请填写功能名称】主键 + * @return 【请填写功能名称】 + */ + public NotificationRecords selectNotificationRecordsById(Long id); + + /** + * 查询【请填写功能名称】列表 + * + * @param notificationRecords 【请填写功能名称】 + * @return 【请填写功能名称】集合 + */ + public List selectNotificationRecordsList(NotificationRecords notificationRecords); + + /** + * 新增【请填写功能名称】 + * + * @param notificationRecords 【请填写功能名称】 + * @return 结果 + */ + public int insertNotificationRecords(NotificationRecords notificationRecords); + + /** + * 修改【请填写功能名称】 + * + * @param notificationRecords 【请填写功能名称】 + * @return 结果 + */ + public int updateNotificationRecords(NotificationRecords notificationRecords); + + /** + * 删除【请填写功能名称】 + * + * @param id 【请填写功能名称】主键 + * @return 结果 + */ + public int deleteNotificationRecordsById(Long id); + + /** + * 批量删除【请填写功能名称】 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteNotificationRecordsByIds(Long[] ids); + + /** + * 批量新增通知记录 + * + * @param list 通知记录列表 + * @return 结果 + */ + public int batchInsertNotificationRecords(List list); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/NotificationsMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/NotificationsMapper.java new file mode 100644 index 0000000..3d73299 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/NotificationsMapper.java @@ -0,0 +1,62 @@ +package com.ruoyi.system.mapper; + +import com.ruoyi.common.core.domain.entity.Notifications; + +import java.util.List; + +/** + * 【请填写功能名称】Mapper接口 + * + * @author ruoyi + * @date 2025-08-23 + */ +public interface NotificationsMapper +{ + /** + * 查询【请填写功能名称】 + * + * @param id 【请填写功能名称】主键 + * @return 【请填写功能名称】 + */ + public Notifications selectNotificationsById(Long id); + + /** + * 查询【请填写功能名称】列表 + * + * @param notifications 【请填写功能名称】 + * @return 【请填写功能名称】集合 + */ + public List selectNotificationsList(Notifications notifications); + + /** + * 新增【请填写功能名称】 + * + * @param notifications 【请填写功能名称】 + * @return 结果 + */ + public int insertNotifications(Notifications notifications); + + /** + * 修改【请填写功能名称】 + * + * @param notifications 【请填写功能名称】 + * @return 结果 + */ + public int updateNotifications(Notifications notifications); + + /** + * 删除【请填写功能名称】 + * + * @param id 【请填写功能名称】主键 + * @return 结果 + */ + public int deleteNotificationsById(Long id); + + /** + * 批量删除【请填写功能名称】 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteNotificationsByIds(Long[] ids); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/INotificationRecordsService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/INotificationRecordsService.java new file mode 100644 index 0000000..01c9909 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/INotificationRecordsService.java @@ -0,0 +1,80 @@ +package com.ruoyi.system.service; + +import com.ruoyi.common.core.domain.entity.NotificationRecords; +import com.ruoyi.common.core.domain.entity.Notifications; +import com.ruoyi.common.core.domain.entity.ShopUser; + +import java.util.List; + +/** + * 【请填写功能名称】Service接口 + * + * @author ruoyi + * @date 2025-08-23 + */ +public interface INotificationRecordsService +{ + /** + * 绑定用户到通知记录 + * + * @param id 通知ID + * @param shopUsers 用户列表 + */ + public void bind(Long id, List shopUsers); + + /** + * 获取通知已绑定的用户列表 + * + * @param notificationId 通知ID + * @return 用户列表 + */ + public List getBindUsers(Long notificationId); + + /** + * 查询【请填写功能名称】 + * + * @param id 【请填写功能名称】主键 + * @return 【请填写功能名称】 + */ + public NotificationRecords selectNotificationRecordsById(Long id); + + /** + * 查询【请填写功能名称】列表 + * + * @param notificationRecords 【请填写功能名称】 + * @return 【请填写功能名称】集合 + */ + public List selectNotificationRecordsList(NotificationRecords notificationRecords); + + /** + * 新增【请填写功能名称】 + * + * @param notificationRecords 【请填写功能名称】 + * @return 结果 + */ + public int insertNotificationRecords(NotificationRecords notificationRecords); + + /** + * 修改【请填写功能名称】 + * + * @param notificationRecords 【请填写功能名称】 + * @return 结果 + */ + public int updateNotificationRecords(NotificationRecords notificationRecords); + + /** + * 批量删除【请填写功能名称】 + * + * @param ids 需要删除的【请填写功能名称】主键集合 + * @return 结果 + */ + public int deleteNotificationRecordsByIds(Long[] ids); + + /** + * 删除【请填写功能名称】信息 + * + * @param id 【请填写功能名称】主键 + * @return 结果 + */ + public int deleteNotificationRecordsById(Long id); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/INotificationsService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/INotificationsService.java new file mode 100644 index 0000000..c075e63 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/INotificationsService.java @@ -0,0 +1,71 @@ +package com.ruoyi.system.service; + +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.entity.Notifications; + +import java.util.List; + +/** + * 【请填写功能名称】Service接口 + * + * @author ruoyi + * @date 2025-08-23 + */ +public interface INotificationsService +{ + /** + * 查询【请填写功能名称】 + * + * @param id 【请填写功能名称】主键 + * @return 【请填写功能名称】 + */ + public Notifications selectNotificationsById(Long id); + + /** + * 查询【请填写功能名称】列表 + * + * @param notifications 【请填写功能名称】 + * @return 【请填写功能名称】集合 + */ + public List selectNotificationsList(Notifications notifications); + + /** + * 新增【请填写功能名称】 + * + * @param notifications 【请填写功能名称】 + * @return 结果 + */ + public int insertNotifications(Notifications notifications); + + /** + * 修改【请填写功能名称】 + * + * @param notifications 【请填写功能名称】 + * @return 结果 + */ + public int updateNotifications(Notifications notifications); + + /** + * 批量删除【请填写功能名称】 + * + * @param ids 需要删除的【请填写功能名称】主键集合 + * @return 结果 + */ + public int deleteNotificationsByIds(Long[] ids); + + /** + * 删除【请填写功能名称】信息 + * + * @param id 【请填写功能名称】主键 + * @return 结果 + */ + public int deleteNotificationsById(Long id); + + /** + * 发布通知 + * + * @param id 通知ID + * @return 结果 + */ + public AjaxResult publishNotification(Long id); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotificationRecordsServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotificationRecordsServiceImpl.java new file mode 100644 index 0000000..c5479a5 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotificationRecordsServiceImpl.java @@ -0,0 +1,245 @@ +package com.ruoyi.system.service.impl; + +import com.ruoyi.common.core.domain.entity.NotificationRecords; +import com.ruoyi.common.core.domain.entity.Notifications; +import com.ruoyi.common.core.domain.entity.ShopUser; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.system.mapper.NotificationRecordsMapper; +import com.ruoyi.system.service.INotificationRecordsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 【请填写功能名称】Service业务层处理 + * + * @author ruoyi + * @date 2025-08-23 + */ +@Transactional +@Service +public class NotificationRecordsServiceImpl implements INotificationRecordsService +{ + @Autowired + private NotificationRecordsMapper notificationRecordsMapper; + + /** + * 查询【请填写功能名称】 + * + * @param id 【请填写功能名称】主键 + * @return 【请填写功能名称】 + */ + @Override + public NotificationRecords selectNotificationRecordsById(Long id) + { + return notificationRecordsMapper.selectNotificationRecordsById(id); + } + + /** + * 查询【请填写功能名称】列表 + * + * @param notificationRecords 【请填写功能名称】 + * @return 【请填写功能名称】 + */ + @Override + public List selectNotificationRecordsList(NotificationRecords notificationRecords) + { + return notificationRecordsMapper.selectNotificationRecordsList(notificationRecords); + } + + /** + * 新增【请填写功能名称】 + * + * @param notificationRecords 【请填写功能名称】 + * @return 结果 + */ + @Override + public int insertNotificationRecords(NotificationRecords notificationRecords) + { + notificationRecords.setCreateTime(DateUtils.getNowDate()); + return notificationRecordsMapper.insertNotificationRecords(notificationRecords); + } + + /** + * 修改【请填写功能名称】 + * + * @param notificationRecords 【请填写功能名称】 + * @return 结果 + */ + @Override + public int updateNotificationRecords(NotificationRecords notificationRecords) + { + notificationRecords.setUpdateTime(DateUtils.getNowDate()); + return notificationRecordsMapper.updateNotificationRecords(notificationRecords); + } + + /** + * 批量删除【请填写功能名称】 + * + * @param ids 需要删除的【请填写功能名称】主键 + * @return 结果 + */ + @Override + public int deleteNotificationRecordsByIds(Long[] ids) + { + return notificationRecordsMapper.deleteNotificationRecordsByIds(ids); + } + + /** + * 删除【请填写功能名称】信息 + * + * @param id 【请填写功能名称】主键 + * @return 结果 + */ + @Override + public int deleteNotificationRecordsById(Long id) + { + return notificationRecordsMapper.deleteNotificationRecordsById(id); + } + + /** + * 绑定用户到通知记录 + * + * @param id 通知ID + * @param shopUsers 用户列表 + */ + @Override + @Transactional + public void bind(Long id, List shopUsers) { + System.out.println("开始绑定用户,通知ID: " + id + ", 用户数量: " + (shopUsers != null ? shopUsers.size() : 0)); + + if (id == null || shopUsers == null || shopUsers.isEmpty()) { + System.out.println("通知ID为空或用户列表为空,无法绑定"); + return; + } + + // 打印用户列表信息 + System.out.println("用户列表详情:"); + for (ShopUser user : shopUsers) { + System.out.println("用户ID: " + (user != null ? user.getUserId() : "null") + + ", 类型: " + (user != null && user.getUserId() != null ? user.getUserId().getClass().getName() : "null")); + } + + // 获取当前时间 + Date now = DateUtils.getNowDate(); + + // 查询该通知已经绑定的用户ID列表 + NotificationRecords query = new NotificationRecords(); + query.setNotificationId(id); + List existingRecords = notificationRecordsMapper.selectNotificationRecordsList(query); + Set existingUserIds = existingRecords.stream() + .map(NotificationRecords::getUserId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + System.out.println("已绑定用户数量: " + existingUserIds.size()); + + // 创建通知记录列表 + List recordsList = new ArrayList<>(); + + // 遍历用户列表,为每个用户创建通知记录(排除已绑定的用户) + int validUserCount = 0; + int invalidUserCount = 0; + int duplicateUserCount = 0; + + for (ShopUser user : shopUsers) { + try { + // 验证用户ID是否有效 + if (user == null || user.getUserId() == null) { + System.out.println("用户或用户ID为空,跳过"); + invalidUserCount++; + continue; + } + + + if (existingUserIds.contains(user.getUserId())) { + System.out.println("用户ID: " + user.getUserId() + " 已绑定,跳过"); + duplicateUserCount++; + continue; + } + + // 创建通知记录 + NotificationRecords record = new NotificationRecords(); + record.setUserId(user.getUserId()); + // 默认设置为in-app渠道 + record.setChannel("in-app"); + // 设置状态为待发送 + record.setStatus("pending"); + record.setCreateTime(now); + record.setNotificationId(id); + recordsList.add(record); + validUserCount++; + + System.out.println("添加用户ID: " + user.getUserId() + " 到待绑定列表"); + } catch (Exception e) { + // 记录错误日志,但继续处理其他用户 + System.err.println("处理用户ID时出错: " + (user != null ? user.getUserId() : "null") + ", 错误: " + e.getMessage()); + e.printStackTrace(); + invalidUserCount++; + } + } + + System.out.println("有效用户数: " + validUserCount + ", 无效用户数: " + invalidUserCount + ", 重复用户数: " + duplicateUserCount); + System.out.println("待插入记录数: " + recordsList.size()); + + // 批量插入通知记录 + if (!recordsList.isEmpty()) { + try { + int insertCount = notificationRecordsMapper.batchInsertNotificationRecords(recordsList); + System.out.println("成功插入记录数: " + insertCount); + } catch (Exception e) { + System.err.println("批量插入通知记录失败: " + e.getMessage()); + e.printStackTrace(); + throw new RuntimeException("批量插入通知记录失败: " + e.getMessage(), e); + } + } else { + System.out.println("没有需要插入的记录"); + } + } + + /** + * 获取通知已绑定的用户列表 + * + * @param notificationId 通知ID + * @return 用户列表 + */ + @Override + public List getBindUsers(Long notificationId) { + if (notificationId == null) { + return new ArrayList<>(); + } + + // 创建查询条件 + NotificationRecords query = new NotificationRecords(); + query.setNotificationId(notificationId); + + // 查询通知记录 + List records = notificationRecordsMapper.selectNotificationRecordsList(query); + + // 提取用户ID列表 + List userIds = records.stream() + .map(NotificationRecords::getUserId) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + // 如果没有绑定用户,返回空列表 + if (userIds.isEmpty()) { + return new ArrayList<>(); + } + + // 查询用户信息 + // 这里需要调用ShopUserMapper来查询用户信息 + // 由于没有提供ShopUserMapper,这里简单处理,将用户ID封装成ShopUser对象返回 + List users = new ArrayList<>(); + for (Long userId : userIds) { + ShopUser user = new ShopUser(); + user.setUserId(userId); + users.add(user); + } + + return users; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotificationsServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotificationsServiceImpl.java new file mode 100644 index 0000000..da4b5ab --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/NotificationsServiceImpl.java @@ -0,0 +1,221 @@ +package com.ruoyi.system.service.impl; + +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.entity.NotificationRecords; +import com.ruoyi.common.core.domain.entity.Notifications; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.system.mapper.NotificationRecordsMapper; +import com.ruoyi.system.mapper.NotificationsMapper; +import com.ruoyi.system.service.INotificationsService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; + +/** + * 【请填写功能名称】Service业务层处理 + * + * @author ruoyi + * @date 2025-08-23 + */ +@Service +public class NotificationsServiceImpl implements INotificationsService +{ + private static final Logger log = LoggerFactory.getLogger(NotificationsServiceImpl.class); + + @Autowired + private NotificationsMapper notificationsMapper; + + @Autowired + private NotificationRecordsMapper notificationRecordsMapper; + + /** + * 查询【请填写功能名称】 + * + * @param id 【请填写功能名称】主键 + * @return 【请填写功能名称】 + */ + @Override + public Notifications selectNotificationsById(Long id) + { + return notificationsMapper.selectNotificationsById(id); + } + + /** + * 查询【请填写功能名称】列表 + * + * @param notifications 【请填写功能名称】 + * @return 【请填写功能名称】 + */ + @Override + public List selectNotificationsList(Notifications notifications) + { + return notificationsMapper.selectNotificationsList(notifications); + } + + /** + * 新增【请填写功能名称】 + * + * @param notifications 【请填写功能名称】 + * @return 结果 + */ + @Override + public int insertNotifications(Notifications notifications) + { + notifications.setCreateTime(DateUtils.getNowDate()); + return notificationsMapper.insertNotifications(notifications); + } + + /** + * 修改【请填写功能名称】 + * + * @param notifications 【请填写功能名称】 + * @return 结果 + */ + @Override + public int updateNotifications(Notifications notifications) + { + return notificationsMapper.updateNotifications(notifications); + } + + /** + * 批量删除【请填写功能名称】 + * + * @param ids 需要删除的【请填写功能名称】主键 + * @return 结果 + */ + @Override + public int deleteNotificationsByIds(Long[] ids) + { + return notificationsMapper.deleteNotificationsByIds(ids); + } + + /** + * 删除【请填写功能名称】信息 + * + * @param id 【请填写功能名称】主键 + * @return 结果 + */ + @Override + public int deleteNotificationsById(Long id) + { + return notificationsMapper.deleteNotificationsById(id); + } + + /** + * 发布通知 + * + * @param id 通知ID + * @return 结果 + */ + @Override + @Transactional + public AjaxResult publishNotification(Long id) + { + // 查询通知信息 + Notifications notification = notificationsMapper.selectNotificationsById(id); + if (notification == null) + { + return AjaxResult.error("通知不存在"); + } + + // 查询该通知的所有记录 + NotificationRecords query = new NotificationRecords(); + query.setNotificationId(id); + List records = notificationRecordsMapper.selectNotificationRecordsList(query); + + if (records.isEmpty()) + { + return AjaxResult.error("该通知没有绑定任何用户,请先绑定用户"); + } + + // 当前时间 + Date now = DateUtils.getNowDate(); + int successCount = 0; + int failCount = 0; + + // 遍历所有记录,进行发布 + for (NotificationRecords record : records) + { + // 如果记录已经发送过,则不再创建新记录,只更新状态 + if ("sent".equals(record.getStatus())) + { + // 调用第三方接口发送通知 + boolean sendResult = sendNotificationToThirdParty(notification, record); + + if (sendResult) + { + successCount++; + } + else + { + failCount++; + // 更新失败原因 + record.setFailureReason("重新发送失败"); + notificationRecordsMapper.updateNotificationRecords(record); + } + } + else + { + // 调用第三方接口发送通知 + boolean sendResult = sendNotificationToThirdParty(notification, record); + + if (sendResult) + { + // 更新记录状态为已发送 + record.setStatus("sent"); + record.setSentTime(now); + record.setUpdateTime(now); + notificationRecordsMapper.updateNotificationRecords(record); + successCount++; + } + else + { + // 更新记录状态为发送失败 + record.setStatus("failed"); + record.setFailureReason("发送失败"); + record.setUpdateTime(now); + notificationRecordsMapper.updateNotificationRecords(record); + failCount++; + } + } + } + + // 更新通知状态为已发布 +// notification.setStatus("published"); +// notification.setPublishTime(now); + notificationsMapper.updateNotifications(notification); + + return AjaxResult.success("通知发布完成,成功:" + successCount + ",失败:" + failCount); + } + + /** + * 调用第三方接口发送通知 + * + * @param notification 通知信息 + * @param record 通知记录 + * @return 发送结果 + */ + private boolean sendNotificationToThirdParty(Notifications notification, NotificationRecords record) + { + try + { + // TODO: 实现调用第三方接口发送通知的逻辑 + // 这里是模拟实现,实际项目中需要根据具体的第三方接口进行调用 + log.info("发送通知:通知ID={}, 用户ID={}, 标题={}, 内容={}", + notification.getId(), record.getUserId(), notification.getTitle(), notification.getContent()); + + // 模拟发送成功 + return true; + } + catch (Exception e) + { + log.error("发送通知失败:", e); + return false; + } + } +} diff --git a/ruoyi-system/src/main/resources/mapper/system/NotificationRecordsMapper.xml b/ruoyi-system/src/main/resources/mapper/system/NotificationRecordsMapper.xml new file mode 100644 index 0000000..55afb2a --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/system/NotificationRecordsMapper.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + select id, notification_id, user_id, channel, status, sent_time, read_time, failure_reason, create_time, update_time from notification_records + + + + + + + + insert into notification_records + + notification_id, + user_id, + channel, + status, + sent_time, + read_time, + failure_reason, + create_time, + update_time, + + + #{notificationId}, + #{userId}, + #{channel}, + #{status}, + #{sentTime}, + #{readTime}, + #{failureReason}, + #{createTime}, + #{updateTime}, + + + + + update notification_records + + notification_id = #{notificationId}, + user_id = #{userId}, + channel = #{channel}, + status = #{status}, + sent_time = #{sentTime}, + read_time = #{readTime}, + failure_reason = #{failureReason}, + create_time = #{createTime}, + update_time = #{updateTime}, + + where id = #{id} + + + + delete from notification_records where id = #{id} + + + + delete from notification_records where id in + + #{id} + + + + + insert into notification_records + (notification_id, user_id, channel, status, sent_time, read_time, failure_reason, create_time, update_time) + values + + ( + #{item.notificationId}, + #{item.userId}, + #{item.channel}, + #{item.status}, + #{item.sentTime}, + #{item.readTime}, + #{item.failureReason}, + #{item.createTime}, + #{item.updateTime} + ) + + + \ No newline at end of file diff --git a/ruoyi-system/src/main/resources/mapper/system/NotificationsMapper.xml b/ruoyi-system/src/main/resources/mapper/system/NotificationsMapper.xml new file mode 100644 index 0000000..bd7d4c3 --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/system/NotificationsMapper.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + select id, title, content, notification_type, extra_data, creator, create_time, updated_time, send_time from notifications + + + + + + + + insert into notifications + + title, + content, + notification_type, + extra_data, + creator, + create_time, + updated_time, + send_time, + + + #{title}, + #{content}, + #{notificationType}, + #{extraData}, + #{creator}, + #{createTime}, + #{updatedTime}, + #{sendTime}, + + + + + update notifications + + title = #{title}, + content = #{content}, + notification_type = #{notificationType}, + extra_data = #{extraData}, + creator = #{creator}, + create_time = #{createTime}, + updated_time = #{updatedTime}, + send_time = #{sendTime}, + + where id = #{id} + + + + delete from notifications where id = #{id} + + + + delete from notifications where id in + + #{id} + + + \ No newline at end of file diff --git a/ruoyi-ui/src/api/notify/notifications.js b/ruoyi-ui/src/api/notify/notifications.js new file mode 100644 index 0000000..2da2eb5 --- /dev/null +++ b/ruoyi-ui/src/api/notify/notifications.js @@ -0,0 +1,71 @@ +import request from '@/utils/request' + +// 查询【请填写功能名称】列表 +export function listNotifications(query) { + return request({ + url: '/back/notifications/list', + method: 'get', + params: query + }) +} + +// 查询【请填写功能名称】详细 +export function getNotifications(id) { + return request({ + url: '/back/notifications/' + id, + method: 'get' + }) +} + +// 新增【请填写功能名称】 +export function addNotifications(data) { + return request({ + url: '/back/notifications', + method: 'post', + data: data + }) +} + +// 修改【请填写功能名称】 +export function updateNotifications(data) { + return request({ + url: '/back/notifications', + method: 'put', + data: data + }) +} + +// 删除【请填写功能名称】 +export function delNotifications(id) { + return request({ + url: '/back/notifications/' + id, + method: 'delete' + }) +} + +// 绑定用户 +export function bindUsers(id, data) { + return request({ + url: '/back/notifications/bind', + method: 'post', + params: { id: id }, + data: data + }) +} + +// 获取通知已绑定的用户列表 +export function getBindUsers(id) { + return request({ + url: '/back/notifications/bindUsers/' + id, + method: 'get' + }) +} + +// 发布通知 +export function publishNotification(id) { + return request({ + url: '/back/notifications/publish/' + id, + method: 'post' + }) +} + diff --git a/ruoyi-ui/src/views/notifications/index.vue b/ruoyi-ui/src/views/notifications/index.vue new file mode 100644 index 0000000..e5ecf2d --- /dev/null +++ b/ruoyi-ui/src/views/notifications/index.vue @@ -0,0 +1,584 @@ + + +