Browse Source

Merge branch 'feature-riderSms' into dev-1

codingliang 2 years ago
parent
commit
c2123d0d31
26 changed files with 955 additions and 12 deletions
  1. 15 0
      src/main/java/com/sqx/common/exception/SqxExceptionHandler.java
  2. 27 0
      src/main/java/com/sqx/common/sms/SmsConfig.java
  3. 45 0
      src/main/java/com/sqx/common/sms/SmsConfigValueCache.java
  4. 42 0
      src/main/java/com/sqx/common/sms/SmsSendResult.java
  5. 56 0
      src/main/java/com/sqx/common/sms/SmsSendUtil.java
  6. 11 0
      src/main/java/com/sqx/common/utils/Constant.java
  7. 79 0
      src/main/java/com/sqx/modules/errand/controller/TbIndentSmsController.java
  8. 4 2
      src/main/java/com/sqx/modules/errand/controller/app/AppTbIndentController.java
  9. 34 0
      src/main/java/com/sqx/modules/errand/controller/app/AppTbIndentSmsController.java
  10. 9 0
      src/main/java/com/sqx/modules/errand/dao/TbIndentSmsSendLogDao.java
  11. 9 0
      src/main/java/com/sqx/modules/errand/dao/TbIndentSmsTemplateDao.java
  12. 28 0
      src/main/java/com/sqx/modules/errand/dto/RiderDeliveryDTO.java
  13. 34 0
      src/main/java/com/sqx/modules/errand/dto/SmsLogQueryDTO.java
  14. 39 0
      src/main/java/com/sqx/modules/errand/dto/SmsTemplateDTO.java
  15. 23 0
      src/main/java/com/sqx/modules/errand/dto/SmsTemplateQueryDTO.java
  16. 48 0
      src/main/java/com/sqx/modules/errand/entity/TbIndentSmsSendLog.java
  17. 41 0
      src/main/java/com/sqx/modules/errand/entity/TbIndentSmsTemplate.java
  18. 2 1
      src/main/java/com/sqx/modules/errand/service/TbIndentService.java
  19. 19 0
      src/main/java/com/sqx/modules/errand/service/TbIndentSmsSendLogService.java
  20. 27 0
      src/main/java/com/sqx/modules/errand/service/TbIndentSmsTemplateService.java
  21. 83 8
      src/main/java/com/sqx/modules/errand/service/impl/TbIndentServiceImpl.java
  22. 49 0
      src/main/java/com/sqx/modules/errand/service/impl/TbIndentSmsSendLogServiceImpl.java
  23. 152 0
      src/main/java/com/sqx/modules/errand/service/impl/TbIndentSmsTemplateServiceImpl.java
  24. 75 0
      src/main/java/com/sqx/modules/errand/util/SmsTemplateValUtil.java
  25. 3 0
      src/main/java/com/sqx/modules/order/entity/TbOrder.java
  26. 1 1
      src/main/resources/application-dev.yml

+ 15 - 0
src/main/java/com/sqx/common/exception/SqxExceptionHandler.java

@@ -5,6 +5,9 @@ import org.apache.shiro.authz.AuthorizationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.dao.DuplicateKeyException;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.validation.BindException;
+import org.springframework.validation.FieldError;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
 import org.springframework.web.servlet.NoHandlerFoundException;
@@ -47,6 +50,18 @@ public class SqxExceptionHandler {
 		return Result.error("没有权限,请联系管理员授权");
 	}
 
+	@ExceptionHandler(BindException.class)
+	public Result bindException(BindException ex) {
+		FieldError fieldError = ex.getFieldError();
+		assert fieldError != null;
+		return Result.error(fieldError.getDefaultMessage());
+	}
+
+	@ExceptionHandler(HttpMessageNotReadableException.class)
+	public Result HttpMessageNotReadableException() {
+		return Result.error("请求参数缺失");
+	}
+
 	@ExceptionHandler(Exception.class)
 	public Result handleException(Exception e){
 		logger.error(e.getMessage(), e);

+ 27 - 0
src/main/java/com/sqx/common/sms/SmsConfig.java

@@ -0,0 +1,27 @@
+package com.sqx.common.sms;
+
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * 短信发送配置
+ */
+@Data
+@Builder
+public class SmsConfig {
+
+    /**
+     * 短信签名
+     */
+    private String smsSign;
+
+    /**
+     * clientId
+     */
+    private String clientId;
+
+    /**
+     * secret
+     */
+    private String clientSecret;
+}

+ 45 - 0
src/main/java/com/sqx/common/sms/SmsConfigValueCache.java

@@ -0,0 +1,45 @@
+package com.sqx.common.sms;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.sqx.common.exception.SqxException;
+import com.sqx.modules.common.service.CommonInfoService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * 短信发送配置缓存
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class SmsConfigValueCache {
+
+    private final CommonInfoService commonInfoService;
+
+    /**
+     * 腾讯短信配置
+     */
+    private SmsConfig tencentSmsConfig;
+
+    /**
+     * 获取腾讯云sms配置
+     * @return
+     */
+    public SmsConfig getTencentSmsConfig() {
+        if (ObjectUtil.isNull(tencentSmsConfig)) {
+            try {
+                this.tencentSmsConfig = SmsConfig.builder()
+                        .clientId(commonInfoService.findOne(31).getValue())
+                        .clientSecret(commonInfoService.findOne(32).getValue())
+                        .smsSign(commonInfoService.findOne(12).getValue())
+                        .build();
+            } catch (Exception e) {
+                log.error("腾讯短信配置构建失败,【{}】", e.getMessage());
+                throw new SqxException("腾讯短信配置构建失败");
+            }
+        }
+
+        return tencentSmsConfig;
+    }
+}

+ 42 - 0
src/main/java/com/sqx/common/sms/SmsSendResult.java

@@ -0,0 +1,42 @@
+package com.sqx.common.sms;
+
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * 短信发送结果
+ */
+@Data
+@Builder
+public class SmsSendResult {
+
+    /**
+     * code 1表示成功 0表示失败
+     */
+    private String code;
+
+    /**
+     * 返回信息
+     */
+    private String msg;
+
+    /**
+     * sms模板id
+     */
+    private Long templateId;
+
+    /**
+     * 发送内容
+     */
+    private String content;
+
+    /**
+     * 发送人id
+     */
+    private Long sendFromId;
+
+    /**
+     * 接收人号码
+     */
+    private String sendTo;
+}

+ 56 - 0
src/main/java/com/sqx/common/sms/SmsSendUtil.java

@@ -0,0 +1,56 @@
+package com.sqx.common.sms;
+
+import com.github.qcloudsms.SmsSingleSender;
+import com.github.qcloudsms.SmsSingleSenderResult;
+import com.sqx.common.utils.Constant;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 短信发送工具
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class SmsSendUtil {
+
+    private final SmsConfig smsConfig;
+    /**
+     * 最终发送内容模板,格式: 【短信签名】短信内容
+     */
+    private final String contentTemplate = "【%s】%s";
+
+    /**
+     * 使用腾讯sms发送短信
+     * @param phone 手机号码
+     * @param content 短信内容,内容需要和腾讯云sms控制台已创建的模板格式保持一致
+     * @return
+     */
+    public SmsSendResult sendByTencent(String phone, String content) {
+        SmsSingleSender smsSingleSender = new SmsSingleSender(Integer.parseInt(smsConfig.getClientId()), smsConfig.getClientSecret());
+
+        String code;
+        String msg;
+        try {
+            SmsSingleSenderResult result = smsSingleSender.send(0, "86", phone, String.format(contentTemplate, smsConfig.getSmsSign(), content), "", "");
+            if (result.result == 0) {
+                code = Constant.YES;
+                log.info("腾讯短信发送成功,发送参数:phone【{}】, content【{}】", phone, content);
+            } else {
+                code = Constant.NO;
+                log.error("腾讯短信发送失败,发送参数:phone【{}】, content【{}】,错误信息【{}】", phone, content, result.errMsg);
+            }
+            msg = result.errMsg;
+        } catch (Exception e) {
+            code = Constant.NO;
+            msg = e.getMessage();
+            log.error("腾讯短信发送失败,发送参数:phone【{}】, content【{}】,错误信息【{}】", phone, content, e.getMessage());
+        }
+
+        return SmsSendResult.builder()
+                .code(code)
+                .msg(msg)
+                .content(content)
+                .sendTo(phone)
+                .build();
+    }
+}

+ 11 - 0
src/main/java/com/sqx/common/utils/Constant.java

@@ -27,6 +27,17 @@ public class Constant {
      *  升序
      */
     public static final String ASC = "asc";
+
+    /**
+     * yes
+     */
+    public static final String YES = "1";
+
+    /**
+     * no
+     */
+    public static final String NO = "0";
+
 	/**
 	 * 菜单类型
 	 */

+ 79 - 0
src/main/java/com/sqx/modules/errand/controller/TbIndentSmsController.java

@@ -0,0 +1,79 @@
+package com.sqx.modules.errand.controller;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.sqx.common.exception.SqxException;
+import com.sqx.common.utils.PageUtils;
+import com.sqx.common.utils.Result;
+import com.sqx.modules.errand.dto.SmsLogQueryDTO;
+import com.sqx.modules.errand.dto.SmsTemplateDTO;
+import com.sqx.modules.errand.dto.SmsTemplateQueryDTO;
+import com.sqx.modules.errand.service.TbIndentSmsSendLogService;
+import com.sqx.modules.errand.service.TbIndentSmsTemplateService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+import java.util.Arrays;
+
+@RestController
+@RequestMapping("admin/tb-indent-sms")
+@Api(value = "管理端-跑腿确认送达短信", tags = {"管理端-跑腿确认送达短信"})
+@RequiredArgsConstructor
+public class TbIndentSmsController {
+
+    private final TbIndentSmsSendLogService smsSendLogService;
+    private final TbIndentSmsTemplateService smsTemplateService;
+
+    @ApiOperation("模板分页")
+    @GetMapping(value = "template")
+    public Result templatePage(SmsTemplateQueryDTO queryDTO) {
+        PageUtils pageUtils = smsTemplateService.templatePage(queryDTO);
+        return Result.success().put("data", pageUtils);
+    }
+
+    @ApiOperation("新增模板")
+    @PostMapping(value = "template")
+    public Result addTemplate(@Valid @RequestBody SmsTemplateDTO template) {
+        smsTemplateService.saveTemplate(template);
+        return Result.success();
+    }
+
+    @ApiOperation("修改模板")
+    @PutMapping(value = "template")
+    public Result updateTemplate(@Valid @RequestBody SmsTemplateDTO template) {
+        if (ObjectUtil.isNull(template.getId())) {
+            throw new SqxException("模板id不能为空");
+        }
+        smsTemplateService.updateTemplate(template);
+        return Result.success();
+    }
+
+    @ApiOperation("删除模板")
+    @DeleteMapping(value = "template")
+    public Result delTemplates(@RequestBody Long[] ids) {
+        smsTemplateService.removeByIds(Arrays.asList(ids));
+        return Result.success();
+    }
+
+    @ApiOperation("短信发送记录分页")
+    @GetMapping(value = "log")
+    public Result logPage(SmsLogQueryDTO queryDTO) {
+        PageUtils pageUtils = smsSendLogService.logPage(queryDTO);
+        return Result.success().put("data", pageUtils);
+    }
+
+    @ApiOperation("删除短信发送记录")
+    @DeleteMapping(value = "log")
+    public Result delLogs(@RequestBody Long[] ids) {
+        smsSendLogService.removeByIds(Arrays.asList(ids));
+        return Result.success();
+    }
+}

+ 4 - 2
src/main/java/com/sqx/modules/errand/controller/app/AppTbIndentController.java

@@ -7,6 +7,7 @@ import com.sqx.modules.app.entity.UserEntity;
 import com.sqx.modules.app.service.UserService;
 import com.sqx.modules.common.entity.CommonInfo;
 import com.sqx.modules.common.service.CommonInfoService;
+import com.sqx.modules.errand.dto.RiderDeliveryDTO;
 import com.sqx.modules.errand.entity.*;
 import com.sqx.modules.errand.service.ErrandComplaintService;
 import com.sqx.modules.errand.service.TbIndentService;
@@ -18,6 +19,7 @@ import org.apache.commons.lang.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
+import javax.validation.Valid;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -245,9 +247,9 @@ public class AppTbIndentController {
     @Login
     @PostMapping(value = "riderDelivery")
     @ApiOperation("骑手已送达")
-    public Result riderDelivery(@RequestAttribute Long userId, String indentNumber, String itemCode){
+    public Result riderDelivery(@RequestAttribute Long userId, @Valid @RequestBody RiderDeliveryDTO riderDeliveryDTO){
 
-        return tbIndentService.riderDelivery(userId, indentNumber, itemCode);
+        return tbIndentService.riderDelivery(userId, riderDeliveryDTO);
     }
 
     //用户确认已送达

+ 34 - 0
src/main/java/com/sqx/modules/errand/controller/app/AppTbIndentSmsController.java

@@ -0,0 +1,34 @@
+package com.sqx.modules.errand.controller.app;
+
+import com.sqx.common.query.PageQuery;
+import com.sqx.common.utils.Constant;
+import com.sqx.common.utils.PageUtils;
+import com.sqx.common.utils.Result;
+import com.sqx.modules.errand.dto.SmsTemplateQueryDTO;
+import com.sqx.modules.errand.service.TbIndentSmsTemplateService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("app/tb-indent-sms")
+@Api(value = "骑手端-跑腿确认送达短信", tags = {"骑手端-跑腿确认送达短信"})
+@RequiredArgsConstructor
+public class AppTbIndentSmsController {
+
+    private final TbIndentSmsTemplateService smsTemplateService;
+
+    @ApiOperation("模板分页")
+    @GetMapping(value = "template")
+    public Result templatePage(PageQuery pageQuery) {
+        SmsTemplateQueryDTO queryDTO = new SmsTemplateQueryDTO();
+        BeanUtils.copyProperties(pageQuery, queryDTO);
+        queryDTO.setStatus(Constant.YES);
+        PageUtils pageUtils = smsTemplateService.templatePage(queryDTO);
+        return Result.success().put("data", pageUtils);
+    }
+}

+ 9 - 0
src/main/java/com/sqx/modules/errand/dao/TbIndentSmsSendLogDao.java

@@ -0,0 +1,9 @@
+package com.sqx.modules.errand.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.sqx.modules.errand.entity.TbIndentSmsSendLog;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface TbIndentSmsSendLogDao extends BaseMapper<TbIndentSmsSendLog>  {
+}

+ 9 - 0
src/main/java/com/sqx/modules/errand/dao/TbIndentSmsTemplateDao.java

@@ -0,0 +1,9 @@
+package com.sqx.modules.errand.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.sqx.modules.errand.entity.TbIndentSmsTemplate;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface TbIndentSmsTemplateDao extends BaseMapper<TbIndentSmsTemplate> {
+}

+ 28 - 0
src/main/java/com/sqx/modules/errand/dto/RiderDeliveryDTO.java

@@ -0,0 +1,28 @@
+package com.sqx.modules.errand.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 骑手送达dto
+ */
+@Data
+@ApiModel("RiderDeliveryDTO")
+public class RiderDeliveryDTO {
+
+    @ApiModelProperty(value = "跑腿订单号", required = true)
+    @NotBlank(message = "跑腿订单号不能为空")
+    private String indentNumber;
+
+    @ApiModelProperty(value = "收货码")
+    private String itemCode;
+
+    @ApiModelProperty(value = "短信模板id,外卖订单该值不能为空")
+    private Long smsTemplateId;
+
+    @ApiModelProperty(value = "图片地址,多个图片使用,分割,外卖订单该值不能为空")
+    private String imgs;
+}

+ 34 - 0
src/main/java/com/sqx/modules/errand/dto/SmsLogQueryDTO.java

@@ -0,0 +1,34 @@
+package com.sqx.modules.errand.dto;
+
+import com.sqx.common.query.PageQuery;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * 短信历史分页查询dto
+ */
+@Data
+@ApiModel("SmsLogQueryDTO")
+public class SmsLogQueryDTO extends PageQuery {
+
+    @ApiModelProperty("订单id")
+    private Long orderId;
+
+    @ApiModelProperty("是否发送成功")
+    private String successFlag;
+
+    @ApiModelProperty("接受人")
+    private String sendTo;
+
+    @ApiModelProperty("查询开始时间")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private Date startTime;
+
+    @ApiModelProperty("查询结束时间")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private Date endTime;
+}

+ 39 - 0
src/main/java/com/sqx/modules/errand/dto/SmsTemplateDTO.java

@@ -0,0 +1,39 @@
+package com.sqx.modules.errand.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
+
+/**
+ * 短信模板
+ */
+@Data
+@ApiModel("SmsTemplateDTO")
+public class SmsTemplateDTO {
+    @ApiModelProperty("id,修改时不能为空")
+    private Long id;
+
+    @ApiModelProperty(value = "模板名称", required = true)
+    @NotBlank(message = "模板名称不能为空")
+    private String templateName;
+
+    @ApiModelProperty(value = "模板内容 支持自定义变量", required = true)
+    @NotBlank(message = "模板内容不能为空")
+    private String templateContent;
+
+    @ApiModelProperty(value = "第三方平台模板code")
+    private String platformCode;
+
+    @ApiModelProperty(value = "第三方平台类型 1腾讯", required = true)
+    @NotBlank(message = "第三方平台类型不能为空")
+    @Pattern(regexp = "(1)", message = "第三方平台类型目前只支持腾讯 1")
+    private String platformType;
+
+    @ApiModelProperty(value = "状态 1启用 0禁用", required = true)
+    @NotBlank(message = "状态不能为空")
+    @Pattern(regexp = "(1|0)", message = "状态只能为1或0")
+    private String status;
+}

+ 23 - 0
src/main/java/com/sqx/modules/errand/dto/SmsTemplateQueryDTO.java

@@ -0,0 +1,23 @@
+package com.sqx.modules.errand.dto;
+
+import com.sqx.common.query.PageQuery;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 短信模板分页查询dto
+ */
+@Data
+@ApiModel("SmsTemplateQueryDTO")
+public class SmsTemplateQueryDTO extends PageQuery {
+
+    @ApiModelProperty("模板名称")
+    private String templateName;
+
+    @ApiModelProperty("平台类型")
+    private String platformType;
+
+    @ApiModelProperty("状态")
+    private String status;
+}

+ 48 - 0
src/main/java/com/sqx/modules/errand/entity/TbIndentSmsSendLog.java

@@ -0,0 +1,48 @@
+package com.sqx.modules.errand.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 跑腿订单确认收货短信发送记录
+ */
+@Data
+@ApiModel("tb_indent_sms_send_log")
+public class TbIndentSmsSendLog {
+
+    /**
+     * id
+     */
+    @TableId(type = IdType.AUTO)
+    @ApiModelProperty("id")
+    private Long id;
+
+    @ApiModelProperty("订单id")
+    private Long orderId;
+
+    @ApiModelProperty("短信模板id")
+    private Long templateId;
+
+    @ApiModelProperty("发送内容")
+    private String sendContent;
+
+    @ApiModelProperty("是否发送成功 1发送成功 0发送失败")
+    private String successFlag;
+
+    @ApiModelProperty("短信发送结果")
+    private String sendResult;
+
+    @ApiModelProperty("发送人id")
+    private Long sendFromId;
+
+    @ApiModelProperty("接收号码")
+    private String sendTo;
+
+    @ApiModelProperty("发送时间")
+    private Date sendTime;
+}

+ 41 - 0
src/main/java/com/sqx/modules/errand/entity/TbIndentSmsTemplate.java

@@ -0,0 +1,41 @@
+package com.sqx.modules.errand.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 跑腿订单确认收货短信模板
+ */
+@Data
+@ApiModel("tb_indent_sms_template")
+public class TbIndentSmsTemplate implements Serializable {
+
+    @TableId(type = IdType.AUTO)
+    @ApiModelProperty("id")
+    private Long id;
+
+    @ApiModelProperty("模板名称")
+    private String templateName;
+
+    @ApiModelProperty("模板内容 支持自定义变量")
+    private String templateContent;
+
+    @ApiModelProperty("第三方平台模板code")
+    private String platformCode;
+
+    @ApiModelProperty("第三方平台类型 1腾讯")
+    private String platformType;
+
+    @ApiModelProperty("状态 1启用 0禁用")
+    private String status;
+
+    @TableLogic(value = "0", delval = "1")
+    @ApiModelProperty("是否删除 1是,0否")
+    private String delFlag;
+}

+ 2 - 1
src/main/java/com/sqx/modules/errand/service/TbIndentService.java

@@ -3,6 +3,7 @@ package com.sqx.modules.errand.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.sqx.common.utils.Result;
 import com.sqx.modules.app.entity.UserEntity;
+import com.sqx.modules.errand.dto.RiderDeliveryDTO;
 import com.sqx.modules.errand.entity.ErrandAddress;
 import com.sqx.modules.errand.entity.ErrandEvaluate;
 import com.sqx.modules.errand.entity.ErrandRedPacket;
@@ -31,7 +32,7 @@ public interface TbIndentService extends IService<TbIndent> {
 
     Result riderCancleIndent(String indentNumber,Integer type);
 
-    Result riderDelivery(Long userId, String indentNumber, String itemCode);
+    Result riderDelivery(Long userId, RiderDeliveryDTO deliveryDTO);
 
     Result userDelivery(Long userId, String indentNumber);
 

+ 19 - 0
src/main/java/com/sqx/modules/errand/service/TbIndentSmsSendLogService.java

@@ -0,0 +1,19 @@
+package com.sqx.modules.errand.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.sqx.common.sms.SmsSendResult;
+import com.sqx.common.utils.PageUtils;
+import com.sqx.modules.errand.dto.SmsLogQueryDTO;
+import com.sqx.modules.errand.entity.TbIndentSmsSendLog;
+
+public interface TbIndentSmsSendLogService extends IService<TbIndentSmsSendLog> {
+
+    PageUtils logPage(SmsLogQueryDTO queryDTO);
+
+    /**
+     * 保存短信发送日志
+     * @param indentId 跑腿订单id
+     * @param smsSendResult 短信发送结果
+     */
+    void saveLog(Long indentId, SmsSendResult smsSendResult);
+}

+ 27 - 0
src/main/java/com/sqx/modules/errand/service/TbIndentSmsTemplateService.java

@@ -0,0 +1,27 @@
+package com.sqx.modules.errand.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.sqx.common.sms.SmsSendResult;
+import com.sqx.common.utils.PageUtils;
+import com.sqx.modules.app.entity.UserEntity;
+import com.sqx.modules.errand.dto.SmsTemplateDTO;
+import com.sqx.modules.errand.dto.SmsTemplateQueryDTO;
+import com.sqx.modules.errand.entity.TbIndentSmsTemplate;
+
+public interface TbIndentSmsTemplateService extends IService<TbIndentSmsTemplate> {
+
+    void saveTemplate(SmsTemplateDTO template);
+
+    void updateTemplate(SmsTemplateDTO template);
+
+    PageUtils templatePage(SmsTemplateQueryDTO queryDTO);
+
+    /**
+     * 短信发送
+     * @param smsTemplateId 模板id
+     * @param fromUser 发送人信息
+     * @param toPhone 手机人手机号
+     * @return 短信发送结果
+     */
+    SmsSendResult sendSms(Long smsTemplateId, UserEntity fromUser, String toPhone);
+}

+ 83 - 8
src/main/java/com/sqx/modules/errand/service/impl/TbIndentServiceImpl.java

@@ -1,11 +1,15 @@
 package com.sqx.modules.errand.service.impl;
 
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sqx.common.exception.SqxException;
+import com.sqx.common.sms.SmsSendResult;
 import com.sqx.common.utils.DateUtils;
 import com.sqx.common.utils.PageUtils;
 import com.sqx.common.utils.Result;
@@ -20,17 +24,19 @@ import com.sqx.modules.common.entity.CommonInfo;
 import com.sqx.modules.common.service.CommonInfoService;
 import com.sqx.modules.errand.dao.ErrandEvaluateDao;
 import com.sqx.modules.errand.dao.TbIndentDao;
+import com.sqx.modules.errand.dto.RiderDeliveryDTO;
 import com.sqx.modules.errand.entity.ErrandAddress;
 import com.sqx.modules.errand.entity.ErrandEvaluate;
 import com.sqx.modules.errand.entity.ErrandRedPacket;
 import com.sqx.modules.errand.entity.TbIndent;
 import com.sqx.modules.errand.service.TbIndentService;
+import com.sqx.modules.errand.service.TbIndentSmsSendLogService;
+import com.sqx.modules.errand.service.TbIndentSmsTemplateService;
 import com.sqx.modules.errand.util.LonLatUtil;
 import com.sqx.modules.goods.dao.GoodsShopDao;
 import com.sqx.modules.goods.dao.GoodsShopRelevancyDao;
 import com.sqx.modules.goods.entity.GoodsShop;
 import com.sqx.modules.goods.entity.GoodsShopRelevancy;
-import com.sqx.modules.message.dao.MessageInfoDao;
 import com.sqx.modules.message.entity.MessageInfo;
 import com.sqx.modules.message.service.MessageService;
 import com.sqx.modules.order.dao.OrderGoodsDao;
@@ -52,9 +58,16 @@ import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.annotation.Resource;
 import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 @Service
@@ -92,6 +105,12 @@ public class TbIndentServiceImpl extends ServiceImpl<TbIndentDao, TbIndent> impl
     private MessageService messageService;
     @Autowired
     private GoodsShopRelevancyDao goodsShopRelevancyDao;
+
+    @Resource
+    private TbIndentSmsTemplateService smsTemplateService;
+    @Resource
+    private TbIndentSmsSendLogService smsSendLogService;
+
     private ReentrantReadWriteLock reentrantReadWriteLock=new ReentrantReadWriteLock(true);
 
     @Override
@@ -803,17 +822,73 @@ public class TbIndentServiceImpl extends ServiceImpl<TbIndentDao, TbIndent> impl
     }
 
     @Override
-    public Result riderDelivery(Long userId, String indentNumber, String itemCode) {
+    @Transactional
+    public Result riderDelivery(Long userId, RiderDeliveryDTO deliveryDTO) {
+        // 添加拍照发短信逻辑
+        // 因为原有的确认送达方法代码比较凌乱,且不好重新封装,所以这里就在原有确认收货方法之前添加拍照发短信逻辑
         reentrantReadWriteLock.writeLock().lock();
         try{
-            return finshOrder(userId, indentNumber, itemCode);
-        }catch (Exception e){
-            e.printStackTrace();
+            String indentNumber = deliveryDTO.getIndentNumber();
+            TbIndent indentOrder = tbIndentDao.findIndentByNumber(indentNumber);
+            if (ObjectUtil.isNull(indentOrder)) {
+                throw new SqxException("无效的跑腿订单id");
+            }
+
+            // 如果是外卖订单
+            if (ObjectUtil.equal(indentOrder.getIndentType(), "5")) {
+                handTakeoutOrder(indentOrder, userId, deliveryDTO);
+            }
+
+            return finshOrder(userId, indentNumber, deliveryDTO.getItemCode());
+        } catch (Exception e){
             log.error("完成订单异常:"+e.getMessage(),e);
-        }finally {
+            throw new SqxException(e.getMessage());
+        } finally {
             reentrantReadWriteLock.writeLock().unlock();
         }
-        return Result.error("系统繁忙,请稍后再试!");
+    }
+
+    /**
+     * 处理外卖订单
+     * @param indentOrder 跑腿订单
+     * @param userId 当前用户id
+     * @param deliveryDTO 送达信息
+     */
+    private void handTakeoutOrder(TbIndent indentOrder, Long userId, RiderDeliveryDTO deliveryDTO) {
+        // 6表示跑腿订单处于已完成状态
+        if("6".equals(indentOrder.getIndentState())){
+            return;
+        }
+
+        Long smsTemplateId = deliveryDTO.getSmsTemplateId();
+        String imgs = deliveryDTO.getImgs();
+        if (ObjectUtil.isNull(smsTemplateId) || StrUtil.isBlank(imgs)) {
+            throw new SqxException("短信模板id或图片不能为空");
+        }
+
+        // 收货人手机
+        String userPhone = indentOrder.getUserPhone();
+        // 当前骑手
+        UserEntity riderUser = userService.getById(userId);
+
+        if (StrUtil.isBlank(userPhone)) {
+            log.error("外卖跑腿订单【{}】收货人手机号码为空...", deliveryDTO.getIndentNumber());
+            return;
+        }
+
+        if (ObjectUtil.isNull(riderUser) || StrUtil.isBlank(riderUser.getPhone())) {
+            log.error("外卖跑腿订单【{}】当前骑手id【{}】骑手不存在,或当前骑手手机号码为空...", deliveryDTO.getIndentNumber(), userId);
+            return;
+        }
+
+        // 订单新增送达图片
+        TbOrder tbOrder = appOrderService.getById(indentOrder.getOrderId());
+        tbOrder.setDeliveryImgs(imgs);
+        appOrderService.updateOrder(tbOrder);
+
+        // 发送短信并记录短信发送记录
+        SmsSendResult smsSendResult = smsTemplateService.sendSms(smsTemplateId, riderUser, userPhone);
+        smsSendLogService.saveLog(indentOrder.getIndentId(), smsSendResult);
     }
 
     @Transactional

+ 49 - 0
src/main/java/com/sqx/modules/errand/service/impl/TbIndentSmsSendLogServiceImpl.java

@@ -0,0 +1,49 @@
+package com.sqx.modules.errand.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sqx.common.sms.SmsSendResult;
+import com.sqx.common.utils.PageUtils;
+import com.sqx.modules.errand.dao.TbIndentSmsSendLogDao;
+import com.sqx.modules.errand.dto.SmsLogQueryDTO;
+import com.sqx.modules.errand.entity.TbIndentSmsSendLog;
+import com.sqx.modules.errand.service.TbIndentSmsSendLogService;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+
+@Service
+public class TbIndentSmsSendLogServiceImpl extends ServiceImpl<TbIndentSmsSendLogDao, TbIndentSmsSendLog> implements TbIndentSmsSendLogService {
+
+    @Override
+    public PageUtils logPage(SmsLogQueryDTO queryDTO) {
+        Page<TbIndentSmsSendLog> pages = new Page<>(queryDTO.getPage(), queryDTO.getLimit());
+        LambdaQueryWrapper<TbIndentSmsSendLog> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(ObjectUtil.isNotNull(queryDTO.getOrderId()), TbIndentSmsSendLog::getOrderId, queryDTO.getOrderId());
+        queryWrapper.eq(StrUtil.isNotBlank(queryDTO.getSuccessFlag()), TbIndentSmsSendLog::getSuccessFlag, queryDTO.getSuccessFlag());
+        queryWrapper.eq(StrUtil.isNotBlank(queryDTO.getSendTo()), TbIndentSmsSendLog::getSendTo, queryDTO.getSendTo());
+        queryWrapper.ge(ObjectUtil.isNotNull(queryDTO.getStartTime()), TbIndentSmsSendLog::getSendTime, queryDTO.getStartTime());
+        queryWrapper.le(ObjectUtil.isNotNull(queryDTO.getEndTime()), TbIndentSmsSendLog::getSendTime, queryDTO.getEndTime());
+
+        return new PageUtils(this.page(pages, queryWrapper));
+    }
+
+    @Override
+    public void saveLog(Long indentId, SmsSendResult smsSendResult) {
+        TbIndentSmsSendLog log = new TbIndentSmsSendLog();
+
+        log.setSendTime(new Date());
+        log.setOrderId(indentId);
+        log.setTemplateId(smsSendResult.getTemplateId());
+        log.setSendContent(smsSendResult.getContent());
+        log.setSuccessFlag(smsSendResult.getCode());
+        log.setSendResult(smsSendResult.getMsg());
+        log.setSendFromId(smsSendResult.getSendFromId());
+        log.setSendTo(smsSendResult.getSendTo());
+
+        save(log);
+    }
+}

+ 152 - 0
src/main/java/com/sqx/modules/errand/service/impl/TbIndentSmsTemplateServiceImpl.java

@@ -0,0 +1,152 @@
+package com.sqx.modules.errand.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sqx.common.exception.SqxException;
+import com.sqx.common.sms.SmsConfigValueCache;
+import com.sqx.common.sms.SmsSendResult;
+import com.sqx.common.sms.SmsSendUtil;
+import com.sqx.common.utils.Constant;
+import com.sqx.common.utils.PageUtils;
+import com.sqx.modules.app.entity.UserEntity;
+import com.sqx.modules.errand.dao.TbIndentSmsTemplateDao;
+import com.sqx.modules.errand.dto.SmsTemplateDTO;
+import com.sqx.modules.errand.dto.SmsTemplateQueryDTO;
+import com.sqx.modules.errand.entity.TbIndentSmsTemplate;
+import com.sqx.modules.errand.service.TbIndentSmsTemplateService;
+import com.sqx.modules.errand.util.SmsTemplateValUtil;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+@RequiredArgsConstructor
+public class TbIndentSmsTemplateServiceImpl extends ServiceImpl<TbIndentSmsTemplateDao, TbIndentSmsTemplate> implements TbIndentSmsTemplateService {
+
+    private final SmsConfigValueCache smsConfigValueCache;
+
+    @Override
+    public void saveTemplate(SmsTemplateDTO template) {
+        // 校验模板名称是否唯一
+        checkTemplateUnique(template);
+
+        // 检验模板是否符合规范
+        checkTemplateContent(template);
+
+        // 转换成po
+        TbIndentSmsTemplate tbIndentSmsTemplate = new TbIndentSmsTemplate();
+        BeanUtils.copyProperties(template, tbIndentSmsTemplate);
+
+        // 填充默认属性
+        tbIndentSmsTemplate.setDelFlag(Constant.NO);
+
+        // 执行保存操作
+        save(tbIndentSmsTemplate);
+    }
+
+    @Override
+    public void updateTemplate(SmsTemplateDTO template) {
+        // 校验模板名称是否唯一
+        checkTemplateUnique(template);
+
+        // 检验模板是否符合规范
+        checkTemplateContent(template);
+
+        // 转换成po
+        TbIndentSmsTemplate tbIndentSmsTemplate = new TbIndentSmsTemplate();
+        BeanUtils.copyProperties(template, tbIndentSmsTemplate);
+
+        // 填充默认属性
+        tbIndentSmsTemplate.setDelFlag(Constant.NO);
+
+        // 执行保存操作
+        updateById(tbIndentSmsTemplate);
+    }
+
+    @Override
+    public PageUtils templatePage(SmsTemplateQueryDTO queryDTO) {
+        Page<TbIndentSmsTemplate> pages = new Page<>(queryDTO.getPage(), queryDTO.getLimit());
+        LambdaQueryWrapper<TbIndentSmsTemplate> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.like(StrUtil.isNotBlank(queryDTO.getTemplateName()), TbIndentSmsTemplate::getTemplateName, queryDTO.getTemplateName());
+        queryWrapper.eq(StrUtil.isNotBlank(queryDTO.getStatus()), TbIndentSmsTemplate::getStatus, queryDTO.getStatus());
+        queryWrapper.eq(StrUtil.isNotBlank(queryDTO.getPlatformType()), TbIndentSmsTemplate::getPlatformType, queryDTO.getPlatformType());
+
+        return new PageUtils(this.page(pages, queryWrapper));
+    }
+
+    @Override
+    public SmsSendResult sendSms(Long smsTemplateId, UserEntity fromUser, String toPhone) {
+        TbIndentSmsTemplate smsTemplate = getById(smsTemplateId);
+        if (ObjectUtil.isNull(smsTemplate)) {
+            throw new SqxException("无效的短信模板id");
+        }
+
+        String templateContent = smsTemplate.getTemplateContent();
+        Map<String, String> templateVal = getTemplateVal(templateContent, fromUser);
+        String finalContent = SmsTemplateValUtil.replaceTemplateVal(templateContent, templateVal);
+
+        SmsSendResult smsSendResult;
+
+        // 1表示使用腾讯sms发送
+        if ("1".equals(smsTemplate.getPlatformType())) {
+            SmsSendUtil smsSendUtil = new SmsSendUtil(smsConfigValueCache.getTencentSmsConfig());
+
+            smsSendResult = smsSendUtil.sendByTencent(toPhone, finalContent);
+        } else {
+            throw new SqxException("不支持的短信发送平台...");
+        }
+
+        // 填充smsSendResult其他属性
+        smsSendResult.setTemplateId(smsTemplateId);
+        smsSendResult.setSendFromId(fromUser.getUserId());
+
+        return smsSendResult;
+    }
+
+    /**
+     * 获取模板动态参数
+     * @param templateContent 模板
+     * @param fromUser 发送人信息
+     * @return
+     */
+    private Map<String, String> getTemplateVal(String templateContent, UserEntity fromUser) {
+        // 获取当前模板有哪些自定义参数
+        List<String> templateValName = SmsTemplateValUtil.getTemplateValName(templateContent);
+        Map<String, String> templateVal = new HashMap<>();
+        templateValName.forEach(valName -> {
+            String value;
+            if (ObjectUtil.equal(valName, SmsTemplateValUtil.SUPPORT_VAL_NAME_LIST.get(0))) {
+                value = fromUser.getPhone();
+            } else {
+                value = fromUser.getUserName();
+            }
+
+            templateVal.put(valName, value);
+        });
+
+        return templateVal;
+    }
+
+    private void checkTemplateUnique(SmsTemplateDTO template) {
+        LambdaQueryWrapper<TbIndentSmsTemplate> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(TbIndentSmsTemplate::getTemplateName, template.getTemplateName());
+        queryWrapper.ne(template.getId() != null, TbIndentSmsTemplate::getId, template.getId());
+
+        if (count(queryWrapper) > 0) {
+            throw new SqxException("当前模板名称已经存在");
+        }
+    }
+
+    private void checkTemplateContent(SmsTemplateDTO template) {
+        if (!SmsTemplateValUtil.checkText(template.getTemplateContent())) {
+            throw new SqxException("当前模板内容存在未定义变量");
+        }
+    }
+}

+ 75 - 0
src/main/java/com/sqx/modules/errand/util/SmsTemplateValUtil.java

@@ -0,0 +1,75 @@
+package com.sqx.modules.errand.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 短信模板变量工具类
+ */
+public class SmsTemplateValUtil {
+
+    /**
+     * 模板占位符
+     */
+    public static final String TEMPLATE_HOLD = "\\$\\{%s}";
+
+    /**
+     * 模板正则表达式
+     */
+    public static final Pattern PATTERN = Pattern.compile("\\$\\{(.*?)\\}");
+
+    /**
+     * 当前支持的变量名称列表
+     */
+    public static final List<String> SUPPORT_VAL_NAME_LIST = Arrays.asList("currentUserPhone", "currentUserName");
+
+    /**
+     * 获取text中的自定义变量名称
+     * @param text 例如:这是一条测试短信,验证码为 ${code}。 可以把code提取出来
+     * @return
+     */
+    public static List<String> getTemplateValName(String text) {
+        Matcher matcher = PATTERN.matcher(text);
+
+        List<String> valNames = new ArrayList<>();
+        while (matcher.find()) {
+            valNames.add(matcher.group(1));
+        }
+
+        return valNames;
+    }
+
+    /**
+     * 校验text中自定义变量名称
+     * @param text
+     * @return
+     */
+    public static boolean checkText(String text) {
+        List<String> templateValName = getTemplateValName(text);
+        for (String valName : templateValName) {
+            if (!SUPPORT_VAL_NAME_LIST.contains(valName)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * 模板参数替换
+     * @param text  模板内容
+     * @param value 动态参数
+     * @return
+     */
+    public static String replaceTemplateVal(String text, Map<String, String> value) {
+        final String[] finalText = {text};
+        value.keySet().forEach(key -> {
+            finalText[0] = finalText[0].replaceAll(String.format(TEMPLATE_HOLD, key), value.get(key));
+        });
+        return finalText[0];
+    }
+}

+ 3 - 0
src/main/java/com/sqx/modules/order/entity/TbOrder.java

@@ -131,6 +131,9 @@ public class TbOrder implements Serializable {
     @ApiModelProperty("订单备注")
     private String remark;
 
+    @ApiModelProperty("送达图片,多个图片之间使用,分割")
+    private String deliveryImgs;
+
     @ApiModelProperty("商铺名")
     @TableField(exist = false)
     private String shopName;

+ 1 - 1
src/main/resources/application-dev.yml

@@ -3,7 +3,7 @@ spring:
         type: com.alibaba.druid.pool.DruidDataSource
         druid:
             driver-class-name: com.mysql.cj.jdbc.Driver
-            url: jdbc:mysql://223.84.177.126:3306/tcwm2.5?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=CTT
+            url: jdbc:mysql://103.131.169.54:33007/tcwm2.5?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=CTT
             username: root
             password: chuanghai_2024.
             initial-size: 10