Browse Source

初始化短信日志的 CRUD 代码

YunaiV 3 years ago
parent
commit
7760e163b3
19 changed files with 681 additions and 65 deletions
  1. 60 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SysSmsLogController.java
  2. 0 38
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsTemplateVO.java
  3. 96 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/log/SysSmsLogExcelVO.java
  4. 47 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/log/SysSmsLogExportReqVO.java
  5. 52 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/log/SysSmsLogPageReqVO.java
  6. 89 0
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/log/SysSmsLogRespVO.java
  7. 30 0
      src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsLogConvert.java
  8. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java
  9. 31 0
      src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsLogMapper.java
  10. 21 0
      src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java
  11. 28 0
      src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java
  12. 14 0
      src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java
  13. 21 22
      src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java
  14. 1 1
      src/main/resources/codegen/java/service/service.vm
  15. 2 0
      src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelServiceTest.java
  16. 151 0
      src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogServiceTest.java
  17. 3 3
      src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java
  18. 1 0
      src/test/resources/sql/clean.sql
  19. 33 0
      src/test/resources/sql/create_tables.sql

+ 60 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SysSmsLogController.java

@@ -0,0 +1,60 @@
+package cn.iocoder.dashboard.modules.system.controller.sms;
+
+import cn.iocoder.dashboard.common.pojo.CommonResult;
+import cn.iocoder.dashboard.common.pojo.PageResult;
+import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
+import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogExcelVO;
+import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogExportReqVO;
+import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogPageReqVO;
+import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogRespVO;
+import cn.iocoder.dashboard.modules.system.convert.sms.SysSmsLogConvert;
+import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO;
+import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+
+import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
+import static cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum.EXPORT;
+
+@Api(tags = "短信日志")
+@RestController
+@RequestMapping("/system/sms-log")
+@Validated
+public class SysSmsLogController {
+
+    @Resource
+    private SysSmsLogService smsLogService;
+
+    @GetMapping("/page")
+    @ApiOperation("获得短信日志分页")
+    @PreAuthorize("@ss.hasPermission('system:sms-log:query')")
+    public CommonResult<PageResult<SysSmsLogRespVO>> getSmsLogPage(@Valid SysSmsLogPageReqVO pageVO) {
+        PageResult<SysSmsLogDO> pageResult = smsLogService.getSmsLogPage(pageVO);
+        return success(SysSmsLogConvert.INSTANCE.convertPage(pageResult));
+    }
+
+    @GetMapping("/export-excel")
+    @ApiOperation("导出短信日志 Excel")
+    @PreAuthorize("@ss.hasPermission('system:sms-log:export')")
+    @OperateLog(type = EXPORT)
+    public void exportSmsLogExcel(@Valid SysSmsLogExportReqVO exportReqVO,
+                                  HttpServletResponse response) throws IOException {
+        List<SysSmsLogDO> list = smsLogService.getSmsLogList(exportReqVO);
+        // 导出 Excel
+        List<SysSmsLogExcelVO> datas = SysSmsLogConvert.INSTANCE.convertList02(list);
+        ExcelUtils.write(response, "短信日志.xls", "数据", SysSmsLogExcelVO.class, datas);
+    }
+
+}

+ 0 - 38
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsTemplateVO.java

@@ -1,38 +0,0 @@
-package cn.iocoder.dashboard.modules.system.controller.sms.vo;
-
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-/**
- * 渠道模板VO类
- *
- * @author zzf
- * @date 2021/1/25 17:03
- */
-@Data
-@EqualsAndHashCode
-public class SmsTemplateVO {
-
-    /**
-     * 业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板)
-     */
-    private String bizCode;
-
-    /**
-     * 编码
-     */
-    private String code;
-
-    /**
-     * 实际渠道模板唯一标识
-     */
-    private String apiTemplateId;
-
-    /**
-     * 内容
-     */
-    private String content;
-
-
-
-}

+ 96 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/log/SysSmsLogExcelVO.java

@@ -0,0 +1,96 @@
+package cn.iocoder.dashboard.modules.system.controller.sms.vo.log;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * 短信日志 Excel VO
+ *
+ * @author 芋道源码
+ */
+@Data
+public class SysSmsLogExcelVO {
+
+    @ExcelProperty("编号")
+    private Long id;
+
+    @ExcelProperty("短信渠道编号")
+    private Long channelId;
+
+    @ExcelProperty("短信渠道编码")
+    // TODO 导出枚举
+    private String channelCode;
+
+    @ExcelProperty("模板编号")
+    private Long templateId;
+
+    @ExcelProperty("模板编码")
+    private String templateCode;
+
+    @ExcelProperty("短信类型")
+    private Integer templateType;
+
+    @ExcelProperty("短信内容")
+    private String templateContent;
+
+    @ExcelProperty("短信参数")
+    private Map<String, Object> templateParams;
+
+    @ExcelProperty("短信 API 的模板编号")
+    private String apiTemplateId;
+
+    @ExcelProperty("手机号")
+    private String mobile;
+
+    @ExcelProperty("用户编号")
+    private Long userId;
+
+    @ExcelProperty("用户类型")
+    // TODO 导出枚举
+    private Integer userType;
+
+    @ExcelProperty("发送状态")
+    // TODO 导出枚举
+    private Integer sendStatus;
+
+    @ExcelProperty("发送时间")
+    private Date sendTime;
+
+    @ExcelProperty("发送结果的编码")
+    private Integer sendCode;
+
+    @ExcelProperty("发送结果的提示")
+    private String sendMsg;
+
+    @ExcelProperty("短信 API 发送结果的编码")
+    private String apiSendCode;
+
+    @ExcelProperty("短信 API 发送失败的提示")
+    private String apiSendMsg;
+
+    @ExcelProperty("短信 API 发送返回的唯一请求 ID")
+    private String apiRequestId;
+
+    @ExcelProperty("短信 API 发送返回的序号")
+    private String apiSerialNo;
+
+    @ExcelProperty("接收状态")
+    // TODO 导出枚举
+    private Integer receiveStatus;
+
+    @ExcelProperty("接收时间")
+    private Date receiveTime;
+
+    @ExcelProperty("API 接收结果的编码")
+    private String apiReceiveCode;
+
+    @ExcelProperty("API 接收结果的说明")
+    private String apiReceiveMsg;
+
+    @ExcelProperty("创建时间")
+    private Date createTime;
+
+}

+ 47 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/log/SysSmsLogExportReqVO.java

@@ -0,0 +1,47 @@
+package cn.iocoder.dashboard.modules.system.controller.sms.vo.log;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel(value = "短信日志 Excel 导出 Request VO", description = "参数和 SysSmsLogPageReqVO 是一致的")
+@Data
+public class SysSmsLogExportReqVO {
+
+    @ApiModelProperty(value = "短信渠道编号", example = "10")
+    private Long channelId;
+
+    @ApiModelProperty(value = "模板编号", example = "20")
+    private Long templateId;
+
+    @ApiModelProperty(value = "手机号", example = "15601691300")
+    private String mobile;
+
+    @ApiModelProperty(value = "发送状态", example = "1")
+    private Integer sendStatus;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "开始发送时间")
+    private Date beginSendTime;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "结束发送时间")
+    private Date endSendTime;
+
+    @ApiModelProperty(value = "接收状态", example = "0")
+    private Integer receiveStatus;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "开始接收时间")
+    private Date beginReceiveTime;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "结束接收时间")
+    private Date endReceiveTime;
+
+}

+ 52 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/log/SysSmsLogPageReqVO.java

@@ -0,0 +1,52 @@
+package cn.iocoder.dashboard.modules.system.controller.sms.vo.log;
+
+import cn.iocoder.dashboard.common.pojo.PageParam;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel("短信日志分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class SysSmsLogPageReqVO extends PageParam {
+
+    @ApiModelProperty(value = "短信渠道编号", example = "10")
+    private Long channelId;
+
+    @ApiModelProperty(value = "模板编号", example = "20")
+    private Long templateId;
+
+    @ApiModelProperty(value = "手机号", example = "15601691300")
+    private String mobile;
+
+    @ApiModelProperty(value = "发送状态", example = "1",  notes = "参见 SysSmsSendStatusEnum 枚举类")
+    private Integer sendStatus;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "开始发送时间")
+    private Date beginSendTime;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "结束发送时间")
+    private Date endSendTime;
+
+    @ApiModelProperty(value = "接收状态", example = "0", notes = "参见 SysSmsReceiveStatusEnum 枚举类")
+    private Integer receiveStatus;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "开始接收时间")
+    private Date beginReceiveTime;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "结束接收时间")
+    private Date endReceiveTime;
+
+}

+ 89 - 0
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/log/SysSmsLogRespVO.java

@@ -0,0 +1,89 @@
+package cn.iocoder.dashboard.modules.system.controller.sms.vo.log;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.Map;
+
+@ApiModel("短信日志 Response VO")
+@Data
+public class SysSmsLogRespVO {
+
+    @ApiModelProperty(value = "编号", required = true, example = "1024")
+    private Long id;
+
+    @ApiModelProperty(value = "短信渠道编号", required = true, example = "10")
+    private Long channelId;
+
+    @ApiModelProperty(value = "短信渠道编码", required = true, example = "ALIYUN")
+    private String channelCode;
+
+    @ApiModelProperty(value = "模板编号", required = true, example = "20")
+    private Long templateId;
+
+    @ApiModelProperty(value = "模板编码", required = true, example = "test-01")
+    private String templateCode;
+
+    @ApiModelProperty(value = "短信类型", required = true, example = "1")
+    private Integer templateType;
+
+    @ApiModelProperty(value = "短信内容", required = true, example = "你好,你的验证码是 1024")
+    private String templateContent;
+
+    @ApiModelProperty(value = "短信参数", required = true, example = "name,code")
+    private Map<String, Object> templateParams;
+
+    @ApiModelProperty(value = "短信 API 的模板编号", required = true, example = "SMS_207945135")
+    private String apiTemplateId;
+
+    @ApiModelProperty(value = "手机号", required = true, example = "15601691300")
+    private String mobile;
+
+    @ApiModelProperty(value = "用户编号", example = "10")
+    private Long userId;
+
+    @ApiModelProperty(value = "用户类型", example = "1")
+    private Integer userType;
+
+    @ApiModelProperty(value = "发送状态", required = true, example = "1")
+    private Integer sendStatus;
+
+    @ApiModelProperty(value = "发送时间")
+    private Date sendTime;
+
+    @ApiModelProperty(value = "发送结果的编码", example = "0")
+    private Integer sendCode;
+
+    @ApiModelProperty(value = "发送结果的提示", example = "成功")
+    private String sendMsg;
+
+    @ApiModelProperty(value = "短信 API 发送结果的编码", example = "SUCCESS")
+    private String apiSendCode;
+
+    @ApiModelProperty(value = "短信 API 发送失败的提示", example = "成功")
+    private String apiSendMsg;
+
+    @ApiModelProperty(value = "短信 API 发送返回的唯一请求 ID", example = "3837C6D3-B96F-428C-BBB2-86135D4B5B99")
+    private String apiRequestId;
+
+    @ApiModelProperty(value = "短信 API 发送返回的序号", example = "62923244790")
+    private String apiSerialNo;
+
+    @ApiModelProperty(value = "接收状态", required = true, example = "0")
+    private Integer receiveStatus;
+
+    @ApiModelProperty(value = "接收时间")
+    private Date receiveTime;
+
+    @ApiModelProperty(value = "API 接收结果的编码", example = "DELIVRD")
+    private String apiReceiveCode;
+
+    @ApiModelProperty(value = "API 接收结果的说明", example = "用户接收成功")
+    private String apiReceiveMsg;
+
+    @ApiModelProperty(value = "创建时间", required = true)
+    private Date createTime;
+
+}

+ 30 - 0
src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsLogConvert.java

@@ -0,0 +1,30 @@
+package cn.iocoder.dashboard.modules.system.convert.sms;
+
+import cn.iocoder.dashboard.common.pojo.PageResult;
+import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogExcelVO;
+import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogRespVO;
+import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+/**
+ * 短信日志 Convert
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface SysSmsLogConvert {
+
+    SysSmsLogConvert INSTANCE = Mappers.getMapper(SysSmsLogConvert.class);
+
+    SysSmsLogRespVO convert(SysSmsLogDO bean);
+
+    List<SysSmsLogRespVO> convertList(List<SysSmsLogDO> list);
+
+    PageResult<SysSmsLogRespVO> convertPage(PageResult<SysSmsLogDO> page);
+
+    List<SysSmsLogExcelVO> convertList02(List<SysSmsLogDO> list);
+
+}

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java

@@ -23,9 +23,9 @@ import java.util.Map;
 @Data
 @EqualsAndHashCode(callSuper = true)
 @ToString(callSuper = true)
+@Builder
 @AllArgsConstructor
 @NoArgsConstructor
-@Builder
 public class SysSmsLogDO extends BaseDO {
 
     /**

+ 31 - 0
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsLogMapper.java

@@ -1,9 +1,40 @@
 package cn.iocoder.dashboard.modules.system.dal.mysql.sms;
 
+import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX;
+import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogExportReqVO;
+import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogPageReqVO;
 import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 @Mapper
 public interface SysSmsLogMapper extends BaseMapperX<SysSmsLogDO> {
+
+    default PageResult<SysSmsLogDO> selectPage(SysSmsLogPageReqVO reqVO) {
+        return selectPage(reqVO, new QueryWrapperX<SysSmsLogDO>()
+                .eqIfPresent("channel_id", reqVO.getChannelId())
+                .eqIfPresent("template_id", reqVO.getTemplateId())
+                .likeIfPresent("mobile", reqVO.getMobile())
+                .eqIfPresent("send_status", reqVO.getSendStatus())
+                .betweenIfPresent("send_time", reqVO.getBeginSendTime(), reqVO.getEndSendTime())
+                .eqIfPresent("receive_status", reqVO.getReceiveStatus())
+                .betweenIfPresent("receive_time", reqVO.getBeginReceiveTime(), reqVO.getEndReceiveTime())
+                .orderByDesc("id"));
+    }
+
+    default List<SysSmsLogDO> selectList(SysSmsLogExportReqVO reqVO) {
+        return selectList(new QueryWrapperX<SysSmsLogDO>()
+                .eqIfPresent("channel_id", reqVO.getChannelId())
+                .eqIfPresent("template_id", reqVO.getTemplateId())
+                .likeIfPresent("mobile", reqVO.getMobile())
+                .eqIfPresent("send_status", reqVO.getSendStatus())
+                .betweenIfPresent("send_time", reqVO.getBeginSendTime(), reqVO.getEndSendTime())
+                .eqIfPresent("receive_status", reqVO.getReceiveStatus())
+                .betweenIfPresent("receive_time", reqVO.getBeginReceiveTime(), reqVO.getEndReceiveTime())
+                .orderByDesc("id"));
+    }
+
 }

+ 21 - 0
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java

@@ -1,8 +1,13 @@
 package cn.iocoder.dashboard.modules.system.service.sms;
 
+import cn.iocoder.dashboard.common.pojo.PageResult;
+import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogExportReqVO;
+import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogPageReqVO;
+import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO;
 import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
 
 import java.util.Date;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -53,4 +58,20 @@ public interface SysSmsLogService {
      */
     void updateSmsReceiveResult(Long id, Boolean success, Date receiveTime, String apiReceiveCode, String apiReceiveMsg);
 
+    /**
+     * 获得短信日志分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 短信日志分页
+     */
+    PageResult<SysSmsLogDO> getSmsLogPage(SysSmsLogPageReqVO pageReqVO);
+
+    /**
+     * 获得短信日志列表, 用于 Excel 导出
+     *
+     * @param exportReqVO 查询条件
+     * @return 短信日志列表
+     */
+    List<SysSmsLogDO> getSmsLogList(SysSmsLogExportReqVO exportReqVO);
+
 }

+ 28 - 0
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java

@@ -14,6 +14,34 @@ import java.util.Map;
  */
 public interface SysSmsService {
 
+    /**
+     * 发送单条短信给用户(管理员)
+     *
+     * 在 mobile 为空时,使用 userId 加载对应管理员的手机号
+     *
+     * @param mobile 手机号
+     * @param userId 用户编号
+     * @param templateCode 短信模板编号
+     * @param templateParams 短信模板参数
+     * @return 发送日志编号
+     */
+    Long sendSingleSmsToAdmin(String mobile, Long userId,
+                              String templateCode, Map<String, Object> templateParams);
+
+    /**
+     * 发送单条短信给用户(会员)
+     *
+     * 在 mobile 为空时,使用 userId 加载对应会员的手机号
+     *
+     * @param mobile 手机号
+     * @param userId 用户编号
+     * @param templateCode 短信模板编号
+     * @param templateParams 短信模板参数
+     * @return 发送日志编号
+     */
+    Long sendSingleSmsToMember(String mobile, Long userId,
+                              String templateCode, Map<String, Object> templateParams);
+
     Long sendSingleSms(String mobile, Long userId, Integer userType,
                        String templateCode, Map<String, Object> templateParams);
 

+ 14 - 0
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java

@@ -1,6 +1,9 @@
 package cn.iocoder.dashboard.modules.system.service.sms.impl;
 
 import cn.iocoder.dashboard.common.pojo.CommonResult;
+import cn.iocoder.dashboard.common.pojo.PageResult;
+import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogExportReqVO;
+import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogPageReqVO;
 import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO;
 import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsLogMapper;
@@ -12,6 +15,7 @@ import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 import java.util.Date;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
@@ -69,4 +73,14 @@ public class SysSmsLogServiceImpl implements SysSmsLogService {
                 .apiReceiveCode(apiReceiveCode).apiReceiveMsg(apiReceiveMsg).build());
     }
 
+    @Override
+    public PageResult<SysSmsLogDO> getSmsLogPage(SysSmsLogPageReqVO pageReqVO) {
+        return smsLogMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public List<SysSmsLogDO> getSmsLogList(SysSmsLogExportReqVO exportReqVO) {
+        return smsLogMapper.selectList(exportReqVO);
+    }
+
 }

+ 21 - 22
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java

@@ -25,7 +25,6 @@ import org.springframework.util.Assert;
 import javax.annotation.Resource;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.stream.Collectors;
 
 import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
@@ -53,13 +52,31 @@ public class SysSmsServiceImpl implements SysSmsService {
     @Resource
     private SysUserService userService;
 
+    @Override
+    public Long sendSingleSmsToAdmin(String mobile, Long userId, String templateCode, Map<String, Object> templateParams) {
+        // 如果 mobile 为空,则加载用户编号对应的手机号
+        if (StrUtil.isEmpty(mobile)) {
+            SysUserDO user = userService.getUser(userId);
+            if (user != null) {
+                mobile = user.getMobile();
+            }
+        }
+        // 执行发送
+        return this.sendSingleSms(mobile, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams);
+    }
+
+    @Override
+    public Long sendSingleSmsToMember(String mobile, Long userId, String templateCode, Map<String, Object> templateParams) {
+        throw new UnsupportedOperationException("暂时不支持该操作,感兴趣可以实现该功能哟!");
+    }
+
     @Override
     public Long sendSingleSms(String mobile, Long userId, Integer userType,
                               String templateCode, Map<String, Object> templateParams) {
         // 校验短信模板是否合法
         SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode);
         // 校验手机号码是否存在
-        mobile = this.checkMobile(mobile, userId, userType);
+        mobile = this.checkMobile(mobile);
 
         // 创建发送日志
         Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()); // 如果模板被禁用,则不发送短信,只记录日志
@@ -77,7 +94,7 @@ public class SysSmsServiceImpl implements SysSmsService {
     @Override
     public void sendBatchSms(List<String> mobiles, List<Long> userIds, Integer userType,
                              String templateCode, Map<String, Object> templateParams) {
-        throw new IllegalArgumentException("暂时不支持该操作,感兴趣可以实现该功能哟!");
+        throw new UnsupportedOperationException("暂时不支持该操作,感兴趣可以实现该功能哟!");
     }
 
     private SysSmsTemplateDO checkSmsTemplateValid(String templateCode) {
@@ -108,31 +125,13 @@ public class SysSmsServiceImpl implements SysSmsService {
         }).collect(Collectors.toList());
     }
 
-    private String checkMobile(String mobile, Long userId, Integer userType) {
-        mobile = getMobile(mobile, userId, userType);
+    private String checkMobile(String mobile) {
         if (StrUtil.isEmpty(mobile)) {
             throw exception(SMS_SEND_MOBILE_NOT_EXISTS);
         }
         return mobile;
     }
 
-    private String getMobile(String mobile, Long userId, Integer userType) {
-        // 如果已经有手机号,则直接返回
-        if (StrUtil.isNotEmpty(mobile)) {
-            return mobile;
-        }
-        // 没有手机号,则基于 userId 检索
-        if (userId == null || userType == null) {
-            return null;
-        }
-        if (Objects.equals(userType, UserTypeEnum.ADMIN.getValue())) {
-            SysUserDO user = userService.getUser(userId);
-            return user != null ? user.getMobile() : null;
-        }
-        // TODO 芋艿:支持 C 端用户
-        return null;
-    }
-
     @Override
     public void doSendSms(SysSmsSendMessage message) {
         // 获得渠道对应的 SmsClient 客户端

+ 1 - 1
src/main/resources/codegen/java/service/service.vm

@@ -63,7 +63,7 @@ public interface ${table.className}Service {
      * 获得${table.classComment}列表, 用于 Excel 导出
      *
      * @param exportReqVO 查询条件
-     * @return ${table.classComment}分页
+     * @return ${table.classComment}列表
      */
     List<${table.className}DO> get${simpleClassName}List(${table.className}ExportReqVO exportReqVO);
 

+ 2 - 0
src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelServiceTest.java

@@ -138,6 +138,8 @@ public class SysSmsChannelServiceTest extends BaseDbUnitTest {
        assertPojoEquals(dbSmsChannel, pageResult.getList().get(0));
     }
 
+    // ========== 随机对象 ==========
+
     @SafeVarargs
     private static SysSmsChannelDO randomSmsChannelDO(Consumer<SysSmsChannelDO>... consumers) {
         Consumer<SysSmsChannelDO> consumer = (o) -> {

+ 151 - 0
src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogServiceTest.java

@@ -0,0 +1,151 @@
+package cn.iocoder.dashboard.modules.system.service.sms;
+
+import cn.iocoder.dashboard.BaseDbUnitTest;
+import cn.iocoder.dashboard.common.enums.UserTypeEnum;
+import cn.iocoder.dashboard.common.pojo.PageResult;
+import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogExportReqVO;
+import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogPageReqVO;
+import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO;
+import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsLogMapper;
+import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsReceiveStatusEnum;
+import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
+import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsTemplateTypeEnum;
+import cn.iocoder.dashboard.modules.system.service.sms.impl.SysSmsLogServiceImpl;
+import cn.iocoder.dashboard.util.collection.ArrayUtils;
+import cn.iocoder.dashboard.util.object.ObjectUtils;
+import org.junit.jupiter.api.Test;
+import org.springframework.context.annotation.Import;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.List;
+import java.util.function.Consumer;
+
+import static cn.hutool.core.util.RandomUtil.randomEle;
+import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
+import static cn.iocoder.dashboard.util.RandomUtils.randomPojo;
+import static cn.iocoder.dashboard.util.RandomUtils.randomString;
+import static cn.iocoder.dashboard.util.date.DateUtils.buildTime;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+* {@link SysSmsLogServiceImpl} 的单元测试类
+*
+* @author 芋道源码
+*/
+@Import(SysSmsLogServiceImpl.class)
+public class SysSmsLogServiceTest extends BaseDbUnitTest {
+
+    @Resource
+    private SysSmsLogServiceImpl smsLogService;
+
+    @Resource
+    private SysSmsLogMapper smsLogMapper;
+
+    @Test // TODO 请修改 null 为需要的值
+    public void testGetSmsLogPage() {
+       // mock 数据
+       SysSmsLogDO dbSmsLog = randomSmsLogDO(o -> { // 等会查询到
+           o.setChannelId(1L);
+           o.setTemplateId(10L);
+           o.setMobile("15601691300");
+           o.setSendStatus(SysSmsSendStatusEnum.INIT.getStatus());
+           o.setSendTime(buildTime(2020, 11, 11));
+           o.setReceiveStatus(SysSmsReceiveStatusEnum.INIT.getStatus());
+           o.setReceiveTime(buildTime(2021, 11, 11));
+       });
+       smsLogMapper.insert(dbSmsLog);
+       // 测试 channelId 不匹配
+       smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setChannelId(2L)));
+       // 测试 templateId 不匹配
+       smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setTemplateId(20L)));
+       // 测试 mobile 不匹配
+       smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setMobile("18818260999")));
+       // 测试 sendStatus 不匹配
+       smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setSendStatus(SysSmsSendStatusEnum.IGNORE.getStatus())));
+       // 测试 sendTime 不匹配
+       smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setSendTime(buildTime(2020, 12, 12))));
+       // 测试 receiveStatus 不匹配
+       smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setReceiveStatus(SysSmsReceiveStatusEnum.SUCCESS.getStatus())));
+       // 测试 receiveTime 不匹配
+       smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setReceiveTime(buildTime(2021, 12, 12))));
+       // 准备参数
+       SysSmsLogPageReqVO reqVO = new SysSmsLogPageReqVO();
+       reqVO.setChannelId(1L);
+       reqVO.setTemplateId(10L);
+       reqVO.setMobile("156");
+       reqVO.setSendStatus(SysSmsSendStatusEnum.INIT.getStatus());
+       reqVO.setBeginSendTime(buildTime(2020, 11, 1));
+       reqVO.setEndSendTime(buildTime(2020, 11, 30));
+       reqVO.setReceiveStatus(SysSmsReceiveStatusEnum.INIT.getStatus());
+       reqVO.setBeginReceiveTime(buildTime(2021, 11, 1));
+       reqVO.setEndReceiveTime(buildTime(2021, 11, 30));
+
+       // 调用
+       PageResult<SysSmsLogDO> pageResult = smsLogService.getSmsLogPage(reqVO);
+       // 断言
+       assertEquals(1, pageResult.getTotal());
+       assertEquals(1, pageResult.getList().size());
+       assertPojoEquals(dbSmsLog, pageResult.getList().get(0));
+    }
+
+    @Test
+    public void testGetSmsLogList() {
+        // mock 数据
+        SysSmsLogDO dbSmsLog = randomSmsLogDO(o -> { // 等会查询到
+            o.setChannelId(1L);
+            o.setTemplateId(10L);
+            o.setMobile("15601691300");
+            o.setSendStatus(SysSmsSendStatusEnum.INIT.getStatus());
+            o.setSendTime(buildTime(2020, 11, 11));
+            o.setReceiveStatus(SysSmsReceiveStatusEnum.INIT.getStatus());
+            o.setReceiveTime(buildTime(2021, 11, 11));
+        });
+        smsLogMapper.insert(dbSmsLog);
+        // 测试 channelId 不匹配
+        smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setChannelId(2L)));
+        // 测试 templateId 不匹配
+        smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setTemplateId(20L)));
+        // 测试 mobile 不匹配
+        smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setMobile("18818260999")));
+        // 测试 sendStatus 不匹配
+        smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setSendStatus(SysSmsSendStatusEnum.IGNORE.getStatus())));
+        // 测试 sendTime 不匹配
+        smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setSendTime(buildTime(2020, 12, 12))));
+        // 测试 receiveStatus 不匹配
+        smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setReceiveStatus(SysSmsReceiveStatusEnum.SUCCESS.getStatus())));
+        // 测试 receiveTime 不匹配
+        smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setReceiveTime(buildTime(2021, 12, 12))));
+        // 准备参数
+        SysSmsLogExportReqVO reqVO = new SysSmsLogExportReqVO();
+        reqVO.setChannelId(1L);
+        reqVO.setTemplateId(10L);
+        reqVO.setMobile("156");
+        reqVO.setSendStatus(SysSmsSendStatusEnum.INIT.getStatus());
+        reqVO.setBeginSendTime(buildTime(2020, 11, 1));
+        reqVO.setEndSendTime(buildTime(2020, 11, 30));
+        reqVO.setReceiveStatus(SysSmsReceiveStatusEnum.INIT.getStatus());
+        reqVO.setBeginReceiveTime(buildTime(2021, 11, 1));
+        reqVO.setEndReceiveTime(buildTime(2021, 11, 30));
+
+       // 调用
+       List<SysSmsLogDO> list = smsLogService.getSmsLogList(reqVO);
+       // 断言
+       assertEquals(1, list.size());
+       assertPojoEquals(dbSmsLog, list.get(0));
+    }
+
+    // ========== 随机对象 ==========
+
+    @SafeVarargs
+    private static SysSmsLogDO randomSmsLogDO(Consumer<SysSmsLogDO>... consumers) {
+        Consumer<SysSmsLogDO> consumer = (o) -> {
+            o.setTemplateParams(new HashMap<>());
+            o.getTemplateParams().put(randomString(), randomString());
+            o.getTemplateParams().put(randomString(), randomString());
+            o.setTemplateType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 templateType 的范围
+            o.setUserType(randomEle(UserTypeEnum.values()).getValue()); // 保证 userType 的范围
+        };
+        return randomPojo(SysSmsLogDO.class, ArrayUtils.append(consumer, consumers));
+    }
+}

+ 3 - 3
src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java

@@ -79,7 +79,7 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest {
         SysSmsTemplateCreateReqVO reqVO = randomPojo(SysSmsTemplateCreateReqVO.class, o -> {
             o.setContent("正在进行登录操作{operation},您的验证码是{code}");
             o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
-            o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 type 的泛微
+            o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 type 的 范围
         });
         // mock Channel 的方法
         SysSmsChannelDO channelDO = randomPojo(SysSmsChannelDO.class, o -> {
@@ -114,7 +114,7 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest {
             o.setId(dbSmsTemplate.getId()); // 设置更新的 ID
             o.setContent("正在进行登录操作{operation},您的验证码是{code}");
             o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
-            o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 type 的泛微
+            o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 type 的 范围
         });
         // mock 方法
         SysSmsChannelDO channelDO = randomPojo(SysSmsChannelDO.class, o -> {
@@ -339,7 +339,7 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest {
     private static SysSmsTemplateDO randomSmsTemplateDO(Consumer<SysSmsTemplateDO>... consumers) {
         Consumer<SysSmsTemplateDO> consumer = (o) -> {
             o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
-            o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 type 的泛微
+            o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 type 的 范围
         };
         return randomPojo(SysSmsTemplateDO.class, ArrayUtils.append(consumer, consumers));
     }

+ 1 - 0
src/test/resources/sql/clean.sql

@@ -21,3 +21,4 @@ DELETE FROM "sys_operate_log";
 DELETE FROM "sys_user";
 DELETE FROM "sys_sms_channel";
 DELETE FROM "sys_sms_template";
+DELETE FROM "sys_sms_log";

+ 33 - 0
src/test/resources/sql/create_tables.sql

@@ -378,3 +378,36 @@ CREATE TABLE "sys_sms_template" (
     "deleted" bit NOT NULL DEFAULT FALSE,
     PRIMARY KEY ("id")
 ) COMMENT '短信模板';
+
+CREATE TABLE "sys_sms_log" (
+   "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+   "channel_id" bigint NOT NULL,
+   "channel_code" varchar(63) NOT NULL,
+   "template_id" bigint NOT NULL,
+   "template_code" varchar(63) NOT NULL,
+   "template_type" tinyint NOT NULL,
+   "template_content" varchar(255) NOT NULL,
+   "template_params" varchar(255) NOT NULL,
+   "api_template_id" varchar(63) NOT NULL,
+   "mobile" varchar(11) NOT NULL,
+   "user_id" bigint DEFAULT '0',
+   "user_type" tinyint DEFAULT '0',
+   "send_status" tinyint NOT NULL DEFAULT '0',
+   "send_time" timestamp DEFAULT NULL,
+   "send_code" int DEFAULT NULL,
+   "send_msg" varchar(255) DEFAULT NULL,
+   "api_send_code" varchar(63) DEFAULT NULL,
+   "api_send_msg" varchar(255) DEFAULT NULL,
+   "api_request_id" varchar(255) DEFAULT NULL,
+   "api_serial_no" varchar(255) DEFAULT NULL,
+   "receive_status" tinyint NOT NULL DEFAULT '0',
+   "receive_time" timestamp DEFAULT NULL,
+   "api_receive_code" varchar(63) DEFAULT NULL,
+   "api_receive_msg" varchar(255) DEFAULT NULL,
+   "creator" varchar(64) DEFAULT '',
+   "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+   "updater" varchar(64) DEFAULT '',
+   "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+   "deleted" bit NOT NULL DEFAULT FALSE,
+   PRIMARY KEY ("id")
+) COMMENT '短信日志';