Merge branch 'refs/heads/zt-test' into test
# Conflicts: # zt-framework/zt-common/src/main/java/com/zt/plat/framework/common/biz/system/permission/PermissionCommonApi.java # zt-framework/zt-spring-boot-starter-biz-tenant/src/main/java/com/zt/plat/framework/tenant/core/context/DeptContextHolder.java # zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/permission/PermissionServiceImpl.java
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
<modules>
|
||||
<module>zt-module-system-api</module>
|
||||
<module>zt-module-system-server</module>
|
||||
<module>zt-module-system-server-app</module>
|
||||
</modules>
|
||||
<artifactId>zt-module-system</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.zt.plat.module.system.api.dept.dto;
|
||||
|
||||
import com.zt.plat.framework.common.enums.CommonStatusEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 公司部门推送消息 Response DTO
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Schema(description = "RPC 服务 - 部门推送消息 Response DTO")
|
||||
@Data
|
||||
public class DeptMsgRespDTO {
|
||||
|
||||
|
||||
/**
|
||||
* 主键编号
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 本系统部门 ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 外部系统标识
|
||||
*/
|
||||
private String systemCode;
|
||||
|
||||
/**
|
||||
* 外部系统组织编码
|
||||
*/
|
||||
private String externalDeptCode;
|
||||
|
||||
/**
|
||||
* 外部系统组织名称
|
||||
*/
|
||||
private String externalDeptName;
|
||||
|
||||
/**
|
||||
* 映射状态
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 是否发送消息
|
||||
*/
|
||||
private Integer isSendMsg;
|
||||
|
||||
}
|
||||
@@ -2,23 +2,27 @@ package com.zt.plat.module.system.api.esp;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.system.api.dept.dto.*;
|
||||
import com.zt.plat.module.system.api.esp.dto.EspDto;
|
||||
import com.zt.plat.module.system.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME)
|
||||
@Tag(name = "RPC 服务 - 部门")
|
||||
@Tag(name = "RPC 服务 - 部门推送消息")
|
||||
public interface EspApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/dept";
|
||||
String PREFIX = ApiConstants.PREFIX + "/dept-esp";
|
||||
|
||||
|
||||
@PostMapping(PREFIX + "/create")
|
||||
@Operation(summary = "新增部门")
|
||||
CommonResult<Long> createDept(@RequestBody DeptSaveReqDTO createReqVO);
|
||||
|
||||
|
||||
@PostMapping(PREFIX + "/pushMsg")
|
||||
@Operation(summary = "推送消息")
|
||||
CommonResult<List<EspDto>> pushMsg(@RequestBody DeptSaveReqDTO syncReqDTO);
|
||||
@Operation(summary = "查询部门消息")
|
||||
CommonResult<List<DeptMsgRespDTO>> selectDepMsg(@RequestBody DeptSaveReqDTO syncReqDTO);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.zt.plat.module.system.api.msg;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.system.api.sms.dto.log.SmsLogRespDTO;
|
||||
import com.zt.plat.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
|
||||
import com.zt.plat.module.system.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME)
|
||||
@Tag(name = "RPC 服务 - 消息发送")
|
||||
public interface MsgSendApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/msg/send";
|
||||
|
||||
@PostMapping(PREFIX + "/sendTextMsg")
|
||||
@Operation(summary = "发送企业微信文本消息", description = "在 mobile 为空时,使用 userId 加载对应 Admin 的手机号")
|
||||
CommonResult<Long> sendTextMsg(@Valid @RequestBody SmsSendSingleToUserReqDTO reqDTO);
|
||||
|
||||
@PostMapping(PREFIX + "/sendImageMsg")
|
||||
@Operation(summary = "发送企业微信图片消息", description = "在 mobile 为空时,使用 userId 加载对应 Member 的手机号")
|
||||
CommonResult<Long> sendImageMsg(@Valid @RequestBody SmsSendSingleToUserReqDTO reqDTO);
|
||||
|
||||
@GetMapping(PREFIX + "/sendVoiceMsg")
|
||||
@Operation(summary = "发送企业微信语音消息")
|
||||
CommonResult<SmsLogRespDTO> getSmsLog(@RequestParam("id") Long id);
|
||||
|
||||
@PostMapping(PREFIX + "/sendVideoMsg")
|
||||
@Operation(summary = "发送企业微信视频消息", description = "在 mobile 为空时,使用 userId 加载对应 Admin 的手机号")
|
||||
CommonResult<Long> sendVideoMsg(@Valid @RequestBody SmsSendSingleToUserReqDTO reqDTO);
|
||||
|
||||
@PostMapping(PREFIX + "/sendFileMsg")
|
||||
@Operation(summary = "发送企业微信文件消息", description = "在 mobile 为空时,使用 userId 加载对应 Member 的手机号")
|
||||
CommonResult<Long> sendFileMsg(@Valid @RequestBody SmsSendSingleToUserReqDTO reqDTO);
|
||||
|
||||
@GetMapping(PREFIX + "/sendTextCardMsg")
|
||||
@Operation(summary = "发送企业微信文本卡片消息")
|
||||
CommonResult<SmsLogRespDTO> sendTextCardMsg(@RequestParam("id") Long id);
|
||||
|
||||
@PostMapping(PREFIX + "/sendTextCardMsgPich01")
|
||||
@Operation(summary = "发送企业微信文本卡片消息 -物资存货智能管理 预警信息", description = "在 mobile 为空时,使用 userId 加载对应 Admin 的手机号")
|
||||
CommonResult<Long> sendTextCardMsgPich01(@Valid @RequestBody SmsSendSingleToUserReqDTO reqDTO);
|
||||
|
||||
@PostMapping(PREFIX + "/sendNewsMsg")
|
||||
@Operation(summary = "发送企业微信图文消息", description = "在 mobile 为空时,使用 userId 加载对应 Member 的手机号")
|
||||
CommonResult<Long> sendNewsMsg(@Valid @RequestBody SmsSendSingleToUserReqDTO reqDTO);
|
||||
|
||||
@GetMapping(PREFIX + "/sendMpNewsMsg")
|
||||
@Operation(summary = "发送企业微信图文消息(mpnews)")
|
||||
CommonResult<SmsLogRespDTO> sendMpNewsMsg(@RequestParam("id") Long id);
|
||||
|
||||
@PostMapping(PREFIX + "/sendMarkdownMsg")
|
||||
@Operation(summary = "发送企业微信小程序通知消息", description = "在 mobile 为空时,使用 userId 加载对应 Admin 的手机号")
|
||||
CommonResult<Long> sendMarkdownMsg(@Valid @RequestBody SmsSendSingleToUserReqDTO reqDTO);
|
||||
|
||||
@PostMapping(PREFIX + "/sendMiniProgramNoticeMsg")
|
||||
@Operation(summary = "发送企业微信图片消息", description = "在 mobile 为空时,使用 userId 加载对应 Member 的手机号")
|
||||
CommonResult<Long> sendMiniProgramNoticeMsg(@Valid @RequestBody SmsSendSingleToUserReqDTO reqDTO);
|
||||
|
||||
@GetMapping(PREFIX + "/sendInteractiveTaskCardMsg")
|
||||
@Operation(summary = "发送企业微信任务卡片消息")
|
||||
CommonResult<SmsLogRespDTO> sendInteractiveTaskCardMsg(@RequestParam("id") Long id);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.zt.plat.module.system.api.sms.dto.code;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class User implements Serializable {
|
||||
/**
|
||||
* 返回码
|
||||
*/
|
||||
private Integer errcode;
|
||||
/**
|
||||
* 对返回码的文本描述内容
|
||||
*/
|
||||
private String errmsg;
|
||||
|
||||
/**
|
||||
* 成员UserID
|
||||
*/
|
||||
private String UserId;
|
||||
|
||||
/**
|
||||
* 手机设备号(由中铝集团在安装时随机生成,删除重装会改变,升级不受影响)
|
||||
*/
|
||||
private String DeviceId;
|
||||
|
||||
/**
|
||||
* 成员身份信息,2:超级管理员, 4:分级管理员,5:普通成员
|
||||
*/
|
||||
private Integer usertype;
|
||||
|
||||
|
||||
/**
|
||||
* 判断受否授权成功
|
||||
*
|
||||
* @return true-授权成功、false-授权失败
|
||||
*/
|
||||
public boolean isAuthorized() {
|
||||
return this.getErrcode() == 0;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import com.zt.plat.framework.common.validation.Mobile;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Schema(description = "RPC 服务 - 短信发送给 Admin 或者 Member 用户 Request DTO")
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.fhs.core.trans.vo.VO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -20,6 +21,12 @@ public class AdminUserRespDTO implements VO {
|
||||
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "工号", example = "A00123")
|
||||
private String workcode;
|
||||
|
||||
@Schema(description = "备注", example = "我是一个用户")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long tenantId;
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ public class ApiConstants {
|
||||
|
||||
/**
|
||||
* 服务名
|
||||
*
|
||||
* 注意,需要保证和 spring.application.name 保持一致
|
||||
*/
|
||||
public static final String NAME = "system-server";
|
||||
|
||||
@@ -108,6 +108,9 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode SMS_CHANNEL_DISABLE = new ErrorCode(1_002_011_001, "短信渠道不处于开启状态,不允许选择");
|
||||
ErrorCode SMS_CHANNEL_HAS_CHILDREN = new ErrorCode(1_002_011_002, "无法删除,该短信渠道还有短信模板");
|
||||
ErrorCode SMS_CHANNEL_BALANCE_UNSUPPORTED = new ErrorCode(1_002_011_003, "该短信渠道不支持余额查询");
|
||||
ErrorCode MSG_CHANNEL_NOT_EXISTS = new ErrorCode(1_002_011_004, "消息渠道不存在");
|
||||
|
||||
|
||||
|
||||
// ========== 短信模板 1-002-012-000 ==========
|
||||
ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_012_000, "短信模板不存在");
|
||||
@@ -122,6 +125,7 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_013_001, "模板参数({})缺失");
|
||||
ErrorCode SMS_SEND_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_013_002, "短信模板不存在");
|
||||
ErrorCode SMS_CALLBACK_SIGN_INVALID = new ErrorCode(1_002_013_100, "短信回调签名校验失败");
|
||||
ErrorCode MSG_CALLBACK_SIGN_INVALID = new ErrorCode(1_002_013_101, "消息回调签名校验失败");
|
||||
|
||||
// ========== 短信验证码 1-002-014-000 ==========
|
||||
ErrorCode SMS_CODE_NOT_FOUND = new ErrorCode(1_002_014_000, "验证码不存在");
|
||||
@@ -206,6 +210,8 @@ public interface ErrorCodeConstants {
|
||||
// ========== 用户与部门关系 1-002-029-000 ==========
|
||||
ErrorCode USER_DEPT_NOT_EXISTS = new ErrorCode(1_002_029_000, "用户与部门关系不存在");
|
||||
|
||||
ErrorCode USER_DEPT_SAVE_EXISTS = new ErrorCode(1_002_029_001, "插入用户部门失败");
|
||||
|
||||
// ========== 系统序列号分段明细 1-002-030-000 ==========
|
||||
ErrorCode SEQUENCE_DETAIL_NOT_EXISTS = new ErrorCode(1_002_030_000, "系统序列号分段明细不存在");
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre
|
||||
|
||||
## 创建目录,并使用它作为工作目录
|
||||
RUN mkdir -p /zt-module-system-server
|
||||
WORKDIR /zt-module-system-server
|
||||
RUN mkdir -p /zt-module-system-server-app
|
||||
WORKDIR /zt-module-system-server-app
|
||||
## 将后端项目的 Jar 文件,复制到镜像中
|
||||
COPY ./target/zt-module-system-server.jar app.jar
|
||||
COPY ./target/zt-module-system-server-app.jar app.jar
|
||||
|
||||
## 设置 TZ 时区
|
||||
## 设置 JAVA_OPTS 环境变量,可通过 docker run -e "JAVA_OPTS=" 进行覆盖
|
||||
48
zt-module-system/zt-module-system-server-app/pom.xml
Normal file
48
zt-module-system/zt-module-system-server-app/pom.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>zt-module-system</artifactId>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<artifactId>zt-module-system-server-app</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
system 模块启动器。
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-module-system-server</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
<!-- 设置构建的 jar 包名 -->
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<!-- 打包 -->
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal> <!-- 将引入的 jar 打入其中 -->
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -88,7 +88,7 @@
|
||||
</root>
|
||||
|
||||
<!--针对不同的业务路径,配置dao层的sql打印日志级别为DEBUG-->
|
||||
<logger name="com.zt.plat.module.system.dal.mysql" level="DEBUG" additivity="false">
|
||||
<logger name="com.zt.plat.module.infra.dal.mysql" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</logger>
|
||||
</springProfile>
|
||||
@@ -103,4 +103,8 @@
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
<!-- <logger name="com.zt.plat.module.system.dal" level="DEBUG" additivity="false">-->
|
||||
<!-- <appender-ref ref="STDOUT"/>-->
|
||||
<!-- </logger>-->
|
||||
|
||||
</configuration>
|
||||
@@ -200,26 +200,14 @@
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-text</artifactId>
|
||||
<version>1.13.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<!-- 设置构建的 jar 包名 -->
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<!-- 打包 -->
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal> <!-- 将引入的 jar 打入其中 -->
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -41,7 +41,7 @@ public class DatabusDeptProviderApiImpl implements DatabusDeptProviderApi {
|
||||
public CommonResult<CursorPageResult<DatabusDeptData>> getPageByCursor(CursorPageReqDTO reqDTO) {
|
||||
// 构建游标查询条件
|
||||
LambdaQueryWrapper<DeptDO> queryWrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
queryWrapper.eq(DeptDO::getDeptSource, 3);
|
||||
// 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId)
|
||||
if (!reqDTO.isFirstPage()) {
|
||||
queryWrapper.and(w -> w
|
||||
@@ -105,6 +105,7 @@ public class DatabusDeptProviderApiImpl implements DatabusDeptProviderApi {
|
||||
Long total = null;
|
||||
if (reqDTO.isFirstPage()) {
|
||||
LambdaQueryWrapper<DeptDO> countWrapper = new LambdaQueryWrapper<>();
|
||||
countWrapper.eq(DeptDO::getDeptSource, 3);
|
||||
if (reqDTO.getTenantId() != null) {
|
||||
countWrapper.eq(DeptDO::getTenantId, reqDTO.getTenantId());
|
||||
}
|
||||
@@ -175,6 +176,8 @@ public class DatabusDeptProviderApiImpl implements DatabusDeptProviderApi {
|
||||
@Override
|
||||
public CommonResult<Long> count(Long tenantId) {
|
||||
LambdaQueryWrapper<DeptDO> queryWrapper = new LambdaQueryWrapper<>();
|
||||
// ⚠️ 只统计 userSource = 3 的用户
|
||||
queryWrapper.eq(DeptDO::getDeptSource, 3);
|
||||
if (tenantId != null) {
|
||||
queryWrapper.eq(DeptDO::getTenantId, tenantId);
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi {
|
||||
// 构建游标查询条件
|
||||
LambdaQueryWrapper<AdminUserDO> queryWrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
// ⚠️ 只同步 userSource = 2 的用户
|
||||
queryWrapper.eq(AdminUserDO::getUserSource, 2);
|
||||
// ⚠️ 只同步 userSource = 3 的用户
|
||||
queryWrapper.eq(AdminUserDO::getUserSource, 3);
|
||||
|
||||
// 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId)
|
||||
if (!reqDTO.isFirstPage()) {
|
||||
@@ -103,8 +103,8 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi {
|
||||
Long total = null;
|
||||
if (reqDTO.isFirstPage()) {
|
||||
LambdaQueryWrapper<AdminUserDO> countWrapper = new LambdaQueryWrapper<>();
|
||||
// ⚠️ 只统计 userSource = 2 的用户
|
||||
countWrapper.eq(AdminUserDO::getUserSource, 2);
|
||||
// ⚠️ 只统计 userSource = 3 的用户
|
||||
countWrapper.eq(AdminUserDO::getUserSource, 3);
|
||||
if (reqDTO.getTenantId() != null) {
|
||||
countWrapper.eq(AdminUserDO::getTenantId, reqDTO.getTenantId());
|
||||
}
|
||||
@@ -148,8 +148,8 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi {
|
||||
@Override
|
||||
public CommonResult<Long> count(Long tenantId) {
|
||||
LambdaQueryWrapper<AdminUserDO> queryWrapper = new LambdaQueryWrapper<>();
|
||||
// ⚠️ 只统计 userSource = 2 的用户
|
||||
queryWrapper.eq(AdminUserDO::getUserSource, 2);
|
||||
// ⚠️ 只统计 userSource = 3 的用户
|
||||
queryWrapper.eq(AdminUserDO::getUserSource, 3);
|
||||
if (tenantId != null) {
|
||||
queryWrapper.eq(AdminUserDO::getTenantId, tenantId);
|
||||
}
|
||||
|
||||
@@ -2,15 +2,17 @@ package com.zt.plat.module.system.api.esp;
|
||||
|
||||
import com.zt.plat.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.util.object.ObjectUtils;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.module.system.api.dept.dto.DeptMsgRespDTO;
|
||||
import com.zt.plat.module.system.api.dept.dto.DeptSaveReqDTO;
|
||||
import com.zt.plat.module.system.api.esp.dto.EspDto;
|
||||
import com.zt.plat.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
|
||||
import com.zt.plat.module.system.service.dept.IEspService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController
|
||||
@Validated
|
||||
@@ -18,16 +20,26 @@ public class EspApiImpl implements EspApi {
|
||||
|
||||
|
||||
@Resource
|
||||
private IEspService deptService;
|
||||
private IEspService espService;
|
||||
|
||||
|
||||
@Override
|
||||
public CommonResult<List<EspDto>> pushMsg(DeptSaveReqDTO syncReqDTO)
|
||||
public CommonResult<Long> createDept(DeptSaveReqDTO createReqVO) {
|
||||
DeptSaveReqVO reqVO = BeanUtils.toBean(createReqVO, DeptSaveReqVO.class);
|
||||
Long deptId = espService.createDept(reqVO);
|
||||
return success(deptId);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CommonResult<List<DeptMsgRespDTO>> selectDepMsg(DeptSaveReqDTO syncReqDTO)
|
||||
{
|
||||
if(Objects.isNull(syncReqDTO) || null == syncReqDTO.getId())
|
||||
{
|
||||
return CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
|
||||
"ID不能为空");
|
||||
}
|
||||
return CommonResult.success(deptService.pushMsg(syncReqDTO));
|
||||
return espService.selectDepMsg(syncReqDTO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.zt.plat.module.system.api.msg;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.module.system.api.sms.dto.log.SmsLogRespDTO;
|
||||
import com.zt.plat.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
|
||||
import com.zt.plat.module.system.service.sms.SmsLogService;
|
||||
import com.zt.plat.module.system.service.sms.SmsSendService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController
|
||||
@Validated
|
||||
public class MsgSendApiImpl implements MsgSendApi {
|
||||
|
||||
@Resource
|
||||
private SmsSendService smsSendService;
|
||||
@Resource
|
||||
private SmsLogService smsLogService;
|
||||
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> sendTextMsg(SmsSendSingleToUserReqDTO reqDTO) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> sendImageMsg(SmsSendSingleToUserReqDTO reqDTO) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<SmsLogRespDTO> getSmsLog(Long id) {
|
||||
return success(BeanUtils.toBean(smsLogService.getSmsLog(id), SmsLogRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> sendVideoMsg(SmsSendSingleToUserReqDTO reqDTO) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> sendFileMsg(SmsSendSingleToUserReqDTO reqDTO) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<SmsLogRespDTO> sendTextCardMsg(Long id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> sendTextCardMsgPich01(SmsSendSingleToUserReqDTO reqDTO) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> sendNewsMsg(SmsSendSingleToUserReqDTO reqDTO) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<SmsLogRespDTO> sendMpNewsMsg(Long id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> sendMarkdownMsg(SmsSendSingleToUserReqDTO reqDTO) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> sendMiniProgramNoticeMsg(SmsSendSingleToUserReqDTO reqDTO) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<SmsLogRespDTO> sendInteractiveTaskCardMsg(Long id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import com.zt.plat.module.system.controller.admin.auth.vo.*;
|
||||
import com.zt.plat.module.system.convert.auth.AuthConvert;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.MenuDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.RoleDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.RoleMenuDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import com.zt.plat.module.system.enums.logger.LoginLogTypeEnum;
|
||||
import com.zt.plat.module.system.service.auth.AdminAuthService;
|
||||
@@ -33,7 +34,9 @@ import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
@@ -126,7 +129,18 @@ public class AuthController {
|
||||
// 1.3 获得菜单列表
|
||||
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
|
||||
List<MenuDO> menuList = menuService.getMenuList(menuIds);
|
||||
Set<RoleMenuDO> roleMenuList = permissionService.getByRoleIdAndMenuIds(roleIds, menuIds);
|
||||
Map<Long, RoleMenuDO> roleMenuMap = new HashMap<>(roleMenuList.size());
|
||||
for (RoleMenuDO roleMenu : roleMenuList) {
|
||||
roleMenuMap.put(roleMenu.getMenuId(), roleMenu);
|
||||
}
|
||||
menuList = menuService.filterDisableMenus(menuList);
|
||||
for (MenuDO menu : menuList) {
|
||||
RoleMenuDO roleMenu = roleMenuMap.get(menu.getId());
|
||||
if (roleMenu != null && roleMenu.getShowMenu() != null && !roleMenu.getShowMenu()) {
|
||||
menu.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 拼接结果返回
|
||||
return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
|
||||
|
||||
@@ -123,7 +123,7 @@ public class DeptController {
|
||||
|
||||
@GetMapping("/top-level-list")
|
||||
@Operation(summary = "获取当前用户可访问的顶级部门列表", description = "用于懒加载,返回当前用户所属部门的最顶层祖先部门,如果用户没有关联任何部门则返回空列表")
|
||||
@PreAuthorize("@ss.hasPermission('system:dept:query')")
|
||||
// @PreAuthorize("@ss.hasPermission('system:dept:query')")
|
||||
public CommonResult<List<DeptRespVO>> getTopLevelDeptList() {
|
||||
List<DeptDO> list = deptService.getTopLevelDeptList();
|
||||
return success(BeanUtils.toBean(list, DeptRespVO.class));
|
||||
|
||||
@@ -6,11 +6,13 @@ import com.zt.plat.framework.common.enums.CommonStatusEnum;
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.util.collection.CollectionUtils;
|
||||
import com.zt.plat.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleDataScopeReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleMenuItemReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleMenuReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.permission.vo.permission.PermissionAssignUserRoleReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.permission.vo.permission.PermissionUserSupervisionRespVO;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.MenuDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.RoleDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.RoleMenuDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import com.zt.plat.module.system.enums.permission.MenuTypeEnum;
|
||||
import com.zt.plat.module.system.service.permission.MenuService;
|
||||
@@ -57,8 +59,16 @@ public class PermissionController {
|
||||
@Parameter(name = "roleId", description = "角色编号", required = true)
|
||||
@GetMapping("/list-role-menus")
|
||||
@PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')")
|
||||
public CommonResult<Set<Long>> getRoleMenuList(Long roleId) {
|
||||
return success(permissionService.getRoleMenuListByRoleId(roleId));
|
||||
public CommonResult<Set<PermissionAssignRoleMenuItemReqVO>> getRoleMenuList(Long roleId) {
|
||||
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(roleId);
|
||||
Set<RoleMenuDO> menuList = permissionService.getByRoleIdAndMenuIds(Collections.singleton(roleId), menuIds);
|
||||
Set<PermissionAssignRoleMenuItemReqVO> result = menuList.stream().map(menu -> {
|
||||
PermissionAssignRoleMenuItemReqVO reqVO = new PermissionAssignRoleMenuItemReqVO();
|
||||
reqVO.setId(menu.getMenuId());
|
||||
reqVO.setShowMenu(menu.getShowMenu());
|
||||
return reqVO;
|
||||
}).collect(Collectors.toSet());
|
||||
return success(result);
|
||||
}
|
||||
|
||||
@PostMapping("/assign-role-menu")
|
||||
@@ -66,10 +76,13 @@ public class PermissionController {
|
||||
@PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')")
|
||||
public CommonResult<Boolean> assignRoleMenu(@Validated @RequestBody PermissionAssignRoleMenuReqVO reqVO) {
|
||||
// 开启多租户的情况下,需要过滤掉未开通的菜单
|
||||
tenantService.handleTenantMenu(menuIds -> reqVO.getMenuIds().removeIf(menuId -> !CollUtil.contains(menuIds, menuId)));
|
||||
tenantService.handleTenantMenu(menuIds -> reqVO.getMenus().removeIf(menu -> !CollUtil.contains(menuIds, menu.getId())));
|
||||
|
||||
// 执行菜单的分配
|
||||
permissionService.assignRoleMenu(reqVO.getRoleId(), reqVO.getMenuIds());
|
||||
permissionService.assignRoleMenu(reqVO.getRoleId(), reqVO.getMenus().stream().map(PermissionAssignRoleMenuItemReqVO::getId).collect(Collectors.toSet()));
|
||||
|
||||
// 更新菜单的显示状态
|
||||
permissionService.updateMenuDisplay(reqVO.getRoleId(), reqVO.getMenus());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.zt.plat.module.system.controller.admin.permission.vo.permission;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Schema(description = "管理后台 - 赋予角色菜单--菜单列表 Request VO")
|
||||
@Data
|
||||
public class PermissionAssignRoleMenuItemReqVO {
|
||||
|
||||
@Schema(description = "菜单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "菜单ID不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "是否显示菜单,默认显示(true)")
|
||||
private Boolean showMenu = true;
|
||||
|
||||
@Schema(description = "是否显示菜单按钮是否点击过(避免大量更新数据,只更新点击过的)")
|
||||
private Boolean showMenuChanged = false;
|
||||
|
||||
}
|
||||
@@ -15,7 +15,7 @@ public class PermissionAssignRoleMenuReqVO {
|
||||
@NotNull(message = "角色编号不能为空")
|
||||
private Long roleId;
|
||||
|
||||
@Schema(description = "菜单编号列表", example = "1,3,5")
|
||||
private Set<Long> menuIds = Collections.emptySet(); // 兜底
|
||||
@Schema(description = "菜单编列表")
|
||||
private Set<PermissionAssignRoleMenuItemReqVO> menus = Collections.emptySet(); // 兜底
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms;
|
||||
|
||||
import com.zt.plat.module.system.service.sms.SmsSendService;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Tag(name = "管理后台 - 消息回调")
|
||||
@RestController
|
||||
@RequestMapping("/system/sms/callback")
|
||||
public class MsgCallBackController {
|
||||
|
||||
|
||||
@Resource
|
||||
private SmsSendService smsSendService;
|
||||
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 短信回调")
|
||||
@@ -73,4 +74,13 @@ public class SmsCallbackController {
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/zle")
|
||||
@PermitAll
|
||||
@TenantIgnore
|
||||
@Operation(summary = "中铝e办短信的回调")
|
||||
public CommonResult<Boolean> receiveZleSmsStatus(@RequestBody String requestBody) throws Throwable {
|
||||
smsSendService.receiveSmsStatus(SmsChannelEnum.ZLE.getCode(), requestBody);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,11 +6,10 @@ import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.framework.excel.core.util.ExcelUtils;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.template.SmsTemplateRespVO;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.template.SmsTemplateSaveReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.template.SmsTemplateSendReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.msg.TextMessage;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.template.*;
|
||||
import com.zt.plat.module.system.dal.dataobject.sms.SmsTemplateDO;
|
||||
import com.zt.plat.module.system.service.msg.ISendMsgService;
|
||||
import com.zt.plat.module.system.service.sms.SmsSendService;
|
||||
import com.zt.plat.module.system.service.sms.SmsTemplateService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -19,13 +18,13 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static com.zt.plat.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
||||
import static com.zt.plat.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 短信模板")
|
||||
@@ -37,6 +36,8 @@ public class SmsTemplateController {
|
||||
private SmsTemplateService smsTemplateService;
|
||||
@Resource
|
||||
private SmsSendService smsSendService;
|
||||
@Resource
|
||||
private ISendMsgService sendMsgService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建短信模板")
|
||||
@@ -100,4 +101,18 @@ public class SmsTemplateController {
|
||||
sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
|
||||
}
|
||||
|
||||
@PostMapping("/send-msg")
|
||||
@Operation(summary = "发送消息")
|
||||
@PreAuthorize("@ss.hasPermission('system:sms-template:send-msg')")
|
||||
public CommonResult<Object> sendMsg(@Valid @RequestBody MsgTemplateSendReqVO sendReqVO,TextMessage textMessage) throws Exception{
|
||||
|
||||
String msgtype = textMessage.getMsgtype();
|
||||
if (StringUtils.isBlank(msgtype)){
|
||||
return CommonResult.error(BAD_REQUEST.getCode(), String.format("请求参数缺失:%s",msgtype));
|
||||
}
|
||||
//发送消息到MQ
|
||||
CommonResult<Object> objectCommonResult = sendMsgService.sendTextMsg(sendReqVO,textMessage);
|
||||
return success(objectCommonResult);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 企业微信消息发送对象父类
|
||||
*
|
||||
* @author dongqiang.hao
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class BaseMessage implements Serializable {
|
||||
|
||||
/**
|
||||
* 指定接收消息的成员,成员ID列表(多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为”@all”,则向该企业应用的全部成员发送
|
||||
*/
|
||||
private String touser;
|
||||
/**
|
||||
* 指定接收消息的部门,部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为”@all”时忽略本参数
|
||||
*/
|
||||
private String toparty;
|
||||
/**
|
||||
* 指定接收消息的标签,标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为”@all”时忽略本参数
|
||||
*/
|
||||
private String totag;
|
||||
/**
|
||||
* 企业应用的id,整型。企业内部开发,可在应用的设置页面查看;第三方服务商,可通过接口 获取企业授权信息 获取该参数值
|
||||
*/
|
||||
private String agentid;
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
private String msgtype;
|
||||
/**
|
||||
* 发送消息的自建应用类型
|
||||
*/
|
||||
private String appType;
|
||||
/**
|
||||
* 表示是否开启重复消息检查,0表示否,1表示是,默认0
|
||||
*/
|
||||
private Integer enable_duplicate_check = 0;
|
||||
/**
|
||||
* 表示是否重复消息检查的时间间隔,默认1800s,最大不超过4小时
|
||||
*/
|
||||
private Integer duplicate_check_interval;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 任务卡片消息按钮对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
public class Btn implements Serializable {
|
||||
|
||||
/**
|
||||
* 按钮key值,用户点击后,会产生任务卡片回调事件,回调事件会带上该key值,只能由数字、字母和“_-@”组成,最长支持128字节
|
||||
*/
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* 按钮名称,最长支持18个字节,超过则截断
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 按钮字体颜色,可选“red”或者“blue”,默认为“blue”
|
||||
*/
|
||||
private String color;
|
||||
|
||||
/**
|
||||
* 按钮字体是否加粗,默认false
|
||||
*/
|
||||
private Boolean is_bold;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 小程序通知消息内容元素对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
public class ContentItem implements Serializable {
|
||||
/**
|
||||
* 元素对象键值,长度10个汉字以内
|
||||
*/
|
||||
private String key;
|
||||
/**
|
||||
* 元素对象值,长度30个汉字以内(支持id转译)
|
||||
*/
|
||||
private String value;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.WxMsgTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
/**
|
||||
* 企业微信文件消息发送对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class FileMessage extends BaseMessage {
|
||||
/**
|
||||
* 消息类型,此时固定为:file
|
||||
*/
|
||||
private final String msgtype = WxMsgTypeConstant.FILE.getCode();
|
||||
|
||||
/**
|
||||
* 企业微信文件消息体对象
|
||||
*/
|
||||
private Media file = new Media();
|
||||
|
||||
/**
|
||||
* 表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0
|
||||
*/
|
||||
private Integer safe = 0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.WxMsgTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 企业微信图片消息发送对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class ImageMessage extends BaseMessage {
|
||||
/**
|
||||
* 消息类型,此时固定为:image
|
||||
*/
|
||||
private final String msgtype = WxMsgTypeConstant.IMAGE.getCode();
|
||||
|
||||
/**
|
||||
* 企业微信图片消息体对象
|
||||
*/
|
||||
private Media image = new Media();
|
||||
|
||||
/**
|
||||
* 表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0
|
||||
*/
|
||||
private Integer safe = 0;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
/**
|
||||
* 企业微信任务卡片消息体对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
public class InteractiveTaskCard implements Serializable {
|
||||
|
||||
/**
|
||||
* 标题,不超过128个字节,超过会自动截断(支持id转译)
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 描述,不超过512个字节,超过会自动截断(支持id转译)
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 点击后跳转的链接。最长2048字节,请确保包含了协议头(http/https)
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 任务id,同一个应用发送的任务卡片消息的任务id不能重复,只能由数字、字母和“_-@”组成,最长支持128字节
|
||||
*/
|
||||
private String task_id;
|
||||
|
||||
/**
|
||||
* 按钮列表,按钮个数为1~2个。
|
||||
*/
|
||||
private List<Btn> btn = new ArrayList<>();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.WxMsgTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
/**
|
||||
* 企业微信任务卡片消息发送对象
|
||||
* 仅企业微信3.1.6及以上版本支持
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class InteractiveTaskCardMessage extends BaseMessage {
|
||||
/**
|
||||
* 消息类型,此时固定为:interactive_taskcard
|
||||
*/
|
||||
private final String msgtype = WxMsgTypeConstant.INTERACTIVE_TASKCARD.getCode();
|
||||
/**
|
||||
* 任务卡片消息体对象,
|
||||
*/
|
||||
private InteractiveTaskCard interactive_taskcard = new InteractiveTaskCard();
|
||||
/**
|
||||
* 表示是否开启id转译,0表示否,1表示是,默认0。仅第三方应用需要用到,企业自建应用可以忽略。
|
||||
*/
|
||||
private Integer enable_id_trans = 0;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
/**
|
||||
* 企业微信markdown内容消息体对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
public class Markdown implements Serializable {
|
||||
|
||||
/**
|
||||
* markdown内容,最长不超过2048个字节,必须是utf8编码
|
||||
*/
|
||||
private String content;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.WxMsgTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
/**
|
||||
* 企业微信markdown消息发送对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class MarkdownMessage extends BaseMessage {
|
||||
/**
|
||||
* 消息类型,此时固定为:markdown
|
||||
*/
|
||||
private final String msgtype = WxMsgTypeConstant.MARKDOWN.getCode();
|
||||
/**
|
||||
* markdown消息内容对象,
|
||||
*/
|
||||
private Markdown markdown = new Markdown();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
/**
|
||||
* 企业微信媒体消息体对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
public class Media implements Serializable {
|
||||
/**
|
||||
* 文件上传时,企业微信服务器读取文件流的name
|
||||
*/
|
||||
public static final String MEDIA_NAME = "media";
|
||||
/**
|
||||
* 图片、语音、视频媒体文件id,可以调用上传临时素材接口获取
|
||||
*/
|
||||
private String media_id;
|
||||
/**
|
||||
* 视频消息的标题,不超过128个字节,超过会自动截断(视频消息)
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 视频消息的描述,不超过512个字节,超过会自动截断(视频消息)
|
||||
*/
|
||||
private String description;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
/**
|
||||
* 企业微信图文消息体对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
public class MiniProgramNotice implements Serializable {
|
||||
/**
|
||||
* 小程序appid,必须是与当前应用关联的小程序
|
||||
*/
|
||||
private String appid;
|
||||
|
||||
/**
|
||||
* 点击消息卡片后的小程序页面,仅限本小程序内的页面。该字段不填则消息点击后不跳转。
|
||||
*/
|
||||
private String page;
|
||||
|
||||
/**
|
||||
* 消息标题,长度限制4-12个汉字(支持id转译)
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 消息描述,长度限制4-12个汉字(支持id转译)
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 是否放大第一个content_item
|
||||
*/
|
||||
private String emphasis_first_item;
|
||||
|
||||
/**
|
||||
* 消息内容键值对,最多允许10个item
|
||||
*/
|
||||
private List<ContentItem> content_item = new ArrayList<>();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.WxMsgTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
/**
|
||||
* 企业微信小程序通知消息发送对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class MiniProgramNoticeMessage extends BaseMessage {
|
||||
/**
|
||||
* 消息类型,此时固定为:miniprogram_notice
|
||||
*/
|
||||
private final String msgtype = WxMsgTypeConstant.MINIPROGRAM_NOTICE.getCode();
|
||||
/**
|
||||
* 小程序通知消息内容对象,
|
||||
*/
|
||||
private MiniProgramNotice miniprogram_notice = new MiniProgramNotice();
|
||||
/**
|
||||
* 表示是否开启id转译,0表示否,1表示是,默认0。仅第三方应用需要用到,企业自建应用可以忽略。
|
||||
*/
|
||||
private Integer enable_id_trans = 0;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import com.zt.plat.module.system.framework.sms.core.client.dto.msg.MpNews;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.WxMsgTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
/**
|
||||
* 企业微信图文消息发送对象(文件存储在企业微信)
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class MpNewsMessage extends BaseMessage {
|
||||
/**
|
||||
* 消息类型,此时固定为:mpnews
|
||||
*/
|
||||
private final String msgtype = WxMsgTypeConstant.MPNEWS.getCode();
|
||||
|
||||
/**
|
||||
* 企业微信图文消息体对象
|
||||
*/
|
||||
private MpNews mpnews = new MpNews();
|
||||
|
||||
/**
|
||||
* 表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0
|
||||
*/
|
||||
private Integer safe = 0;
|
||||
|
||||
/**
|
||||
* 表示是否开启id转译,0表示否,1表示是,默认0。仅第三方应用需要用到,企业自建应用可以忽略。
|
||||
*/
|
||||
private Integer enable_id_trans = 0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import com.zt.plat.module.system.framework.sms.core.client.dto.msg.News;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.WxMsgTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
/**
|
||||
* 企业微信图文消息发送对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class NewsMessage extends BaseMessage {
|
||||
/**
|
||||
* 消息类型,此时固定为:news
|
||||
*/
|
||||
private final String msgtype = WxMsgTypeConstant.NEWS.getCode();
|
||||
|
||||
/**
|
||||
* 企业微信图文消息体对象
|
||||
*/
|
||||
private News news = new News();
|
||||
|
||||
/**
|
||||
* 表示是否开启id转译,0表示否,1表示是,默认0。仅第三方应用需要用到,企业自建应用可以忽略。
|
||||
*/
|
||||
private Integer enable_id_trans = 0;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import com.zt.plat.module.system.util.StringSolveUtils;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
/**
|
||||
* 企业微信文本消息体对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
public class Text implements Serializable {
|
||||
|
||||
/**
|
||||
* 点击事件消息模板
|
||||
*/
|
||||
public static final String URL_CONTENT_TEMPLATE = "<a href=\"${url}\">${content}</a>";
|
||||
|
||||
/**
|
||||
* 消息内容,最长不超过2048个字节,超过将截断(支持id转译)
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 消息点击url地址(自定义属性)
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 构建点击事件消息模板
|
||||
*/
|
||||
public void buildUrlContent() {
|
||||
if (StringUtils.isNotBlank(this.getUrl())) {
|
||||
Map<String, Object> substituteMap = new HashMap<>(2);
|
||||
substituteMap.put("url", this.getUrl());
|
||||
substituteMap.put("content", this.getContent());
|
||||
this.setContent(StringSolveUtils.placeholderReplace(URL_CONTENT_TEMPLATE, substituteMap));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import com.zt.plat.module.system.framework.sms.core.client.dto.msg.TextCard;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.WxMsgTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
/**
|
||||
* 企业微信文本卡片消息发送对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class TextCardMessage extends BaseMessage {
|
||||
/**
|
||||
* 消息类型,此时固定为:textcard
|
||||
*/
|
||||
private final String msgtype = WxMsgTypeConstant.TEXTCARD.getCode();
|
||||
/**
|
||||
* 消息内容对象
|
||||
*/
|
||||
private TextCard textcard = new TextCard();
|
||||
/**
|
||||
* 表示是否开启id转译,0表示否,1表示是,默认0。仅第三方应用需要用到,企业自建应用可以忽略。
|
||||
*/
|
||||
private Integer enable_id_trans = 0;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.WxMsgTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
/**
|
||||
* 企业微信文本消息发送对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class TextMessage extends BaseMessage {
|
||||
/**
|
||||
* 消息类型,此时固定为:text
|
||||
*/
|
||||
private final String msgtype = WxMsgTypeConstant.TEXT.getCode();
|
||||
/**
|
||||
* 消息内容对象,其中text参数的content字段可以支持换行、以及A标签,即可打开自定义的网页(可参考以上示例代码)(注意:换行符请用转义过的\n)
|
||||
*/
|
||||
private Text text = new Text();
|
||||
/**
|
||||
* 表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0
|
||||
*/
|
||||
private Integer safe = 0;
|
||||
/**
|
||||
* 表示是否开启id转译,0表示否,1表示是,默认0。仅第三方应用需要用到,企业自建应用可以忽略。
|
||||
*/
|
||||
private Integer enable_id_trans = 0;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.WxMsgTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
/**
|
||||
* 企业微信视频消息发送对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class VideoMessage extends BaseMessage {
|
||||
/**
|
||||
* 消息类型,此时固定为:video
|
||||
*/
|
||||
private final String msgtype = WxMsgTypeConstant.VIDEO.getCode();
|
||||
|
||||
/**
|
||||
* 企业微信视频消息体对象
|
||||
*/
|
||||
private Media video = new Media();
|
||||
|
||||
/**
|
||||
* 表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0
|
||||
*/
|
||||
private Integer safe = 0;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.msg;
|
||||
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.WxMsgTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
/**
|
||||
* 企业微信语音消息发送对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class VoiceMessage extends BaseMessage {
|
||||
/**
|
||||
* 消息类型,此时固定为:voice
|
||||
*/
|
||||
private final String msgtype = WxMsgTypeConstant.VOICE.getCode();
|
||||
|
||||
/**
|
||||
* 企业微信语音消息体对象
|
||||
*/
|
||||
private Media voice = new Media();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.zt.plat.module.system.controller.admin.sms.vo.template;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.Map;
|
||||
|
||||
@Schema(description = "管理后台 - 短信模板的发送 Request VO")
|
||||
@Data
|
||||
public class MsgTemplateSendReqVO {
|
||||
|
||||
/* @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300")
|
||||
@NotNull(message = "手机号不能为空")
|
||||
private String mobile;*/
|
||||
|
||||
@Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01")
|
||||
@NotNull(message = "模板编码不能为空")
|
||||
private String templateCode;
|
||||
|
||||
@Schema(description = "模板参数")
|
||||
private Map<String, Object> templateParams;
|
||||
|
||||
@Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01")
|
||||
@NotNull(message = "用户ID不能为空")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户属性", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01")
|
||||
@NotNull(message = "用户属性不能为空")
|
||||
private Integer userType;
|
||||
|
||||
}
|
||||
@@ -58,6 +58,13 @@ public class UserRespVO{
|
||||
@DictFormat(DictTypeConstants.USER_SEX)
|
||||
private Integer sex;
|
||||
|
||||
@Schema(description = "用户来源,参见 UserSourceEnum 枚举类", example = "1")
|
||||
private Integer userSource;
|
||||
|
||||
@Schema(description = "用户来源标签", example = "外部用户")
|
||||
@ExcelProperty("用户来源")
|
||||
private String userSourceLabel;
|
||||
|
||||
@Schema(description = "用户头像", example = "123456789")
|
||||
private String avatar;
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ public class UserSaveReqVO {
|
||||
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "zt")
|
||||
@NotBlank(message = "用户账号不能为空")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9]+$", message = "用户账号由 数字、字母 组成")
|
||||
@Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符")
|
||||
@Size(min = 1, max = 30, message = "用户账号长度为 1-30 个字符")
|
||||
@DiffLogField(name = "用户账号")
|
||||
private String username;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.zt.plat.module.system.dal.dataobject.dept.DeptDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.dept.PostDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.RoleDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import com.zt.plat.module.system.enums.user.UserSourceEnum;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@@ -32,6 +33,10 @@ public interface UserConvert {
|
||||
default UserRespVO convert(AdminUserDO user) {
|
||||
UserRespVO vo = BeanUtils.toBean(user, UserRespVO.class);
|
||||
vo.setAvatar(user.getAvatar());
|
||||
if (user.getUserSource() != null) {
|
||||
UserSourceEnum sourceEnum = UserSourceEnum.of(user.getUserSource());
|
||||
vo.setUserSourceLabel(sourceEnum != null ? sourceEnum.getName() : null);
|
||||
}
|
||||
if (user.getDeptIds() != null) {
|
||||
vo.setDeptIds(CollectionUtils.convertList(user.getDeptIds(), Long::longValue));
|
||||
}
|
||||
|
||||
@@ -74,14 +74,15 @@ public class DeptDO extends TenantBaseDO {
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 是否公司
|
||||
*/
|
||||
private Boolean isCompany;
|
||||
|
||||
/**
|
||||
* 是否集团
|
||||
*/
|
||||
private Boolean isGroup;
|
||||
/**
|
||||
* 是否公司
|
||||
*/
|
||||
private Boolean isCompany;
|
||||
|
||||
/**
|
||||
* 部门来源类型
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.zt.plat.module.system.dal.dataobject.msg;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.common.enums.CommonStatusEnum;
|
||||
import com.zt.plat.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.zt.plat.framework.tenant.core.aop.TenantIgnore;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.SmsChannelEnum;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 消息渠道 DO
|
||||
*
|
||||
* @author zzf
|
||||
* @since 2021-01-25
|
||||
*/
|
||||
@TableName(value = "system_sms_channel", autoResultMap = true)
|
||||
@KeySequence("system_sms_channel_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@TenantIgnore
|
||||
public class MsgChannelDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 渠道编号
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
/**
|
||||
* 短信签名
|
||||
*/
|
||||
private String signature;
|
||||
/**
|
||||
* 企业编号(epid)
|
||||
*/
|
||||
private String epid;
|
||||
/**
|
||||
* 渠道编码
|
||||
* 枚举 {@link SmsChannelEnum}
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* 启用状态
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 短信 API 的账号
|
||||
*/
|
||||
private String apiKey;
|
||||
/**
|
||||
* 短信 API 的密钥
|
||||
*/
|
||||
private String apiSecret;
|
||||
/**
|
||||
* 短信发送回调 URL
|
||||
*/
|
||||
private String callbackUrl;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.zt.plat.module.system.dal.dataobject.msg;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import com.zt.plat.framework.common.enums.CommonStatusEnum;
|
||||
import com.zt.plat.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.zt.plat.framework.tenant.core.aop.TenantIgnore;
|
||||
import com.zt.plat.module.system.dal.dataobject.sms.SmsChannelDO;
|
||||
import com.zt.plat.module.system.enums.sms.SmsTemplateTypeEnum;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息模板 DO
|
||||
* @author zzf
|
||||
* @since 2021-01-25
|
||||
*/
|
||||
@TableName(value = "system_sms_template", autoResultMap = true)
|
||||
@KeySequence("system_sms_template_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@TenantIgnore
|
||||
public class MsgTemplateDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 自增编号
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
// ========= 模板相关字段 =========
|
||||
|
||||
/**
|
||||
* 短信类型
|
||||
* 枚举 {@link SmsTemplateTypeEnum}
|
||||
*/
|
||||
private Integer type;
|
||||
/**
|
||||
* 启用状态
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 模板编码,保证唯一
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* 模板名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 模板内容
|
||||
* 内容的参数,使用 {} 包括,例如说 {name}
|
||||
*/
|
||||
private String content;
|
||||
/**
|
||||
* 参数数组(自动根据内容生成)
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<String> params;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 短信 API 的模板编号
|
||||
*/
|
||||
private String apiTemplateId;
|
||||
|
||||
// ========= 渠道相关字段 =========
|
||||
|
||||
/**
|
||||
* 短信渠道编号
|
||||
* 关联 {@link SmsChannelDO#getId()}
|
||||
*/
|
||||
private Long channelId;
|
||||
/**
|
||||
* 短信渠道编码
|
||||
* 冗余 {@link SmsChannelDO#getCode()}
|
||||
*/
|
||||
private String channelCode;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.zt.plat.module.system.dal.dataobject.msg;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.zt.plat.framework.tenant.core.aop.TenantIgnore;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import java.io.Serializable;
|
||||
/**
|
||||
* Activemq消息队列
|
||||
*
|
||||
* @author Dy
|
||||
* @since 2021-07-22
|
||||
*/
|
||||
@TableName(value = "sys_active_mq", autoResultMap = true)
|
||||
@KeySequence("sys_active_mq_seq")
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@TenantIgnore
|
||||
public class SysActiveMq implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "ID", type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
|
||||
@TableField("TITLE")
|
||||
private String title;
|
||||
|
||||
@TableField("JMS_TYPE")
|
||||
private String jmsType;
|
||||
|
||||
@TableField("CONTENT_TYPE")
|
||||
private String contentType;
|
||||
|
||||
@TableField("DATETIME")
|
||||
private String datetime;
|
||||
|
||||
@TableField("CONSUME_DATETIME")
|
||||
private String consumeDatetime;
|
||||
|
||||
@TableField("PUBLISHER")
|
||||
private String publisher;
|
||||
|
||||
@TableField("LISTENER_CLASS_NAME")
|
||||
private String listenerClassName;
|
||||
|
||||
@TableField("CONSUME_FLAG")
|
||||
private String consumeFlag;
|
||||
|
||||
@TableField("CONSUME_MESSAGE")
|
||||
private String consumeMessage;
|
||||
|
||||
@TableField("TEXT_CONTENT")
|
||||
private String textContent;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.zt.plat.module.system.dal.dataobject.msg;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.zt.plat.framework.tenant.core.aop.TenantIgnore;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import java.io.Serializable;
|
||||
/**
|
||||
* Activemq消息队列
|
||||
*
|
||||
* @author Dy
|
||||
* @since 2021-07-22
|
||||
*/
|
||||
@TableName(value = "sys_active_mq_log", autoResultMap = true)
|
||||
@KeySequence("sys_active_mq_log_seq")
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@TenantIgnore
|
||||
public class SysActiveMqLog implements Serializable {
|
||||
|
||||
|
||||
@TableId(value = "ID", type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
|
||||
@TableField("TITLE")
|
||||
private String title;
|
||||
|
||||
@TableField("JMS_TYPE")
|
||||
private String jmsType;
|
||||
|
||||
@TableField("CONTENT_TYPE")
|
||||
private String contentType;
|
||||
|
||||
@TableField("DATETIME")
|
||||
private String datetime;
|
||||
|
||||
@TableField("CONSUME_DATETIME")
|
||||
private String consumeDatetime;
|
||||
|
||||
@TableField("PUBLISHER")
|
||||
private String publisher;
|
||||
|
||||
@TableField("LISTENER_CLASS_NAME")
|
||||
private String listenerClassName;
|
||||
|
||||
@TableField("CONSUME_FLAG")
|
||||
private String consumeFlag;
|
||||
|
||||
@TableField("CONSUME_MESSAGE")
|
||||
private String consumeMessage;
|
||||
|
||||
@TableField("TEXT_CONTENT")
|
||||
private String textContent;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.zt.plat.module.system.dal.dataobject.msg;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.tenant.core.aop.TenantIgnore;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import java.io.Serializable;
|
||||
/**
|
||||
* 企业微信审核配置表
|
||||
* @author Dy
|
||||
* @since 2021-08-26
|
||||
*/
|
||||
@TableName(value = "sys_wx_audit_config", autoResultMap = true)
|
||||
@KeySequence("sys_wx_audit_config_seq")
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@TenantIgnore
|
||||
public class SysWxAuditConfig implements Serializable {
|
||||
|
||||
/**
|
||||
* 状态-生效
|
||||
*/
|
||||
public static final String STATE_ACTIVE = "active";
|
||||
/**
|
||||
* 状态-未生效
|
||||
*/
|
||||
public static final String STATE_INACTIVE = "inactive";
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
@TableField("APP_TYPE")
|
||||
private String appType;
|
||||
|
||||
@TableField("CORP_ID")
|
||||
private String corpId;
|
||||
|
||||
@TableField("CORP_SECRET")
|
||||
private String corpSecret;
|
||||
|
||||
@TableField("AGENT_ID")
|
||||
private String agentId;
|
||||
|
||||
@TableField("STATE")
|
||||
private String state;
|
||||
|
||||
@TableField("SORT_INDEX")
|
||||
private Integer sortIndex;
|
||||
|
||||
@TableField("EXT1")
|
||||
private String ext1;
|
||||
|
||||
@TableField("EXT2")
|
||||
private String ext2;
|
||||
|
||||
@TableField("EXT3")
|
||||
private String ext3;
|
||||
|
||||
@TableField("CREATE_USER")
|
||||
private String createUser;
|
||||
|
||||
@TableField("CREATE_USER_NAME")
|
||||
private String createUserName;
|
||||
|
||||
@TableField("ID")
|
||||
private Integer id;
|
||||
|
||||
@TableField("WX_CONTEXT_PATH")
|
||||
private String wxContextPath;
|
||||
|
||||
@TableField("HTTP_CONTEXT_PATH")
|
||||
private String httpContextPath;
|
||||
|
||||
@TableField("UPDATE_TIME")
|
||||
private String updateTime;
|
||||
|
||||
@TableField("CREATE_TIME")
|
||||
private String createTime;
|
||||
|
||||
@TableField("UPDATE_USER")
|
||||
private String updateUser;
|
||||
|
||||
@TableField("UPDATE_USER_NAME")
|
||||
private String updateUserName;
|
||||
|
||||
|
||||
}
|
||||
@@ -33,4 +33,9 @@ public class RoleMenuDO extends TenantBaseDO {
|
||||
*/
|
||||
private Long menuId;
|
||||
|
||||
/**
|
||||
* 是否显示菜单
|
||||
*/
|
||||
private Boolean showMenu = true;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.zt.plat.module.system.dal.mysql.msg;
|
||||
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.module.system.dal.dataobject.msg.SysActiveMqLog;
|
||||
import com.zt.plat.module.system.dal.dataobject.sms.SmsLogDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysActiveMqDao extends BaseMapperX<SysActiveMqLog> {
|
||||
|
||||
|
||||
}
|
||||
@@ -59,7 +59,7 @@ public interface UserDeptMapper extends BaseMapperX<UserDeptDO> {
|
||||
@Select("<script>" +
|
||||
"SELECT ud.* FROM system_user_dept ud " +
|
||||
"INNER JOIN system_users u ON ud.user_id = u.id " +
|
||||
"WHERE u.user_source = 2 " +
|
||||
"WHERE u.user_source = 3 " +
|
||||
"AND ud.deleted = 0 " +
|
||||
"<if test='tenantId != null'> AND ud.tenant_id = #{tenantId} </if>" +
|
||||
"<if test='cursorTime != null'>" +
|
||||
@@ -75,17 +75,17 @@ public interface UserDeptMapper extends BaseMapperX<UserDeptDO> {
|
||||
@Param("limit") Integer limit);
|
||||
|
||||
/**
|
||||
* 统计用户-部门关系数量(只统计 userSource = 2 的用户)
|
||||
* 统计用户-部门关系数量(只统计 userSource = 3 的用户)
|
||||
* @param tenantId 租户ID(可选)
|
||||
* @return 数量
|
||||
*/
|
||||
@Select("<script>" +
|
||||
"SELECT COUNT(*) FROM system_user_dept ud " +
|
||||
"INNER JOIN system_users u ON ud.user_id = u.id " +
|
||||
"WHERE u.user_source = 2 " +
|
||||
"WHERE u.user_source = 3 " +
|
||||
"AND ud.deleted = 0 " +
|
||||
"<if test='tenantId != null'> AND ud.tenant_id = #{tenantId} </if>" +
|
||||
"</script>")
|
||||
Long countWithUserSource(@Param("tenantId") Long tenantId);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.zt.plat.module.system.framework.sms.core.client.dto.msg;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
/**
|
||||
* 企业微信图文消息体对象
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Data
|
||||
public class Article implements Serializable {
|
||||
|
||||
/**
|
||||
* 标题,不超过128个字节,超过会自动截断(支持id转译)
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 描述,不超过512个字节,超过会自动截断(支持id转译)
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图 1068*455,小图150*150。
|
||||
*/
|
||||
private String url;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.zt.plat.module.system.framework.sms.core.client.dto.msg;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 企业微信图文消息体对象(文件存储在企业微信)
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
public class MpArticle implements Serializable {
|
||||
|
||||
/**
|
||||
* 标题,不超过128个字节,超过会自动截断(支持id转译)
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 图文消息缩略图的media_id, 可以通过素材管理接口获得。此处thumb_media_id即上传接口返回的media_id
|
||||
*/
|
||||
private String thumb_media_id;
|
||||
|
||||
/**
|
||||
* 图文消息的作者,不超过64个字节
|
||||
*/
|
||||
private String author;
|
||||
|
||||
/**
|
||||
* 图文消息点击“阅读原文”之后的页面链接
|
||||
*/
|
||||
private String content_source_url;
|
||||
|
||||
/**
|
||||
* 图文消息的内容,支持html标签,不超过666 K个字节(支持id转译)
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 图文消息的描述,不超过512个字节,超过会自动截断(支持id转译)
|
||||
*/
|
||||
private String digest;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.zt.plat.module.system.framework.sms.core.client.dto.msg;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 企业微信图文消息体对象(文件存储在企业微信)
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
public class MpNews implements Serializable {
|
||||
/**
|
||||
* 图文消息,一个图文消息支持1到8条图文
|
||||
*/
|
||||
private List<MpArticle> articles = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.zt.plat.module.system.framework.sms.core.client.dto.msg;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 企业微信图文消息体对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
public class News implements Serializable {
|
||||
/**
|
||||
* 图文消息,一个图文消息支持1到8条图文
|
||||
*/
|
||||
private List<Article> articles = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.zt.plat.module.system.framework.sms.core.client.dto.msg;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 企业微信文本卡片消息体对象
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class TextCard implements Serializable {
|
||||
|
||||
/**
|
||||
* 标题,不超过128个字节,超过会自动截断(支持id转译)
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 描述,不超过512个字节,超过会自动截断(支持id转译)
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 消息点击点击后跳转的链接。最长2048字节,请确保包含了协议头(http/https)
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 按钮文字。 默认为“详情”, 不超过4个文字,超过自动截断。
|
||||
*/
|
||||
private String btntxt;
|
||||
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import com.zt.plat.module.system.framework.sms.core.property.SmsChannelPropertie
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
@@ -83,6 +82,7 @@ public class SmsClientFactoryImpl implements SmsClientFactory {
|
||||
case QINIU: return new QiniuSmsClient(properties);
|
||||
// case CMCC_MAS: return new CmccMasSmsClient(properties);
|
||||
case HL95: return new Hl95SmsClient(properties);
|
||||
case ZLE: return new ZleSmsClient(properties);
|
||||
}
|
||||
// 创建失败,错误日志 + 抛出异常
|
||||
log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties);
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
package com.zt.plat.module.system.framework.sms.core.client.impl;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.zt.plat.framework.common.core.KeyValue;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.impl.extra.SmsBalanceClient;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
||||
import com.zt.plat.module.system.framework.sms.core.property.SmsChannelProperties;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
public class ZleSmsClient extends AbstractSmsClient implements SmsBalanceClient {
|
||||
|
||||
|
||||
private static final String SEND_URL = "https://api.sms.95ytx.com:9091/mxt/send";
|
||||
private static final String BALANCE_URL = "https://api.sms.95ytx.com:9091/mxt/getfee";
|
||||
private static final DateTimeFormatter STATUS_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
||||
|
||||
public ZleSmsClient(SmsChannelProperties properties) {
|
||||
super(properties);
|
||||
Assert.notEmpty(properties.getApiKey(), "用户名(apiKey) 不能为空");
|
||||
Assert.notEmpty(properties.getApiSecret(), "密码(apiSecret) 不能为空");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsSendRespDTO sendSms(Long logId, String mobile, String content, String apiTemplateId,
|
||||
List<KeyValue<String, Object>> templateParams) {
|
||||
Assert.notEmpty(properties.getEpid(), "中铝e办需要配置 epid");
|
||||
Assert.notEmpty(properties.getSignature(), "短信签名不能为空");
|
||||
String finalContent = appendSignatureIfMissing(content, properties.getSignature());
|
||||
String linkId = buildLinkId(logId);
|
||||
|
||||
Map<String, Object> form = new HashMap<>();
|
||||
form.put("username", properties.getApiKey());
|
||||
form.put("password", properties.getApiSecret());
|
||||
form.put("epid", properties.getEpid());
|
||||
form.put("phone", mobile);
|
||||
form.put("message", finalContent);
|
||||
form.put("linkid", linkId);
|
||||
// subcode 可为空
|
||||
|
||||
String resp;
|
||||
try (HttpResponse response = HttpRequest.post(SEND_URL)
|
||||
.form(form)
|
||||
.charset(StandardCharsets.UTF_8)
|
||||
.execute()) {
|
||||
resp = StrUtil.trim(response.body());
|
||||
}
|
||||
|
||||
boolean success = StrUtil.equals(resp, "00");
|
||||
return new SmsSendRespDTO()
|
||||
.setSuccess(success)
|
||||
.setApiCode(resp)
|
||||
.setApiMsg(resp)
|
||||
.setApiRequestId(linkId)
|
||||
.setSerialNo(linkId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析短信状态
|
||||
* @param text 结果
|
||||
* @return List<SmsReceiveRespDTO>
|
||||
*/
|
||||
@Override
|
||||
public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
|
||||
JSONObject obj = JSONUtil.parseObj(text, false);
|
||||
String reportCode = obj.getStr("FReportCode");
|
||||
String linkId = obj.getStr("FLinkID");
|
||||
LocalDateTime deliverTime = parseDeliverTime(obj.getStr("FDeliverTime"));
|
||||
String mobile = obj.getStr("FDestAddr");
|
||||
boolean success = StrUtil.equalsIgnoreCase(reportCode, "DELIVRD") || StrUtil.equals(reportCode, "0");
|
||||
Long logId = parseLongSafely(linkId);
|
||||
|
||||
SmsReceiveRespDTO dto = new SmsReceiveRespDTO()
|
||||
.setSuccess(success)
|
||||
.setErrorCode(reportCode)
|
||||
.setErrorMsg(reportCode)
|
||||
.setMobile(mobile)
|
||||
.setReceiveTime(deliverTime)
|
||||
.setSerialNo(linkId)
|
||||
.setLogId(logId);
|
||||
return Collections.singletonList(dto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) {
|
||||
// 中铝e办无模板审核接口,直接返回可用
|
||||
return new SmsTemplateRespDTO()
|
||||
.setId(apiTemplateId)
|
||||
.setContent(apiTemplateId)
|
||||
.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询余额
|
||||
* @return Integer
|
||||
*/
|
||||
@Override
|
||||
public Integer queryBalance() {
|
||||
Assert.notEmpty(properties.getEpid(), "中铝e办需要配置 epid");
|
||||
Map<String, Object> form = MapUtil.<String, Object>builder()
|
||||
.put("username", properties.getApiKey())
|
||||
.put("password", properties.getApiSecret())
|
||||
.put("epid", properties.getEpid())
|
||||
.build();
|
||||
String resp;
|
||||
try (HttpResponse response = HttpRequest.get(BALANCE_URL)
|
||||
.form(form)
|
||||
.charset(StandardCharsets.UTF_8)
|
||||
.execute()) {
|
||||
if (response.getStatus() != HttpURLConnection.HTTP_OK) {
|
||||
throw new IllegalStateException("余额查询失败,HTTP 状态码:" + response.getStatus());
|
||||
}
|
||||
resp = StrUtil.trim(response.body());
|
||||
}
|
||||
if (!StrUtil.isNumeric(resp)) {
|
||||
throw new IllegalStateException("余额查询失败,返回值:" + resp);
|
||||
}
|
||||
return Integer.valueOf(resp);
|
||||
}
|
||||
|
||||
private static String appendSignatureIfMissing(String content, String signature) {
|
||||
if (StrUtil.isBlank(signature)) {
|
||||
return content;
|
||||
}
|
||||
String wrapped = StrUtil.startWithAny(signature, "【", "[") ? signature : "【" + signature + "】";
|
||||
return StrUtil.startWith(content, wrapped) ? content : wrapped + content;
|
||||
}
|
||||
|
||||
private static String buildLinkId(Long logId) {
|
||||
String raw = String.valueOf(logId);
|
||||
return raw.length() > 20 ? raw.substring(raw.length() - 20) : raw;
|
||||
}
|
||||
|
||||
private static LocalDateTime parseDeliverTime(String timeText) {
|
||||
if (StrUtil.isBlank(timeText)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return LocalDateTime.parse(timeText, STATUS_TIME_FORMATTER);
|
||||
} catch (Exception ex) {
|
||||
log.warn("[parseDeliverTime][无法解析时间:{}]", timeText, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Long parseLongSafely(String text) {
|
||||
try {
|
||||
return Long.parseLong(text);
|
||||
} catch (Exception ignore) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package com.zt.plat.module.system.framework.sms.core.enums;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
/**
|
||||
* 审核类型静态枚举类
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
@Component
|
||||
public class AuditConstants {
|
||||
|
||||
/**
|
||||
* 中铝E办驰宏数字化应用(企业微信)
|
||||
*/
|
||||
public static final String CHINALCO_ZLEB_CHSZH = "chinalco_zleb_chszh";
|
||||
|
||||
/**
|
||||
* 中铜阳光采购应用(企业微信)
|
||||
*/
|
||||
public static final String CHINALCO_SUNEPS = "chinalco_suneps";
|
||||
|
||||
|
||||
/**
|
||||
* token身份认证令牌
|
||||
*/
|
||||
public static final String TOKEN = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
/**
|
||||
* 企业微信审核页面加载配置代码集ID
|
||||
*/
|
||||
public static final String AUDIT_CODE_SET = "qywx.audit_dispatcher";
|
||||
|
||||
/**
|
||||
* 阳光采购企业微信审核回调地址集合映射
|
||||
*/
|
||||
public static final Map<String, String> REDIRECT_URL_MAPPING = new HashMap<>(1);
|
||||
/**
|
||||
* 企业微信审核回调地址-需要微信认证,使用时需要在前面添加微信请求uri
|
||||
*/
|
||||
public static final String REDIRECT_URL_AUTH = "/qywx/${appType}/index?appType=${appType}&approveType=${approveType}&processInstanceId=${processInstanceId}&taskId=${taskId}&companyCode=${companyCode}&businessId=${businessId}";
|
||||
/**
|
||||
* 企业微信审核回调地址-不需要微信认证,使用时需要在前面添加微信请求uri
|
||||
*/
|
||||
public static final String REDIRECT_URL = "/${appType}/index?appType=${appType}&approveType=${approveType}&processInstanceId=${processInstanceId}&taskId=${taskId}&companyCode=${companyCode}&businessId=${businessId}";
|
||||
|
||||
static {
|
||||
REDIRECT_URL_MAPPING.put("noAuth", REDIRECT_URL);
|
||||
REDIRECT_URL_MAPPING.put("auth", REDIRECT_URL_AUTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批类型
|
||||
*/
|
||||
public enum SunepsAuditType {
|
||||
|
||||
/**
|
||||
* 询价单审批
|
||||
*/
|
||||
REQUEST_AUDIT("requestAudit", "询价单审批"),
|
||||
/**
|
||||
* 会审会签审批
|
||||
*/
|
||||
RESULT_AUDIT("resultAudit", "会审会签审批"),
|
||||
/**
|
||||
* 流标审批
|
||||
*/
|
||||
FLOW_AUDIT("flowAudit", "流标审批"),
|
||||
/**
|
||||
* 谈判方案审批
|
||||
*/
|
||||
NEGO_PLAN("negoPlan", "谈判方案审批"),
|
||||
/**
|
||||
* 终止审批
|
||||
*/
|
||||
TERM_AUDIT("termAudit", "终止审批"),
|
||||
/**
|
||||
* 评标报告审批
|
||||
*/
|
||||
REQUEST_EVA_REPORT("requestEvaReport", "评标报告审批"),
|
||||
/**
|
||||
* 供应商注册
|
||||
*/
|
||||
SUPPLIER_REGISTER("supplierRegister", "供应商注册"),
|
||||
/**
|
||||
* 供应商自荐
|
||||
*/
|
||||
SUPPLIER_SELF("supplierSelf", "供应商自荐"),
|
||||
/**
|
||||
* 供应商基本信息变更
|
||||
*/
|
||||
SUPPLIER_BASE_INFO("supplierBaseInfo", "供应商基本信息变更"),
|
||||
/**
|
||||
* 供应商启用
|
||||
*/
|
||||
SUPPLIER_ENABLE("supplierEnable", "供应商启用"),
|
||||
/**
|
||||
* 供应商可供大类变更
|
||||
*/
|
||||
SUPPLIER_MATE_TYPE("supplierMateType", "供应商可供大类变更"),
|
||||
/**
|
||||
* 合格供应商变更
|
||||
*/
|
||||
SUPPLIER_CHANGE("supplierChange", "合格供应商变更"),
|
||||
/**
|
||||
* 特种供应商认证审批
|
||||
*/
|
||||
T_SUPP_AUDIT("TSuppAudit", "特种供应商认证审批"),
|
||||
/**
|
||||
* 审核消息卡片描述模型
|
||||
*/
|
||||
AUDIT_DESCRIPTION_FORMAT("<div class=\"gray\">${subTitle}</div> <div class=\"normal\">${description}</div> <div class=\"normal\">当前节点:${taskName}</div> <div class=\"highlight\">点击查看详细情况</div>", "审核消息卡片描述模型"),
|
||||
|
||||
/**
|
||||
* 审核回调url,使用时需要在前面添加微信请求uri
|
||||
*/
|
||||
REDIRECT_URL("/qywx/${appType}/index?appType=${appType}&approveType=${approveType}&processInstanceId=${processInstanceId}&taskId=${taskId}&companyCode=${companyCode}&businessId=${businessId}", "审核回调url");
|
||||
|
||||
/**
|
||||
* 消息全局键key-key
|
||||
*/
|
||||
public static final String CODE_KEY = "code";
|
||||
|
||||
/**
|
||||
* 消息全局值value-key
|
||||
*/
|
||||
public static final String MSG_KEY = "msg";
|
||||
|
||||
/**
|
||||
* 审核类型代码
|
||||
*/
|
||||
private final String code;
|
||||
/**
|
||||
* 审核类型说明
|
||||
*/
|
||||
private final String msg;
|
||||
|
||||
SunepsAuditType(String code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.zt.plat.module.system.framework.sms.core.enums;
|
||||
|
||||
/**
|
||||
* 消息ActiveMQ静态变量枚举
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
public enum JmsConstant {
|
||||
/**
|
||||
* 测试点对点消息队列,使用时需要添加环境前缀JmsProperties jmsProperties===>jmsProperties.getQueuePrefix()
|
||||
*/
|
||||
QUEUE_TEST("queue.test", "测试点对点消息队列"),
|
||||
/**
|
||||
* 测试主题消息队列,使用时需要添加环境前缀JmsProperties jmsProperties===>jmsProperties.getTopicPrefix()
|
||||
*/
|
||||
TOPIC_TEST("topic.test", "测试主题消息队列"),
|
||||
/**
|
||||
* 消息类型-队列
|
||||
*/
|
||||
JMS_TYPE_QUEUE("queue", "消息类型-队列"),
|
||||
/**
|
||||
* 消息类型-主题
|
||||
*/
|
||||
JMS_TYPE_TOPIC("topic", "消息类型-主题"),
|
||||
/**
|
||||
* 消息消费结果-成功
|
||||
*/
|
||||
CONSUME_SUCCESS("success", "消息消费结果-成功"),
|
||||
/**
|
||||
* 消息消费结果-失败
|
||||
*/
|
||||
CONSUME_FAILURE("failure", "消息消费结果-失败");
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
private final String code;
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
private final String msg;
|
||||
|
||||
JmsConstant(String code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ public enum SmsChannelEnum {
|
||||
QINIU("QINIU", "七牛云"),
|
||||
HL95("HL95", "鸿联九五"),
|
||||
// CMCC_MAS("CMCC_MAS", "中国移动云MAS"),
|
||||
ZLE("ZLE", "中铝e办"),
|
||||
;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.zt.plat.module.system.framework.sms.core.enums;
|
||||
|
||||
/**
|
||||
* 企业微信消息类型枚举类
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
public enum WxMsgTypeConstant {
|
||||
/**
|
||||
* 文本消息:其中text参数的content字段可以支持换行、以及A标签,即可打开自定义的网页(可参考以上示例代码)(注意:换行符请用转义过的\n)
|
||||
*/
|
||||
TEXT("text", "文本消息"),
|
||||
/**
|
||||
* 图片消息
|
||||
*/
|
||||
IMAGE("image", "图片消息"),
|
||||
/**
|
||||
* 语音消息
|
||||
*/
|
||||
VOICE("voice", "语音消息"),
|
||||
/**
|
||||
* 视频消息
|
||||
*/
|
||||
VIDEO("video", "视频消息"),
|
||||
/**
|
||||
* 文件消息
|
||||
*/
|
||||
FILE("file", "文件消息"),
|
||||
/**
|
||||
* 卡片消息的展现形式非常灵活,支持使用br标签或者空格来进行换行处理,也支持使用div标签来使用不同的字体颜色,目前内置了3种文字颜色:灰色(gray)、高亮(highlight)、默认黑色(normal),将其作为div标签的class属性即可,具体用法请参考上面的示例。
|
||||
*/
|
||||
TEXTCARD("textcard", "文本卡片消息"),
|
||||
/**
|
||||
* 图文消息
|
||||
*/
|
||||
NEWS("news", "图文消息"),
|
||||
/**
|
||||
* mpnews类型的图文消息,跟普通的图文消息一致,唯一的差异是图文内容存储在企业微信。多次发送mpnews,会被认为是不同的图文,阅读、点赞的统计会被分开计算。
|
||||
*/
|
||||
MPNEWS("mpnews", "图文消息(mpnews)"),
|
||||
/**
|
||||
* 目前仅支持markdown语法的子集,微工作台(原企业号)不支持展示markdown消息
|
||||
*/
|
||||
MARKDOWN("markdown", "markdown消息"),
|
||||
/**
|
||||
* 小程序通知消息
|
||||
* 小程序通知消息只允许绑定了小程序的应用发送,之前,消息会通过统一的会话【小程序通知】发送给用户。
|
||||
* 从2019年6月28日起,用户收到的小程序通知会出现在各个独立的应用中。
|
||||
* 不支持@all全员发送
|
||||
*/
|
||||
MINIPROGRAM_NOTICE("miniprogram_notice", "小程序通知消息"),
|
||||
/**
|
||||
* 任务卡片消息
|
||||
* 仅企业微信3.1.6及以上版本支持
|
||||
* 任务卡片消息的展现支持简单的markdown语法,详情请见附录支持的markdown语法 。
|
||||
* 要发送该类型的消息,应用必须配置好回调URL,详见配置应用回调,用户点击任务卡片的按钮后,企业微信会回调任务卡片事件到该URL,配置的URL按任务卡片更新消息协议返回数据即可。
|
||||
* 开发者可以通过更新任务卡片消息状态接口更新卡片状态。
|
||||
*/
|
||||
INTERACTIVE_TASKCARD("interactive_taskcard", "任务卡片消息");
|
||||
|
||||
/**
|
||||
* 类型key
|
||||
*/
|
||||
private final String code;
|
||||
/**
|
||||
* 类型说明
|
||||
*/
|
||||
private final String msg;
|
||||
|
||||
/**
|
||||
* 构造器
|
||||
*
|
||||
* @param code 类型
|
||||
* @param msg 说明
|
||||
*/
|
||||
WxMsgTypeConstant(String code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型
|
||||
*/
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取说明
|
||||
*/
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
package com.zt.plat.module.system.mq.consumer.msg;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.msg.TextCardMessage;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.dto.msg.TextCard;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.AuditConstants;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.JmsConstant;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.WxMsgTypeConstant;
|
||||
import com.zt.plat.module.system.mq.message.sms.SmsSendMessage;
|
||||
import com.zt.plat.module.system.service.msg.ISendWxMsgService;
|
||||
import com.zt.plat.module.system.service.msg.ISysRocketMqService;
|
||||
import com.zt.plat.module.system.util.StringSolveUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||
import org.apache.rocketmq.spring.core.RocketMQListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 中铝 e 办的消费者
|
||||
*
|
||||
* @author zzf
|
||||
*/
|
||||
@Component
|
||||
@RocketMQMessageListener(
|
||||
topic = SmsSendMessage.TOPIC,
|
||||
consumerGroup = SmsSendMessage.TOPIC + "_CONSUMER"
|
||||
)
|
||||
@Slf4j
|
||||
public class MsgSendConsumer implements RocketMQListener<MessageExt> {
|
||||
|
||||
|
||||
@Resource
|
||||
private ISysRocketMqService sysActiveMqService;
|
||||
|
||||
@Resource
|
||||
private ISendWxMsgService sendWxMsgService;
|
||||
|
||||
|
||||
@Override
|
||||
public void onMessage(MessageExt msg) {
|
||||
|
||||
log.info("中铝e办[onMessage][消息内容({})]", msg.toString());
|
||||
String msgId = msg.getMsgId();
|
||||
int reconsumeTimes = msg.getReconsumeTimes();
|
||||
String consumeMsg;
|
||||
try {
|
||||
|
||||
if (msg.getBody() == null || msg.getBody().length == 0){
|
||||
log.error("[onMessage][消息体为空 msgId={}]", msgId);
|
||||
return;
|
||||
}
|
||||
|
||||
String json = new String(msg.getBody(), StandardCharsets.UTF_8);
|
||||
JSONObject jsonObject = JSON.parseObject(json);
|
||||
String toUser = jsonObject.getString("touser"); // 企业微信接收者
|
||||
String userName = jsonObject.getString("userName"); // 用户名
|
||||
String userEname = jsonObject.getString("userEname"); // 英文名
|
||||
String userCname = jsonObject.getString("userCname"); // 中文名
|
||||
String desc = jsonObject.getString("description");
|
||||
// 校验接受用户
|
||||
if (StringUtils.isBlank(toUser)) {
|
||||
consumeMsg = "企业微信消息发送失败,用户【" + userEname + "-" + userCname + "】未绑定企业微信账号!";
|
||||
//TODO 添加文本消息
|
||||
sysActiveMqService.saveByTextMessage(this.getClass().getName(), msg, JmsConstant.JMS_TYPE_QUEUE.getCode(), JmsConstant.CONSUME_FAILURE.getCode(), consumeMsg);
|
||||
} else {
|
||||
String msgtype = jsonObject.getString("msgtype");
|
||||
// 文本卡片消息
|
||||
if (Objects.equals(msgtype, WxMsgTypeConstant.TEXTCARD.getCode())) {
|
||||
/* 构建审批回调url */
|
||||
String appType = jsonObject.getString("appType");
|
||||
String approveType = jsonObject.getString("approveType");
|
||||
String companyCode = jsonObject.getString("userCompanyCode");
|
||||
String taskId = jsonObject.getString("taskId");
|
||||
String processInstanceId = jsonObject.getString("processInstanceId");
|
||||
String businessId = jsonObject.getString("businessId");
|
||||
Map<String, Object> substituteMap = new HashMap<>(5);
|
||||
substituteMap.put("appType", appType.toLowerCase(Locale.ROOT));
|
||||
substituteMap.put("approveType", approveType);
|
||||
substituteMap.put("companyCode", companyCode);
|
||||
substituteMap.put("taskId", taskId);
|
||||
substituteMap.put("processInstanceId", processInstanceId);
|
||||
substituteMap.put("businessId", businessId);
|
||||
String redirectUrl = StringSolveUtils.placeholderReplace(AuditConstants.SunepsAuditType.REDIRECT_URL.getCode(), substituteMap);
|
||||
|
||||
/* 构建文本卡片消息 */
|
||||
String title = jsonObject.getString("title");
|
||||
String taskName = jsonObject.getString("taskName");
|
||||
String datetime = jsonObject.getString("datetime");
|
||||
String btnTxt = jsonObject.getString("btntxt");
|
||||
substituteMap.put("subTitle", datetime + "——" + userName);
|
||||
substituteMap.put("description", desc);
|
||||
substituteMap.put("taskName", taskName);
|
||||
String description = StringSolveUtils.placeholderReplace(AuditConstants.SunepsAuditType.AUDIT_DESCRIPTION_FORMAT.getCode(), substituteMap);
|
||||
TextCardMessage textCardMessage = new TextCardMessage();
|
||||
TextCard textCard = new TextCard();
|
||||
textCard.setTitle(title)
|
||||
.setDescription(description)
|
||||
.setUrl(redirectUrl);
|
||||
if (StringUtils.isNotBlank(btnTxt)) {
|
||||
textCard.setBtntxt(btnTxt);
|
||||
}
|
||||
textCardMessage.setTextcard(textCard).setAppType(appType).setTouser(toUser);
|
||||
//TODO 发送企业微信文本卡片消息
|
||||
sendWxMsgService.sendTextCardMsg(textCardMessage);
|
||||
consumeMsg = "企业微信消息发送成功,接收用户【" + userEname + "-" + msgtype + "】!";
|
||||
//TODO 保存文本卡片消息队列消费的消息信息
|
||||
sysActiveMqService.saveByTextMessage(this.getClass().getName(), msg, JmsConstant.JMS_TYPE_QUEUE.getCode(), JmsConstant.CONSUME_SUCCESS.getCode(), consumeMsg);
|
||||
}
|
||||
|
||||
// 文本消息
|
||||
if (Objects.equals(msgtype, WxMsgTypeConstant.FILE.getCode())) {
|
||||
/* 构建审批回调url */
|
||||
String appType = jsonObject.getString("appType");
|
||||
String approveType = jsonObject.getString("approveType");
|
||||
String companyCode = jsonObject.getString("userCompanyCode");
|
||||
String taskId = jsonObject.getString("taskId");
|
||||
String processInstanceId = jsonObject.getString("processInstanceId");
|
||||
String businessId = jsonObject.getString("businessId");
|
||||
Map<String, Object> substituteMap = new HashMap<>(5);
|
||||
substituteMap.put("appType", appType.toLowerCase(Locale.ROOT));
|
||||
substituteMap.put("approveType", approveType);
|
||||
substituteMap.put("companyCode", companyCode);
|
||||
substituteMap.put("taskId", taskId);
|
||||
substituteMap.put("processInstanceId", processInstanceId);
|
||||
substituteMap.put("businessId", businessId);
|
||||
String redirectUrl = StringSolveUtils.placeholderReplace(AuditConstants.SunepsAuditType.REDIRECT_URL.getCode(), substituteMap);
|
||||
|
||||
/* 构建文本消息 */
|
||||
String title = jsonObject.getString("title");
|
||||
String taskName = jsonObject.getString("taskName");
|
||||
String datetime = jsonObject.getString("datetime");
|
||||
String btnTxt = jsonObject.getString("btntxt");
|
||||
substituteMap.put("subTitle", datetime + "——" + userName);
|
||||
substituteMap.put("description", desc);
|
||||
substituteMap.put("taskName", taskName);
|
||||
String description = StringSolveUtils.placeholderReplace(AuditConstants.SunepsAuditType.AUDIT_DESCRIPTION_FORMAT.getCode(), substituteMap);
|
||||
TextCardMessage textCardMessage = new TextCardMessage();
|
||||
TextCard textCard = new TextCard();
|
||||
textCard.setTitle(title)
|
||||
.setDescription(description)
|
||||
.setUrl(redirectUrl);
|
||||
if (StringUtils.isNotBlank(btnTxt)) {
|
||||
textCard.setBtntxt(btnTxt);
|
||||
}
|
||||
textCardMessage.setTextcard(textCard).setAppType(appType).setTouser(toUser);
|
||||
//TODO 送企业微信文本卡片消息
|
||||
sendWxMsgService.sendTextCardMsg(textCardMessage);
|
||||
consumeMsg = "企业微信消息发送成功,接收用户【" + userEname + "-" + msgtype + "】!";
|
||||
//TODO 存文本卡片消息队列消费的消息信息
|
||||
sysActiveMqService.saveByTextMessage(this.getClass().getName(), msg, JmsConstant.JMS_TYPE_QUEUE.getCode(), JmsConstant.CONSUME_SUCCESS.getCode(), consumeMsg);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("消息发送失败!{}", e.getMessage(), e);
|
||||
try {
|
||||
// 重试时不重复保存队列消息
|
||||
if (reconsumeTimes>0) {
|
||||
sysActiveMqService.saveByTextMessage(this.getClass().getName(), msg, JmsConstant.JMS_TYPE_QUEUE.getCode(), JmsConstant.CONSUME_FAILURE.getCode(), e.getMessage());
|
||||
}
|
||||
} catch (Exception jmsException) {
|
||||
log.error("消息保存失败!{}", jmsException.getMessage(), jmsException);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.zt.plat.module.system.mq.message.msg;
|
||||
|
||||
import com.zt.plat.framework.common.core.KeyValue;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息发送消息
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Data
|
||||
public class MsgSendMessage {
|
||||
|
||||
public static final String TOPIC = "SMS_SEND_TOPIC";
|
||||
/**
|
||||
* 消息日志编号
|
||||
*/
|
||||
@NotNull(message = "短信日志编号不能为空")
|
||||
private Long logId;
|
||||
|
||||
/**
|
||||
* 消息内容(已按模板格式化后的文本)
|
||||
*/
|
||||
private String content;
|
||||
/**
|
||||
* 消息渠道编号
|
||||
*/
|
||||
@NotNull(message = "短信渠道编号不能为空")
|
||||
private Long channelId;
|
||||
/**
|
||||
* 消息 API 的模板编号
|
||||
*/
|
||||
@NotNull(message = "消息 API 的模板编号不能为空")
|
||||
private String apiTemplateId;
|
||||
/**
|
||||
* 短信模板参数
|
||||
*/
|
||||
private List<KeyValue<String, Object>> templateParams;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.zt.plat.module.system.mq.producer.msg;
|
||||
|
||||
import com.zt.plat.framework.common.core.KeyValue;
|
||||
import com.zt.plat.module.system.mq.message.sms.SmsSendMessage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Sms 短信相关消息的 Producer
|
||||
*
|
||||
* @author zzf
|
||||
* @since 2021/3/9 16:35
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MsgProducer {
|
||||
|
||||
@Resource
|
||||
private RocketMQTemplate rocketMQTemplate;
|
||||
|
||||
/**
|
||||
* 发送 {@link SmsSendMessage} 消息
|
||||
* @param logId 短信日志编号
|
||||
* @param channelId 渠道编号
|
||||
* @param apiTemplateId 短信模板编号
|
||||
* @param templateParams 短信模板参数
|
||||
*/
|
||||
public void sendMsg(Long logId, String content,
|
||||
Long channelId, String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
|
||||
SmsSendMessage message = new SmsSendMessage().setLogId(logId).setContent(content);
|
||||
message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams);
|
||||
rocketMQTemplate.syncSend(SmsSendMessage.TOPIC, message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +1,37 @@
|
||||
package com.zt.plat.module.system.service.dept;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.zt.plat.framework.common.enums.CommonStatusEnum;
|
||||
import com.zt.plat.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.module.system.api.dept.dto.DeptMsgRespDTO;
|
||||
import com.zt.plat.module.system.api.dept.dto.DeptSaveReqDTO;
|
||||
import com.zt.plat.module.system.api.esp.dto.EspDto;
|
||||
import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.EspPageReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.EspSaveRespVo;
|
||||
import com.zt.plat.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
|
||||
import com.zt.plat.module.system.dal.dataobject.dept.DeptDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.dept.DeptPushMsgDO;
|
||||
import com.zt.plat.module.system.dal.mysql.dept.DeptMapper;
|
||||
import com.zt.plat.module.system.dal.mysql.dept.EspMapper;
|
||||
import com.zt.plat.module.system.dal.redis.RedisKeyConstants;
|
||||
import com.zt.plat.module.system.enums.dept.DeptSourceEnum;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.seata.common.result.Result;
|
||||
import org.apache.seata.spring.annotation.GlobalTransactional;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
@@ -33,13 +44,31 @@ import static com.zt.plat.module.system.enums.ErrorCodeConstants.*;
|
||||
@Validated
|
||||
public class EspServiceImpl implements IEspService {
|
||||
|
||||
|
||||
@Resource
|
||||
private DeptExternalCodeService deptExternalCodeService;
|
||||
|
||||
@Resource
|
||||
private EspMapper espMapper;
|
||||
|
||||
@Resource
|
||||
private DeptMapper deptMapper;
|
||||
|
||||
@Resource
|
||||
private CacheManager cacheManager;
|
||||
|
||||
@Resource
|
||||
private com.zt.plat.module.system.mq.producer.databus.DatabusChangeProducer databusChangeProducer;
|
||||
|
||||
private static final String ROOT_CODE_PREFIX = "ZT";
|
||||
private static final String EXTERNAL_CODE_PREFIX = "CU";
|
||||
private static final int CODE_SEGMENT_LENGTH = 3;
|
||||
private static final int MAX_SEQUENCE = 999;
|
||||
private static final int BATCH_SIZE = 1000;
|
||||
private static final Comparator<DeptDO> DEPT_COMPARATOR = Comparator
|
||||
.comparing(DeptDO::getSort, Comparator.nullsLast(Comparator.naturalOrder()))
|
||||
.thenComparing(DeptDO::getId, Comparator.nullsLast(Comparator.naturalOrder()));
|
||||
|
||||
@Override
|
||||
@CacheEvict(cacheNames = RedisKeyConstants.DEPT_EXTERNAL_CODE_LIST, key = "#createReqVO.deptId", beforeInvocation = false)
|
||||
public Long createDeptPushMsg(EspSaveRespVo createReqVO) {
|
||||
@@ -103,12 +132,243 @@ public class EspServiceImpl implements IEspService {
|
||||
return espMapper.selectListByDeptId(deptId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EspDto> pushMsg(DeptSaveReqDTO syncReqDTO) {
|
||||
|
||||
return BeanUtils.toBean(espMapper.selectpushMsg(syncReqDTO), EspDto.class);
|
||||
@Override
|
||||
@GlobalTransactional(rollbackFor = Exception.class)
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST,
|
||||
allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存
|
||||
public Long createDept(DeptSaveReqVO createReqVO) {
|
||||
// 允许上级组织为空,视为顶级组织
|
||||
createReqVO.setParentId(normalizeParentId(createReqVO.getParentId()));
|
||||
// 创建时默认有效
|
||||
createReqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
// 默认部门来源:未指定时视为外部部门
|
||||
if (createReqVO.getDeptSource() == null) {
|
||||
createReqVO.setDeptSource(DeptSourceEnum.EXTERNAL.getSource());
|
||||
}
|
||||
// 校验父部门的有效性
|
||||
validateParentDept(null, createReqVO.getParentId());
|
||||
// 校验部门名的唯一性
|
||||
validateDeptNameUnique(null, createReqVO.getParentId(), createReqVO.getName());
|
||||
// 生成并校验部门编码(所有来源统一走生成逻辑,iWork 不再豁免)
|
||||
if (Boolean.TRUE.equals(createReqVO.getDelayCodeGeneration())) {
|
||||
createReqVO.setCode(null);
|
||||
} else {
|
||||
String resolvedCode = generateDeptCode(createReqVO.getParentId(), createReqVO.getDeptSource());
|
||||
validateDeptCodeUnique(null, resolvedCode);
|
||||
createReqVO.setCode(resolvedCode);
|
||||
}
|
||||
|
||||
// 插入部门
|
||||
DeptDO dept = BeanUtils.toBean(createReqVO, DeptDO.class);
|
||||
// 设置部门来源(前置已默认化,此处兜底)
|
||||
if (dept.getDeptSource() == null) {
|
||||
dept.setDeptSource(DeptSourceEnum.EXTERNAL.getSource());
|
||||
}
|
||||
int insert = deptMapper.insert(dept);
|
||||
if (insert == 0) {
|
||||
throw exception(USER_DEPT_SAVE_EXISTS);
|
||||
}
|
||||
// 外部编码映射
|
||||
upsertExternalMappingIfPresent(dept.getId(), createReqVO);
|
||||
// 发布部门创建事件
|
||||
databusChangeProducer.sendDeptCreatedMessage(dept);
|
||||
//推送消息
|
||||
DeptSaveReqDTO deptSaveReqDTO = new DeptSaveReqDTO();
|
||||
BeanUtils.copyProperties(dept,deptSaveReqDTO);
|
||||
return dept.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<DeptMsgRespDTO>> selectDepMsg(DeptSaveReqDTO syncReqDTO) {
|
||||
if (syncReqDTO == null) {
|
||||
return CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST);
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<DeptPushMsgDO> wrapper = new LambdaQueryWrapper<>();
|
||||
if(syncReqDTO.getId() != null){
|
||||
wrapper.eq(DeptPushMsgDO::getId, syncReqDTO.getId());
|
||||
}
|
||||
|
||||
List<DeptPushMsgDO> list = espMapper.selectList(wrapper);
|
||||
if (CollectionUtils.isEmpty(list)){
|
||||
return CommonResult.error(GlobalErrorCodeConstants.NOT_FOUND);
|
||||
}
|
||||
|
||||
ArrayList<DeptMsgRespDTO> lists = new ArrayList<>(list.size());
|
||||
for (DeptPushMsgDO deptPushMsgDO : list){
|
||||
DeptMsgRespDTO deptMsgRespDTO = new DeptMsgRespDTO();
|
||||
BeanUtils.copyProperties(deptPushMsgDO, deptMsgRespDTO);
|
||||
lists.add(deptMsgRespDTO);
|
||||
}
|
||||
return CommonResult.success(lists);
|
||||
}
|
||||
|
||||
private Long normalizeParentId(Long parentId) {
|
||||
return parentId == null ? DeptDO.PARENT_ID_ROOT : parentId;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void validateParentDept(Long id, Long parentId) {
|
||||
if (parentId == null || DeptDO.PARENT_ID_ROOT.equals(parentId)) {
|
||||
return;
|
||||
}
|
||||
// 1. 不能设置自己为父部门
|
||||
if (Objects.equals(id, parentId)) {
|
||||
throw exception(DEPT_PARENT_ERROR);
|
||||
}
|
||||
// 2. 父部门不存在
|
||||
DeptDO parentDept = deptMapper.selectById(parentId);
|
||||
if (parentDept == null) {
|
||||
return;
|
||||
}
|
||||
// 3. 递归校验父部门,如果父部门是自己的子部门,则报错,避免形成环路
|
||||
if (id == null) { // id 为空,说明新增,不需要考虑环路
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < Short.MAX_VALUE; i++) {
|
||||
// 3.1 校验环路
|
||||
parentId = parentDept.getParentId();
|
||||
if (Objects.equals(id, parentId)) {
|
||||
throw exception(DEPT_PARENT_IS_CHILD);
|
||||
}
|
||||
// 3.2 继续递归下一级父部门
|
||||
if (parentId == null || DeptDO.PARENT_ID_ROOT.equals(parentId)) {
|
||||
break;
|
||||
}
|
||||
parentDept = deptMapper.selectById(parentId);
|
||||
if (parentDept == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String generateDeptCode(Long parentId, Integer deptSource) {
|
||||
Long effectiveParentId = normalizeParentId(parentId);
|
||||
String prefix = resolveCodePrefix(effectiveParentId, deptSource);
|
||||
int nextSequence = determineNextSequence(effectiveParentId, prefix);
|
||||
assertSequenceRange(nextSequence);
|
||||
return prefix + formatSequence(nextSequence);
|
||||
}
|
||||
|
||||
|
||||
@VisibleForTesting
|
||||
void validateDeptNameUnique(Long id, Long parentId, String name) {
|
||||
Long effectiveParentId = normalizeParentId(parentId);
|
||||
if (Objects.equals(effectiveParentId, DeptDO.PARENT_ID_ROOT)) {
|
||||
return;
|
||||
}
|
||||
DeptDO dept = deptMapper.selectByParentIdAndName(effectiveParentId, name);
|
||||
if (dept == null) {
|
||||
return;
|
||||
}
|
||||
// 如果 id 为空,说明不用比较是否为相同 id 的部门
|
||||
if (id == null) {
|
||||
throw exception(DEPT_NAME_DUPLICATE);
|
||||
}
|
||||
if (ObjectUtil.notEqual(dept.getId(), id)) {
|
||||
throw exception(DEPT_NAME_DUPLICATE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@VisibleForTesting
|
||||
void validateDeptCodeUnique(Long id, String code) {
|
||||
if (StrUtil.isBlank(code)) {
|
||||
return;
|
||||
}
|
||||
DeptDO dept = deptMapper.selectByCode(code);
|
||||
if (dept == null) {
|
||||
return;
|
||||
}
|
||||
// 如果 id 为空,说明不用比较是否为相同 id 的部门
|
||||
if (id == null) {
|
||||
throw exception(DEPT_CODE_DUPLICATE);
|
||||
}
|
||||
if (ObjectUtil.notEqual(dept.getId(), id)) {
|
||||
throw exception(DEPT_CODE_DUPLICATE);
|
||||
}
|
||||
}
|
||||
|
||||
private void upsertExternalMappingIfPresent(Long deptId, DeptSaveReqVO reqVO) {
|
||||
String systemCode = StrUtil.trimToNull(reqVO.getExternalSystemCode());
|
||||
String externalCode = StrUtil.trimToNull(reqVO.getExternalDeptCode());
|
||||
if (StrUtil.hasEmpty(systemCode, externalCode) || deptId == null) {
|
||||
return;
|
||||
}
|
||||
String externalName = StrUtil.trimToNull(reqVO.getExternalDeptName());
|
||||
deptExternalCodeService.saveOrUpdateDeptExternalCode(deptId, systemCode, externalCode, externalName, reqVO.getStatus());
|
||||
}
|
||||
|
||||
|
||||
private String resolveCodePrefix(Long parentId, Integer deptSource) {
|
||||
boolean isExternal = Objects.equals(deptSource, DeptSourceEnum.EXTERNAL.getSource());
|
||||
if (DeptDO.PARENT_ID_ROOT.equals(parentId)) {
|
||||
return isExternal ? EXTERNAL_CODE_PREFIX : ROOT_CODE_PREFIX;
|
||||
}
|
||||
|
||||
DeptDO parentDept = deptMapper.selectById(parentId);
|
||||
if (parentDept == null || StrUtil.isBlank(parentDept.getCode())) {
|
||||
return isExternal ? EXTERNAL_CODE_PREFIX : ROOT_CODE_PREFIX;
|
||||
}
|
||||
|
||||
String parentCode = parentDept.getCode();
|
||||
if (isExternal) {
|
||||
if (parentCode.startsWith(EXTERNAL_CODE_PREFIX)) {
|
||||
return parentCode;
|
||||
}
|
||||
if (parentCode.startsWith(ROOT_CODE_PREFIX)) {
|
||||
return EXTERNAL_CODE_PREFIX + parentCode.substring(ROOT_CODE_PREFIX.length());
|
||||
}
|
||||
return EXTERNAL_CODE_PREFIX;
|
||||
}
|
||||
return parentCode;
|
||||
}
|
||||
|
||||
|
||||
private int determineNextSequence(Long parentId, String prefix) {
|
||||
DeptDO lastChild = deptMapper.selectLastChildByCode(parentId, prefix);
|
||||
Integer sequence = parseSequence(lastChild != null ? lastChild.getCode() : null, prefix);
|
||||
if (sequence != null) {
|
||||
return sequence + 1;
|
||||
}
|
||||
return deptMapper.selectListByParentId(parentId, null).stream()
|
||||
.map(DeptDO::getCode)
|
||||
.map(code -> parseSequence(code, prefix))
|
||||
.filter(Objects::nonNull)
|
||||
.max(Integer::compareTo)
|
||||
.map(val -> val + 1)
|
||||
.orElse(1);
|
||||
}
|
||||
|
||||
|
||||
private void assertSequenceRange(int sequence) {
|
||||
if (sequence > MAX_SEQUENCE) {
|
||||
throw exception(DEPT_CODE_OUT_OF_RANGE);
|
||||
}
|
||||
}
|
||||
|
||||
private String formatSequence(int sequence) {
|
||||
return StrUtil.padPre(String.valueOf(sequence), CODE_SEGMENT_LENGTH, '0');
|
||||
}
|
||||
|
||||
private Integer parseSequence(String code, String prefix) {
|
||||
if (StrUtil.isBlank(code) || StrUtil.isBlank(prefix) || !code.startsWith(prefix)) {
|
||||
return null;
|
||||
}
|
||||
String suffix = code.substring(prefix.length());
|
||||
if (suffix.length() != CODE_SEGMENT_LENGTH || !StrUtil.isNumeric(suffix)) {
|
||||
return null;
|
||||
}
|
||||
return Integer.parseInt(suffix);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private DeptPushMsgDO validateExists(Long id) {
|
||||
if (id == null) {
|
||||
throw exception(DEPT_EXTERNAL_RELATION_NOT_EXISTS);
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package com.zt.plat.module.system.service.dept;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.system.api.dept.dto.DeptMsgRespDTO;
|
||||
import com.zt.plat.module.system.api.dept.dto.DeptSaveReqDTO;
|
||||
import com.zt.plat.module.system.api.esp.dto.EspDto;
|
||||
import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.EspPageReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.EspSaveRespVo;
|
||||
import com.zt.plat.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
|
||||
import com.zt.plat.module.system.dal.dataobject.dept.DeptPushMsgDO;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 部门推送消息 Service 接口
|
||||
*/
|
||||
@@ -47,11 +48,18 @@ public interface IEspService {
|
||||
*/
|
||||
List<DeptPushMsgDO> getPushMsgByDeptId(Long deptId);
|
||||
|
||||
/**
|
||||
* 创建部门
|
||||
* @param reqVO 部门信息
|
||||
* @return 部门编号
|
||||
*/
|
||||
Long createDept(DeptSaveReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 推送部门数据到外部系统
|
||||
* @param syncReqDTO 同步请求
|
||||
*/
|
||||
List<EspDto> pushMsg(DeptSaveReqDTO syncReqDTO);
|
||||
CommonResult<List<DeptMsgRespDTO>> selectDepMsg(DeptSaveReqDTO syncReqDTO);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@ import com.zt.plat.module.system.util.sync.SyncVerifyUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.DigestUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -39,6 +41,8 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
|
||||
|
||||
private static final String JOB_CODE_PREFIX = "IWORK_JOB_";
|
||||
private static final int DEFAULT_SORT = 999;
|
||||
/** 当上游密码缺失时,用空字符串的 MD5 作为占位,保证账号可创建 */
|
||||
private static final String EMPTY_PASSWORD_PLACEHOLDER = DigestUtils.md5DigestAsHex("".getBytes(StandardCharsets.UTF_8)).toUpperCase(Locale.ROOT);
|
||||
|
||||
private final DeptService deptService;
|
||||
private final PostService postService;
|
||||
@@ -325,10 +329,9 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
|
||||
}
|
||||
boolean inactive = isInactiveUser(user.getStatus());
|
||||
String username = resolveUsername(user);
|
||||
if (StrUtil.isBlank(username)) {
|
||||
log.warn("[iWork] 人员缺少可用账号(工号={}, 登录账号={}),跳过:id={} name={}",
|
||||
user.getWorkcode(), user.getLoginid(), user.getId(), user.getLastname());
|
||||
result.increaseFailed();
|
||||
if (username == null) {
|
||||
logSkip("人员", user.getId(), "缺少工号与登录账号,跳过同步");
|
||||
result.increaseSkipped();
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
@@ -350,9 +353,8 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
|
||||
continue;
|
||||
}
|
||||
if (StrUtil.isBlank(externalPassword)) {
|
||||
log.warn("[iWork] 人员缺少密码信息,无法创建:id={} username={}", user.getId(), username);
|
||||
result.increaseFailed();
|
||||
continue;
|
||||
externalPassword = EMPTY_PASSWORD_PLACEHOLDER;
|
||||
log.info("[iWork] 人员缺少密码信息,使用空密码占位同步:id={} username={}", user.getId(), username);
|
||||
}
|
||||
outcome = createUser(user, username, deptId, postId, status, externalPassword);
|
||||
} else {
|
||||
@@ -545,7 +547,7 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
|
||||
CommonStatusEnum status) {
|
||||
UserSaveReqVO req = new UserSaveReqVO();
|
||||
req.setUsername(username);
|
||||
req.setWorkcode(trimToNull(source.getWorkcode()));
|
||||
req.setWorkcode(resolveWorkcode(source));
|
||||
req.setNickname(limitLength(StrUtil.blankToDefault(source.getLastname(), username), 30));
|
||||
req.setRemark(buildUserRemark(source));
|
||||
if (deptId != null) {
|
||||
@@ -776,6 +778,23 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
|
||||
* 工号优先、登录账号兜底,确保账号体系与 iWork 一致
|
||||
*/
|
||||
private String resolveUsername(IWorkHrUserPageRespVO.User user) {
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
if (StrUtil.isNotBlank(user.getLoginid())) {
|
||||
return user.getLoginid().trim();
|
||||
}
|
||||
// loginid 为空也继续同步,username 设为空字符串,不再回退工号
|
||||
return " ";
|
||||
}
|
||||
|
||||
/**
|
||||
* 工号为空时自动使用登录账号作为工号兜底,避免因缺失工号而跳过同步。
|
||||
*/
|
||||
private String resolveWorkcode(IWorkHrUserPageRespVO.User user) {
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
if (StrUtil.isNotBlank(user.getWorkcode())) {
|
||||
return user.getWorkcode().trim();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.zt.plat.module.system.service.msg;
|
||||
|
||||
import com.zt.plat.module.system.mq.message.sms.SmsSendMessage;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
/**
|
||||
* 监听消息 Service 接口
|
||||
* @author ZT
|
||||
*/
|
||||
public interface IMonitorMsgService {
|
||||
|
||||
/**
|
||||
* 发送单条短信给管理后台的用户
|
||||
* 在 mobile 为空时,使用 userId 加载对应管理员的手机号
|
||||
* @param mobile 手机号
|
||||
* @param userId 用户编号
|
||||
* @param templateCode 短信模板编号
|
||||
* @param templateParams 短信模板参数
|
||||
* @return 发送日志编号
|
||||
*/
|
||||
Long sendSingleSmsToAdmin(String mobile, Long userId,
|
||||
String templateCode, Map<String, Object> templateParams);
|
||||
|
||||
/**
|
||||
* 发送单条短信给用户 APP 的用户
|
||||
* 在 mobile 为空时,使用 userId 加载对应会员的手机号
|
||||
* @param mobile 手机号
|
||||
* @param userId 用户编号
|
||||
* @param templateCode 短信模板编号
|
||||
* @param templateParams 短信模板参数
|
||||
* @return 发送日志编号
|
||||
*/
|
||||
Long sendSingleSmsToMember(String mobile, Long userId,
|
||||
String templateCode, Map<String, Object> templateParams);
|
||||
|
||||
/**
|
||||
* 发送单条短信给用户
|
||||
* @param mobile 手机号
|
||||
* @param userId 用户编号
|
||||
* @param userType 用户类型
|
||||
* @param templateCode 短信模板编号
|
||||
* @param templateParams 短信模板参数
|
||||
* @return 发送日志编号
|
||||
*/
|
||||
Long sendSingleSms(String mobile, Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams);
|
||||
|
||||
default void sendBatchSms(List<String> mobiles, List<Long> userIds, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams) {
|
||||
throw new UnsupportedOperationException("暂时不支持该操作,感兴趣可以实现该功能哟!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行真正的短信发送
|
||||
* 注意,该方法仅仅提供给 MQ Consumer 使用
|
||||
* @param message 短信
|
||||
*/
|
||||
void doSendSms(SmsSendMessage message);
|
||||
|
||||
/**
|
||||
* 接收短信的接收结果
|
||||
* @param channelCode 渠道编码
|
||||
* @param text 结果内容
|
||||
* @throws Throwable 处理失败时,抛出异常
|
||||
*/
|
||||
void receiveSmsStatus(String channelCode, String text) throws Throwable;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.zt.plat.module.system.service.msg;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.msg.TextMessage;
|
||||
import com.zt.plat.module.system.dal.dataobject.sms.SmsLogDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.sms.SmsTemplateDO;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
/**
|
||||
* 消息日志 Service 接口
|
||||
*
|
||||
* @author zzf
|
||||
*/
|
||||
public interface IMsgLogService {
|
||||
|
||||
/**
|
||||
* 创建短信日志
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param userType 用户类型
|
||||
* @param isSend 是否发送
|
||||
* @param template 短信模板
|
||||
* @param templateContent 短信内容
|
||||
* @param templateParams 短信参数
|
||||
* @return 发送日志编号
|
||||
*/
|
||||
Long createSmsLog(Long userId, Integer userType, Boolean isSend,
|
||||
SmsTemplateDO template, String templateContent, Map<String, Object> templateParams);
|
||||
|
||||
/**
|
||||
* 更新日志的发送结果
|
||||
*
|
||||
* @param id 日志编号
|
||||
* @param success 发送是否成功
|
||||
* @param apiSendCode 短信 API 发送结果的编码
|
||||
* @param apiSendMsg 短信 API 发送失败的提示
|
||||
* @param apiRequestId 短信 API 发送返回的唯一请求 ID
|
||||
* @param apiSerialNo 短信 API 发送返回的序号
|
||||
*/
|
||||
void updateSmsSendResult(Long id, Boolean success,
|
||||
String apiSendCode, String apiSendMsg,
|
||||
String apiRequestId, String apiSerialNo);
|
||||
|
||||
/**
|
||||
* 更新日志的接收结果
|
||||
*
|
||||
* @param id 日志编号
|
||||
* @param success 是否接收成功
|
||||
* @param receiveTime 用户接收时间
|
||||
* @param apiReceiveCode API 接收结果的编码
|
||||
* @param apiReceiveMsg API 接收结果的说明
|
||||
*/
|
||||
void updateSmsReceiveResult(Long id, Boolean success,
|
||||
LocalDateTime receiveTime, String apiReceiveCode, String apiReceiveMsg);
|
||||
|
||||
/**
|
||||
* 获得短信日志分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 短信日志分页
|
||||
*/
|
||||
PageResult<SmsLogDO> getSmsLogPage(SmsLogPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 根据日志编号查询短信日志
|
||||
*
|
||||
* @param id 日志编号
|
||||
* @return 短信日志
|
||||
*/
|
||||
SmsLogDO getSmsLog(Long id);
|
||||
|
||||
/**
|
||||
* 创建消息日志
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param userType 用户类型
|
||||
* @param isSend 是否发送
|
||||
* @param template 短信模板
|
||||
* @param textMessage 短信内容
|
||||
* @param templateParams 短信参数
|
||||
* @return 创建消息日志编号
|
||||
*/
|
||||
Long createMsgLog(Long userId, Integer userType, Boolean isSend, SmsTemplateDO template, TextMessage textMessage, Map<String, Object> templateParams);
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.zt.plat.module.system.service.msg;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.msg.*;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.template.MsgTemplateSendReqVO;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 生产者发送消息接口类
|
||||
*
|
||||
* @author dongqiang.hao
|
||||
*/
|
||||
public interface ISendMsgService {
|
||||
|
||||
/**
|
||||
* 发送文本消息
|
||||
*
|
||||
* @param textMessage 文本消息包装对象
|
||||
* @return r 响应对象
|
||||
*/
|
||||
CommonResult<Object> sendTextMsg(MsgTemplateSendReqVO sendReqVO, TextMessage textMessage) throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信图片消息
|
||||
*
|
||||
* @param imageMessage 图片消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendImageMsg(Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams,ImageMessage imageMessage)throws Exception;
|
||||
|
||||
|
||||
/**
|
||||
* 发送企业微信语音消息
|
||||
*
|
||||
* @param voiceMessage 语音消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendVoiceMsg(Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams,VoiceMessage voiceMessage)throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信视频消息
|
||||
*
|
||||
* @param videoMessage 视频消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendVideoMsg(Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams,VideoMessage videoMessage)throws Exception;
|
||||
|
||||
|
||||
/**
|
||||
* 发送企业微信文件消息
|
||||
*
|
||||
* @param fileMessage 文件消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendFileMsg(Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams,FileMessage fileMessage)throws Exception;
|
||||
|
||||
|
||||
/**
|
||||
* 发送企业微信文本卡片消息
|
||||
*
|
||||
* @param textCardMessage 文本卡片消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendTextCardMsgPich01(Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams,TextCardMessage textCardMessage) throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信文本卡片消息
|
||||
*
|
||||
* @param textCardMessage 文本卡片消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendTextCardMsg(Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams,TextCardMessage textCardMessage)throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信图文消息
|
||||
*
|
||||
* @param newsMessage 图文消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendNewsMsg(Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams,NewsMessage newsMessage)throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信图文消息(mpnews)
|
||||
*
|
||||
* @param mpNewsMessage 图文消息(mpnews)对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendMpNewsMsg(Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams,MpNewsMessage mpNewsMessage)throws Exception;
|
||||
|
||||
|
||||
/**
|
||||
* 发送企业微信markdown消息
|
||||
*
|
||||
* @param markdownMessage markdown消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendMarkdownMsg(Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams,MarkdownMessage markdownMessage) throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信小程序通知消息
|
||||
*
|
||||
* @param miniProgramNoticeMessage 小程序通知消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendMiniProgramNoticeMsg(Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams,MiniProgramNoticeMessage miniProgramNoticeMessage)throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信任务卡片消息
|
||||
*
|
||||
* @param interactiveTaskCardMessage 任务卡片消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendInteractiveTaskCardMsg(Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams,InteractiveTaskCardMessage interactiveTaskCardMessage)throws Exception;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.zt.plat.module.system.service.msg;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.msg.*;
|
||||
|
||||
/**
|
||||
* TODO ============================== 企微消息发送接口类 =========================================
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
public interface ISendWxMsgService {
|
||||
|
||||
/**
|
||||
* 发送企业微信文本消息
|
||||
*
|
||||
* @param textMessage 文本消息包装对象
|
||||
* @return r 响应对象
|
||||
*/
|
||||
CommonResult<Object> sendTextMsg(TextMessage textMessage)throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信图片消息
|
||||
*
|
||||
* @param imageMessage 图片消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendImageMsg(ImageMessage imageMessage)throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信语音消息
|
||||
*
|
||||
* @param voiceMessage 语音消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendVoiceMsg(VoiceMessage voiceMessage)throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信视频消息
|
||||
*
|
||||
* @param videoMessage 视频消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendVideoMsg(VideoMessage videoMessage)throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信文件消息
|
||||
*
|
||||
* @param fileMessage 文件消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendFileMsg(FileMessage fileMessage)throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信文本卡片消息
|
||||
*
|
||||
* @param textCardMessage 文本卡片消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendTextCardMsg(TextCardMessage textCardMessage)throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信文本卡片消息 -物资存货智能管理 预警信息
|
||||
*
|
||||
* @param textCardMessage 文本卡片消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendTextCardMsgPich01(TextCardMessage textCardMessage)throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信图文消息
|
||||
*
|
||||
* @param newsMessage 图文消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendNewsMsg(NewsMessage newsMessage)throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信图文消息(mpnews)
|
||||
*
|
||||
* @param mpNewsMessage 图文消息(mpnews)对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendMpNewsMsg(MpNewsMessage mpNewsMessage)throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信markdown消息
|
||||
*
|
||||
* @param markdownMessage markdown消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendMarkdownMsg(MarkdownMessage markdownMessage)throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信小程序通知消息
|
||||
*
|
||||
* @param miniProgramNoticeMessage 小程序通知消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendMiniProgramNoticeMsg(MiniProgramNoticeMessage miniProgramNoticeMessage) throws Exception;
|
||||
|
||||
/**
|
||||
* 发送企业微信任务卡片消息
|
||||
*
|
||||
* @param interactiveTaskCardMessage 任务卡片消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
CommonResult<Object> sendInteractiveTaskCardMsg(InteractiveTaskCardMessage interactiveTaskCardMessage) throws Exception;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.zt.plat.module.system.service.msg;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.zt.plat.module.system.dal.dataobject.msg.SysActiveMqLog;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
/**
|
||||
* RocketMq消息队列 服务类
|
||||
* @author dongqiang.hao
|
||||
* @since 2025-01-07
|
||||
*/
|
||||
public interface ISysRocketMqService extends IService<SysActiveMqLog> {
|
||||
|
||||
/**
|
||||
* 保存消息队列消费的消息信息
|
||||
*
|
||||
* @param listenerClassName 队列监听类名
|
||||
* @param tm 消息对象
|
||||
* @param jmsType 消息类型(QUEUE-队列/TOPIC-主题)
|
||||
* @throws Exception 消息消费异常
|
||||
*/
|
||||
void saveByTextMessage(String listenerClassName, MessageExt tm, String jmsType) throws Exception;
|
||||
|
||||
/**
|
||||
* 保存文本卡片消息队列消费的消息信息
|
||||
*
|
||||
* @param listenerClassName 队列监听类名
|
||||
* @param tm 消息对象
|
||||
* @param jmsType 消息类型(QUEUE-队列/TOPIC-主题)
|
||||
* @param consumeFlag 消费结果(success-成功/failure-失败)
|
||||
* @param consumeMessage 消费失败消息
|
||||
* @throws Exception 消息消费异常
|
||||
*/
|
||||
void saveByTextMessage(String listenerClassName, MessageExt tm, String jmsType, String consumeFlag, String consumeMessage) throws Exception;
|
||||
|
||||
/**
|
||||
* 保存阳光采购消息队列消费的消息信息
|
||||
*
|
||||
* @param listenerClassName 队列监听类名
|
||||
* @param tm 消息对象
|
||||
* @param jmsType 消息类型(QUEUE-队列/TOPIC-主题)
|
||||
* @param consumeFlag 消费结果(success-成功/failure-失败)
|
||||
* @param consumeMessage 消费失败消息
|
||||
* @throws Exception 消息消费异常
|
||||
*/
|
||||
void saveSunepsByTextMessage(String listenerClassName, MessageExt tm, String jmsType, String consumeFlag, String consumeMessage) throws Exception;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.zt.plat.module.system.service.msg;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.zt.plat.module.system.dal.dataobject.msg.SysWxAuditConfig;
|
||||
|
||||
/**
|
||||
* 企业微信审核配置表 服务类
|
||||
*
|
||||
* @author Dy
|
||||
* @since 2021-08-26
|
||||
*/
|
||||
public interface SysWxAuditConfigService extends IService<SysWxAuditConfig> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
package com.zt.plat.module.system.service.msg.config;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* 系统参数配置组件
|
||||
* TODO
|
||||
* @author luzemin
|
||||
*/
|
||||
@Component
|
||||
@PropertySource("classpath:config.properties")
|
||||
public class HttpUrlConfig {
|
||||
|
||||
/**
|
||||
* 企业微信审核涉及的app
|
||||
*/
|
||||
public static final String[] APP_TYPES = new String[]{"suneps", "pscs", "market", "bssim", "dzxs", "boli", "lmps"};
|
||||
|
||||
/**
|
||||
* 企业微信审核http请求url——提交审核
|
||||
*/
|
||||
public static final String COMMIT_URL = "commitUrl";
|
||||
/**
|
||||
* 企业微信审核http请求url——获取审核历史信息
|
||||
*/
|
||||
public static final String COMMENT_URL = "commentUrl";
|
||||
/**
|
||||
* 企业微信审核http请求url——获取用户待办
|
||||
*/
|
||||
public static final String TODO_URL = "todoUrl";
|
||||
/**
|
||||
* 企业微信审核http请求url——获取用户已办
|
||||
*/
|
||||
public static final String DONE_URL = "doneUrl";
|
||||
/**
|
||||
* 企业微信审核http请求url——获取流程是否结束信息
|
||||
*/
|
||||
public static final String FINISH_URL = "finishUrl";
|
||||
/**
|
||||
* 企业微信审核http请求url——文件存储
|
||||
*/
|
||||
public static final String STORAGE_URL = "storageUrl";
|
||||
/**
|
||||
* 获取合同文本内容请求url
|
||||
*/
|
||||
public static final String RENDERBPOCONTENT_URL = "renderBpoContentUrl";
|
||||
/**
|
||||
* 获字化采购报表地址
|
||||
*/
|
||||
private static final String FINE_REPORT_URL = "fineReportUrl";
|
||||
/**
|
||||
* 获数字化附件管理地址
|
||||
*/
|
||||
private static final String FILE_STORAGE_URL = "fileStorageUrl";
|
||||
|
||||
/**
|
||||
* 获数字化附件预览
|
||||
*/
|
||||
private static final String FILE_VIEW_URL = "fileViewUrl";
|
||||
|
||||
/**
|
||||
* 应用http调用地址
|
||||
*/
|
||||
private static final String HTTP_CONTEXT_PATH = "httpContextPath";
|
||||
|
||||
/**
|
||||
* 微信审核应用地址
|
||||
*/
|
||||
private static final String WX_CONTEXT_PATH = "wxContextPath";
|
||||
|
||||
/**
|
||||
* 微信审核应用地址
|
||||
*/
|
||||
private static final String WX_SUBMIT_DATA = "wxSubmitData";
|
||||
|
||||
|
||||
/**
|
||||
* 企业微信审核http请求url——提交审核应用和url映射集合
|
||||
*/
|
||||
private static final Map<String, String> COMMIT_URL_MAPPING = new HashMap<>();
|
||||
/**
|
||||
* 企业微信审核http请求url——获取审核历史信息应用和url映射集合
|
||||
*/
|
||||
private static final Map<String, String> COMMENT_URL_MAPPING = new HashMap<>();
|
||||
/**
|
||||
* 企业微信审核http请求url——获取用户待办应用和url映射集合
|
||||
*/
|
||||
private static final Map<String, String> TODO_URL_MAPPING = new HashMap<>();
|
||||
/**
|
||||
* 企业微信审核http请求url——获取用户已办应用和url映射集合
|
||||
*/
|
||||
private static final Map<String, String> DONE_URL_MAPPING = new HashMap<>();
|
||||
/**
|
||||
* 企业微信审核http请求url——文件存储应用和url映射集合
|
||||
*/
|
||||
private static final Map<String, String> STORAGE_URL_MAPPING = new HashMap<>();
|
||||
/**
|
||||
* 企业微信审核http请求url——文件存储应用和url映射集合
|
||||
*/
|
||||
private static final Map<String, String> FINISH_URL_MAPPING = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 获取合同文本内容请求url
|
||||
*/
|
||||
private static final Map<String, String> RENDERBPOCONTENT_URL_MAPPING = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 获取合同文本内容请求url
|
||||
*/
|
||||
private static final Map<String, String> FINE_REPORT_URL_MAPPING = new HashMap<>();
|
||||
/**
|
||||
* 获取合同文本内容请求url
|
||||
*/
|
||||
private static final Map<String, String> FILE_VIEW_URL_MAPPING = new HashMap<>();
|
||||
/**
|
||||
* 获取合同文本内容请求url
|
||||
*/
|
||||
private static final Map<String, String> FILE_STORAGE_URL_MAPPING = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 获取应用http调用地址
|
||||
*/
|
||||
private static final Map<String, String> HTTP_CONTEXT_PATH_MAPPING = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 微信审核应用地址
|
||||
*/
|
||||
private static final Map<String, String> WX_CONTEXT_PATH_MAPPING = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 微信审核应用地址
|
||||
*/
|
||||
private static final Map<String, String> WX_SUBMIT_DATA_MAPPING = new HashMap<>();
|
||||
|
||||
|
||||
@PostConstruct
|
||||
public void initConfig() throws IOException {
|
||||
Properties properties = new Properties();
|
||||
InputStream configInputStream = this.getClass().getClassLoader().getResourceAsStream("config.properties");
|
||||
properties.load(configInputStream);
|
||||
Arrays.stream(APP_TYPES).forEach(appType -> {
|
||||
COMMIT_URL_MAPPING.put(appType.concat(".").concat(COMMIT_URL), properties.getProperty(appType.concat(".").concat(COMMIT_URL)));
|
||||
COMMENT_URL_MAPPING.put(appType.concat(".").concat(COMMENT_URL), properties.getProperty(appType.concat(".").concat(COMMENT_URL)));
|
||||
TODO_URL_MAPPING.put(appType.concat(".").concat(TODO_URL), properties.getProperty(appType.concat(".").concat(TODO_URL)));
|
||||
DONE_URL_MAPPING.put(appType.concat(".").concat(DONE_URL), properties.getProperty(appType.concat(".").concat(DONE_URL)));
|
||||
STORAGE_URL_MAPPING.put(appType.concat(".").concat(STORAGE_URL), properties.getProperty(appType.concat(".").concat(STORAGE_URL)));
|
||||
FINISH_URL_MAPPING.put(appType.concat(".").concat(FINISH_URL), properties.getProperty(appType.concat(".").concat(FINISH_URL)));
|
||||
RENDERBPOCONTENT_URL_MAPPING.put(appType.concat(".").concat(RENDERBPOCONTENT_URL), properties.getProperty(appType.concat(".").concat(RENDERBPOCONTENT_URL)));
|
||||
FINE_REPORT_URL_MAPPING.put(appType.concat(".").concat(FINE_REPORT_URL), properties.getProperty(appType.concat(".").concat(FINE_REPORT_URL)));
|
||||
FILE_STORAGE_URL_MAPPING.put(appType.concat(".").concat(FILE_STORAGE_URL), properties.getProperty(appType.concat(".").concat(FILE_STORAGE_URL)));
|
||||
FILE_VIEW_URL_MAPPING.put(appType.concat(".").concat(FILE_VIEW_URL), properties.getProperty(appType.concat(".").concat(FILE_VIEW_URL)));
|
||||
HTTP_CONTEXT_PATH_MAPPING.put(appType.concat(".").concat(HTTP_CONTEXT_PATH), properties.getProperty(appType.concat(".").concat(HTTP_CONTEXT_PATH)));
|
||||
WX_CONTEXT_PATH_MAPPING.put(appType.concat(".").concat(WX_CONTEXT_PATH), properties.getProperty(appType.concat(".").concat(WX_CONTEXT_PATH)));
|
||||
WX_SUBMIT_DATA_MAPPING.put(appType.concat(".").concat(WX_SUBMIT_DATA), properties.getProperty(appType.concat(".").concat(WX_SUBMIT_DATA)));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业微信审核http请求url——提交审核
|
||||
*
|
||||
* @param appType 应用类型
|
||||
* @return 对应应用提交审核请求url
|
||||
*/
|
||||
public String getCommitUrl(String appType) {
|
||||
return COMMIT_URL_MAPPING.get(appType.concat(".").concat(COMMIT_URL));
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业微信审核http请求url——获取审核历史信息
|
||||
*
|
||||
* @param appType 应用类型
|
||||
* @return 对应应用获取审核历史信息请求url
|
||||
*/
|
||||
public String getCommentUrl(String appType) {
|
||||
return COMMENT_URL_MAPPING.get(appType.concat(".").concat(COMMENT_URL));
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业微信审核http请求url——获取用户待办
|
||||
*
|
||||
* @param appType 应用类型
|
||||
* @return 对应应用获取用户待办请求url
|
||||
*/
|
||||
public String getTodoUrl(String appType) {
|
||||
return TODO_URL_MAPPING.get(appType.concat(".").concat(TODO_URL));
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业微信审核http请求url——获取用户已办
|
||||
*
|
||||
* @param appType 应用类型
|
||||
* @return 对应应用获取用户已办请求url
|
||||
*/
|
||||
public String getDoneUrl(String appType) {
|
||||
return DONE_URL_MAPPING.get(appType.concat(".").concat(DONE_URL));
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业微信审核http请求url——文件存储
|
||||
*
|
||||
* @param appType 应用类型
|
||||
* @return 对应应用文件存储请求url
|
||||
*/
|
||||
public String getStorageUrl(String appType) {
|
||||
return STORAGE_URL_MAPPING.get(appType.concat(".").concat(STORAGE_URL));
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业微信审核http请求url——获取流程是否结束信息
|
||||
*
|
||||
* @param appType 应用类型
|
||||
* @return 对应应用获取审核历史信息请求url
|
||||
*/
|
||||
public String getFinishUrl(String appType) {
|
||||
return FINISH_URL_MAPPING.get(appType.concat(".").concat(FINISH_URL));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取合同文本内容
|
||||
*
|
||||
* @param appType 应用类型
|
||||
* @return 获取合同文本内容请求url
|
||||
*/
|
||||
public String getRenderBpoContentUrl(String appType) {
|
||||
return RENDERBPOCONTENT_URL_MAPPING.get(appType.concat(".").concat(RENDERBPOCONTENT_URL));
|
||||
}
|
||||
/**
|
||||
* 数字化采购报表地址
|
||||
*
|
||||
* @param appType 应用类型
|
||||
* @return 获取请求url
|
||||
*/
|
||||
public String getFineReportUrl(String appType) {
|
||||
return FINE_REPORT_URL_MAPPING.get(appType.concat(".").concat(FINE_REPORT_URL));
|
||||
}
|
||||
|
||||
/**
|
||||
* 字化附件管理地址
|
||||
*
|
||||
* @param appType 应用类型
|
||||
* @return 获取合同文本内容请求url
|
||||
*/
|
||||
public String getFileStorageUrl(String appType) {
|
||||
return FILE_STORAGE_URL_MAPPING.get(appType.concat(".").concat(FILE_STORAGE_URL));
|
||||
}
|
||||
|
||||
/**
|
||||
* 字化附件预览
|
||||
*
|
||||
* @param appType 应用类型
|
||||
* @return 获取合同文本内容请求url
|
||||
*/
|
||||
public String getFileViewUrl(String appType) {
|
||||
return FILE_VIEW_URL_MAPPING.get(appType.concat(".").concat(FILE_VIEW_URL));
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用http调用地址
|
||||
*
|
||||
* @param appType 应用类型
|
||||
* @return 获取合同文本内容请求url
|
||||
*/
|
||||
public String getHttpContextPath(String appType) {
|
||||
return HTTP_CONTEXT_PATH_MAPPING.get(appType.concat(".").concat(HTTP_CONTEXT_PATH));
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用http调用地址
|
||||
*
|
||||
* @param appType 应用类型
|
||||
* @return 获取合同文本内容请求url
|
||||
*/
|
||||
public String getWxContextPath(String appType) {
|
||||
return WX_CONTEXT_PATH_MAPPING.get(appType.concat(".").concat(WX_CONTEXT_PATH));
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用http调用地址
|
||||
*
|
||||
* @param appType 应用类型
|
||||
* @return 获取合同文本内容请求url
|
||||
*/
|
||||
public String getWxSubmitData(String appType) {
|
||||
return WX_SUBMIT_DATA_MAPPING.get(appType.concat(".").concat(WX_SUBMIT_DATA));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,376 @@
|
||||
package com.zt.plat.module.system.service.msg.config;
|
||||
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.zt.plat.framework.common.util.http.HttpClientUtils;
|
||||
import com.zt.plat.module.system.api.sms.dto.code.User;
|
||||
import com.zt.plat.module.system.dal.dataobject.msg.SysWxAuditConfig;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.AuditConstants;
|
||||
import com.zt.plat.module.system.service.msg.SysWxAuditConfigService;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Component
|
||||
@PropertySource("classpath:qywx.properties")
|
||||
public class WeiXinProperties {
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
@Resource
|
||||
private SysWxAuditConfigService sysWxAuditConfigService;
|
||||
|
||||
/**
|
||||
* 企业微信——企业access_token获取url
|
||||
*/
|
||||
@Getter
|
||||
@Value("${qyAccessTokenUrl}")
|
||||
private String qyAccessTokenUrl;
|
||||
|
||||
/**
|
||||
* 企业微信——消息发送url
|
||||
*/
|
||||
@Getter
|
||||
@Value("${qySendMsgUrl}")
|
||||
private String qySendMsgUrl;
|
||||
|
||||
/**
|
||||
* 企业微信——用户Oauth2认证授权url
|
||||
*/
|
||||
@Getter
|
||||
@Value("${qyAuthorizeUrl}")
|
||||
private String qyAuthorizeUrl;
|
||||
|
||||
/**
|
||||
* 企业微信-企业自建应用用户信息获取url
|
||||
*/
|
||||
@Getter
|
||||
@Value("${qyUserInfoUrl}")
|
||||
private String qyUserInfoUrl;
|
||||
|
||||
/**
|
||||
* 企业微信-企业自建应用用户信息获取url
|
||||
*/
|
||||
@Getter
|
||||
@Value("${qyUserUrl}")
|
||||
private String qyUserUrl;
|
||||
|
||||
/**
|
||||
* 企业微信-上传临时素材url
|
||||
*/
|
||||
@Getter
|
||||
@Value("${qyUploadTempFileUrl}")
|
||||
private String qyUploadTempFileUrl;
|
||||
|
||||
/**
|
||||
* 企业微信-部门创建url
|
||||
*/
|
||||
@Getter
|
||||
@Value("${qyDeptCreateUrl}")
|
||||
private String qyDeptCreateUrl;
|
||||
|
||||
/**
|
||||
* 企业微信-部门更新url
|
||||
*/
|
||||
@Getter
|
||||
@Value("${qyDeptUpdateUrl}")
|
||||
private String qyDeptUpdateUrl;
|
||||
|
||||
/**
|
||||
* 企业微信-部门删除url
|
||||
*/
|
||||
@Getter
|
||||
@Value("${qyDeptDeleteUrl}")
|
||||
private String qyDeptDeleteUrl;
|
||||
|
||||
/**
|
||||
* 企业微信-部门列表拉取url
|
||||
*/
|
||||
@Getter
|
||||
@Value("${qyDeptQueryListUrl}")
|
||||
private String qyDeptQueryListUrl;
|
||||
/**
|
||||
* 企业微信-部门列表拉取url
|
||||
*/
|
||||
@Getter
|
||||
@Value("${qyMenuCreateUrl}")
|
||||
private String qyMenuCreateUrl;
|
||||
/**
|
||||
* 企业微信-部门列表拉取url
|
||||
*/
|
||||
@Getter
|
||||
@Value("${qyMenuDeleteUrl}")
|
||||
private String qyMenuDeleteUrl;
|
||||
/**
|
||||
* 企业微信-部门列表拉取url
|
||||
*/
|
||||
@Getter
|
||||
@Value("${qyMenuQueryUrl}")
|
||||
private String qyMenuQueryUrl;
|
||||
|
||||
/**
|
||||
* 企业微信-ticket获取url
|
||||
*/
|
||||
@Getter
|
||||
@Value("${ticketUrl}")
|
||||
private String ticketUrl;
|
||||
|
||||
/**
|
||||
* 获取企业微信-企业access_token,先从redis持久化缓存中获取,若不存在,则从腾讯获取并加入缓存,key为企业微信corpId+corpSecret
|
||||
*
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param corpSecret 企业微信企业应用密钥
|
||||
* @return String 企业微信-企业access_token
|
||||
*/
|
||||
public String getQyAccessToken(String corpId, String corpSecret) {
|
||||
Object accessToken = redisTemplate.opsForValue().get(corpId.concat(corpSecret));
|
||||
if (Objects.nonNull(accessToken)) {
|
||||
return accessToken.toString();
|
||||
} else {
|
||||
JSONObject jsonObject = HttpClientUtils.httpGet(this.buildQyAccessTokenUrl(corpId, corpSecret));
|
||||
String qyAccessToken = jsonObject.getString("access_token");
|
||||
String expiresIn = jsonObject.getString("expires_in");
|
||||
redisTemplate.opsForValue().set(corpId.concat(corpSecret), qyAccessToken, Long.parseLong(expiresIn), TimeUnit.SECONDS);
|
||||
return qyAccessToken;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取JsapiTicket,先从redis持久化缓存中获取,若不存在,则从腾讯获取并加入缓存,key为ticket
|
||||
*/
|
||||
public String getJsapiTicket(String accessToken) {
|
||||
Object ticket = redisTemplate.opsForValue().get("ticket");
|
||||
if (Objects.nonNull(ticket)) {
|
||||
return ticket.toString();
|
||||
} else {
|
||||
JSONObject jsonObject = HttpClientUtils.httpGet(this.buildTicketUrl(accessToken));
|
||||
String qyTicket = jsonObject.getString("ticket");
|
||||
String expiresIn = jsonObject.getString("expires_in");
|
||||
redisTemplate.opsForValue().set("ticket", qyTicket, Long.parseLong(expiresIn), TimeUnit.SECONDS);
|
||||
return qyTicket;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取企业微信内建应用简单用户信息对象
|
||||
*
|
||||
* @param code 企业微信Oauth2授权成功后获取的授权code,每次成员授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param corpSecret 企业微信企业应用密钥
|
||||
* @return QywxUser企业颞部开发获取的用户信息对象
|
||||
*/
|
||||
public User getUser(String code, String corpId, String corpSecret) {
|
||||
JSONObject jsonObject = HttpClientUtils.httpGet(this.buildQyUserInfoUrl(code, corpId, corpSecret));
|
||||
return jsonObject.toJavaObject(User.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建企业微信access_token获取url
|
||||
*
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param corpSecret 企业微信企业应用密钥
|
||||
*/
|
||||
public String buildQyAccessTokenUrl(String corpId, String corpSecret) {
|
||||
return this.getQyAccessTokenUrl().replace("CORP_ID", corpId).replace("CORP_SECRET", corpSecret);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建获取企业微信内建应用简单用户信息对象获取url
|
||||
*
|
||||
* @param code 企业微信Oauth2授权成功后获取的授权code
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param corpSecret 企业微信企业应用密钥
|
||||
*/
|
||||
public String buildQyUserInfoUrl(String code, String corpId, String corpSecret) {
|
||||
return this.getQyUserInfoUrl().replaceAll("ACCESS_TOKEN", this.getQyAccessToken(corpId, corpSecret)).replaceAll("CODE", code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建读取成员url
|
||||
*
|
||||
* @param userId 企业微信用户id
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param corpSecret 企业微信企业应用密钥
|
||||
*/
|
||||
public String buildQyUserUrl(String userId, String corpId, String corpSecret) {
|
||||
return this.getQyUserUrl().replaceAll("ACCESS_TOKEN", this.getQyAccessToken(corpId, corpSecret)).replaceAll("USER_ID", userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建消息发送url
|
||||
*
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param corpSecret 企业微信企业应用密钥
|
||||
*/
|
||||
public String buildQySendMsgUrl(String corpId, String corpSecret) {
|
||||
return this.getQySendMsgUrl().replace("ACCESS_TOKEN", this.getQyAccessToken(corpId, corpSecret));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建企业微信授权url
|
||||
*
|
||||
* @param redirectUrl 授权成功重定向url
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param state 授权成功重定向url携带的自定义参数
|
||||
* @return 企业微信授权url
|
||||
*/
|
||||
public String buildQyAuthorizeUrl(String corpId, String agentId, String redirectUrl, String state) {
|
||||
return this.getQyAuthorizeUrl()
|
||||
.replaceAll("CORPID", corpId)
|
||||
.replaceAll("REDIRECT_URI", redirectUrl)
|
||||
.replaceAll("AGENTID", agentId)
|
||||
.replaceAll("STATE", state);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传临时素材url
|
||||
*
|
||||
* @param type 媒体文件类型,分别有图片(image)、语音(voice)、视频(video),普通文件(file)
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param corpSecret 企业微信企业应用密钥
|
||||
* @return String 上传临时素材url
|
||||
*/
|
||||
public String buildQyUploadTempFileUrl(String type, String corpId, String corpSecret) {
|
||||
return this.getQyUploadTempFileUrl().replace("ACCESS_TOKEN", this.getQyAccessToken(corpId, corpSecret)).replaceAll("TYPE", type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建企业微信-部门创建url
|
||||
*
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param corpSecret 企业微信企业应用密钥
|
||||
* @return String 部门创建url
|
||||
*/
|
||||
public String buildQyDeptCreateUrl(String corpId, String corpSecret) {
|
||||
return this.getQyDeptCreateUrl().replace("ACCESS_TOKEN", this.getQyAccessToken(corpId, corpSecret));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建企业微信-部门更新url
|
||||
*
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param corpSecret 企业微信企业应用密钥
|
||||
* @return String 部门更新url
|
||||
*/
|
||||
public String buildQyDeptUpdateUrl(String corpId, String corpSecret) {
|
||||
return this.getQyDeptUpdateUrl().replace("ACCESS_TOKEN", this.getQyAccessToken(corpId, corpSecret));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建企业微信-部门删除url
|
||||
*
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param corpSecret 企业微信企业应用密钥
|
||||
* @param id 部门id
|
||||
* @return String 部门删除url
|
||||
*/
|
||||
public String buildQyDeptDeleteUrl(String id, String corpId, String corpSecret) {
|
||||
return this.getQyDeptDeleteUrl().replace("ACCESS_TOKEN", this.getQyAccessToken(corpId, corpSecret)).replaceAll("ID", id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建企业微信-部门列表拉取url
|
||||
*
|
||||
* @param id 部门id
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param corpSecret 企业微信企业应用密钥
|
||||
* @return String 部门列表拉取url
|
||||
*/
|
||||
public String buildQyDeptQueryListUrl(String id, String corpId, String corpSecret) {
|
||||
return this.getQyDeptQueryListUrl().replace("ACCESS_TOKEN", this.getQyAccessToken(corpId, corpSecret)).replaceAll("DEPARTMENT_ID", id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建企业微信应用菜单创建url
|
||||
*
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param corpSecret 企业微信企业应用密钥
|
||||
* @param agentId 企业微信企业应用ID
|
||||
* @return String 应用菜单创建url
|
||||
*/
|
||||
public String buildQyMenuCreateUrl(String corpId, String corpSecret, String agentId) {
|
||||
return this.getQyMenuCreateUrl().replace("ACCESS_TOKEN", this.getQyAccessToken(corpId, corpSecret)).replace("AGENT_ID", agentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建企业微信应用菜单删除url
|
||||
*
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param corpSecret 企业微信企业应用密钥
|
||||
* @param agentId 企业微信企业应用ID
|
||||
* @return string 应用菜单删除url
|
||||
*/
|
||||
public String buildQyMenuDeleteUrl(String corpId, String corpSecret, String agentId) {
|
||||
return this.getQyMenuDeleteUrl().replace("ACCESS_TOKEN", this.getQyAccessToken(corpId, corpSecret)).replace("AGENT_ID", agentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建企业微信应用菜单拉取url
|
||||
*
|
||||
* @param corpId 企业微信企业ID
|
||||
* @param corpSecret 企业微信企业应用密钥
|
||||
* @param agentId 企业微信企业应用ID
|
||||
* @return string 应用菜单拉取url
|
||||
*/
|
||||
public String buildQyMenuQueryUrl(String corpId, String corpSecret, String agentId) {
|
||||
return this.getQyMenuQueryUrl().replace("ACCESS_TOKEN", this.getQyAccessToken(corpId, corpSecret)).replace("AGENT_ID", agentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建企业微信应用ticket获取url
|
||||
*/
|
||||
public String buildTicketUrl(String accessToken) {
|
||||
return this.getTicketUrl().replace("ACCESS_TOKEN", accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取企业微信消息发送应用配置
|
||||
*
|
||||
* @param appType 服务应用类型
|
||||
* @return SysWxAuditConfig 企业微信消息发送应用配置
|
||||
*/
|
||||
/**
|
||||
* 获取企业微信消息发送应用配置
|
||||
*
|
||||
* @param appType 服务应用类型
|
||||
* @return SysWxAuditConfig 企业微信消息发送应用配置
|
||||
*/
|
||||
public SysWxAuditConfig buildSysWxAuditConfig(String appType) throws Exception{
|
||||
if (StringUtils.isBlank(appType)) {
|
||||
throw new Exception("请求缺少服务应用类型!");
|
||||
|
||||
}
|
||||
List<SysWxAuditConfig> sysWxAuditConfigs = sysWxAuditConfigService.list(new LambdaQueryWrapper<SysWxAuditConfig>()
|
||||
.eq(SysWxAuditConfig::getAppType, appType)
|
||||
.eq(SysWxAuditConfig::getState, SysWxAuditConfig.STATE_ACTIVE)
|
||||
.eq(SysWxAuditConfig::getExt1, AuditConstants.CHINALCO_ZLEB_CHSZH));
|
||||
SysWxAuditConfig sysWxAuditConfig = sysWxAuditConfigs.get(0);
|
||||
if (StringUtils.isBlank(sysWxAuditConfig.getWxContextPath())) {
|
||||
throw new Exception("微信审核应用上下文根未配置,请配置后重试!");
|
||||
}
|
||||
if (StringUtils.isBlank(sysWxAuditConfig.getHttpContextPath())) {
|
||||
throw new Exception("微信审核http远程请求上下文根未配置,请配置后重试!");
|
||||
}
|
||||
if (StringUtils.isBlank(sysWxAuditConfig.getCorpId())) {
|
||||
throw new Exception("微信审核企业ID未配置,请配置后重试!");
|
||||
}
|
||||
if (StringUtils.isBlank(sysWxAuditConfig.getCorpSecret())) {
|
||||
throw new Exception("微信审核企业应用密钥未配置,请配置后重试!");
|
||||
}
|
||||
if (StringUtils.isBlank(sysWxAuditConfig.getAgentId())) {
|
||||
throw new Exception("微信审核企业应用ID未配置,请配置后重试!");
|
||||
}
|
||||
return sysWxAuditConfig;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.zt.plat.module.system.service.msg.impl;
|
||||
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.msg.TextMessage;
|
||||
import com.zt.plat.module.system.dal.dataobject.sms.SmsLogDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.sms.SmsTemplateDO;
|
||||
import com.zt.plat.module.system.dal.mysql.sms.SmsLogMapper;
|
||||
import com.zt.plat.module.system.enums.sms.SmsReceiveStatusEnum;
|
||||
import com.zt.plat.module.system.enums.sms.SmsSendStatusEnum;
|
||||
import com.zt.plat.module.system.service.msg.IMsgLogService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@Service
|
||||
public class MsgLogServiceImpl implements IMsgLogService {
|
||||
|
||||
@Resource
|
||||
private SmsLogMapper smsLogMapper;
|
||||
|
||||
|
||||
@Override
|
||||
public Long createSmsLog(Long userId, Integer userType, Boolean isSend, SmsTemplateDO template, String templateContent, Map<String, Object> templateParams) {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSmsSendResult(Long id, Boolean success, String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSmsReceiveResult(Long id, Boolean success, LocalDateTime receiveTime, String apiReceiveCode, String apiReceiveMsg) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<SmsLogDO> getSmsLogPage(SmsLogPageReqVO pageReqVO) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsLogDO getSmsLog(Long id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建消息日志
|
||||
*/
|
||||
@Override
|
||||
public Long createMsgLog(Long userId, Integer userType, Boolean isSend, SmsTemplateDO template,
|
||||
TextMessage textMessage, Map<String, Object> templateParams) {
|
||||
SmsLogDO.SmsLogDOBuilder logBuilder = SmsLogDO.builder();
|
||||
// 根据是否要发送,设置状态
|
||||
logBuilder.sendStatus(Objects.equals(isSend, true) ? SmsSendStatusEnum.INIT.getStatus()
|
||||
: SmsSendStatusEnum.IGNORE.getStatus());
|
||||
// 设置手机相关字段
|
||||
//logBuilder.mobile(mobile).userId(userId).userType(userType);
|
||||
// 设置模板相关字段
|
||||
logBuilder.templateId(template.getId()).templateCode(template.getCode()).templateType(template.getType());
|
||||
logBuilder.templateContent(String.valueOf(textMessage)).templateParams(templateParams)
|
||||
.apiTemplateId(template.getApiTemplateId());
|
||||
// 设置渠道相关字段
|
||||
logBuilder.channelId(template.getChannelId()).channelCode(template.getChannelCode());
|
||||
// 设置接收相关字段
|
||||
logBuilder.receiveStatus(SmsReceiveStatusEnum.INIT.getStatus());
|
||||
|
||||
// 插入数据库
|
||||
SmsLogDO logDO = logBuilder.build();
|
||||
smsLogMapper.insert(logDO);
|
||||
return logDO.getId();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.zt.plat.module.system.service.msg.impl;
|
||||
|
||||
/**
|
||||
* 流程审核企业微信待办消息队列监听
|
||||
*/
|
||||
/*
|
||||
@Slf4j
|
||||
@Component
|
||||
@RocketMQMessageListener(topic = "springboot-mq",consumerGroup = "consumer-service")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class RocketmqMsgQueueReceiver implements RocketMQListener<String> {
|
||||
|
||||
@Resource
|
||||
private ISysRocketMqService sysActiveMqService;
|
||||
|
||||
@Resource
|
||||
private ISendMsgService sendMsgService;
|
||||
|
||||
*/
|
||||
/**
|
||||
* 接受消息
|
||||
*//*
|
||||
|
||||
@Override
|
||||
public void onMessage(String jsonStr) {
|
||||
TextMessage tm = JSON.parseObject(jsonStr, TextMessage.class);
|
||||
log.info("接收到消息: {}", tm);
|
||||
String consumeMsg;
|
||||
try {
|
||||
Text text = tm.getText();
|
||||
String toUser = tm.getTouser();// 企业微信接收者
|
||||
String userName = tm.getToparty(); // 部门
|
||||
String userEname = tm.getText().getContent();//标签
|
||||
String agentid = tm.getAgentid();//企微ID
|
||||
String msgtype = tm.getMsgtype();//消息类型
|
||||
String appType = tm.getAppType();// 消息自建类型
|
||||
Integer enableDuplicateCheck = tm.getEnable_duplicate_check();//是否重启重复消息检查
|
||||
Integer duplicateCheckInterval = tm.getDuplicate_check_interval();// 是否重复消息检查的时间间隔
|
||||
String userCname = tm.getText().getContent();
|
||||
// 校验接受用户
|
||||
if (StringUtils.isBlank(toUser)) {
|
||||
consumeMsg = "企业微信消息发送失败,用户【" + userEname + "-" + userCname + "】未绑定企业微信账号!";
|
||||
sysActiveMqService.saveByTextMessage(this.getClass().getName(), tm, JmsConstant.JMS_TYPE_QUEUE.getCode(), JmsConstant.CONSUME_FAILURE.getCode(), consumeMsg);
|
||||
} else {
|
||||
String msgType = tm.getMsgtype();
|
||||
if (Objects.equals(msgType, WxMsgTypeConstant.TEXTCARD.getCode())) {
|
||||
*/
|
||||
/* 构建审批回调url *//*
|
||||
|
||||
String appType = tm.getStringProperty("appType");
|
||||
String approveType = tm.getStringProperty("approveType");
|
||||
String companyCode = tm.getStringProperty("userCompanyCode");
|
||||
String taskId = tm.getStringProperty("taskId");
|
||||
String processInstanceId = tm.getStringProperty("processInstanceId");
|
||||
String businessId = tm.getStringProperty("businessId");
|
||||
Map<String, Object> substituteMap = new HashMap<>(5);
|
||||
substituteMap.put("appType", appType.toLowerCase(Locale.ROOT));
|
||||
substituteMap.put("approveType", approveType);
|
||||
substituteMap.put("companyCode", companyCode);
|
||||
substituteMap.put("taskId", taskId);
|
||||
substituteMap.put("processInstanceId", processInstanceId);
|
||||
substituteMap.put("businessId", businessId);
|
||||
String redirectUrl = StringSolveUtils.placeholderReplace(AuditConstants.SunepsAuditType.REDIRECT_URL.getCode(), substituteMap);
|
||||
|
||||
*/
|
||||
/* 构建文本卡片消息 *//*
|
||||
|
||||
String title = tm.getStringProperty("title");
|
||||
String taskName = tm.getStringProperty("taskName");
|
||||
String datetime = tm.getStringProperty("datetime");
|
||||
String btnTxt = tm.getStringProperty("btntxt");
|
||||
substituteMap.put("subTitle", datetime + "——" + userName);
|
||||
substituteMap.put("description", descriptionText);
|
||||
substituteMap.put("taskName", taskName);
|
||||
String description = StringSolveUtils.placeholderReplace(AuditConstants.SunepsAuditType.AUDIT_DESCRIPTION_FORMAT.getCode(), substituteMap);
|
||||
TextCardMessage textCardMessage = new TextCardMessage();
|
||||
TextCard textCard = new TextCard();
|
||||
textCard.setTitle(title)
|
||||
.setDescription(description)
|
||||
.setUrl(redirectUrl);
|
||||
if (StringUtils.isNotBlank(btnTxt)) {
|
||||
textCard.setBtntxt(btnTxt);
|
||||
}
|
||||
textCardMessage.setTextcard(textCard).setAppType(appType).setTouser(toUser);
|
||||
sendMsgService.sendTextCardMsg(textCardMessage);
|
||||
consumeMsg = "企业微信消息发送成功,接收用户【" + userEname + "-" + userCname + "】!";
|
||||
sysActiveMqService.saveByTextMessage(this.getClass().getName(), tm, JmsConstant.JMS_TYPE_QUEUE.getCode(), JmsConstant.CONSUME_SUCCESS.getCode(), consumeMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("中铝e办发送消息异常:{}",e.getMessage(),e);
|
||||
try {
|
||||
// 重试时不重复保存队列消息
|
||||
if (!message.getJMSRedelivered()) {
|
||||
sysActiveMqService.saveByTextMessage(this.getClass().getName(), tm, JmsConstant.JMS_TYPE_QUEUE.getCode(), JmsConstant.CONSUME_FAILURE.getCode(), e.getMessage());
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
log.error("中铝e办发送消息异常:{}", exception.getMessage(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,732 @@
|
||||
package com.zt.plat.module.system.service.msg.impl;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.zt.plat.framework.common.core.KeyValue;
|
||||
import com.zt.plat.framework.common.enums.CommonStatusEnum;
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.util.validation.MatcherSolveUtils;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.msg.*;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.template.MsgTemplateSendReqVO;
|
||||
import com.zt.plat.module.system.dal.dataobject.sms.SmsChannelDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.sms.SmsTemplateDO;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.WxMsgTypeConstant;
|
||||
import com.zt.plat.module.system.mq.producer.msg.MsgProducer;
|
||||
import com.zt.plat.module.system.service.msg.IMsgLogService;
|
||||
import com.zt.plat.module.system.service.msg.ISendMsgService;
|
||||
import com.zt.plat.module.system.service.sms.SmsChannelService;
|
||||
import com.zt.plat.module.system.service.sms.SmsTemplateService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.zt.plat.module.system.enums.ErrorCodeConstants.*;
|
||||
/**
|
||||
* 消息发送接口实现
|
||||
* TODO =========================================== 参考这个发送消息类文件===========================================================
|
||||
* @author luzemin
|
||||
*/
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class SendMsgServiceImpl implements ISendMsgService {
|
||||
|
||||
/**
|
||||
* 文本消息内容限制
|
||||
*/
|
||||
public static final int INT_2048 = 2048;
|
||||
|
||||
@Resource
|
||||
private SmsChannelService smsChannelService;
|
||||
|
||||
@Resource
|
||||
private SmsTemplateService smsTemplateService;
|
||||
|
||||
@Resource
|
||||
private IMsgLogService msgLogService;
|
||||
|
||||
@Resource
|
||||
private MsgProducer msgProducer;
|
||||
/**
|
||||
* 发送MQ文本消息
|
||||
* 用户ID,模版内容,消息类型、模版编码
|
||||
* @param textMessage 文本消息包装对象
|
||||
* @return r 响应对象
|
||||
*/
|
||||
@Override
|
||||
public CommonResult<Object> sendTextMsg(MsgTemplateSendReqVO sendReqVO, TextMessage textMessage) throws Exception {
|
||||
|
||||
Long userId = sendReqVO.getUserId();
|
||||
Integer userType = sendReqVO.getUserType();
|
||||
String templateCode = sendReqVO.getTemplateCode();
|
||||
Map<String, Object> templateParams = sendReqVO.getTemplateParams();
|
||||
// 校验模板是否合法
|
||||
SmsTemplateDO template = validateSmsTemplate(templateCode);
|
||||
// 校验渠道是否合法
|
||||
SmsChannelDO smsChannel = validateSmsChannel(template.getChannelId());
|
||||
|
||||
// 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
|
||||
List<KeyValue<String, Object>> newTemplateParams = buildTemplateParams(template, templateParams);
|
||||
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(textMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(textMessage.getMsgtype(), WxMsgTypeConstant.TEXT.getCode())) {
|
||||
throw new Exception("文本消息类型必须为" + WxMsgTypeConstant.TEXT.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(textMessage.getText())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (StringUtils.isBlank(textMessage.getText().getContent())) {
|
||||
throw new Exception("消息发送消息体不能为空!");
|
||||
}
|
||||
/* 消息内容长度检验 */
|
||||
if (textMessage.getText().getContent().length() > INT_2048) {
|
||||
throw new Exception("消息发送消息内容,最长不超过2048个字节,超过将截断!");
|
||||
}
|
||||
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus())
|
||||
&& CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus());
|
||||
//格式化短信内容
|
||||
//String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
|
||||
//创建发送日志
|
||||
Long sendLogId = msgLogService.createMsgLog(userId, userType, isSend, template, textMessage, templateParams);
|
||||
|
||||
//发送 MQ 消息,异步执行发送消息(发送日志、内容、渠道ID、模版ID)
|
||||
if (isSend) {
|
||||
msgProducer.sendMsg(sendLogId, textMessage.getText().getContent(), template.getChannelId(), template.getApiTemplateId(), newTemplateParams);
|
||||
}
|
||||
|
||||
return CommonResult.success(sendLogId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Object> sendImageMsg(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams, ImageMessage imageMessage) throws Exception {
|
||||
|
||||
// 校验短信模板是否合法
|
||||
SmsTemplateDO template = validateSmsTemplate(templateCode);
|
||||
// 校验短信渠道是否合法
|
||||
SmsChannelDO smsChannel = validateSmsChannel(template.getChannelId());
|
||||
|
||||
// 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
|
||||
List<KeyValue<String, Object>> newTemplateParams = buildTemplateParams(template, templateParams);
|
||||
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(imageMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(imageMessage.getMsgtype(), WxMsgTypeConstant.IMAGE.getCode())) {
|
||||
throw new Exception("图片消息类型必须为" + WxMsgTypeConstant.IMAGE.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(imageMessage.getImage())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 图片媒体ID校验 */
|
||||
if (StringUtils.isBlank(imageMessage.getImage().getMedia_id())) {
|
||||
throw new Exception("图片媒体ID不能为空!");
|
||||
}
|
||||
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus())
|
||||
&& CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus());
|
||||
String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
|
||||
Long sendLogId = msgLogService.createSmsLog(userId, userType, isSend, template, content, templateParams);
|
||||
|
||||
/* if (isSend) {
|
||||
msgProducer.sendSendMsg(sendLogId, content, template.getChannelId(),
|
||||
template.getApiTemplateId(), newTemplateParams);
|
||||
}*/
|
||||
return CommonResult.success(sendLogId);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Object> sendVoiceMsg(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams, VoiceMessage voiceMessage) throws Exception {
|
||||
|
||||
// 校验短信模板是否合法
|
||||
SmsTemplateDO template = validateSmsTemplate(templateCode);
|
||||
// 校验短信渠道是否合法
|
||||
SmsChannelDO smsChannel = validateSmsChannel(template.getChannelId());
|
||||
|
||||
// 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
|
||||
List<KeyValue<String, Object>> newTemplateParams = buildTemplateParams(template, templateParams);
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(voiceMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(voiceMessage.getMsgtype(), WxMsgTypeConstant.VOICE.getCode())) {
|
||||
throw new Exception("语音消息类型必须为" + WxMsgTypeConstant.VOICE.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(voiceMessage.getVoice())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 语音媒体ID校验 */
|
||||
if (StringUtils.isBlank(voiceMessage.getVoice().getMedia_id())) {
|
||||
throw new Exception("语音媒体ID不能为空!");
|
||||
}
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus())
|
||||
&& CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus());
|
||||
String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
|
||||
Long sendLogId = msgLogService.createSmsLog(userId, userType, isSend, template, content, templateParams);
|
||||
|
||||
/* if (isSend) {
|
||||
msgProducer.sendSendMsg(sendLogId, content, template.getChannelId(),
|
||||
template.getApiTemplateId(), newTemplateParams);
|
||||
}*/
|
||||
return CommonResult.success(sendLogId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Object> sendVideoMsg(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams, VideoMessage videoMessage) throws Exception {
|
||||
|
||||
// 校验短信模板是否合法
|
||||
SmsTemplateDO template = validateSmsTemplate(templateCode);
|
||||
// 校验短信渠道是否合法
|
||||
SmsChannelDO smsChannel = validateSmsChannel(template.getChannelId());
|
||||
|
||||
// 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
|
||||
List<KeyValue<String, Object>> newTemplateParams = buildTemplateParams(template, templateParams);
|
||||
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(videoMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(videoMessage.getMsgtype(), WxMsgTypeConstant.VIDEO.getCode())) {
|
||||
throw new Exception("视频消息类型必须为" + WxMsgTypeConstant.VIDEO.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(videoMessage.getVideo())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 视频媒体ID校验 */
|
||||
if (StringUtils.isBlank(videoMessage.getVideo().getMedia_id())) {
|
||||
throw new Exception("视频媒体ID不能为空!");
|
||||
}
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus())
|
||||
&& CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus());
|
||||
String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
|
||||
Long sendLogId = msgLogService.createSmsLog(userId, userType, isSend, template, content, templateParams);
|
||||
|
||||
/* if (isSend) {
|
||||
msgProducer.sendSendMsg(sendLogId, content, template.getChannelId(),
|
||||
template.getApiTemplateId(), newTemplateParams);
|
||||
}*/
|
||||
return CommonResult.success(sendLogId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Object> sendFileMsg(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams, FileMessage fileMessage) throws Exception {
|
||||
|
||||
// 校验短信模板是否合法
|
||||
SmsTemplateDO template = validateSmsTemplate(templateCode);
|
||||
// 校验短信渠道是否合法
|
||||
SmsChannelDO smsChannel = validateSmsChannel(template.getChannelId());
|
||||
|
||||
// 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
|
||||
List<KeyValue<String, Object>> newTemplateParams = buildTemplateParams(template, templateParams);
|
||||
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(fileMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(fileMessage.getMsgtype(), WxMsgTypeConstant.FILE.getCode())) {
|
||||
throw new Exception("文件消息类型必须为" + WxMsgTypeConstant.FILE.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(fileMessage.getFile())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 文件媒体ID校验 */
|
||||
if (StringUtils.isBlank(fileMessage.getFile().getMedia_id())) {
|
||||
throw new Exception("文件媒体ID不能为空!");
|
||||
}
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus())
|
||||
&& CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus());
|
||||
String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
|
||||
Long sendLogId = msgLogService.createSmsLog(userId, userType, isSend, template, content, templateParams);
|
||||
|
||||
/* if (isSend) {
|
||||
msgProducer.sendSendMsg(sendLogId, content, template.getChannelId(),
|
||||
template.getApiTemplateId(), newTemplateParams);
|
||||
}*/
|
||||
return CommonResult.success(sendLogId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Object> sendTextCardMsgPich01(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams, TextCardMessage textCardMessage) throws Exception {
|
||||
|
||||
// 校验短信模板是否合法
|
||||
SmsTemplateDO template = validateSmsTemplate(templateCode);
|
||||
// 校验短信渠道是否合法
|
||||
SmsChannelDO smsChannel = validateSmsChannel(template.getChannelId());
|
||||
|
||||
// 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
|
||||
List<KeyValue<String, Object>> newTemplateParams = buildTemplateParams(template, templateParams);
|
||||
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(textCardMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(textCardMessage.getMsgtype(), WxMsgTypeConstant.TEXTCARD.getCode())) {
|
||||
throw new Exception("文本卡片消息类型必须为" + WxMsgTypeConstant.TEXTCARD.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(textCardMessage.getTextcard())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 文本卡片消息标题校验 */
|
||||
if (StringUtils.isBlank(textCardMessage.getTextcard().getTitle())) {
|
||||
throw new Exception("文本卡片消息比标题不能为空!");
|
||||
}
|
||||
/* 文本卡片消息描述校验 */
|
||||
if (StringUtils.isBlank(textCardMessage.getTextcard().getDescription())) {
|
||||
throw new Exception("文本卡片消息描述校验不能为空!");
|
||||
}
|
||||
/* 文本卡片消息点击url校验 */
|
||||
if (StringUtils.isBlank(textCardMessage.getTextcard().getUrl())) {
|
||||
throw new Exception("文本卡片消息点击url校验不能为空!");
|
||||
}
|
||||
/* 文本卡片消息点击url正确性校验 */
|
||||
textCardMessage.getTextcard().setUrl(textCardMessage.getTextcard().getUrl());
|
||||
if (!MatcherSolveUtils.checkInternetURL(textCardMessage.getTextcard().getUrl())) {
|
||||
throw new Exception("消息发送消息内容,点击跳转url不是正确的网络url链接!");
|
||||
}
|
||||
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus())
|
||||
&& CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus());
|
||||
String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
|
||||
Long sendLogId = msgLogService.createSmsLog(userId, userType, isSend, template, content, templateParams);
|
||||
|
||||
/* if (isSend) {
|
||||
msgProducer.sendSendMsg(sendLogId, content, template.getChannelId(),
|
||||
template.getApiTemplateId(), newTemplateParams);
|
||||
}*/
|
||||
return CommonResult.success(sendLogId);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Object> sendTextCardMsg(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams, TextCardMessage textCardMessage) throws Exception {
|
||||
|
||||
// 校验短信模板是否合法
|
||||
SmsTemplateDO template = validateSmsTemplate(templateCode);
|
||||
// 校验短信渠道是否合法
|
||||
SmsChannelDO smsChannel = validateSmsChannel(template.getChannelId());
|
||||
|
||||
// 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
|
||||
List<KeyValue<String, Object>> newTemplateParams = buildTemplateParams(template, templateParams);
|
||||
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(textCardMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(textCardMessage.getMsgtype(), WxMsgTypeConstant.TEXTCARD.getCode())) {
|
||||
throw new Exception("文本卡片消息类型必须为" + WxMsgTypeConstant.TEXTCARD.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(textCardMessage.getTextcard())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 文本卡片消息标题校验 */
|
||||
if (StringUtils.isBlank(textCardMessage.getTextcard().getTitle())) {
|
||||
throw new Exception("文本卡片消息比标题不能为空!");
|
||||
}
|
||||
/* 文本卡片消息描述校验 */
|
||||
if (StringUtils.isBlank(textCardMessage.getTextcard().getDescription())) {
|
||||
throw new Exception("文本卡片消息描述校验不能为空!");
|
||||
}
|
||||
/* 文本卡片消息点击url校验 */
|
||||
if (StringUtils.isBlank(textCardMessage.getTextcard().getUrl())) {
|
||||
throw new Exception("文本卡片消息点击url校验不能为空!");
|
||||
}
|
||||
/* 文本卡片消息点击url正确性校验 */
|
||||
if (!MatcherSolveUtils.checkInternetURL(textCardMessage.getTextcard().getUrl())) {
|
||||
throw new Exception("消息发送消息内容,点击跳转url不是正确的网络url链接!");
|
||||
}
|
||||
|
||||
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus())
|
||||
&& CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus());
|
||||
String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
|
||||
Long sendLogId = msgLogService.createSmsLog(userId, userType, isSend, template, content, templateParams);
|
||||
|
||||
/* if (isSend) {
|
||||
msgProducer.sendSendMsg(sendLogId, content, template.getChannelId(),
|
||||
template.getApiTemplateId(), newTemplateParams);
|
||||
}*/
|
||||
return CommonResult.success(sendLogId);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Object> sendNewsMsg(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams, NewsMessage newsMessage) throws Exception {
|
||||
|
||||
// 校验短信模板是否合法
|
||||
SmsTemplateDO template = validateSmsTemplate(templateCode);
|
||||
// 校验短信渠道是否合法
|
||||
SmsChannelDO smsChannel = validateSmsChannel(template.getChannelId());
|
||||
|
||||
// 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
|
||||
List<KeyValue<String, Object>> newTemplateParams = buildTemplateParams(template, templateParams);
|
||||
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(newsMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(newsMessage.getMsgtype(), WxMsgTypeConstant.NEWS.getCode())) {
|
||||
throw new Exception("图文消息类型必须为" + WxMsgTypeConstant.NEWS.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(newsMessage.getNews())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 图文消息校验 */
|
||||
if (newsMessage.getNews().getArticles().isEmpty()) {
|
||||
throw new Exception("图文消息内容不能为空!");
|
||||
} else {
|
||||
//newsMessage.setAgentid(sysWxAuditConfig.getAgentId());
|
||||
newsMessage.getNews().getArticles().forEach(article -> {
|
||||
/* 消息标题校验 */
|
||||
if (StringUtils.isBlank(article.getTitle())) {
|
||||
try {
|
||||
throw new Exception("图文消息内容标题不能为空!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/* 消息url校验 */
|
||||
if (StringUtils.isBlank(article.getUrl())) {
|
||||
try {
|
||||
throw new Exception("图文消息内容点击url不能为空!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/* 消息url正确性校验 */
|
||||
// article.setUrl(sysWxAuditConfig.getWxContextPath() + article.getUrl());
|
||||
if (!MatcherSolveUtils.checkInternetURL(article.getUrl())) {
|
||||
try {
|
||||
throw new Exception("消息发送消息内容,点击跳转url不是正确的网络url链接!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus())
|
||||
&& CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus());
|
||||
String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
|
||||
Long sendLogId = msgLogService.createSmsLog(userId, userType, isSend, template, content, templateParams);
|
||||
|
||||
/* if (isSend) {
|
||||
msgProducer.sendSendMsg(sendLogId, content, template.getChannelId(),
|
||||
template.getApiTemplateId(), newTemplateParams);
|
||||
}*/
|
||||
return CommonResult.success(sendLogId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Object> sendMpNewsMsg(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams, MpNewsMessage mpNewsMessage) throws Exception {
|
||||
|
||||
// 校验短信模板是否合法
|
||||
SmsTemplateDO template = validateSmsTemplate(templateCode);
|
||||
// 校验短信渠道是否合法
|
||||
SmsChannelDO smsChannel = validateSmsChannel(template.getChannelId());
|
||||
|
||||
// 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
|
||||
List<KeyValue<String, Object>> newTemplateParams = buildTemplateParams(template, templateParams);
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(mpNewsMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(mpNewsMessage.getMsgtype(), WxMsgTypeConstant.MPNEWS.getCode())) {
|
||||
throw new Exception("图文(mpnews)消息类型必须为" + WxMsgTypeConstant.MPNEWS.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(mpNewsMessage.getMpnews())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 图文消息校验 */
|
||||
if (mpNewsMessage.getMpnews().getArticles().isEmpty()) {
|
||||
throw new Exception("图文消息内容不能为空!");
|
||||
} else {
|
||||
mpNewsMessage.getMpnews().getArticles().forEach(article -> {
|
||||
/* 消息标题校验 */
|
||||
if (StringUtils.isBlank(article.getTitle())) {
|
||||
try {
|
||||
throw new Exception("图文消息内容标题不能为空!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/* 消息图片媒体ID校验 */
|
||||
if (StringUtils.isBlank(article.getThumb_media_id())) {
|
||||
try {
|
||||
throw new Exception("图文消息内容图片媒体ID不能为空!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (StringUtils.isBlank(article.getContent())) {
|
||||
try {
|
||||
throw new Exception("图文消息内容能为空!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus())
|
||||
&& CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus());
|
||||
String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
|
||||
Long sendLogId = msgLogService.createSmsLog(userId, userType, isSend, template, content, templateParams);
|
||||
|
||||
/* if (isSend) {
|
||||
msgProducer.sendSendMsg(sendLogId, content, template.getChannelId(),
|
||||
template.getApiTemplateId(), newTemplateParams);
|
||||
}*/
|
||||
return CommonResult.success(sendLogId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Object> sendMarkdownMsg(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams, MarkdownMessage markdownMessage) throws Exception {
|
||||
|
||||
// 校验短信模板是否合法
|
||||
SmsTemplateDO template = validateSmsTemplate(templateCode);
|
||||
// 校验短信渠道是否合法
|
||||
SmsChannelDO smsChannel = validateSmsChannel(template.getChannelId());
|
||||
|
||||
// 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
|
||||
List<KeyValue<String, Object>> newTemplateParams = buildTemplateParams(template, templateParams);
|
||||
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(markdownMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(markdownMessage.getMsgtype(), WxMsgTypeConstant.MARKDOWN.getCode())) {
|
||||
throw new Exception("markdown消息消息类型必须为" + WxMsgTypeConstant.MARKDOWN.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(markdownMessage.getMarkdown())) {
|
||||
throw new Exception("markdown消息内容能为空!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (StringUtils.isBlank(markdownMessage.getMarkdown().getContent())) {
|
||||
throw new Exception("markdown消息内容能为空!");
|
||||
}
|
||||
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus())
|
||||
&& CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus());
|
||||
String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
|
||||
Long sendLogId = msgLogService.createSmsLog(userId, userType, isSend, template, content, templateParams);
|
||||
|
||||
/* if (isSend) {
|
||||
msgProducer.sendSendMsg(sendLogId, content, template.getChannelId(),
|
||||
template.getApiTemplateId(), newTemplateParams);
|
||||
}*/
|
||||
return CommonResult.success(sendLogId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Object> sendMiniProgramNoticeMsg(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams, MiniProgramNoticeMessage miniProgramNoticeMessage) throws Exception {
|
||||
|
||||
// 校验短信模板是否合法
|
||||
SmsTemplateDO template = validateSmsTemplate(templateCode);
|
||||
// 校验短信渠道是否合法
|
||||
SmsChannelDO smsChannel = validateSmsChannel(template.getChannelId());
|
||||
// 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
|
||||
List<KeyValue<String, Object>> newTemplateParams = buildTemplateParams(template, templateParams);
|
||||
|
||||
|
||||
/* 基础信息校验 */
|
||||
if (StringUtils.isAllBlank(miniProgramNoticeMessage.getTouser(), miniProgramNoticeMessage.getToparty(), miniProgramNoticeMessage.getTotag())) {
|
||||
throw new Exception("消息发送对象不能为空!");
|
||||
}
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(miniProgramNoticeMessage.getMsgtype(), WxMsgTypeConstant.MINIPROGRAM_NOTICE.getCode())) {
|
||||
throw new Exception("小程序通知消息消息类型必须为" + WxMsgTypeConstant.MINIPROGRAM_NOTICE.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(miniProgramNoticeMessage.getMiniprogram_notice())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 小程序appid校验 */
|
||||
if (StringUtils.isBlank(miniProgramNoticeMessage.getMiniprogram_notice().getAppid())) {
|
||||
throw new Exception("小程序appid,必须是与当前应用关联的小程序!");
|
||||
}
|
||||
/* 小程序标题校验 */
|
||||
if (StringUtils.isBlank(miniProgramNoticeMessage.getMiniprogram_notice().getTitle())) {
|
||||
throw new Exception("消息标题不能为空,长度限制4-12个汉字!");
|
||||
}
|
||||
/* 小程序消息内容校验 */
|
||||
if (Objects.isNull(miniProgramNoticeMessage.getMiniprogram_notice().getContent_item())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 小程序消息内容校验 */
|
||||
if (miniProgramNoticeMessage.getMiniprogram_notice().getContent_item().isEmpty()) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 小程序消息内容校验key-value校验 */
|
||||
miniProgramNoticeMessage.getMiniprogram_notice().getContent_item().forEach(contentItem -> {
|
||||
/* 小程序消息内容key校验 */
|
||||
if (StringUtils.isBlank(contentItem.getKey())) {
|
||||
try {
|
||||
throw new Exception("小程序消息内容key不能为空!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/* 小程序消息内容value校验 */
|
||||
if (StringUtils.isBlank(contentItem.getValue())) {
|
||||
try {
|
||||
throw new Exception("小程序消息内容value不能为空!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus())
|
||||
&& CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus());
|
||||
String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
|
||||
Long sendLogId = msgLogService.createSmsLog(userId, userType, isSend, template, content, templateParams);
|
||||
|
||||
/* if (isSend) {
|
||||
msgProducer.sendSendMsg(sendLogId, content, template.getChannelId(),
|
||||
template.getApiTemplateId(), newTemplateParams);
|
||||
}*/
|
||||
return CommonResult.success(sendLogId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Object> sendInteractiveTaskCardMsg(Long userId, Integer userType, String templateCode, Map<String, Object> templateParams, InteractiveTaskCardMessage interactiveTaskCardMessage) throws Exception {
|
||||
|
||||
// 校验短信模板是否合法
|
||||
SmsTemplateDO template = validateSmsTemplate(templateCode);
|
||||
// 校验短信渠道是否合法
|
||||
SmsChannelDO smsChannel = validateSmsChannel(template.getChannelId());
|
||||
// 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
|
||||
List<KeyValue<String, Object>> newTemplateParams = buildTemplateParams(template, templateParams);
|
||||
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(interactiveTaskCardMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(interactiveTaskCardMessage.getMsgtype(), WxMsgTypeConstant.INTERACTIVE_TASKCARD.getCode())) {
|
||||
throw new Exception("任务卡片消息消息类型必须为" + WxMsgTypeConstant.INTERACTIVE_TASKCARD.getCode() + "!");
|
||||
}
|
||||
/* 任务卡片消息内容校验 */
|
||||
if (Objects.isNull(interactiveTaskCardMessage.getInteractive_taskcard())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 任务卡片消息内容标题校验 */
|
||||
if (StringUtils.isBlank(interactiveTaskCardMessage.getInteractive_taskcard().getTitle())) {
|
||||
throw new Exception("任务卡片消息内容标题不能为空!");
|
||||
}
|
||||
/* 任务卡片消息url校验 */
|
||||
if (!MatcherSolveUtils.checkInternetURL(interactiveTaskCardMessage.getInteractive_taskcard().getUrl())) {
|
||||
throw new Exception("任务卡片消息内容标题不能为空,点击跳转url不是正确的网络url链接!");
|
||||
}
|
||||
/* 任务卡片消息内容任务id校验 */
|
||||
if (StringUtils.isBlank(interactiveTaskCardMessage.getInteractive_taskcard().getTask_id())) {
|
||||
throw new Exception("任务卡片消息内容任务id不能为空,任务id,同一个应用发送的任务卡片消息的任务id不能重复,只能由数字、字母和“_-@”组成,最长支持128字节!");
|
||||
}
|
||||
/* 任务卡片消息内容按钮组校验 */
|
||||
if (Objects.isNull(interactiveTaskCardMessage.getInteractive_taskcard().getBtn())) {
|
||||
throw new Exception("任务卡片消息内容按钮组不能为空!");
|
||||
}
|
||||
/* 任务卡片消息内容按钮组校验 */
|
||||
interactiveTaskCardMessage.getInteractive_taskcard().getBtn().forEach(btn -> {
|
||||
/* 任务卡片消息内容按钮组按钮key校验 */
|
||||
if (StringUtils.isBlank(interactiveTaskCardMessage.getInteractive_taskcard().getTitle())) {
|
||||
try {
|
||||
throw new Exception("任务卡片消息内容按钮组按钮key不能为空,按钮key值,用户点击后,会产生任务卡片回调事件,回调事件会带上该key值,只能由数字、字母和“_-@”组成,最长支持128字节!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/* 任务卡片消息内容按钮组阿牛name校验 */
|
||||
if (StringUtils.isBlank(interactiveTaskCardMessage.getInteractive_taskcard().getTitle())) {
|
||||
try {
|
||||
throw new Exception("任务卡片消息内容按钮组阿牛name不能为空,按钮名称,最长支持18个字节,超过则截断!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus())
|
||||
&& CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus());
|
||||
String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
|
||||
Long sendLogId = msgLogService.createSmsLog(userId, userType, isSend, template, content, templateParams);
|
||||
|
||||
/* if (isSend) {
|
||||
msgProducer.sendSendMsg(sendLogId, content, template.getChannelId(),
|
||||
template.getApiTemplateId(), newTemplateParams);
|
||||
}*/
|
||||
return CommonResult.success(sendLogId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 企业微信消息发送基础信息校验
|
||||
*
|
||||
* @param baseMessage 企业微信消息体
|
||||
*/
|
||||
private void msgSendBaseCheck(BaseMessage baseMessage) throws Exception{
|
||||
if (StringUtils.isAllBlank(baseMessage.getTouser(), baseMessage.getToparty(), baseMessage.getTotag())) {
|
||||
throw new Exception("消息发送对象不能为空!");
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
SmsTemplateDO validateSmsTemplate(String templateCode) {
|
||||
// 获得短信模板。考虑到效率,从缓存中获取
|
||||
SmsTemplateDO template = smsTemplateService.getSmsTemplateByCodeFromCache(templateCode);
|
||||
// 短信模板不存在
|
||||
if (template == null) {
|
||||
throw exception(MSG_CALLBACK_SIGN_INVALID);
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
|
||||
@VisibleForTesting
|
||||
SmsChannelDO validateSmsChannel(Long channelId) {
|
||||
// 获得短信模板。考虑到效率,从缓存中获取
|
||||
SmsChannelDO channelDO = smsChannelService.getSmsChannel(channelId);
|
||||
// 短信模板不存在
|
||||
if (channelDO == null) {
|
||||
throw exception(MSG_CHANNEL_NOT_EXISTS);
|
||||
}
|
||||
return channelDO;
|
||||
}
|
||||
|
||||
|
||||
@VisibleForTesting
|
||||
List<KeyValue<String, Object>> buildTemplateParams(SmsTemplateDO template, Map<String, Object> templateParams) {
|
||||
return template.getParams().stream().map(key -> {
|
||||
Object value = templateParams.get(key);
|
||||
if (value == null) {
|
||||
throw exception(MSG_CALLBACK_SIGN_INVALID, key);
|
||||
}
|
||||
return new KeyValue<>(key, value);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,587 @@
|
||||
package com.zt.plat.module.system.service.msg.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.util.http.HttpClientUtils;
|
||||
import com.zt.plat.framework.common.util.validation.MatcherSolveUtils;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.WxMsgTypeConstant;
|
||||
import com.zt.plat.module.system.service.msg.config.WeiXinProperties;
|
||||
import com.zt.plat.module.system.dal.dataobject.msg.SysWxAuditConfig;
|
||||
import com.zt.plat.module.system.service.msg.ISendWxMsgService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import com.zt.plat.module.system.controller.admin.sms.vo.msg.*;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.Objects;
|
||||
/**
|
||||
* TODO ================================ 中铝e办MQ生产者 ======================================
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class SendWxMsgServiceImpl implements ISendWxMsgService {
|
||||
|
||||
|
||||
/**
|
||||
* 文本消息内容限制
|
||||
*/
|
||||
public static final int INT_2048 = 2048;
|
||||
/**
|
||||
* 企业微信消息发送响应结果代码key
|
||||
*/
|
||||
public static final String WX_MSG_RESPONSE_CODE = "errcode";
|
||||
/**
|
||||
* 企业微信消息发送成功响应代码值
|
||||
*/
|
||||
public static final String WX_MSG_RESPONSE_SUCCESS_CODE = "0";
|
||||
|
||||
@Resource
|
||||
private WeiXinProperties weiXinProperties;
|
||||
|
||||
/**
|
||||
* 发送企业微信文本消息
|
||||
*
|
||||
* @param textMessage 文本消息对象
|
||||
* @return r 响应对象
|
||||
*/
|
||||
@Override
|
||||
public CommonResult<Object> sendTextMsg(TextMessage textMessage) throws Exception{
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(textMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(textMessage.getMsgtype(), WxMsgTypeConstant.TEXT.getCode())) {
|
||||
throw new Exception("文本消息类型必须为" + WxMsgTypeConstant.TEXT.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(textMessage.getText())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (StringUtils.isBlank(textMessage.getText().getContent())) {
|
||||
throw new Exception("消息发送消息体不能为空!");
|
||||
}
|
||||
/* 消息内容长度检验 */
|
||||
if (textMessage.getText().getContent().length() > INT_2048) {
|
||||
throw new Exception("消息发送消息内容,最长不超过2048个字节,超过将截断!");
|
||||
}
|
||||
/* 消息发送 */
|
||||
SysWxAuditConfig sysWxAuditConfig = this.buildSysWxAuditConfig(textMessage);
|
||||
textMessage.setAgentid(sysWxAuditConfig.getAgentId());
|
||||
/* 如果消息包含点击链接,重新包装处理消息内容 */
|
||||
if (StringUtils.isNotBlank(textMessage.getText().getUrl())) {
|
||||
textMessage.getText().setUrl(sysWxAuditConfig.getWxContextPath() + textMessage.getText().getUrl());
|
||||
/* url校验 */
|
||||
if (!MatcherSolveUtils.checkInternetURL(textMessage.getText().getUrl())) {
|
||||
throw new Exception("消息发送消息内容,点击跳转url不是正确的网络url链接!");
|
||||
}
|
||||
textMessage.getText().buildUrlContent();
|
||||
}
|
||||
JSONObject jsonObject = HttpClientUtils.httpPost(weiXinProperties.buildQySendMsgUrl(sysWxAuditConfig.getCorpId(), sysWxAuditConfig.getCorpSecret()), (JSONObject) JSONObject.toJSON(textMessage));
|
||||
return buildQywxMsgSendResult(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送企业微信图片消息
|
||||
*
|
||||
* @param imageMessage 图片消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
@Override
|
||||
public CommonResult<Object> sendImageMsg(ImageMessage imageMessage) throws Exception{
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(imageMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(imageMessage.getMsgtype(), WxMsgTypeConstant.IMAGE.getCode())) {
|
||||
throw new Exception("图片消息类型必须为" + WxMsgTypeConstant.IMAGE.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(imageMessage.getImage())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 图片媒体ID校验 */
|
||||
if (StringUtils.isBlank(imageMessage.getImage().getMedia_id())) {
|
||||
throw new Exception("图片媒体ID不能为空!");
|
||||
}
|
||||
/* 消息发送 */
|
||||
SysWxAuditConfig sysWxAuditConfig = this.buildSysWxAuditConfig(imageMessage);
|
||||
imageMessage.setAgentid(sysWxAuditConfig.getAgentId());
|
||||
JSONObject jsonObject = HttpClientUtils.httpPost(weiXinProperties.buildQySendMsgUrl(sysWxAuditConfig.getCorpId(), sysWxAuditConfig.getCorpSecret()), (JSONObject) JSONObject.toJSON(imageMessage));
|
||||
System.out.println("图片消息发送返回:" + jsonObject.toJSONString());
|
||||
return buildQywxMsgSendResult(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送企业微信语音消息
|
||||
*
|
||||
* @param voiceMessage 语音消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
@Override
|
||||
public CommonResult<Object> sendVoiceMsg(VoiceMessage voiceMessage) throws Exception{
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(voiceMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(voiceMessage.getMsgtype(), WxMsgTypeConstant.VOICE.getCode())) {
|
||||
throw new Exception("语音消息类型必须为" + WxMsgTypeConstant.VOICE.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(voiceMessage.getVoice())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 语音媒体ID校验 */
|
||||
if (StringUtils.isBlank(voiceMessage.getVoice().getMedia_id())) {
|
||||
throw new Exception("语音媒体ID不能为空!");
|
||||
}
|
||||
/* 消息发送 */
|
||||
SysWxAuditConfig sysWxAuditConfig = this.buildSysWxAuditConfig(voiceMessage);
|
||||
voiceMessage.setAgentid(sysWxAuditConfig.getAgentId());
|
||||
JSONObject jsonObject = HttpClientUtils.httpPost(weiXinProperties.buildQySendMsgUrl(sysWxAuditConfig.getCorpId(), sysWxAuditConfig.getCorpSecret()), (JSONObject) JSONObject.toJSON(voiceMessage));
|
||||
return buildQywxMsgSendResult(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送企业微信视频消息
|
||||
*
|
||||
* @param videoMessage 视频消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
@Override
|
||||
public CommonResult<Object> sendVideoMsg(VideoMessage videoMessage) throws Exception{
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(videoMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(videoMessage.getMsgtype(), WxMsgTypeConstant.VIDEO.getCode())) {
|
||||
throw new Exception("视频消息类型必须为" + WxMsgTypeConstant.VIDEO.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(videoMessage.getVideo())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 视频媒体ID校验 */
|
||||
if (StringUtils.isBlank(videoMessage.getVideo().getMedia_id())) {
|
||||
throw new Exception("视频媒体ID不能为空!");
|
||||
}
|
||||
/* 消息发送 */
|
||||
SysWxAuditConfig sysWxAuditConfig = this.buildSysWxAuditConfig(videoMessage);
|
||||
videoMessage.setAgentid(sysWxAuditConfig.getAgentId());
|
||||
JSONObject jsonObject = HttpClientUtils.httpPost(weiXinProperties.buildQySendMsgUrl(sysWxAuditConfig.getCorpId(), sysWxAuditConfig.getCorpSecret()), (JSONObject) JSONObject.toJSON(videoMessage));
|
||||
return buildQywxMsgSendResult(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送企业微信文件消息
|
||||
*
|
||||
* @param fileMessage 文件消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
@Override
|
||||
public CommonResult<Object> sendFileMsg(FileMessage fileMessage) throws Exception{
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(fileMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(fileMessage.getMsgtype(), WxMsgTypeConstant.FILE.getCode())) {
|
||||
throw new Exception("文件消息类型必须为" + WxMsgTypeConstant.FILE.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(fileMessage.getFile())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 文件媒体ID校验 */
|
||||
if (StringUtils.isBlank(fileMessage.getFile().getMedia_id())) {
|
||||
throw new Exception("文件媒体ID不能为空!");
|
||||
}
|
||||
/* 消息发送 */
|
||||
SysWxAuditConfig sysWxAuditConfig = this.buildSysWxAuditConfig(fileMessage);
|
||||
fileMessage.setAgentid(sysWxAuditConfig.getAgentId());
|
||||
JSONObject jsonObject = HttpClientUtils.httpPost(weiXinProperties.buildQySendMsgUrl(sysWxAuditConfig.getCorpId(), sysWxAuditConfig.getCorpSecret()), (JSONObject) JSONObject.toJSON(fileMessage));
|
||||
return buildQywxMsgSendResult(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送企业微信文本卡片消息
|
||||
*
|
||||
* @param textCardMessage 文本卡片消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
@Override
|
||||
public CommonResult<Object> sendTextCardMsg(TextCardMessage textCardMessage) throws Exception{
|
||||
SysWxAuditConfig sysWxAuditConfig = this.buildSysWxAuditConfig(textCardMessage);
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(textCardMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(textCardMessage.getMsgtype(), WxMsgTypeConstant.TEXTCARD.getCode())) {
|
||||
throw new Exception("文本卡片消息类型必须为" + WxMsgTypeConstant.TEXTCARD.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(textCardMessage.getTextcard())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 文本卡片消息标题校验 */
|
||||
if (StringUtils.isBlank(textCardMessage.getTextcard().getTitle())) {
|
||||
throw new Exception("文本卡片消息比标题不能为空!");
|
||||
}
|
||||
/* 文本卡片消息描述校验 */
|
||||
if (StringUtils.isBlank(textCardMessage.getTextcard().getDescription())) {
|
||||
throw new Exception("文本卡片消息描述校验不能为空!");
|
||||
}
|
||||
/* 文本卡片消息点击url校验 */
|
||||
if (StringUtils.isBlank(textCardMessage.getTextcard().getUrl())) {
|
||||
throw new Exception("文本卡片消息点击url校验不能为空!");
|
||||
}
|
||||
/* 文本卡片消息点击url正确性校验 */
|
||||
textCardMessage.getTextcard().setUrl(sysWxAuditConfig.getWxContextPath() + textCardMessage.getTextcard().getUrl());
|
||||
if (!MatcherSolveUtils.checkInternetURL(textCardMessage.getTextcard().getUrl())) {
|
||||
throw new Exception("消息发送消息内容,点击跳转url不是正确的网络url链接!");
|
||||
}
|
||||
/* 消息发送 */
|
||||
textCardMessage.setAgentid(sysWxAuditConfig.getAgentId());
|
||||
//TODO 此出发中铝 e 办
|
||||
JSONObject jsonObject = HttpClientUtils.httpPost(weiXinProperties.buildQySendMsgUrl(sysWxAuditConfig.getCorpId(), sysWxAuditConfig.getCorpSecret()), (JSONObject) JSONObject.toJSON(textCardMessage));
|
||||
return buildQywxMsgSendResult(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送企业微信文本卡片消息
|
||||
*
|
||||
* @param textCardMessage 文本卡片消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
@Override
|
||||
public CommonResult<Object> sendTextCardMsgPich01(TextCardMessage textCardMessage) throws Exception{
|
||||
|
||||
SysWxAuditConfig sysWxAuditConfig = this.buildSysWxAuditConfig(textCardMessage);
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(textCardMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(textCardMessage.getMsgtype(), WxMsgTypeConstant.TEXTCARD.getCode())) {
|
||||
throw new Exception("文本卡片消息类型必须为" + WxMsgTypeConstant.TEXTCARD.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(textCardMessage.getTextcard())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 文本卡片消息标题校验 */
|
||||
if (StringUtils.isBlank(textCardMessage.getTextcard().getTitle())) {
|
||||
throw new Exception("文本卡片消息比标题不能为空!");
|
||||
}
|
||||
/* 文本卡片消息描述校验 */
|
||||
if (StringUtils.isBlank(textCardMessage.getTextcard().getDescription())) {
|
||||
throw new Exception("文本卡片消息描述校验不能为空!");
|
||||
}
|
||||
/* 文本卡片消息点击url校验 */
|
||||
if (StringUtils.isBlank(textCardMessage.getTextcard().getUrl())) {
|
||||
throw new Exception("文本卡片消息点击url校验不能为空!");
|
||||
}
|
||||
/* 文本卡片消息点击url正确性校验 */
|
||||
textCardMessage.getTextcard().setUrl(textCardMessage.getTextcard().getUrl());
|
||||
if (!MatcherSolveUtils.checkInternetURL(textCardMessage.getTextcard().getUrl())) {
|
||||
throw new Exception("消息发送消息内容,点击跳转url不是正确的网络url链接!");
|
||||
}
|
||||
/* 消息发送 */
|
||||
textCardMessage.setAgentid(sysWxAuditConfig.getAgentId());
|
||||
JSONObject jsonObject = HttpClientUtils.httpPost(weiXinProperties.buildQySendMsgUrl(sysWxAuditConfig.getCorpId(), sysWxAuditConfig.getCorpSecret()), (JSONObject) JSONObject.toJSON(textCardMessage));
|
||||
return buildQywxMsgSendResult(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送企业微信图文消息
|
||||
*
|
||||
* @param newsMessage 图文消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
@Override
|
||||
public CommonResult<Object> sendNewsMsg(NewsMessage newsMessage) throws Exception{
|
||||
|
||||
SysWxAuditConfig sysWxAuditConfig = this.buildSysWxAuditConfig(newsMessage);
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(newsMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(newsMessage.getMsgtype(), WxMsgTypeConstant.NEWS.getCode())) {
|
||||
throw new Exception("图文消息类型必须为" + WxMsgTypeConstant.NEWS.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(newsMessage.getNews())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 图文消息校验 */
|
||||
if (newsMessage.getNews().getArticles().isEmpty()) {
|
||||
throw new Exception("图文消息内容不能为空!");
|
||||
} else {
|
||||
newsMessage.setAgentid(sysWxAuditConfig.getAgentId());
|
||||
newsMessage.getNews().getArticles().forEach(article -> {
|
||||
/* 消息标题校验 */
|
||||
if (StringUtils.isBlank(article.getTitle())) {
|
||||
try {
|
||||
throw new Exception("图文消息内容标题不能为空!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/* 消息url校验 */
|
||||
if (StringUtils.isBlank(article.getUrl())) {
|
||||
try {
|
||||
throw new Exception("图文消息内容点击url不能为空!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/* 消息url正确性校验 */
|
||||
article.setUrl(sysWxAuditConfig.getWxContextPath() + article.getUrl());
|
||||
if (!MatcherSolveUtils.checkInternetURL(article.getUrl())) {
|
||||
try {
|
||||
throw new Exception("消息发送消息内容,点击跳转url不是正确的网络url链接!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/* 消息发送 */
|
||||
JSONObject jsonObject = HttpClientUtils.httpPost(weiXinProperties.buildQySendMsgUrl(sysWxAuditConfig.getCorpId(), sysWxAuditConfig.getCorpSecret()), (JSONObject) JSONObject.toJSON(newsMessage));
|
||||
return buildQywxMsgSendResult(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送企业微信图文消息(mpnews)
|
||||
*
|
||||
* @param mpNewsMessage 图文消息(mpnews)对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
@Override
|
||||
public CommonResult<Object> sendMpNewsMsg(MpNewsMessage mpNewsMessage)throws Exception {
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(mpNewsMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(mpNewsMessage.getMsgtype(), WxMsgTypeConstant.MPNEWS.getCode())) {
|
||||
throw new Exception("图文(mpnews)消息类型必须为" + WxMsgTypeConstant.MPNEWS.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(mpNewsMessage.getMpnews())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 图文消息校验 */
|
||||
if (mpNewsMessage.getMpnews().getArticles().isEmpty()) {
|
||||
throw new Exception("图文消息内容不能为空!");
|
||||
} else {
|
||||
mpNewsMessage.getMpnews().getArticles().forEach(article -> {
|
||||
/* 消息标题校验 */
|
||||
if (StringUtils.isBlank(article.getTitle())) {
|
||||
try {
|
||||
throw new Exception("图文消息内容标题不能为空!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/* 消息图片媒体ID校验 */
|
||||
if (StringUtils.isBlank(article.getThumb_media_id())) {
|
||||
try {
|
||||
throw new Exception("图文消息内容图片媒体ID不能为空!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (StringUtils.isBlank(article.getContent())) {
|
||||
try {
|
||||
throw new Exception("图文消息内容能为空!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/* 消息发送 */
|
||||
SysWxAuditConfig sysWxAuditConfig = this.buildSysWxAuditConfig(mpNewsMessage);
|
||||
mpNewsMessage.setAgentid(sysWxAuditConfig.getAgentId());
|
||||
JSONObject jsonObject = HttpClientUtils.httpPost(weiXinProperties.buildQySendMsgUrl(sysWxAuditConfig.getCorpId(), sysWxAuditConfig.getCorpSecret()), (JSONObject) JSONObject.toJSON(mpNewsMessage));
|
||||
return buildQywxMsgSendResult(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送企业微信markdown消息
|
||||
*
|
||||
* @param markdownMessage markdown消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
@Override
|
||||
public CommonResult<Object> sendMarkdownMsg(MarkdownMessage markdownMessage) throws Exception{
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(markdownMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(markdownMessage.getMsgtype(), WxMsgTypeConstant.MARKDOWN.getCode())) {
|
||||
throw new Exception("markdown消息消息类型必须为" + WxMsgTypeConstant.MARKDOWN.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(markdownMessage.getMarkdown())) {
|
||||
throw new Exception("markdown消息内容能为空!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (StringUtils.isBlank(markdownMessage.getMarkdown().getContent())) {
|
||||
throw new Exception("markdown消息内容能为空!");
|
||||
}
|
||||
/* 消息发送 */
|
||||
SysWxAuditConfig sysWxAuditConfig = this.buildSysWxAuditConfig(markdownMessage);
|
||||
markdownMessage.setAgentid(sysWxAuditConfig.getAgentId());
|
||||
JSONObject jsonObject = HttpClientUtils.httpPost(weiXinProperties.buildQySendMsgUrl(sysWxAuditConfig.getCorpId(), sysWxAuditConfig.getCorpSecret()), (JSONObject) JSONObject.toJSON(markdownMessage));
|
||||
return buildQywxMsgSendResult(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送企业微信小程序通知消息
|
||||
*
|
||||
* @param miniProgramNoticeMessage 小程序通知消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
@Override
|
||||
public CommonResult<Object> sendMiniProgramNoticeMsg(MiniProgramNoticeMessage miniProgramNoticeMessage) throws Exception {
|
||||
/* 基础信息校验 */
|
||||
if (StringUtils.isAllBlank(miniProgramNoticeMessage.getTouser(), miniProgramNoticeMessage.getToparty(), miniProgramNoticeMessage.getTotag())) {
|
||||
throw new Exception("消息发送对象不能为空!");
|
||||
}
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(miniProgramNoticeMessage.getMsgtype(), WxMsgTypeConstant.MINIPROGRAM_NOTICE.getCode())) {
|
||||
throw new Exception("小程序通知消息消息类型必须为" + WxMsgTypeConstant.MINIPROGRAM_NOTICE.getCode() + "!");
|
||||
}
|
||||
/* 消息内容校验 */
|
||||
if (Objects.isNull(miniProgramNoticeMessage.getMiniprogram_notice())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 小程序appid校验 */
|
||||
if (StringUtils.isBlank(miniProgramNoticeMessage.getMiniprogram_notice().getAppid())) {
|
||||
throw new Exception("小程序appid,必须是与当前应用关联的小程序!");
|
||||
}
|
||||
/* 小程序标题校验 */
|
||||
if (StringUtils.isBlank(miniProgramNoticeMessage.getMiniprogram_notice().getTitle())) {
|
||||
throw new Exception("消息标题不能为空,长度限制4-12个汉字!");
|
||||
}
|
||||
/* 小程序消息内容校验 */
|
||||
if (Objects.isNull(miniProgramNoticeMessage.getMiniprogram_notice().getContent_item())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 小程序消息内容校验 */
|
||||
if (miniProgramNoticeMessage.getMiniprogram_notice().getContent_item().isEmpty()) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 小程序消息内容校验key-value校验 */
|
||||
miniProgramNoticeMessage.getMiniprogram_notice().getContent_item().forEach(contentItem -> {
|
||||
/* 小程序消息内容key校验 */
|
||||
if (StringUtils.isBlank(contentItem.getKey())) {
|
||||
try {
|
||||
throw new Exception("小程序消息内容key不能为空!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/* 小程序消息内容value校验 */
|
||||
if (StringUtils.isBlank(contentItem.getValue())) {
|
||||
try {
|
||||
throw new Exception("小程序消息内容value不能为空!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
/* 消息发送 */
|
||||
SysWxAuditConfig sysWxAuditConfig = this.buildSysWxAuditConfig(miniProgramNoticeMessage);
|
||||
miniProgramNoticeMessage.setAgentid(sysWxAuditConfig.getAgentId());
|
||||
JSONObject jsonObject = HttpClientUtils.httpPost(weiXinProperties.buildQySendMsgUrl(sysWxAuditConfig.getCorpId(), sysWxAuditConfig.getCorpSecret()), (JSONObject) JSONObject.toJSON(miniProgramNoticeMessage));
|
||||
return buildQywxMsgSendResult(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送企业微信任务卡片消息
|
||||
*
|
||||
* @param interactiveTaskCardMessage 任务卡片消息对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
@Override
|
||||
public CommonResult<Object> sendInteractiveTaskCardMsg(InteractiveTaskCardMessage interactiveTaskCardMessage) throws Exception {
|
||||
SysWxAuditConfig sysWxAuditConfig = this.buildSysWxAuditConfig(interactiveTaskCardMessage);
|
||||
/* 基础信息校验 */
|
||||
msgSendBaseCheck(interactiveTaskCardMessage);
|
||||
/* 消息类型校验 */
|
||||
if (!Objects.equals(interactiveTaskCardMessage.getMsgtype(), WxMsgTypeConstant.INTERACTIVE_TASKCARD.getCode())) {
|
||||
throw new Exception("任务卡片消息消息类型必须为" + WxMsgTypeConstant.INTERACTIVE_TASKCARD.getCode() + "!");
|
||||
}
|
||||
/* 任务卡片消息内容校验 */
|
||||
if (Objects.isNull(interactiveTaskCardMessage.getInteractive_taskcard())) {
|
||||
throw new Exception("消息内容不能为空!");
|
||||
}
|
||||
/* 任务卡片消息内容标题校验 */
|
||||
if (StringUtils.isBlank(interactiveTaskCardMessage.getInteractive_taskcard().getTitle())) {
|
||||
throw new Exception("任务卡片消息内容标题不能为空!");
|
||||
}
|
||||
/* 任务卡片消息url校验 */
|
||||
interactiveTaskCardMessage.getInteractive_taskcard().setUrl(sysWxAuditConfig.getWxContextPath() + interactiveTaskCardMessage.getInteractive_taskcard().getUrl());
|
||||
if (!MatcherSolveUtils.checkInternetURL(interactiveTaskCardMessage.getInteractive_taskcard().getUrl())) {
|
||||
throw new Exception("任务卡片消息内容标题不能为空,点击跳转url不是正确的网络url链接!");
|
||||
}
|
||||
/* 任务卡片消息内容任务id校验 */
|
||||
if (StringUtils.isBlank(interactiveTaskCardMessage.getInteractive_taskcard().getTask_id())) {
|
||||
throw new Exception("任务卡片消息内容任务id不能为空,任务id,同一个应用发送的任务卡片消息的任务id不能重复,只能由数字、字母和“_-@”组成,最长支持128字节!");
|
||||
}
|
||||
/* 任务卡片消息内容按钮组校验 */
|
||||
if (Objects.isNull(interactiveTaskCardMessage.getInteractive_taskcard().getBtn())) {
|
||||
throw new Exception("任务卡片消息内容按钮组不能为空!");
|
||||
}
|
||||
/* 任务卡片消息内容按钮组校验 */
|
||||
interactiveTaskCardMessage.getInteractive_taskcard().getBtn().forEach(btn -> {
|
||||
/* 任务卡片消息内容按钮组按钮key校验 */
|
||||
if (StringUtils.isBlank(interactiveTaskCardMessage.getInteractive_taskcard().getTitle())) {
|
||||
try {
|
||||
throw new Exception("任务卡片消息内容按钮组按钮key不能为空,按钮key值,用户点击后,会产生任务卡片回调事件,回调事件会带上该key值,只能由数字、字母和“_-@”组成,最长支持128字节!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/* 任务卡片消息内容按钮组阿牛name校验 */
|
||||
if (StringUtils.isBlank(interactiveTaskCardMessage.getInteractive_taskcard().getTitle())) {
|
||||
try {
|
||||
throw new Exception("任务卡片消息内容按钮组阿牛name不能为空,按钮名称,最长支持18个字节,超过则截断!");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
/* 消息发送 */
|
||||
interactiveTaskCardMessage.setAgentid(sysWxAuditConfig.getAgentId());
|
||||
JSONObject jsonObject = HttpClientUtils.httpPost(weiXinProperties.buildQySendMsgUrl(sysWxAuditConfig.getCorpId(), sysWxAuditConfig.getCorpSecret()), (JSONObject) JSONObject.toJSON(interactiveTaskCardMessage));
|
||||
return buildQywxMsgSendResult(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业微信消息发送基础信息校验
|
||||
*
|
||||
* @param baseMessage 企业微信消息体
|
||||
*/
|
||||
private void msgSendBaseCheck(BaseMessage baseMessage) throws Exception{
|
||||
if (StringUtils.isAllBlank(baseMessage.getTouser(), baseMessage.getToparty(), baseMessage.getTotag())) {
|
||||
throw new Exception("消息发送对象不能为空!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取企业微信消息发送应用配置
|
||||
*
|
||||
* @param baseMessage 企业微信消息体
|
||||
* @return SysWxAuditConfig 企业微信消息发送应用配置
|
||||
*/
|
||||
private SysWxAuditConfig buildSysWxAuditConfig(BaseMessage baseMessage) throws Exception{
|
||||
return weiXinProperties.buildSysWxAuditConfig(baseMessage.getAppType());
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理企业微信消息发送结果响应数据
|
||||
* @param jsonObject 企业微信消息发送结果对象
|
||||
* @return R 消息发送响应对象
|
||||
*/
|
||||
private CommonResult<Object> buildQywxMsgSendResult(JSONObject jsonObject) {
|
||||
if (Objects.equals(jsonObject.getString(WX_MSG_RESPONSE_CODE), WX_MSG_RESPONSE_SUCCESS_CODE)) {
|
||||
return CommonResult.success(jsonObject);
|
||||
} else {
|
||||
return CommonResult.error(100029,"发送中铝e办失败{}").setData(jsonObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.zt.plat.module.system.service.msg.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.zt.plat.framework.common.util.http.HttpClientUtils;
|
||||
import com.zt.plat.framework.common.util.security.DESUtil;
|
||||
import com.zt.plat.module.system.dal.dataobject.msg.SysActiveMq;
|
||||
import com.zt.plat.module.system.dal.dataobject.msg.SysActiveMqLog;
|
||||
import com.zt.plat.module.system.dal.mysql.msg.SysActiveMqDao;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.AuditConstants;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.JmsConstant;
|
||||
import com.zt.plat.module.system.service.msg.ISysRocketMqService;
|
||||
import com.zt.plat.module.system.service.msg.config.HttpUrlConfig;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Activemq 消息队列 服务实现类
|
||||
*
|
||||
* @author Dy
|
||||
* @since 2021-07-22
|
||||
*/
|
||||
@Service
|
||||
@Transactional(rollbackFor = {Exception.class, Error.class}, propagation = Propagation.REQUIRES_NEW)
|
||||
public class SysActiveMqServiceImpl extends ServiceImpl<SysActiveMqDao, SysActiveMqLog> implements ISysRocketMqService {
|
||||
|
||||
@Resource
|
||||
private HttpUrlConfig httpUrlConfig;
|
||||
|
||||
|
||||
/**
|
||||
* 保存消息队列消费的消息信息
|
||||
*
|
||||
* @param listenerClassName 队列监听类名
|
||||
* @param tm 消息对象
|
||||
* @param jmsType 消息类型(QUEUE-队列/TOPIC-主题)
|
||||
*/
|
||||
@Override
|
||||
public void saveByTextMessage(String listenerClassName, MessageExt tm, String jmsType) throws Exception {
|
||||
this.saveByTextMessage(listenerClassName, tm, jmsType, JmsConstant.CONSUME_SUCCESS.getCode(), "消费成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存消息队列消费的消息信息
|
||||
*
|
||||
* @param listenerClassName 队列监听类名
|
||||
* @param tm 消息对象
|
||||
* @param jmsType 消息类型(QUEUE-队列/TOPIC-主题)
|
||||
* @param consumeFlag 消费结果(success-成功/failure-失败)
|
||||
* @param consumeMessage 消费失败消息
|
||||
*/
|
||||
@Override
|
||||
public void saveByTextMessage(String listenerClassName, MessageExt tm, String jmsType, String consumeFlag, String consumeMessage) throws Exception {
|
||||
SysActiveMqLog sysActiveMqLog = new SysActiveMqLog();
|
||||
String json = new String(tm.getBody(), StandardCharsets.UTF_8);
|
||||
com.alibaba.fastjson2.JSONObject jsonObject = JSON.parseObject(json);
|
||||
sysActiveMqLog.setTitle(jsonObject.getString("title"))
|
||||
.setDatetime(jsonObject.getString("datetime"))
|
||||
.setPublisher(jsonObject.getString("publisher"))
|
||||
.setContentType(jsonObject.getString("type"))
|
||||
.setConsumeDatetime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")))
|
||||
.setTextContent(jsonObject.getString("content"))
|
||||
.setListenerClassName(listenerClassName)
|
||||
.setJmsType(jmsType)
|
||||
.setConsumeFlag(consumeFlag)
|
||||
.setConsumeMessage(consumeMessage);
|
||||
this.baseMapper.insert(sysActiveMqLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveSunepsByTextMessage(String listenerClassName, MessageExt tm, String jmsType, String consumeFlag, String consumeMessage) throws Exception {
|
||||
|
||||
SysActiveMq sysActiveMq = new SysActiveMq();
|
||||
String json = new String(tm.getBody(), StandardCharsets.UTF_8);
|
||||
com.alibaba.fastjson2.JSONObject jsonObject = JSON.parseObject(json);
|
||||
|
||||
sysActiveMq.setTitle(jsonObject.getString("title"))
|
||||
.setDatetime(jsonObject.getString("datetime"))
|
||||
.setPublisher(jsonObject.getString("publisher"))
|
||||
.setContentType(jsonObject.getString("type"))
|
||||
.setConsumeDatetime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")))
|
||||
.setTextContent(jsonObject.getString("content"))
|
||||
.setListenerClassName(listenerClassName)
|
||||
.setJmsType(jmsType)
|
||||
.setConsumeFlag(consumeFlag)
|
||||
.setConsumeMessage(consumeMessage);
|
||||
String token = Arrays.toString(new DESUtil().encrypt(AuditConstants.TOKEN.getBytes()));
|
||||
HttpClientUtils.httpPostByToken(httpUrlConfig.getHttpContextPath("suneps") + "/ieps/mobile/saveMqLog", JSONObject.toJSONString(sysActiveMq), token);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.zt.plat.module.system.service.msg.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.zt.plat.module.system.dal.dataobject.msg.SysWxAuditConfig;
|
||||
import com.zt.plat.module.system.service.msg.SysWxAuditConfigService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Service
|
||||
public class SysWxAuditConfigImpl implements SysWxAuditConfigService {
|
||||
|
||||
|
||||
@Override
|
||||
public boolean saveBatch(Collection<SysWxAuditConfig> entityList, int batchSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveOrUpdateBatch(Collection<SysWxAuditConfig> entityList, int batchSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateBatchById(Collection<SysWxAuditConfig> entityList, int batchSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveOrUpdate(SysWxAuditConfig entity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysWxAuditConfig getOne(Wrapper<SysWxAuditConfig> queryWrapper, boolean throwEx) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SysWxAuditConfig> getOneOpt(Wrapper<SysWxAuditConfig> queryWrapper, boolean throwEx) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getMap(Wrapper<SysWxAuditConfig> queryWrapper) {
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> V getObj(Wrapper<SysWxAuditConfig> queryWrapper, Function<? super Object, V> mapper) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseMapper<SysWxAuditConfig> getBaseMapper() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<SysWxAuditConfig> getEntityClass() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -72,16 +72,21 @@ public class EbanOAuth2ServiceImpl implements EbanOAuth2Service {
|
||||
throw exception(AUTH_LOGIN_EBAN_TOKEN_INVALID);
|
||||
}
|
||||
|
||||
String workcode = StrUtil.trim(StrUtil.blankToDefault(userInfo.getLoginName(), userInfo.getUsername()));
|
||||
if (StrUtil.isBlank(workcode)) {
|
||||
log.error("E办OAuth2用户信息缺少工号(loginName),无法匹配账号: {}", JSONUtil.toJsonStr(userInfo));
|
||||
throw exception(AUTH_LOGIN_EBAN_TOKEN_INVALID);
|
||||
String loginName = StrUtil.trim(userInfo.getLoginName());
|
||||
AdminUserDO user = null;
|
||||
if (StrUtil.isNotBlank(loginName)) {
|
||||
user = userService.getUserByUsername(loginName);
|
||||
}
|
||||
|
||||
AdminUserDO user = userService.getUserByWorkcode(workcode);
|
||||
// 若未匹配到,再尝试用工号匹配(工号为空则不匹配)
|
||||
if (user == null) {
|
||||
createLoginLog(null, workcode, LoginLogTypeEnum.LOGIN_SOCIAL, LoginResultEnum.BAD_CREDENTIALS);
|
||||
log.warn("E办OAuth2用户工号未在系统中找到对应账号: {}", workcode);
|
||||
String workcode = StrUtil.trim(StrUtil.blankToDefault(userInfo.getLoginName(), userInfo.getUsername()));
|
||||
if (StrUtil.isNotBlank(workcode)) {
|
||||
user = userService.getUserByWorkcode(workcode);
|
||||
}
|
||||
}
|
||||
if (user == null) {
|
||||
createLoginLog(null, loginName, LoginLogTypeEnum.LOGIN_SOCIAL, LoginResultEnum.BAD_CREDENTIALS);
|
||||
log.warn("E办OAuth2 用户未找到匹配账号,loginName={} workcode={}", loginName, userInfo.getUsername());
|
||||
throw exception(AUTH_LOGIN_EBAN_USER_NOT_SYNC);
|
||||
}
|
||||
|
||||
@@ -105,7 +110,7 @@ public class EbanOAuth2ServiceImpl implements EbanOAuth2Service {
|
||||
tokenInfo.getExpiresIn(),
|
||||
userInfo
|
||||
);
|
||||
log.info("成功保存E办token,userId={}, uid={}, workcode={}", user.getId(), userInfo.getUid(), workcode);
|
||||
log.info("成功保存E办token,userId={}, uid={}, workcode={}", user.getId(), userInfo.getUid(), user.getWorkcode());
|
||||
|
||||
return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL, ebanAccessTokenDO);
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.zt.plat.module.system.service.permission;
|
||||
|
||||
import com.zt.plat.framework.common.biz.system.permission.dto.DeptDataPermissionRespDTO;
|
||||
import com.zt.plat.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleMenuItemReqVO;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.RoleMenuDO;
|
||||
import com.zt.plat.module.system.enums.permission.DataScopeEnum;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -153,4 +155,21 @@ public interface PermissionService {
|
||||
*/
|
||||
DataScopeEnum getUserDataPermissionLevel(Long userId);
|
||||
|
||||
/**
|
||||
* 更新菜单是否显示
|
||||
*
|
||||
* @param roleId 用户编号
|
||||
* @param menus 包含菜单编号和是否显示的Bean List
|
||||
* @return
|
||||
*/
|
||||
void updateMenuDisplay(Long roleId, Set<PermissionAssignRoleMenuItemReqVO> menus);
|
||||
|
||||
/**
|
||||
* 根据角色ID和菜单IDS批量查询
|
||||
*
|
||||
* @param ids
|
||||
* @return
|
||||
*/
|
||||
Set<RoleMenuDO> getByRoleIdAndMenuIds(Set<Long> roleIds, Set<Long> ids);
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.Sets;
|
||||
@@ -14,6 +16,7 @@ import com.zt.plat.framework.common.enums.CommonStatusEnum;
|
||||
import com.zt.plat.framework.common.util.collection.CollectionUtils;
|
||||
import com.zt.plat.framework.datapermission.core.annotation.DataPermission;
|
||||
import com.zt.plat.framework.tenant.core.context.DeptContextHolder;
|
||||
import com.zt.plat.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleMenuItemReqVO;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.MenuDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.RoleDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.RoleMenuDO;
|
||||
@@ -45,8 +48,8 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
import static com.zt.plat.framework.common.util.collection.CollectionUtils.*;
|
||||
import static com.zt.plat.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
import static com.zt.plat.framework.common.util.collection.CollectionUtils.singleton;
|
||||
import static com.zt.plat.framework.common.util.json.JsonUtils.toJsonString;
|
||||
import static com.zt.plat.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
import static com.zt.plat.module.system.enums.ErrorCodeConstants.ROLE_CAN_NOT_UPDATE_NORMAL_TYPE_ROLE;
|
||||
@@ -485,4 +488,35 @@ public class PermissionServiceImpl implements PermissionService {
|
||||
return SpringUtil.getBean(getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新菜单是否显示
|
||||
*
|
||||
* @param roleId 用户编号
|
||||
* @param menus 包含菜单编号和是否显示的Bean List
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateMenuDisplay(Long roleId, Set<PermissionAssignRoleMenuItemReqVO> menus) {
|
||||
for (PermissionAssignRoleMenuItemReqVO menu : menus) {
|
||||
if (menu.getShowMenuChanged()) {
|
||||
LambdaUpdateWrapper<RoleMenuDO> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(RoleMenuDO::getRoleId, roleId).eq(RoleMenuDO::getMenuId, menu.getId()).set(RoleMenuDO::getShowMenu, menu.getShowMenu());
|
||||
roleMenuMapper.update(updateWrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleMenuDO> getByRoleIdAndMenuIds(Set<Long> roleIds, Set<Long> ids) {
|
||||
Set<RoleMenuDO> result = new HashSet<>(ids.size());
|
||||
for (Long roleId : roleIds) {
|
||||
LambdaQueryWrapper<RoleMenuDO> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(RoleMenuDO::getRoleId, roleId).in(!ids.isEmpty(),RoleMenuDO::getMenuId, ids);
|
||||
result.addAll(roleMenuMapper.selectList(queryWrapper));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ public class SmsSendServiceImpl implements SmsSendService {
|
||||
|
||||
Long sendLogId = smsLogService.createSmsLog(mobile, userId, userType, isSend, template, content, templateParams);
|
||||
|
||||
// 发送 MQ 消息,异步执行发送短信
|
||||
//TODO 发送 MQ 消息,异步执行发送短信
|
||||
if (isSend) {
|
||||
smsProducer.sendSmsSendMessage(sendLogId, mobile, content, template.getChannelId(),
|
||||
template.getApiTemplateId(), newTemplateParams);
|
||||
|
||||
@@ -190,7 +190,8 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
// 2.1 只更新非空字段
|
||||
AdminUserDO updateObj = new AdminUserDO();
|
||||
updateObj.setId(updateReqVO.getId());
|
||||
if (StrUtil.isNotBlank(updateReqVO.getUsername())) {
|
||||
// iwork 同步时,存在用户名为空的情况,因此改为 isNotEmpty 判断
|
||||
if (StrUtil.isNotEmpty(updateReqVO.getUsername())) {
|
||||
updateObj.setUsername(updateReqVO.getUsername());
|
||||
}
|
||||
if (StrUtil.isNotBlank(updateReqVO.getNickname())) {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.zt.plat.module.system.util;
|
||||
|
||||
import org.apache.commons.text.StringSubstitutor;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 字符串处理工具类
|
||||
*
|
||||
* @author luzemin
|
||||
*/
|
||||
public class StringSolveUtils {
|
||||
|
||||
/**
|
||||
* 使用map集合替换字符串中${key}
|
||||
*
|
||||
* @param str 待替换字符串
|
||||
* @param substituteMap 替代品属性集合
|
||||
* @return 替换后字符串
|
||||
*/
|
||||
public static String placeholderReplace(String str, Map<String, Object> substituteMap) {
|
||||
StringSubstitutor stringSubstitutor = new StringSubstitutor(substituteMap);
|
||||
return stringSubstitutor.replace(str);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
# ================= ????? (PSCS) =================
|
||||
# ?????????http url
|
||||
pscs.commitUrl=/pscs/mobile/doSubmit
|
||||
# ?????????http url
|
||||
pscs.wxSubmitData=/pscs/mobile/doSubmitData
|
||||
# ?????????????http url
|
||||
pscs.commentUrl=/pscs/mobile/getApproveCommentById/
|
||||
# ?????????????http url
|
||||
pscs.todoUrl=/pscs/mobile/getApproveToDoByUserName/
|
||||
# ?????????????http url
|
||||
pscs.doneUrl=/pscs/mobile/getApproveDoneByUserName/
|
||||
# ?????????????http url
|
||||
pscs.finishUrl=/pscs/mobile/getApproveVariablesById/
|
||||
# ???????????http url
|
||||
pscs.storageUrl=http://cg.chncopper.com/storage/
|
||||
# ???????????????
|
||||
pscs.renderBpoContentUrl=/pscs/mobile/renderBpoContent
|
||||
# ?????????
|
||||
pscs.fineReportUrl=https://xs.chxz.com/FineReport/ReportServer
|
||||
# ?????????
|
||||
pscs.fileStorageUrl=https://xs.chxz.com/storage/
|
||||
# ???????
|
||||
pscs.fileViewUrl=https://xs.chxz.com/fv/onlinePreview
|
||||
# ?????pscs????
|
||||
pscs.httpContextPath=https://szh.chxz.com/omc
|
||||
# ?????pscs????????
|
||||
pscs.wxContextPath=http://xs.chxz.com/qywx
|
||||
|
||||
# ================= ????? (BSSIM) =================
|
||||
# ?????????http url
|
||||
bssim.commitUrl=/bssim/mobile/doSubmit
|
||||
# ?????????????http url
|
||||
bssim.commentUrl=/bssim/mobile/getApproveCommentById/
|
||||
# ?????????????http url
|
||||
bssim.todoUrl=/bssim/mobile/getApproveToDoByUserName/
|
||||
# ?????????????http url
|
||||
bssim.doneUrl=/bssim/mobile/getApproveDoneByUserName/
|
||||
# ?????????????http url
|
||||
bssim.finishUrl=/bssim/mobile/getApproveVariablesById/
|
||||
# ???????????http url
|
||||
bssim.storageUrl=http://cg.chncopper.com/storage/
|
||||
# ???????????????
|
||||
bssim.renderBpoContentUrl=/bssim/mobile/renderBpoContent
|
||||
# ?????????
|
||||
bssim.fineReportUrl=https://xs.chxz.com/FineReport/ReportServer
|
||||
# ?????????
|
||||
bssim.fileStorageUrl=https://xs.chxz.com/storage/
|
||||
# ???????
|
||||
bssim.fileViewUrl=https://xs.chxz.com/fv/onlinePreview
|
||||
# ?????bssim????
|
||||
bssim.httpContextPath=https://szh.chxz.com/bssim
|
||||
# ?????bssim????????
|
||||
bssim.wxContextPath=http://xs.chxz.com/qywx
|
||||
|
||||
# ================= ???? (SUNEPS) =================
|
||||
# ????????http url
|
||||
suneps.commitUrl=/ieps/mobile/doSubmit
|
||||
# ????????????http url
|
||||
suneps.commentUrl=/ieps/mobile/getApproveCommentById/
|
||||
# ????????????http url
|
||||
suneps.todoUrl=/ieps/mobile/getApproveToDoByUserName/
|
||||
# ????????????http url
|
||||
suneps.doneUrl=/ieps/mobile/getApproveDoneByUserName/
|
||||
# ??????????http url
|
||||
suneps.storageUrl=https://cg.chncopper.com/storage/
|
||||
# ????suneps????
|
||||
suneps.httpContextPath=http://172.16.34.30/ieps
|
||||
# ????suneps????????
|
||||
suneps.wxContextPath=http://xs.chxz.com/qywx
|
||||
|
||||
# ================= ???? (MARKET) =================
|
||||
# ??????http url
|
||||
market.commitUrl=/ieps/mobile/doSubmit
|
||||
# ??????????http url
|
||||
market.commentUrl=/ieps/mobile/getApproveCommentById/
|
||||
# ?????????http url
|
||||
market.todoUrl=/ieps/mobile/getApproveToDoByUserName/
|
||||
# ??????????http url
|
||||
market.doneUrl=/ieps/mobile/getApproveDoneByUserName/
|
||||
# ????market????
|
||||
market.httpContextPath=http://172.16.34.30/market
|
||||
# ????market????????
|
||||
market.wxContextPath=http://xs.chxz.com/qywx
|
||||
|
||||
# ================= ??????? (DZXS) =================
|
||||
# ???????????http url
|
||||
dzxs.commitUrl=/dzxs/mobile/doSubmit
|
||||
# ???????????????http url
|
||||
dzxs.commentUrl=/dzxs/mobile/getApproveCommentById/
|
||||
# ???????????????http url
|
||||
dzxs.todoUrl=/dzxs/mobile/getApproveToDoByUserName/
|
||||
# ???????????????http url
|
||||
dzxs.doneUrl=/dzxs/mobile/getApproveDoneByUserName/
|
||||
# ???????????????http url
|
||||
dzxs.finishUrl=/dzxs/mobile/getApproveVariablesById/
|
||||
# ?????????????http url
|
||||
dzxs.storageUrl=http://cg.chncopper.com/storage/
|
||||
# ???????????
|
||||
dzxs.fineReportUrl=https://xs.chxz.com/FineReport/ReportServer
|
||||
# ?????????
|
||||
dzxs.fileStorageUrl=https://xs.chxz.com/storage/
|
||||
# ???????
|
||||
dzxs.fileViewUrl=https://xs.chxz.com/fv/onlinePreview
|
||||
# ???????dzxs????
|
||||
dzxs.httpContextPath=http://10.198.0.197
|
||||
# ???????dzxs????????
|
||||
dzxs.wxContextPath=http://xs.chxz.com/qywx
|
||||
|
||||
# ================= ??????? (BOLI) =================
|
||||
# ???????boli????http url
|
||||
boli.commitUrl=/pscs/mobile/doSubmit
|
||||
# ???????boli????????http url
|
||||
boli.commentUrl=/pscs/mobile/getApproveCommentById/
|
||||
# ???????boli????????http url
|
||||
boli.todoUrl=/pscs/mobile/getApproveToDoByUserName/
|
||||
# ???????boli????????http url
|
||||
boli.doneUrl=/pscs/mobile/getApproveDoneByUserName/
|
||||
# ???????boli????????http url
|
||||
boli.finishUrl=/pscs/mobile/getApproveVariablesById/
|
||||
# ???????boli??????http url
|
||||
boli.storageUrl=http://cg.chncopper.com/storage/
|
||||
# ???????boli????
|
||||
boli.fineReportUrl=https://xs.chxz.com/FineReport/ReportServer
|
||||
# ?????????
|
||||
boli.fileStorageUrl=https://xs.chxz.com/storage/
|
||||
# ???????
|
||||
boli.fileViewUrl=https://xs.chxz.com/fv/onlinePreview
|
||||
# ???????boli????
|
||||
boli.httpContextPath=https://szh.chxz.com/boli
|
||||
# ???????boli????????
|
||||
boli.wxContextPath=http://xs.chxz.com/qywx
|
||||
|
||||
# ================= ??????? (LMPS) =================
|
||||
# ???????????http url
|
||||
lmps.commitUrl=/lmps/mobile/doSubmit
|
||||
# ???????????????http url
|
||||
lmps.commentUrl=/lmps/mobile/getApproveCommentById/
|
||||
# ???????????????http url
|
||||
lmps.todoUrl=/lmps/mobile/getApproveToDoByUserName/
|
||||
# ???????????????http url
|
||||
lmps.doneUrl=/lmps/mobile/getApproveDoneByUserName/
|
||||
# ???????????????http url
|
||||
lmps.finishUrl=/lmps/mobile/getApproveVariablesById/
|
||||
# ?????????????http url
|
||||
lmps.storageUrl=http://cg.chncopper.com/storage/
|
||||
# ???????????
|
||||
lmps.fineReportUrl=http://xs.chxz.com/FineReport/ReportServer
|
||||
# ?????????
|
||||
lmps.fileStorageUrl=https://xs.chxz.com/storage/
|
||||
# ???????
|
||||
lmps.fileViewUrl=https://xs.chxz.com/fv/onlinePreview
|
||||
# ???????lmps????
|
||||
lmps.httpContextPath=https://szh.chxz.com/lmps
|
||||
# ???????lmps????????
|
||||
lmps.wxContextPath=http://xs.chxz.com/qywx
|
||||
@@ -0,0 +1,43 @@
|
||||
# ================= ?????? =================
|
||||
|
||||
# ????-??access_token??url
|
||||
qyAccessTokenUrl=https://qw.chinalco.com.cn:8443/cgi-bin/gettoken?corpid=CORP_ID&corpsecret=CORP_SECRET
|
||||
|
||||
# ????-??????url
|
||||
qySendMsgUrl=https://qw.chinalco.com.cn:8443/cgi-bin/message/send?access_token=ACCESS_TOKEN
|
||||
|
||||
# ????-????????Oauth2????url
|
||||
qyAuthorizeUrl=https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&agentid=AGENTID&state=STATE#wechat_redirect
|
||||
|
||||
# ????-????????????url
|
||||
qyUserInfoUrl=https://qw.chinalco.com.cn:8443/cgi-bin/user/getuserinfo?access_token=ACCESS_TOKEN&code=CODE
|
||||
|
||||
# ????url
|
||||
qyUserUrl=https://qw.chinalco.com.cn:8443/cgi-bin/user/get?access_token=ACCESS_TOKEN&userid=USER_ID
|
||||
|
||||
# ????-??????url
|
||||
qyUploadTempFileUrl=https://qw.chinalco.com.cn:8443/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
|
||||
|
||||
# ????-????url
|
||||
qyDeptCreateUrl=
|
||||
|
||||
# ????-????url
|
||||
qyDeptUpdateUrl=
|
||||
|
||||
# ????-????url
|
||||
qyDeptDeleteUrl=
|
||||
|
||||
# ????-??????url
|
||||
qyDeptQueryListUrl=https://qw.chinalco.com.cn:8443/cgi-bin/department/list?access_token=ACCESS_TOKEN&id=DEPARTMENT_ID
|
||||
|
||||
# ????-??????url
|
||||
qyMenuCreateUrl=
|
||||
|
||||
# ????-??????url
|
||||
qyMenuDeleteUrl=
|
||||
|
||||
# ????-??????url
|
||||
qyMenuQueryUrl=
|
||||
|
||||
# ????-ticket??url
|
||||
ticketUrl=https://qw.chinalco.com.cn:8443/cgi-bin/get_jsapi_ticket?access_token=ACCESS_TOKEN
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user