diff --git a/pigx-common/pigx-common-bom/pom.xml b/pigx-common/pigx-common-bom/pom.xml index f4058a431..44a19b03c 100644 --- a/pigx-common/pigx-common-bom/pom.xml +++ b/pigx-common/pigx-common-bom/pom.xml @@ -53,6 +53,9 @@ 1.8.4 8.7.2-jdk17-20240715 3.2.1 + 2.0.1 + 2.3 + 3.1 @@ -414,7 +417,30 @@ org.dromara.sms4j sms4j-spring-boot-starter - ${sms4j.version} + ${sms4j.version} + + + + com.sun.mail + jakarta.mail + ${jakarta.mail.version} + + + + org.dromara.sms4j + sms4j-oa-core + ${sms4j.version} + + + + org.apache.velocity + velocity-engine-core + ${velocity.version} + + + org.apache.velocity.tools + velocity-tools-generic + ${velocity.tool.version} diff --git a/pigx-common/pigx-common-log/src/main/java/com/pig4cloud/pigx/common/log/util/JacksonSensitiveFieldUtil.java b/pigx-common/pigx-common-log/src/main/java/com/pig4cloud/pigx/common/log/util/JacksonSensitiveFieldUtil.java index af0099853..5d7e253c9 100644 --- a/pigx-common/pigx-common-log/src/main/java/com/pig4cloud/pigx/common/log/util/JacksonSensitiveFieldUtil.java +++ b/pigx-common/pigx-common-log/src/main/java/com/pig4cloud/pigx/common/log/util/JacksonSensitiveFieldUtil.java @@ -9,7 +9,7 @@ import lombok.Getter; import lombok.SneakyThrows; /** - * Jackson 脱敏 + * Jackson 脱敏工具类 * * @author lengleng * @date 2024/07/18 @@ -57,6 +57,17 @@ public class JacksonSensitiveFieldUtil { return objectMapper.writeValueAsString(o); } + /** + * 将值写入字符串 + * + * @param value 价值 + * @return {@link String } + */ + @SneakyThrows + public static String writeValueAsString(Object value) { + return objectMapper.writeValueAsString(value); + } + @JsonFilter("filter properties by name") private static class PropertyFilterMixIn { } diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/SmsBizCodeEnum.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/SmsBizCodeEnum.java new file mode 100644 index 000000000..d7bcfad2d --- /dev/null +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/SmsBizCodeEnum.java @@ -0,0 +1,23 @@ +package com.pig4cloud.pigx.admin.api.constant; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * 短信发送编码 + * + * @author lengleng + * @date 2024/7/18 + *

+ * SMS_NORMAL_CODE("SMS_NORMAL_CODE", "普通验证码"), + */ +@RequiredArgsConstructor +public enum SmsBizCodeEnum { + + SMS_NORMAL_CODE("SMS_NORMAL_CODE", "普通验证码"); + + @Getter + private final String code; + + private final String desc; +} diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/SystemConfigTypeEnum.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/SystemConfigTypeEnum.java new file mode 100644 index 000000000..de2d1547a --- /dev/null +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/SystemConfigTypeEnum.java @@ -0,0 +1,54 @@ +package com.pig4cloud.pigx.admin.api.constant; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * 系统配置枚举 + * + * @author lengleng + * @date 2024/7/14 + */ +@RequiredArgsConstructor +public enum SystemConfigTypeEnum { + /** + * 存储 + */ + STORAGE("storage"), + /** + * 短信 + */ + SMS("sms"), + /** + * 网站 + */ + WEBSITE("website"), + /** + * 邮件 + */ + EMAIL("email"), + + + /** + * webhook + */ + WEBHOOK("webhook"), + + /** + * 叮叮 + */ + DINGDING("dingding"), + /** + * 飞书 + */ + FEISHU("feishu"), + /** + * 微信 + */ + WETALK("wetalk"); + + @Getter + private final String value; + + +} diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/dto/MessageEmailDTO.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/dto/MessageEmailDTO.java new file mode 100644 index 000000000..8d4e1fc9d --- /dev/null +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/dto/MessageEmailDTO.java @@ -0,0 +1,72 @@ +package com.pig4cloud.pigx.admin.api.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.experimental.FieldNameConstants; + +import java.util.*; + +/** + * 短信发送 + * + * @author lengleng + * @date 2024/7/18 + */ +@Data +@FieldNameConstants +public class MessageEmailDTO { + + /** + * 邮件列表 + */ + @NotNull + private List mailAddress = new ArrayList<>(); + + /** + * 标题 + */ + @NotBlank + private String title; + + /** + * body + */ + private String body; + + /** + * [HTML全文] + */ + private String html; + + /** + * HTML 值 + */ + private Map htmlValues = new HashMap<>(); + + /** + * CC 列表 + */ + private List ccList = new ArrayList<>(); + + /** + * 密件抄送列表 + */ + private List bccList = new ArrayList<>(); + + /** + * 附件文件 (fileName) + */ + private List attachmentList = new ArrayList<>(); + + /** + * ZIP 名称 + */ + private String zipName; + + /** + * 业务代码 + */ + private String bizCode; + +} diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/dto/MessageHookDTO.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/dto/MessageHookDTO.java new file mode 100644 index 000000000..8e3b72d79 --- /dev/null +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/dto/MessageHookDTO.java @@ -0,0 +1,63 @@ +package com.pig4cloud.pigx.admin.api.dto; + +import lombok.Data; +import lombok.experimental.FieldNameConstants; + +import java.util.ArrayList; +import java.util.List; + +/** + * 短信发送 + * + * @author lengleng + * @date 2024/7/18 + */ +@Data +@FieldNameConstants +public class MessageHookDTO { + + + /** + * 业务代码 + */ + private String bizCode; + + /** + * 通知列表 + */ + private List phoneList = new ArrayList<>(); + + + /** + * 通知全部 + */ + private boolean noticeAll; + + + /** + * 消息类型 + */ + private String messageType; + + + /** + * 留言内容 + */ + private String messageContent; + + /** + * 消息标题 + */ + private String messageTitle; + + /** + * 消息 URL + */ + private String messageUrl; + + /** + * 图片链接 + */ + private String picUrl; + +} diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/dto/MessageSmsDTO.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/dto/MessageSmsDTO.java new file mode 100644 index 000000000..8e78f845d --- /dev/null +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/dto/MessageSmsDTO.java @@ -0,0 +1,99 @@ +package com.pig4cloud.pigx.admin.api.dto; + +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.FieldNameConstants; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; + +/** + * 短信发送 + * + * @author lengleng + * @date 2024/7/18 + */ +@FieldNameConstants +public class MessageSmsDTO { + + /** + * 手机号列表 + */ + @NotNull + @Getter + @Setter + private List mobiles; + + /** + * 业务标识 + */ + @Getter + @Setter + private String bizCode; + + /** + * 模板参数 + */ + @Getter + @Setter + private LinkedHashMap params; + + /** + * ext 参数 + */ + private String extParams; + + /** + * 供应商 + */ + private String supplier; + + + /** + * 模板 ID + */ + private String templateId; + + // Builder类 + public static class Builder { + private MessageSmsDTO dto; + + public Builder() { + dto = new MessageSmsDTO(); + dto.mobiles = new ArrayList<>(); + dto.bizCode = "DEFAULT_CODE"; + dto.params = new LinkedHashMap<>(); + } + + public Builder mobile(String mobile) { + dto.mobiles.add(mobile); + return this; + } + + public Builder biz(String bizCode) { + dto.bizCode = bizCode; + return this; + } + + public Builder param(String key, String value) { + dto.params.put(key, value); + return this; + } + + public Builder param(String value) { + dto.params.put("code", value); + return this; + } + + public MessageSmsDTO build() { + return dto; + } + } + + // 静态方法用于创建Builder实例 + public static Builder builder() { + return new Builder(); + } +} diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysSystemConfigEntity.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysSystemConfigEntity.java new file mode 100644 index 000000000..13e3174c1 --- /dev/null +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysSystemConfigEntity.java @@ -0,0 +1,106 @@ +package com.pig4cloud.pigx.admin.api.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.pig4cloud.pigx.common.core.util.TenantTable; +import lombok.experimental.FieldNameConstants; + +import java.time.LocalDateTime; + +/** + * 系统配置 + * + * @author pig + * @date 2024-07-14 20:58:54 + */ +@Data +@TenantTable +@FieldNameConstants +@TableName("sys_system_config") +@EqualsAndHashCode(callSuper = true) +@Schema(description = "系统配置") +public class SysSystemConfigEntity extends Model { + + + /** + * 主键 + */ + @TableId(type = IdType.ASSIGN_ID) + @Schema(description="主键") + private Long id; + + /** + * 配置类型 + */ + @Schema(description="配置类型") + private String configType; + + /** + * 配置名称 + */ + @Schema(description="配置名称") + private String configName; + + /** + * 配置标识 + */ + @Schema(description="配置标识") + private String configKey; + + /** + * 配置值 + */ + @Schema(description="配置值") + private String configValue; + + /** + * 开启状态 + */ + @Schema(description="开启状态") + private String configStatus; + + /** + * 创建人 + */ + @TableField(fill = FieldFill.INSERT) + @Schema(description="创建人") + private String createBy; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + @Schema(description="创建时间") + private LocalDateTime createTime; + + /** + * 修改人 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + @Schema(description="修改人") + private String updateBy; + + /** + * 修改时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + @Schema(description="修改时间") + private LocalDateTime updateTime; + + /** + * 删除标记 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + @Schema(description="删除标记") + private String delFlag; + + /** + * 租户ID + */ + @Schema(description="租户ID") + private Long tenantId; +} diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteMessageService.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteMessageService.java new file mode 100644 index 000000000..2d5b12520 --- /dev/null +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteMessageService.java @@ -0,0 +1,67 @@ +/* + * + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + * + */ + +package com.pig4cloud.pigx.admin.api.feign; + +import com.pig4cloud.pigx.admin.api.dto.MessageEmailDTO; +import com.pig4cloud.pigx.admin.api.dto.MessageHookDTO; +import com.pig4cloud.pigx.admin.api.dto.MessageSmsDTO; +import com.pig4cloud.pigx.common.core.constant.ServiceNameConstants; +import com.pig4cloud.pigx.common.core.util.R; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +/** + * 远程消息服务 + * + * @author lengleng + * @date 2024/07/18 + */ +@FeignClient(contextId = "remoteMessageService", value = ServiceNameConstants.UPMS_SERVICE) +public interface RemoteMessageService { + + + /** + * 发送短消息 + * + * @param smsDTO 短信 DTO + * @return {@link R } + */ + @PostMapping("/sysMessage/send/sms") + R sendSms(@RequestBody MessageSmsDTO smsDTO); + + /** + * 发送邮件 + * + * @param emailDTO 电子邮件 DTO + * @return {@link R } + */ + @PostMapping("/sysMessage/send/email") + R sendEmail(@RequestBody MessageEmailDTO emailDTO); + + /** + * 发送钩子 + * + * @param hookDTO 钩子 dto + * @return {@link R } + */ + @PostMapping("/sysMessage/send/hook") + R sendHook(@RequestBody MessageHookDTO hookDTO); +} diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/SysSystemSmsConfigVO.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/SysSystemSmsConfigVO.java new file mode 100644 index 000000000..258940927 --- /dev/null +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/SysSystemSmsConfigVO.java @@ -0,0 +1,62 @@ +package com.pig4cloud.pigx.admin.api.vo; + +import com.pig4cloud.pigx.common.sensitive.annotation.Sensitive; +import com.pig4cloud.pigx.common.sensitive.core.SensitiveTypeEnum; +import lombok.Data; + +/** + * 系统短信配置 + * + * @author lengleng + * @date 2024/7/14 + */ +@Data +public class SysSystemSmsConfigVO { + + /** + * 配置标识 + */ + private String configId; + + /** + * 厂商标识 + */ + private String supplier; + + /** + * accessKey + */ + private String accessKeyId; + + /** + * accessKeySecret + */ + @Sensitive(type = SensitiveTypeEnum.KEY) + private String accessKeySecret; + + /** + * 短信签名 + */ + private String signature; + + /** + * 模板ID + */ + private String templateId; + + /** + * sdkAppId + */ + private String sdkAppId; + + /** + * 重试间隔(单位:秒),默认为5秒 + */ + private int retryInterval = 5; + + + /** + * 最大发送数量,默认integer上限 + */ + private int maximum = Integer.MAX_VALUE; +} diff --git a/pigx-upms/pigx-upms-api/src/main/resources/META-INF/spring/org.springframework.cloud.openfeign.FeignClient.imports b/pigx-upms/pigx-upms-api/src/main/resources/META-INF/spring/org.springframework.cloud.openfeign.FeignClient.imports index 9c6fd9992..7a1673f03 100644 --- a/pigx-upms/pigx-upms-api/src/main/resources/META-INF/spring/org.springframework.cloud.openfeign.FeignClient.imports +++ b/pigx-upms/pigx-upms-api/src/main/resources/META-INF/spring/org.springframework.cloud.openfeign.FeignClient.imports @@ -12,3 +12,4 @@ com.pig4cloud.pigx.admin.api.feign.RemoteDictService com.pig4cloud.pigx.admin.api.feign.RemoteAuditLogService com.pig4cloud.pigx.admin.api.feign.RemoteMenuService com.pig4cloud.pigx.admin.api.feign.RemoteRouteConfService +com.pig4cloud.pigx.admin.api.feign.RemoteMessageService diff --git a/pigx-upms/pigx-upms-biz/pom.xml b/pigx-upms/pigx-upms-biz/pom.xml index 8c7530a69..7fb4c3c12 100644 --- a/pigx-upms/pigx-upms-biz/pom.xml +++ b/pigx-upms/pigx-upms-biz/pom.xml @@ -154,6 +154,26 @@ com.github.binarywang weixin-java-cp + + + org.dromara.sms4j + sms4j-spring-boot-starter + + + + com.sun.mail + jakarta.mail + + + + org.dromara.sms4j + sms4j-oa-core + + + + org.apache.velocity + velocity-engine-core + org.springframework.boot diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/MobileController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/MobileController.java deleted file mode 100644 index b38e863c7..000000000 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/MobileController.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2018-2025, lengleng All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * Neither the name of the pig4cloud.com developer nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * Author: lengleng (wangiegie@gmail.com) - */ - -package com.pig4cloud.pigx.admin.controller; - -import com.pig4cloud.pigx.admin.service.MobileService; -import com.pig4cloud.pigx.common.core.util.R; -import com.pig4cloud.pigx.common.security.annotation.Inner; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.AllArgsConstructor; -import org.springframework.http.HttpHeaders; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author lengleng - * @date 2018/11/14 - *

- * 手机验证码 - */ -@RestController -@AllArgsConstructor -@RequestMapping("/mobile") -@Tag(description = "mobile", name = "手机管理模块") -@SecurityRequirement(name = HttpHeaders.AUTHORIZATION) -public class MobileController { - - private final MobileService mobileService; - - @Inner(value = false) - @GetMapping("/{mobile}") - public R sendSmsCode(@PathVariable String mobile) { - return mobileService.sendSmsCode(mobile); - } - -} diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysMessageController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysMessageController.java index 4d0b2bf2b..844f2810a 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysMessageController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysMessageController.java @@ -6,15 +6,20 @@ import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pig4cloud.pigx.admin.api.dto.MessageEmailDTO; +import com.pig4cloud.pigx.admin.api.dto.MessageHookDTO; +import com.pig4cloud.pigx.admin.api.dto.MessageSmsDTO; import com.pig4cloud.pigx.admin.api.entity.SysMessageEntity; import com.pig4cloud.pigx.admin.api.vo.SysMessageVO; import com.pig4cloud.pigx.admin.service.SysMessageService; import com.pig4cloud.pigx.common.core.util.R; import com.pig4cloud.pigx.common.excel.annotation.ResponseExcel; import com.pig4cloud.pigx.common.log.annotation.SysLog; +import com.pig4cloud.pigx.common.security.annotation.Inner; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springdoc.core.annotations.ParameterObject; import org.springframework.http.HttpHeaders; @@ -36,134 +41,188 @@ import java.util.List; @SecurityRequirement(name = HttpHeaders.AUTHORIZATION) public class SysMessageController { - private final SysMessageService sysMessageService; + private final SysMessageService sysMessageService; - /** - * 分页查询 - * @param page 分页对象 - * @param sysMessage 站内信息 - * @return - */ - @Operation(summary = "分页查询", description = "分页查询") - @GetMapping("/page") - @PreAuthorize("@pms.hasPermission('sys_message_view')") - public R getSysMessagePage(@ParameterObject Page page, @ParameterObject SysMessageEntity sysMessage) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); - wrapper.like(StrUtil.isNotBlank(sysMessage.getTitle()), SysMessageEntity::getTitle, sysMessage.getTitle()); - return R.ok(sysMessageService.page(page, wrapper)); - } + /** + * 分页查询 + * + * @param page 分页对象 + * @param sysMessage 站内信息 + * @return + */ + @Operation(summary = "分页查询", description = "分页查询") + @GetMapping("/page") + @PreAuthorize("@pms.hasPermission('sys_message_view')") + public R getSysMessagePage(@ParameterObject Page page, @ParameterObject SysMessageEntity sysMessage) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.like(StrUtil.isNotBlank(sysMessage.getTitle()), SysMessageEntity::getTitle, sysMessage.getTitle()); + return R.ok(sysMessageService.page(page, wrapper)); + } - /** - * 通过id查询站内信息 - * @param id id - * @return R - */ - @Operation(summary = "通过id查询", description = "通过id查询") - @GetMapping("/{id}") - @PreAuthorize("@pms.hasPermission('sys_message_view')") - public R getById(@PathVariable("id") Long id) { - return R.ok(sysMessageService.getMessage(id)); - } + /** + * 通过id查询站内信息 + * + * @param id id + * @return R + */ + @Operation(summary = "通过id查询", description = "通过id查询") + @GetMapping("/{id}") + @PreAuthorize("@pms.hasPermission('sys_message_view')") + public R getById(@PathVariable("id") Long id) { + return R.ok(sysMessageService.getMessage(id)); + } - /** - * 新增站内信息 - * @param sysMessage 站内信息 - * @return R - */ - @Operation(summary = "新增站内信息", description = "新增站内信息") - @SysLog("新增站内信息") - @PostMapping - @PreAuthorize("@pms.hasPermission('sys_message_add')") - public R save(@RequestBody SysMessageVO sysMessage) { - return R.ok(sysMessageService.saveOrUpdateMessage(sysMessage)); - } + /** + * 新增站内信息 + * + * @param sysMessage 站内信息 + * @return R + */ + @Operation(summary = "新增站内信息", description = "新增站内信息") + @SysLog("新增站内信息") + @PostMapping + @PreAuthorize("@pms.hasPermission('sys_message_add')") + public R save(@RequestBody SysMessageVO sysMessage) { + return R.ok(sysMessageService.saveOrUpdateMessage(sysMessage)); + } - /** - * 修改站内信息 - * @param sysMessage 站内信息 - * @return R - */ - @Operation(summary = "修改站内信息", description = "修改站内信息") - @SysLog("修改站内信息") - @PutMapping - @PreAuthorize("@pms.hasPermission('sys_message_edit')") - public R updateById(@RequestBody SysMessageVO sysMessage) { - return R.ok(sysMessageService.saveOrUpdateMessage(sysMessage)); - } + /** + * 修改站内信息 + * + * @param sysMessage 站内信息 + * @return R + */ + @Operation(summary = "修改站内信息", description = "修改站内信息") + @SysLog("修改站内信息") + @PutMapping + @PreAuthorize("@pms.hasPermission('sys_message_edit')") + public R updateById(@RequestBody SysMessageVO sysMessage) { + return R.ok(sysMessageService.saveOrUpdateMessage(sysMessage)); + } - /** - * 通过id删除站内信息 - * @param ids id列表 - * @return R - */ - @Operation(summary = "通过id删除站内信息", description = "通过id删除站内信息") - @SysLog("通过id删除站内信息") - @DeleteMapping - @PreAuthorize("@pms.hasPermission('sys_message_del')") - public R removeById(@RequestBody Long[] ids) { - return R.ok(sysMessageService.removeBatchByIds(CollUtil.toList(ids))); - } + /** + * 通过id删除站内信息 + * + * @param ids id列表 + * @return R + */ + @Operation(summary = "通过id删除站内信息", description = "通过id删除站内信息") + @SysLog("通过id删除站内信息") + @DeleteMapping + @PreAuthorize("@pms.hasPermission('sys_message_del')") + public R removeById(@RequestBody Long[] ids) { + return R.ok(sysMessageService.removeBatchByIds(CollUtil.toList(ids))); + } - /** - * 导出excel 表格 - * @param sysMessage 查询条件 - * @param ids 导出指定ID - * @return excel 文件流 - */ - @ResponseExcel - @GetMapping("/export") - @PreAuthorize("@pms.hasPermission('sys_message_export')") - public List export(SysMessageEntity sysMessage, Long[] ids) { - return sysMessageService - .list(Wrappers.lambdaQuery(sysMessage).in(ArrayUtil.isNotEmpty(ids), SysMessageEntity::getId, ids)); - } + /** + * 导出excel 表格 + * + * @param sysMessage 查询条件 + * @param ids 导出指定ID + * @return excel 文件流 + */ + @ResponseExcel + @GetMapping("/export") + @PreAuthorize("@pms.hasPermission('sys_message_export')") + public List export(SysMessageEntity sysMessage, Long[] ids) { + return sysMessageService + .list(Wrappers.lambdaQuery(sysMessage).in(ArrayUtil.isNotEmpty(ids), SysMessageEntity::getId, ids)); + } - /** - * 发送站内信息 - * @param id 站内信息 - * @return R - */ - @Operation(summary = "发送站内信息", description = "发送站内信息") - @SysLog("发送站内信息") - @PostMapping("/send") - @PreAuthorize("@pms.hasPermission('sys_message_add')") - public R send(Long id) { - return R.ok(sysMessageService.sendMessage(id)); - } + /** + * 发送站内信息 + * + * @param id 站内信息 + * @return R + */ + @Operation(summary = "发送站内信息", description = "发送站内信息") + @SysLog("发送站内信息") + @PostMapping("/send") + @PreAuthorize("@pms.hasPermission('sys_message_add')") + public R send(Long id) { + return R.ok(sysMessageService.sendMessage(id)); + } - /** - * 读取站内信息 - * @param id 站内信息 - * @return R - */ - @Operation(summary = "读取站内信息", description = "读取站内信息") - @SysLog("发送站内信息") - @PostMapping("/read") - public R read(Long id) { - return R.ok(sysMessageService.readMessage(id)); - } + /** + * 读取站内信息 + * + * @param id 站内信息 + * @return R + */ + @Operation(summary = "读取站内信息", description = "读取站内信息") + @SysLog("发送站内信息") + @PostMapping("/read") + public R read(Long id) { + return R.ok(sysMessageService.readMessage(id)); + } - /** - * 查询用户公告 - * @param page 分页条件 - * @param sysMessage 查询条件 - * @return list - */ - @Operation(summary = "查询用户信", description = "查询用户信") - @GetMapping("/user/page") - public R getUserMessageList(@ParameterObject Page page, SysMessageVO sysMessage) { - return R.ok(sysMessageService.pageUserMessage(page, sysMessage)); - } + /** + * 查询用户公告 + * + * @param page 分页条件 + * @param sysMessage 查询条件 + * @return list + */ + @Operation(summary = "查询用户信", description = "查询用户信") + @GetMapping("/user/page") + public R getUserMessageList(@ParameterObject Page page, SysMessageVO sysMessage) { + return R.ok(sysMessageService.pageUserMessage(page, sysMessage)); + } - /** - * 查询信息阅读列表 - * @return list - */ - @Operation(summary = "查询用户阅读情况", description = "查询用户阅读情况") - @GetMapping("/user/read/page") - public R getUserMessageList(@ParameterObject Page page, @ParameterObject Long messageId, - @ParameterObject @RequestParam(required = false) String name) { - return R.ok(sysMessageService.pageUserRead(page, messageId, name)); - } + /** + * 查询信息阅读列表 + * + * @return list + */ + @Operation(summary = "查询用户阅读情况", description = "查询用户阅读情况") + @GetMapping("/user/read/page") + public R getUserMessageList(@ParameterObject Page page, @ParameterObject Long messageId, + @ParameterObject @RequestParam(required = false) String name) { + return R.ok(sysMessageService.pageUserRead(page, messageId, name)); + } + /** + * 发送短信验证码 + * + * @param mobile 手机号 + * @return {@link R } + */ + @Inner(value = false) + @GetMapping("/send/smsCode") + public R sendSmsCode(@RequestParam String mobile) { + return sysMessageService.sendSmsCode(mobile); + } + + /** + * 发送短信 + * + * @param messageSmsDTO 消息 短信 DTO + * @return {@link R } + */ + @PostMapping("/send/sms") + public R sendSms(@Valid @RequestBody MessageSmsDTO messageSmsDTO) { + return sysMessageService.sendSms(messageSmsDTO); + } + + /** + * 发送邮件 + * + * @param messageEmailDTO 留言内容 电子邮件 DTO + * @return {@link R } + */ + @PostMapping("/send/email") + public R sendEmail(@Valid @RequestBody MessageEmailDTO messageEmailDTO) { + return sysMessageService.sendEmail(messageEmailDTO); + } + + /** + * 发送 webhook + * + * @param messageHookDTO 消息挂钩 DTO + * @return {@link R } + */ + @PostMapping("/send/webhook") + public R sendWebhook(@Valid @RequestBody MessageHookDTO messageHookDTO) { + return sysMessageService.sendHook(messageHookDTO); + } } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysSystemConfigController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysSystemConfigController.java new file mode 100644 index 000000000..312b2e8d1 --- /dev/null +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysSystemConfigController.java @@ -0,0 +1,122 @@ +package com.pig4cloud.pigx.admin.controller; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ArrayUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pig4cloud.pigx.admin.api.entity.SysSystemConfigEntity; +import com.pig4cloud.pigx.admin.service.SysSystemConfigService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.excel.annotation.ResponseExcel; +import com.pig4cloud.pigx.common.log.annotation.SysLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.http.HttpHeaders; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 系统配置 + * + * @author pig + * @date 2024-07-14 20:58:54 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/system-config") +@Tag(description = "sysSystemConfig", name = "系统配置管理") +@SecurityRequirement(name = HttpHeaders.AUTHORIZATION) +public class SysSystemConfigController { + + private final SysSystemConfigService sysSystemConfigService; + + /** + * 分页查询 + * + * @param page 分页对象 + * @param sysSystemConfig 系统配置 + * @return + */ + @Operation(summary = "分页查询", description = "分页查询") + @GetMapping("/page") + @PreAuthorize("@pms.hasPermission('sys_message_view')") + public R getSysSystemConfigPage(@ParameterObject Page page, @ParameterObject SysSystemConfigEntity sysSystemConfig) { + return sysSystemConfigService.pageSystemConfig(page, sysSystemConfig); + } + + + /** + * 通过条件查询系统配置 + * + * @param sysSystemConfig 查询条件 + * @return R 对象列表 + */ + @Operation(summary = "通过条件查询", description = "通过条件查询对象") + @GetMapping("/details") + @PreAuthorize("@pms.hasPermission('sys_message_view')") + public R getDetails(@ParameterObject SysSystemConfigEntity sysSystemConfig) { + return sysSystemConfigService.listSystemConfig(sysSystemConfig); + } + + /** + * 新增系统配置 + * + * @param sysSystemConfig 系统配置 + * @return R + */ + @Operation(summary = "新增系统配置", description = "新增系统配置") + @SysLog("新增系统配置") + @PostMapping + @PreAuthorize("@pms.hasPermission('sys_message_add')") + public R save(@RequestBody SysSystemConfigEntity sysSystemConfig) { + return R.ok(sysSystemConfigService.save(sysSystemConfig)); + } + + /** + * 修改系统配置 + * + * @param sysSystemConfig 系统配置 + * @return R + */ + @Operation(summary = "修改系统配置", description = "修改系统配置") + @SysLog("修改系统配置") + @PutMapping + @PreAuthorize("@pms.hasPermission('sys_message_edit')") + public R updateById(@RequestBody SysSystemConfigEntity sysSystemConfig) { + return sysSystemConfigService.updateSystemConfig(sysSystemConfig); + } + + /** + * 通过id删除系统配置 + * + * @param ids id列表 + * @return R + */ + @Operation(summary = "通过id删除系统配置", description = "通过id删除系统配置") + @SysLog("通过id删除系统配置") + @DeleteMapping + @PreAuthorize("@pms.hasPermission('sys_message_del')") + public R removeById(@RequestBody Long[] ids) { + return R.ok(sysSystemConfigService.removeBatchByIds(CollUtil.toList(ids))); + } + + + /** + * 导出excel 表格 + * + * @param sysSystemConfig 查询条件 + * @param ids 导出指定ID + * @return excel 文件流 + */ + @ResponseExcel + @GetMapping("/export") + @PreAuthorize("@pms.hasPermission('sys_message_export')") + public List export(SysSystemConfigEntity sysSystemConfig, Long[] ids) { + return sysSystemConfigService.list(Wrappers.lambdaQuery(sysSystemConfig).in(ArrayUtil.isNotEmpty(ids), SysSystemConfigEntity::getId, ids)); + } +} diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/mapper/SysSystemConfigMapper.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/mapper/SysSystemConfigMapper.java new file mode 100644 index 000000000..4602e8367 --- /dev/null +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/mapper/SysSystemConfigMapper.java @@ -0,0 +1,10 @@ +package com.pig4cloud.pigx.admin.mapper; + +import com.pig4cloud.pigx.admin.api.entity.SysSystemConfigEntity; +import com.pig4cloud.pigx.common.data.datascope.PigxBaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SysSystemConfigMapper extends PigxBaseMapper { + +} diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/MobileService.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/MobileService.java deleted file mode 100644 index 684446dc7..000000000 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/MobileService.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2018-2025, lengleng All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * Neither the name of the pig4cloud.com developer nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * Author: lengleng (wangiegie@gmail.com) - */ - -package com.pig4cloud.pigx.admin.service; - -import com.pig4cloud.pigx.common.core.util.R; - -/** - * @author lengleng - * @date 2018/11/14 - */ -public interface MobileService { - - /** - * 发送手机验证码 - * @param mobile mobile - * @return code - */ - R sendSmsCode(String mobile); - -} diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysMessageService.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysMessageService.java index 886610514..3e27142da 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysMessageService.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysMessageService.java @@ -3,52 +3,93 @@ package com.pig4cloud.pigx.admin.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.admin.api.dto.MessageEmailDTO; +import com.pig4cloud.pigx.admin.api.dto.MessageHookDTO; +import com.pig4cloud.pigx.admin.api.dto.MessageSmsDTO; import com.pig4cloud.pigx.admin.api.entity.SysMessageEntity; import com.pig4cloud.pigx.admin.api.vo.SysMessageVO; +import com.pig4cloud.pigx.common.core.util.R; public interface SysMessageService extends IService { - /** - * 发送信息 - * @param id 消息ID - * @return true/false - */ - Boolean sendMessage(Long id); + /** + * 发送信息 + * + * @param id 消息ID + * @return true/false + */ + Boolean sendMessage(Long id); - /** - * 保存 - * @param sysMessage 消息 - * @return true/false - */ - Boolean saveOrUpdateMessage(SysMessageVO sysMessage); + /** + * 保存 + * + * @param sysMessage 消息 + * @return true/false + */ + Boolean saveOrUpdateMessage(SysMessageVO sysMessage); - /** - * 获取用户的信息列表 - * @return list - */ - IPage pageUserMessage(Page page, SysMessageVO sysMessage); + /** + * 获取用户的信息列表 + * + * @return list + */ + IPage pageUserMessage(Page page, SysMessageVO sysMessage); - /** - * 读取信息 - * @param id id - * @return true/false - */ - Boolean readMessage(Long id); + /** + * 读取信息 + * + * @param id id + * @return true/false + */ + Boolean readMessage(Long id); - /** - * 获取信息 - * @param id id - * @return messageVO - */ - SysMessageVO getMessage(Long id); + /** + * 获取信息 + * + * @param id id + * @return messageVO + */ + SysMessageVO getMessage(Long id); - /** - * 查询用户阅读情况 - * @param page 分页 - * @param messageId 消息ID - * @param name 姓名 - * @return page - */ - Page pageUserRead(Page page, Long messageId, String name); + /** + * 查询用户阅读情况 + * + * @param page 分页 + * @param messageId 消息ID + * @param name 姓名 + * @return page + */ + Page pageUserRead(Page page, Long messageId, String name); + /** + * 发送手机验证码 + * + * @param mobile mobile + * @return code + */ + R sendSmsCode(String mobile); + + /** + * 发送短信 + * + * @param messageSmsDTO 消息 短信 DTO + * @return {@link R } + */ + R sendSms(MessageSmsDTO messageSmsDTO); + + /** + * 发送邮件 + * + * @param messageEmailDTO 留言内容 电子邮件 DTO + * @return {@link R } + */ + R sendEmail(MessageEmailDTO messageEmailDTO); + + /** + * 发送钩子消息 + * + * @param messageHookDTO 消息挂钩 DTO + * @return {@link R } + */ + R sendHook(MessageHookDTO messageHookDTO); } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysSystemConfigService.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysSystemConfigService.java new file mode 100644 index 000000000..ae8d6c038 --- /dev/null +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysSystemConfigService.java @@ -0,0 +1,40 @@ +package com.pig4cloud.pigx.admin.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.admin.api.entity.SysSystemConfigEntity; +import com.pig4cloud.pigx.common.core.util.R; + +/** + * SYS 系统配置服务 + * + * @author lengleng + * @date 2024/07/18 + */ +public interface SysSystemConfigService extends IService { + + /** + * 列出系统配置 + * + * @param query 查询 + * @return {@link R } + */ + R listSystemConfig(SysSystemConfigEntity query); + + /** + * 系统配置 + * + * @param page 页 + * @param sysSystemConfig sys 系统配置 + * @return {@link R } + */ + R pageSystemConfig(Page page, SysSystemConfigEntity sysSystemConfig); + + /** + * 更新系统配置 + * + * @param sysSystemConfig sys 系统配置 + * @return {@link R } + */ + R updateSystemConfig(SysSystemConfigEntity sysSystemConfig); +} diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/MobileServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/MobileServiceImpl.java deleted file mode 100644 index 487f82182..000000000 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/MobileServiceImpl.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2018-2025, lengleng All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * Neither the name of the pig4cloud.com developer nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * Author: lengleng (wangiegie@gmail.com) - */ - -package com.pig4cloud.pigx.admin.service.impl; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.RandomUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.toolkit.StringPool; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import com.pig4cloud.pigx.admin.api.entity.SysUser; -import com.pig4cloud.pigx.admin.mapper.SysUserMapper; -import com.pig4cloud.pigx.admin.service.MobileService; -import com.pig4cloud.pigx.common.core.constant.CacheConstants; -import com.pig4cloud.pigx.common.core.constant.SecurityConstants; -import com.pig4cloud.pigx.common.core.constant.enums.LoginTypeEnum; -import com.pig4cloud.pigx.common.core.exception.ErrorCodes; -import com.pig4cloud.pigx.common.core.util.MsgUtils; -import com.pig4cloud.pigx.common.core.util.R; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * @author lengleng - * @date 2018/11/14 - *

- * 手机登录相关业务实现 - */ -@Slf4j -@Service -@AllArgsConstructor -public class MobileServiceImpl implements MobileService { - - private final StringRedisTemplate redisTemplate; - - private final SysUserMapper userMapper; - - /** - * 发送手机验证码 TODO: 调用短信网关发送验证码,测试返回前端 - * @param mobile mobile - * @return code - */ - @Override - public R sendSmsCode(String mobile) { - List userList = userMapper - .selectList(Wrappers.query().lambda().eq(SysUser::getPhone, mobile)); - - if (CollUtil.isEmpty(userList)) { - log.info("手机号未注册:{}", mobile); - return R.ok(Boolean.FALSE, MsgUtils.getMessage(ErrorCodes.SYS_APP_PHONE_UNREGISTERED, mobile)); - } - - String codeObj = redisTemplate.opsForValue() - .get(CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + mobile); - - if (StrUtil.isNotBlank(codeObj)) { - log.info("手机号验证码未过期:{},{}", mobile, codeObj); - return R.ok(Boolean.FALSE, MsgUtils.getMessage(ErrorCodes.SYS_APP_SMS_OFTEN)); - } - - String code = RandomUtil.randomNumbers(Integer.parseInt(SecurityConstants.CODE_SIZE)); - log.debug("手机号生成验证码成功:{},{}", mobile, code); - redisTemplate.opsForValue() - .set(CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + mobile, code, - SecurityConstants.CODE_TIME, TimeUnit.SECONDS); - return R.ok(Boolean.TRUE, code); - } - -} diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMessageServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMessageServiceImpl.java index 2671d115d..a0cf24937 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMessageServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMessageServiceImpl.java @@ -1,31 +1,91 @@ package com.pig4cloud.pigx.admin.service.impl; +import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.mail.MailAccount; +import cn.hutool.extra.mail.MailUtil; +import cn.hutool.extra.template.Template; +import cn.hutool.extra.template.TemplateConfig; +import cn.hutool.extra.template.TemplateEngine; +import cn.hutool.extra.template.TemplateUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.amazonaws.services.s3.model.S3Object; import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.github.yulichang.wrapper.MPJLambdaWrapper; -import com.pig4cloud.pigx.admin.api.entity.SysMessageEntity; -import com.pig4cloud.pigx.admin.api.entity.SysMessageRelationEntity; -import com.pig4cloud.pigx.admin.api.entity.SysUser; +import com.pig4cloud.pigx.admin.api.constant.SmsBizCodeEnum; +import com.pig4cloud.pigx.admin.api.constant.SystemConfigTypeEnum; +import com.pig4cloud.pigx.admin.api.dto.MessageEmailDTO; +import com.pig4cloud.pigx.admin.api.dto.MessageHookDTO; +import com.pig4cloud.pigx.admin.api.dto.MessageSmsDTO; +import com.pig4cloud.pigx.admin.api.dto.SysLogDTO; +import com.pig4cloud.pigx.admin.api.entity.*; +import com.pig4cloud.pigx.admin.api.feign.RemoteLogService; import com.pig4cloud.pigx.admin.api.vo.OrgTreeVO; import com.pig4cloud.pigx.admin.api.vo.SysMessageReadVO; import com.pig4cloud.pigx.admin.api.vo.SysMessageVO; -import com.pig4cloud.pigx.admin.mapper.SysMessageMapper; -import com.pig4cloud.pigx.admin.mapper.SysMessageRelationMapper; -import com.pig4cloud.pigx.admin.mapper.SysUserMapper; +import com.pig4cloud.pigx.admin.mapper.*; import com.pig4cloud.pigx.admin.service.SysMessageService; +import com.pig4cloud.pigx.common.core.constant.CacheConstants; +import com.pig4cloud.pigx.common.core.constant.SecurityConstants; +import com.pig4cloud.pigx.common.core.constant.enums.LoginTypeEnum; import com.pig4cloud.pigx.common.core.constant.enums.YesNoEnum; +import com.pig4cloud.pigx.common.core.exception.CheckedException; +import com.pig4cloud.pigx.common.core.exception.ErrorCodes; +import com.pig4cloud.pigx.common.core.util.MsgUtils; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder; +import com.pig4cloud.pigx.common.file.core.FileTemplate; +import com.pig4cloud.pigx.common.log.util.JacksonSensitiveFieldUtil; +import com.pig4cloud.pigx.common.log.util.LogTypeEnum; +import com.pig4cloud.pigx.common.log.util.SysLogUtils; import com.pig4cloud.pigx.common.security.util.SecurityUtils; import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.dromara.oa.api.OaSender; +import org.dromara.oa.comm.entity.Request; +import org.dromara.oa.comm.enums.MessageType; +import org.dromara.oa.comm.enums.OaType; +import org.dromara.oa.core.byteTalk.config.ByteTalkConfig; +import org.dromara.oa.core.dingTalk.config.DingTalkConfig; +import org.dromara.oa.core.provider.factory.OaFactory; +import org.dromara.oa.core.weTalk.config.WeTalkConfig; +import org.dromara.sms4j.aliyun.config.AlibabaConfig; +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.cloopen.config.CloopenConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.ctyun.config.CtyunConfig; +import org.dromara.sms4j.dingzhong.config.DingZhongConfig; +import org.dromara.sms4j.emay.config.EmayConfig; +import org.dromara.sms4j.huawei.config.HuaweiConfig; +import org.dromara.sms4j.jdcloud.config.JdCloudConfig; +import org.dromara.sms4j.netease.config.NeteaseConfig; +import org.dromara.sms4j.provider.config.BaseConfig; +import org.dromara.sms4j.qiniu.config.QiNiuConfig; +import org.dromara.sms4j.tencent.config.TencentConfig; +import org.dromara.sms4j.unisms.config.UniConfig; +import org.dromara.sms4j.yunpian.config.YunpianConfig; +import org.dromara.sms4j.zhutong.config.ZhutongConfig; import org.springframework.beans.BeanUtils; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** @@ -34,161 +94,381 @@ import java.util.stream.Collectors; * @author pig * @date 2023-10-25 13:37:25 */ +@Slf4j @Service @RequiredArgsConstructor -public class SysMessageServiceImpl extends ServiceImpl - implements SysMessageService { +public class SysMessageServiceImpl extends ServiceImpl implements SysMessageService { - private final SysMessageRelationMapper relationMapper; + /** + * 支持短信服务商 + */ + private static final Class[] SUPPORT_CONFIG_CLAZZ = {AlibabaConfig.class, CloopenConfig.class, CtyunConfig.class, EmayConfig.class, HuaweiConfig.class, JdCloudConfig.class, NeteaseConfig.class, TencentConfig.class, UniConfig.class, YunpianConfig.class, ZhutongConfig.class, DingZhongConfig.class, QiNiuConfig.class}; - private final SysUserMapper userMapper; + private final RemoteLogService remoteLogService; - /** - * 发送信息 - * @param id id - * @return true/false - */ - @Override - @Transactional(rollbackFor = Exception.class) - public Boolean sendMessage(Long id) { - // 更新信息状态 - SysMessageEntity sysMessage = new SysMessageEntity(); - sysMessage.setSendFlag(YesNoEnum.YES.getCode()); - baseMapper.update(sysMessage, Wrappers.lambdaQuery().eq(SysMessageEntity::getId, id)); - return Boolean.TRUE; - } + private final SysSystemConfigMapper sysSystemConfigMapper; - /** - * 保存消息及其关联关系 - * @param sysMessage 消息对象 - * @return 是否保存成功 - */ - @Transactional(rollbackFor = Exception.class) - public Boolean saveOrUpdateMessage(SysMessageVO sysMessage) { - SysMessageEntity messageEntity = new SysMessageEntity(); - BeanUtils.copyProperties(sysMessage, messageEntity); + private final SysMessageRelationMapper relationMapper; - if (Objects.isNull(sysMessage.getId())) { - baseMapper.insert(messageEntity); - } - else { - baseMapper.updateById(sysMessage); - } + private final StringRedisTemplate redisTemplate; - // 删除原有用户 - relationMapper.delete(Wrappers.lambdaQuery() - .eq(SysMessageRelationEntity::getMsgId, messageEntity.getId())); + private final SysUserMapper userMapper; - List userList = sysMessage.getUserList(); - if (CollUtil.isNotEmpty(userList)) { - userList.forEach(user -> { - SysMessageRelationEntity relationEntity = new SysMessageRelationEntity(); - relationEntity.setMsgId(messageEntity.getId()); - relationEntity.setUserId(user.getId()); - relationMapper.insert(relationEntity); - }); - } - else { - userMapper.selectList(Wrappers.emptyWrapper()).stream().map(SysUser::getUserId).forEach(userId -> { - SysMessageRelationEntity relationEntity = new SysMessageRelationEntity(); - relationEntity.setMsgId(messageEntity.getId()); - relationEntity.setUserId(userId); - relationMapper.insert(relationEntity); - }); - } - return Boolean.TRUE; - } + private final SysFileMapper fileMapper; - /** - * 获取用户的信息列表 - * @return list - */ - @Override - public IPage pageUserMessage(Page page, SysMessageVO sysMessage) { - MPJLambdaWrapper wrapper = new MPJLambdaWrapper() - .selectAll(SysMessageEntity.class) - .select(SysMessageRelationEntity::getReadFlag) - .leftJoin(SysMessageRelationEntity.class, SysMessageRelationEntity::getMsgId, SysMessageEntity::getId) - .eq(SysMessageRelationEntity::getUserId, SecurityUtils.getUser().getId()) - .eq(SysMessageEntity::getSendFlag, YesNoEnum.YES.getCode()) - .eq(StrUtil.isNotBlank(sysMessage.getCategory()), SysMessageEntity::getCategory, sysMessage.getCategory()) - .eq(StrUtil.isNotBlank(sysMessage.getReadFlag()), SysMessageRelationEntity::getReadFlag, - sysMessage.getReadFlag()) - .orderByDesc(SysMessageEntity::getSort) - .orderByDesc(SysMessageEntity::getCreateTime); - return baseMapper.selectJoinPage(page, SysMessageVO.class, wrapper); - } + private final FileTemplate fileTemplate; - /** - * 读取信息 - * @param id id - * @return true/false - */ - @Override - public Boolean readMessage(Long id) { - SysMessageRelationEntity relationEntity = new SysMessageRelationEntity(); - relationEntity.setReadFlag(YesNoEnum.YES.getCode()); - relationMapper.update(relationEntity, - Wrappers.lambdaQuery() - .eq(SysMessageRelationEntity::getMsgId, id) - .eq(SysMessageRelationEntity::getUserId, SecurityUtils.getUser().getId())); - return Boolean.TRUE; - } + /** + * 发送信息 + * + * @param id id + * @return true/false + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean sendMessage(Long id) { + // 更新信息状态 + SysMessageEntity sysMessage = new SysMessageEntity(); + sysMessage.setSendFlag(YesNoEnum.YES.getCode()); + baseMapper.update(sysMessage, Wrappers.lambdaQuery().eq(SysMessageEntity::getId, id)); + return Boolean.TRUE; + } - /** - * 获取信息 - * @param id id - * @return messageVO - */ - @Override - public SysMessageVO getMessage(Long id) { - SysMessageEntity messageEntity = baseMapper.selectById(id); - SysMessageVO SysMessageVO = new SysMessageVO(); - BeanUtils.copyProperties(messageEntity, SysMessageVO); + /** + * 保存消息及其关联关系 + * + * @param sysMessage 消息对象 + * @return 是否保存成功 + */ + @Transactional(rollbackFor = Exception.class) + public Boolean saveOrUpdateMessage(SysMessageVO sysMessage) { + SysMessageEntity messageEntity = new SysMessageEntity(); + BeanUtils.copyProperties(sysMessage, messageEntity); - // 全体通知 - if (messageEntity.getAllFlag().equals(YesNoEnum.YES.getCode())) { - return SysMessageVO; - } - List userIdList = relationMapper - .selectList(Wrappers.lambdaQuery().eq(SysMessageRelationEntity::getMsgId, id)) - .stream() - .map(SysMessageRelationEntity::getUserId) - .collect(Collectors.toList()); + if (Objects.isNull(sysMessage.getId())) { + baseMapper.insert(messageEntity); + } else { + baseMapper.updateById(sysMessage); + } - if (CollUtil.isNotEmpty(userIdList)) { - List orgNodeUserVoList = userMapper.selectBatchIds(userIdList).stream().map(user -> { - OrgTreeVO nodeUserVo = new OrgTreeVO(); - nodeUserVo.setId(user.getUserId()); - nodeUserVo.setAvatar(user.getAvatar()); - nodeUserVo.setName(user.getName()); - return nodeUserVo; - }).collect(Collectors.toList()); + // 删除原有用户 + relationMapper.delete(Wrappers.lambdaQuery().eq(SysMessageRelationEntity::getMsgId, messageEntity.getId())); - SysMessageVO.setUserList(orgNodeUserVoList); - } + List userList = sysMessage.getUserList(); + if (CollUtil.isNotEmpty(userList)) { + userList.forEach(user -> { + SysMessageRelationEntity relationEntity = new SysMessageRelationEntity(); + relationEntity.setMsgId(messageEntity.getId()); + relationEntity.setUserId(user.getId()); + relationMapper.insert(relationEntity); + }); + } else { + userMapper.selectList(Wrappers.emptyWrapper()).stream().map(SysUser::getUserId).forEach(userId -> { + SysMessageRelationEntity relationEntity = new SysMessageRelationEntity(); + relationEntity.setMsgId(messageEntity.getId()); + relationEntity.setUserId(userId); + relationMapper.insert(relationEntity); + }); + } + return Boolean.TRUE; + } - return SysMessageVO; - } + /** + * 获取用户的信息列表 + * + * @return list + */ + @Override + public IPage pageUserMessage(Page page, SysMessageVO sysMessage) { + MPJLambdaWrapper wrapper = new MPJLambdaWrapper().selectAll(SysMessageEntity.class).select(SysMessageRelationEntity::getReadFlag).leftJoin(SysMessageRelationEntity.class, SysMessageRelationEntity::getMsgId, SysMessageEntity::getId).eq(SysMessageRelationEntity::getUserId, SecurityUtils.getUser().getId()).eq(SysMessageEntity::getSendFlag, YesNoEnum.YES.getCode()).eq(StrUtil.isNotBlank(sysMessage.getCategory()), SysMessageEntity::getCategory, sysMessage.getCategory()).eq(StrUtil.isNotBlank(sysMessage.getReadFlag()), SysMessageRelationEntity::getReadFlag, sysMessage.getReadFlag()).orderByDesc(SysMessageEntity::getSort).orderByDesc(SysMessageEntity::getCreateTime); + return baseMapper.selectJoinPage(page, SysMessageVO.class, wrapper); + } - /** - * 查询用户阅读情况 - * @param page 分页 - * @param messageId 消息ID - * @param name 姓名 - * @return page - */ - @Override - public Page pageUserRead(Page page, Long messageId, String name) { - MPJLambdaWrapper wrapper = new MPJLambdaWrapper() - .selectAll(SysMessageRelationEntity.class) - .select(SysUser::getUsername, SysUser::getName, SysUser::getUserId) - .select(SysMessageEntity::getTitle) - .leftJoin(SysUser.class, SysUser::getUserId, SysMessageRelationEntity::getUserId) - .leftJoin(SysMessageEntity.class, SysMessageEntity::getId, SysMessageRelationEntity::getMsgId) - .eq(SysMessageRelationEntity::getMsgId, messageId) - .like(StrUtil.isNotBlank(name), SysUser::getName, name); - return relationMapper.selectJoinPage(page, SysMessageReadVO.class, wrapper); - } + /** + * 读取信息 + * + * @param id id + * @return true/false + */ + @Override + public Boolean readMessage(Long id) { + SysMessageRelationEntity relationEntity = new SysMessageRelationEntity(); + relationEntity.setReadFlag(YesNoEnum.YES.getCode()); + relationMapper.update(relationEntity, Wrappers.lambdaQuery().eq(SysMessageRelationEntity::getMsgId, id).eq(SysMessageRelationEntity::getUserId, SecurityUtils.getUser().getId())); + return Boolean.TRUE; + } + /** + * 获取信息 + * + * @param id id + * @return messageVO + */ + @Override + public SysMessageVO getMessage(Long id) { + SysMessageEntity messageEntity = baseMapper.selectById(id); + SysMessageVO SysMessageVO = new SysMessageVO(); + BeanUtils.copyProperties(messageEntity, SysMessageVO); + + // 全体通知 + if (messageEntity.getAllFlag().equals(YesNoEnum.YES.getCode())) { + return SysMessageVO; + } + List userIdList = relationMapper.selectList(Wrappers.lambdaQuery().eq(SysMessageRelationEntity::getMsgId, id)).stream().map(SysMessageRelationEntity::getUserId).collect(Collectors.toList()); + + if (CollUtil.isNotEmpty(userIdList)) { + List orgNodeUserVoList = userMapper.selectBatchIds(userIdList).stream().map(user -> { + OrgTreeVO nodeUserVo = new OrgTreeVO(); + nodeUserVo.setId(user.getUserId()); + nodeUserVo.setAvatar(user.getAvatar()); + nodeUserVo.setName(user.getName()); + return nodeUserVo; + }).collect(Collectors.toList()); + + SysMessageVO.setUserList(orgNodeUserVoList); + } + + return SysMessageVO; + } + + /** + * 查询用户阅读情况 + * + * @param page 分页 + * @param messageId 消息ID + * @param name 姓名 + * @return page + */ + @Override + public Page pageUserRead(Page page, Long messageId, String name) { + MPJLambdaWrapper wrapper = new MPJLambdaWrapper().selectAll(SysMessageRelationEntity.class).select(SysUser::getUsername, SysUser::getName, SysUser::getUserId).select(SysMessageEntity::getTitle).leftJoin(SysUser.class, SysUser::getUserId, SysMessageRelationEntity::getUserId).leftJoin(SysMessageEntity.class, SysMessageEntity::getId, SysMessageRelationEntity::getMsgId).eq(SysMessageRelationEntity::getMsgId, messageId).like(StrUtil.isNotBlank(name), SysUser::getName, name); + return relationMapper.selectJoinPage(page, SysMessageReadVO.class, wrapper); + } + + /** + * 发送手机验证码 TODO: 调用短信网关发送验证码,测试返回前端 + * + * @param mobile mobile + * @return code + */ + @Override + public R sendSmsCode(String mobile) { + List userList = userMapper.selectList(Wrappers.query().lambda().eq(SysUser::getPhone, mobile)); + + if (CollUtil.isEmpty(userList)) { + log.info("手机号未注册:{}", mobile); + return R.ok(Boolean.FALSE, MsgUtils.getMessage(ErrorCodes.SYS_APP_PHONE_UNREGISTERED, mobile)); + } + + String codeObj = redisTemplate.opsForValue().get(CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + mobile); + + if (StrUtil.isNotBlank(codeObj)) { + log.info("手机号验证码未过期:{},{}", mobile, codeObj); + return R.ok(Boolean.FALSE, MsgUtils.getMessage(ErrorCodes.SYS_APP_SMS_OFTEN)); + } + + String code = RandomUtil.randomNumbers(Integer.parseInt(SecurityConstants.CODE_SIZE)); + log.debug("手机号生成验证码成功:{},{}", mobile, code); + redisTemplate.opsForValue().set(CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + mobile, code, SecurityConstants.CODE_TIME, TimeUnit.SECONDS); + + // 发送 + return this.sendSms(MessageSmsDTO.builder().mobile(mobile).biz(SmsBizCodeEnum.SMS_NORMAL_CODE.getCode()).param(code).build()); + } + + /** + * 发送短信 + * + * @param messageSmsDTO 消息 短信 DTO + * @return {@link R } + */ + @Override + public R sendSms(MessageSmsDTO messageSmsDTO) { + + // 根据业务编码获取短信通道配置 + List configEntityList = sysSystemConfigMapper.selectList(Wrappers.lambdaQuery().eq(SysSystemConfigEntity::getConfigType, SystemConfigTypeEnum.SMS.getValue()).eq(SysSystemConfigEntity::getConfigStatus, YesNoEnum.YES.getCode()).eq(SysSystemConfigEntity::getConfigKey, messageSmsDTO.getBizCode())); + if (CollUtil.isEmpty(configEntityList)) { + return R.failed("发送失败,短信通道配置不存在"); + } + + SysSystemConfigEntity configEntity = configEntityList.get(0); + JSONObject configMap = JSONUtil.parseObj(configEntity.getConfigValue()); + + // 组装SMS4J 的发送对象 + SmsBlend smsBlend = SmsFactory.getSmsBlend(messageSmsDTO.getBizCode()); + if (Objects.isNull(smsBlend)) { + Class targetClass = Arrays.stream(SUPPORT_CONFIG_CLAZZ).filter(config -> config.getSimpleName().toLowerCase().contains(configMap.getStr(MessageSmsDTO.Fields.supplier))).findFirst().orElseThrow(() -> new CheckedException("发送失败,短信通道配置不存在")); + BaseConfig baseConfig = (BaseConfig) JSONUtil.toBean(configEntity.getConfigValue(), targetClass); + + // 如果渠道扩展参数不为空则增加特性化参数 + if (StrUtil.isNotBlank(configMap.getStr(MessageSmsDTO.Fields.extParams))) { + JSONObject extParams = configMap.getJSONObject(MessageSmsDTO.Fields.extParams); + BeanUtil.copyProperties(extParams, baseConfig); + } + + baseConfig.setConfigId(configEntity.getConfigKey()); + SmsFactory.createSmsBlend(baseConfig); + smsBlend = SmsFactory.getSmsBlend(messageSmsDTO.getBizCode()); + } + + // 异步发送短信 + SysLogDTO sysLog = SysLogUtils.getSysLog(); + Long start = System.currentTimeMillis(); + sysLog.setTenantId(TenantContextHolder.getTenantId()); + for (String mobile : messageSmsDTO.getMobiles()) { + smsBlend.sendMessageAsync(mobile, configMap.getStr(MessageSmsDTO.Fields.templateId), messageSmsDTO.getParams(), smsResponse -> { + log.info("发送短信结果:{}", smsResponse); + sysLog.setTitle(String.format("发送短信 %s", mobile)); + sysLog.setLogType(LogTypeEnum.NORMAL.getType()); + sysLog.setServiceId(SystemConfigTypeEnum.SMS.getValue()); + sysLog.setParams(JacksonSensitiveFieldUtil.writeValueAsString(smsResponse)); + sysLog.setTime(System.currentTimeMillis() - start); + sysLog.setException(JacksonSensitiveFieldUtil.writeValueAsString(smsResponse)); + remoteLogService.saveLog(sysLog); + }); + } + return R.ok(); + } + + /** + * 发送钩子消息 + * + * @param messageHookDTO 消息挂钩 DTO + * @return {@link R } + */ + @Override + public R sendHook(MessageHookDTO messageHookDTO) { + + // 根据业务编码获取短信通道配置 + List configEntityList = sysSystemConfigMapper.selectList(Wrappers.lambdaQuery() + .eq(SysSystemConfigEntity::getConfigType, SystemConfigTypeEnum.WEBHOOK.getValue()) + .eq(SysSystemConfigEntity::getConfigStatus, YesNoEnum.YES.getCode()) + .eq(SysSystemConfigEntity::getConfigKey, messageHookDTO.getBizCode())); + if (CollUtil.isEmpty(configEntityList)) { + return R.failed("发送失败,短信通道配置不存在"); + } + + SysSystemConfigEntity configEntity = configEntityList.get(0); + JSONObject configMap = JSONUtil.parseObj(configEntity.getConfigValue()); + String supplier = configMap.getStr("supplier"); + + // 根据配置创建服务实例并注册 + OaSender alarm = OaFactory.getSmsOaBlend(messageHookDTO.getBizCode()); + if (Objects.isNull(alarm)) { + if (StrUtil.equalsAnyIgnoreCase(OaType.DING_TALK.toString(), supplier)) { + DingTalkConfig dingTalkConfig = new DingTalkConfig(); + dingTalkConfig.setConfigId(messageHookDTO.getBizCode()); + dingTalkConfig.setSign(configMap.getStr("sign")); + dingTalkConfig.setTokenId(configMap.getStr("tokenId")); + OaFactory.createAndRegisterOaSender(dingTalkConfig); + } + if (StrUtil.equalsAnyIgnoreCase(OaType.BYTE_TALK.toString(), supplier)) { + ByteTalkConfig byteTalkConfig = new ByteTalkConfig(); + byteTalkConfig.setConfigId(messageHookDTO.getBizCode()); + byteTalkConfig.setSign(configMap.getStr("sign")); + byteTalkConfig.setTokenId(configMap.getStr("tokenId")); + OaFactory.createAndRegisterOaSender(byteTalkConfig); + } + + + if (StrUtil.equalsAnyIgnoreCase(OaType.WE_TALK.toString(), supplier)) { + WeTalkConfig weTalkConfig = new WeTalkConfig(); + weTalkConfig.setConfigId(messageHookDTO.getBizCode()); + weTalkConfig.setSign(configMap.getStr("sign")); + weTalkConfig.setTokenId(configMap.getStr("tokenId")); + OaFactory.createAndRegisterOaSender(weTalkConfig); + } + alarm = OaFactory.getSmsOaBlend(messageHookDTO.getBizCode()); + } + + + Request request = new Request(); + request.setContent(messageHookDTO.getMessageContent()); + request.setTitle(messageHookDTO.getMessageTitle()); + request.setMessageUrl(messageHookDTO.getMessageUrl()); + request.setPicUrl(messageHookDTO.getPicUrl()); + request.setIsNoticeAll(messageHookDTO.isNoticeAll()); + request.setPhoneList(messageHookDTO.getPhoneList()); + + SysLogDTO sysLog = SysLogUtils.getSysLog(); + sysLog.setTenantId(TenantContextHolder.getTenantId()); + Long start = System.currentTimeMillis(); + alarm.senderAsync(request, MessageType.valueOf(String.format("%s_%s", supplier, messageHookDTO.getMessageType()).toUpperCase()), response -> { + log.info("发送Hook结果:{}", response); + sysLog.setTitle(String.format("发送Hook %s", messageHookDTO.getBizCode())); + sysLog.setLogType(LogTypeEnum.NORMAL.getType()); + sysLog.setServiceId(SystemConfigTypeEnum.WEBHOOK.getValue()); + sysLog.setParams(JacksonSensitiveFieldUtil.writeValueAsString(messageHookDTO)); + sysLog.setTime(System.currentTimeMillis() - start); + sysLog.setException(JacksonSensitiveFieldUtil.writeValueAsString(response)); + remoteLogService.saveLog(sysLog); + }); + return R.ok(); + } + + /** + * 发送邮件 + * + * @param messageEmailDTO 留言内容 电子邮件 DTO + * @return {@link R } + */ + @SneakyThrows + @Override + public R sendEmail(MessageEmailDTO messageEmailDTO) { + // 根据业务编码获取短信通道配置 + List configEntityList = sysSystemConfigMapper.selectList(Wrappers.lambdaQuery() + .eq(SysSystemConfigEntity::getConfigType, SystemConfigTypeEnum.EMAIL.getValue()) + .eq(SysSystemConfigEntity::getConfigStatus, YesNoEnum.YES.getCode()). + eq(SysSystemConfigEntity::getConfigKey, messageEmailDTO.getBizCode())); + if (CollUtil.isEmpty(configEntityList)) { + return R.failed("发送失败,通道配置不存在"); + } + SysSystemConfigEntity configEntity = configEntityList.get(0); + JSONObject configMap = JSONUtil.parseObj(configEntity.getConfigValue()); + + + List tempFileList = new ArrayList<>(); + if (CollUtil.isNotEmpty(messageEmailDTO.getAttachmentList())) { + TenantContextHolder.setTenantSkip(); + for (String fileName : messageEmailDTO.getAttachmentList()) { + SysFile sysFile = fileMapper.selectOne(Wrappers.lambdaQuery().eq(SysFile::getFileName, fileName)); + S3Object s3Object = fileTemplate.getObject(sysFile.getBucketName(), sysFile.getDir(), fileName); + File file = FileUtil.file(FileUtil.getTmpDirPath(), sysFile.getOriginal()); + tempFileList.add(file); + IoUtil.copy(s3Object.getObjectContent(), FileUtil.getOutputStream(file)); + } + } + + MailAccount account = new MailAccount(); + account.setHost(configMap.getStr("smtpServer")); + account.setPort(configMap.getInt("port")); + account.setAuth(configMap.getBool("isAuth")); + account.setSslEnable(configMap.getBool("isSSL")); + account.setFrom(configMap.getStr("username")); + account.setUser(configMap.getStr("username")); + account.setPass(configMap.getStr("password")); + + // 渲染模板 + TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig()); + Template template = engine.getTemplate(configMap.getStr("html")); + String result = template.render(messageEmailDTO.getHtmlValues()); + + Long start = System.currentTimeMillis(); + MailUtil.send(account, messageEmailDTO.getMailAddress(), + messageEmailDTO.getCcList(), + messageEmailDTO.getBccList(), + messageEmailDTO.getTitle(), result, true, tempFileList.toArray(new File[0])); + Long end = System.currentTimeMillis(); + // 写入日志 + SysLogDTO sysLog = SysLogUtils.getSysLog(); + sysLog.setTitle(String.format("发送邮件 %s", messageEmailDTO.getTitle())); + sysLog.setLogType(LogTypeEnum.NORMAL.getType()); + sysLog.setServiceId(SystemConfigTypeEnum.EMAIL.getValue()); + sysLog.setParams(JacksonSensitiveFieldUtil.writeValueAsString(messageEmailDTO)); + sysLog.setTenantId(TenantContextHolder.getTenantId()); + sysLog.setTime(end - start); + remoteLogService.saveLog(sysLog); + // 删除临时文件 + tempFileList.forEach(FileUtil::del); + return R.ok(); + } } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysSystemConfigServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysSystemConfigServiceImpl.java new file mode 100644 index 000000000..fa032e8af --- /dev/null +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysSystemConfigServiceImpl.java @@ -0,0 +1,118 @@ +package com.pig4cloud.pigx.admin.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.admin.api.constant.SystemConfigTypeEnum; +import com.pig4cloud.pigx.admin.api.entity.SysSystemConfigEntity; +import com.pig4cloud.pigx.admin.mapper.SysSystemConfigMapper; +import com.pig4cloud.pigx.admin.service.SysSystemConfigService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.log.util.JacksonSensitiveFieldUtil; +import lombok.SneakyThrows; +import org.dromara.oa.api.OaSender; +import org.dromara.oa.core.provider.factory.OaFactory; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.springframework.stereotype.Service; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * SYS 系统配置服务实现 + * + * @author lengleng + * @date 2024/07/18 + */ +@Service +public class SysSystemConfigServiceImpl extends ServiceImpl implements SysSystemConfigService { + + private final SysMessageServiceImpl sysMessageServiceImpl; + + public SysSystemConfigServiceImpl(SysMessageServiceImpl sysMessageServiceImpl) { + this.sysMessageServiceImpl = sysMessageServiceImpl; + } + + /** + * 列出系统配置 + * + * @param query 查询 + * @return {@link R } + */ + @Override + public R listSystemConfig(SysSystemConfigEntity query) { + List configEntityList = baseMapper.selectList(Wrappers.query(query)); + configEntityList.stream().forEach(systemConfig -> { + if (StrUtil.isNotBlank(systemConfig.getConfigValue())) { + systemConfig.setConfigValue(JacksonSensitiveFieldUtil.readStr(systemConfig.getConfigValue())); + } + }); + + return R.ok(configEntityList); + } + + /** + * 系统配置 + * + * @param page 页 + * @param sysSystemConfig sys 系统配置 + * @return {@link R } + */ + @Override + public R pageSystemConfig(Page page, SysSystemConfigEntity sysSystemConfig) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(StrUtil.isNotBlank(sysSystemConfig.getConfigType()), SysSystemConfigEntity::getConfigType, sysSystemConfig.getConfigType()); + wrapper.like(StrUtil.isNotBlank(sysSystemConfig.getConfigName()) + , SysSystemConfigEntity::getConfigName, sysSystemConfig.getConfigName()); + Page pageResult = baseMapper.selectPage(page, wrapper); + pageResult.getRecords().forEach(systemConfig -> { + if (StrUtil.isNotBlank(systemConfig.getConfigValue())) { + systemConfig.setConfigValue(JacksonSensitiveFieldUtil.readStr(systemConfig.getConfigValue())); + } + }); + + return R.ok(pageResult); + } + + /** + * 更新系统配置 + * + * @param sysSystemConfig sys 系统配置 + * @return {@link R } + */ + @Override + @SneakyThrows + public R updateSystemConfig(SysSystemConfigEntity sysSystemConfig) { + // 更新configValue ,如果 accessSecret,tokenId,sign 属性为空,则不更新以上属性 + SysSystemConfigEntity configEntity = baseMapper.selectById(sysSystemConfig.getId()); + JSONObject oldValue = JSONUtil.parseObj(configEntity.getConfigValue()); + JSONObject newValue = JSONUtil.parseObj(sysSystemConfig.getConfigValue()); + BeanUtil.copyProperties(newValue, oldValue); + + sysSystemConfig.setConfigValue(JSONUtil.toJsonPrettyStr(oldValue)); + + baseMapper.updateById(sysSystemConfig); + // 更新短信配置 + if (SystemConfigTypeEnum.SMS.getValue().equals(sysSystemConfig.getConfigType()) + && Objects.nonNull(SmsFactory.getSmsBlend(sysSystemConfig.getConfigKey()))) { + SmsFactory.unregister(sysSystemConfig.getConfigKey()); + } + + if (SystemConfigTypeEnum.WEBHOOK.getValue().equals(sysSystemConfig.getConfigType())) { + // 更新webhook配置, 官方工具类没有提供清除方法,只能通过反射清除 + Field configsField = ReflectUtil.getField(OaFactory.class, "CONFIGS"); + configsField.setAccessible(true); + Map configs = (Map) configsField.get(null); + configs.clear(); + } + return R.ok(); + } +} diff --git a/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysSystemConfigMapper.xml b/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysSystemConfigMapper.xml new file mode 100644 index 000000000..96931db14 --- /dev/null +++ b/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysSystemConfigMapper.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/pigx-visual/pigx-codegen/pom.xml b/pigx-visual/pigx-codegen/pom.xml index d75e07227..03fa294d4 100755 --- a/pigx-visual/pigx-codegen/pom.xml +++ b/pigx-visual/pigx-codegen/pom.xml @@ -159,12 +159,10 @@ org.apache.velocity velocity-engine-core - ${velocity.version} org.apache.velocity.tools velocity-tools-generic - ${velocity.tool.version} diff --git a/pom.xml b/pom.xml index bdac12708..2fbf3720c 100644 --- a/pom.xml +++ b/pom.xml @@ -51,8 +51,6 @@ 2.0.0 3.0.0 3.0.5 - 2.3 - 3.1 3.0.5 2.12.6 2.3.5