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

plp
YunaiV 3 years ago
parent 143035d798
commit ae3ee95cdd

@ -1,7 +1,9 @@
package cn.iocoder.yudao.framework.mybatis.core.query; package cn.iocoder.yudao.framework.mybatis.core.query;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction; import com.baomidou.mybatisplus.core.toolkit.support.SFunction;

@ -146,19 +146,19 @@ public class QueryWrapperX<T> extends QueryWrapper<T> {
* *
* @return this * @return this
*/ */
public QueryWrapperX<T> limit1() { public QueryWrapperX<T> limitN(int n) {
Assert.notNull(SqlConstants.DB_TYPE, "获取不到数据库的类型"); Assert.notNull(SqlConstants.DB_TYPE, "获取不到数据库的类型");
switch (SqlConstants.DB_TYPE) { switch (SqlConstants.DB_TYPE) {
case ORACLE: case ORACLE:
case ORACLE_12C: case ORACLE_12C:
super.eq("ROWNUM", 1); super.eq("ROWNUM", n);
break; break;
case SQL_SERVER: case SQL_SERVER:
case SQL_SERVER2005: case SQL_SERVER2005:
super.select("TOP 1 *"); // 由于 SQL Server 是通过 SELECT TOP 1 实现限制一条,所以只好使用 * 查询剩余字段 super.select("TOP " + n + " *"); // 由于 SQL Server 是通过 SELECT TOP 1 实现限制一条,所以只好使用 * 查询剩余字段
break; break;
default: default:
super.last("LIMIT 1"); super.last("LIMIT " + n);
} }
return this; return this;
} }

@ -153,13 +153,13 @@ public interface ErrorCodeConstants {
ErrorCode MAIL_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1002025000, "模板参数({})缺失"); ErrorCode MAIL_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1002025000, "模板参数({})缺失");
ErrorCode MAIL_SEND_MAIL_NOT_EXISTS = new ErrorCode(1002025000, "邮箱不存在"); ErrorCode MAIL_SEND_MAIL_NOT_EXISTS = new ErrorCode(1002025000, "邮箱不存在");
// ========== 站内信模版 1002023000 ========== // ========== 站内信模版 1002026000 ==========
ErrorCode NOTIFY_TEMPLATE_NOT_EXISTS = new ErrorCode(1002023000, "站内信模版不存在"); ErrorCode NOTIFY_TEMPLATE_NOT_EXISTS = new ErrorCode(1002026000, "站内信模版不存在");
ErrorCode NOTIFY_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1002023001, "已经存在编码为【{}】的站内信模板"); ErrorCode NOTIFY_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1002026001, "已经存在编码为【{}】的站内信模板");
ErrorCode NOTIFY_TEMPLATE_PARAM_MISS = new ErrorCode(1002023002, "模板参数({})缺失");
// ========== 站内信模版 1002027000 ==========
// ========== 站内信 1002024000 ==========
ErrorCode NOTIFY_MESSAGE_NOT_EXISTS = new ErrorCode(1002024000, "站内信不存在"); // ========== 站内信发送 1002028000 ==========
ErrorCode NOTIFY_MESSAGE_ID_PARAM_ERROR = new ErrorCode(1002024001, "站内信ID错误"); ErrorCode NOTIFY_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1002025000, "模板参数({})缺失");
} }

@ -1,54 +0,0 @@
package cn.iocoder.yudao.module.system.controller.admin.notify;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.log.NotifyLogBaseVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.log.NotifyLogPageReqVO;
import cn.iocoder.yudao.module.system.convert.notify.NotifyLogConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
import cn.iocoder.yudao.module.system.service.notify.NotifyLogService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
/**
* <p>
*
* </p>
*
* @author LuoWenFeng
*/
@Api(tags = "管理后台 - 站内信发送日志")
@RestController
@RequestMapping("/system/notify-log")
@Validated
public class NotifyLogController {
@Resource
private NotifyLogService notifyLogService;
@Resource
private AdminUserService userService;
@GetMapping("/page")
@ApiOperation("获得发送站内信日志分页")
public CommonResult<PageResult<NotifyLogBaseVO>> getNotifyLogPage(@Valid NotifyLogPageReqVO pageVO) {
PageResult<NotifyMessageDO> pageResult = notifyLogService.getNotifyMessageSendPage(pageVO);
PageResult<NotifyLogBaseVO> result = NotifyLogConvert.INSTANCE.convertPage(pageResult);
result.getList().forEach(v -> {
v.setReceiveUserName(userService.getUser(v.getUserId()).getNickname());
});
return success(result);
}
}

@ -1,9 +1,9 @@
package cn.iocoder.yudao.module.system.controller.admin.notify; package cn.iocoder.yudao.module.system.controller.admin.notify;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageRespVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageRespVO;
import cn.iocoder.yudao.module.system.convert.notify.NotifyMessageConvert; import cn.iocoder.yudao.module.system.convert.notify.NotifyMessageConvert;
@ -18,7 +18,6 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Collections;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -33,6 +32,8 @@ public class NotifyMessageController {
@Resource @Resource
private NotifyMessageService notifyMessageService; private NotifyMessageService notifyMessageService;
// ========== 管理所有的站内信 ==========
@GetMapping("/get") @GetMapping("/get")
@ApiOperation("获得站内信") @ApiOperation("获得站内信")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@ -50,38 +51,45 @@ public class NotifyMessageController {
return success(NotifyMessageConvert.INSTANCE.convertPage(pageResult)); return success(NotifyMessageConvert.INSTANCE.convertPage(pageResult));
} }
@GetMapping("/get-recent-list") // ========== 查看自己的站内信 ==========
@ApiOperation("获取当前用户最新站内信默认10条")
@ApiImplicitParam(name = "size", value = "10", defaultValue = "10", dataTypeClass = Integer.class)
public CommonResult<List<NotifyMessageRespVO>> getRecentList(@RequestParam(name = "size", defaultValue = "10") Integer size) {
NotifyMessagePageReqVO reqVO = new NotifyMessagePageReqVO();
List<NotifyMessageDO> pageResult = notifyMessageService.getNotifyMessageList(reqVO, size);
if (CollUtil.isNotEmpty(pageResult)) {
return success(NotifyMessageConvert.INSTANCE.convertList(pageResult));
}
return success(Collections.emptyList());
}
@GetMapping("/get-unread-count") @GetMapping("/my-page")
@ApiOperation("获得未读站内信数量") @ApiOperation("获得我的站内信分页")
public CommonResult<Long> getUnreadCount() { public CommonResult<PageResult<NotifyMessageRespVO>> getMyMyNotifyMessagePage(@Valid NotifyMessageMyPageReqVO pageVO) {
return success(notifyMessageService.getUnreadNotifyMessageCount(getLoginUserId(), UserTypeEnum.ADMIN.getValue())); PageResult<NotifyMessageDO> pageResult = notifyMessageService.getMyMyNotifyMessagePage(pageVO,
getLoginUserId(), UserTypeEnum.ADMIN.getValue());
return success(NotifyMessageConvert.INSTANCE.convertPage(pageResult));
} }
@PutMapping("/update-list-read") @PutMapping("/update-read")
@ApiOperation("批量标记已读") @ApiOperation("标记站内信为已读")
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class) @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
public CommonResult<Boolean> batchUpdateNotifyMessageReadStatus(@RequestBody List<Long> ids) { public CommonResult<Boolean> updateNotifyMessageRead(@RequestParam("ids") List<Long> ids) {
notifyMessageService.batchUpdateNotifyMessageReadStatus(ids, getLoginUserId()); notifyMessageService.updateNotifyMessageRead(ids, getLoginUserId(), UserTypeEnum.ADMIN.getValue());
return success(Boolean.TRUE); return success(Boolean.TRUE);
} }
@PutMapping("/update-all-read") @PutMapping("/update-all-read")
@ApiOperation("所有未读消息标记已读") @ApiOperation("标记所有站内信为已读")
public CommonResult<Boolean> batchUpdateAllNotifyMessageReadStatus() { public CommonResult<Boolean> updateAllNotifyMessageRead() {
notifyMessageService.batchUpdateAllNotifyMessageReadStatus(getLoginUserId(), UserTypeEnum.ADMIN.getValue()); notifyMessageService.updateAllNotifyMessageRead(getLoginUserId(), UserTypeEnum.ADMIN.getValue());
return success(Boolean.TRUE); return success(Boolean.TRUE);
} }
@GetMapping("/get-unread-list")
@ApiOperation("获取当前用户的最新站内信列表,默认 10 条")
@ApiImplicitParam(name = "size", value = "10", defaultValue = "10", dataTypeClass = Integer.class)
public CommonResult<List<NotifyMessageRespVO>> getUnreadNotifyMessageList(
@RequestParam(name = "size", defaultValue = "10") Integer size) {
List<NotifyMessageDO> list = notifyMessageService.getUnreadNotifyMessageList(
getLoginUserId(), UserTypeEnum.ADMIN.getValue(), size);
return success(NotifyMessageConvert.INSTANCE.convertList(list));
}
@GetMapping("/get-unread-count")
@ApiOperation("获得当前用户的未读站内信数量")
public CommonResult<Long> getUnreadNotifyMessageCount() {
return success(notifyMessageService.getUnreadNotifyMessageCount(getLoginUserId(), UserTypeEnum.ADMIN.getValue()));
}
} }

@ -2,8 +2,6 @@ package cn.iocoder.yudao.module.system.controller.admin.notify;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.*; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.*;
import cn.iocoder.yudao.module.system.convert.notify.NotifyTemplateConvert; import cn.iocoder.yudao.module.system.convert.notify.NotifyTemplateConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
@ -17,13 +15,9 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Api(tags = "管理后台 - 站内信模版") @Api(tags = "管理后台 - 站内信模版")
@RestController @RestController
@ -37,7 +31,6 @@ public class NotifyTemplateController {
@Resource @Resource
private NotifySendService notifySendService; private NotifySendService notifySendService;
@PostMapping("/create") @PostMapping("/create")
@ApiOperation("创建站内信模版") @ApiOperation("创建站内信模版")
@PreAuthorize("@ss.hasPermission('system:notify-template:create')") @PreAuthorize("@ss.hasPermission('system:notify-template:create')")
@ -79,22 +72,12 @@ public class NotifyTemplateController {
return success(NotifyTemplateConvert.INSTANCE.convertPage(pageResult)); return success(NotifyTemplateConvert.INSTANCE.convertPage(pageResult));
} }
@GetMapping("/export-excel")
@ApiOperation("导出站内信模版 Excel")
@PreAuthorize("@ss.hasPermission('system:notify-template:export')")
@OperateLog(type = EXPORT)
public void exportNotifyTemplateExcel(@Valid NotifyTemplateExportReqVO exportReqVO,
HttpServletResponse response) throws IOException {
List<NotifyTemplateDO> list = notifyTemplateService.getNotifyTemplateList(exportReqVO);
// 导出 Excel
List<NotifyTemplateExcelVO> datas = NotifyTemplateConvert.INSTANCE.convertList02(list);
ExcelUtils.write(response, "站内信模版.xls", "数据", NotifyTemplateExcelVO.class, datas);
}
@PostMapping("/send-notify") @PostMapping("/send-notify")
@ApiOperation("发送站内信") @ApiOperation("发送站内信")
@PreAuthorize("@ss.hasPermission('system:notify-template:send-notify')")
public CommonResult<Long> sendNotify(@Valid @RequestBody NotifyTemplateSendReqVO sendReqVO) { public CommonResult<Long> sendNotify(@Valid @RequestBody NotifyTemplateSendReqVO sendReqVO) {
return success(notifySendService.sendSingleNotifyToAdmin(sendReqVO.getUserId(), return success(notifySendService.sendSingleNotifyToAdmin(sendReqVO.getUserId(),
sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams())); sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
} }
} }

@ -1,44 +0,0 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.log;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* Base VO VO 使
* VO Swagger
*/
@Data
public class NotifyLogBaseVO {
@ApiModelProperty(value = "模版编码")
private String templateCode;
@ApiModelProperty(value = "标题")
private String title;
@ApiModelProperty(value = "内容", required = true)
private String content;
@ApiModelProperty(value = "发送时间", required = true)
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date sendTime;
@ApiModelProperty(value = "芋艿", required = true)
private String receiveUserName;
@ApiModelProperty(value = "1", required = true)
private Long userId;
@ApiModelProperty(value = "是否已读 false-未读 true-已读")
private Boolean readStatus;
@ApiModelProperty(value = "阅读时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date readTime;
}

@ -4,35 +4,58 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.Date; import java.util.Date;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/** /**
* Base VO VO 使 * Base VO VO 使
* VO Swagger * VO Swagger
*/ */
@Data @Data
public class NotifyMessageBaseVO { public class NotifyMessageBaseVO {
@ApiModelProperty(value = "标题") @ApiModelProperty(value = "用户编号", required = true, example = "25025")
private String title; @NotNull(message = "用户编号不能为空")
private Long userId;
@ApiModelProperty(value = "内容") @ApiModelProperty(value = "用户类型", required = true, example = "1", notes = "参见 UserTypeEnum 枚举")
private String content; @NotNull(message = "用户类型不能为空")
private Byte userType;
@ApiModelProperty(value = "发送时间") @ApiModelProperty(value = "模版编号", required = true, example = "13013")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @NotNull(message = "模版编号不能为空")
private Date sendTime; private Long templateId;
@ApiModelProperty(value = "模板编码", required = true, example = "test_01")
@NotNull(message = "模板编码不能为空")
private String templateCode;
@ApiModelProperty(value = "模版发送人名称", required = true, example = "芋艿")
@NotNull(message = "模版发送人名称不能为空")
private String templateNickname;
@ApiModelProperty(value = "模版内容", required = true, example = "测试内容")
@NotNull(message = "模版内容不能为空")
private String templateContent;
@ApiModelProperty(value = "模版类型", required = true, example = "2")
@NotNull(message = "模版类型不能为空")
private Integer templateType;
@ApiModelProperty(value = "芋艿") @ApiModelProperty(value = "模版参数", required = true)
private String sendUserName; @NotNull(message = "模版参数不能为空")
private Map<String, Object> templateParams;
@ApiModelProperty(value = "是否已读 false-未读 true-已读") @ApiModelProperty(value = "是否已读", required = true, example = "true")
@NotNull(message = "是否已读不能为空")
private Boolean readStatus; private Boolean readStatus;
@ApiModelProperty(value = "阅读时间") @ApiModelProperty(value = "阅读时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date readTime; private LocalDateTime readTime;
} }

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.log; package cn.iocoder.yudao.module.system.controller.admin.notify.vo.message;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
@ -8,23 +8,21 @@ import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date; import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 站内信日志分页 Request VO") @ApiModel("管理后台 - 站内信分页 Request VO")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true) @ToString(callSuper = true)
public class NotifyLogPageReqVO extends PageParam { public class NotifyMessageMyPageReqVO extends PageParam {
@ApiModelProperty(value = "模版编码") @ApiModelProperty(value = "是否已读", example = "true")
private String templateCode; private Boolean readStatus;
@ApiModelProperty(value = "标题")
private String title;
@ApiModelProperty(value = "创建时间") @ApiModelProperty(value = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] sendTime; private LocalDateTime[] createTime;
} }

@ -8,6 +8,7 @@ import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import java.util.Date; import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; 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_
@ToString(callSuper = true) @ToString(callSuper = true)
public class NotifyMessagePageReqVO extends PageParam { public class NotifyMessagePageReqVO extends PageParam {
@ApiModelProperty(value = "标题") @ApiModelProperty(value = "用户编号", example = "25025")
private String title; private Long userId;
@ApiModelProperty(value = "是否已读 0-未读 1-已读") @ApiModelProperty(value = "用户类型", example = "1")
private Boolean readStatus; private Integer userType;
@ApiModelProperty(value = "模板编码", example = "test_01")
private String templateCode;
@ApiModelProperty(value = "模版类型", example = "2")
private Integer templateType;
@ApiModelProperty(value = "创建时间") @ApiModelProperty(value = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] createTime; private LocalDateTime[] createTime;
} }

@ -10,7 +10,10 @@ import io.swagger.annotations.*;
@ToString(callSuper = true) @ToString(callSuper = true)
public class NotifyMessageRespVO extends NotifyMessageBaseVO { public class NotifyMessageRespVO extends NotifyMessageBaseVO {
@ApiModelProperty(value = "ID", required = true) @ApiModelProperty(value = "ID", required = true, example = "1024")
private Long id; private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
} }

@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.validation.InEnum;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
/** /**
@ -14,24 +15,32 @@ import javax.validation.constraints.NotNull;
@Data @Data
public class NotifyTemplateBaseVO { public class NotifyTemplateBaseVO {
@ApiModelProperty(value = "模版编码", required = true) @ApiModelProperty(value = "模版名称", required = true, example = "测试模版")
@NotEmpty(message = "模版名称不能为空")
private String name;
@ApiModelProperty(value = "模版编码", required = true, example = "SEND_TEST")
@NotNull(message = "模版编码不能为空") @NotNull(message = "模版编码不能为空")
private String code; private String code;
@ApiModelProperty(value = "模版标题", required = true) @ApiModelProperty(value = "模版类型", required = true, example = "1", notes = "对应 system_notify_template_type 字典")
@NotNull(message = "模版标题不能为空") @NotNull(message = "模版类型不能为空")
private String title; private Integer type;
@ApiModelProperty(value = "发送人名称", required = true, example = "土豆")
@NotEmpty(message = "发送人名称不能为空")
private String nickname;
@ApiModelProperty(value = "模版内容", required = true) @ApiModelProperty(value = "模版内容", required = true, example = "我是模版内容")
@NotNull(message = "模版内容不能为空") @NotEmpty(message = "模版内容不能为空")
private String content; private String content;
@ApiModelProperty(value = "状态1-启用 0-禁用", required = true) @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
@NotNull(message = "状态1-启用 0-禁用不能为空") @NotNull(message = "状态不能为空")
@InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
private Integer status; private Integer status;
@ApiModelProperty(value = "备注") @ApiModelProperty(value = "备注", example = "我是备注")
private String remarks; private String remark;
} }

@ -8,5 +8,4 @@ import io.swagger.annotations.*;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true) @ToString(callSuper = true)
public class NotifyTemplateCreateReqVO extends NotifyTemplateBaseVO { public class NotifyTemplateCreateReqVO extends NotifyTemplateBaseVO {
} }

@ -1,43 +0,0 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template;
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import com.alibaba.excel.annotation.ExcelProperty;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
/**
* Excel VO
*
* @author
*/
@Data
public class NotifyTemplateExcelVO {
@ExcelProperty("ID")
private Long id;
@ExcelProperty("模版编码")
private String code;
@ExcelProperty("模版标题")
private String title;
@ExcelProperty("模版内容")
private String content;
@ExcelProperty(value = "状态1-启用 0-禁用", converter = DictConvert.class)
@DictFormat(DictTypeConstants.COMMON_STATUS)
private Integer status;
@ExcelProperty("备注")
private String remarks;
@ExcelProperty("创建时间")
private Date createTime;
}

@ -1,28 +0,0 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel(value = "管理后台 - 站内信模版 Excel 导出 Request VO", description = "参数和 NotifyTemplatePageReqVO 是一致的")
@Data
public class NotifyTemplateExportReqVO {
@ApiModelProperty(value = "模版编码")
private String code;
@ApiModelProperty(value = "模版标题")
private String title;
@ApiModelProperty(value = "状态1-启用 0-禁用")
private Integer status;
@ApiModelProperty(value = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] createTime;
}

@ -1,6 +1,9 @@
package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template; package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import lombok.*; import lombok.*;
import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import io.swagger.annotations.*; import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ -14,17 +17,17 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@ToString(callSuper = true) @ToString(callSuper = true)
public class NotifyTemplatePageReqVO extends PageParam { public class NotifyTemplatePageReqVO extends PageParam {
@ApiModelProperty(value = "模版编码") @ApiModelProperty(value = "模版编码", example = "test_01")
private String code; private String code;
@ApiModelProperty(value = "模版标题") @ApiModelProperty(value = "模版名称", example = "我是名称")
private String title; private String name;
@ApiModelProperty(value = "状态1-启用 0-禁用") @ApiModelProperty(value = "状态", example = "1", notes = "参见 CommonStatusEnum 枚举类")
private String status; private Integer status;
@ApiModelProperty(value = "创建时间") @ApiModelProperty(value = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date[] createTime; private LocalDateTime[] createTime;
} }

@ -10,7 +10,7 @@ import io.swagger.annotations.*;
@ToString(callSuper = true) @ToString(callSuper = true)
public class NotifyTemplateRespVO extends NotifyTemplateBaseVO { public class NotifyTemplateRespVO extends NotifyTemplateBaseVO {
@ApiModelProperty(value = "ID", required = true) @ApiModelProperty(value = "ID", required = true, example = "1024")
private Long id; private Long id;
@ApiModelProperty(value = "参数数组", example = "name,code") @ApiModelProperty(value = "参数数组", example = "name,code")

@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.Map; import java.util.Map;
@ -16,7 +17,7 @@ public class NotifyTemplateSendReqVO {
private Long userId; private Long userId;
@ApiModelProperty(value = "模板编码", required = true, example = "01") @ApiModelProperty(value = "模板编码", required = true, example = "01")
@NotNull(message = "模板编码不能为空") @NotEmpty(message = "模板编码不能为空")
private String templateCode; private String templateCode;
@ApiModelProperty(value = "模板参数") @ApiModelProperty(value = "模板参数")

@ -10,8 +10,8 @@ import javax.validation.constraints.*;
@ToString(callSuper = true) @ToString(callSuper = true)
public class NotifyTemplateUpdateReqVO extends NotifyTemplateBaseVO { public class NotifyTemplateUpdateReqVO extends NotifyTemplateBaseVO {
@ApiModelProperty(value = "ID", required = true) @ApiModelProperty(value = "ID", required = true, example = "1024")
@NotNull(message = "ID不能为空") @NotNull(message = "ID 不能为空")
private Long id; private Long id;
} }

@ -1,23 +0,0 @@
package cn.iocoder.yudao.module.system.convert.notify;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.log.NotifyLogBaseVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* <p>
*
* </p>
*
* @author LuoWenFeng
*/
@Mapper
public interface NotifyLogConvert {
NotifyLogConvert INSTANCE = Mappers.getMapper(NotifyLogConvert.class);
PageResult<NotifyLogBaseVO> convertPage(PageResult<NotifyMessageDO> page);
}

@ -5,7 +5,6 @@ import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateExcelVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateRespVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateRespVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
@ -32,6 +31,4 @@ public interface NotifyTemplateConvert {
PageResult<NotifyTemplateRespVO> convertPage(PageResult<NotifyTemplateDO> page); PageResult<NotifyTemplateRespVO> convertPage(PageResult<NotifyTemplateDO> page);
List<NotifyTemplateExcelVO> convertList02(List<NotifyTemplateDO> list);
} }

@ -2,19 +2,24 @@ package cn.iocoder.yudao.module.system.dal.dataobject.notify;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.*; import lombok.*;
import java.time.LocalDateTime;
import java.util.Date; import java.util.Date;
import java.util.Map;
/** /**
* DO * DO
* *
* @author xrcoder * @author xrcoder
*/ */
@TableName("system_notify_message") @TableName(value = "system_notify_message", autoResultMap = true)
@KeySequence("system_notify_message_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @KeySequence("system_notify_message_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ -25,22 +30,10 @@ import java.util.Date;
public class NotifyMessageDO extends BaseDO { public class NotifyMessageDO extends BaseDO {
/** /**
* ID *
*/ */
@TableId @TableId
private Long id; private Long id;
/**
*
*
* {@link NotifyTemplateDO#getId()}
*/
private Long templateId;
/**
*
*
* {@link NotifyTemplateDO#getCode()}
*/
private String templateCode;
/** /**
* *
* *
@ -53,28 +46,49 @@ public class NotifyMessageDO extends BaseDO {
* {@link UserTypeEnum} * {@link UserTypeEnum}
*/ */
private Integer userType; private Integer userType;
// ========= 模板相关字段 =========
/**
*
*
* {@link NotifyTemplateDO#getId()}
*/
private Long templateId;
/** /**
* *
*
* {@link NotifyTemplateDO#getCode()}
*/ */
private String title; private String templateCode;
/** /**
* *
*
* {@link NotifyTemplateDO#getType()}
*/ */
private String content; private Integer templateType;
// TODO @luowenfeng是不是创建时间直接作为发送时间
/** /**
* *
*
* {@link NotifyTemplateDO#getNickname()}
*/ */
private Date sendTime; private String templateNickname;
// TODO @luowenfeng是不是不用发送 id 和名字😑?
/** /**
* id *
*
* {@link NotifyTemplateDO#getContent()}
*/ */
private Long sendUserId; private String templateContent;
/** /**
* *
*
* {@link NotifyTemplateDO#getParams()}
*/ */
private String sendUserName; @TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, Object> templateParams;
// ========= 读取相关字段 =========
/** /**
* *
*/ */
@ -82,6 +96,6 @@ public class NotifyMessageDO extends BaseDO {
/** /**
* *
*/ */
private Date readTime; private LocalDateTime readTime;
} }

@ -31,14 +31,24 @@ public class NotifyTemplateDO extends BaseDO {
*/ */
@TableId @TableId
private Long id; private Long id;
/**
*
*/
private String name;
/** /**
* *
*/ */
private String code; private String code;
/** /**
* *
*
* system_notify_template_type
*/
private Integer type;
/**
*
*/ */
private String title; private String nickname;
/** /**
* *
*/ */

@ -3,60 +3,65 @@ package cn.iocoder.yudao.module.system.dal.mysql.notify;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.log.NotifyLogPageReqVO; import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO; import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List; import java.util.List;
/**
* Mapper
*
* @author xrcoder
*/
@Mapper @Mapper
public interface NotifyMessageMapper extends BaseMapperX<NotifyMessageDO> { public interface NotifyMessageMapper extends BaseMapperX<NotifyMessageDO> {
default PageResult<NotifyMessageDO> selectPage(NotifyMessagePageReqVO reqVO, Long userId, Integer userType) { default PageResult<NotifyMessageDO> selectPage(NotifyMessagePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<NotifyMessageDO>() return selectPage(reqVO, new LambdaQueryWrapperX<NotifyMessageDO>()
.likeIfPresent(NotifyMessageDO::getTitle, reqVO.getTitle()) .eqIfPresent(NotifyMessageDO::getUserId, reqVO.getUserId())
.eqIfPresent(NotifyMessageDO::getReadStatus, reqVO.getReadStatus()) .eqIfPresent(NotifyMessageDO::getUserType, reqVO.getUserType())
.likeIfPresent(NotifyMessageDO::getTemplateCode, reqVO.getTemplateCode())
.eqIfPresent(NotifyMessageDO::getTemplateType, reqVO.getTemplateType())
.betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime()) .betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime())
.eq(NotifyMessageDO::getUserId, userId)
.eq(NotifyMessageDO::getUserType, userType)
.orderByDesc(NotifyMessageDO::getId)); .orderByDesc(NotifyMessageDO::getId));
} }
default PageResult<NotifyMessageDO> selectSendPage(NotifyLogPageReqVO reqVO, Long userId) { default PageResult<NotifyMessageDO> selectPage(NotifyMessageMyPageReqVO reqVO, Long userId, Integer userType) {
return selectPage(reqVO, new LambdaQueryWrapperX<NotifyMessageDO>() return selectPage(reqVO, new LambdaQueryWrapperX<NotifyMessageDO>()
.likeIfPresent(NotifyMessageDO::getTitle, reqVO.getTitle()) .eq(NotifyMessageDO::getReadStatus, reqVO.getReadStatus())
.betweenIfPresent(NotifyMessageDO::getSendTime, reqVO.getSendTime()) .betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(NotifyMessageDO::getTemplateCode, reqVO.getTemplateCode()) .eq(NotifyMessageDO::getUserId, userId)
.eq(NotifyMessageDO::getSendUserId, userId) .eq(NotifyMessageDO::getUserType, userType)
.orderByDesc(NotifyMessageDO::getId)); .orderByDesc(NotifyMessageDO::getId));
} }
default List<NotifyMessageDO> selectList(NotifyMessagePageReqVO reqVO, Integer size, Long userId, Integer userType) { default int updateListRead(Collection<Long> ids, Long userId, Integer userType) {
return selectList(new LambdaQueryWrapperX<NotifyMessageDO>() return update(new NotifyMessageDO().setReadStatus(true).setReadTime(LocalDateTime.now()),
.likeIfPresent(NotifyMessageDO::getTitle, reqVO.getTitle()) new LambdaQueryWrapperX<NotifyMessageDO>()
.eqIfPresent(NotifyMessageDO::getReadStatus, reqVO.getReadStatus()) .in(NotifyMessageDO::getId, ids)
.betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime()) .eq(NotifyMessageDO::getUserId, userId)
.eqIfPresent(NotifyMessageDO::getUserId, userId) .eq(NotifyMessageDO::getUserType, userType)
.eqIfPresent(NotifyMessageDO::getUserType, userType) .eq(NotifyMessageDO::getReadStatus, false));
.orderByDesc(NotifyMessageDO::getId)
.last("limit " + size));
} }
default Long selectUnreadCountByUserIdAndUserType(Long userId, Integer userType) { default int updateListRead(Long userId, Integer userType) {
return selectCount(new LambdaQueryWrapperX<NotifyMessageDO>() return update(new NotifyMessageDO().setReadStatus(true).setReadTime(LocalDateTime.now()),
.eq(NotifyMessageDO::getReadStatus, false) new LambdaQueryWrapperX<NotifyMessageDO>()
.eq(NotifyMessageDO::getUserId, userId) .eq(NotifyMessageDO::getUserId, userId)
.eq(NotifyMessageDO::getUserType, userType)); .eq(NotifyMessageDO::getUserType, userType)
.eq(NotifyMessageDO::getReadStatus, false));
} }
default List<NotifyMessageDO> selectUnreadListByUserIdAndUserType(Long userId, Integer userType) { default List<NotifyMessageDO> selectUnreadListByUserIdAndUserType(Long userId, Integer userType, Integer size) {
return selectList(new LambdaQueryWrapperX<NotifyMessageDO>() return selectList(new QueryWrapperX<NotifyMessageDO>() // 由于要使用 limitN 语句,所以只能用 QueryWrapperX
.eq("user_id", userId)
.eq("user_type", userType)
.eq("read_status", false)
.orderByDesc("id").limitN(size));
}
default Long selectUnreadCountByUserIdAndUserType(Long userId, Integer userType) {
return selectCount(new LambdaQueryWrapperX<NotifyMessageDO>()
.eq(NotifyMessageDO::getReadStatus, false) .eq(NotifyMessageDO::getReadStatus, false)
.eq(NotifyMessageDO::getUserId, userId) .eq(NotifyMessageDO::getUserId, userId)
.eq(NotifyMessageDO::getUserType, userType)); .eq(NotifyMessageDO::getUserType, userType));

@ -1,45 +1,23 @@
package cn.iocoder.yudao.module.system.dal.mysql.notify; package cn.iocoder.yudao.module.system.dal.mysql.notify;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateExportReqVO; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
/**
* Mapper
*
* @author xrcoder
*/
@Mapper @Mapper
public interface NotifyTemplateMapper extends BaseMapperX<NotifyTemplateDO> { public interface NotifyTemplateMapper extends BaseMapperX<NotifyTemplateDO> {
@Select("SELECT COUNT(*) FROM system_notify_template WHERE update_time > #{maxUpdateTime}")
Long selectCountByUpdateTimeGt(Date maxUpdateTime);
default NotifyTemplateDO selectByCode(String code) { default NotifyTemplateDO selectByCode(String code) {
return selectOne(NotifyTemplateDO::getCode, code); return selectOne(NotifyTemplateDO::getCode, code);
} }
default PageResult<NotifyTemplateDO> selectPage(NotifyTemplatePageReqVO reqVO) { default PageResult<NotifyTemplateDO> selectPage(NotifyTemplatePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<NotifyTemplateDO>() return selectPage(reqVO, new LambdaQueryWrapperX<NotifyTemplateDO>()
.eqIfPresent(NotifyTemplateDO::getCode, reqVO.getCode()) .likeIfPresent(NotifyTemplateDO::getCode, reqVO.getCode())
.eqIfPresent(NotifyTemplateDO::getTitle, reqVO.getTitle()) .likeIfPresent(NotifyTemplateDO::getName, reqVO.getName())
.eqIfPresent(NotifyTemplateDO::getStatus, reqVO.getStatus())
.betweenIfPresent(NotifyTemplateDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(NotifyTemplateDO::getId));
}
default List<NotifyTemplateDO> selectList(NotifyTemplateExportReqVO reqVO) {
return selectList(new LambdaQueryWrapperX<NotifyTemplateDO>()
.eqIfPresent(NotifyTemplateDO::getCode, reqVO.getCode())
.eqIfPresent(NotifyTemplateDO::getTitle, reqVO.getTitle())
.eqIfPresent(NotifyTemplateDO::getStatus, reqVO.getStatus()) .eqIfPresent(NotifyTemplateDO::getStatus, reqVO.getStatus())
.betweenIfPresent(NotifyTemplateDO::getCreateTime, reqVO.getCreateTime()) .betweenIfPresent(NotifyTemplateDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(NotifyTemplateDO::getId)); .orderByDesc(NotifyTemplateDO::getId));

@ -22,7 +22,7 @@ public interface SmsCodeMapper extends BaseMapperX<SmsCodeDO> {
.eqIfPresent("scene", scene) .eqIfPresent("scene", scene)
.eqIfPresent("code", code) .eqIfPresent("code", code)
.orderByDesc("id") .orderByDesc("id")
.limit1()); .limitN(1));
} }
} }

@ -45,7 +45,7 @@ public interface MailLogService {
* @param isSend * @param isSend
* @return * @return
*/ */
Long createMailLog(Long userId,Integer userType, String toMail, Long createMailLog(Long userId, Integer userType, String toMail,
MailAccountDO account, MailTemplateDO template , MailAccountDO account, MailTemplateDO template ,
String templateContent, Map<String, Object> templateParams, Boolean isSend); String templateContent, Map<String, Object> templateParams, Boolean isSend);

@ -88,8 +88,7 @@ public class MailSendServiceImpl implements MailSendService {
// 校验邮箱是否存在 // 校验邮箱是否存在
mail = checkMail(mail); mail = checkMail(mail);
// 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志 checkTemplateParams(template, templateParams);
List<KeyValue<String, Object>> newTemplateParams = buildTemplateParams(template, templateParams);
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志 // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()); Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus());
@ -152,21 +151,19 @@ public class MailSendServiceImpl implements MailSendService {
} }
/** /**
* KeyValue *
* *
* @param template * @param template
* @param templateParams * @param templateParams
* @return
*/ */
@VisibleForTesting @VisibleForTesting
public List<KeyValue<String, Object>> buildTemplateParams(MailTemplateDO template, Map<String, Object> templateParams) { public void checkTemplateParams(MailTemplateDO template, Map<String, Object> templateParams) {
return template.getParams().stream().map(key -> { template.getParams().forEach(key -> {
Object value = templateParams.get(key); Object value = templateParams.get(key);
if (value == null) { if (value == null) {
throw exception(MAIL_SEND_TEMPLATE_PARAM_MISS, key); throw exception(MAIL_SEND_TEMPLATE_PARAM_MISS, key);
} }
return new KeyValue<>(key, value); });
}).collect(Collectors.toList());
} }
} }

@ -1,24 +0,0 @@
package cn.iocoder.yudao.module.system.service.notify;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.log.NotifyLogPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
/**
* Service
*
* @author LuoWenFeng
*/
public interface NotifyLogService {
// TODO @LuoWenFengNotifyLogService=》NotifyMessageService
/**
*
*
* @param pageReqVO
* @return
*/
PageResult<NotifyMessageDO> getNotifyMessageSendPage(NotifyLogPageReqVO pageReqVO);
}

@ -1,35 +0,0 @@
package cn.iocoder.yudao.module.system.service.notify;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.log.NotifyLogPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyMessageMapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
/**
* <p>
* Service
*
* </p>
*
* @author LuoWenFeng
*/
@Service
@Validated
public class NotifyLogServiceImpl implements NotifyLogService {
@Resource
private NotifyMessageMapper notifyMessageMapper;
@Override
public PageResult<NotifyMessageDO> getNotifyMessageSendPage(NotifyLogPageReqVO pageReqVO) {
return notifyMessageMapper.selectSendPage(pageReqVO, getLoginUserId());
}
}

@ -1,11 +1,14 @@
package cn.iocoder.yudao.module.system.service.notify; package cn.iocoder.yudao.module.system.service.notify;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO; import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Service * Service
@ -15,68 +18,80 @@ import java.util.List;
public interface NotifyMessageService { public interface NotifyMessageService {
/** /**
* *
* *
* @param id * @param userId
* @return * @param userType
* @param template
* @param templateContent
* @param templateParams
* @return
*/ */
NotifyMessageDO getNotifyMessage(Long id); Long createNotifyMessage(Long userId, Integer userType,
NotifyTemplateDO template, String templateContent, Map<String, Object> templateParams);
/** /**
* *
* *
* @param ids * @param pageReqVO
* @return * @return
*/ */
List<NotifyMessageDO> getNotifyMessageList(Collection<Long> ids); PageResult<NotifyMessageDO> getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO);
/** /**
* *
* *
* @param pageReqVO * @param pageReqVO
* @param userId
* @param userType
* @return * @return
*/ */
List<NotifyMessageDO> getNotifyMessageList(NotifyMessagePageReqVO pageReqVO, Integer size); PageResult<NotifyMessageDO> getMyMyNotifyMessagePage(NotifyMessageMyPageReqVO pageReqVO, Long userId, Integer userType);
/** /**
* *
* *
* @param pageReqVO * @param id
* @return * @return
*/ */
PageResult<NotifyMessageDO> getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO); NotifyMessageDO getNotifyMessage(Long id);
/** /**
* *
* *
* @param userId ID * @param userId
* @param userType * @param userType
* @return * @param size
* @return
*/ */
Long getUnreadNotifyMessageCount(Long userId, Integer userType); List<NotifyMessageDO> getUnreadNotifyMessageList(Long userId, Integer userType, Integer size);
/** /**
* *
* *
* @param id * @param userId
* @param status * @param userType
* @return
*/ */
void updateNotifyMessageReadStatus(Long id, Boolean status); Long getUnreadNotifyMessageCount(Long userId, Integer userType);
/** /**
* *
* *
* @param ids * @param ids
* @param userId ID * @param userId
* @param userType
* @return
*/ */
void batchUpdateNotifyMessageReadStatus(Collection<Long> ids, Long userId); int updateNotifyMessageRead(Collection<Long> ids, Long userId, Integer userType);
/** /**
* *
* *
* @param userId ID * @param userId
* @param userType * @param userType
* @return
*/ */
void batchUpdateAllNotifyMessageReadStatus(Long userId, Integer userType); int updateAllNotifyMessageRead(Long userId, Integer userType);
} }

@ -1,30 +1,20 @@
package cn.iocoder.yudao.module.system.service.notify; package cn.iocoder.yudao.module.system.service.notify;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO; import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyMessageMapper; import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyMessageMapper;
import com.google.common.annotations.VisibleForTesting;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collection; import java.util.Collection;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
/** /**
* Service * Service
@ -38,142 +28,50 @@ public class NotifyMessageServiceImpl implements NotifyMessageService {
@Resource @Resource
private NotifyMessageMapper notifyMessageMapper; private NotifyMessageMapper notifyMessageMapper;
@Resource @Override
private NotifyTemplateService notifyTemplateService; public Long createNotifyMessage(Long userId, Integer userType,
NotifyTemplateDO template, String templateContent, Map<String, Object> templateParams) {
NotifyMessageDO message = new NotifyMessageDO().setUserId(userId).setUserType(userType)
@VisibleForTesting .setTemplateId(template.getId()).setTemplateCode(template.getCode())
public NotifyTemplateDO checkNotifyTemplateValid(String templateCode) { .setTemplateType(template.getType()).setTemplateNickname(template.getNickname())
// 获得站内信模板。考虑到效率,从缓存中获取 .setTemplateContent(templateContent).setTemplateParams(templateParams).setReadStatus(false);
NotifyTemplateDO template = notifyTemplateService.getNotifyTemplateByCodeFromCache(templateCode); notifyMessageMapper.insert(message);
// 站内信模板不存在 return message.getId();
if (template == null) {
throw exception(NOTIFY_TEMPLATE_NOT_EXISTS);
}
return template;
}
/**
* KeyValue
*
* @param template
* @param templateParams
* @return
*/
@VisibleForTesting
public List<KeyValue<String, Object>> buildTemplateParams(NotifyTemplateDO template, Map<String, Object> templateParams) {
return template.getParams().stream().map(key -> {
Object value = templateParams.get(key);
if (value == null) {
throw exception(NOTIFY_TEMPLATE_PARAM_MISS, key);
}
return new KeyValue<>(key, value);
}).collect(Collectors.toList());
}
private void validateNotifyMessageExists(Long id) {
if (notifyMessageMapper.selectById(id) == null) {
throw exception(NOTIFY_MESSAGE_NOT_EXISTS);
}
} }
@Override @Override
public NotifyMessageDO getNotifyMessage(Long id) { public PageResult<NotifyMessageDO> getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO) {
return notifyMessageMapper.selectById(id); return notifyMessageMapper.selectPage(pageReqVO);
} }
@Override @Override
public List<NotifyMessageDO> getNotifyMessageList(Collection<Long> ids) { public PageResult<NotifyMessageDO> getMyMyNotifyMessagePage(NotifyMessageMyPageReqVO pageReqVO, Long userId, Integer userType) {
return notifyMessageMapper.selectBatchIds(ids); return notifyMessageMapper.selectPage(pageReqVO, userId, userType);
} }
@Override @Override
public List<NotifyMessageDO> getNotifyMessageList(NotifyMessagePageReqVO pageReqVO, Integer size) { public NotifyMessageDO getNotifyMessage(Long id) {
return notifyMessageMapper.selectList(pageReqVO, size, getLoginUserId(), UserTypeEnum.ADMIN.getValue()); return notifyMessageMapper.selectById(id);
} }
@Override @Override
public PageResult<NotifyMessageDO> getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO) { public List<NotifyMessageDO> getUnreadNotifyMessageList(Long userId, Integer userType, Integer size) {
return notifyMessageMapper.selectPage(pageReqVO, getLoginUserId(), UserTypeEnum.ADMIN.getValue()); return notifyMessageMapper.selectUnreadListByUserIdAndUserType(userId, userType, size);
} }
/**
*
*
* @param userId ID
* @param userType
* @return
*/
@Override @Override
public Long getUnreadNotifyMessageCount(Long userId, Integer userType) { public Long getUnreadNotifyMessageCount(Long userId, Integer userType) {
return notifyMessageMapper.selectUnreadCountByUserIdAndUserType(userId, userType); return notifyMessageMapper.selectUnreadCountByUserIdAndUserType(userId, userType);
} }
/**
*
*
* @param id
* @param status
*/
@Override
public void updateNotifyMessageReadStatus(Long id, Boolean status) {
// 校验消息是否存在
this.validateNotifyMessageExists(id);
// 更新状态
batchUpdateReadStatus(CollectionUtils.singleton(id));
}
/**
*
*
* @param ids
* @param userId ID
*/
@Override @Override
public void batchUpdateNotifyMessageReadStatus(Collection<Long> ids, Long userId) { public int updateNotifyMessageRead(Collection<Long> ids, Long userId, Integer userType) {
List<NotifyMessageDO> list = getNotifyMessageList(ids); return notifyMessageMapper.updateListRead(ids, userId, userType);
if (CollUtil.isEmpty(list)) {
throw exception(NOTIFY_MESSAGE_NOT_EXISTS);
}
// 验证站内信是否是属于用户
for (NotifyMessageDO messageDO : list) {
checkNotifyMessageIdValid(messageDO, userId);
}
batchUpdateReadStatus(ids);
}
@VisibleForTesting
public void checkNotifyMessageIdValid(NotifyMessageDO notifyMessageDO, Long userId) {
if (!NumberUtil.equals(notifyMessageDO.getUserId(), userId)) {
throw exception(NOTIFY_MESSAGE_ID_PARAM_ERROR);
}
} }
/**
*
*
* @param userId ID
* @param userType
*/
@Override @Override
public void batchUpdateAllNotifyMessageReadStatus(Long userId, Integer userType) { public int updateAllNotifyMessageRead(Long userId, Integer userType) {
List<NotifyMessageDO> list = notifyMessageMapper.selectUnreadListByUserIdAndUserType(userId, userType); return notifyMessageMapper.updateListRead(userId, userType);
if (CollUtil.isNotEmpty(list)) {
batchUpdateReadStatus(CollectionUtils.convertList(list, NotifyMessageDO::getId));
}
}
/**
*
*
* @param ids
*/
private void batchUpdateReadStatus(Collection<Long> ids) {
NotifyMessageDO updateObj = new NotifyMessageDO();
updateObj.setReadStatus(true);
updateObj.setReadTime(new Date());
// TODO @luowenfeng涉及到 mybatis 的操作,都要隐藏到 mapper 中;
notifyMessageMapper.update(updateObj, new LambdaQueryWrapperX<NotifyMessageDO>().in(NotifyMessageDO::getId, ids));
} }
} }

@ -3,9 +3,13 @@ package cn.iocoder.yudao.module.system.service.notify;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/**
* Service
*
* @author xrcoder
*/
public interface NotifySendService { public interface NotifySendService {
/** /**
* *
* *

@ -1,25 +1,20 @@
package cn.iocoder.yudao.module.system.service.notify; package cn.iocoder.yudao.module.system.service.notify;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyMessageMapper;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTICE_NOT_FOUND;
// TODO @luowenfeng可以直接合并到 NotifyMessageService 中;之前 sms 台复杂,所以没合并。
/** /**
* Service * Service
* *
@ -34,10 +29,7 @@ public class NotifySendServiceImpl implements NotifySendService {
private NotifyTemplateService notifyTemplateService; private NotifyTemplateService notifyTemplateService;
@Resource @Resource
private NotifyMessageMapper notifyMessageMapper; private NotifyMessageService notifyMessageService;
@Resource
private AdminUserService userService;
@Override @Override
public Long sendSingleNotifyToAdmin(Long userId, String templateCode, Map<String, Object> templateParams) { public Long sendSingleNotifyToAdmin(Long userId, String templateCode, Map<String, Object> templateParams) {
@ -51,38 +43,44 @@ public class NotifySendServiceImpl implements NotifySendService {
@Override @Override
public Long sendSingleNotify(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams) { public Long sendSingleNotify(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams) {
// 校验短信模板是否合法 // 校验模版
NotifyTemplateDO template = this.checkNotifyTemplateValid(templateCode); NotifyTemplateDO template = checkNotifyTemplateValid(templateCode);
String content = notifyTemplateService.formatNotifyTemplateContent(template.getContent(), templateParams); if (Objects.equals(template.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
// 获得用户 log.info("[sendSingleNotify][模版({})已经关闭,无法给用户({}/{})发送]", templateCode, userId, userType);
AdminUserDO sendUser = userService.getUser(getLoginUserId()); return null;
}
// 校验参数
checkTemplateParams(template, templateParams);
// todo 模板状态未开启时的业务;如果未开启,就直接 return 好了; // 发送站内信
NotifyMessageDO notifyMessageDO = new NotifyMessageDO(); String content = notifyTemplateService.formatNotifyTemplateContent(template.getContent(), templateParams);
notifyMessageDO.setContent(content); return notifyMessageService.createNotifyMessage(userId, userType, template, content, templateParams);
notifyMessageDO.setTitle(template.getTitle());
notifyMessageDO.setReadStatus(false);
notifyMessageDO.setTemplateId(template.getId());
notifyMessageDO.setTemplateCode(templateCode);
notifyMessageDO.setUserId(userId);
notifyMessageDO.setUserType(userType);
notifyMessageDO.setSendTime(new Date());
notifyMessageDO.setSendUserId(sendUser.getId());
notifyMessageDO.setSendUserName(sendUser.getUsername());
notifyMessageMapper.insert(notifyMessageDO);
return notifyMessageDO.getId();
} }
// 此注解的含义
@VisibleForTesting @VisibleForTesting
public NotifyTemplateDO checkNotifyTemplateValid(String templateCode) { public NotifyTemplateDO checkNotifyTemplateValid(String templateCode) {
// 获得信模板。考虑到效率,从缓存中获取 // 获得站内信模板。考虑到效率,从缓存中获取
NotifyTemplateDO template = notifyTemplateService.getNotifyTemplateByCodeFromCache(templateCode); NotifyTemplateDO template = notifyTemplateService.getNotifyTemplateByCodeFromCache(templateCode);
// 信模板不存在 // 站内信模板不存在
if (template == null) { if (template == null) {
throw exception(NOTICE_NOT_FOUND); throw exception(NOTICE_NOT_FOUND);
} }
return template; return template;
} }
/**
*
*
* @param template
* @param templateParams
*/
@VisibleForTesting
public void checkTemplateParams(NotifyTemplateDO template, Map<String, Object> templateParams) {
template.getParams().forEach(key -> {
Object value = templateParams.get(key);
if (value == null) {
throw exception(NOTIFY_SEND_TEMPLATE_PARAM_MISS, key);
}
});
}
} }

@ -2,14 +2,11 @@ package cn.iocoder.yudao.module.system.service.notify;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@ -17,7 +14,6 @@ import java.util.Map;
* *
* @author xrcoder * @author xrcoder
*/ */
// TODO 芋艿:缺少单测,可以参考 SmsTemplateServiceTest 写下
public interface NotifyTemplateService { public interface NotifyTemplateService {
/** /**
@ -33,16 +29,6 @@ public interface NotifyTemplateService {
*/ */
NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code); NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code);
/**
*
*
* @param content
* @param params
* @return
*/
String formatNotifyTemplateContent(String content, Map<String, Object> params);
/** /**
* *
* *
@ -73,14 +59,6 @@ public interface NotifyTemplateService {
*/ */
NotifyTemplateDO getNotifyTemplate(Long id); NotifyTemplateDO getNotifyTemplate(Long id);
/**
*
*
* @param ids
* @return
*/
List<NotifyTemplateDO> getNotifyTemplateList(Collection<Long> ids);
/** /**
* *
* *
@ -90,11 +68,12 @@ public interface NotifyTemplateService {
PageResult<NotifyTemplateDO> getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO); PageResult<NotifyTemplateDO> getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO);
/** /**
* , Excel *
* *
* @param exportReqVO * @param content
* @return * @param params
* @return
*/ */
List<NotifyTemplateDO> getNotifyTemplateList(NotifyTemplateExportReqVO exportReqVO); String formatNotifyTemplateContent(String content, Map<String, Object> params);
} }

@ -1,12 +1,10 @@
package cn.iocoder.yudao.module.system.service.notify; package cn.iocoder.yudao.module.system.service.notify;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO; import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
import cn.iocoder.yudao.module.system.convert.notify.NotifyTemplateConvert; import cn.iocoder.yudao.module.system.convert.notify.NotifyTemplateConvert;
@ -15,20 +13,17 @@ import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyTemplateMapper;
import cn.iocoder.yudao.module.system.mq.producer.notify.NotifyProducer; import cn.iocoder.yudao.module.system.mq.producer.notify.NotifyProducer;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collection;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_CODE_DUPLICATE; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS;
/** /**
* Service * Service
@ -40,12 +35,6 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEM
@Slf4j @Slf4j
public class NotifyTemplateServiceImpl implements NotifyTemplateService { public class NotifyTemplateServiceImpl implements NotifyTemplateService {
/**
* {@link #schedulePeriodicRefresh()}
* Redis Pub/Sub
*/
private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
/** /**
* {} * {}
*/ */
@ -65,82 +54,25 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService {
*/ */
private volatile Map<String, NotifyTemplateDO> notifyTemplateCache; private volatile Map<String, NotifyTemplateDO> notifyTemplateCache;
/**
*
*/
private volatile Date maxUpdateTime;
/** /**
* *
*/ */
@Override @Override
@PostConstruct
public void initLocalCache() { public void initLocalCache() {
// 获取站内信模板列表,如果有更新 // 第一步:查询数据
List<NotifyTemplateDO> notifyTemplateList = this.loadNotifyTemplateIfUpdate(maxUpdateTime); List<NotifyTemplateDO> templates = notifyTemplateMapper.selectList();
if (CollUtil.isEmpty(notifyTemplateList)) { log.info("[initLocalCache][缓存站内信模版,数量为:{}]", templates.size());
return;
}
// 写入缓存
notifyTemplateCache = CollectionUtils.convertMap(notifyTemplateList, NotifyTemplateDO::getCode);
maxUpdateTime = CollectionUtils.getMaxValue(notifyTemplateList, NotifyTemplateDO::getUpdateTime);
log.info("[initLocalCache][初始化 NotifyTemplate 数量为 {}]", notifyTemplateList.size());
}
/**
*
*
*
* @param maxUpdateTime
* @return
*/
private List<NotifyTemplateDO> loadNotifyTemplateIfUpdate(Date maxUpdateTime) {
// 第一步,判断是否要更新。
if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据
log.info("[loadNotifyTemplateIfUpdate][首次加载全量站内信模板]");
} else { // 判断数据库中是否有更新的站内信模板
if (notifyTemplateMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
return null;
}
log.info("[loadNotifyTemplateIfUpdate][增量加载全量站内信模板]");
}
// 第二步,如果有更新,则从数据库加载所有站内信模板
return notifyTemplateMapper.selectList();
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD) // 第二步:构建缓存
public void schedulePeriodicRefresh() { notifyTemplateCache = CollectionUtils.convertMap(templates, NotifyTemplateDO::getCode);
initLocalCache();
} }
/**
*
*
* @param code
* @return
*/
@Override @Override
public NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code) { public NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code) {
return notifyTemplateCache.get(code); return notifyTemplateCache.get(code);
} }
/**
*
*
* @param content
* @param params
* @return
*/
@Override
public String formatNotifyTemplateContent(String content, Map<String, Object> params) {
return StrUtil.format(content, params);
}
@VisibleForTesting
public List<String> parseTemplateContentParams(String content) {
return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
}
@Override @Override
public Long createNotifyTemplate(NotifyTemplateCreateReqVO createReqVO) { public Long createNotifyTemplate(NotifyTemplateCreateReqVO createReqVO) {
// 校验站内信编码是否重复 // 校验站内信编码是否重复
@ -150,32 +82,37 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService {
NotifyTemplateDO notifyTemplate = NotifyTemplateConvert.INSTANCE.convert(createReqVO); NotifyTemplateDO notifyTemplate = NotifyTemplateConvert.INSTANCE.convert(createReqVO);
notifyTemplate.setParams(parseTemplateContentParams(notifyTemplate.getContent())); notifyTemplate.setParams(parseTemplateContentParams(notifyTemplate.getContent()));
notifyTemplateMapper.insert(notifyTemplate); notifyTemplateMapper.insert(notifyTemplate);
// 发送刷新消息 // 发送刷新消息
notifyProducer.sendNotifyTemplateRefreshMessage(); notifyProducer.sendNotifyTemplateRefreshMessage();
// 返回
return notifyTemplate.getId(); return notifyTemplate.getId();
} }
@Override @Override
public void updateNotifyTemplate(NotifyTemplateUpdateReqVO updateReqVO) { public void updateNotifyTemplate(NotifyTemplateUpdateReqVO updateReqVO) {
// 校验存在 // 校验存在
this.validateNotifyTemplateExists(updateReqVO.getId()); validateNotifyTemplateExists(updateReqVO.getId());
// 校验站内信编码是否重复 // 校验站内信编码是否重复
checkNotifyTemplateCodeDuplicate(updateReqVO.getId(), updateReqVO.getCode()); checkNotifyTemplateCodeDuplicate(updateReqVO.getId(), updateReqVO.getCode());
// 更新 // 更新
NotifyTemplateDO updateObj = NotifyTemplateConvert.INSTANCE.convert(updateReqVO); NotifyTemplateDO updateObj = NotifyTemplateConvert.INSTANCE.convert(updateReqVO);
updateObj.setParams(parseTemplateContentParams(updateObj.getContent())); updateObj.setParams(parseTemplateContentParams(updateObj.getContent()));
notifyTemplateMapper.updateById(updateObj); notifyTemplateMapper.updateById(updateObj);
// 发送刷新消息 // 发送刷新消息
notifyProducer.sendNotifyTemplateRefreshMessage(); notifyProducer.sendNotifyTemplateRefreshMessage();
} }
@VisibleForTesting
public List<String> parseTemplateContentParams(String content) {
return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
}
@Override @Override
public void deleteNotifyTemplate(Long id) { public void deleteNotifyTemplate(Long id) {
// 校验存在 // 校验存在
this.validateNotifyTemplateExists(id); validateNotifyTemplateExists(id);
// 删除 // 删除
notifyTemplateMapper.deleteById(id); notifyTemplateMapper.deleteById(id);
// 发送刷新消息 // 发送刷新消息
@ -193,21 +130,11 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService {
return notifyTemplateMapper.selectById(id); return notifyTemplateMapper.selectById(id);
} }
@Override
public List<NotifyTemplateDO> getNotifyTemplateList(Collection<Long> ids) {
return notifyTemplateMapper.selectBatchIds(ids);
}
@Override @Override
public PageResult<NotifyTemplateDO> getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO) { public PageResult<NotifyTemplateDO> getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO) {
return notifyTemplateMapper.selectPage(pageReqVO); return notifyTemplateMapper.selectPage(pageReqVO);
} }
@Override
public List<NotifyTemplateDO> getNotifyTemplateList(NotifyTemplateExportReqVO exportReqVO) {
return notifyTemplateMapper.selectList(exportReqVO);
}
@VisibleForTesting @VisibleForTesting
public void checkNotifyTemplateCodeDuplicate(Long id, String code) { public void checkNotifyTemplateCodeDuplicate(Long id, String code) {
NotifyTemplateDO template = notifyTemplateMapper.selectByCode(code); NotifyTemplateDO template = notifyTemplateMapper.selectByCode(code);
@ -222,4 +149,16 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService {
throw exception(NOTIFY_TEMPLATE_CODE_DUPLICATE, code); throw exception(NOTIFY_TEMPLATE_CODE_DUPLICATE, code);
} }
} }
/**
*
*
* @param content
* @param params
* @return
*/
@Override
public String formatNotifyTemplateContent(String content, Map<String, Object> params) {
return StrUtil.format(content, params);
}
} }

@ -145,7 +145,7 @@ class MailSendServiceImplTest extends BaseMockitoUnitTest {
} }
@Test @Test
public void testBuildTemplateParams_paramMiss() { public void testCheckTemplateParams_paramMiss() {
// 准备参数 // 准备参数
MailTemplateDO template = randomPojo(MailTemplateDO.class, MailTemplateDO template = randomPojo(MailTemplateDO.class,
o -> o.setParams(Lists.newArrayList("code"))); o -> o.setParams(Lists.newArrayList("code")));
@ -153,7 +153,7 @@ class MailSendServiceImplTest extends BaseMockitoUnitTest {
// mock 方法 // mock 方法
// 调用,并断言异常 // 调用,并断言异常
assertServiceException(() -> mailSendService.buildTemplateParams(template, templateParams), assertServiceException(() -> mailSendService.checkTemplateParams(template, templateParams),
MAIL_SEND_TEMPLATE_PARAM_MISS, "code"); MAIL_SEND_TEMPLATE_PARAM_MISS, "code");
} }

@ -0,0 +1,266 @@
package cn.iocoder.yudao.module.system.service.notify;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyMessageMapper;
import com.baomidou.mybatisplus.annotation.DbType;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static org.junit.jupiter.api.Assertions.*;
/**
* {@link NotifyMessageServiceImpl}
*
* @author
*/
@Import(NotifyMessageServiceImpl.class)
public class NotifyMessageServiceImplTest extends BaseDbUnitTest {
@Resource
private NotifyMessageServiceImpl notifyMessageService;
@Resource
private NotifyMessageMapper notifyMessageMapper;
@Test
public void testCreateNotifyMessage_success() {
// 准备参数
Long userId = randomLongId();
Integer userType = randomEle(UserTypeEnum.values()).getValue();
NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class);
String templateContent = randomString();
Map<String, Object> templateParams = randomTemplateParams();
// mock 方法
// 调用
Long messageId = notifyMessageService.createNotifyMessage(userId, userType,
template, templateContent, templateParams);
// 断言
NotifyMessageDO message = notifyMessageMapper.selectById(messageId);
assertNotNull(message);
assertEquals(userId, message.getUserId());
assertEquals(userType, message.getUserType());
assertEquals(template.getId(), message.getTemplateId());
assertEquals(template.getCode(), message.getTemplateCode());
assertEquals(template.getType(), message.getTemplateType());
assertEquals(template.getNickname(), message.getTemplateNickname());
assertEquals(templateContent, message.getTemplateContent());
assertEquals(templateParams, message.getTemplateParams());
assertEquals(false, message.getReadStatus());
assertNull(message.getReadTime());
}
@Test
public void testGetNotifyMessagePage() {
// mock 数据
NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
o.setUserId(1L);
o.setUserType(UserTypeEnum.ADMIN.getValue());
o.setTemplateCode("test_01");
o.setTemplateType(10);
o.setCreateTime(buildTime(2022, 1, 2));
o.setTemplateParams(randomTemplateParams());
});
notifyMessageMapper.insert(dbNotifyMessage);
// 测试 userId 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
// 测试 userType 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
// 测试 templateCode 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setTemplateCode("test_11")));
// 测试 templateType 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setTemplateType(20)));
// 测试 createTime 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setCreateTime(buildTime(2022, 2, 1))));
// 准备参数
NotifyMessagePageReqVO reqVO = new NotifyMessagePageReqVO();
reqVO.setUserId(1L);
reqVO.setUserType(UserTypeEnum.ADMIN.getValue());
reqVO.setTemplateCode("est_01");
reqVO.setTemplateType(10);
reqVO.setCreateTime(buildBetweenTime(2022, 1, 1, 2022, 1, 10));
// 调用
PageResult<NotifyMessageDO> pageResult = notifyMessageService.getNotifyMessagePage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbNotifyMessage, pageResult.getList().get(0));
}
@Test
public void testGetMyNotifyMessagePage() {
// mock 数据
NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
o.setUserId(1L);
o.setUserType(UserTypeEnum.ADMIN.getValue());
o.setReadStatus(true);
o.setCreateTime(buildTime(2022, 1, 2));
o.setTemplateParams(randomTemplateParams());
});
notifyMessageMapper.insert(dbNotifyMessage);
// 测试 userId 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
// 测试 userType 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
// 测试 readStatus 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(false)));
// 测试 createTime 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setCreateTime(buildTime(2022, 2, 1))));
// 准备参数
Long userId = 1L;
Integer userType = UserTypeEnum.ADMIN.getValue();
NotifyMessageMyPageReqVO reqVO = new NotifyMessageMyPageReqVO();
reqVO.setReadStatus(true);
reqVO.setCreateTime(buildBetweenTime(2022, 1, 1, 2022, 1, 10));
// 调用
PageResult<NotifyMessageDO> pageResult = notifyMessageService.getMyMyNotifyMessagePage(reqVO, userId, userType);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbNotifyMessage, pageResult.getList().get(0));
}
@Test
public void testGetUnreadNotifyMessageList() {
SqlConstants.init(DbType.MYSQL);
// mock 数据
NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
o.setUserId(1L);
o.setUserType(UserTypeEnum.ADMIN.getValue());
o.setReadStatus(false);
o.setTemplateParams(randomTemplateParams());
});
notifyMessageMapper.insert(dbNotifyMessage);
// 测试 userId 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
// 测试 userType 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
// 测试 readStatus 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true)));
// 准备参数
Long userId = 1L;
Integer userType = UserTypeEnum.ADMIN.getValue();
Integer size = 10;
// 调用
List<NotifyMessageDO> list = notifyMessageService.getUnreadNotifyMessageList(userId, userType, size);
// 断言
assertEquals(1, list.size());
assertPojoEquals(dbNotifyMessage, list.get(0));
}
@Test
public void testGetUnreadNotifyMessageCount() {
SqlConstants.init(DbType.MYSQL);
// mock 数据
NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
o.setUserId(1L);
o.setUserType(UserTypeEnum.ADMIN.getValue());
o.setReadStatus(false);
o.setTemplateParams(randomTemplateParams());
});
notifyMessageMapper.insert(dbNotifyMessage);
// 测试 userId 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
// 测试 userType 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
// 测试 readStatus 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true)));
// 准备参数
Long userId = 1L;
Integer userType = UserTypeEnum.ADMIN.getValue();
// 调用,并断言
assertEquals(1, notifyMessageService.getUnreadNotifyMessageCount(userId, userType));
}
@Test
public void testUpdateNotifyMessageRead() {
// mock 数据
NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
o.setUserId(1L);
o.setUserType(UserTypeEnum.ADMIN.getValue());
o.setReadStatus(false);
o.setReadTime(null);
o.setTemplateParams(randomTemplateParams());
});
notifyMessageMapper.insert(dbNotifyMessage);
// 测试 userId 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
// 测试 userType 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
// 测试 readStatus 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true)));
// 准备参数
Collection<Long> ids = Arrays.asList(dbNotifyMessage.getId(), dbNotifyMessage.getId() + 1,
dbNotifyMessage.getId() + 2, dbNotifyMessage.getId() + 3);
Long userId = 1L;
Integer userType = UserTypeEnum.ADMIN.getValue();
// 调用
int updateCount = notifyMessageService.updateNotifyMessageRead(ids, userId, userType);
// 断言
assertEquals(1, updateCount);
NotifyMessageDO notifyMessage = notifyMessageMapper.selectById(dbNotifyMessage.getId());
assertTrue(notifyMessage.getReadStatus());
assertNotNull(notifyMessage.getReadTime());
}
@Test
public void testUpdateAllNotifyMessageRead() {
// mock 数据
NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到
o.setUserId(1L);
o.setUserType(UserTypeEnum.ADMIN.getValue());
o.setReadStatus(false);
o.setReadTime(null);
o.setTemplateParams(randomTemplateParams());
});
notifyMessageMapper.insert(dbNotifyMessage);
// 测试 userId 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L)));
// 测试 userType 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
// 测试 readStatus 不匹配
notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true)));
// 准备参数
Long userId = 1L;
Integer userType = UserTypeEnum.ADMIN.getValue();
// 调用
int updateCount = notifyMessageService.updateAllNotifyMessageRead(userId, userType);
// 断言
assertEquals(1, updateCount);
NotifyMessageDO notifyMessage = notifyMessageMapper.selectById(dbNotifyMessage.getId());
assertTrue(notifyMessage.getReadStatus());
assertNotNull(notifyMessage.getReadTime());
}
private static Map<String, Object> randomTemplateParams() {
return MapUtil.<String, Object>builder().put(randomString(), randomString())
.put(randomString(), randomString()).build();
}
}

@ -0,0 +1,121 @@
package cn.iocoder.yudao.module.system.service.notify;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.util.HashMap;
import java.util.Map;
import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
class NotifySendServiceImplTest extends BaseMockitoUnitTest {
@InjectMocks
private NotifySendServiceImpl notifySendService;
@Mock
private NotifyTemplateService notifyTemplateService;
@Mock
private NotifyMessageService notifyMessageService;
/**
*
*/
@Test
public void testSendSingleNotify_successWhenMailTemplateEnable() {
// 准备参数
Long userId = randomLongId();
Integer userType = randomEle(UserTypeEnum.values()).getValue();
String templateCode = randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build();
// mock NotifyTemplateService 的方法
NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class, o -> {
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setContent("验证码为{code}, 操作为{op}");
o.setParams(Lists.newArrayList("code", "op"));
});
when(notifyTemplateService.getNotifyTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
String content = randomString();
when(notifyTemplateService.formatNotifyTemplateContent(eq(template.getContent()), eq(templateParams)))
.thenReturn(content);
// mock NotifyMessageService 的方法
Long messageId = randomLongId();
when(notifyMessageService.createNotifyMessage(eq(userId), eq(userType),
eq(template), eq(content), eq(templateParams))).thenReturn(messageId);
// 调用
Long resultMessageId = notifySendService.sendSingleNotify(userId, userType, templateCode, templateParams);
// 断言
assertEquals(messageId, resultMessageId);
}
/**
*
*/
@Test
public void testSendSingleMail_successWhenSmsTemplateDisable() {
// 准备参数
Long userId = randomLongId();
Integer userType = randomEle(UserTypeEnum.values()).getValue();
String templateCode = randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build();
// mock NotifyTemplateService 的方法
NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class, o -> {
o.setStatus(CommonStatusEnum.DISABLE.getStatus());
o.setContent("验证码为{code}, 操作为{op}");
o.setParams(Lists.newArrayList("code", "op"));
});
when(notifyTemplateService.getNotifyTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
// 调用
Long resultMessageId = notifySendService.sendSingleNotify(userId, userType, templateCode, templateParams);
// 断言
assertNull(resultMessageId);
verify(notifyTemplateService, never()).formatNotifyTemplateContent(anyString(), anyMap());
verify(notifyMessageService, never()).createNotifyMessage(anyLong(), anyInt(), any(), anyString(), anyMap());
}
@Test
public void testCheckMailTemplateValid_notExists() {
// 准备参数
String templateCode = randomString();
// mock 方法
// 调用,并断言异常
assertServiceException(() -> notifySendService.checkNotifyTemplateValid(templateCode),
NOTICE_NOT_FOUND);
}
@Test
public void testCheckTemplateParams_paramMiss() {
// 准备参数
NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class,
o -> o.setParams(Lists.newArrayList("code")));
Map<String, Object> templateParams = new HashMap<>();
// mock 方法
// 调用,并断言异常
assertServiceException(() -> notifySendService.checkTemplateParams(template, templateParams),
NOTIFY_SEND_TEMPLATE_PARAM_MISS, "code");
}
}

@ -0,0 +1,146 @@
package cn.iocoder.yudao.module.system.service.notify;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyTemplateMapper;
import cn.iocoder.yudao.module.system.mq.producer.notify.NotifyProducer;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.verify;
/**
* {@link NotifyTemplateServiceImpl}
*
* @author
*/
@Import(NotifyTemplateServiceImpl.class)
public class NotifyTemplateServiceImplTest extends BaseDbUnitTest {
@Resource
private NotifyTemplateServiceImpl notifyTemplateService;
@Resource
private NotifyTemplateMapper notifyTemplateMapper;
@MockBean
private NotifyProducer notifyProducer;
@Test
public void testCreateNotifyTemplate_success() {
// 准备参数
NotifyTemplateCreateReqVO reqVO = randomPojo(NotifyTemplateCreateReqVO.class,
o -> o.setStatus(randomCommonStatus()));
// 调用
Long notifyTemplateId = notifyTemplateService.createNotifyTemplate(reqVO);
// 断言
assertNotNull(notifyTemplateId);
// 校验记录的属性是否正确
NotifyTemplateDO notifyTemplate = notifyTemplateMapper.selectById(notifyTemplateId);
assertPojoEquals(reqVO, notifyTemplate);
verify(notifyProducer).sendNotifyTemplateRefreshMessage();
}
@Test
public void testUpdateNotifyTemplate_success() {
// mock 数据
NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class);
notifyTemplateMapper.insert(dbNotifyTemplate);// @Sql: 先插入出一条存在的数据
// 准备参数
NotifyTemplateUpdateReqVO reqVO = randomPojo(NotifyTemplateUpdateReqVO.class, o -> {
o.setId(dbNotifyTemplate.getId()); // 设置更新的 ID
o.setStatus(randomCommonStatus());
});
// 调用
notifyTemplateService.updateNotifyTemplate(reqVO);
// 校验是否更新正确
NotifyTemplateDO notifyTemplate = notifyTemplateMapper.selectById(reqVO.getId()); // 获取最新的
assertPojoEquals(reqVO, notifyTemplate);
verify(notifyProducer).sendNotifyTemplateRefreshMessage();
}
@Test
public void testUpdateNotifyTemplate_notExists() {
// 准备参数
NotifyTemplateUpdateReqVO reqVO = randomPojo(NotifyTemplateUpdateReqVO.class);
// 调用, 并断言异常
assertServiceException(() -> notifyTemplateService.updateNotifyTemplate(reqVO), NOTIFY_TEMPLATE_NOT_EXISTS);
}
@Test
public void testDeleteNotifyTemplate_success() {
// mock 数据
NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class);
notifyTemplateMapper.insert(dbNotifyTemplate);// @Sql: 先插入出一条存在的数据
// 准备参数
Long id = dbNotifyTemplate.getId();
// 调用
notifyTemplateService.deleteNotifyTemplate(id);
// 校验数据不存在了
assertNull(notifyTemplateMapper.selectById(id));
verify(notifyProducer).sendNotifyTemplateRefreshMessage();
}
@Test
public void testDeleteNotifyTemplate_notExists() {
// 准备参数
Long id = randomLongId();
// 调用, 并断言异常
assertServiceException(() -> notifyTemplateService.deleteNotifyTemplate(id), NOTIFY_TEMPLATE_NOT_EXISTS);
}
@Test
public void testGetNotifyTemplatePage() {
// mock 数据
NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class, o -> { // 等会查询到
o.setName("芋头");
o.setCode("test_01");
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setCreateTime(buildTime(2022, 2, 3));
});
notifyTemplateMapper.insert(dbNotifyTemplate);
// 测试 name 不匹配
notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setName("投")));
// 测试 code 不匹配
notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setCode("test_02")));
// 测试 status 不匹配
notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 createTime 不匹配
notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setCreateTime(buildTime(2022, 1, 5))));
// 准备参数
NotifyTemplatePageReqVO reqVO = new NotifyTemplatePageReqVO();
reqVO.setName("芋");
reqVO.setCode("est_01");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setCreateTime(buildBetweenTime(2022, 2, 1, 2022, 2, 5));
// 调用
PageResult<NotifyTemplateDO> pageResult = notifyTemplateService.getNotifyTemplatePage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbNotifyTemplate, pageResult.getList().get(0));
}
}

@ -28,3 +28,5 @@ DELETE FROM "system_oauth2_code";
DELETE FROM "system_mail_account"; DELETE FROM "system_mail_account";
DELETE FROM "system_mail_template"; DELETE FROM "system_mail_template";
DELETE FROM "system_mail_log"; DELETE FROM "system_mail_log";
DELETE FROM "system_notify_template";
DELETE FROM "system_notify_message";

@ -626,3 +626,43 @@ CREATE TABLE IF NOT EXISTS "system_mail_log" (
"deleted" bit NOT NULL DEFAULT FALSE, "deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id") PRIMARY KEY ("id")
) COMMENT '邮件日志表'; ) COMMENT '邮件日志表';
-- 将该建表 SQL 语句,添加到 yudao-module-system-biz 模块的 test/resources/sql/create_tables.sql 文件里
CREATE TABLE IF NOT EXISTS "system_notify_template" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar NOT NULL,
"code" varchar NOT NULL,
"nickname" varchar NOT NULL,
"content" varchar NOT NULL,
"type" varchar NOT NULL,
"params" varchar,
"status" varchar NOT NULL,
"remark" varchar,
"creator" varchar DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT '站内信模板表';
CREATE TABLE IF NOT EXISTS "system_notify_message" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"user_id" bigint NOT NULL,
"user_type" varchar NOT NULL,
"template_id" bigint NOT NULL,
"template_code" varchar NOT NULL,
"template_nickname" varchar NOT NULL,
"template_content" varchar NOT NULL,
"template_type" int NOT NULL,
"template_params" varchar NOT NULL,
"read_status" bit NOT NULL,
"read_time" varchar,
"creator" varchar DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
PRIMARY KEY ("id")
) COMMENT '站内信消息表';

@ -115,6 +115,7 @@ yudao:
- cn.iocoder.yudao.module.member.enums.ErrorCodeConstants - cn.iocoder.yudao.module.member.enums.ErrorCodeConstants
- cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants - cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants
- cn.iocoder.yudao.module.system.enums.ErrorCodeConstants - cn.iocoder.yudao.module.system.enums.ErrorCodeConstants
- cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants
tenant: # 多租户相关配置项 tenant: # 多租户相关配置项
enable: true enable: true
ignore-urls: ignore-urls:
@ -141,6 +142,7 @@ yudao:
- system_mail_account - system_mail_account
- system_mail_template - system_mail_template
- system_mail_log - system_mail_log
- system_notify_template
- infra_codegen_column - infra_codegen_column
- infra_codegen_table - infra_codegen_table
- infra_test_demo - infra_test_demo

@ -0,0 +1,51 @@
import request from '@/utils/request'
import qs from 'qs'
// 获得我的站内信分页
export function getNotifyMessagePage(query) {
return request({
url: '/system/notify-message/page',
method: 'get',
params: query
})
}
// 获得我的站内信分页
export function getMyNotifyMessagePage(query) {
return request({
url: '/system/notify-message/my-page',
method: 'get',
params: query
})
}
// 批量标记已读
export function updateNotifyMessageRead(ids) {
return request({
url: '/system/notify-message/update-read?' + qs.stringify({ids: ids}, { indices: false }),
method: 'put'
})
}
// 标记所有站内信为已读
export function updateAllNotifyMessageRead() {
return request({
url: '/system/notify-message/update-all-read',
method: 'put'
})
}
// 获取当前用户的最新站内信列表
export function getUnreadNotifyMessageList() {
return request({
url: '/system/notify-message/get-unread-list',
method: 'get'
})
}
export function getUnreadNotifyMessageCount() {
return request({
url: '/system/notify-message/get-unread-count',
method: 'get'
})
}

@ -1,38 +0,0 @@
import request from '@/utils/request'
// 获得我的站内信分页
export function getNotifyMessagePage(query) {
return request({
url: '/system/notify-message/page',
method: 'get',
params: query
})
}
// 获得单条我的站内信
export function getNotifyMessage(query) {
return request({
url: '/system/notify-message/get',
method: 'get',
params: query
})
}
// 批量标记已读
export function updateNotifyMessageListRead(data) {
return request({
url: '/system/notify-message/update-list-read',
method: 'put',
data: data
})
}
// 所有未读消息标记已读
export function updateNotifyMessageAllRead(data) {
return request({
url: '/system/notify-message/update-all-read',
method: 'put',
data: data
})
}

@ -1,11 +0,0 @@
import request from '@/utils/request'
// 获得我的站内信分页
export function getNotifyLogPage(query) {
return request({
url: '/system/notify-log/page',
method: 'get',
params: query
})
}

@ -9,7 +9,7 @@ export default {
name: 'YudaoDoc', name: 'YudaoDoc',
data() { data() {
return { return {
url: 'http://www.iocoder.cn/Yudao/build-debugger-environment/?yudao' url: 'https://doc.iocoder.cn/'
} }
}, },
methods: { methods: {

@ -0,0 +1,83 @@
<template>
<div>
<el-popover placement="bottom" width="600" trigger="click">
<!-- icon 展示 -->
<el-badge slot="reference" :is-dot="unreadCount > 0" type="danger">
<svg-icon icon-class="message" @click="getList"/>
</el-badge>
<!-- 弹出列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column width="120" property="templateNickname" label="日期" />
<el-table-column width="180" property="title" label="发送时间">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="类型" align="center" prop="templateType" width="100">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE" :value="scope.row.templateType" />
</template>
</el-table-column>
<el-table-column property="templateContent" label="内容" />
</el-table>
<!-- 更多 -->
<div style="text-align: right; margin-top: 10px">
<el-button type="primary" size="mini" @click="goMyList"></el-button>
</div>
</el-popover>
</div>
</template>
<script>
import {getUnreadNotifyMessageCount, getUnreadNotifyMessageList} from "@/api/system/notify/message";
export default {
name: 'NotifyMessage',
data() {
return {
//
loading: false,
//
list: [],
// ,
unreadCount: 0,
}
},
created() {
//
this.getUnreadCount()
//
window.timer = setInterval(()=>{
this.getUnreadCount()
},1000 * 60 * 2)
},
methods: {
getList: function() {
this.loading = true;
getUnreadNotifyMessageList().then(response => {
this.list = response.data;
this.loading = false;
// unreadCount 0
this.unreadCount = 0
});
},
getUnreadCount: function() {
getUnreadNotifyMessageCount().then(response => {
this.unreadCount = response.data;
})
},
goMyList: function() {
this.$router.push({
name: 'MyNotifyMessage'
});
}
}
}
</script>
<style>
.el-badge__content.is-fixed {
top: 10px; /* 保证徽章的位置 */
}
</style>

@ -9,6 +9,9 @@
<template v-if="device!=='mobile'"> <template v-if="device!=='mobile'">
<search id="header-search" class="right-menu-item" /> <search id="header-search" class="right-menu-item" />
<!-- 站内信 -->
<notify-message class="right-menu-item hover-effect" />
<el-tooltip content="源码地址" effect="dark" placement="bottom"> <el-tooltip content="源码地址" effect="dark" placement="bottom">
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" /> <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
</el-tooltip> </el-tooltip>
@ -57,6 +60,7 @@ import SizeSelect from '@/components/SizeSelect'
import Search from '@/components/HeaderSearch' import Search from '@/components/HeaderSearch'
import RuoYiGit from '@/components/RuoYi/Git' import RuoYiGit from '@/components/RuoYi/Git'
import RuoYiDoc from '@/components/RuoYi/Doc' import RuoYiDoc from '@/components/RuoYi/Doc'
import NotifyMessage from '@/layout/components/Message'
import {getPath} from "@/utils/ruoyi"; import {getPath} from "@/utils/ruoyi";
export default { export default {
@ -68,7 +72,8 @@ export default {
SizeSelect, SizeSelect,
Search, Search,
RuoYiGit, RuoYiGit,
RuoYiDoc RuoYiDoc,
NotifyMessage
}, },
computed: { computed: {
...mapGetters([ ...mapGetters([

@ -75,7 +75,8 @@ export const constantRoutes = [
meta: {title: '首页', icon: 'dashboard', affix: true} meta: {title: '首页', icon: 'dashboard', affix: true}
} }
] ]
}, { },
{
path: '/user', path: '/user',
component: Layout, component: Layout,
hidden: true, hidden: true,
@ -85,9 +86,14 @@ export const constantRoutes = [
component: (resolve) => require(['@/views/system/user/profile/index'], resolve), component: (resolve) => require(['@/views/system/user/profile/index'], resolve),
name: 'Profile', name: 'Profile',
meta: {title: '个人中心', icon: 'user'} meta: {title: '个人中心', icon: 'user'}
} }, {
] path: 'notify-message',
}, { component: (resolve) => require(['@/views/system/notify/my/index'], resolve),
name: 'MyNotifyMessage',
meta: { title: '我的站内信', icon: 'message' },
}]
},
{
path: '/dict', path: '/dict',
component: Layout, component: Layout,
hidden: true, hidden: true,
@ -98,18 +104,8 @@ export const constantRoutes = [
meta: {title: '字典数据', icon: '', activeMenu: '/system/dict'} meta: {title: '字典数据', icon: '', activeMenu: '/system/dict'}
} }
] ]
}, { },
path: '/property', {
component: Layout,
hidden: true,
children: [{
path: 'value/:propertyId(\\d+)',
component: (resolve) => require(['@/views/mall/product/property/value'], resolve),
name: 'PropertyValue',
meta: {title: '商品属性值', icon: '', activeMenu: '/product/property'}
}
]
}, {
path: '/job', path: '/job',
component: Layout, component: Layout,
hidden: true, hidden: true,
@ -131,24 +127,8 @@ export const constantRoutes = [
meta: {title: '修改生成配置', activeMenu: '/infra/codegen'} meta: {title: '修改生成配置', activeMenu: '/infra/codegen'}
} }
] ]
}, { },
path: '/spu', {
component: Layout,
hidden: true,
children: [{
path: 'edit/:spuId(\\d+)',
component: (resolve) => require(['@/views/mall/product/spu/save'], resolve),
name: 'SpuEdit',
meta: {title: '修改商品', activeMenu: '/product/spu'}
},
{
path: 'add',
component: (resolve) => require(['@/views/mall/product/spu/save'], resolve),
name: 'SpuAdd',
meta: {title: '添加商品', activeMenu: '/product/spu'}
}
]
}, {
path: '/bpm', path: '/bpm',
component: Layout, component: Layout,
hidden: true, hidden: true,
@ -165,7 +145,8 @@ export const constantRoutes = [
meta: {title: '查看 OA 请假', icon: 'view', activeMenu: '/bpm/oa/leave'} meta: {title: '查看 OA 请假', icon: 'view', activeMenu: '/bpm/oa/leave'}
} }
] ]
}, { },
{
path: '/bpm', path: '/bpm',
component: Layout, component: Layout,
hidden: true, hidden: true,
@ -197,6 +178,36 @@ export const constantRoutes = [
} }
] ]
}, },
{
path: '/property',
component: Layout,
hidden: true,
children: [{
path: 'value/:propertyId(\\d+)',
component: (resolve) => require(['@/views/mall/product/property/value'], resolve),
name: 'PropertyValue',
meta: {title: '商品属性值', icon: '', activeMenu: '/product/property'}
}
]
},
{
path: '/spu',
component: Layout,
hidden: true,
children: [{
path: 'edit/:spuId(\\d+)',
component: (resolve) => require(['@/views/mall/product/spu/save'], resolve),
name: 'SpuEdit',
meta: {title: '修改商品', activeMenu: '/product/spu'}
},
{
path: 'add',
component: (resolve) => require(['@/views/mall/product/spu/save'], resolve),
name: 'SpuAdd',
meta: {title: '添加商品', activeMenu: '/product/spu'}
}
]
},
{ {
path: '/trade/order', path: '/trade/order',
component: Layout, component: Layout,

@ -25,8 +25,8 @@ export const DICT_TYPE = {
SYSTEM_SMS_RECEIVE_STATUS: 'system_sms_receive_status', SYSTEM_SMS_RECEIVE_STATUS: 'system_sms_receive_status',
SYSTEM_ERROR_CODE_TYPE: 'system_error_code_type', SYSTEM_ERROR_CODE_TYPE: 'system_error_code_type',
SYSTEM_OAUTH2_GRANT_TYPE: 'system_oauth2_grant_type', SYSTEM_OAUTH2_GRANT_TYPE: 'system_oauth2_grant_type',
SYSTEM_NOTIFY_READ_STATUS: "system_notify_read_status",
SYSTEM_MAIL_SEND_STATUS: 'system_mail_send_status', SYSTEM_MAIL_SEND_STATUS: 'system_mail_send_status',
SYSTEM_NOTIFY_TEMPLATE_TYPE: 'system_notify_template_type',
// ========== INFRA 模块 ========== // ========== INFRA 模块 ==========
INFRA_BOOLEAN_STRING: 'infra_boolean_string', INFRA_BOOLEAN_STRING: 'infra_boolean_string',

@ -140,7 +140,7 @@ export default {
// //
list: [], list: [],
// //
title: "", title: "邮件发送日志详细",
// //
open: false, open: false,
// //

@ -0,0 +1,179 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="用户编号" prop="userId">
<el-input v-model="queryParams.userId" placeholder="请输入用户编号" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="用户类型" prop="userType">
<el-select v-model="queryParams.userType" placeholder="请选择用户类型" clearable size="small">
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.USER_TYPE)"
:key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
<el-form-item label="模板编码" prop="templateCode">
<el-input v-model="queryParams.templateCode" placeholder="请输入模板编码" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="模版类型" prop="templateType">
<el-select v-model="queryParams.templateType" placeholder="请选择模版类型" clearable size="small">
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE)"
:key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<!-- 操作工具栏 -->
<el-row :gutter="10" class="mb8">
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="编号" align="center" prop="id" />
<el-table-column label="用户编号" align="center" prop="userId" />
<el-table-column label="用户类型" align="center" prop="userType">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.USER_TYPE" :value="scope.row.userType" />
</template>
</el-table-column>
<el-table-column label="模板编码" align="center" prop="templateCode" />
<el-table-column label="发送人名称" align="center" prop="templateNickname" />
<el-table-column label="模版内容" align="center" prop="templateContent" />
<el-table-column label="模版类型" align="center" prop="templateType">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE" :value="scope.row.templateType" />
</template>
</el-table-column>
<el-table-column label="是否已读" align="center" prop="readStatus">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.readStatus" />
</template>
</el-table-column>
<el-table-column label="阅读时间" align="center" prop="readTime" width="180">
<template v-slot="scope">
<span>{{ parseTime(scope.row.readTime) }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template v-slot="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template v-slot="scope">
<el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row)"
v-hasPermi="['system:notify-message:query']">详细</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
<!-- 站内信详细-->
<el-dialog :title="title" :visible.sync="open" width="700px" v-dialogDrag append-to-body>
<el-form ref="form" :model="form" label-width="160px">
<el-row>
<el-col :span="24">
<el-form-item label="日志主键:">{{ form.id }}</el-form-item>
<el-form-item label="发送时间:">{{ parseTime(form.createTime) }}</el-form-item>
<el-form-item label="用户编号:">{{ form.userId }}</el-form-item>
<el-form-item label="用户类型:">
<dict-tag :type="DICT_TYPE.USER_TYPE" :value="form.userType"/>
</el-form-item>
<el-form-item label="模板编号:">{{ form.templateId }}</el-form-item>
<el-form-item label="模板编码:">{{ form.templateCode }}</el-form-item>
<el-form-item label="模板类型:">
<dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE" :value="form.templateType" />
</el-form-item>
<el-form-item label="模版发送人名称:">{{ form.templateNickname }}</el-form-item>
<el-form-item label="邮件内容:">{{ form.templateContent }}</el-form-item>
<el-form-item label="模版参数:">{{ form.templateParams }}</el-form-item>
<el-form-item label="是否已读:">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="form.readStatus" />
</el-form-item>
<el-form-item label="阅读时间:">{{ parseTime(form.readTime) }}</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="open = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getNotifyMessagePage } from "@/api/system/notify/message";
export default {
name: "NotifyMessage",
data() {
return {
//
loading: true,
//
showSearch: true,
//
total: 0,
//
list: [],
//
title: "站内信详细",
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
userId: null,
userType: null,
templateCode: null,
templateType: null,
createTime: [],
},
//
form: {},
};
},
created() {
this.getList();
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
//
getNotifyMessagePage(this.queryParams).then(response => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 详细按钮操作 */
handleView(row) {
this.open = true;
this.form = row;
}
}
};
</script>

@ -1,17 +1,14 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<!-- 搜索工作栏 --> <!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="150px"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="模板标题" prop="title"> <el-form-item label="是否已读" prop="readStatus">
<el-input v-model="queryParams.title" placeholder="请输入模板标题" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="读取状态" prop="readStatus">
<el-select v-model="queryParams.readStatus" placeholder="请选择状态" clearable> <el-select v-model="queryParams.readStatus" placeholder="请选择状态" clearable>
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYSTEM_NOTIFY_READ_STATUS)" <el-option v-for="dict in this.getDictDatas(DICT_TYPE.INFRA_BOOLEAN_STRING)"
:key="dict.value" :label="dict.label" :value="dict.value"/> :key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="创建时间" prop="createTime"> <el-form-item label="发送时间" prop="createTime">
<el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange" <el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" /> range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
</el-form-item> </el-form-item>
@ -35,17 +32,21 @@
<!-- 列表 --> <!-- 列表 -->
<el-table v-loading="loading" ref="tables" :data="list"> <el-table v-loading="loading" ref="tables" :data="list">
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55" />
<el-table-column label="模板标题" align="center" prop="title" /> <el-table-column label="发送人" align="center" prop="templateNickname" width="120" />
<el-table-column label="模板内容" align="center" prop="content" width="300" /> <el-table-column label="发送时间" align="center" prop="createTime" width="180">
<el-table-column label="发送人" align="center" prop="sendUserName" />
<el-table-column label="发送时间" align="center" prop="sendTime" width="180">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ parseTime(scope.row.sendTime) }}</span> <span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="类型" align="center" prop="templateType" width="80">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE" :value="scope.row.templateType" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="读取状态" align="center" prop="readStatus"> <el-table-column label="内容" align="center" prop="templateContent" />
<el-table-column label="是否已读" align="center" prop="readStatus" width="80">
<template slot-scope="scope"> <template slot-scope="scope">
<dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_READ_STATUS" :value="scope.row.readStatus"/> <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.readStatus"/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="150"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="150">
@ -62,7 +63,7 @@
</template> </template>
<script> <script>
import { getNotifyMessagePage, updateNotifyMessageListRead, updateNotifyMessageAllRead} from "@/api/system/notify/myNotify"; import {getMyNotifyMessagePage, updateAllNotifyMessageRead, updateNotifyMessageRead} from "@/api/system/notify/message";
export default { export default {
name: "myNotify", name: "myNotify",
@ -70,25 +71,17 @@ export default {
return { return {
// //
loading: true, loading: true,
//
exportLoading: false,
// //
showSearch: true, showSearch: true,
// //
total: 0, total: 0,
// //
list: [], list: [],
//
title: "",
//
open: false,
// //
queryParams: { queryParams: {
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
readStatus: null, readStatus: null,
code: null,
title: null,
createTime: [] createTime: []
}, },
}; };
@ -101,7 +94,7 @@ export default {
getList() { getList() {
this.loading = true; this.loading = true;
// //
getNotifyMessagePage(this.queryParams).then(response => { getMyNotifyMessagePage(this.queryParams).then(response => {
this.list = response.data.list; this.list = response.data.list;
this.total = response.data.total; this.total = response.data.total;
this.loading = false; this.loading = false;
@ -117,25 +110,26 @@ export default {
this.resetForm("queryForm"); this.resetForm("queryForm");
this.handleQuery(); this.handleQuery();
}, },
handleUpdateList(){ handleUpdateList() {
let list = this.$refs["tables"].selection; let list = this.$refs["tables"].selection;
if(list.length != 0){ if (list.length === 0) {
this.handleUpdate(list.map(v=>v.id)) return;
} }
this.handleUpdate(list.map(v => v.id))
}, },
handleUpdateSingle(row){ handleUpdateSingle(row) {
this.handleUpdate([row.id]) this.handleUpdate([row.id])
}, },
handleUpdate(ids){ handleUpdate(ids) {
updateNotifyMessageListRead(ids).then(response => { updateNotifyMessageRead(ids).then(response => {
this.$modal.msgSuccess("修改成功"); this.$modal.msgSuccess("标记已读成功!");
this.getList(); this.getList();
}); });
}, },
handleUpdateAll(){ handleUpdateAll(){
updateNotifyMessageAllRead().then(response => { updateAllNotifyMessageRead().then(response => {
this.$modal.msgSuccess("修改成功"); this.$modal.msgSuccess("全部已读成功!");
this.getList(); this.getList();
}); });
} }
} }

@ -1,120 +0,0 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="150px">
<el-form-item label="模板编码" prop="templateCode">
<el-input v-model="queryParams.templateCode" placeholder="请输入模板编码" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="模板标题" prop="title">
<el-input v-model="queryParams.title" placeholder="请输入模板标题" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="发送时间" prop="sendTime">
<el-date-picker v-model="queryParams.sendTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<!-- 操作工具栏 -->
<!-- <el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading"
v-hasPermi="['system:notify-log:export']">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row> -->
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="模板编码" align="center" prop="templateCode" />
<el-table-column label="模板标题" align="center" prop="title" />
<el-table-column label="模板内容" align="center" prop="content" width="300" />
<el-table-column label="阅读状态" align="center" prop="readStatus">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_READ_STATUS" :value="scope.row.readStatus"/>
</template>
</el-table-column>
<el-table-column label="接收人" align="center" prop="receiveUserName" />
<el-table-column label="发送时间" align="center" prop="sendTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.sendTime) }}</span>
</template>
</el-table-column>
<el-table-column label="阅读时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.readTime) }}</span>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
</div>
</template>
<script>
import { getNotifyLogPage} from "@/api/system/notify/notifyLog";
export default {
name: "notifyLog",
data() {
return {
//
loading: true,
//
exportLoading: false,
//
showSearch: true,
//
total: 0,
//
list: [],
//
title: "",
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
templateCode: null,
title: null,
sendTime: []
},
};
},
created() {
this.getList();
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
//
getNotifyLogPage(this.queryParams).then(response => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
}
}
</script>
<style>
</style>

@ -1,15 +1,15 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<!-- 搜索工作栏 --> <!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="150px"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="模板编码" prop="code"> <el-form-item label="模板名称" prop="name">
<el-input v-model="queryParams.code" placeholder="请输入模板编码" clearable @keyup.enter.native="handleQuery"/> <el-input v-model="queryParams.name" placeholder="请输入模板名称" clearable @keyup.enter.native="handleQuery"/>
</el-form-item> </el-form-item>
<el-form-item label="模板标题" prop="title"> <el-form-item label="模版编码" prop="code">
<el-input v-model="queryParams.title" placeholder="请输入模板标题" clearable @keyup.enter.native="handleQuery"/> <el-input v-model="queryParams.code" placeholder="请输入模版编码" clearable @keyup.enter.native="handleQuery"/>
</el-form-item> </el-form-item>
<el-form-item label="开启状态" prop="status"> <el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择开启状态" clearable> <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)" <el-option v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
:key="dict.value" :label="dict.label" :value="dict.value"/> :key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select> </el-select>
@ -30,17 +30,19 @@
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['system:notify-template:create']">新增</el-button> v-hasPermi="['system:notify-template:create']">新增</el-button>
</el-col> </el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading"
v-hasPermi="['system:notify-template:export']">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
<!-- 列表 --> <!-- 列表 -->
<el-table v-loading="loading" :data="list"> <el-table v-loading="loading" :data="list">
<el-table-column label="模板编码" align="center" prop="code" /> <el-table-column label="模板编码" align="center" prop="code" />
<el-table-column label="模板标题" align="center" prop="title" /> <el-table-column label="模板名称" align="center" prop="name" />
<el-table-column label="类型" align="center" prop="type">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column label="发送人名称" align="center" prop="nickname" />
<el-table-column label="模板内容" align="center" prop="content" width="300" /> <el-table-column label="模板内容" align="center" prop="content" width="300" />
<el-table-column label="开启状态" align="center" prop="status"> <el-table-column label="开启状态" align="center" prop="status">
<template slot-scope="scope"> <template slot-scope="scope">
@ -74,12 +76,21 @@
<el-form-item label="模板编号" prop="code"> <el-form-item label="模板编号" prop="code">
<el-input v-model="form.code" placeholder="请输入模板编号" /> <el-input v-model="form.code" placeholder="请输入模板编号" />
</el-form-item> </el-form-item>
<el-form-item label="模板标题" prop="title"> <el-form-item label="模板名称" prop="name">
<el-input v-model="form.title" placeholder="请输入标题名称" /> <el-input v-model="form.name" placeholder="请输入模版名称" />
</el-form-item>
<el-form-item label="发件人名称" prop="nickname">
<el-input v-model="form.nickname" placeholder="请输入发件人名称" />
</el-form-item> </el-form-item>
<el-form-item label="模板内容" prop="content"> <el-form-item label="模板内容" prop="content">
<el-input type="textarea" v-model="form.content" placeholder="请输入模板内容" /> <el-input type="textarea" v-model="form.content" placeholder="请输入模板内容" />
</el-form-item> </el-form-item>
<el-form-item label="类型" prop="type">
<el-select v-model="form.type" placeholder="请选择类型">
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE)"
:key="dict.value" :label="dict.label" :value="parseInt(dict.value)" />
</el-select>
</el-form-item>
<el-form-item label="开启状态" prop="status"> <el-form-item label="开启状态" prop="status">
<el-radio-group v-model="form.status"> <el-radio-group v-model="form.status">
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)" <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
@ -122,8 +133,9 @@
<script> <script>
import { createNotifyTemplate, updateNotifyTemplate, deleteNotifyTemplate, getNotifyTemplate, getNotifyTemplatePage, import { createNotifyTemplate, updateNotifyTemplate, deleteNotifyTemplate, getNotifyTemplate, getNotifyTemplatePage,
exportNotifyTemplateExcel, sendNotify } from "@/api/system/notify/notifyTemplate"; sendNotify } from "@/api/system/notify/template";
import {listSimpleUsers} from "@/api/system/user"; import {listSimpleUsers} from "@/api/system/user";
import {CommonStatusEnum} from "@/utils/constants";
export default { export default {
name: "NotifyTemplate", name: "NotifyTemplate",
@ -131,8 +143,6 @@ export default {
return { return {
// //
loading: true, loading: true,
//
exportLoading: false,
// //
showSearch: true, showSearch: true,
// //
@ -156,11 +166,12 @@ export default {
form: {}, form: {},
// //
rules: { rules: {
status: [{ required: true, message: "开启状态不能为空", trigger: "blur" }], name: [{ required: true, message: "模板名称不能为空", trigger: "blur" }],
code: [{ required: true, message: "模板编码不能为空", trigger: "blur" }], code: [{ required: true, message: "模版编码不能为空", trigger: "blur" }],
title: [{ required: true, message: "模板标题不能为空", trigger: "blur" }], nickname: [{ required: true, message: "发件人名称不能为空", trigger: "blur" }],
content: [{ required: true, message: "模板内容不能为空", trigger: "blur" }], content: [{ required: true, message: "模版内容不能为空", trigger: "blur" }],
userId: [{ required: true, message: "接收人不能为空", trigger: "blur" }] type: [{ required: true, message: "类型不能为空", trigger: "change" }],
status: [{ required: true, message: "状态不能为空", trigger: "blur" }],
}, },
// //
users: [], users: [],
@ -170,8 +181,8 @@ export default {
params: [], // params: [], //
}, },
sendNotifyRules: { sendNotifyRules: {
mobile: [{ required: true, message: "手机不能为空", trigger: "blur" }], userId: [{ required: true, message: "接收人不能为空", trigger: "blur" }],
templateCode: [{ required: true, message: "手机不能为空", trigger: "blur" }], templateCode: [{ required: true, message: "模版编号不能为空", trigger: "blur" }],
templateParams: { } templateParams: { }
} }
}; };
@ -203,10 +214,13 @@ export default {
reset() { reset() {
this.form = { this.form = {
id: undefined, id: undefined,
status: undefined, name: undefined,
code: undefined, code: undefined,
title: undefined, nickname: undefined,
content: undefined, content: undefined,
type: undefined,
params: undefined,
status: CommonStatusEnum.ENABLE,
remark: undefined, remark: undefined,
}; };
this.resetForm("form"); this.resetForm("form");
@ -270,21 +284,6 @@ export default {
this.$modal.msgSuccess("删除成功"); this.$modal.msgSuccess("删除成功");
}).catch(() => {}); }).catch(() => {});
}, },
/** 导出按钮操作 */
handleExport() {
//
let params = {...this.queryParams};
params.pageNo = undefined;
params.pageSize = undefined;
//
this.$modal.confirm('是否确认导出所有站内信模板数据项?', "警告").then(() => {
this.exportLoading = true;
return exportNotifyTemplateExcel(params);
}).then(response => {
this.$download.excel(response, '短信模板.xls');
this.exportLoading = false;
}).catch(() => {});
},
/** 发送站内信按钮 */ /** 发送站内信按钮 */
handleSendNotify(row) { handleSendNotify(row) {
this.resetSendNotify(row); this.resetSendNotify(row);
Loading…
Cancel
Save