Commit ae3ee95cdd5b9e46199f48deb5b50296af39bfca

Authored by YunaiV
1 parent 143035d7

站内信模块:整体功能实现

Showing 56 changed files with 1367 additions and 1018 deletions
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java
1 1 package cn.iocoder.yudao.framework.mybatis.core.query;
2 2  
  3 +import cn.hutool.core.lang.Assert;
3 4 import cn.hutool.core.util.ArrayUtil;
4 5 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
  6 +import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants;
5 7 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
6 8 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
7 9 import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
... ...
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/QueryWrapperX.java
... ... @@ -146,19 +146,19 @@ public class QueryWrapperX<T> extends QueryWrapper<T> {
146 146 *
147 147 * @return this
148 148 */
149   - public QueryWrapperX<T> limit1() {
  149 + public QueryWrapperX<T> limitN(int n) {
150 150 Assert.notNull(SqlConstants.DB_TYPE, "获取不到数据库的类型");
151 151 switch (SqlConstants.DB_TYPE) {
152 152 case ORACLE:
153 153 case ORACLE_12C:
154   - super.eq("ROWNUM", 1);
  154 + super.eq("ROWNUM", n);
155 155 break;
156 156 case SQL_SERVER:
157 157 case SQL_SERVER2005:
158   - super.select("TOP 1 *"); // 由于 SQL Server 是通过 SELECT TOP 1 实现限制一条,所以只好使用 * 查询剩余字段
  158 + super.select("TOP " + n + " *"); // 由于 SQL Server 是通过 SELECT TOP 1 实现限制一条,所以只好使用 * 查询剩余字段
159 159 break;
160 160 default:
161   - super.last("LIMIT 1");
  161 + super.last("LIMIT " + n);
162 162 }
163 163 return this;
164 164 }
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
... ... @@ -153,13 +153,13 @@ public interface ErrorCodeConstants {
153 153 ErrorCode MAIL_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1002025000, "模板参数({})缺失");
154 154 ErrorCode MAIL_SEND_MAIL_NOT_EXISTS = new ErrorCode(1002025000, "邮箱不存在");
155 155  
156   - // ========== 站内信模版 1002023000 ==========
157   - ErrorCode NOTIFY_TEMPLATE_NOT_EXISTS = new ErrorCode(1002023000, "站内信模版不存在");
158   - ErrorCode NOTIFY_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1002023001, "已经存在编码为【{}】的站内信模板");
159   - ErrorCode NOTIFY_TEMPLATE_PARAM_MISS = new ErrorCode(1002023002, "模板参数({})缺失");
160   -
161   - // ========== 站内信 1002024000 ==========
162   - ErrorCode NOTIFY_MESSAGE_NOT_EXISTS = new ErrorCode(1002024000, "站内信不存在");
163   - ErrorCode NOTIFY_MESSAGE_ID_PARAM_ERROR = new ErrorCode(1002024001, "站内信ID错误");
  156 + // ========== 站内信模版 1002026000 ==========
  157 + ErrorCode NOTIFY_TEMPLATE_NOT_EXISTS = new ErrorCode(1002026000, "站内信模版不存在");
  158 + ErrorCode NOTIFY_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1002026001, "已经存在编码为【{}】的站内信模板");
  159 +
  160 + // ========== 站内信模版 1002027000 ==========
  161 +
  162 + // ========== 站内信发送 1002028000 ==========
  163 + ErrorCode NOTIFY_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1002025000, "模板参数({})缺失");
164 164  
165 165 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyLogController.java deleted
1   -package cn.iocoder.yudao.module.system.controller.admin.notify;
2   -
3   -import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
5   -import cn.iocoder.yudao.module.system.controller.admin.notify.vo.log.NotifyLogBaseVO;
6   -import cn.iocoder.yudao.module.system.controller.admin.notify.vo.log.NotifyLogPageReqVO;
7   -import cn.iocoder.yudao.module.system.convert.notify.NotifyLogConvert;
8   -import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
9   -import cn.iocoder.yudao.module.system.service.notify.NotifyLogService;
10   -import cn.iocoder.yudao.module.system.service.user.AdminUserService;
11   -import io.swagger.annotations.Api;
12   -import io.swagger.annotations.ApiOperation;
13   -import org.springframework.validation.annotation.Validated;
14   -import org.springframework.web.bind.annotation.GetMapping;
15   -import org.springframework.web.bind.annotation.RequestMapping;
16   -import org.springframework.web.bind.annotation.RestController;
17   -
18   -import javax.annotation.Resource;
19   -import javax.validation.Valid;
20   -
21   -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
22   -
23   -/**
24   - * <p>
25   - *
26   - * </p>
27   - *
28   - * @author LuoWenFeng
29   - */
30   -@Api(tags = "管理后台 - 站内信发送日志")
31   -@RestController
32   -@RequestMapping("/system/notify-log")
33   -@Validated
34   -public class NotifyLogController {
35   -
36   - @Resource
37   - private NotifyLogService notifyLogService;
38   -
39   - @Resource
40   - private AdminUserService userService;
41   -
42   - @GetMapping("/page")
43   - @ApiOperation("获得发送站内信日志分页")
44   - public CommonResult<PageResult<NotifyLogBaseVO>> getNotifyLogPage(@Valid NotifyLogPageReqVO pageVO) {
45   - PageResult<NotifyMessageDO> pageResult = notifyLogService.getNotifyMessageSendPage(pageVO);
46   - PageResult<NotifyLogBaseVO> result = NotifyLogConvert.INSTANCE.convertPage(pageResult);
47   - result.getList().forEach(v -> {
48   - v.setReceiveUserName(userService.getUser(v.getUserId()).getNickname());
49   - });
50   - return success(result);
51   - }
52   -
53   -
54   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyMessageController.java
1 1 package cn.iocoder.yudao.module.system.controller.admin.notify;
2 2  
3   -import cn.hutool.core.collection.CollUtil;
4 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
5 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
7 7 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
8 8 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageRespVO;
9 9 import cn.iocoder.yudao.module.system.convert.notify.NotifyMessageConvert;
... ... @@ -18,7 +18,6 @@ import org.springframework.web.bind.annotation.*;
18 18  
19 19 import javax.annotation.Resource;
20 20 import javax.validation.Valid;
21   -import java.util.Collections;
22 21 import java.util.List;
23 22  
24 23 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
... ... @@ -33,6 +32,8 @@ public class NotifyMessageController {
33 32 @Resource
34 33 private NotifyMessageService notifyMessageService;
35 34  
  35 + // ========== 管理所有的站内信 ==========
  36 +
36 37 @GetMapping("/get")
37 38 @ApiOperation("获得站内信")
38 39 @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
... ... @@ -50,38 +51,45 @@ public class NotifyMessageController {
50 51 return success(NotifyMessageConvert.INSTANCE.convertPage(pageResult));
51 52 }
52 53  
53   - @GetMapping("/get-recent-list")
54   - @ApiOperation("获取当前用户最新站内信,默认10条")
55   - @ApiImplicitParam(name = "size", value = "10", defaultValue = "10", dataTypeClass = Integer.class)
56   - public CommonResult<List<NotifyMessageRespVO>> getRecentList(@RequestParam(name = "size", defaultValue = "10") Integer size) {
57   - NotifyMessagePageReqVO reqVO = new NotifyMessagePageReqVO();
58   - List<NotifyMessageDO> pageResult = notifyMessageService.getNotifyMessageList(reqVO, size);
59   - if (CollUtil.isNotEmpty(pageResult)) {
60   - return success(NotifyMessageConvert.INSTANCE.convertList(pageResult));
61   - }
62   - return success(Collections.emptyList());
63   - }
  54 + // ========== 查看自己的站内信 ==========
64 55  
65   - @GetMapping("/get-unread-count")
66   - @ApiOperation("获得未读站内信数量")
67   - public CommonResult<Long> getUnreadCount() {
68   - return success(notifyMessageService.getUnreadNotifyMessageCount(getLoginUserId(), UserTypeEnum.ADMIN.getValue()));
  56 + @GetMapping("/my-page")
  57 + @ApiOperation("获得我的站内信分页")
  58 + public CommonResult<PageResult<NotifyMessageRespVO>> getMyMyNotifyMessagePage(@Valid NotifyMessageMyPageReqVO pageVO) {
  59 + PageResult<NotifyMessageDO> pageResult = notifyMessageService.getMyMyNotifyMessagePage(pageVO,
  60 + getLoginUserId(), UserTypeEnum.ADMIN.getValue());
  61 + return success(NotifyMessageConvert.INSTANCE.convertPage(pageResult));
69 62 }
70 63  
71   - @PutMapping("/update-list-read")
72   - @ApiOperation("批量标记已读")
  64 + @PutMapping("/update-read")
  65 + @ApiOperation("标记站内信为已读")
73 66 @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
74   - public CommonResult<Boolean> batchUpdateNotifyMessageReadStatus(@RequestBody List<Long> ids) {
75   - notifyMessageService.batchUpdateNotifyMessageReadStatus(ids, getLoginUserId());
  67 + public CommonResult<Boolean> updateNotifyMessageRead(@RequestParam("ids") List<Long> ids) {
  68 + notifyMessageService.updateNotifyMessageRead(ids, getLoginUserId(), UserTypeEnum.ADMIN.getValue());
76 69 return success(Boolean.TRUE);
77 70 }
78 71  
79 72 @PutMapping("/update-all-read")
80   - @ApiOperation("所有未读消息标记已读")
81   - public CommonResult<Boolean> batchUpdateAllNotifyMessageReadStatus() {
82   - notifyMessageService.batchUpdateAllNotifyMessageReadStatus(getLoginUserId(), UserTypeEnum.ADMIN.getValue());
  73 + @ApiOperation("标记所有站内信为已读")
  74 + public CommonResult<Boolean> updateAllNotifyMessageRead() {
  75 + notifyMessageService.updateAllNotifyMessageRead(getLoginUserId(), UserTypeEnum.ADMIN.getValue());
83 76 return success(Boolean.TRUE);
84 77 }
85 78  
  79 + @GetMapping("/get-unread-list")
  80 + @ApiOperation("获取当前用户的最新站内信列表,默认 10 条")
  81 + @ApiImplicitParam(name = "size", value = "10", defaultValue = "10", dataTypeClass = Integer.class)
  82 + public CommonResult<List<NotifyMessageRespVO>> getUnreadNotifyMessageList(
  83 + @RequestParam(name = "size", defaultValue = "10") Integer size) {
  84 + List<NotifyMessageDO> list = notifyMessageService.getUnreadNotifyMessageList(
  85 + getLoginUserId(), UserTypeEnum.ADMIN.getValue(), size);
  86 + return success(NotifyMessageConvert.INSTANCE.convertList(list));
  87 + }
  88 +
  89 + @GetMapping("/get-unread-count")
  90 + @ApiOperation("获得当前用户的未读站内信数量")
  91 + public CommonResult<Long> getUnreadNotifyMessageCount() {
  92 + return success(notifyMessageService.getUnreadNotifyMessageCount(getLoginUserId(), UserTypeEnum.ADMIN.getValue()));
  93 + }
86 94  
87 95 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyTemplateController.java
... ... @@ -2,8 +2,6 @@ package cn.iocoder.yudao.module.system.controller.admin.notify;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5   -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
6   -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
7 5 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.*;
8 6 import cn.iocoder.yudao.module.system.convert.notify.NotifyTemplateConvert;
9 7 import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
... ... @@ -17,13 +15,9 @@ import org.springframework.validation.annotation.Validated;
17 15 import org.springframework.web.bind.annotation.*;
18 16  
19 17 import javax.annotation.Resource;
20   -import javax.servlet.http.HttpServletResponse;
21 18 import javax.validation.Valid;
22   -import java.io.IOException;
23   -import java.util.List;
24 19  
25 20 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
26   -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
27 21  
28 22 @Api(tags = "管理后台 - 站内信模版")
29 23 @RestController
... ... @@ -37,7 +31,6 @@ public class NotifyTemplateController {
37 31 @Resource
38 32 private NotifySendService notifySendService;
39 33  
40   -
41 34 @PostMapping("/create")
42 35 @ApiOperation("创建站内信模版")
43 36 @PreAuthorize("@ss.hasPermission('system:notify-template:create')")
... ... @@ -79,22 +72,12 @@ public class NotifyTemplateController {
79 72 return success(NotifyTemplateConvert.INSTANCE.convertPage(pageResult));
80 73 }
81 74  
82   - @GetMapping("/export-excel")
83   - @ApiOperation("导出站内信模版 Excel")
84   - @PreAuthorize("@ss.hasPermission('system:notify-template:export')")
85   - @OperateLog(type = EXPORT)
86   - public void exportNotifyTemplateExcel(@Valid NotifyTemplateExportReqVO exportReqVO,
87   - HttpServletResponse response) throws IOException {
88   - List<NotifyTemplateDO> list = notifyTemplateService.getNotifyTemplateList(exportReqVO);
89   - // 导出 Excel
90   - List<NotifyTemplateExcelVO> datas = NotifyTemplateConvert.INSTANCE.convertList02(list);
91   - ExcelUtils.write(response, "站内信模版.xls", "数据", NotifyTemplateExcelVO.class, datas);
92   - }
93   -
94 75 @PostMapping("/send-notify")
95 76 @ApiOperation("发送站内信")
  77 + @PreAuthorize("@ss.hasPermission('system:notify-template:send-notify')")
96 78 public CommonResult<Long> sendNotify(@Valid @RequestBody NotifyTemplateSendReqVO sendReqVO) {
97 79 return success(notifySendService.sendSingleNotifyToAdmin(sendReqVO.getUserId(),
98 80 sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
99 81 }
  82 +
100 83 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/log/NotifyLogBaseVO.java deleted
1   -package cn.iocoder.yudao.module.system.controller.admin.notify.vo.log;
2   -
3   -import io.swagger.annotations.ApiModelProperty;
4   -import lombok.Data;
5   -import org.springframework.format.annotation.DateTimeFormat;
6   -
7   -import java.util.Date;
8   -
9   -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
10   -
11   -/**
12   - * 站内信 Base VO,提供给添加、修改、详细的子 VO 使用
13   - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
14   - */
15   -@Data
16   -public class NotifyLogBaseVO {
17   -
18   - @ApiModelProperty(value = "模版编码")
19   - private String templateCode;
20   -
21   - @ApiModelProperty(value = "标题")
22   - private String title;
23   -
24   - @ApiModelProperty(value = "内容", required = true)
25   - private String content;
26   -
27   - @ApiModelProperty(value = "发送时间", required = true)
28   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
29   - private Date sendTime;
30   -
31   - @ApiModelProperty(value = "芋艿", required = true)
32   - private String receiveUserName;
33   -
34   - @ApiModelProperty(value = "1", required = true)
35   - private Long userId;
36   -
37   - @ApiModelProperty(value = "是否已读 false-未读 true-已读")
38   - private Boolean readStatus;
39   -
40   - @ApiModelProperty(value = "阅读时间")
41   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
42   - private Date readTime;
43   -
44   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessageBaseVO.java
... ... @@ -4,35 +4,58 @@ import io.swagger.annotations.ApiModelProperty;
4 4 import lombok.Data;
5 5 import org.springframework.format.annotation.DateTimeFormat;
6 6  
  7 +import javax.validation.constraints.NotNull;
  8 +import java.time.LocalDateTime;
7 9 import java.util.Date;
  10 +import java.util.Map;
8 11  
9 12 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
10 13  
11 14 /**
12   - * 站内信 Base VO,提供给添加、修改、详细的子 VO 使用
  15 + * 站内信消息 Base VO,提供给添加、修改、详细的子 VO 使用
13 16 * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
14 17 */
15 18 @Data
16 19 public class NotifyMessageBaseVO {
17 20  
18   - @ApiModelProperty(value = "标题")
19   - private String title;
  21 + @ApiModelProperty(value = "用户编号", required = true, example = "25025")
  22 + @NotNull(message = "用户编号不能为空")
  23 + private Long userId;
20 24  
21   - @ApiModelProperty(value = "内容")
22   - private String content;
  25 + @ApiModelProperty(value = "用户类型", required = true, example = "1", notes = "参见 UserTypeEnum 枚举")
  26 + @NotNull(message = "用户类型不能为空")
  27 + private Byte userType;
23 28  
24   - @ApiModelProperty(value = "发送时间")
25   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
26   - private Date sendTime;
  29 + @ApiModelProperty(value = "模版编号", required = true, example = "13013")
  30 + @NotNull(message = "模版编号不能为空")
  31 + private Long templateId;
  32 +
  33 + @ApiModelProperty(value = "模板编码", required = true, example = "test_01")
  34 + @NotNull(message = "模板编码不能为空")
  35 + private String templateCode;
  36 +
  37 + @ApiModelProperty(value = "模版发送人名称", required = true, example = "芋艿")
  38 + @NotNull(message = "模版发送人名称不能为空")
  39 + private String templateNickname;
  40 +
  41 + @ApiModelProperty(value = "模版内容", required = true, example = "测试内容")
  42 + @NotNull(message = "模版内容不能为空")
  43 + private String templateContent;
  44 +
  45 + @ApiModelProperty(value = "模版类型", required = true, example = "2")
  46 + @NotNull(message = "模版类型不能为空")
  47 + private Integer templateType;
27 48  
28   - @ApiModelProperty(value = "芋艿")
29   - private String sendUserName;
  49 + @ApiModelProperty(value = "模版参数", required = true)
  50 + @NotNull(message = "模版参数不能为空")
  51 + private Map<String, Object> templateParams;
30 52  
31   - @ApiModelProperty(value = "是否已读 false-未读 true-已读")
  53 + @ApiModelProperty(value = "是否已读", required = true, example = "true")
  54 + @NotNull(message = "是否已读不能为空")
32 55 private Boolean readStatus;
33 56  
34 57 @ApiModelProperty(value = "阅读时间")
35 58 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
36   - private Date readTime;
  59 + private LocalDateTime readTime;
37 60  
38 61 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/log/NotifyLogPageReqVO.java renamed to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessageMyPageReqVO.java
1   -package cn.iocoder.yudao.module.system.controller.admin.notify.vo.log;
  1 +package cn.iocoder.yudao.module.system.controller.admin.notify.vo.message;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 4 import io.swagger.annotations.ApiModel;
... ... @@ -8,23 +8,21 @@ import lombok.EqualsAndHashCode;
8 8 import lombok.ToString;
9 9 import org.springframework.format.annotation.DateTimeFormat;
10 10  
11   -import java.util.Date;
  11 +import java.time.LocalDateTime;
12 12  
13 13 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
14 14  
15   -@ApiModel("管理后台 - 站内信日志分页 Request VO")
  15 +@ApiModel("管理后台 - 站内信分页 Request VO")
16 16 @Data
17 17 @EqualsAndHashCode(callSuper = true)
18 18 @ToString(callSuper = true)
19   -public class NotifyLogPageReqVO extends PageParam {
  19 +public class NotifyMessageMyPageReqVO extends PageParam {
20 20  
21   - @ApiModelProperty(value = "模版编码")
22   - private String templateCode;
23   -
24   - @ApiModelProperty(value = "标题")
25   - private String title;
  21 + @ApiModelProperty(value = "是否已读", example = "true")
  22 + private Boolean readStatus;
26 23  
27 24 @ApiModelProperty(value = "创建时间")
28 25 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
29   - private Date[] sendTime;
  26 + private LocalDateTime[] createTime;
  27 +
30 28 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessagePageReqVO.java
... ... @@ -8,6 +8,7 @@ import lombok.EqualsAndHashCode;
8 8 import lombok.ToString;
9 9 import org.springframework.format.annotation.DateTimeFormat;
10 10  
  11 +import java.time.LocalDateTime;
11 12 import java.util.Date;
12 13  
13 14 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
... ... @@ -18,14 +19,20 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
18 19 @ToString(callSuper = true)
19 20 public class NotifyMessagePageReqVO extends PageParam {
20 21  
21   - @ApiModelProperty(value = "标题")
22   - private String title;
  22 + @ApiModelProperty(value = "用户编号", example = "25025")
  23 + private Long userId;
23 24  
24   - @ApiModelProperty(value = "是否已读 0-未读 1-已读")
25   - private Boolean readStatus;
  25 + @ApiModelProperty(value = "用户类型", example = "1")
  26 + private Integer userType;
  27 +
  28 + @ApiModelProperty(value = "模板编码", example = "test_01")
  29 + private String templateCode;
  30 +
  31 + @ApiModelProperty(value = "模版类型", example = "2")
  32 + private Integer templateType;
26 33  
27 34 @ApiModelProperty(value = "创建时间")
28 35 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
29   - private Date[] createTime;
  36 + private LocalDateTime[] createTime;
30 37  
31 38 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java
... ... @@ -10,7 +10,10 @@ import io.swagger.annotations.*;
10 10 @ToString(callSuper = true)
11 11 public class NotifyMessageRespVO extends NotifyMessageBaseVO {
12 12  
13   - @ApiModelProperty(value = "ID", required = true)
  13 + @ApiModelProperty(value = "ID", required = true, example = "1024")
14 14 private Long id;
15 15  
  16 + @ApiModelProperty(value = "创建时间", required = true)
  17 + private Date createTime;
  18 +
16 19 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateBaseVO.java
... ... @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.validation.InEnum;
5 5 import io.swagger.annotations.ApiModelProperty;
6 6 import lombok.Data;
7 7  
  8 +import javax.validation.constraints.NotEmpty;
8 9 import javax.validation.constraints.NotNull;
9 10  
10 11 /**
... ... @@ -14,24 +15,32 @@ import javax.validation.constraints.NotNull;
14 15 @Data
15 16 public class NotifyTemplateBaseVO {
16 17  
17   - @ApiModelProperty(value = "模版编码", required = true)
  18 + @ApiModelProperty(value = "模版名称", required = true, example = "测试模版")
  19 + @NotEmpty(message = "模版名称不能为空")
  20 + private String name;
  21 +
  22 + @ApiModelProperty(value = "模版编码", required = true, example = "SEND_TEST")
18 23 @NotNull(message = "模版编码不能为空")
19 24 private String code;
20 25  
21   - @ApiModelProperty(value = "模版标题", required = true)
22   - @NotNull(message = "模版标题不能为空")
23   - private String title;
  26 + @ApiModelProperty(value = "模版类型", required = true, example = "1", notes = "对应 system_notify_template_type 字典")
  27 + @NotNull(message = "模版类型不能为空")
  28 + private Integer type;
  29 +
  30 + @ApiModelProperty(value = "发送人名称", required = true, example = "土豆")
  31 + @NotEmpty(message = "发送人名称不能为空")
  32 + private String nickname;
24 33  
25   - @ApiModelProperty(value = "模版内容", required = true)
26   - @NotNull(message = "模版内容不能为空")
  34 + @ApiModelProperty(value = "模版内容", required = true, example = "我是模版内容")
  35 + @NotEmpty(message = "模版内容不能为空")
27 36 private String content;
28 37  
29   - @ApiModelProperty(value = "状态:1-启用 0-禁用", required = true)
30   - @NotNull(message = "状态:1-启用 0-禁用不能为空")
  38 + @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
  39 + @NotNull(message = "状态不能为空")
31 40 @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
32 41 private Integer status;
33 42  
34   - @ApiModelProperty(value = "备注")
35   - private String remarks;
  43 + @ApiModelProperty(value = "备注", example = "我是备注")
  44 + private String remark;
36 45  
37 46 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateCreateReqVO.java
... ... @@ -8,5 +8,4 @@ import io.swagger.annotations.*;
8 8 @EqualsAndHashCode(callSuper = true)
9 9 @ToString(callSuper = true)
10 10 public class NotifyTemplateCreateReqVO extends NotifyTemplateBaseVO {
11   -
12 11 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateExcelVO.java deleted
1   -package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template;
2   -
3   -import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
4   -import lombok.*;
5   -import java.util.*;
6   -import io.swagger.annotations.*;
7   -
8   -import com.alibaba.excel.annotation.ExcelProperty;
9   -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
10   -import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
11   -
12   -
13   -/**
14   - * 站内信模版 Excel VO
15   - *
16   - * @author 芋道源码
17   - */
18   -@Data
19   -public class NotifyTemplateExcelVO {
20   -
21   - @ExcelProperty("ID")
22   - private Long id;
23   -
24   - @ExcelProperty("模版编码")
25   - private String code;
26   -
27   - @ExcelProperty("模版标题")
28   - private String title;
29   -
30   - @ExcelProperty("模版内容")
31   - private String content;
32   -
33   - @ExcelProperty(value = "状态:1-启用 0-禁用", converter = DictConvert.class)
34   - @DictFormat(DictTypeConstants.COMMON_STATUS)
35   - private Integer status;
36   -
37   - @ExcelProperty("备注")
38   - private String remarks;
39   -
40   - @ExcelProperty("创建时间")
41   - private Date createTime;
42   -
43   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateExportReqVO.java deleted
1   -package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template;
2   -
3   -import lombok.*;
4   -import java.util.*;
5   -import io.swagger.annotations.*;
6   -import cn.iocoder.yudao.framework.common.pojo.PageParam;
7   -import org.springframework.format.annotation.DateTimeFormat;
8   -
9   -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
10   -
11   -@ApiModel(value = "管理后台 - 站内信模版 Excel 导出 Request VO", description = "参数和 NotifyTemplatePageReqVO 是一致的")
12   -@Data
13   -public class NotifyTemplateExportReqVO {
14   -
15   - @ApiModelProperty(value = "模版编码")
16   - private String code;
17   -
18   - @ApiModelProperty(value = "模版标题")
19   - private String title;
20   -
21   - @ApiModelProperty(value = "状态:1-启用 0-禁用")
22   - private Integer status;
23   -
24   - @ApiModelProperty(value = "创建时间")
25   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
26   - private Date[] createTime;
27   -
28   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplatePageReqVO.java
1 1 package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template;
2 2  
  3 +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
3 4 import lombok.*;
  5 +
  6 +import java.time.LocalDateTime;
4 7 import java.util.*;
5 8 import io.swagger.annotations.*;
6 9 import cn.iocoder.yudao.framework.common.pojo.PageParam;
... ... @@ -14,17 +17,17 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
14 17 @ToString(callSuper = true)
15 18 public class NotifyTemplatePageReqVO extends PageParam {
16 19  
17   - @ApiModelProperty(value = "模版编码")
  20 + @ApiModelProperty(value = "模版编码", example = "test_01")
18 21 private String code;
19 22  
20   - @ApiModelProperty(value = "模版标题")
21   - private String title;
  23 + @ApiModelProperty(value = "模版名称", example = "我是名称")
  24 + private String name;
22 25  
23   - @ApiModelProperty(value = "状态:1-启用 0-禁用")
24   - private String status;
  26 + @ApiModelProperty(value = "状态", example = "1", notes = "参见 CommonStatusEnum 枚举类")
  27 + private Integer status;
25 28  
26 29 @ApiModelProperty(value = "创建时间")
27 30 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
28   - private Date[] createTime;
  31 + private LocalDateTime[] createTime;
29 32  
30 33 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateRespVO.java
... ... @@ -10,7 +10,7 @@ import io.swagger.annotations.*;
10 10 @ToString(callSuper = true)
11 11 public class NotifyTemplateRespVO extends NotifyTemplateBaseVO {
12 12  
13   - @ApiModelProperty(value = "ID", required = true)
  13 + @ApiModelProperty(value = "ID", required = true, example = "1024")
14 14 private Long id;
15 15  
16 16 @ApiModelProperty(value = "参数数组", example = "name,code")
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java
... ... @@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModel;
4 4 import io.swagger.annotations.ApiModelProperty;
5 5 import lombok.Data;
6 6  
  7 +import javax.validation.constraints.NotEmpty;
7 8 import javax.validation.constraints.NotNull;
8 9 import java.util.Map;
9 10  
... ... @@ -16,7 +17,7 @@ public class NotifyTemplateSendReqVO {
16 17 private Long userId;
17 18  
18 19 @ApiModelProperty(value = "模板编码", required = true, example = "01")
19   - @NotNull(message = "模板编码不能为空")
  20 + @NotEmpty(message = "模板编码不能为空")
20 21 private String templateCode;
21 22  
22 23 @ApiModelProperty(value = "模板参数")
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateUpdateReqVO.java
... ... @@ -10,8 +10,8 @@ import javax.validation.constraints.*;
10 10 @ToString(callSuper = true)
11 11 public class NotifyTemplateUpdateReqVO extends NotifyTemplateBaseVO {
12 12  
13   - @ApiModelProperty(value = "ID", required = true)
14   - @NotNull(message = "ID不能为空")
  13 + @ApiModelProperty(value = "ID", required = true, example = "1024")
  14 + @NotNull(message = "ID 不能为空")
15 15 private Long id;
16 16  
17 17 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/notify/NotifyLogConvert.java deleted
1   -package cn.iocoder.yudao.module.system.convert.notify;
2   -
3   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.module.system.controller.admin.notify.vo.log.NotifyLogBaseVO;
5   -import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
6   -import org.mapstruct.Mapper;
7   -import org.mapstruct.factory.Mappers;
8   -
9   -/**
10   - * <p>
11   - *
12   - * </p>
13   - *
14   - * @author LuoWenFeng
15   - */
16   -@Mapper
17   -public interface NotifyLogConvert {
18   -
19   - NotifyLogConvert INSTANCE = Mappers.getMapper(NotifyLogConvert.class);
20   -
21   - PageResult<NotifyLogBaseVO> convertPage(PageResult<NotifyMessageDO> page);
22   -
23   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/notify/NotifyTemplateConvert.java
... ... @@ -5,7 +5,6 @@ import java.util.*;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6  
7 7 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO;
8   -import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateExcelVO;
9 8 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateRespVO;
10 9 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
11 10 import org.mapstruct.Mapper;
... ... @@ -32,6 +31,4 @@ public interface NotifyTemplateConvert {
32 31  
33 32 PageResult<NotifyTemplateRespVO> convertPage(PageResult<NotifyTemplateDO> page);
34 33  
35   - List<NotifyTemplateExcelVO> convertList02(List<NotifyTemplateDO> list);
36   -
37 34 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notify/NotifyMessageDO.java
... ... @@ -2,19 +2,24 @@ package cn.iocoder.yudao.module.system.dal.dataobject.notify;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
5 6 import com.baomidou.mybatisplus.annotation.KeySequence;
  7 +import com.baomidou.mybatisplus.annotation.TableField;
6 8 import com.baomidou.mybatisplus.annotation.TableId;
7 9 import com.baomidou.mybatisplus.annotation.TableName;
  10 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
8 11 import lombok.*;
9 12  
  13 +import java.time.LocalDateTime;
10 14 import java.util.Date;
  15 +import java.util.Map;
11 16  
12 17 /**
13 18 * 站内信 DO
14 19 *
15 20 * @author xrcoder
16 21 */
17   -@TableName("system_notify_message")
  22 +@TableName(value = "system_notify_message", autoResultMap = true)
18 23 @KeySequence("system_notify_message_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
19 24 @Data
20 25 @EqualsAndHashCode(callSuper = true)
... ... @@ -25,23 +30,11 @@ import java.util.Date;
25 30 public class NotifyMessageDO extends BaseDO {
26 31  
27 32 /**
28   - * ID
  33 + * 站内信编号,自增
29 34 */
30 35 @TableId
31 36 private Long id;
32 37 /**
33   - * 站内信模版编号
34   - *
35   - * 关联 {@link NotifyTemplateDO#getId()}
36   - */
37   - private Long templateId;
38   - /**
39   - * 站内信模版编码
40   - *
41   - * 关联 {@link NotifyTemplateDO#getCode()}
42   - */
43   - private String templateCode;
44   - /**
45 38 * 用户编号
46 39 *
47 40 * 关联 MemberUserDO 的 id 字段、或者 AdminUserDO 的 id 字段
... ... @@ -53,28 +46,49 @@ public class NotifyMessageDO extends BaseDO {
53 46 * 枚举 {@link UserTypeEnum}
54 47 */
55 48 private Integer userType;
  49 +
  50 + // ========= 模板相关字段 =========
  51 +
  52 + /**
  53 + * 模版编号
  54 + *
  55 + * 关联 {@link NotifyTemplateDO#getId()}
  56 + */
  57 + private Long templateId;
56 58 /**
57   - * 标题
  59 + * 模版编码
  60 + *
  61 + * 关联 {@link NotifyTemplateDO#getCode()}
58 62 */
59   - private String title;
  63 + private String templateCode;
60 64 /**
61   - * 内容
  65 + * 模版类型
  66 + *
  67 + * 冗余 {@link NotifyTemplateDO#getType()}
62 68 */
63   - private String content;
64   - // TODO @luowenfeng:是不是创建时间,直接作为发送时间;
  69 + private Integer templateType;
65 70 /**
66   - * 发送时间
  71 + * 模版发送人名称
  72 + *
  73 + * 冗余 {@link NotifyTemplateDO#getNickname()}
67 74 */
68   - private Date sendTime;
69   - // TODO @luowenfeng:是不是不用发送 id 和名字😑?
  75 + private String templateNickname;
70 76 /**
71   - * 发送用户id
  77 + * 模版内容
  78 + *
  79 + * 基于 {@link NotifyTemplateDO#getContent()} 格式化后的内容
72 80 */
73   - private Long sendUserId;
  81 + private String templateContent;
74 82 /**
75   - * 发送用户名
  83 + * 模版参数
  84 + *
  85 + * 基于 {@link NotifyTemplateDO#getParams()} 输入后的参数
76 86 */
77   - private String sendUserName;
  87 + @TableField(typeHandler = JacksonTypeHandler.class)
  88 + private Map<String, Object> templateParams;
  89 +
  90 + // ========= 读取相关字段 =========
  91 +
78 92 /**
79 93 * 是否已读
80 94 */
... ... @@ -82,6 +96,6 @@ public class NotifyMessageDO extends BaseDO {
82 96 /**
83 97 * 阅读时间
84 98 */
85   - private Date readTime;
  99 + private LocalDateTime readTime;
86 100  
87 101 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notify/NotifyTemplateDO.java
... ... @@ -32,13 +32,23 @@ public class NotifyTemplateDO extends BaseDO {
32 32 @TableId
33 33 private Long id;
34 34 /**
  35 + * 模版名称
  36 + */
  37 + private String name;
  38 + /**
35 39 * 模版编码
36 40 */
37 41 private String code;
38 42 /**
39   - * 模版标题
  43 + * 模版类型
  44 + *
  45 + * 对应 system_notify_template_type 字典
  46 + */
  47 + private Integer type;
  48 + /**
  49 + * 发送人名称
40 50 */
41   - private String title;
  51 + private String nickname;
42 52 /**
43 53 * 模版内容
44 54 */
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyMessageMapper.java
... ... @@ -3,60 +3,65 @@ package cn.iocoder.yudao.module.system.dal.mysql.notify;
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6   -import cn.iocoder.yudao.module.system.controller.admin.notify.vo.log.NotifyLogPageReqVO;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
  7 +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
7 8 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
8 9 import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
9 10 import org.apache.ibatis.annotations.Mapper;
10 11  
  12 +import java.time.LocalDateTime;
  13 +import java.util.Collection;
11 14 import java.util.List;
12 15  
13   -/**
14   - * 站内信 Mapper
15   - *
16   - * @author xrcoder
17   - */
18 16 @Mapper
19 17 public interface NotifyMessageMapper extends BaseMapperX<NotifyMessageDO> {
20 18  
21   - default PageResult<NotifyMessageDO> selectPage(NotifyMessagePageReqVO reqVO, Long userId, Integer userType) {
  19 + default PageResult<NotifyMessageDO> selectPage(NotifyMessagePageReqVO reqVO) {
22 20 return selectPage(reqVO, new LambdaQueryWrapperX<NotifyMessageDO>()
23   - .likeIfPresent(NotifyMessageDO::getTitle, reqVO.getTitle())
24   - .eqIfPresent(NotifyMessageDO::getReadStatus, reqVO.getReadStatus())
  21 + .eqIfPresent(NotifyMessageDO::getUserId, reqVO.getUserId())
  22 + .eqIfPresent(NotifyMessageDO::getUserType, reqVO.getUserType())
  23 + .likeIfPresent(NotifyMessageDO::getTemplateCode, reqVO.getTemplateCode())
  24 + .eqIfPresent(NotifyMessageDO::getTemplateType, reqVO.getTemplateType())
25 25 .betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime())
26   - .eq(NotifyMessageDO::getUserId, userId)
27   - .eq(NotifyMessageDO::getUserType, userType)
28 26 .orderByDesc(NotifyMessageDO::getId));
29 27 }
30 28  
31   - default PageResult<NotifyMessageDO> selectSendPage(NotifyLogPageReqVO reqVO, Long userId) {
  29 + default PageResult<NotifyMessageDO> selectPage(NotifyMessageMyPageReqVO reqVO, Long userId, Integer userType) {
32 30 return selectPage(reqVO, new LambdaQueryWrapperX<NotifyMessageDO>()
33   - .likeIfPresent(NotifyMessageDO::getTitle, reqVO.getTitle())
34   - .betweenIfPresent(NotifyMessageDO::getSendTime, reqVO.getSendTime())
35   - .eqIfPresent(NotifyMessageDO::getTemplateCode, reqVO.getTemplateCode())
36   - .eq(NotifyMessageDO::getSendUserId, userId)
  31 + .eq(NotifyMessageDO::getReadStatus, reqVO.getReadStatus())
  32 + .betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime())
  33 + .eq(NotifyMessageDO::getUserId, userId)
  34 + .eq(NotifyMessageDO::getUserType, userType)
37 35 .orderByDesc(NotifyMessageDO::getId));
38 36 }
39 37  
40   - default List<NotifyMessageDO> selectList(NotifyMessagePageReqVO reqVO, Integer size, Long userId, Integer userType) {
41   - return selectList(new LambdaQueryWrapperX<NotifyMessageDO>()
42   - .likeIfPresent(NotifyMessageDO::getTitle, reqVO.getTitle())
43   - .eqIfPresent(NotifyMessageDO::getReadStatus, reqVO.getReadStatus())
44   - .betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime())
45   - .eqIfPresent(NotifyMessageDO::getUserId, userId)
46   - .eqIfPresent(NotifyMessageDO::getUserType, userType)
47   - .orderByDesc(NotifyMessageDO::getId)
48   - .last("limit " + size));
  38 + default int updateListRead(Collection<Long> ids, Long userId, Integer userType) {
  39 + return update(new NotifyMessageDO().setReadStatus(true).setReadTime(LocalDateTime.now()),
  40 + new LambdaQueryWrapperX<NotifyMessageDO>()
  41 + .in(NotifyMessageDO::getId, ids)
  42 + .eq(NotifyMessageDO::getUserId, userId)
  43 + .eq(NotifyMessageDO::getUserType, userType)
  44 + .eq(NotifyMessageDO::getReadStatus, false));
49 45 }
50 46  
51   - default Long selectUnreadCountByUserIdAndUserType(Long userId, Integer userType) {
52   - return selectCount(new LambdaQueryWrapperX<NotifyMessageDO>()
53   - .eq(NotifyMessageDO::getReadStatus, false)
54   - .eq(NotifyMessageDO::getUserId, userId)
55   - .eq(NotifyMessageDO::getUserType, userType));
  47 + default int updateListRead(Long userId, Integer userType) {
  48 + return update(new NotifyMessageDO().setReadStatus(true).setReadTime(LocalDateTime.now()),
  49 + new LambdaQueryWrapperX<NotifyMessageDO>()
  50 + .eq(NotifyMessageDO::getUserId, userId)
  51 + .eq(NotifyMessageDO::getUserType, userType)
  52 + .eq(NotifyMessageDO::getReadStatus, false));
56 53 }
57 54  
58   - default List<NotifyMessageDO> selectUnreadListByUserIdAndUserType(Long userId, Integer userType) {
59   - return selectList(new LambdaQueryWrapperX<NotifyMessageDO>()
  55 + default List<NotifyMessageDO> selectUnreadListByUserIdAndUserType(Long userId, Integer userType, Integer size) {
  56 + return selectList(new QueryWrapperX<NotifyMessageDO>() // 由于要使用 limitN 语句,所以只能用 QueryWrapperX
  57 + .eq("user_id", userId)
  58 + .eq("user_type", userType)
  59 + .eq("read_status", false)
  60 + .orderByDesc("id").limitN(size));
  61 + }
  62 +
  63 + default Long selectUnreadCountByUserIdAndUserType(Long userId, Integer userType) {
  64 + return selectCount(new LambdaQueryWrapperX<NotifyMessageDO>()
60 65 .eq(NotifyMessageDO::getReadStatus, false)
61 66 .eq(NotifyMessageDO::getUserId, userId)
62 67 .eq(NotifyMessageDO::getUserType, userType));
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyTemplateMapper.java
1 1 package cn.iocoder.yudao.module.system.dal.mysql.notify;
2 2  
3   -import java.util.*;
4   -
5 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6   -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
7 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
8   -import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateExportReqVO;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
9 6 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
10 7 import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
11   -import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
12 8 import org.apache.ibatis.annotations.Mapper;
13   -import org.apache.ibatis.annotations.Select;
14 9  
15   -/**
16   - * 站内信模版 Mapper
17   - *
18   - * @author xrcoder
19   - */
20 10 @Mapper
21 11 public interface NotifyTemplateMapper extends BaseMapperX<NotifyTemplateDO> {
22 12  
23   - @Select("SELECT COUNT(*) FROM system_notify_template WHERE update_time > #{maxUpdateTime}")
24   - Long selectCountByUpdateTimeGt(Date maxUpdateTime);
25   -
26 13 default NotifyTemplateDO selectByCode(String code) {
27 14 return selectOne(NotifyTemplateDO::getCode, code);
28 15 }
29 16  
30 17 default PageResult<NotifyTemplateDO> selectPage(NotifyTemplatePageReqVO reqVO) {
31 18 return selectPage(reqVO, new LambdaQueryWrapperX<NotifyTemplateDO>()
32   - .eqIfPresent(NotifyTemplateDO::getCode, reqVO.getCode())
33   - .eqIfPresent(NotifyTemplateDO::getTitle, reqVO.getTitle())
34   - .eqIfPresent(NotifyTemplateDO::getStatus, reqVO.getStatus())
35   - .betweenIfPresent(NotifyTemplateDO::getCreateTime, reqVO.getCreateTime())
36   - .orderByDesc(NotifyTemplateDO::getId));
37   - }
38   -
39   - default List<NotifyTemplateDO> selectList(NotifyTemplateExportReqVO reqVO) {
40   - return selectList(new LambdaQueryWrapperX<NotifyTemplateDO>()
41   - .eqIfPresent(NotifyTemplateDO::getCode, reqVO.getCode())
42   - .eqIfPresent(NotifyTemplateDO::getTitle, reqVO.getTitle())
  19 + .likeIfPresent(NotifyTemplateDO::getCode, reqVO.getCode())
  20 + .likeIfPresent(NotifyTemplateDO::getName, reqVO.getName())
43 21 .eqIfPresent(NotifyTemplateDO::getStatus, reqVO.getStatus())
44 22 .betweenIfPresent(NotifyTemplateDO::getCreateTime, reqVO.getCreateTime())
45 23 .orderByDesc(NotifyTemplateDO::getId));
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsCodeMapper.java
... ... @@ -22,7 +22,7 @@ public interface SmsCodeMapper extends BaseMapperX&lt;SmsCodeDO&gt; {
22 22 .eqIfPresent("scene", scene)
23 23 .eqIfPresent("code", code)
24 24 .orderByDesc("id")
25   - .limit1());
  25 + .limitN(1));
26 26 }
27 27  
28 28 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogService.java
... ... @@ -45,7 +45,7 @@ public interface MailLogService {
45 45 * @param isSend 是否发送成功
46 46 * @return 日志编号
47 47 */
48   - Long createMailLog(Long userId,Integer userType, String toMail,
  48 + Long createMailLog(Long userId, Integer userType, String toMail,
49 49 MailAccountDO account, MailTemplateDO template ,
50 50 String templateContent, Map<String, Object> templateParams, Boolean isSend);
51 51  
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java
... ... @@ -88,8 +88,7 @@ public class MailSendServiceImpl implements MailSendService {
88 88  
89 89 // 校验邮箱是否存在
90 90 mail = checkMail(mail);
91   - // 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
92   - List<KeyValue<String, Object>> newTemplateParams = buildTemplateParams(template, templateParams);
  91 + checkTemplateParams(template, templateParams);
93 92  
94 93 // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
95 94 Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus());
... ... @@ -152,21 +151,19 @@ public class MailSendServiceImpl implements MailSendService {
152 151 }
153 152  
154 153 /**
155   - * 将参数模板,处理成有序的 KeyValue 数组
  154 + * 校验邮件参数是否确实
156 155 *
157 156 * @param template 邮箱模板
158   - * @param templateParams 原始参数
159   - * @return 处理后的参数
  157 + * @param templateParams 参数列表
160 158 */
161 159 @VisibleForTesting
162   - public List<KeyValue<String, Object>> buildTemplateParams(MailTemplateDO template, Map<String, Object> templateParams) {
163   - return template.getParams().stream().map(key -> {
  160 + public void checkTemplateParams(MailTemplateDO template, Map<String, Object> templateParams) {
  161 + template.getParams().forEach(key -> {
164 162 Object value = templateParams.get(key);
165 163 if (value == null) {
166 164 throw exception(MAIL_SEND_TEMPLATE_PARAM_MISS, key);
167 165 }
168   - return new KeyValue<>(key, value);
169   - }).collect(Collectors.toList());
  166 + });
170 167 }
171 168  
172 169 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyLogService.java deleted
1   -package cn.iocoder.yudao.module.system.service.notify;
2   -
3   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.module.system.controller.admin.notify.vo.log.NotifyLogPageReqVO;
5   -import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
6   -
7   -/**
8   - * 站内信日志 Service 接口
9   - *
10   - * @author LuoWenFeng
11   - */
12   -public interface NotifyLogService {
13   -
14   - // TODO @LuoWenFeng:NotifyLogService=》NotifyMessageService
15   -
16   - /**
17   - * 获得站内信发送分页
18   - *
19   - * @param pageReqVO 分页查询
20   - * @return 站内信分页
21   - */
22   - PageResult<NotifyMessageDO> getNotifyMessageSendPage(NotifyLogPageReqVO pageReqVO);
23   -
24   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyLogServiceImpl.java deleted
1   -package cn.iocoder.yudao.module.system.service.notify;
2   -
3   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.module.system.controller.admin.notify.vo.log.NotifyLogPageReqVO;
5   -import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
6   -import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyMessageMapper;
7   -import org.springframework.stereotype.Service;
8   -import org.springframework.validation.annotation.Validated;
9   -
10   -import javax.annotation.Resource;
11   -
12   -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
13   -
14   -/**
15   - * <p>
16   - * 站内信日志 Service 实现类
17   - *
18   - * </p>
19   - *
20   - * @author LuoWenFeng
21   - */
22   -@Service
23   -@Validated
24   -public class NotifyLogServiceImpl implements NotifyLogService {
25   -
26   - @Resource
27   - private NotifyMessageMapper notifyMessageMapper;
28   -
29   - @Override
30   - public PageResult<NotifyMessageDO> getNotifyMessageSendPage(NotifyLogPageReqVO pageReqVO) {
31   - return notifyMessageMapper.selectSendPage(pageReqVO, getLoginUserId());
32   - }
33   -
34   -
35   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyMessageService.java
1 1 package cn.iocoder.yudao.module.system.service.notify;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
4 5 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
5 6 import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
  7 +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
6 8  
7 9 import java.util.Collection;
8 10 import java.util.List;
  11 +import java.util.Map;
9 12  
10 13 /**
11 14 * 站内信 Service 接口
... ... @@ -15,68 +18,80 @@ import java.util.List;
15 18 public interface NotifyMessageService {
16 19  
17 20 /**
18   - * 获得站内信
  21 + * 创建站内信
19 22 *
20   - * @param id 编号
21   - * @return 站内信
  23 + * @param userId 用户编号
  24 + * @param userType 用户类型
  25 + * @param template 模版信息
  26 + * @param templateContent 模版内容
  27 + * @param templateParams 模版参数
  28 + * @return 站内信编号
22 29 */
23   - NotifyMessageDO getNotifyMessage(Long id);
  30 + Long createNotifyMessage(Long userId, Integer userType,
  31 + NotifyTemplateDO template, String templateContent, Map<String, Object> templateParams);
24 32  
25 33 /**
26   - * 获得站内信列表
  34 + * 获得站内信分页
27 35 *
28   - * @param ids 编号
29   - * @return 站内信列表
  36 + * @param pageReqVO 分页查询
  37 + * @return 站内信分页
30 38 */
31   - List<NotifyMessageDO> getNotifyMessageList(Collection<Long> ids);
  39 + PageResult<NotifyMessageDO> getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO);
32 40  
33 41 /**
34   - * 获得站内信集合
  42 + * 获得【我的】站内信分页
35 43 *
36 44 * @param pageReqVO 分页查询
  45 + * @param userId 用户编号
  46 + * @param userType 用户类型
37 47 * @return 站内信分页
38 48 */
39   - List<NotifyMessageDO> getNotifyMessageList(NotifyMessagePageReqVO pageReqVO, Integer size);
  49 + PageResult<NotifyMessageDO> getMyMyNotifyMessagePage(NotifyMessageMyPageReqVO pageReqVO, Long userId, Integer userType);
40 50  
41 51 /**
42   - * 获得站内信分页
  52 + * 获得站内信
43 53 *
44   - * @param pageReqVO 分页查询
45   - * @return 站内信分页
  54 + * @param id 编号
  55 + * @return 站内信
46 56 */
47   - PageResult<NotifyMessageDO> getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO);
  57 + NotifyMessageDO getNotifyMessage(Long id);
48 58  
49 59 /**
50   - * 统计用户未读站内信条数
  60 + * 获得【我的】未读站内信列表
51 61 *
52   - * @param userId 用户ID
  62 + * @param userId 用户编号
53 63 * @param userType 用户类型
54   - * @return 返回未读站内信条数
  64 + * @param size 数量
  65 + * @return 站内信列表
55 66 */
56   - Long getUnreadNotifyMessageCount(Long userId, Integer userType);
  67 + List<NotifyMessageDO> getUnreadNotifyMessageList(Long userId, Integer userType, Integer size);
57 68  
58 69 /**
59   - * 修改站内信阅读状态
  70 + * 统计用户未读站内信条数
60 71 *
61   - * @param id 站内信编号
62   - * @param status 状态
  72 + * @param userId 用户编号
  73 + * @param userType 用户类型
  74 + * @return 返回未读站内信条数
63 75 */
64   - void updateNotifyMessageReadStatus(Long id, Boolean status);
  76 + Long getUnreadNotifyMessageCount(Long userId, Integer userType);
65 77  
66 78 /**
67   - * 批量修改站内信阅读状态
  79 + * 标记站内信为已读
68 80 *
69 81 * @param ids 站内信编号集合
70   - * @param userId 用户ID
  82 + * @param userId 用户编号
  83 + * @param userType 用户类型
  84 + * @return 更新到的条数
71 85 */
72   - void batchUpdateNotifyMessageReadStatus(Collection<Long> ids, Long userId);
  86 + int updateNotifyMessageRead(Collection<Long> ids, Long userId, Integer userType);
73 87  
74 88 /**
75   - * 批量修改用户所有未读消息标记已读
  89 + * 标记所有站内信为已读
76 90 *
77   - * @param userId 用户ID
  91 + * @param userId 用户编号
78 92 * @param userType 用户类型
  93 + * @return 更新到的条数
79 94 */
80   - void batchUpdateAllNotifyMessageReadStatus(Long userId, Integer userType);
  95 + int updateAllNotifyMessageRead(Long userId, Integer userType);
81 96  
82 97 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyMessageServiceImpl.java
1 1 package cn.iocoder.yudao.module.system.service.notify;
2 2  
3   -import cn.hutool.core.collection.CollUtil;
4   -import cn.hutool.core.util.NumberUtil;
5   -import cn.iocoder.yudao.framework.common.core.KeyValue;
6   -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
7 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
9   -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  4 +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
10 5 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
11 6 import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
12 7 import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
13 8 import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyMessageMapper;
14   -import com.google.common.annotations.VisibleForTesting;
15 9 import org.springframework.stereotype.Service;
16 10 import org.springframework.validation.annotation.Validated;
17 11  
18 12 import javax.annotation.Resource;
19 13 import java.util.Collection;
20   -import java.util.Date;
21 14 import java.util.List;
22 15 import java.util.Map;
23   -import java.util.stream.Collectors;
24 16  
25 17 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
26   -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
27   -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
28 18  
29 19 /**
30 20 * 站内信 Service 实现类
... ... @@ -38,142 +28,50 @@ public class NotifyMessageServiceImpl implements NotifyMessageService {
38 28 @Resource
39 29 private NotifyMessageMapper notifyMessageMapper;
40 30  
41   - @Resource
42   - private NotifyTemplateService notifyTemplateService;
43   -
44   -
45   - @VisibleForTesting
46   - public NotifyTemplateDO checkNotifyTemplateValid(String templateCode) {
47   - // 获得站内信模板。考虑到效率,从缓存中获取
48   - NotifyTemplateDO template = notifyTemplateService.getNotifyTemplateByCodeFromCache(templateCode);
49   - // 站内信模板不存在
50   - if (template == null) {
51   - throw exception(NOTIFY_TEMPLATE_NOT_EXISTS);
52   - }
53   - return template;
54   - }
55   -
56   - /**
57   - * 将参数模板,处理成有序的 KeyValue 数组
58   - *
59   - * @param template 站内信模板
60   - * @param templateParams 原始参数
61   - * @return 处理后的参数
62   - */
63   - @VisibleForTesting
64   - public List<KeyValue<String, Object>> buildTemplateParams(NotifyTemplateDO template, Map<String, Object> templateParams) {
65   - return template.getParams().stream().map(key -> {
66   - Object value = templateParams.get(key);
67   - if (value == null) {
68   - throw exception(NOTIFY_TEMPLATE_PARAM_MISS, key);
69   - }
70   - return new KeyValue<>(key, value);
71   - }).collect(Collectors.toList());
72   - }
73   -
74   - private void validateNotifyMessageExists(Long id) {
75   - if (notifyMessageMapper.selectById(id) == null) {
76   - throw exception(NOTIFY_MESSAGE_NOT_EXISTS);
77   - }
  31 + @Override
  32 + public Long createNotifyMessage(Long userId, Integer userType,
  33 + NotifyTemplateDO template, String templateContent, Map<String, Object> templateParams) {
  34 + NotifyMessageDO message = new NotifyMessageDO().setUserId(userId).setUserType(userType)
  35 + .setTemplateId(template.getId()).setTemplateCode(template.getCode())
  36 + .setTemplateType(template.getType()).setTemplateNickname(template.getNickname())
  37 + .setTemplateContent(templateContent).setTemplateParams(templateParams).setReadStatus(false);
  38 + notifyMessageMapper.insert(message);
  39 + return message.getId();
78 40 }
79 41  
80 42 @Override
81   - public NotifyMessageDO getNotifyMessage(Long id) {
82   - return notifyMessageMapper.selectById(id);
  43 + public PageResult<NotifyMessageDO> getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO) {
  44 + return notifyMessageMapper.selectPage(pageReqVO);
83 45 }
84 46  
85 47 @Override
86   - public List<NotifyMessageDO> getNotifyMessageList(Collection<Long> ids) {
87   - return notifyMessageMapper.selectBatchIds(ids);
  48 + public PageResult<NotifyMessageDO> getMyMyNotifyMessagePage(NotifyMessageMyPageReqVO pageReqVO, Long userId, Integer userType) {
  49 + return notifyMessageMapper.selectPage(pageReqVO, userId, userType);
88 50 }
89 51  
90 52 @Override
91   - public List<NotifyMessageDO> getNotifyMessageList(NotifyMessagePageReqVO pageReqVO, Integer size) {
92   - return notifyMessageMapper.selectList(pageReqVO, size, getLoginUserId(), UserTypeEnum.ADMIN.getValue());
  53 + public NotifyMessageDO getNotifyMessage(Long id) {
  54 + return notifyMessageMapper.selectById(id);
93 55 }
94 56  
95 57 @Override
96   - public PageResult<NotifyMessageDO> getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO) {
97   - return notifyMessageMapper.selectPage(pageReqVO, getLoginUserId(), UserTypeEnum.ADMIN.getValue());
  58 + public List<NotifyMessageDO> getUnreadNotifyMessageList(Long userId, Integer userType, Integer size) {
  59 + return notifyMessageMapper.selectUnreadListByUserIdAndUserType(userId, userType, size);
98 60 }
99 61  
100   - /**
101   - * 统计用户未读站内信条数
102   - *
103   - * @param userId 用户ID
104   - * @param userType 用户类型
105   - * @return 返回未读站内信条数
106   - */
107 62 @Override
108 63 public Long getUnreadNotifyMessageCount(Long userId, Integer userType) {
109 64 return notifyMessageMapper.selectUnreadCountByUserIdAndUserType(userId, userType);
110 65 }
111 66  
112   - /**
113   - * 修改站内信阅读状态
114   - *
115   - * @param id 站内信编号
116   - * @param status 状态
117   - */
118   - @Override
119   - public void updateNotifyMessageReadStatus(Long id, Boolean status) {
120   - // 校验消息是否存在
121   - this.validateNotifyMessageExists(id);
122   - // 更新状态
123   - batchUpdateReadStatus(CollectionUtils.singleton(id));
124   - }
125   -
126   - /**
127   - * 批量修改站内信阅读状态
128   - *
129   - * @param ids 站内信编号集合
130   - * @param userId 用户ID
131   - */
132 67 @Override
133   - public void batchUpdateNotifyMessageReadStatus(Collection<Long> ids, Long userId) {
134   - List<NotifyMessageDO> list = getNotifyMessageList(ids);
135   - if (CollUtil.isEmpty(list)) {
136   - throw exception(NOTIFY_MESSAGE_NOT_EXISTS);
137   - }
138   - // 验证站内信是否是属于用户
139   - for (NotifyMessageDO messageDO : list) {
140   - checkNotifyMessageIdValid(messageDO, userId);
141   - }
142   - batchUpdateReadStatus(ids);
143   - }
144   -
145   - @VisibleForTesting
146   - public void checkNotifyMessageIdValid(NotifyMessageDO notifyMessageDO, Long userId) {
147   - if (!NumberUtil.equals(notifyMessageDO.getUserId(), userId)) {
148   - throw exception(NOTIFY_MESSAGE_ID_PARAM_ERROR);
149   - }
  68 + public int updateNotifyMessageRead(Collection<Long> ids, Long userId, Integer userType) {
  69 + return notifyMessageMapper.updateListRead(ids, userId, userType);
150 70 }
151 71  
152   - /**
153   - * 批量修改用户所有未读消息标记已读
154   - *
155   - * @param userId 用户ID
156   - * @param userType 用户类型
157   - */
158 72 @Override
159   - public void batchUpdateAllNotifyMessageReadStatus(Long userId, Integer userType) {
160   - List<NotifyMessageDO> list = notifyMessageMapper.selectUnreadListByUserIdAndUserType(userId, userType);
161   - if (CollUtil.isNotEmpty(list)) {
162   - batchUpdateReadStatus(CollectionUtils.convertList(list, NotifyMessageDO::getId));
163   - }
164   - }
165   -
166   - /**
167   - * 批量修改阅读状态为已读
168   - *
169   - * @param ids 站内变编号数组
170   - */
171   - private void batchUpdateReadStatus(Collection<Long> ids) {
172   - NotifyMessageDO updateObj = new NotifyMessageDO();
173   - updateObj.setReadStatus(true);
174   - updateObj.setReadTime(new Date());
175   - // TODO @luowenfeng:涉及到 mybatis 的操作,都要隐藏到 mapper 中;
176   - notifyMessageMapper.update(updateObj, new LambdaQueryWrapperX<NotifyMessageDO>().in(NotifyMessageDO::getId, ids));
  73 + public int updateAllNotifyMessageRead(Long userId, Integer userType) {
  74 + return notifyMessageMapper.updateListRead(userId, userType);
177 75 }
178 76  
179 77 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifySendService.java
... ... @@ -3,9 +3,13 @@ package cn.iocoder.yudao.module.system.service.notify;
3 3 import java.util.List;
4 4 import java.util.Map;
5 5  
  6 +/**
  7 + * 站内信发送 Service 接口
  8 + *
  9 + * @author xrcoder
  10 + */
6 11 public interface NotifySendService {
7 12  
8   -
9 13 /**
10 14 * 发送单条站内信给管理后台的用户
11 15 *
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifySendServiceImpl.java
1 1 package cn.iocoder.yudao.module.system.service.notify;
2 2  
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 4 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
4   -import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
5 5 import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
6   -import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
7   -import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyMessageMapper;
8   -import cn.iocoder.yudao.module.system.service.user.AdminUserService;
9 6 import com.google.common.annotations.VisibleForTesting;
10 7 import lombok.extern.slf4j.Slf4j;
11 8 import org.springframework.stereotype.Service;
12 9 import org.springframework.validation.annotation.Validated;
13 10  
14 11 import javax.annotation.Resource;
15   -import java.util.Date;
16 12 import java.util.Map;
  13 +import java.util.Objects;
17 14  
18 15 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
19   -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
20   -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTICE_NOT_FOUND;
  16 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
21 17  
22   -// TODO @luowenfeng:可以直接合并到 NotifyMessageService 中;之前 sms 台复杂,所以没合并。
23 18 /**
24 19 * 站内信发送 Service 实现类
25 20 *
... ... @@ -34,10 +29,7 @@ public class NotifySendServiceImpl implements NotifySendService {
34 29 private NotifyTemplateService notifyTemplateService;
35 30  
36 31 @Resource
37   - private NotifyMessageMapper notifyMessageMapper;
38   -
39   - @Resource
40   - private AdminUserService userService;
  32 + private NotifyMessageService notifyMessageService;
41 33  
42 34 @Override
43 35 public Long sendSingleNotifyToAdmin(Long userId, String templateCode, Map<String, Object> templateParams) {
... ... @@ -51,38 +43,44 @@ public class NotifySendServiceImpl implements NotifySendService {
51 43  
52 44 @Override
53 45 public Long sendSingleNotify(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams) {
54   - // 校验短信模板是否合法
55   - NotifyTemplateDO template = this.checkNotifyTemplateValid(templateCode);
56   - String content = notifyTemplateService.formatNotifyTemplateContent(template.getContent(), templateParams);
57   - // 获得用户
58   - AdminUserDO sendUser = userService.getUser(getLoginUserId());
  46 + // 校验模版
  47 + NotifyTemplateDO template = checkNotifyTemplateValid(templateCode);
  48 + if (Objects.equals(template.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
  49 + log.info("[sendSingleNotify][模版({})已经关闭,无法给用户({}/{})发送]", templateCode, userId, userType);
  50 + return null;
  51 + }
  52 + // 校验参数
  53 + checkTemplateParams(template, templateParams);
59 54  
60   - // todo 模板状态未开启时的业务;如果未开启,就直接 return 好了;
61   - NotifyMessageDO notifyMessageDO = new NotifyMessageDO();
62   - notifyMessageDO.setContent(content);
63   - notifyMessageDO.setTitle(template.getTitle());
64   - notifyMessageDO.setReadStatus(false);
65   - notifyMessageDO.setTemplateId(template.getId());
66   - notifyMessageDO.setTemplateCode(templateCode);
67   - notifyMessageDO.setUserId(userId);
68   - notifyMessageDO.setUserType(userType);
69   - notifyMessageDO.setSendTime(new Date());
70   - notifyMessageDO.setSendUserId(sendUser.getId());
71   - notifyMessageDO.setSendUserName(sendUser.getUsername());
72   - notifyMessageMapper.insert(notifyMessageDO);
73   - return notifyMessageDO.getId();
  55 + // 发送站内信
  56 + String content = notifyTemplateService.formatNotifyTemplateContent(template.getContent(), templateParams);
  57 + return notifyMessageService.createNotifyMessage(userId, userType, template, content, templateParams);
74 58 }
75 59  
76   - // 此注解的含义
77 60 @VisibleForTesting
78 61 public NotifyTemplateDO checkNotifyTemplateValid(String templateCode) {
79   - // 获得短信模板。考虑到效率,从缓存中获取
  62 + // 获得站内信模板。考虑到效率,从缓存中获取
80 63 NotifyTemplateDO template = notifyTemplateService.getNotifyTemplateByCodeFromCache(templateCode);
81   - // 短信模板不存在
  64 + // 站内信模板不存在
82 65 if (template == null) {
83 66 throw exception(NOTICE_NOT_FOUND);
84 67 }
85 68 return template;
86 69 }
87 70  
  71 + /**
  72 + * 校验站内信模版参数是否确实
  73 + *
  74 + * @param template 邮箱模板
  75 + * @param templateParams 参数列表
  76 + */
  77 + @VisibleForTesting
  78 + public void checkTemplateParams(NotifyTemplateDO template, Map<String, Object> templateParams) {
  79 + template.getParams().forEach(key -> {
  80 + Object value = templateParams.get(key);
  81 + if (value == null) {
  82 + throw exception(NOTIFY_SEND_TEMPLATE_PARAM_MISS, key);
  83 + }
  84 + });
  85 + }
88 86 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateService.java
... ... @@ -2,14 +2,11 @@ package cn.iocoder.yudao.module.system.service.notify;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO;
5   -import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateExportReqVO;
6 5 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
7 6 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
8 7 import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
9 8  
10 9 import javax.validation.Valid;
11   -import java.util.Collection;
12   -import java.util.List;
13 10 import java.util.Map;
14 11  
15 12 /**
... ... @@ -17,7 +14,6 @@ import java.util.Map;
17 14 *
18 15 * @author xrcoder
19 16 */
20   -// TODO 芋艿:缺少单测,可以参考 SmsTemplateServiceTest 写下
21 17 public interface NotifyTemplateService {
22 18  
23 19 /**
... ... @@ -33,16 +29,6 @@ public interface NotifyTemplateService {
33 29 */
34 30 NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code);
35 31  
36   -
37   - /**
38   - * 格式化站内信内容
39   - *
40   - * @param content 站内信模板的内容
41   - * @param params 站内信内容的参数
42   - * @return 格式化后的内容
43   - */
44   - String formatNotifyTemplateContent(String content, Map<String, Object> params);
45   -
46 32 /**
47 33 * 创建站内信模版
48 34 *
... ... @@ -74,14 +60,6 @@ public interface NotifyTemplateService {
74 60 NotifyTemplateDO getNotifyTemplate(Long id);
75 61  
76 62 /**
77   - * 获得站内信模版列表
78   - *
79   - * @param ids 编号
80   - * @return 站内信模版列表
81   - */
82   - List<NotifyTemplateDO> getNotifyTemplateList(Collection<Long> ids);
83   -
84   - /**
85 63 * 获得站内信模版分页
86 64 *
87 65 * @param pageReqVO 分页查询
... ... @@ -90,11 +68,12 @@ public interface NotifyTemplateService {
90 68 PageResult<NotifyTemplateDO> getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO);
91 69  
92 70 /**
93   - * 获得站内信模版列表, 用于 Excel 导出
  71 + * 格式化站内信内容
94 72 *
95   - * @param exportReqVO 查询条件
96   - * @return 站内信模版列表
  73 + * @param content 站内信模板的内容
  74 + * @param params 站内信内容的参数
  75 + * @return 格式化后的内容
97 76 */
98   - List<NotifyTemplateDO> getNotifyTemplateList(NotifyTemplateExportReqVO exportReqVO);
  77 + String formatNotifyTemplateContent(String content, Map<String, Object> params);
99 78  
100 79 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImpl.java
1 1 package cn.iocoder.yudao.module.system.service.notify;
2 2  
3   -import cn.hutool.core.collection.CollUtil;
4 3 import cn.hutool.core.util.ReUtil;
5 4 import cn.hutool.core.util.StrUtil;
6 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 7 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO;
9   -import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateExportReqVO;
10 8 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
11 9 import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
12 10 import cn.iocoder.yudao.module.system.convert.notify.NotifyTemplateConvert;
... ... @@ -15,20 +13,17 @@ import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyTemplateMapper;
15 13 import cn.iocoder.yudao.module.system.mq.producer.notify.NotifyProducer;
16 14 import com.google.common.annotations.VisibleForTesting;
17 15 import lombok.extern.slf4j.Slf4j;
18   -import org.springframework.scheduling.annotation.Scheduled;
19 16 import org.springframework.stereotype.Service;
20 17 import org.springframework.validation.annotation.Validated;
21 18  
  19 +import javax.annotation.PostConstruct;
22 20 import javax.annotation.Resource;
23   -import java.util.Collection;
24   -import java.util.Date;
25 21 import java.util.List;
26 22 import java.util.Map;
27 23 import java.util.regex.Pattern;
28 24  
29 25 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
30   -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_CODE_DUPLICATE;
31   -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS;
  26 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
32 27  
33 28 /**
34 29 * 站内信模版 Service 实现类
... ... @@ -41,12 +36,6 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEM
41 36 public class NotifyTemplateServiceImpl implements NotifyTemplateService {
42 37  
43 38 /**
44   - * 定时执行 {@link #schedulePeriodicRefresh()} 的周期
45   - * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高
46   - */
47   - private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
48   -
49   - /**
50 39 * 正则表达式,匹配 {} 中的变量
51 40 */
52 41 private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}");
... ... @@ -66,81 +55,24 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService {
66 55 private volatile Map<String, NotifyTemplateDO> notifyTemplateCache;
67 56  
68 57 /**
69   - * 缓存站内信模板的最大更新时间,用于后续的增量轮询,判断是否有更新
70   - */
71   - private volatile Date maxUpdateTime;
72   -
73   - /**
74 58 * 初始化站内信模板的本地缓存
75 59 */
76 60 @Override
  61 + @PostConstruct
77 62 public void initLocalCache() {
78   - // 获取站内信模板列表,如果有更新
79   - List<NotifyTemplateDO> notifyTemplateList = this.loadNotifyTemplateIfUpdate(maxUpdateTime);
80   - if (CollUtil.isEmpty(notifyTemplateList)) {
81   - return;
82   - }
83   -
84   - // 写入缓存
85   - notifyTemplateCache = CollectionUtils.convertMap(notifyTemplateList, NotifyTemplateDO::getCode);
86   - maxUpdateTime = CollectionUtils.getMaxValue(notifyTemplateList, NotifyTemplateDO::getUpdateTime);
87   - log.info("[initLocalCache][初始化 NotifyTemplate 数量为 {}]", notifyTemplateList.size());
88   - }
89   -
90   - /**
91   - * 如果站内信模板发生变化,从数据库中获取最新的全量站内信模板。
92   - * 如果未发生变化,则返回空
93   - *
94   - * @param maxUpdateTime 当前站内信模板的最大更新时间
95   - * @return 站内信模板列表
96   - */
97   - private List<NotifyTemplateDO> loadNotifyTemplateIfUpdate(Date maxUpdateTime) {
98   - // 第一步,判断是否要更新。
99   - if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据
100   - log.info("[loadNotifyTemplateIfUpdate][首次加载全量站内信模板]");
101   - } else { // 判断数据库中是否有更新的站内信模板
102   - if (notifyTemplateMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
103   - return null;
104   - }
105   - log.info("[loadNotifyTemplateIfUpdate][增量加载全量站内信模板]");
106   - }
107   - // 第二步,如果有更新,则从数据库加载所有站内信模板
108   - return notifyTemplateMapper.selectList();
109   - }
  63 + // 第一步:查询数据
  64 + List<NotifyTemplateDO> templates = notifyTemplateMapper.selectList();
  65 + log.info("[initLocalCache][缓存站内信模版,数量为:{}]", templates.size());
110 66  
111   - @Scheduled(fixedDelay = SCHEDULER_PERIOD)
112   - public void schedulePeriodicRefresh() {
113   - initLocalCache();
  67 + // 第二步:构建缓存
  68 + notifyTemplateCache = CollectionUtils.convertMap(templates, NotifyTemplateDO::getCode);
114 69 }
115 70  
116   - /**
117   - * 获得站内信模板,从缓存中
118   - *
119   - * @param code 模板编码
120   - * @return 站内信模板
121   - */
122 71 @Override
123 72 public NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code) {
124 73 return notifyTemplateCache.get(code);
125 74 }
126 75  
127   - /**
128   - * 格式化站内信内容
129   - *
130   - * @param content 站内信模板的内容
131   - * @param params 站内信内容的参数
132   - * @return 格式化后的内容
133   - */
134   - @Override
135   - public String formatNotifyTemplateContent(String content, Map<String, Object> params) {
136   - return StrUtil.format(content, params);
137   - }
138   -
139   - @VisibleForTesting
140   - public List<String> parseTemplateContentParams(String content) {
141   - return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
142   - }
143   -
144 76 @Override
145 77 public Long createNotifyTemplate(NotifyTemplateCreateReqVO createReqVO) {
146 78 // 校验站内信编码是否重复
... ... @@ -150,32 +82,37 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService {
150 82 NotifyTemplateDO notifyTemplate = NotifyTemplateConvert.INSTANCE.convert(createReqVO);
151 83 notifyTemplate.setParams(parseTemplateContentParams(notifyTemplate.getContent()));
152 84 notifyTemplateMapper.insert(notifyTemplate);
  85 +
153 86 // 发送刷新消息
154 87 notifyProducer.sendNotifyTemplateRefreshMessage();
155   - // 返回
156 88 return notifyTemplate.getId();
157 89 }
158 90  
159 91 @Override
160 92 public void updateNotifyTemplate(NotifyTemplateUpdateReqVO updateReqVO) {
161 93 // 校验存在
162   - this.validateNotifyTemplateExists(updateReqVO.getId());
  94 + validateNotifyTemplateExists(updateReqVO.getId());
163 95 // 校验站内信编码是否重复
164 96 checkNotifyTemplateCodeDuplicate(updateReqVO.getId(), updateReqVO.getCode());
165 97  
166 98 // 更新
167 99 NotifyTemplateDO updateObj = NotifyTemplateConvert.INSTANCE.convert(updateReqVO);
168 100 updateObj.setParams(parseTemplateContentParams(updateObj.getContent()));
169   -
170 101 notifyTemplateMapper.updateById(updateObj);
  102 +
171 103 // 发送刷新消息
172 104 notifyProducer.sendNotifyTemplateRefreshMessage();
173 105 }
174 106  
  107 + @VisibleForTesting
  108 + public List<String> parseTemplateContentParams(String content) {
  109 + return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
  110 + }
  111 +
175 112 @Override
176 113 public void deleteNotifyTemplate(Long id) {
177 114 // 校验存在
178   - this.validateNotifyTemplateExists(id);
  115 + validateNotifyTemplateExists(id);
179 116 // 删除
180 117 notifyTemplateMapper.deleteById(id);
181 118 // 发送刷新消息
... ... @@ -194,20 +131,10 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService {
194 131 }
195 132  
196 133 @Override
197   - public List<NotifyTemplateDO> getNotifyTemplateList(Collection<Long> ids) {
198   - return notifyTemplateMapper.selectBatchIds(ids);
199   - }
200   -
201   - @Override
202 134 public PageResult<NotifyTemplateDO> getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO) {
203 135 return notifyTemplateMapper.selectPage(pageReqVO);
204 136 }
205 137  
206   - @Override
207   - public List<NotifyTemplateDO> getNotifyTemplateList(NotifyTemplateExportReqVO exportReqVO) {
208   - return notifyTemplateMapper.selectList(exportReqVO);
209   - }
210   -
211 138 @VisibleForTesting
212 139 public void checkNotifyTemplateCodeDuplicate(Long id, String code) {
213 140 NotifyTemplateDO template = notifyTemplateMapper.selectByCode(code);
... ... @@ -222,4 +149,16 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService {
222 149 throw exception(NOTIFY_TEMPLATE_CODE_DUPLICATE, code);
223 150 }
224 151 }
  152 +
  153 + /**
  154 + * 格式化站内信内容
  155 + *
  156 + * @param content 站内信模板的内容
  157 + * @param params 站内信内容的参数
  158 + * @return 格式化后的内容
  159 + */
  160 + @Override
  161 + public String formatNotifyTemplateContent(String content, Map<String, Object> params) {
  162 + return StrUtil.format(content, params);
  163 + }
225 164 }
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java
... ... @@ -145,7 +145,7 @@ class MailSendServiceImplTest extends BaseMockitoUnitTest {
145 145 }
146 146  
147 147 @Test
148   - public void testBuildTemplateParams_paramMiss() {
  148 + public void testCheckTemplateParams_paramMiss() {
149 149 // 准备参数
150 150 MailTemplateDO template = randomPojo(MailTemplateDO.class,
151 151 o -> o.setParams(Lists.newArrayList("code")));
... ... @@ -153,7 +153,7 @@ class MailSendServiceImplTest extends BaseMockitoUnitTest {
153 153 // mock 方法
154 154  
155 155 // 调用,并断言异常
156   - assertServiceException(() -> mailSendService.buildTemplateParams(template, templateParams),
  156 + assertServiceException(() -> mailSendService.checkTemplateParams(template, templateParams),
157 157 MAIL_SEND_TEMPLATE_PARAM_MISS, "code");
158 158 }
159 159  
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifyMessageServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.service.notify;
  2 +
  3 +import cn.hutool.core.map.MapUtil;
  4 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants;
  7 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  8 +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
  9 +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
  10 +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
  11 +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
  12 +import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyMessageMapper;
  13 +import com.baomidou.mybatisplus.annotation.DbType;
  14 +import org.junit.jupiter.api.Test;
  15 +import org.springframework.context.annotation.Import;
  16 +
  17 +import javax.annotation.Resource;
  18 +import java.util.Arrays;
  19 +import java.util.Collection;
  20 +import java.util.List;
  21 +import java.util.Map;
  22 +
  23 +import static cn.hutool.core.util.RandomUtil.randomEle;
  24 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
  25 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
  26 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  27 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  28 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  29 +import static org.junit.jupiter.api.Assertions.*;
  30 +
  31 +/**
  32 +* {@link NotifyMessageServiceImpl} 的单元测试类
  33 +*
  34 +* @author 芋道源码
  35 +*/
  36 +@Import(NotifyMessageServiceImpl.class)
  37 +public class NotifyMessageServiceImplTest extends BaseDbUnitTest {
  38 +
  39 + @Resource
  40 + private NotifyMessageServiceImpl notifyMessageService;
  41 +
  42 + @Resource
  43 + private NotifyMessageMapper notifyMessageMapper;
  44 +
  45 + @Test
  46 + public void testCreateNotifyMessage_success() {
  47 + // 准备参数
  48 + Long userId = randomLongId();
  49 + Integer userType = randomEle(UserTypeEnum.values()).getValue();
  50 + NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class);
  51 + String templateContent = randomString();
  52 + Map<String, Object> templateParams = randomTemplateParams();
  53 + // mock 方法
  54 +
  55 + // 调用
  56 + Long messageId = notifyMessageService.createNotifyMessage(userId, userType,
  57 + template, templateContent, templateParams);
  58 + // 断言
  59 + NotifyMessageDO message = notifyMessageMapper.selectById(messageId);
  60 + assertNotNull(message);
  61 + assertEquals(userId, message.getUserId());
  62 + assertEquals(userType, message.getUserType());
  63 + assertEquals(template.getId(), message.getTemplateId());
  64 + assertEquals(template.getCode(), message.getTemplateCode());
  65 + assertEquals(template.getType(), message.getTemplateType());
  66 + assertEquals(template.getNickname(), message.getTemplateNickname());
  67 + assertEquals(templateContent, message.getTemplateContent());
  68 + assertEquals(templateParams, message.getTemplateParams());
  69 + assertEquals(false, message.getReadStatus());
  70 + assertNull(message.getReadTime());
  71 + }
  72 +
  73 + @Test
  74 + public void testGetNotifyMessagePage() {
  75 + // mock 数据
  76 + NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
  77 + o.setUserId(1L);
  78 + o.setUserType(UserTypeEnum.ADMIN.getValue());
  79 + o.setTemplateCode("test_01");
  80 + o.setTemplateType(10);
  81 + o.setCreateTime(buildTime(2022, 1, 2));
  82 + o.setTemplateParams(randomTemplateParams());
  83 + });
  84 + notifyMessageMapper.insert(dbNotifyMessage);
  85 + // 测试 userId 不匹配
  86 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
  87 + // 测试 userType 不匹配
  88 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
  89 + // 测试 templateCode 不匹配
  90 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setTemplateCode("test_11")));
  91 + // 测试 templateType 不匹配
  92 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setTemplateType(20)));
  93 + // 测试 createTime 不匹配
  94 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setCreateTime(buildTime(2022, 2, 1))));
  95 + // 准备参数
  96 + NotifyMessagePageReqVO reqVO = new NotifyMessagePageReqVO();
  97 + reqVO.setUserId(1L);
  98 + reqVO.setUserType(UserTypeEnum.ADMIN.getValue());
  99 + reqVO.setTemplateCode("est_01");
  100 + reqVO.setTemplateType(10);
  101 + reqVO.setCreateTime(buildBetweenTime(2022, 1, 1, 2022, 1, 10));
  102 +
  103 + // 调用
  104 + PageResult<NotifyMessageDO> pageResult = notifyMessageService.getNotifyMessagePage(reqVO);
  105 + // 断言
  106 + assertEquals(1, pageResult.getTotal());
  107 + assertEquals(1, pageResult.getList().size());
  108 + assertPojoEquals(dbNotifyMessage, pageResult.getList().get(0));
  109 + }
  110 +
  111 + @Test
  112 + public void testGetMyNotifyMessagePage() {
  113 + // mock 数据
  114 + NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
  115 + o.setUserId(1L);
  116 + o.setUserType(UserTypeEnum.ADMIN.getValue());
  117 + o.setReadStatus(true);
  118 + o.setCreateTime(buildTime(2022, 1, 2));
  119 + o.setTemplateParams(randomTemplateParams());
  120 + });
  121 + notifyMessageMapper.insert(dbNotifyMessage);
  122 + // 测试 userId 不匹配
  123 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
  124 + // 测试 userType 不匹配
  125 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
  126 + // 测试 readStatus 不匹配
  127 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(false)));
  128 + // 测试 createTime 不匹配
  129 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setCreateTime(buildTime(2022, 2, 1))));
  130 + // 准备参数
  131 + Long userId = 1L;
  132 + Integer userType = UserTypeEnum.ADMIN.getValue();
  133 + NotifyMessageMyPageReqVO reqVO = new NotifyMessageMyPageReqVO();
  134 + reqVO.setReadStatus(true);
  135 + reqVO.setCreateTime(buildBetweenTime(2022, 1, 1, 2022, 1, 10));
  136 +
  137 + // 调用
  138 + PageResult<NotifyMessageDO> pageResult = notifyMessageService.getMyMyNotifyMessagePage(reqVO, userId, userType);
  139 + // 断言
  140 + assertEquals(1, pageResult.getTotal());
  141 + assertEquals(1, pageResult.getList().size());
  142 + assertPojoEquals(dbNotifyMessage, pageResult.getList().get(0));
  143 + }
  144 +
  145 + @Test
  146 + public void testGetUnreadNotifyMessageList() {
  147 + SqlConstants.init(DbType.MYSQL);
  148 + // mock 数据
  149 + NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
  150 + o.setUserId(1L);
  151 + o.setUserType(UserTypeEnum.ADMIN.getValue());
  152 + o.setReadStatus(false);
  153 + o.setTemplateParams(randomTemplateParams());
  154 + });
  155 + notifyMessageMapper.insert(dbNotifyMessage);
  156 + // 测试 userId 不匹配
  157 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
  158 + // 测试 userType 不匹配
  159 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
  160 + // 测试 readStatus 不匹配
  161 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true)));
  162 + // 准备参数
  163 + Long userId = 1L;
  164 + Integer userType = UserTypeEnum.ADMIN.getValue();
  165 + Integer size = 10;
  166 +
  167 + // 调用
  168 + List<NotifyMessageDO> list = notifyMessageService.getUnreadNotifyMessageList(userId, userType, size);
  169 + // 断言
  170 + assertEquals(1, list.size());
  171 + assertPojoEquals(dbNotifyMessage, list.get(0));
  172 + }
  173 +
  174 + @Test
  175 + public void testGetUnreadNotifyMessageCount() {
  176 + SqlConstants.init(DbType.MYSQL);
  177 + // mock 数据
  178 + NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
  179 + o.setUserId(1L);
  180 + o.setUserType(UserTypeEnum.ADMIN.getValue());
  181 + o.setReadStatus(false);
  182 + o.setTemplateParams(randomTemplateParams());
  183 + });
  184 + notifyMessageMapper.insert(dbNotifyMessage);
  185 + // 测试 userId 不匹配
  186 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
  187 + // 测试 userType 不匹配
  188 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
  189 + // 测试 readStatus 不匹配
  190 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true)));
  191 + // 准备参数
  192 + Long userId = 1L;
  193 + Integer userType = UserTypeEnum.ADMIN.getValue();
  194 +
  195 + // 调用,并断言
  196 + assertEquals(1, notifyMessageService.getUnreadNotifyMessageCount(userId, userType));
  197 + }
  198 +
  199 + @Test
  200 + public void testUpdateNotifyMessageRead() {
  201 + // mock 数据
  202 + NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
  203 + o.setUserId(1L);
  204 + o.setUserType(UserTypeEnum.ADMIN.getValue());
  205 + o.setReadStatus(false);
  206 + o.setReadTime(null);
  207 + o.setTemplateParams(randomTemplateParams());
  208 + });
  209 + notifyMessageMapper.insert(dbNotifyMessage);
  210 + // 测试 userId 不匹配
  211 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
  212 + // 测试 userType 不匹配
  213 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
  214 + // 测试 readStatus 不匹配
  215 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true)));
  216 + // 准备参数
  217 + Collection<Long> ids = Arrays.asList(dbNotifyMessage.getId(), dbNotifyMessage.getId() + 1,
  218 + dbNotifyMessage.getId() + 2, dbNotifyMessage.getId() + 3);
  219 + Long userId = 1L;
  220 + Integer userType = UserTypeEnum.ADMIN.getValue();
  221 +
  222 + // 调用
  223 + int updateCount = notifyMessageService.updateNotifyMessageRead(ids, userId, userType);
  224 + // 断言
  225 + assertEquals(1, updateCount);
  226 + NotifyMessageDO notifyMessage = notifyMessageMapper.selectById(dbNotifyMessage.getId());
  227 + assertTrue(notifyMessage.getReadStatus());
  228 + assertNotNull(notifyMessage.getReadTime());
  229 + }
  230 +
  231 + @Test
  232 + public void testUpdateAllNotifyMessageRead() {
  233 + // mock 数据
  234 + NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
  235 + o.setUserId(1L);
  236 + o.setUserType(UserTypeEnum.ADMIN.getValue());
  237 + o.setReadStatus(false);
  238 + o.setReadTime(null);
  239 + o.setTemplateParams(randomTemplateParams());
  240 + });
  241 + notifyMessageMapper.insert(dbNotifyMessage);
  242 + // 测试 userId 不匹配
  243 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
  244 + // 测试 userType 不匹配
  245 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
  246 + // 测试 readStatus 不匹配
  247 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true)));
  248 + // 准备参数
  249 + Long userId = 1L;
  250 + Integer userType = UserTypeEnum.ADMIN.getValue();
  251 +
  252 + // 调用
  253 + int updateCount = notifyMessageService.updateAllNotifyMessageRead(userId, userType);
  254 + // 断言
  255 + assertEquals(1, updateCount);
  256 + NotifyMessageDO notifyMessage = notifyMessageMapper.selectById(dbNotifyMessage.getId());
  257 + assertTrue(notifyMessage.getReadStatus());
  258 + assertNotNull(notifyMessage.getReadTime());
  259 + }
  260 +
  261 + private static Map<String, Object> randomTemplateParams() {
  262 + return MapUtil.<String, Object>builder().put(randomString(), randomString())
  263 + .put(randomString(), randomString()).build();
  264 + }
  265 +
  266 +}
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifySendServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.service.notify;
  2 +
  3 +import cn.hutool.core.map.MapUtil;
  4 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  5 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  6 +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
  7 +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
  8 +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
  9 +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
  10 +import org.assertj.core.util.Lists;
  11 +import org.junit.jupiter.api.Test;
  12 +import org.mockito.InjectMocks;
  13 +import org.mockito.Mock;
  14 +
  15 +import java.util.HashMap;
  16 +import java.util.Map;
  17 +
  18 +import static cn.hutool.core.util.RandomUtil.randomEle;
  19 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  20 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  21 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
  22 +import static org.junit.jupiter.api.Assertions.assertEquals;
  23 +import static org.junit.jupiter.api.Assertions.assertNull;
  24 +import static org.mockito.ArgumentMatchers.eq;
  25 +import static org.mockito.Mockito.*;
  26 +
  27 +class NotifySendServiceImplTest extends BaseMockitoUnitTest {
  28 +
  29 + @InjectMocks
  30 + private NotifySendServiceImpl notifySendService;
  31 +
  32 + @Mock
  33 + private NotifyTemplateService notifyTemplateService;
  34 + @Mock
  35 + private NotifyMessageService notifyMessageService;
  36 +
  37 + /**
  38 + * 发送成功,当短信模板开启时
  39 + */
  40 + @Test
  41 + public void testSendSingleNotify_successWhenMailTemplateEnable() {
  42 + // 准备参数
  43 + Long userId = randomLongId();
  44 + Integer userType = randomEle(UserTypeEnum.values()).getValue();
  45 + String templateCode = randomString();
  46 + Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
  47 + .put("op", "login").build();
  48 + // mock NotifyTemplateService 的方法
  49 + NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class, o -> {
  50 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  51 + o.setContent("验证码为{code}, 操作为{op}");
  52 + o.setParams(Lists.newArrayList("code", "op"));
  53 + });
  54 + when(notifyTemplateService.getNotifyTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
  55 + String content = randomString();
  56 + when(notifyTemplateService.formatNotifyTemplateContent(eq(template.getContent()), eq(templateParams)))
  57 + .thenReturn(content);
  58 + // mock NotifyMessageService 的方法
  59 + Long messageId = randomLongId();
  60 + when(notifyMessageService.createNotifyMessage(eq(userId), eq(userType),
  61 + eq(template), eq(content), eq(templateParams))).thenReturn(messageId);
  62 +
  63 + // 调用
  64 + Long resultMessageId = notifySendService.sendSingleNotify(userId, userType, templateCode, templateParams);
  65 + // 断言
  66 + assertEquals(messageId, resultMessageId);
  67 + }
  68 +
  69 + /**
  70 + * 发送成功,当短信模板关闭时
  71 + */
  72 + @Test
  73 + public void testSendSingleMail_successWhenSmsTemplateDisable() {
  74 + // 准备参数
  75 + Long userId = randomLongId();
  76 + Integer userType = randomEle(UserTypeEnum.values()).getValue();
  77 + String templateCode = randomString();
  78 + Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
  79 + .put("op", "login").build();
  80 + // mock NotifyTemplateService 的方法
  81 + NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class, o -> {
  82 + o.setStatus(CommonStatusEnum.DISABLE.getStatus());
  83 + o.setContent("验证码为{code}, 操作为{op}");
  84 + o.setParams(Lists.newArrayList("code", "op"));
  85 + });
  86 + when(notifyTemplateService.getNotifyTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
  87 +
  88 + // 调用
  89 + Long resultMessageId = notifySendService.sendSingleNotify(userId, userType, templateCode, templateParams);
  90 + // 断言
  91 + assertNull(resultMessageId);
  92 + verify(notifyTemplateService, never()).formatNotifyTemplateContent(anyString(), anyMap());
  93 + verify(notifyMessageService, never()).createNotifyMessage(anyLong(), anyInt(), any(), anyString(), anyMap());
  94 + }
  95 +
  96 + @Test
  97 + public void testCheckMailTemplateValid_notExists() {
  98 + // 准备参数
  99 + String templateCode = randomString();
  100 + // mock 方法
  101 +
  102 + // 调用,并断言异常
  103 + assertServiceException(() -> notifySendService.checkNotifyTemplateValid(templateCode),
  104 + NOTICE_NOT_FOUND);
  105 + }
  106 +
  107 + @Test
  108 + public void testCheckTemplateParams_paramMiss() {
  109 + // 准备参数
  110 + NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class,
  111 + o -> o.setParams(Lists.newArrayList("code")));
  112 + Map<String, Object> templateParams = new HashMap<>();
  113 + // mock 方法
  114 +
  115 + // 调用,并断言异常
  116 + assertServiceException(() -> notifySendService.checkTemplateParams(template, templateParams),
  117 + NOTIFY_SEND_TEMPLATE_PARAM_MISS, "code");
  118 + }
  119 +
  120 +
  121 +}
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.service.notify;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  6 +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO;
  7 +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
  8 +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
  9 +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
  10 +import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyTemplateMapper;
  11 +import cn.iocoder.yudao.module.system.mq.producer.notify.NotifyProducer;
  12 +import org.junit.jupiter.api.Test;
  13 +import org.springframework.boot.test.mock.mockito.MockBean;
  14 +import org.springframework.context.annotation.Import;
  15 +
  16 +import javax.annotation.Resource;
  17 +
  18 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
  19 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
  20 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  21 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  22 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  23 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  24 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS;
  25 +import static org.junit.jupiter.api.Assertions.*;
  26 +import static org.mockito.Mockito.verify;
  27 +
  28 +/**
  29 +* {@link NotifyTemplateServiceImpl} 的单元测试类
  30 +*
  31 +* @author 芋道源码
  32 +*/
  33 +@Import(NotifyTemplateServiceImpl.class)
  34 +public class NotifyTemplateServiceImplTest extends BaseDbUnitTest {
  35 +
  36 + @Resource
  37 + private NotifyTemplateServiceImpl notifyTemplateService;
  38 +
  39 + @Resource
  40 + private NotifyTemplateMapper notifyTemplateMapper;
  41 +
  42 + @MockBean
  43 + private NotifyProducer notifyProducer;
  44 +
  45 + @Test
  46 + public void testCreateNotifyTemplate_success() {
  47 + // 准备参数
  48 + NotifyTemplateCreateReqVO reqVO = randomPojo(NotifyTemplateCreateReqVO.class,
  49 + o -> o.setStatus(randomCommonStatus()));
  50 +
  51 + // 调用
  52 + Long notifyTemplateId = notifyTemplateService.createNotifyTemplate(reqVO);
  53 + // 断言
  54 + assertNotNull(notifyTemplateId);
  55 + // 校验记录的属性是否正确
  56 + NotifyTemplateDO notifyTemplate = notifyTemplateMapper.selectById(notifyTemplateId);
  57 + assertPojoEquals(reqVO, notifyTemplate);
  58 + verify(notifyProducer).sendNotifyTemplateRefreshMessage();
  59 + }
  60 +
  61 + @Test
  62 + public void testUpdateNotifyTemplate_success() {
  63 + // mock 数据
  64 + NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class);
  65 + notifyTemplateMapper.insert(dbNotifyTemplate);// @Sql: 先插入出一条存在的数据
  66 + // 准备参数
  67 + NotifyTemplateUpdateReqVO reqVO = randomPojo(NotifyTemplateUpdateReqVO.class, o -> {
  68 + o.setId(dbNotifyTemplate.getId()); // 设置更新的 ID
  69 + o.setStatus(randomCommonStatus());
  70 + });
  71 +
  72 + // 调用
  73 + notifyTemplateService.updateNotifyTemplate(reqVO);
  74 + // 校验是否更新正确
  75 + NotifyTemplateDO notifyTemplate = notifyTemplateMapper.selectById(reqVO.getId()); // 获取最新的
  76 + assertPojoEquals(reqVO, notifyTemplate);
  77 + verify(notifyProducer).sendNotifyTemplateRefreshMessage();
  78 + }
  79 +
  80 + @Test
  81 + public void testUpdateNotifyTemplate_notExists() {
  82 + // 准备参数
  83 + NotifyTemplateUpdateReqVO reqVO = randomPojo(NotifyTemplateUpdateReqVO.class);
  84 +
  85 + // 调用, 并断言异常
  86 + assertServiceException(() -> notifyTemplateService.updateNotifyTemplate(reqVO), NOTIFY_TEMPLATE_NOT_EXISTS);
  87 + }
  88 +
  89 + @Test
  90 + public void testDeleteNotifyTemplate_success() {
  91 + // mock 数据
  92 + NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class);
  93 + notifyTemplateMapper.insert(dbNotifyTemplate);// @Sql: 先插入出一条存在的数据
  94 + // 准备参数
  95 + Long id = dbNotifyTemplate.getId();
  96 +
  97 + // 调用
  98 + notifyTemplateService.deleteNotifyTemplate(id);
  99 + // 校验数据不存在了
  100 + assertNull(notifyTemplateMapper.selectById(id));
  101 + verify(notifyProducer).sendNotifyTemplateRefreshMessage();
  102 + }
  103 +
  104 + @Test
  105 + public void testDeleteNotifyTemplate_notExists() {
  106 + // 准备参数
  107 + Long id = randomLongId();
  108 +
  109 + // 调用, 并断言异常
  110 + assertServiceException(() -> notifyTemplateService.deleteNotifyTemplate(id), NOTIFY_TEMPLATE_NOT_EXISTS);
  111 + }
  112 +
  113 + @Test
  114 + public void testGetNotifyTemplatePage() {
  115 + // mock 数据
  116 + NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class, o -> { // 等会查询到
  117 + o.setName("芋头");
  118 + o.setCode("test_01");
  119 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  120 + o.setCreateTime(buildTime(2022, 2, 3));
  121 + });
  122 + notifyTemplateMapper.insert(dbNotifyTemplate);
  123 + // 测试 name 不匹配
  124 + notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setName("投")));
  125 + // 测试 code 不匹配
  126 + notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setCode("test_02")));
  127 + // 测试 status 不匹配
  128 + notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
  129 + // 测试 createTime 不匹配
  130 + notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setCreateTime(buildTime(2022, 1, 5))));
  131 + // 准备参数
  132 + NotifyTemplatePageReqVO reqVO = new NotifyTemplatePageReqVO();
  133 + reqVO.setName("芋");
  134 + reqVO.setCode("est_01");
  135 + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
  136 + reqVO.setCreateTime(buildBetweenTime(2022, 2, 1, 2022, 2, 5));
  137 +
  138 + // 调用
  139 + PageResult<NotifyTemplateDO> pageResult = notifyTemplateService.getNotifyTemplatePage(reqVO);
  140 + // 断言
  141 + assertEquals(1, pageResult.getTotal());
  142 + assertEquals(1, pageResult.getList().size());
  143 + assertPojoEquals(dbNotifyTemplate, pageResult.getList().get(0));
  144 + }
  145 +
  146 +}
... ...
yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql
... ... @@ -28,3 +28,5 @@ DELETE FROM &quot;system_oauth2_code&quot;;
28 28 DELETE FROM "system_mail_account";
29 29 DELETE FROM "system_mail_template";
30 30 DELETE FROM "system_mail_log";
  31 +DELETE FROM "system_notify_template";
  32 +DELETE FROM "system_notify_message";
... ...
yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql
... ... @@ -626,3 +626,43 @@ CREATE TABLE IF NOT EXISTS &quot;system_mail_log&quot; (
626 626 "deleted" bit NOT NULL DEFAULT FALSE,
627 627 PRIMARY KEY ("id")
628 628 ) COMMENT '邮件日志表';
  629 +
  630 +-- 将该建表 SQL 语句,添加到 yudao-module-system-biz 模块的 test/resources/sql/create_tables.sql 文件里
  631 +CREATE TABLE IF NOT EXISTS "system_notify_template" (
  632 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  633 + "name" varchar NOT NULL,
  634 + "code" varchar NOT NULL,
  635 + "nickname" varchar NOT NULL,
  636 + "content" varchar NOT NULL,
  637 + "type" varchar NOT NULL,
  638 + "params" varchar,
  639 + "status" varchar NOT NULL,
  640 + "remark" varchar,
  641 + "creator" varchar DEFAULT '',
  642 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  643 + "updater" varchar DEFAULT '',
  644 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  645 + "deleted" bit NOT NULL DEFAULT FALSE,
  646 + PRIMARY KEY ("id")
  647 +) COMMENT '站内信模板表';
  648 +
  649 +CREATE TABLE IF NOT EXISTS "system_notify_message" (
  650 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  651 + "user_id" bigint NOT NULL,
  652 + "user_type" varchar NOT NULL,
  653 + "template_id" bigint NOT NULL,
  654 + "template_code" varchar NOT NULL,
  655 + "template_nickname" varchar NOT NULL,
  656 + "template_content" varchar NOT NULL,
  657 + "template_type" int NOT NULL,
  658 + "template_params" varchar NOT NULL,
  659 + "read_status" bit NOT NULL,
  660 + "read_time" varchar,
  661 + "creator" varchar DEFAULT '',
  662 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  663 + "updater" varchar DEFAULT '',
  664 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  665 + "deleted" bit NOT NULL DEFAULT FALSE,
  666 + "tenant_id" bigint not null default '0',
  667 + PRIMARY KEY ("id")
  668 +) COMMENT '站内信消息表';
... ...
yudao-server/src/main/resources/application.yaml
... ... @@ -115,6 +115,7 @@ yudao:
115 115 - cn.iocoder.yudao.module.member.enums.ErrorCodeConstants
116 116 - cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants
117 117 - cn.iocoder.yudao.module.system.enums.ErrorCodeConstants
  118 + - cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants
118 119 tenant: # 多租户相关配置项
119 120 enable: true
120 121 ignore-urls:
... ... @@ -141,6 +142,7 @@ yudao:
141 142 - system_mail_account
142 143 - system_mail_template
143 144 - system_mail_log
  145 + - system_notify_template
144 146 - infra_codegen_column
145 147 - infra_codegen_table
146 148 - infra_test_demo
... ...
yudao-ui-admin/src/api/system/notify/myNotify.js renamed to yudao-ui-admin/src/api/system/notify/message.js
1 1 import request from '@/utils/request'
2   -
  2 +import qs from 'qs'
3 3  
4 4 // 获得我的站内信分页
5 5 export function getNotifyMessagePage(query) {
... ... @@ -10,29 +10,42 @@ export function getNotifyMessagePage(query) {
10 10 })
11 11 }
12 12  
13   -// 获得单条我的站内信
14   -export function getNotifyMessage(query) {
  13 +// 获得我的站内信分页
  14 +export function getMyNotifyMessagePage(query) {
15 15 return request({
16   - url: '/system/notify-message/get',
  16 + url: '/system/notify-message/my-page',
17 17 method: 'get',
18 18 params: query
19 19 })
20 20 }
21 21  
22 22 // 批量标记已读
23   -export function updateNotifyMessageListRead(data) {
  23 +export function updateNotifyMessageRead(ids) {
24 24 return request({
25   - url: '/system/notify-message/update-list-read',
26   - method: 'put',
27   - data: data
  25 + url: '/system/notify-message/update-read?' + qs.stringify({ids: ids}, { indices: false }),
  26 + method: 'put'
28 27 })
29 28 }
30 29  
31   -// 所有未读消息标记已读
32   -export function updateNotifyMessageAllRead(data) {
  30 +// 标记所有站内信为已读
  31 +export function updateAllNotifyMessageRead() {
33 32 return request({
34 33 url: '/system/notify-message/update-all-read',
35   - method: 'put',
36   - data: data
  34 + method: 'put'
  35 + })
  36 +}
  37 +
  38 +// 获取当前用户的最新站内信列表
  39 +export function getUnreadNotifyMessageList() {
  40 + return request({
  41 + url: '/system/notify-message/get-unread-list',
  42 + method: 'get'
  43 + })
  44 +}
  45 +
  46 +export function getUnreadNotifyMessageCount() {
  47 + return request({
  48 + url: '/system/notify-message/get-unread-count',
  49 + method: 'get'
37 50 })
38 51 }
... ...
yudao-ui-admin/src/api/system/notify/notifyLog.js deleted
1   -import request from '@/utils/request'
2   -
3   -
4   -// 获得我的站内信分页
5   -export function getNotifyLogPage(query) {
6   - return request({
7   - url: '/system/notify-log/page',
8   - method: 'get',
9   - params: query
10   - })
11   -}
yudao-ui-admin/src/api/system/notify/notifyTemplate.js renamed to yudao-ui-admin/src/api/system/notify/template.js
yudao-ui-admin/src/components/RuoYi/Doc/index.vue
... ... @@ -9,7 +9,7 @@ export default {
9 9 name: 'YudaoDoc',
10 10 data() {
11 11 return {
12   - url: 'http://www.iocoder.cn/Yudao/build-debugger-environment/?yudao'
  12 + url: 'https://doc.iocoder.cn/'
13 13 }
14 14 },
15 15 methods: {
... ...
yudao-ui-admin/src/layout/components/Message/index.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-popover placement="bottom" width="600" trigger="click">
  4 + <!-- icon 展示 -->
  5 + <el-badge slot="reference" :is-dot="unreadCount > 0" type="danger">
  6 + <svg-icon icon-class="message" @click="getList"/>
  7 + </el-badge>
  8 +
  9 + <!-- 弹出列表 -->
  10 + <el-table v-loading="loading" :data="list">
  11 + <el-table-column width="120" property="templateNickname" label="日期" />
  12 + <el-table-column width="180" property="title" label="发送时间">
  13 + <template slot-scope="scope">
  14 + <span>{{ parseTime(scope.row.createTime) }}</span>
  15 + </template>
  16 + </el-table-column>
  17 + <el-table-column label="类型" align="center" prop="templateType" width="100">
  18 + <template v-slot="scope">
  19 + <dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE" :value="scope.row.templateType" />
  20 + </template>
  21 + </el-table-column>
  22 + <el-table-column property="templateContent" label="内容" />
  23 + </el-table>
  24 +
  25 + <!-- 更多 -->
  26 + <div style="text-align: right; margin-top: 10px">
  27 + <el-button type="primary" size="mini" @click="goMyList">查看全部</el-button>
  28 + </div>
  29 + </el-popover>
  30 + </div>
  31 +</template>
  32 +
  33 +<script>
  34 +import {getUnreadNotifyMessageCount, getUnreadNotifyMessageList} from "@/api/system/notify/message";
  35 +
  36 +export default {
  37 + name: 'NotifyMessage',
  38 + data() {
  39 + return {
  40 + // 遮罩层
  41 + loading: false,
  42 + // 列表
  43 + list: [],
  44 + // 未读数量,
  45 + unreadCount: 0,
  46 + }
  47 + },
  48 + created() {
  49 + // 首次加载小红点
  50 + this.getUnreadCount()
  51 + // 轮询刷新小红点
  52 + window.timer = setInterval(()=>{
  53 + this.getUnreadCount()
  54 + },1000 * 60 * 2)
  55 + },
  56 + methods: {
  57 + getList: function() {
  58 + this.loading = true;
  59 + getUnreadNotifyMessageList().then(response => {
  60 + this.list = response.data;
  61 + this.loading = false;
  62 + // 强制设置 unreadCount 为 0,避免小红点因为轮询太慢,不消除
  63 + this.unreadCount = 0
  64 + });
  65 + },
  66 + getUnreadCount: function() {
  67 + getUnreadNotifyMessageCount().then(response => {
  68 + this.unreadCount = response.data;
  69 + })
  70 + },
  71 + goMyList: function() {
  72 + this.$router.push({
  73 + name: 'MyNotifyMessage'
  74 + });
  75 + }
  76 + }
  77 +}
  78 +</script>
  79 +<style>
  80 +.el-badge__content.is-fixed {
  81 + top: 10px; /* 保证徽章的位置 */
  82 +}
  83 +</style>
... ...
yudao-ui-admin/src/layout/components/Navbar.vue
... ... @@ -9,6 +9,9 @@
9 9 <template v-if="device!=='mobile'">
10 10 <search id="header-search" class="right-menu-item" />
11 11  
  12 + <!-- 站内信 -->
  13 + <notify-message class="right-menu-item hover-effect" />
  14 +
12 15 <el-tooltip content="源码地址" effect="dark" placement="bottom">
13 16 <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
14 17 </el-tooltip>
... ... @@ -57,6 +60,7 @@ import SizeSelect from &#39;@/components/SizeSelect&#39;
57 60 import Search from '@/components/HeaderSearch'
58 61 import RuoYiGit from '@/components/RuoYi/Git'
59 62 import RuoYiDoc from '@/components/RuoYi/Doc'
  63 +import NotifyMessage from '@/layout/components/Message'
60 64 import {getPath} from "@/utils/ruoyi";
61 65  
62 66 export default {
... ... @@ -68,7 +72,8 @@ export default {
68 72 SizeSelect,
69 73 Search,
70 74 RuoYiGit,
71   - RuoYiDoc
  75 + RuoYiDoc,
  76 + NotifyMessage
72 77 },
73 78 computed: {
74 79 ...mapGetters([
... ...
yudao-ui-admin/src/router/index.js
... ... @@ -75,7 +75,8 @@ export const constantRoutes = [
75 75 meta: {title: '首页', icon: 'dashboard', affix: true}
76 76 }
77 77 ]
78   - }, {
  78 + },
  79 + {
79 80 path: '/user',
80 81 component: Layout,
81 82 hidden: true,
... ... @@ -85,9 +86,14 @@ export const constantRoutes = [
85 86 component: (resolve) => require(['@/views/system/user/profile/index'], resolve),
86 87 name: 'Profile',
87 88 meta: {title: '个人中心', icon: 'user'}
88   - }
89   - ]
90   - }, {
  89 + }, {
  90 + path: 'notify-message',
  91 + component: (resolve) => require(['@/views/system/notify/my/index'], resolve),
  92 + name: 'MyNotifyMessage',
  93 + meta: { title: '我的站内信', icon: 'message' },
  94 + }]
  95 + },
  96 + {
91 97 path: '/dict',
92 98 component: Layout,
93 99 hidden: true,
... ... @@ -98,18 +104,8 @@ export const constantRoutes = [
98 104 meta: {title: '字典数据', icon: '', activeMenu: '/system/dict'}
99 105 }
100 106 ]
101   - }, {
102   - path: '/property',
103   - component: Layout,
104   - hidden: true,
105   - children: [{
106   - path: 'value/:propertyId(\\d+)',
107   - component: (resolve) => require(['@/views/mall/product/property/value'], resolve),
108   - name: 'PropertyValue',
109   - meta: {title: '商品属性值', icon: '', activeMenu: '/product/property'}
110   - }
111   - ]
112   - }, {
  107 + },
  108 + {
113 109 path: '/job',
114 110 component: Layout,
115 111 hidden: true,
... ... @@ -131,24 +127,8 @@ export const constantRoutes = [
131 127 meta: {title: '修改生成配置', activeMenu: '/infra/codegen'}
132 128 }
133 129 ]
134   - }, {
135   - path: '/spu',
136   - component: Layout,
137   - hidden: true,
138   - children: [{
139   - path: 'edit/:spuId(\\d+)',
140   - component: (resolve) => require(['@/views/mall/product/spu/save'], resolve),
141   - name: 'SpuEdit',
142   - meta: {title: '修改商品', activeMenu: '/product/spu'}
143   - },
144   - {
145   - path: 'add',
146   - component: (resolve) => require(['@/views/mall/product/spu/save'], resolve),
147   - name: 'SpuAdd',
148   - meta: {title: '添加商品', activeMenu: '/product/spu'}
149   - }
150   - ]
151   - }, {
  130 + },
  131 + {
152 132 path: '/bpm',
153 133 component: Layout,
154 134 hidden: true,
... ... @@ -165,7 +145,8 @@ export const constantRoutes = [
165 145 meta: {title: '查看 OA 请假', icon: 'view', activeMenu: '/bpm/oa/leave'}
166 146 }
167 147 ]
168   - }, {
  148 + },
  149 + {
169 150 path: '/bpm',
170 151 component: Layout,
171 152 hidden: true,
... ... @@ -198,6 +179,36 @@ export const constantRoutes = [
198 179 ]
199 180 },
200 181 {
  182 + path: '/property',
  183 + component: Layout,
  184 + hidden: true,
  185 + children: [{
  186 + path: 'value/:propertyId(\\d+)',
  187 + component: (resolve) => require(['@/views/mall/product/property/value'], resolve),
  188 + name: 'PropertyValue',
  189 + meta: {title: '商品属性值', icon: '', activeMenu: '/product/property'}
  190 + }
  191 + ]
  192 + },
  193 + {
  194 + path: '/spu',
  195 + component: Layout,
  196 + hidden: true,
  197 + children: [{
  198 + path: 'edit/:spuId(\\d+)',
  199 + component: (resolve) => require(['@/views/mall/product/spu/save'], resolve),
  200 + name: 'SpuEdit',
  201 + meta: {title: '修改商品', activeMenu: '/product/spu'}
  202 + },
  203 + {
  204 + path: 'add',
  205 + component: (resolve) => require(['@/views/mall/product/spu/save'], resolve),
  206 + name: 'SpuAdd',
  207 + meta: {title: '添加商品', activeMenu: '/product/spu'}
  208 + }
  209 + ]
  210 + },
  211 + {
201 212 path: '/trade/order',
202 213 component: Layout,
203 214 hidden: true,
... ...
yudao-ui-admin/src/utils/dict.js
... ... @@ -25,8 +25,8 @@ export const DICT_TYPE = {
25 25 SYSTEM_SMS_RECEIVE_STATUS: 'system_sms_receive_status',
26 26 SYSTEM_ERROR_CODE_TYPE: 'system_error_code_type',
27 27 SYSTEM_OAUTH2_GRANT_TYPE: 'system_oauth2_grant_type',
28   - SYSTEM_NOTIFY_READ_STATUS: "system_notify_read_status",
29 28 SYSTEM_MAIL_SEND_STATUS: 'system_mail_send_status',
  29 + SYSTEM_NOTIFY_TEMPLATE_TYPE: 'system_notify_template_type',
30 30  
31 31 // ========== INFRA 模块 ==========
32 32 INFRA_BOOLEAN_STRING: 'infra_boolean_string',
... ...
yudao-ui-admin/src/views/system/mail/log/index.vue
... ... @@ -140,7 +140,7 @@ export default {
140 140 // 邮件日志列表
141 141 list: [],
142 142 // 弹出层标题
143   - title: "",
  143 + title: "邮件发送日志详细",
144 144 // 是否显示弹出层
145 145 open: false,
146 146 // 查询参数
... ...
yudao-ui-admin/src/views/system/notify/message/index.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
  6 + <el-form-item label="用户编号" prop="userId">
  7 + <el-input v-model="queryParams.userId" placeholder="请输入用户编号" clearable @keyup.enter.native="handleQuery"/>
  8 + </el-form-item>
  9 + <el-form-item label="用户类型" prop="userType">
  10 + <el-select v-model="queryParams.userType" placeholder="请选择用户类型" clearable size="small">
  11 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.USER_TYPE)"
  12 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  13 + </el-select>
  14 + </el-form-item>
  15 + <el-form-item label="模板编码" prop="templateCode">
  16 + <el-input v-model="queryParams.templateCode" placeholder="请输入模板编码" clearable @keyup.enter.native="handleQuery"/>
  17 + </el-form-item>
  18 + <el-form-item label="模版类型" prop="templateType">
  19 + <el-select v-model="queryParams.templateType" placeholder="请选择模版类型" clearable size="small">
  20 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE)"
  21 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  22 + </el-select>
  23 + </el-form-item>
  24 + <el-form-item label="创建时间" prop="createTime">
  25 + <el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
  26 + range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
  27 + </el-form-item>
  28 + <el-form-item>
  29 + <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
  30 + <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
  31 + </el-form-item>
  32 + </el-form>
  33 +
  34 + <!-- 操作工具栏 -->
  35 + <el-row :gutter="10" class="mb8">
  36 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  37 + </el-row>
  38 +
  39 + <!-- 列表 -->
  40 + <el-table v-loading="loading" :data="list">
  41 + <el-table-column label="编号" align="center" prop="id" />
  42 + <el-table-column label="用户编号" align="center" prop="userId" />
  43 + <el-table-column label="用户类型" align="center" prop="userType">
  44 + <template v-slot="scope">
  45 + <dict-tag :type="DICT_TYPE.USER_TYPE" :value="scope.row.userType" />
  46 + </template>
  47 + </el-table-column>
  48 + <el-table-column label="模板编码" align="center" prop="templateCode" />
  49 + <el-table-column label="发送人名称" align="center" prop="templateNickname" />
  50 + <el-table-column label="模版内容" align="center" prop="templateContent" />
  51 + <el-table-column label="模版类型" align="center" prop="templateType">
  52 + <template v-slot="scope">
  53 + <dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE" :value="scope.row.templateType" />
  54 + </template>
  55 + </el-table-column>
  56 + <el-table-column label="是否已读" align="center" prop="readStatus">
  57 + <template v-slot="scope">
  58 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.readStatus" />
  59 + </template>
  60 + </el-table-column>
  61 + <el-table-column label="阅读时间" align="center" prop="readTime" width="180">
  62 + <template v-slot="scope">
  63 + <span>{{ parseTime(scope.row.readTime) }}</span>
  64 + </template>
  65 + </el-table-column>
  66 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  67 + <template v-slot="scope">
  68 + <span>{{ parseTime(scope.row.createTime) }}</span>
  69 + </template>
  70 + </el-table-column>
  71 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  72 + <template v-slot="scope">
  73 + <el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row)"
  74 + v-hasPermi="['system:notify-message:query']">详细</el-button>
  75 + </template>
  76 + </el-table-column>
  77 + </el-table>
  78 + <!-- 分页组件 -->
  79 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  80 + @pagination="getList"/>
  81 +
  82 + <!-- 站内信详细-->
  83 + <el-dialog :title="title" :visible.sync="open" width="700px" v-dialogDrag append-to-body>
  84 + <el-form ref="form" :model="form" label-width="160px">
  85 + <el-row>
  86 + <el-col :span="24">
  87 + <el-form-item label="日志主键:">{{ form.id }}</el-form-item>
  88 + <el-form-item label="发送时间:">{{ parseTime(form.createTime) }}</el-form-item>
  89 + <el-form-item label="用户编号:">{{ form.userId }}</el-form-item>
  90 + <el-form-item label="用户类型:">
  91 + <dict-tag :type="DICT_TYPE.USER_TYPE" :value="form.userType"/>
  92 + </el-form-item>
  93 + <el-form-item label="模板编号:">{{ form.templateId }}</el-form-item>
  94 + <el-form-item label="模板编码:">{{ form.templateCode }}</el-form-item>
  95 + <el-form-item label="模板类型:">
  96 + <dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE" :value="form.templateType" />
  97 + </el-form-item>
  98 + <el-form-item label="模版发送人名称:">{{ form.templateNickname }}</el-form-item>
  99 + <el-form-item label="邮件内容:">{{ form.templateContent }}</el-form-item>
  100 + <el-form-item label="模版参数:">{{ form.templateParams }}</el-form-item>
  101 + <el-form-item label="是否已读:">
  102 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="form.readStatus" />
  103 + </el-form-item>
  104 + <el-form-item label="阅读时间:">{{ parseTime(form.readTime) }}</el-form-item>
  105 + </el-col>
  106 + </el-row>
  107 + </el-form>
  108 + <div slot="footer" class="dialog-footer">
  109 + <el-button @click="open = false">关 闭</el-button>
  110 + </div>
  111 + </el-dialog>
  112 + </div>
  113 +</template>
  114 +
  115 +<script>
  116 +import { getNotifyMessagePage } from "@/api/system/notify/message";
  117 +
  118 +export default {
  119 + name: "NotifyMessage",
  120 + data() {
  121 + return {
  122 + // 遮罩层
  123 + loading: true,
  124 + // 显示搜索条件
  125 + showSearch: true,
  126 + // 总条数
  127 + total: 0,
  128 + // 站内信消息列表
  129 + list: [],
  130 + // 弹出层标题
  131 + title: "站内信详细",
  132 + // 是否显示弹出层
  133 + open: false,
  134 + // 查询参数
  135 + queryParams: {
  136 + pageNo: 1,
  137 + pageSize: 10,
  138 + userId: null,
  139 + userType: null,
  140 + templateCode: null,
  141 + templateType: null,
  142 + createTime: [],
  143 + },
  144 + // 表单参数
  145 + form: {},
  146 + };
  147 + },
  148 + created() {
  149 + this.getList();
  150 + },
  151 + methods: {
  152 + /** 查询列表 */
  153 + getList() {
  154 + this.loading = true;
  155 + // 执行查询
  156 + getNotifyMessagePage(this.queryParams).then(response => {
  157 + this.list = response.data.list;
  158 + this.total = response.data.total;
  159 + this.loading = false;
  160 + });
  161 + },
  162 + /** 搜索按钮操作 */
  163 + handleQuery() {
  164 + this.queryParams.pageNo = 1;
  165 + this.getList();
  166 + },
  167 + /** 重置按钮操作 */
  168 + resetQuery() {
  169 + this.resetForm("queryForm");
  170 + this.handleQuery();
  171 + },
  172 + /** 详细按钮操作 */
  173 + handleView(row) {
  174 + this.open = true;
  175 + this.form = row;
  176 + }
  177 + }
  178 +};
  179 +</script>
... ...
yudao-ui-admin/src/views/system/notify/myNotify.vue renamed to yudao-ui-admin/src/views/system/notify/my/index.vue
1 1 <template>
2 2 <div class="app-container">
3 3 <!-- 搜索工作栏 -->
4   - <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="150px">
5   - <el-form-item label="模板标题" prop="title">
6   - <el-input v-model="queryParams.title" placeholder="请输入模板标题" clearable @keyup.enter.native="handleQuery"/>
7   - </el-form-item>
8   - <el-form-item label="读取状态" prop="readStatus">
  4 + <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
  5 + <el-form-item label="是否已读" prop="readStatus">
9 6 <el-select v-model="queryParams.readStatus" placeholder="请选择状态" clearable>
10   - <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYSTEM_NOTIFY_READ_STATUS)"
  7 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.INFRA_BOOLEAN_STRING)"
11 8 :key="dict.value" :label="dict.label" :value="dict.value"/>
12 9 </el-select>
13 10 </el-form-item>
14   - <el-form-item label="创建时间" prop="createTime">
  11 + <el-form-item label="发送时间" prop="createTime">
15 12 <el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
16 13 range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
17 14 </el-form-item>
... ... @@ -35,17 +32,21 @@
35 32 <!-- 列表 -->
36 33 <el-table v-loading="loading" ref="tables" :data="list">
37 34 <el-table-column type="selection" width="55" />
38   - <el-table-column label="模板标题" align="center" prop="title" />
39   - <el-table-column label="模板内容" align="center" prop="content" width="300" />
40   - <el-table-column label="发送人" align="center" prop="sendUserName" />
41   - <el-table-column label="发送时间" align="center" prop="sendTime" width="180">
  35 + <el-table-column label="发送人" align="center" prop="templateNickname" width="120" />
  36 + <el-table-column label="发送时间" align="center" prop="createTime" width="180">
42 37 <template slot-scope="scope">
43   - <span>{{ parseTime(scope.row.sendTime) }}</span>
  38 + <span>{{ parseTime(scope.row.createTime) }}</span>
  39 + </template>
  40 + </el-table-column>
  41 + <el-table-column label="类型" align="center" prop="templateType" width="80">
  42 + <template v-slot="scope">
  43 + <dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE" :value="scope.row.templateType" />
44 44 </template>
45 45 </el-table-column>
46   - <el-table-column label="读取状态" align="center" prop="readStatus">
  46 + <el-table-column label="内容" align="center" prop="templateContent" />
  47 + <el-table-column label="是否已读" align="center" prop="readStatus" width="80">
47 48 <template slot-scope="scope">
48   - <dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_READ_STATUS" :value="scope.row.readStatus"/>
  49 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.readStatus"/>
49 50 </template>
50 51 </el-table-column>
51 52 <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="150">
... ... @@ -62,7 +63,7 @@
62 63 </template>
63 64  
64 65 <script>
65   -import { getNotifyMessagePage, updateNotifyMessageListRead, updateNotifyMessageAllRead} from "@/api/system/notify/myNotify";
  66 +import {getMyNotifyMessagePage, updateAllNotifyMessageRead, updateNotifyMessageRead} from "@/api/system/notify/message";
66 67  
67 68 export default {
68 69 name: "myNotify",
... ... @@ -70,25 +71,17 @@ export default {
70 71 return {
71 72 // 遮罩层
72 73 loading: true,
73   - // 导出遮罩层
74   - exportLoading: false,
75 74 // 显示搜索条件
76 75 showSearch: true,
77 76 // 总条数
78 77 total: 0,
79 78 // 我的站内信列表
80 79 list: [],
81   - // 弹出层标题
82   - title: "",
83   - // 是否显示弹出层
84   - open: false,
85 80 // 查询参数
86 81 queryParams: {
87 82 pageNo: 1,
88 83 pageSize: 10,
89 84 readStatus: null,
90   - code: null,
91   - title: null,
92 85 createTime: []
93 86 },
94 87 };
... ... @@ -101,7 +94,7 @@ export default {
101 94 getList() {
102 95 this.loading = true;
103 96 // 执行查询
104   - getNotifyMessagePage(this.queryParams).then(response => {
  97 + getMyNotifyMessagePage(this.queryParams).then(response => {
105 98 this.list = response.data.list;
106 99 this.total = response.data.total;
107 100 this.loading = false;
... ... @@ -117,25 +110,26 @@ export default {
117 110 this.resetForm("queryForm");
118 111 this.handleQuery();
119 112 },
120   - handleUpdateList(){
  113 + handleUpdateList() {
121 114 let list = this.$refs["tables"].selection;
122   - if(list.length != 0){
123   - this.handleUpdate(list.map(v=>v.id))
  115 + if (list.length === 0) {
  116 + return;
124 117 }
  118 + this.handleUpdate(list.map(v => v.id))
125 119 },
126   - handleUpdateSingle(row){
  120 + handleUpdateSingle(row) {
127 121 this.handleUpdate([row.id])
128 122 },
129   - handleUpdate(ids){
130   - updateNotifyMessageListRead(ids).then(response => {
131   - this.$modal.msgSuccess("修改成功");
132   - this.getList();
  123 + handleUpdate(ids) {
  124 + updateNotifyMessageRead(ids).then(response => {
  125 + this.$modal.msgSuccess("标记已读成功!");
  126 + this.getList();
133 127 });
134 128 },
135 129 handleUpdateAll(){
136   - updateNotifyMessageAllRead().then(response => {
137   - this.$modal.msgSuccess("修改成功");
138   - this.getList();
  130 + updateAllNotifyMessageRead().then(response => {
  131 + this.$modal.msgSuccess("全部已读成功!");
  132 + this.getList();
139 133 });
140 134 }
141 135 }
... ...
yudao-ui-admin/src/views/system/notify/notifyLog.vue deleted
1   -<template>
2   - <div class="app-container">
3   - <!-- 搜索工作栏 -->
4   - <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="150px">
5   - <el-form-item label="模板编码" prop="templateCode">
6   - <el-input v-model="queryParams.templateCode" placeholder="请输入模板编码" clearable @keyup.enter.native="handleQuery"/>
7   - </el-form-item>
8   - <el-form-item label="模板标题" prop="title">
9   - <el-input v-model="queryParams.title" placeholder="请输入模板标题" clearable @keyup.enter.native="handleQuery"/>
10   - </el-form-item>
11   - <el-form-item label="发送时间" prop="sendTime">
12   - <el-date-picker v-model="queryParams.sendTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
13   - range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
14   - </el-form-item>
15   - <el-form-item>
16   - <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
17   - <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
18   - </el-form-item>
19   - </el-form>
20   -
21   - <!-- 操作工具栏 -->
22   - <!-- <el-row :gutter="10" class="mb8">
23   - <el-col :span="1.5">
24   - <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading"
25   - v-hasPermi="['system:notify-log:export']">导出</el-button>
26   - </el-col>
27   - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
28   - </el-row> -->
29   -
30   - <!-- 列表 -->
31   - <el-table v-loading="loading" :data="list">
32   - <el-table-column label="模板编码" align="center" prop="templateCode" />
33   - <el-table-column label="模板标题" align="center" prop="title" />
34   - <el-table-column label="模板内容" align="center" prop="content" width="300" />
35   - <el-table-column label="阅读状态" align="center" prop="readStatus">
36   - <template slot-scope="scope">
37   - <dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_READ_STATUS" :value="scope.row.readStatus"/>
38   - </template>
39   - </el-table-column>
40   - <el-table-column label="接收人" align="center" prop="receiveUserName" />
41   - <el-table-column label="发送时间" align="center" prop="sendTime" width="180">
42   - <template slot-scope="scope">
43   - <span>{{ parseTime(scope.row.sendTime) }}</span>
44   - </template>
45   - </el-table-column>
46   - <el-table-column label="阅读时间" align="center" prop="createTime" width="180">
47   - <template slot-scope="scope">
48   - <span>{{ parseTime(scope.row.readTime) }}</span>
49   - </template>
50   - </el-table-column>
51   - </el-table>
52   - <!-- 分页组件 -->
53   - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
54   - @pagination="getList"/>
55   -
56   - </div>
57   -</template>
58   -
59   -<script>
60   -import { getNotifyLogPage} from "@/api/system/notify/notifyLog";
61   -
62   -export default {
63   - name: "notifyLog",
64   - data() {
65   - return {
66   - // 遮罩层
67   - loading: true,
68   - // 导出遮罩层
69   - exportLoading: false,
70   - // 显示搜索条件
71   - showSearch: true,
72   - // 总条数
73   - total: 0,
74   - // 我的站内信列表
75   - list: [],
76   - // 弹出层标题
77   - title: "",
78   - // 是否显示弹出层
79   - open: false,
80   - // 查询参数
81   - queryParams: {
82   - pageNo: 1,
83   - pageSize: 10,
84   - templateCode: null,
85   - title: null,
86   - sendTime: []
87   - },
88   - };
89   - },
90   - created() {
91   - this.getList();
92   - },
93   - methods: {
94   - /** 查询列表 */
95   - getList() {
96   - this.loading = true;
97   - // 执行查询
98   - getNotifyLogPage(this.queryParams).then(response => {
99   - this.list = response.data.list;
100   - this.total = response.data.total;
101   - this.loading = false;
102   - });
103   - },
104   - /** 搜索按钮操作 */
105   - handleQuery() {
106   - this.queryParams.pageNo = 1;
107   - this.getList();
108   - },
109   - /** 重置按钮操作 */
110   - resetQuery() {
111   - this.resetForm("queryForm");
112   - this.handleQuery();
113   - },
114   - }
115   -}
116   -</script>
117   -
118   -<style>
119   -
120   -</style>
yudao-ui-admin/src/views/system/notify/notifyTemplate.vue renamed to yudao-ui-admin/src/views/system/notify/template/index.vue
1 1 <template>
2 2 <div class="app-container">
3 3 <!-- 搜索工作栏 -->
4   - <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="150px">
5   - <el-form-item label="模板编码" prop="code">
6   - <el-input v-model="queryParams.code" placeholder="请输入模板编码" clearable @keyup.enter.native="handleQuery"/>
  4 + <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
  5 + <el-form-item label="模板名称" prop="name">
  6 + <el-input v-model="queryParams.name" placeholder="请输入模板名称" clearable @keyup.enter.native="handleQuery"/>
7 7 </el-form-item>
8   - <el-form-item label="模板标题" prop="title">
9   - <el-input v-model="queryParams.title" placeholder="请输入模板标题" clearable @keyup.enter.native="handleQuery"/>
  8 + <el-form-item label="模版编码" prop="code">
  9 + <el-input v-model="queryParams.code" placeholder="请输入模版编码" clearable @keyup.enter.native="handleQuery"/>
10 10 </el-form-item>
11   - <el-form-item label="开启状态" prop="status">
12   - <el-select v-model="queryParams.status" placeholder="请选择开启状态" clearable>
  11 + <el-form-item label="状态" prop="status">
  12 + <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
13 13 <el-option v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
14 14 :key="dict.value" :label="dict.label" :value="dict.value"/>
15 15 </el-select>
... ... @@ -30,17 +30,19 @@
30 30 <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
31 31 v-hasPermi="['system:notify-template:create']">新增</el-button>
32 32 </el-col>
33   - <el-col :span="1.5">
34   - <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading"
35   - v-hasPermi="['system:notify-template:export']">导出</el-button>
36   - </el-col>
37 33 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
38 34 </el-row>
39 35  
40 36 <!-- 列表 -->
41 37 <el-table v-loading="loading" :data="list">
42 38 <el-table-column label="模板编码" align="center" prop="code" />
43   - <el-table-column label="模板标题" align="center" prop="title" />
  39 + <el-table-column label="模板名称" align="center" prop="name" />
  40 + <el-table-column label="类型" align="center" prop="type">
  41 + <template v-slot="scope">
  42 + <dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE" :value="scope.row.type" />
  43 + </template>
  44 + </el-table-column>
  45 + <el-table-column label="发送人名称" align="center" prop="nickname" />
44 46 <el-table-column label="模板内容" align="center" prop="content" width="300" />
45 47 <el-table-column label="开启状态" align="center" prop="status">
46 48 <template slot-scope="scope">
... ... @@ -74,12 +76,21 @@
74 76 <el-form-item label="模板编号" prop="code">
75 77 <el-input v-model="form.code" placeholder="请输入模板编号" />
76 78 </el-form-item>
77   - <el-form-item label="模板标题" prop="title">
78   - <el-input v-model="form.title" placeholder="请输入标题名称" />
  79 + <el-form-item label="模板名称" prop="name">
  80 + <el-input v-model="form.name" placeholder="请输入模版名称" />
  81 + </el-form-item>
  82 + <el-form-item label="发件人名称" prop="nickname">
  83 + <el-input v-model="form.nickname" placeholder="请输入发件人名称" />
79 84 </el-form-item>
80 85 <el-form-item label="模板内容" prop="content">
81 86 <el-input type="textarea" v-model="form.content" placeholder="请输入模板内容" />
82 87 </el-form-item>
  88 + <el-form-item label="类型" prop="type">
  89 + <el-select v-model="form.type" placeholder="请选择类型">
  90 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE)"
  91 + :key="dict.value" :label="dict.label" :value="parseInt(dict.value)" />
  92 + </el-select>
  93 + </el-form-item>
83 94 <el-form-item label="开启状态" prop="status">
84 95 <el-radio-group v-model="form.status">
85 96 <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
... ... @@ -122,8 +133,9 @@
122 133  
123 134 <script>
124 135 import { createNotifyTemplate, updateNotifyTemplate, deleteNotifyTemplate, getNotifyTemplate, getNotifyTemplatePage,
125   - exportNotifyTemplateExcel, sendNotify } from "@/api/system/notify/notifyTemplate";
  136 + sendNotify } from "@/api/system/notify/template";
126 137 import {listSimpleUsers} from "@/api/system/user";
  138 +import {CommonStatusEnum} from "@/utils/constants";
127 139  
128 140 export default {
129 141 name: "NotifyTemplate",
... ... @@ -131,8 +143,6 @@ export default {
131 143 return {
132 144 // 遮罩层
133 145 loading: true,
134   - // 导出遮罩层
135   - exportLoading: false,
136 146 // 显示搜索条件
137 147 showSearch: true,
138 148 // 总条数
... ... @@ -156,11 +166,12 @@ export default {
156 166 form: {},
157 167 // 表单校验
158 168 rules: {
159   - status: [{ required: true, message: "开启状态不能为空", trigger: "blur" }],
160   - code: [{ required: true, message: "模板编码不能为空", trigger: "blur" }],
161   - title: [{ required: true, message: "模板标题不能为空", trigger: "blur" }],
162   - content: [{ required: true, message: "模板内容不能为空", trigger: "blur" }],
163   - userId: [{ required: true, message: "接收人不能为空", trigger: "blur" }]
  169 + name: [{ required: true, message: "模板名称不能为空", trigger: "blur" }],
  170 + code: [{ required: true, message: "模版编码不能为空", trigger: "blur" }],
  171 + nickname: [{ required: true, message: "发件人名称不能为空", trigger: "blur" }],
  172 + content: [{ required: true, message: "模版内容不能为空", trigger: "blur" }],
  173 + type: [{ required: true, message: "类型不能为空", trigger: "change" }],
  174 + status: [{ required: true, message: "状态不能为空", trigger: "blur" }],
164 175 },
165 176 // 用户列表
166 177 users: [],
... ... @@ -170,8 +181,8 @@ export default {
170 181 params: [], // 模板的参数列表
171 182 },
172 183 sendNotifyRules: {
173   - mobile: [{ required: true, message: "手机不能为空", trigger: "blur" }],
174   - templateCode: [{ required: true, message: "手机不能为空", trigger: "blur" }],
  184 + userId: [{ required: true, message: "接收人不能为空", trigger: "blur" }],
  185 + templateCode: [{ required: true, message: "模版编号不能为空", trigger: "blur" }],
175 186 templateParams: { }
176 187 }
177 188 };
... ... @@ -203,10 +214,13 @@ export default {
203 214 reset() {
204 215 this.form = {
205 216 id: undefined,
206   - status: undefined,
  217 + name: undefined,
207 218 code: undefined,
208   - title: undefined,
  219 + nickname: undefined,
209 220 content: undefined,
  221 + type: undefined,
  222 + params: undefined,
  223 + status: CommonStatusEnum.ENABLE,
210 224 remark: undefined,
211 225 };
212 226 this.resetForm("form");
... ... @@ -270,21 +284,6 @@ export default {
270 284 this.$modal.msgSuccess("删除成功");
271 285 }).catch(() => {});
272 286 },
273   - /** 导出按钮操作 */
274   - handleExport() {
275   - // 处理查询参数
276   - let params = {...this.queryParams};
277   - params.pageNo = undefined;
278   - params.pageSize = undefined;
279   - // 执行导出
280   - this.$modal.confirm('是否确认导出所有站内信模板数据项?', "警告").then(() => {
281   - this.exportLoading = true;
282   - return exportNotifyTemplateExcel(params);
283   - }).then(response => {
284   - this.$download.excel(response, '短信模板.xls');
285   - this.exportLoading = false;
286   - }).catch(() => {});
287   - },
288 287 /** 发送站内信按钮 */
289 288 handleSendNotify(row) {
290 289 this.resetSendNotify(row);
... ...