整合多小程序登录 - 公众号发消息

This commit is contained in:
aikai 2024-11-29 10:18:22 +08:00
parent a2f79e6698
commit 9a9d59dd80
83 changed files with 1598 additions and 1181 deletions

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.system.enums.social;
package cn.iocoder.yudao.framework.common.enums;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
@ -53,6 +53,12 @@ public enum SocialTypeEnum implements IntArrayValuable {
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html">接入文档</a>
*/
WECHAT_MINI_APP(34, "WECHAT_MINI_APP"),
/**
* 中鼐智能CRM小程序
*
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html">接入文档</a>
*/
WECHAT_MINI_APP_CRM(35, "WECHAT_MINI_APP_CRM"),
;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SocialTypeEnum::getType).toArray();

View File

@ -0,0 +1,243 @@
package cn.iocoder.yudao.framework.common.template;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.template.dto.*;
import cn.iocoder.yudao.framework.common.template.vo.MsgData;
import cn.iocoder.yudao.framework.common.template.vo.SubscribeMessageReqDTO;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import org.mapstruct.factory.Mappers;
import java.util.Date;
// -- 微信小程序模版转换器
public interface WxMiNiMsgTemplate {
WxMiNiMsgTemplate INSTANCE = Mappers.getMapper(WxMiNiMsgTemplate.class);
/**
* 审批结果通知
*/
String APPROVAL_RESULT_NOTIFICATION = "OnJjp5pdjG1PHMoELYaqp3Xq8jWZ5E6ndO0clEIQ4tk";
/**
* 消息未读提醒
*/
String MESSAGE_UNREAD_REMINDER = "fH29xjNb8pe-7onQ-wE3QrBAC-y8aaC_oosYZKNMtzM";
/**
* 公司公告通知
*/
String COMPANY_ANNOUNCEMENT_NOTICE = "OF4-948Vz9rtE_VA55rmDxo4azOwmrjjk33jDpOiPiY";
/**
* 打卡提醒
*/
String CHECK_IN_REMINDER = "5yHyXhrsyqXi8s4hYhvaeMtz9kT5OPvDCe3h6G1T-OE";
/**
* OA流程待办提醒
*/
String OA_PROCESS_TO_DO_REMINDER = "3cP4btlFSSiZk65qVewN_WoT_bh0OfUkYzzTsADOrR4";
/**
* 转换审批结果通知
*
* @param dto
* @return
*/
default SubscribeMessageReqDTO convertApprovalResultNotification(ApprovalResultNotificationMessageDTO dto) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(dto.getOpenId());
message.setTemplateId(APPROVAL_RESULT_NOTIFICATION);
//审批类型
MsgData processType = new MsgData();
processType.setName("thing1");
processType.setValue(dto.getProcessInstanceName());
message.addData(processType);
//发起时间
MsgData createTime = new MsgData();
createTime.setName("time2");
createTime.setValue(dto.getTime());
message.addData(createTime);
//审批时间
MsgData approvalTime = new MsgData();
approvalTime.setName("time7");
approvalTime.setValue(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));
message.addData(approvalTime);
//审批结果
MsgData approvalResult = new MsgData();
approvalResult.setName("phrase3");
approvalResult.setValue(dto.getResult());
message.addData(approvalResult);
String reason = dto.getReason();
if (StrUtil.isNotEmpty(reason)) {
MsgData approvalReason = new MsgData();
if (reason.length() > 10) {
reason = reason.substring(0, 10) + ". . . . ";
}
approvalReason.setName("thing12");
approvalReason.setValue(reason);
message.addData(approvalReason);
}
message.setMiniProgramState(dto.getMiniProgramState());
message.setPage(dto.getPage());
message.setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType());
return message;
}
/**
* 消息未读提醒
*
* @param dto
* @return
*/
default SubscribeMessageReqDTO convertMessageUnreadReminder(MessageUnreadReminderDTO dto) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(dto.getOpenId());
message.setTemplateId(MESSAGE_UNREAD_REMINDER);
//消息类型
MsgData noticeType = new MsgData();
noticeType.setName("phrase8");
noticeType.setValue(dto.getMsgType());
message.addData(noticeType);
//发送人
MsgData publishMan = new MsgData();
publishMan.setName("thing16");
publishMan.setValue(dto.getSender());
message.addData(publishMan);
//发送时间
MsgData createTime = new MsgData();
createTime.setName("time3");
createTime.setValue(dto.getSendingTime());
message.addData(createTime);
//消息内容
MsgData content = new MsgData();
content.setName("thing2");
String comment = dto.getComment();
if (comment.length() > 10) {
comment = comment.substring(0, 10) + ". . . . ";
}
content.setValue(comment);
message.addData(content);
message.setMiniProgramState(dto.getPage());
message.setPage(dto.getPage());
message.setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType());
return message;
}
default SubscribeMessageReqDTO convertCompanyAnnouncementNotice(CompanyAnnouncementNoticeDTO dto) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(dto.getOpenId());
message.setTemplateId(COMPANY_ANNOUNCEMENT_NOTICE);
//通知类型
MsgData noticeType = new MsgData();
noticeType.setName("thing1");
noticeType.setValue(dto.getNoticeType()); //这里根据业务需求填写具体的公告类型 如全员公告 xxx公告
message.addData(noticeType);
//公告标题
String value = dto.getTitle();
if (value.length() > 10) {
value = value.substring(0, 10) + ". . . . ";
}
MsgData title = new MsgData();
title.setName("thing6");
title.setValue(value);
message.addData(title);
//通知内容
MsgData content = new MsgData();
content.setName("thing2");
content.setValue("具体内容请进入小程序查看");
message.addData(content);
//发布人
MsgData publishMan = new MsgData();
publishMan.setName("thing9");
publishMan.setValue(dto.getNickname());
message.addData(publishMan);
//通知时间
MsgData createTime = new MsgData();
createTime.setName("time3");
createTime.setValue(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));
message.addData(createTime);
message.setMiniProgramState(dto.getMiniProgramState());
message.setPage(dto.getPage());
message.setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType());
return message;
}
/**
* 打卡通知
*
* @param dto
* @return
*/
default SubscribeMessageReqDTO convertCheckInReminder(CheckInReminderDTO dto) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(dto.getOpenId());
message.setTemplateId(CHECK_IN_REMINDER);
MsgData data = new MsgData();
data.setName("thing9");
data.setValue(dto.getCheckInType());
message.addData(data);
data = new MsgData();
data.setName("thing6");
data.setValue(dto.getComment());
message.addData(data);
message.setPage(dto.getPage());
message.setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType());
return message;
}
/**
* OA流程待办提醒
*
* @param dto
* @return
*/
default SubscribeMessageReqDTO convertProcessToDoReminder(ProcessToDoReminderDTO dto) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(dto.getOpenId());
message.setTemplateId(OA_PROCESS_TO_DO_REMINDER);
//待办标题
MsgData processType = new MsgData();
processType.setName("thing1");
processType.setValue(dto.getProcessType());
message.addData(processType);
//申请人
MsgData applicant = new MsgData();
applicant.setName("thing4");
applicant.setValue(dto.getStartUserNickname());
message.addData(applicant);
//申请时间
MsgData createTime = new MsgData();
createTime.setName("time5");
createTime.setValue(dto.getTime());
message.addData(createTime);
//当前进度
MsgData currentSchedule = new MsgData();
currentSchedule.setName("thing6");
currentSchedule.setValue(dto.getSchedule());
message.addData(currentSchedule);
message.setMiniProgramState(dto.getMiniProgramState());
message.setPage(dto.getPage());
message.setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType());
return message;
}
}

View File

@ -0,0 +1,7 @@
package cn.iocoder.yudao.framework.common.template;
// -- 微信公众号模版转换器
public class WxMpMsgTemplate {
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.framework.common.template.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class ApprovalResultNotificationMessageDTO {
@Schema(description = "接收者(用户)的 openid")
private String openId;
@Schema(description = "流程实例名称")
private String processInstanceName;
@Schema(description = "时间")
private String time;
@Schema(description = "结果")
private String result;
@Schema(description = "原因")
private String reason;
@Schema(description = "跳转小程序类型")
private String miniProgramState = "formal";
@Schema(description = "小程序页面地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "pages/home/index")
private String page;
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.framework.common.template.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class CheckInReminderDTO {
@Schema(description = "接收者(用户)的 openid")
private String openId;
@Schema(description = "打卡类型")
private String checkInType;
@Schema(description = "内容")
private String comment;
@Schema(description = "跳转小程序类型")
private String miniProgramState = "formal";
@Schema(description = "小程序页面地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "pages/home/index")
private String page;
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.framework.common.template.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class CompanyAnnouncementNoticeDTO {
@Schema(description = "接收者(用户)的 openid")
private String openId;
@Schema(description = "消息类型")
private String noticeType;
@Schema(description = "标题")
private String title;
@Schema(description = "发布人")
private String nickname;
@Schema(description = "发送时间")
private String sendingTime;
@Schema(description = "跳转小程序类型")
private String miniProgramState = "formal";
@Schema(description = "小程序页面地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "pages/home/index")
private String page;
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.framework.common.template.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
@Data
@Accessors(chain = true)
public class MessageUnreadReminderDTO {
@Schema(description = "接收者(用户)的 openid")
private String openId;
@Schema(description = "消息类型")
private String msgType;
@Schema(description = "发送人")
private String sender;
@Schema(description = "发送时间")
private String sendingTime;
@Schema(description = "内容")
private String comment;
@Schema(description = "跳转小程序类型")
private String miniProgramState = "formal";
@Schema(description = "小程序页面地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "pages/home/index")
private String page;
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.framework.common.template.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class ProcessToDoReminderDTO {
@Schema(description = "接收者(用户)的 openid")
private String openId;
@Schema(description = "待办标题")
private String processType;
@Schema(description = "申请人")
private String startUserNickname;
@Schema(description = "时间")
private String time;
@Schema(description = "进度")
private String schedule;
@Schema(description = "跳转小程序类型")
private String miniProgramState = "formal";
@Schema(description = "小程序页面地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "pages/home/index")
private String page;
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.system.api.subscribe.dto;
package cn.iocoder.yudao.framework.common.template.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -18,7 +18,7 @@ public class MsgData {
@NotNull(message = "模板消息的名称不能为空")
private String name;
@Schema(description = "模版消息字段值", requiredMode = Schema.RequiredMode.REQUIRED, example = "OnJjp5pdjG1PHMoELYaqp3Xq8jWZ5E6ndO0clEIQ4tk")
@Schema(description = "模版消息字段值", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "模板消息的value不能为空")
private String value;
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.system.api.subscribe.dto;
package cn.iocoder.yudao.framework.common.template.vo;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -21,26 +22,28 @@ public class SubscribeMessageReqDTO {
@NotNull(message = "openid不能为空")
private String toUser;
@Schema(description = "所需下发的模板消息的id", requiredMode = Schema.RequiredMode.REQUIRED, example = "OnJjp5pdjG1PHMoELYaqp3Xq8jWZ5E6ndO0clEIQ4tk")
@Schema(description = "所需下发的模板消息的id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "模板消息的id不能为空")
private String templateId;
@Schema(description = "所需下发的模板消息的属性集合", requiredMode = Schema.RequiredMode.REQUIRED, example = "OnJjp5pdjG1PHMoELYaqp3Xq8jWZ5E6ndO0clEIQ4tk")
@Schema(description = "所需下发的模板消息的属性集合", requiredMode = Schema.RequiredMode.REQUIRED)
private List<MsgData> data = new ArrayList<>();
@Schema(description = "跳转小程序类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "developer为开发版trial为体验版formal为正式版默认为正式版")
@NotNull(message = "跳转小程序类型不能为空")
private String miniprogramState = "formal";
private String miniProgramState = "formal";
@Schema(description = "小程序页面地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "pages/home/index")
@NotNull(message = "小程序页面地址不能为空")
private String page;
/**
* 社交平台的类型 (参见 {@link SocialTypeEnum} 枚举)
*/
@Schema(description = "社交平台的类型")
private Integer socialType;
public void addData(MsgData data) {
this.data.add(data);
}
@Schema(description = "模版类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1:小程序模版2公众号模版")
@NotNull(message = "模版类型不能为空")
private String minOrMpType = "1" ;
}

View File

@ -5,8 +5,8 @@ import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkTaskDO;
import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants;
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
import cn.iocoder.yudao.module.system.api.subscribe.dto.MsgData;
import cn.iocoder.yudao.module.system.api.subscribe.dto.SubscribeMessageReqDTO;
import cn.iocoder.yudao.framework.common.template.vo.MsgData;
import cn.iocoder.yudao.framework.common.template.vo.SubscribeMessageReqDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@ -31,114 +31,7 @@ public interface BpmMessageConvert {
NotifySendSingleToUserReqDTO convert1(Long userId, String templateCode, Map<String, Object> templateParams);
/**
* @param openId 微信小程序唯一id
* @param processInstanceName 流程名称
* @param result 审批结果
* @param reason 审批原因
* @param miniProgramState 小程序的状态
* @return
*/
default SubscribeMessageReqDTO convertApprovalResultNotification(String openId, String processInstanceName,
String time, String result, String reason, String processInstanceId,
String miniProgramState) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(openId);
message.setTemplateId("OnJjp5pdjG1PHMoELYaqp3Xq8jWZ5E6ndO0clEIQ4tk");
//审批类型
MsgData processType = new MsgData();
processType.setName("thing1");
processType.setValue(processInstanceName);
message.addData(processType);
//发起时间
MsgData createTime = new MsgData();
createTime.setName("time2");
createTime.setValue(time);
message.addData(createTime);
//审批时间
MsgData approvalTime = new MsgData();
approvalTime.setName("time7");
approvalTime.setValue(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));
message.addData(approvalTime);
//审批结果
MsgData approvalResult = new MsgData();
approvalResult.setName("phrase3");
approvalResult.setValue(result.equals(BpmConstants.AUTO_APPRAVAL) ? "通过" : result);
message.addData(approvalResult);
if (reason != null) {
MsgData approvalReason = new MsgData();
if (reason.length() > 10) {
reason = reason.substring(0, 10) + ". . . . ";
}
approvalReason.setName("thing12");
approvalReason.setValue(reason);
message.addData(approvalReason);
}
message.setMiniprogramState(miniProgramState);
message.setPage("subPagesB/bpm/task/todo/examineApprove?id=" + processInstanceId + "&isDetail=1");
return message;
}
/**
* @param openId 微信小程序唯一id
* @param processInstanceName 流程名称
* @param result 审批结果
* @param reason 审批原因
* @param miniProgramState 小程序的状态
* @return
*/
default SubscribeMessageReqDTO convertApprovalResultNotificationPage(String openId, String processInstanceName,
String time, String result, String reason,
String miniProgramState, String page) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(openId);
message.setTemplateId("OnJjp5pdjG1PHMoELYaqp3Xq8jWZ5E6ndO0clEIQ4tk");
//审批类型
MsgData processType = new MsgData();
processType.setName("thing1");
processType.setValue(processInstanceName);
message.addData(processType);
//发起时间
MsgData createTime = new MsgData();
createTime.setName("time2");
createTime.setValue(time);
message.addData(createTime);
//审批时间
MsgData approvalTime = new MsgData();
approvalTime.setName("time7");
approvalTime.setValue(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));
message.addData(approvalTime);
//审批结果
MsgData approvalResult = new MsgData();
approvalResult.setName("phrase3");
approvalResult.setValue(result);
message.addData(approvalResult);
if (reason != null) {
MsgData approvalReason = new MsgData();
if (reason.length() > 10) {
reason = reason.substring(0, 10) + ". . . . ";
}
approvalReason.setName("thing12");
approvalReason.setValue(reason);
message.addData(approvalReason);
}
message.setMiniprogramState(miniProgramState);
message.setPage(page);
return message;
}
/**
* @param openId 微信小程序唯一id
@ -178,61 +71,9 @@ public interface BpmMessageConvert {
currentSchedule.setValue(schedule);
message.addData(currentSchedule);
message.setMiniprogramState(miniProgramState);
message.setMiniProgramState(miniProgramState);
message.setPage("subPagesB/bpm/task/todo/examineApprove?id=" + processInstanceId);
return message;
}
/**
* @param openId 微信小程序唯一id
* @param workTaskDO 任务对象
* @param nickname 发布人姓名
* @param miniProgramState 小程序的状态
* @return
*/
default SubscribeMessageReqDTO convertWorkTask(String openId, String processInstanceName, BpmOAWorkTaskDO workTaskDO,
String nickname, String time, String miniProgramState, Boolean isFlag,
Long deptId) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(openId);
message.setTemplateId("fH29xjNb8pe-7onQ-wE3QrBAC-y8aaC_oosYZKNMtzM");
//消息类型
MsgData noticeType = new MsgData();
noticeType.setName("phrase8");
noticeType.setValue(processInstanceName);
message.addData(noticeType);
//发送人
MsgData publishMan = new MsgData();
publishMan.setName("thing16");
publishMan.setValue(nickname);
message.addData(publishMan);
//发送时间
MsgData createTime = new MsgData();
createTime.setName("time3");
createTime.setValue(time);
message.addData(createTime);
//消息内容
MsgData content = new MsgData();
content.setName("thing2");
if (isFlag) {
content.setValue("你分配的任务已完成!");
} else {
content.setValue("你收到了一个新的任务!");
}
message.addData(content);
message.setMiniprogramState(miniProgramState);
if (isFlag) {
message.setPage("subPages/task/taskAssignment?userId=" + workTaskDO.getReceiverUserId() + "&deptId=" + deptId);
} else {
message.setPage("subPages/task/taskDispose?id=" + workTaskDO.getId());
}
return message;
}
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.bpm.convert.message.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class BpmMessageDTO {
@Schema(description = "接收者(用户)的 openid")
private String openId;
@Schema(description = "流程实例名称")
private String processInstanceName;
@Schema(description = "时间")
private String time;
@Schema(description = "结果")
private String result;
@Schema(description = "原因")
private String reason;
@Schema(description = "跳转小程序类型")
private String miniProgramState = "formal";
@Schema(description = "小程序页面地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "pages/home/index")
private String page;
}

View File

@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.system.api.assetreceive.AssetReceiveApi;
import cn.iocoder.yudao.module.system.api.assets.AssetsApi;
import cn.iocoder.yudao.module.system.api.assets.AssetsTypeApi;
import cn.iocoder.yudao.module.system.api.attendance.AttendanceApi;
import cn.iocoder.yudao.module.system.api.auth.AdminOauthUserOtherInfoApi;
import cn.iocoder.yudao.module.system.api.bank.BankApi;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.PostApi;
@ -28,7 +29,7 @@ import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@EnableFeignClients(clients = {FileApi.class, RoleApi.class, DeptApi.class, PostApi.class, AdminUserApi.class, SmsSendApi.class, DictDataApi.class, NotifyMessageSendApi.class,
SubscribeMessageSendApi.class, SocialClientApi.class, UsersExtApi.class, AttendanceApi.class, BankApi.class, ConfigApi.class, PositionApi.class, SupplierApi.class, AssetsApi.class,
AssetsTypeApi.class, AssetReceiveApi.class, AttendanceApi.class, AttendanceGroupApi.class, WorkOvertimeApi.class, HolidayApi.class
AssetsTypeApi.class, AssetReceiveApi.class, AttendanceApi.class, AttendanceGroupApi.class, WorkOvertimeApi.class, HolidayApi.class, AdminOauthUserOtherInfoApi.class
})
public class RpcConfiguration {
}

View File

@ -2,15 +2,18 @@ package cn.iocoder.yudao.module.bpm.service.financialpayment;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.Constants;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.template.WxMiNiMsgTemplate;
import cn.iocoder.yudao.framework.common.template.dto.ApprovalResultNotificationMessageDTO;
import cn.iocoder.yudao.framework.common.template.vo.SubscribeMessageReqDTO;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.financialpayment.vo.FinancialPaymentPageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.financialpayment.vo.FinancialPaymentSaveReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.financialpayment.vo.FinancialPaymentSaveVO;
import cn.iocoder.yudao.module.bpm.controller.admin.financialpaymentitem.vo.FinancialPaymentItemSaveReqVO;
import cn.iocoder.yudao.module.bpm.convert.message.BpmMessageConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.financialpayment.FinancialPaymentDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.financialpaymentitem.FinancialPaymentItemDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.*;
@ -21,10 +24,12 @@ import cn.iocoder.yudao.module.bpm.dal.mysql.oa.*;
import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
import cn.iocoder.yudao.module.system.api.auth.AdminOauthUserOtherInfoApi;
import cn.iocoder.yudao.module.system.api.auth.dto.AdminOauthUserOtherInfoApiDTO;
import cn.iocoder.yudao.module.system.api.auth.vo.AdminOauthUserOtherInfoApiVO;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.extern.slf4j.Slf4j;
@ -33,6 +38,7 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
@ -69,6 +75,8 @@ public class FinancialPaymentServiceImpl implements FinancialPaymentService {
private BpmProcessInstanceExtMapper processInstanceExtMapper;
@Resource
private DeptApi deptApi;
@Resource
private AdminOauthUserOtherInfoApi adminOauthUserOtherInfoApi;
@Override
public Long createFinancialPayment(FinancialPaymentSaveVO vo) {
@ -112,22 +120,29 @@ public class FinancialPaymentServiceImpl implements FinancialPaymentService {
processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
}
this.updateById(financialPayment);
try {
AdminUserRespDTO adminUserRespDTO = userApi.getUser(financialPayment.getUserId()).getData();
if (StrUtil.isNotEmpty(adminUserRespDTO.getOpenId())) {
// -- 获取发起人的openId
AdminOauthUserOtherInfoApiVO item = adminOauthUserOtherInfoApi.getByCondition(
new AdminOauthUserOtherInfoApiDTO().setUserIds(Collections.singletonList(financialPayment.getUserId()))
.setSocialType(SocialTypeEnum.WECHAT_MP.getType())).getCheckedData();
if (item != null && StrUtil.isNotEmpty(item.getOpenId())) {
try {
String result = vo.getStatus() == 1 ? "通过" : "拒绝";
String page = vo.getStatus() == 1 ?
"subPages/paymentVoucher/paymentVoucher?id=" + financialPayment.getId() :
String page = vo.getStatus() == 1 ? "subPages/paymentVoucher/paymentVoucher?id=" + financialPayment.getId() :
"subPagesB/bpm/task/todo/examineApprove?id=" + financialPayment.getId() + "&isDetail=1";
// --- 发消息通知发起人
String time = financialPaymentItem.getCreateTime().format(Constants.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND);
subscribeMessageSendApi.sendApprovalResultNotification(
BpmMessageConvert.INSTANCE.convertApprovalResultNotificationPage(
adminUserRespDTO.getOpenId(), financialPayment.getProcessInstanceName(), time, result, (StrUtil.isEmpty(financialPaymentItem.getNotes()) ? result : financialPaymentItem.getNotes()),
"formal", page));
SubscribeMessageReqDTO dto = WxMiNiMsgTemplate.INSTANCE.convertApprovalResultNotification(new ApprovalResultNotificationMessageDTO()
.setOpenId(item.getOpenId())
.setProcessInstanceName(financialPayment.getProcessInstanceName())
.setTime(time)
.setResult(result)
.setReason((StrUtil.isEmpty(financialPaymentItem.getNotes()) ? result : financialPaymentItem.getNotes()))
.setMiniProgramState("formal")
.setPage(page));
subscribeMessageSendApi.sendMsg(dto);
} catch (Exception e) {
log.error("财务管理审批发送通知人失败:{}", financialPayment);
}
} catch (Exception e) {
log.error("财务管理审批发送通知人失败:{}", financialPayment);
}
// 返回
return financialPayment.getId();

View File

@ -1,5 +1,11 @@
package cn.iocoder.yudao.module.bpm.service.message;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.template.WxMiNiMsgTemplate;
import cn.iocoder.yudao.framework.common.template.dto.ApprovalResultNotificationMessageDTO;
import cn.iocoder.yudao.framework.common.template.dto.MessageUnreadReminderDTO;
import cn.iocoder.yudao.framework.common.template.dto.ProcessToDoReminderDTO;
import cn.iocoder.yudao.framework.common.template.vo.SubscribeMessageReqDTO;
import cn.iocoder.yudao.framework.web.config.WebProperties;
import cn.iocoder.yudao.module.bpm.convert.message.BpmMessageConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkTaskDO;
@ -11,6 +17,9 @@ import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcess
import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO;
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAWorkTaskService;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.system.api.auth.AdminOauthUserOtherInfoApi;
import cn.iocoder.yudao.module.system.api.auth.dto.AdminOauthUserOtherInfoApiDTO;
import cn.iocoder.yudao.module.system.api.auth.vo.AdminOauthUserOtherInfoApiVO;
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@ -21,8 +30,7 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -54,6 +62,8 @@ public class BpmMessageServiceImpl implements BpmMessageService {
@Resource
private BpmOAWorkTaskService workTaskService;
@Resource
private AdminOauthUserOtherInfoApi adminOauthUserOtherInfoApi;
@Override
public void sendMessageWhenProcessInstanceApprove(BpmMessageSendWhenProcessInstanceApproveReqDTO reqDTO) {
@ -86,53 +96,62 @@ public class BpmMessageServiceImpl implements BpmMessageService {
}
//发送审批结果通知至微信
String openId = getUserOpenId(reqDTO.getStartUserId());
if (openId != null) {
List<AdminOauthUserOtherInfoApiVO> list = this.getUserOpenId(Collections.singletonList(reqDTO.getStartUserId()), SocialTypeEnum.WECHAT_MP.getType());
for (AdminOauthUserOtherInfoApiVO item : list) {
String openId = item.getOpenId();
if (openId != null) {
if (workTaskDO != null) {
AdminUserRespDTO userRespDTO = userApi.getUser(workTaskDO.getReceiverUserId()).getCheckedData();
SubscribeMessageReqDTO dto = WxMiNiMsgTemplate.INSTANCE.convertMessageUnreadReminder(new MessageUnreadReminderDTO()
.setOpenId(openId)
.setMsgType(reqDTO.getProcessInstanceName())
.setSender(nickName)
.setComment("你分配的任务已完成!")
.setSendingTime(reqDTO.getCreateTime())
.setPage("subPages/task/taskAssignment?userId=" + workTaskDO.getReceiverUserId() + "&deptId=" + userRespDTO.getDeptId())
.setMiniProgramState("formal"));
subscribeMessageSendApi.sendMsg(dto);
if (workTaskDO != null) {
AdminUserRespDTO userRespDTO = userApi.getUser(workTaskDO.getReceiverUserId()).getCheckedData();
subscribeMessageSendApi.sendWorkLogComment(BpmMessageConvert.INSTANCE.convertWorkTask(
openId, reqDTO.getProcessInstanceName(), workTaskDO, nickName, reqDTO.getCreateTime(),
"formal", true, userRespDTO.getDeptId()));
} else {
subscribeMessageSendApi.sendApprovalResultNotification(
BpmMessageConvert.INSTANCE.convertApprovalResultNotification(
openId, reqDTO.getProcessInstanceName(), reqDTO.getCreateTime(), "通过", reqDTO.getReason(),
reqDTO.getProcessInstanceId(),
/**
* 跳转小程序类型developer为开发版trial为体验版formal为正式版默认为正式版
*/
"formal"));
} else {
SubscribeMessageReqDTO dto = WxMiNiMsgTemplate.INSTANCE.convertApprovalResultNotification(new ApprovalResultNotificationMessageDTO()
.setOpenId(openId)
.setProcessInstanceName(reqDTO.getProcessInstanceName())
.setTime(reqDTO.getCreateTime())
.setResult("通过")
.setReason(reqDTO.getReason())
.setMiniProgramState("formal")
.setPage("subPagesB/bpm/task/todo/examineApprove?id=" + reqDTO.getProcessInstanceId() + "&isDetail=1"));
subscribeMessageSendApi.sendMsg(dto);
}
}
}
//当流程全部审批通过
BpmProcessInstanceExtDO processInstance = bpmProcessInstanceService.getProcessInstanceDO(reqDTO.getProcessInstanceId());
if (processInstance.getResult().equals(BpmProcessInstanceResultEnum.APPROVE.getResult())) {
//获取抄送用户ID
String ccIDs = processInstance.getCcids();
if (ccIDs != null && !ccIDs.isEmpty()) {
Pattern pattern = Pattern.compile("\\[(\\d+)]");
Matcher matcher = pattern.matcher(ccIDs);
List<Long> userIds = new ArrayList<>();
while (matcher.find()) {
String ccID = matcher.group(1);
String ccOpenId = getUserOpenId(Long.valueOf(ccID));
userIds.add(Long.valueOf(ccID));
//发送抄送信息至微信
if (ccOpenId != null) {
subscribeMessageSendApi.sendApprovalResultNotification(
BpmMessageConvert.INSTANCE.convertApprovalResultNotification(
ccOpenId, reqDTO.getProcessInstanceName(), reqDTO.getCreateTime(), "抄送", reqDTO.getReason(),
reqDTO.getProcessInstanceId(),
/**
* 跳转小程序类型developer为开发版trial为体验版formal为正式版默认为正式版
*/
"formal"));
}
List<AdminOauthUserOtherInfoApiVO> adminOauthUserOtherInfoApiVOS = this.getUserOpenId(userIds, SocialTypeEnum.WECHAT_MP.getType());
for (AdminOauthUserOtherInfoApiVO adminOauthUserOtherInfoApiVO : adminOauthUserOtherInfoApiVOS) {
if (adminOauthUserOtherInfoApiVO.getOpenId() != null) {
SubscribeMessageReqDTO dto = WxMiNiMsgTemplate.INSTANCE.convertApprovalResultNotification(new ApprovalResultNotificationMessageDTO()
.setOpenId(adminOauthUserOtherInfoApiVO.getOpenId())
.setProcessInstanceName(reqDTO.getProcessInstanceName())
.setTime(reqDTO.getCreateTime())
.setResult("抄送")
.setReason(reqDTO.getReason())
.setMiniProgramState("formal")
.setPage("subPagesB/bpm/task/todo/examineApprove?id=" + reqDTO.getProcessInstanceId() + "&isDetail=1"));
subscribeMessageSendApi.sendMsg(dto);
}
}
}
@ -152,16 +171,19 @@ public class BpmMessageServiceImpl implements BpmMessageService {
reqDTO.getStartUserId(), BpmMessageEnum.PROCESS_INSTANCE_REJECT.getSmsTemplateCode(), templateParams));
// //发送审批结果通知
String openId = getUserOpenId(reqDTO.getStartUserId());
if (openId != null) {
subscribeMessageSendApi.sendApprovalResultNotification(
BpmMessageConvert.INSTANCE.convertApprovalResultNotification(
openId, reqDTO.getProcessInstanceName(), reqDTO.getCreateTime(), "不通过", reqDTO.getReason(),
reqDTO.getProcessInstanceId(),
/**
* 跳转小程序类型developer为开发版trial为体验版formal为正式版默认为正式版
*/
"formal"));
List<AdminOauthUserOtherInfoApiVO> list = this.getUserOpenId(Collections.singletonList(reqDTO.getStartUserId()));
for (AdminOauthUserOtherInfoApiVO item : list) {
if (item.getOpenId() != null) {
SubscribeMessageReqDTO dto = WxMiNiMsgTemplate.INSTANCE.convertApprovalResultNotification(new ApprovalResultNotificationMessageDTO()
.setOpenId(item.getOpenId())
.setProcessInstanceName(reqDTO.getProcessInstanceName())
.setTime(reqDTO.getCreateTime())
.setResult("不通过")
.setReason(reqDTO.getReason())
.setMiniProgramState("formal")
.setPage("subPagesB/bpm/task/todo/examineApprove?id=" + reqDTO.getProcessInstanceId() + "&isDetail=1"));
subscribeMessageSendApi.sendMsg(dto);
}
}
}
@ -205,22 +227,35 @@ public class BpmMessageServiceImpl implements BpmMessageService {
//微信小程序订阅消息
//发送OA流程待办提醒
String openId = getUserOpenId(assigneeUserId); //只有在微信小程序登陆过用户才会有openid
List<AdminOauthUserOtherInfoApiVO> list = getUserOpenId(Collections.singletonList(assigneeUserId));//只有在微信小程序登陆过用户才会有openid
try {
if (openId != null) {
if (workTaskDO != null) {
subscribeMessageSendApi.sendWorkLogComment(BpmMessageConvert.INSTANCE.convertWorkTask(
openId, reqDTO.getProcessInstanceName(), workTaskDO, reqDTO.getStartUserNickname(), reqDTO.getCreateTime(),
"formal", false, null));
} else {
subscribeMessageSendApi.sendProcessToDoReminder(BpmMessageConvert.INSTANCE.convertProcessToDoReminder(
openId, reqDTO.getProcessInstanceName(), reqDTO.getStartUserNickname(), reqDTO.getCreateTime(), reqDTO.getSchedule(),
reqDTO.getProcessInstanceId(),
"formal"));
for (AdminOauthUserOtherInfoApiVO item : list) {
if (item.getOpenId() != null) {
if (workTaskDO != null) {
SubscribeMessageReqDTO dto = WxMiNiMsgTemplate.INSTANCE.convertMessageUnreadReminder(new MessageUnreadReminderDTO()
.setOpenId(item.getOpenId())
.setMsgType(reqDTO.getProcessInstanceName())
.setSender(reqDTO.getStartUserNickname())
.setComment("你收到了一个新的任务!")
.setSendingTime(reqDTO.getCreateTime())
.setPage("subPages/task/taskDispose?id=" + workTaskDO.getId())
.setMiniProgramState("formal"));
subscribeMessageSendApi.sendMsg(dto);
} else {
SubscribeMessageReqDTO dto = WxMiNiMsgTemplate.INSTANCE.convertProcessToDoReminder(new ProcessToDoReminderDTO()
.setOpenId(item.getOpenId())
.setProcessType("您收到了一条新的待办任务:" + reqDTO.getProcessInstanceName())
.setStartUserNickname(reqDTO.getStartUserNickname())
.setTime(reqDTO.getCreateTime())
.setSchedule(reqDTO.getSchedule())
.setMiniProgramState("formal")
.setPage("subPagesB/bpm/task/todo/examineApprove?id=" + reqDTO.getProcessInstanceId()));
subscribeMessageSendApi.sendMsg(dto);
}
}
}
} catch (Exception e) {
log.error("发送OA流程待办提醒失败,openId:{}", openId);
log.error("发送OA流程待办提醒失败:{}", e.getMessage());
}
}
}
@ -230,9 +265,13 @@ public class BpmMessageServiceImpl implements BpmMessageService {
return webProperties.getAdminUi().getUrl() + "/process-instance/detail?id=" + taskId;
}
private String getUserOpenId(Long userId) {
AdminUserRespDTO adminUserRespDTO = userApi.getUser(userId).getData();
private List<AdminOauthUserOtherInfoApiVO> getUserOpenId(List<Long> userIds, Integer socialType) {
return adminOauthUserOtherInfoApi.getOpenIdByCondition(
new AdminOauthUserOtherInfoApiDTO().setUserIds(userIds)
.setSocialType(socialType)).getCheckedData();
}
return adminUserRespDTO.getOpenId();
private List<AdminOauthUserOtherInfoApiVO> getUserOpenId(List<Long> userIds) {
return this.getUserOpenId(userIds, SocialTypeEnum.WECHAT_MINI_APP.getType());
}
}

View File

@ -8,7 +8,7 @@
<version>2.0.0-jdk8-snapshot</version>
</parent>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-hrm</artifactId>
<artifactId>yudao-module-crm</artifactId>
<version>2.0.0-jdk8-snapshot</version>
<packaging>pom</packaging>
<name>${project.artifactId}</name>
@ -16,7 +16,7 @@
1. 我们放基础设施的运维与管理,支撑上层的通用与核心业务。 例如说:定时任务的管理、服务器的信息等等
2. 研发工具,提升研发效率与质量。 例如说:代码生成器、接口文档等等</description>
<modules>
<module>yudao-module-hrm-api</module>
<module>yudao-module-hrm-biz</module>
<module>yudao-module-crm-api</module>
<module>yudao-module-crm-biz</module>
</modules>
</project>

View File

@ -4,11 +4,11 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-hrm</artifactId>
<artifactId>yudao-module-crm</artifactId>
<version>2.0.0-jdk8-snapshot</version>
</parent>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-hrm-api</artifactId>
<artifactId>yudao-module-crm-api</artifactId>
<version>2.0.0-jdk8-snapshot</version>
<name>${project.artifactId}</name>
<description>infra 模块 API暴露给其它模块调用</description>

View File

@ -4,11 +4,11 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-hrm</artifactId>
<artifactId>yudao-module-crm</artifactId>
<version>2.0.0-jdk8-snapshot</version>
</parent>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-hrm-biz</artifactId>
<artifactId>yudao-module-crm-biz</artifactId>
<version>2.0.0-jdk8-snapshot</version>
<name>${project.artifactId}</name>
<description>infra 模块,主要提供两块能力:
@ -21,7 +21,17 @@
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-hrm-api</artifactId>
<artifactId>yudao-module-crm-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-product-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-module-system-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
@ -109,12 +119,6 @@
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-file</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>zn-module-smartfactory-api</artifactId>
<version>2.0.0-jdk8-snapshot</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
@ -131,6 +135,13 @@
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.member.controller.app.auth.vo;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -53,4 +53,4 @@ public class AppAuthLoginReqVO {
return socialType == null || StrUtil.isNotEmpty(socialState);
}
}
}

View File

@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.member.controller.app.auth.vo;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -55,4 +55,4 @@ public class AppAuthSmsLoginReqVO {
return socialType == null || StrUtil.isNotEmpty(socialState);
}
}
}

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.member.controller.app.auth.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -31,4 +31,4 @@ public class AppAuthSocialLoginReqVO {
@NotEmpty(message = "state 不能为空")
private String state;
}
}

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.member.controller.app.social.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -31,4 +31,4 @@ public class AppSocialUserBindReqVO {
@NotEmpty(message = "state 不能为空")
private String state;
}
}

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.member.controller.app.social.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -27,4 +27,4 @@ public class AppSocialUserUnbindReqVO {
@NotEmpty(message = "社交用户的 openid 不能为空")
private String openid;
}
}

View File

@ -26,7 +26,7 @@ import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.system.api.auth;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.auth.dto.AdminOauthUserOtherInfoApiDTO;
import cn.iocoder.yudao.module.system.api.auth.vo.AdminOauthUserOtherInfoApiVO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@Tag(name = "RPC 服务 - 用户三方账号")
public interface AdminOauthUserOtherInfoApi {
String PREFIX = ApiConstants.PREFIX + "/oauth-user-other-info";
@PostMapping(PREFIX + "/getOpenIdByCondition")
@Operation(summary = "根据条件查询用户三方账号信息")
CommonResult<List<AdminOauthUserOtherInfoApiVO>> getOpenIdByCondition(@RequestBody AdminOauthUserOtherInfoApiDTO dto);
@PostMapping(PREFIX + "/getByCondition")
@Operation(summary = "根据条件查询用户三方账号信息")
CommonResult<AdminOauthUserOtherInfoApiVO> getByCondition(@RequestBody AdminOauthUserOtherInfoApiDTO dto);
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.system.api.auth.dto;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@Data
@Accessors(chain = true)
public class AdminOauthUserOtherInfoApiDTO {
/**
* 社交平台的类型 (参见 {@link SocialTypeEnum} 枚举)
*/
private Integer socialType = SocialTypeEnum.WECHAT_MINI_APP.getType();
/**
* 用户状态 0开启 1关闭
*/
private Integer status;
/**
* 用户类型 1公司用户 2工厂用户
*/
private Integer userType;
/**
* 部门ids
*/
private List<Long> deptIds;
/**
* 用户ids
*/
private List<Long> userIds;
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.system.api.auth.vo;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class AdminOauthUserOtherInfoApiVO {
/**
* 编号
*/
private Long id;
/**
* 用户编号
*/
private Long userId;
/**
* 应用appId
*/
private String appId;
/**
* 微信openId
*/
private String openId;
/**
* 社交平台的类型 (参见 {@link SocialTypeEnum} 枚举)
*/
private Integer socialType;
}

View File

@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.system.api.social.dto;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;

View File

@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.system.api.social.dto;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.system.api.subscribe;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.subscribe.dto.SubscribeMessageReqDTO;
import cn.iocoder.yudao.framework.common.template.vo.SubscribeMessageReqDTO;
import cn.iocoder.yudao.module.system.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -9,31 +9,13 @@ import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@Tag(name = "RPC 服务 - 微信小程序订阅消息发送")
public interface SubscribeMessageSendApi {
String PREFIX = ApiConstants.PREFIX + "/subscribe/send";
@PostMapping(PREFIX + "/send-approval-result-notification")
@Operation(summary = "发送审批结果通知")
CommonResult<Long> sendApprovalResultNotification(@RequestBody SubscribeMessageReqDTO reqDTO);
@PostMapping(PREFIX + "/send-process-todo-reminder")
@Operation(summary = "发送OA流程待办提醒")
CommonResult<Long> sendProcessToDoReminder(@RequestBody SubscribeMessageReqDTO reqDTO);
@PostMapping(PREFIX + "/send-company-notice")
@Operation(summary = "发送公司公告通知")
CommonResult<Long> sendCompanyNotice(@RequestBody SubscribeMessageReqDTO reqDTO);
@PostMapping(PREFIX + "/send-worklog-comment")
@Operation(summary = "发送日志评论、回复通知")
CommonResult<Long> sendWorkLogComment(@RequestBody SubscribeMessageReqDTO reqDTO);
@PostMapping(PREFIX + "/send-punch-reminder")
@Operation(summary = "发送打卡提醒通知")
CommonResult<Long> sendPunchReminder(@RequestBody SubscribeMessageReqDTO reqDTO);
@PostMapping(PREFIX + "/send-msg")
@Operation(summary = "发送消息")
CommonResult<Long> sendMsg(@RequestBody SubscribeMessageReqDTO reqDTO);
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.system.api.auth;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.auth.dto.AdminOauthUserOtherInfoApiDTO;
import cn.iocoder.yudao.module.system.api.auth.vo.AdminOauthUserOtherInfoApiVO;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminOauthUserOtherInfoDO;
import cn.iocoder.yudao.module.system.service.auth.AdminOauthUserOtherInfoService;
import cn.iocoder.yudao.module.system.service.auth.dto.AdminOauthUserOtherInfoDTO;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
public class AdminOauthUserOtherInfoApiImpl implements AdminOauthUserOtherInfoApi {
@Resource
private AdminOauthUserOtherInfoService adminOauthUserOtherInfoService;
@Override
public CommonResult<List<AdminOauthUserOtherInfoApiVO>> getOpenIdByCondition(AdminOauthUserOtherInfoApiDTO dto) {
AdminOauthUserOtherInfoDTO adminOauthUserOtherInfoDTO = BeanUtil.copyProperties(dto, AdminOauthUserOtherInfoDTO.class);
List<AdminOauthUserOtherInfoDO> list = adminOauthUserOtherInfoService.getOpenIdByCondition(adminOauthUserOtherInfoDTO);
return CommonResult.success(BeanUtil.copyToList(list, AdminOauthUserOtherInfoApiVO.class));
}
@Override
public CommonResult<AdminOauthUserOtherInfoApiVO> getByCondition(AdminOauthUserOtherInfoApiDTO dto) {
AdminOauthUserOtherInfoDTO adminOauthUserOtherInfoDTO = BeanUtil.copyProperties(dto, AdminOauthUserOtherInfoDTO.class);
List<AdminOauthUserOtherInfoDO> list = adminOauthUserOtherInfoService.getOpenIdByCondition(adminOauthUserOtherInfoDTO);
if (CollUtil.isNotEmpty(list)) {
return CommonResult.success(BeanUtil.copyProperties(list.get(0), AdminOauthUserOtherInfoApiVO.class));
}
return CommonResult.success(null);
}
}

View File

@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.module.system.service.social.SocialClientService;
import lombok.SneakyThrows;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
@ -13,15 +14,12 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.io.File;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
/**
* 社交应用的 API 实现类
*
*/
@RestController
@Validated
@ -43,7 +41,7 @@ public class SocialClientApiImpl implements SocialClientApi {
@Override
public CommonResult<SocialWxPhoneNumberInfoRespDTO> getWxMaPhoneNumberInfo(Integer userType, String phoneCode) {
WxMaPhoneNumberInfo info = socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode);
WxMaPhoneNumberInfo info = socialClientService.getWxMaPhoneNumberInfo(SocialTypeEnum.WECHAT_MINI_APP.getType(), userType, phoneCode);
return success(BeanUtils.toBean(info, SocialWxPhoneNumberInfoRespDTO.class));
}

View File

@ -1,9 +1,10 @@
package cn.iocoder.yudao.module.system.api.subscribe;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.subscribe.dto.MsgData;
import cn.iocoder.yudao.module.system.api.subscribe.dto.SubscribeMessageReqDTO;
import cn.iocoder.yudao.framework.common.template.vo.MsgData;
import cn.iocoder.yudao.framework.common.template.vo.SubscribeMessageReqDTO;
import cn.iocoder.yudao.module.system.service.social.SocialClientService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@ -14,6 +15,7 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -32,63 +34,32 @@ public class SubscribeMessageSendApiImpl implements SubscribeMessageSendApi {
@Resource
private SocialClientService socialClientService;
private final static List<Integer> wechatMiniList = Arrays.asList(SocialTypeEnum.WECHAT_MINI_APP.getType(),
SocialTypeEnum.WECHAT_MINI_APP_CRM.getType());
@SneakyThrows
@Override
public CommonResult<Long> sendApprovalResultNotification(SubscribeMessageReqDTO reqDTO) {
public CommonResult<Long> sendMsg(SubscribeMessageReqDTO reqDTO) {
//发送审批结果通知
String type = reqDTO.getMinOrMpType() ;
if( type == null || type.equals("1") ) {
Integer socialType = reqDTO.getSocialType();
if (wechatMiniList.contains(socialType)) {
socialClientService.getWxMaService().getMsgService().sendSubscribeMsg(initWxMaSubscribeMessage(reqDTO));
} else {
socialClientService.getWxMpService().getTemplateMsgService().sendTemplateMsg(initWxMpSubscribeMessage(reqDTO)) ;
// -- 公众号 点击 跳转 小程序 - 需要获取到小程序appId
reqDTO.getSocialType();
socialClientService.getWxMpService().getTemplateMsgService().sendTemplateMsg(initWxMpSubscribeMessage(reqDTO));
}
return success(1L);
}
@SneakyThrows
@Override
public CommonResult<Long> sendProcessToDoReminder(SubscribeMessageReqDTO reqDTO) {
//发送OA流程待办提醒
String type = reqDTO.getMinOrMpType() ;
if( type == null || type.equals("1") ) {
socialClientService.getWxMaService().getMsgService().sendSubscribeMsg(initWxMaSubscribeMessage(reqDTO));
} else {
socialClientService.getWxMpService().getTemplateMsgService().sendTemplateMsg(initWxMpSubscribeMessage(reqDTO)) ;
}
return success(1L);
}
@SneakyThrows
@Override
public CommonResult<Long> sendCompanyNotice(SubscribeMessageReqDTO reqDTO) {
socialClientService.getWxMaService().getMsgService().sendSubscribeMsg(initWxMaSubscribeMessage(reqDTO));
return success(1L);
}
@SneakyThrows
@Override
public CommonResult<Long> sendWorkLogComment(SubscribeMessageReqDTO reqDTO) {
socialClientService.getWxMaService().getMsgService().sendSubscribeMsg(initWxMaSubscribeMessage(reqDTO));
return success(1L);
}
@Override
public CommonResult<Long> sendPunchReminder(SubscribeMessageReqDTO reqDTO) {
try {
socialClientService.getWxMaService().getMsgService().sendSubscribeMsg(initWxMaSubscribeMessage(reqDTO));
} catch (Exception e) {
log.error("当前用户没有订阅考勤消息:{}", reqDTO.getToUser());
}
return success(1L);
}
private WxMaSubscribeMessage initWxMaSubscribeMessage(SubscribeMessageReqDTO reqDTO) {
WxMaSubscribeMessage message = WxMaSubscribeMessage.builder()
.toUser(reqDTO.getToUser())
.templateId(reqDTO.getTemplateId())
.build();
message.setMiniprogramState(reqDTO.getMiniprogramState());
message.setMiniprogramState(reqDTO.getMiniProgramState());
List<MsgData> dataList = reqDTO.getData();
for (MsgData msgData : dataList) {
WxMaSubscribeMessage.MsgData wxMsgData = new WxMaSubscribeMessage.MsgData();
@ -101,20 +72,20 @@ public class SubscribeMessageSendApiImpl implements SubscribeMessageSendApi {
}
private WxMpTemplateMessage initWxMpSubscribeMessage(SubscribeMessageReqDTO reqDTO){
private WxMpTemplateMessage initWxMpSubscribeMessage(SubscribeMessageReqDTO reqDTO) {
List<MsgData> dataList = reqDTO.getData();
List<WxMpTemplateData> data = new ArrayList<>();
for (MsgData msgData : dataList) {
WxMpTemplateData wxMpTemplateData = new WxMpTemplateData();
wxMpTemplateData.setName(msgData.getName());
wxMpTemplateData.setValue(msgData.getValue());
data.add(wxMpTemplateData) ;
data.add(wxMpTemplateData);
}
WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
.toUser(reqDTO.getToUser())
.templateId(reqDTO.getTemplateId())
.data(data)
.build();
return templateMessage ;
return templateMessage;
}
}

View File

@ -0,0 +1,99 @@
package cn.iocoder.yudao.module.system.controller;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminWxMpInfoDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.module.system.service.auth.AdminOauthUserOtherInfoService;
import cn.iocoder.yudao.module.system.service.auth.AdminWxMpInfoService;
import cn.iocoder.yudao.module.system.service.social.SocialClientService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Tag(name = "管理后台 - 微信公众号")
@RestController
@RequestMapping("/wei-xin")
@Slf4j
public class WeiXinController {
@Resource
private SocialClientService socialClientService;
@Resource
private AdminUserService adminUserService;
@Resource
private AdminWxMpInfoService adminWxMpInfoService;
@Resource
private AdminOauthUserOtherInfoService adminOauthUserOtherInfoService;
@RequestMapping(value = "/monitor", method = {RequestMethod.POST, RequestMethod.GET})
@PermitAll
public void monitor(HttpServletRequest request, HttpServletResponse response) throws IOException {
TenantContextHolder.setTenantId(1L);
response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
String msgSignature = request.getParameter("msg_signature");
String signature = request.getParameter("signature");
String nonce = request.getParameter("nonce");
String timestamp = request.getParameter("timestamp");
String echostr = request.getParameter("echostr");
log.info("微信公众号信息signature={}, timestamp={}, nonce={}, echostr={},msgSignature={}", signature, timestamp, nonce, echostr, msgSignature);
if (StringUtils.isNotBlank(echostr)) {
if (!socialClientService.getWxMpService().checkSignature(timestamp, nonce, signature)) {
// 消息签名不正确说明不是公众平台发过来的消息
response.getWriter().println("非法请求");
return;
}
// 说明是一个仅仅用来验证的请求回显echostr
response.getWriter().println(echostr);
return;
}
WxMpXmlMessage wxMpXmlMessage = WxMpXmlMessage.fromXml(request.getInputStream());
try {
WxMpUser wxMpUser = socialClientService.getWxMpService().getUserService().userInfo(wxMpXmlMessage.getFromUser());
String unionId = wxMpUser.getUnionId();
String event = wxMpXmlMessage.getEvent();
String openId = wxMpXmlMessage.getFromUser();
// - subscribe 订阅
// unsubscribe 取消订阅
// ---- 先通过unionId获取用户信息 - 如果没有获取到的话 - 插入到表中记录 unionId和公众号openId信息 - 后续用户有unionId后再进行绑定
AdminUserDO adminUserDO = adminUserService.getUserByUnionId(unionId);
String appId = socialClientService.getWxMpService().getWxMpConfigStorage().getAppId();
if ("subscribe".equals(event)) {
if (adminUserDO == null) {
adminWxMpInfoService.save(new AdminWxMpInfoDO()
.setAppId(appId)
.setOpenId(openId)
.setUnionId(unionId));
} else {
// ---- 检查 / 插入 公众号openId
adminOauthUserOtherInfoService.checkInsert(adminUserDO.getId(), appId, openId, SocialTypeEnum.WECHAT_MP.getType());
}
} else {
//删除存贮的公众号openId - 这里不管他有没有存 - 先删再说
adminWxMpInfoService.del(appId, unionId);
if (adminUserDO != null) {
// -- 删除 关联的 公众号openId
adminOauthUserOtherInfoService.delByCondition(adminUserDO.getId(), appId, openId, SocialTypeEnum.WECHAT_MP.getType());
}
}
log.info("微信信息用户信息:{}", wxMpUser);
} catch (WxErrorException e) {
throw new RuntimeException(e);
}
log.info("微信公众号信息:{}", wxMpXmlMessage);
}
}

View File

@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -18,10 +18,10 @@ import javax.validation.constraints.NotNull;
@Builder
public class AuthSocialLoginReqVO {
@Schema(description = "社交平台的类型,参见 UserSocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
@Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
@InEnum(SocialTypeEnum.class)
@NotNull(message = "社交平台的类型不能为空")
private Integer type;
private Integer type = SocialTypeEnum.WECHAT_MINI_APP.getType();
@Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotEmpty(message = "授权码不能为空")
@ -35,4 +35,8 @@ public class AuthSocialLoginReqVO {
@NotEmpty(message = "openId 不能为空")
private String openId;
@Schema(description = "unionId", requiredMode = Schema.RequiredMode.REQUIRED, example = "o3bwX6Yw1bvbMAV-jUNjHrbrJu0I")
@NotEmpty(message = "unionId 不能为空")
private String unionId;
}

View File

@ -1,34 +1,32 @@
package cn.iocoder.yudao.module.system.controller.admin.punchrecord;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAReplacementCardApi;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.annotation.security.PermitAll;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.*;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAReplacementCardApi;
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordRespVO;
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 用户打卡记录")
@RestController
@ -101,12 +99,12 @@ public class AttendancePunchRecordController {
@PreAuthorize("@ss.hasPermission('attendance:punch-record:export')")
@OperateLog(type = EXPORT)
public void exportPunchRecordExcel(@Valid AttendancePunchRecordPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<AttendancePunchRecordDO> list = punchRecordService.getPunchRecordPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "用户打卡记录.xls", "数据", AttendancePunchRecordRespVO.class,
BeanUtils.toBean(list, AttendancePunchRecordRespVO.class));
BeanUtils.toBean(list, AttendancePunchRecordRespVO.class));
}
}

View File

@ -4,7 +4,7 @@ import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.socail.vo.user;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.socail.vo.user;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;

View File

@ -1,127 +0,0 @@
package cn.iocoder.yudao.module.system.convert.notice;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.module.system.api.subscribe.dto.MsgData;
import cn.iocoder.yudao.module.system.api.subscribe.dto.SubscribeMessageReqDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.notice.NoticeDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.Date;
/**
* 功能描述
*
* @author yj
* date 2024年04月07日 19:44
*/
@Mapper
public interface NoticeConvert {
NoticeConvert INSTANCE = Mappers.getMapper(NoticeConvert.class);
/**
* @param openId 微信小程序唯一id
* @param notice 公告对象
* @param nickname 发布人姓名
* @param miniProgramState 小程序的状态
* @return
*/
default SubscribeMessageReqDTO convertCompanyNotice(String openId, NoticeDO notice, String noticeLabel, String nickname, String miniProgramState) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(openId);
message.setTemplateId("OF4-948Vz9rtE_VA55rmDxo4azOwmrjjk33jDpOiPiY");
//通知类型
MsgData noticeType = new MsgData();
noticeType.setName("thing1");
noticeType.setValue(noticeLabel); //这里根据业务需求填写具体的公告类型 如全员公告 xxx公告
message.addData(noticeType);
//公告标题
String value = notice.getTitle();
if (value.length() > 10) {
value = value.substring(0,10) + ". . . . ";
}
MsgData title = new MsgData();
title.setName("thing6");
title.setValue(value);
message.addData(title);
//通知内容
MsgData content = new MsgData();
content.setName("thing2");
content.setValue("具体内容请进入小程序查看");
message.addData(content);
//发布人
MsgData publishMan = new MsgData();
publishMan.setName("thing9");
publishMan.setValue(nickname);
message.addData(publishMan);
//通知时间
MsgData createTime = new MsgData();
createTime.setName("time3");
createTime.setValue(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));
message.addData(createTime);
message.setMiniprogramState(miniProgramState);
message.setPage("/subPages/notice/detail?id=" + notice.getId());
return message;
}
/**
* 生日提醒
* @param openId 微信小程序唯一id
* @param miniProgramState 小程序的状态
* @return 提醒模板
*/
default SubscribeMessageReqDTO convertBirthday(String type, String openId, String miniProgramState) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(openId);
message.setTemplateId("fH29xjNb8pe-7onQ-wE3QrBAC-y8aaC_oosYZKNMtzM");
//消息类型
MsgData noticeType = new MsgData();
noticeType.setName("phrase8");
//消息内容
MsgData content = new MsgData();
content.setName("thing2");
switch (type) {
case "birthday":
noticeType.setValue("生日提醒");
content.setValue("今天有人过生日请前往PC端查看");
break;
case "regular":
noticeType.setValue("转正提醒");
content.setValue("恭喜快要转正了哦,记得走转正流程!");
break;
case "contract":
noticeType.setValue("合同提醒");
content.setValue("有人合同已过期请前往PC端查看");
}
message.addData(noticeType);
message.addData(content);
//发送人
MsgData publishMan = new MsgData();
publishMan.setName("thing16");
publishMan.setValue("系统");
message.addData(publishMan);
//发送时间
MsgData createTime = new MsgData();
createTime.setName("time3");
createTime.setValue(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));
message.addData(createTime);
message.setMiniprogramState(miniProgramState);
message.setPage("");
return message;
}
}

View File

@ -1,58 +0,0 @@
package cn.iocoder.yudao.module.system.convert.worklog;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.module.system.api.subscribe.dto.MsgData;
import cn.iocoder.yudao.module.system.api.subscribe.dto.SubscribeMessageReqDTO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.Date;
@Mapper
public interface HolidayRemindConvert {
HolidayRemindConvert INSTANCE = Mappers.getMapper(HolidayRemindConvert.class);
/**
* @param openId 微信小程序唯一id
* @param miniProgramState 小程序的状态
* @return
*/
default SubscribeMessageReqDTO convertHolidayRemind(String openId, String comment, String miniProgramState) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(openId);
message.setTemplateId("fH29xjNb8pe-7onQ-wE3QrBAC-y8aaC_oosYZKNMtzM");
//消息类型
MsgData noticeType = new MsgData();
noticeType.setName("phrase8");
noticeType.setValue("假期提醒");
message.addData(noticeType);
//发送人
MsgData publishMan = new MsgData();
publishMan.setName("thing16");
publishMan.setValue("系统提醒");
message.addData(publishMan);
//发送时间
MsgData createTime = new MsgData();
createTime.setName("time3");
createTime.setValue(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));
message.addData(createTime);
//消息内容
MsgData content = new MsgData();
content.setName("thing2");
if (comment.length() > 10) {
comment = comment.substring(0, 10) + ". . . . ";
}
content.setValue(comment);
message.addData(content);
message.setMiniprogramState(miniProgramState);
// message.setPage("/subPages/workLogDetail/workLogDetail?id=" + logCommentDO.getWorkLogId());
return message;
}
}

View File

@ -1,66 +0,0 @@
package cn.iocoder.yudao.module.system.convert.worklog;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.module.system.api.subscribe.dto.MsgData;
import cn.iocoder.yudao.module.system.api.subscribe.dto.SubscribeMessageReqDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.comment.WorkLogCommentDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.Date;
@Mapper
public interface LogCommentConvert {
LogCommentConvert INSTANCE = Mappers.getMapper(LogCommentConvert.class);
/**
* @param openId 微信小程序唯一id
* @param logCommentDO 评论对象
* @param nickname 发布人姓名
* @param miniProgramState 小程序的状态
* @return
*/
default SubscribeMessageReqDTO convertLogComment(String openId, WorkLogCommentDO logCommentDO, String nickname, String miniProgramState) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(openId);
message.setTemplateId("fH29xjNb8pe-7onQ-wE3QrBAC-y8aaC_oosYZKNMtzM");
//消息类型
MsgData noticeType = new MsgData();
noticeType.setName("phrase8");
if (logCommentDO.getType()) {
noticeType.setValue("评论回复");
} else {
noticeType.setValue("日志评论");
}
message.addData(noticeType);
//发送人
MsgData publishMan = new MsgData();
publishMan.setName("thing16");
publishMan.setValue(nickname);
message.addData(publishMan);
//发送时间
MsgData createTime = new MsgData();
createTime.setName("time3");
createTime.setValue(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));
message.addData(createTime);
//消息内容
MsgData content = new MsgData();
String comment = logCommentDO.getComment();
content.setName("thing2");
if (comment.length() > 10) {
comment = comment.substring(0, 10) + ". . . . ";
}
content.setValue(comment);
message.addData(content);
message.setMiniprogramState(miniProgramState);
message.setPage("/subPages/workLogDetail/workLogDetail?id=" + logCommentDO.getWorkLogId());
return message;
}
}

View File

@ -0,0 +1,45 @@
package cn.iocoder.yudao.module.system.dal.dataobject.auth;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import lombok.*;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 用户三方登录信息 DO
*
* @author 艾楷
*/
@TableName("system_oauth_user_other_info")
@KeySequence("system_oauth_user_other_info_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AdminOauthUserOtherInfoDO extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/**
* 用户编号
*/
private Long userId;
/**
* 应用appId
*/
private String appId;
/**
* 微信openId
*/
private String openId;
/**
* 社交平台的类型 (参见 {@link SocialTypeEnum} 枚举)
*/
private Integer socialType;
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.system.dal.dataobject.auth;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
/**
* 用户三方登录信息 DO
*
* @author 艾楷
*/
@TableName("system_user_wx_mp_info")
@KeySequence("system_user_wx_mp_info_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AdminWxMpInfoDO extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/**
* 应用appId
*/
private String appId;
/**
* unionId
*/
private String openId;
/**
* 公众号微信openId
*/
private String unionId;
}

View File

@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.social;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@ -15,7 +15,7 @@ import lombok.*;
*
* 对应 {@link AuthConfig} 配置满足不同租户有自己的客户端配置实现社交三方登录
*
*/
@TableName(value = "system_social_client", autoResultMap = true)
@KeySequence("system_social_client_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.system.dal.dataobject.social;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

View File

@ -153,6 +153,10 @@ public class AdminUserDO extends TenantBaseDO {
* 微信小程序openId
*/
private String openId;
/**
* 微信unionId
*/
private String unionId;
@TableField(exist = false)
private String deptName;

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.system.dal.mysql.auth;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminOauthUserOtherInfoDO;
import cn.iocoder.yudao.module.system.service.auth.dto.AdminOauthUserOtherInfoDTO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 用户三方登录信息 Mapper
*
* @author 艾楷
*/
@Mapper
public interface AdminOauthUserOtherInfoMapper extends BaseMapperX<AdminOauthUserOtherInfoDO> {
/**
* 通过条件获取用户openId
*
* @param dto
* @return
*/
List<AdminOauthUserOtherInfoDO> getOpenIdByCondition(@Param("dto") AdminOauthUserOtherInfoDTO dto);
}

View File

@ -0,0 +1,16 @@
package cn.iocoder.yudao.module.system.dal.mysql.auth;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminWxMpInfoDO;
import org.apache.ibatis.annotations.Mapper;
/**
* 微信公众号用户信息表(用户暂存没有注册用户的关注信息) Mapper
*
* @author 艾楷
*/
@Mapper
public interface AdminWxMpInfoMapper extends BaseMapperX<AdminWxMpInfoDO> {
}

View File

@ -26,9 +26,6 @@ import java.util.Objects;
@Mapper
public interface AdminUserMapper extends BaseMapperX<AdminUserDO> {
default AdminUserDO sgetByOpenId(String openId) {
return selectOne(AdminUserDO::getOpenId, openId);
}
default AdminUserDO selectByUsername(String username) {
return selectOne(AdminUserDO::getUsername, username);

View File

@ -5,16 +5,19 @@ import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.Constants;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.template.WxMiNiMsgTemplate;
import cn.iocoder.yudao.framework.common.template.dto.CheckInReminderDTO;
import cn.iocoder.yudao.framework.common.template.vo.SubscribeMessageReqDTO;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
import cn.iocoder.yudao.module.system.api.subscribe.dto.MsgData;
import cn.iocoder.yudao.module.system.api.subscribe.dto.SubscribeMessageReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.attendance.dto.AttendanceWorkDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminOauthUserOtherInfoDO;
import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService;
import cn.iocoder.yudao.module.system.service.auth.AdminOauthUserOtherInfoService;
import cn.iocoder.yudao.module.system.service.auth.dto.AdminOauthUserOtherInfoDTO;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
@ -27,7 +30,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
@Slf4j
@ -38,6 +40,8 @@ public class RemindJob {
private SubscribeMessageSendApi subscribeMessageSendApi;
@Resource
private AdminUserService adminUserService;
@Resource
private AdminOauthUserOtherInfoService adminOauthUserOtherInfoService;
// TODO: 2024/4/22 - 考勤提醒 每10分钟执行一次
@XxlJob("remindJob")
@ -82,29 +86,25 @@ public class RemindJob {
return ReturnT.SUCCESS;
}
List<Long> userIds = new ArrayList<>(map.keySet());
List<AdminUserDO> userList = adminUserService.getUserList(userIds);
List<AdminUserDO> users = userList.stream().filter(a -> StrUtil.isNotEmpty(a.getOpenId())).collect(Collectors.toList());
String templateId = "5yHyXhrsyqXi8s4hYhvaeMtz9kT5OPvDCe3h6G1T-OE";
List<AdminOauthUserOtherInfoDO> list = new ArrayList<>();
if (CollectionUtil.isNotEmpty(userIds)) {
list = adminOauthUserOtherInfoService.getOpenIdByCondition(new AdminOauthUserOtherInfoDTO()
.setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType())
.setUserIds(userIds));
}
List<SubscribeMessageReqDTO> dtos = new ArrayList<>();
for (AdminUserDO user : users) {
for (AdminOauthUserOtherInfoDO user : list) {
AttendanceWorkDTO attendanceWorkDTO = map.get(user.getId());
SubscribeMessageReqDTO dto = new SubscribeMessageReqDTO();
dto.setToUser(user.getOpenId());
dto.setTemplateId(templateId);
MsgData data = new MsgData();
data.setName("thing9");
data.setValue(attendanceWorkDTO.getWorkTypeStr());
dto.addData(data);
data = new MsgData();
data.setName("thing6");
data.setValue(attendanceWorkDTO.getData());
dto.addData(data);
dto.setPage("subPages/attendance/index");
SubscribeMessageReqDTO dto = WxMiNiMsgTemplate.INSTANCE.convertCheckInReminder(new CheckInReminderDTO()
.setOpenId(user.getOpenId())
.setCheckInType(attendanceWorkDTO.getWorkTypeStr())
.setComment(attendanceWorkDTO.getData())
.setPage("subPages/attendance/index"));
dtos.add(dto);
}
if (CollectionUtil.isNotEmpty(dtos)) {
for (SubscribeMessageReqDTO dto : dtos) {
subscribeMessageSendApi.sendPunchReminder(dto);
subscribeMessageSendApi.sendMsg(dto);
}
}
if (CollectionUtil.isNotEmpty(editList)) {

View File

@ -1,14 +1,23 @@
package cn.iocoder.yudao.module.system.job.birthday;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.template.WxMiNiMsgTemplate;
import cn.iocoder.yudao.framework.common.template.dto.MessageUnreadReminderDTO;
import cn.iocoder.yudao.framework.common.template.vo.SubscribeMessageReqDTO;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
import cn.iocoder.yudao.module.system.convert.notice.NoticeConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminOauthUserOtherInfoDO;
import cn.iocoder.yudao.module.system.dal.dataobject.laborcontract.LaborContractDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
import cn.iocoder.yudao.module.system.service.auth.AdminOauthUserOtherInfoService;
import cn.iocoder.yudao.module.system.service.auth.dto.AdminOauthUserOtherInfoDTO;
import cn.iocoder.yudao.module.system.service.laborcontract.LaborContractService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
@ -25,6 +34,8 @@ import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@ -41,6 +52,8 @@ public class BirthdayJob {
@Resource
private AdminUserService userService;
@Resource
private AdminOauthUserOtherInfoService adminOauthUserOtherInfoService;
@Resource
private PermissionService permissionService;
@ -55,7 +68,6 @@ public class BirthdayJob {
@XxlJob("birthdayJob")
@TenantJob // --- 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
public ReturnT<String> execute() {
//获取参数
XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();
String jobParam = xxlJobContext.getJobParam();
@ -69,18 +81,19 @@ public class BirthdayJob {
Set<Long> userIds = permissionService.getUserRoleIdListByRoleId(CollectionUtils.singleton(roleId));
//获得用户组中 用户信息
List<AdminUserDO> userDOs = userService.getUserList(userIds);
List<AdminOauthUserOtherInfoDO> list = new ArrayList<>();
if (CollectionUtil.isNotEmpty(userIds)) {
list = adminOauthUserOtherInfoService.getOpenIdByCondition(new AdminOauthUserOtherInfoDTO()
.setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType())
.setUserIds(new ArrayList<>()));
}
// 生日提醒
birthdayRemind(userDOs);
birthdayRemind(list);
// 转正提醒
PositiveReminders(remindDuration);
// 合同到期提醒
ContractReminders(userDOs);
ContractReminders(list);
}
// 返回执行成功
return ReturnT.SUCCESS;
}
@ -88,20 +101,22 @@ public class BirthdayJob {
/**
* 合同到期提醒
*/
private void ContractReminders(List<AdminUserDO> userDOs) {
private void ContractReminders(List<AdminOauthUserOtherInfoDO> list) {
LocalDate now = LocalDate.now();
List<LaborContractDO> laborContractDOS = laborContractService.getListByEndTime(now);
if (CollectionUtil.isNotEmpty(laborContractDOS)) {
// 修改合同状态为过期
laborContractService.updateLaborContractList(convertList(laborContractDOS, LaborContractDO::getId), LaborContractDO.STATUS_EXPIRE);
for (AdminUserDO adminUserDO : userDOs) {
if( adminUserDO.getOpenId() != null && !adminUserDO.getOpenId().isEmpty()) {
subscribeMessageSendApi.sendCompanyNotice(NoticeConvert.INSTANCE.convertBirthday(
"contract", adminUserDO.getOpenId(), "formal"));
for (AdminOauthUserOtherInfoDO otherInfoDO : list) {
if (otherInfoDO.getOpenId() != null && !otherInfoDO.getOpenId().isEmpty()) {
SubscribeMessageReqDTO dto = WxMiNiMsgTemplate.INSTANCE.convertMessageUnreadReminder(new MessageUnreadReminderDTO()
.setOpenId(otherInfoDO.getOpenId())
.setMsgType("合同提醒")
.setSender("系统")
.setComment("有人合同已过期请前往PC端查看")
.setSendingTime(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND))
.setMiniProgramState("formal"));
subscribeMessageSendApi.sendMsg(dto);
}
}
}
@ -111,51 +126,62 @@ public class BirthdayJob {
* 转正提醒
*/
private void PositiveReminders(Integer remindDuration) {
// 获得提醒日期
LocalDate remindDate = LocalDate.now().plusDays(remindDuration == null ? 7 : remindDuration);
// 查询所有试用人员
List<AdminUserDO> userDOS = userService.getUserListByUserStaffing(5);
List<Long> userIds = convertList(userDOS, AdminUserDO::getId);
List<LaborContractDO> laborContractDOS = laborContractService.getListByUserIds(userIds);
List<Long> contractUserIds = laborContractDOS.stream().filter(item -> remindDate.isEqual(item.getSigningDate().plusMonths(item.getProbationPeriodTime())))
.map(LaborContractDO::getUserId)
.collect(Collectors.toList());
// 过滤需要提醒的用户
List<AdminUserDO> positiveUserList = userDOS.stream().filter(item -> contractUserIds.contains(item.getId())).collect(Collectors.toList());
for (AdminUserDO adminUserDO : positiveUserList) {
if( adminUserDO.getOpenId() != null && !adminUserDO.getOpenId().isEmpty()) {
subscribeMessageSendApi.sendCompanyNotice(NoticeConvert.INSTANCE.convertBirthday(
"regular", adminUserDO.getOpenId(), "formal"));
if (CollUtil.isNotEmpty(positiveUserList)) {
List<Long> noticeUserIds = positiveUserList.stream().map(AdminUserDO::getId).collect(Collectors.toList());
List<AdminOauthUserOtherInfoDO> list = new ArrayList<>();
if (CollectionUtil.isNotEmpty(noticeUserIds)) {
list = adminOauthUserOtherInfoService.getOpenIdByCondition(new AdminOauthUserOtherInfoDTO()
.setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType())
.setUserIds(noticeUserIds));
}
for (AdminOauthUserOtherInfoDO otherInfoDO : list) {
if (StrUtil.isNotEmpty(otherInfoDO.getOpenId())) {
SubscribeMessageReqDTO dto = WxMiNiMsgTemplate.INSTANCE.convertMessageUnreadReminder(new MessageUnreadReminderDTO()
.setOpenId(otherInfoDO.getOpenId())
.setMsgType("转正提醒")
.setSender("系统")
.setComment("恭喜快要转正了哦,记得走转正流程!")
.setSendingTime(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND))
.setMiniProgramState("formal"));
subscribeMessageSendApi.sendMsg(dto);
}
}
}
log.info("转正提醒,人员为{}", convertList(positiveUserList, AdminUserDO::getNickname));
}
/**
* 生日提醒
*/
private void birthdayRemind(List<AdminUserDO> userDOs) {
private void birthdayRemind(List<AdminOauthUserOtherInfoDO> userDOs) {
String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("MM-dd"));
// -- 获取当天月日 生日的人员列表
List<AdminUserDO> list = adminUserMapper.selectList(new LambdaQueryWrapper<AdminUserDO>()
.like(AdminUserDO::getBirthdayDay, time));
if (!list.isEmpty()) {
for (AdminUserDO adminUserDO : userDOs) {
if( adminUserDO.getOpenId() != null && !adminUserDO.getOpenId().isEmpty()) {
subscribeMessageSendApi.sendCompanyNotice(NoticeConvert.INSTANCE.convertBirthday(
"birthday", adminUserDO.getOpenId(), "formal"));
for (AdminOauthUserOtherInfoDO otherInfoDO : userDOs) {
if (otherInfoDO.getOpenId() != null && !otherInfoDO.getOpenId().isEmpty()) {
SubscribeMessageReqDTO dto = WxMiNiMsgTemplate.INSTANCE.convertMessageUnreadReminder(new MessageUnreadReminderDTO()
.setOpenId(otherInfoDO.getOpenId())
.setMsgType("生日提醒")
.setSender("系统")
.setComment("今天有人过生日请前往PC端查看")
.setSendingTime(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND))
.setMiniProgramState("formal"));
subscribeMessageSendApi.sendMsg(dto);
}
}
log.info("生日提醒,生日为{},人员为{}", time, convertList(list, AdminUserDO::getNickname));
}
}

View File

@ -1,16 +1,24 @@
package cn.iocoder.yudao.module.system.job.holiday;
import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.template.WxMiNiMsgTemplate;
import cn.iocoder.yudao.framework.common.template.dto.MessageUnreadReminderDTO;
import cn.iocoder.yudao.framework.common.template.vo.SubscribeMessageReqDTO;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
import cn.iocoder.yudao.module.system.controller.admin.user.dto.UserDTO;
import cn.iocoder.yudao.module.system.convert.worklog.HolidayRemindConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminOauthUserOtherInfoDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaybalancesetting.HolidayBalanceSettingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysetting.HolidaySettingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayuserrecord.HolidayUserRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.job.holiday.dto.HolidayRemindDTO;
import cn.iocoder.yudao.module.system.service.auth.AdminOauthUserOtherInfoService;
import cn.iocoder.yudao.module.system.service.auth.dto.AdminOauthUserOtherInfoDTO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.holiday.holidaybalancesetting.HolidayBalanceSettingService;
import cn.iocoder.yudao.module.system.service.holiday.holidaysetting.HolidaySettingService;
@ -42,6 +50,8 @@ public class HolidayRemindJob {
private DeptService deptService;
@Resource
private SubscribeMessageSendApi subscribeMessageSendApi;
@Resource
private AdminOauthUserOtherInfoService adminOauthUserOtherInfoService;
@XxlJob("holidayRemindJob")
@TenantJob // --- 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
@ -82,6 +92,15 @@ public class HolidayRemindJob {
userList.addAll(executiveDirectorUsers);
}
Map<Long, AdminUserDO> userMap = userList.stream().distinct().collect(Collectors.toMap(AdminUserDO::getId, adminUserDO -> adminUserDO));
List<Long> allUserIds = new ArrayList<>(userMap.keySet());
List<AdminOauthUserOtherInfoDO> adminOauthUserOtherInfoDOS = new ArrayList<>();
if (CollectionUtil.isNotEmpty(allUserIds)) {
adminOauthUserOtherInfoDOS = adminOauthUserOtherInfoService.getOpenIdByCondition(new AdminOauthUserOtherInfoDTO()
.setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType())
.setUserIds(allUserIds)
.setStatus(CommonStatusEnum.ENABLE.getStatus()));
}
Map<Long, String> openIdMap = adminOauthUserOtherInfoDOS.stream().collect(Collectors.toMap(AdminOauthUserOtherInfoDO::getUserId, AdminOauthUserOtherInfoDO::getOpenId));
Map<Long, AdminUserDO> leaderMap = new HashMap<>();
for (DeptDO deptDO : deptDOS) {
leaderMap.put(deptDO.getId(), userMap.get(deptDO.getLeaderUserId()));
@ -100,36 +119,36 @@ public class HolidayRemindJob {
for (HolidayUserRecordDO holidayUserRecordDO : holidayUserRecordDOS) {
HolidayRemindDTO remindDTO = new HolidayRemindDTO();
AdminUserDO user = userMap.get(holidayUserRecordDO.getUserId());
if (user == null || user.getOpenId() == null) {
if (user == null || openIdMap.get(user.getId()) == null) {
continue;
}
String name = holidaySettingMap.get(holidayBalanceSettingDO.getHolidaySettingId()) == null ? "" : holidaySettingMap.get(holidayBalanceSettingDO.getHolidaySettingId()).getName();
if (holidayBalanceSettingDO.getReminderRange() == 1) {
remindDTO.setUserId(holidayUserRecordDO.getUserId());
remindDTO.setOpenId(user.getOpenId());
remindDTO.setOpenId(openIdMap.get(user.getId()));
remindDTO.setMsg("您的" + name + "假期即将过期");
holidayRemindDTOS.add(remindDTO);
} else if (holidayBalanceSettingDO.getReminderRange() == 2) {
// 获取到主管 - 这里获取主管需要查询到对应用户所在的部门 - 完了后 在获取部门中的userIds
AdminUserDO adminUserDO = leaderMap.get(user.getDeptId());
remindDTO.setUserId(adminUserDO.getId());
if (leaderMap.get(adminUserDO.getId()) == null || leaderMap.get(adminUserDO.getId()).getOpenId() == null) {
if (leaderMap.get(adminUserDO.getId()) == null || openIdMap.get(adminUserDO.getId()) == null) {
continue;
}
remindDTO.setOpenId(leaderMap.get(adminUserDO.getId()).getOpenId());
remindDTO.setOpenId(openIdMap.get(adminUserDO.getId()));
remindDTO.setMsg(user.getNickname() + "" + name + "假期即将过期");
holidayRemindDTOS.add(remindDTO);
} else {
remindDTO.setUserId(holidayUserRecordDO.getUserId());
remindDTO.setOpenId(user.getOpenId());
remindDTO.setOpenId(openIdMap.get(user.getId()));
remindDTO.setMsg("您的" + name + "假期即将过期");
holidayRemindDTOS.add(remindDTO);
// 获取到主管 - 这里获取主管需要查询到对应用户所在的部门 - 完了后 在获取部门中的userIds
AdminUserDO adminUserDO = leaderMap.get(user.getDeptId());
remindDTO.setUserId(adminUserDO.getId());
if (leaderMap.get(adminUserDO.getId()) != null && leaderMap.get(adminUserDO.getId()).getOpenId() == null) {
remindDTO.setOpenId(leaderMap.get(adminUserDO.getId()).getOpenId());
if (leaderMap.get(adminUserDO.getId()) != null && openIdMap.get(adminUserDO.getId()) == null) {
remindDTO.setOpenId(openIdMap.get(adminUserDO.getId()));
remindDTO.setMsg(user.getNickname() + "" + name + "假期即将过期");
holidayRemindDTOS.add(remindDTO);
}
@ -140,9 +159,14 @@ public class HolidayRemindJob {
// 发送信息 -
for (HolidayRemindDTO holidayRemindDTO : holidayRemindDTOS) {
try {
subscribeMessageSendApi.sendWorkLogComment(HolidayRemindConvert.INSTANCE.convertHolidayRemind(
holidayRemindDTO.getOpenId(), holidayRemindDTO.getMsg(),
"formal"));
SubscribeMessageReqDTO dto = WxMiNiMsgTemplate.INSTANCE.convertMessageUnreadReminder(new MessageUnreadReminderDTO()
.setOpenId(holidayRemindDTO.getOpenId())
.setMsgType("假期提醒")
.setSender("系统提醒")
.setComment(holidayRemindDTO.getMsg())
.setSendingTime(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND))
.setMiniProgramState("formal"));
subscribeMessageSendApi.sendMsg(dto);
} catch (Exception e) {
log.error("发送假期过期提醒失败:{}", holidayRemindDTO);
}

View File

@ -12,35 +12,21 @@ import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.api.attendance.dto.AttendancePunchRecordDTO;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.dto.UserDTO;
import cn.iocoder.yudao.module.system.convert.worklog.HolidayRemindConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.AttendanceGroupDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshiftitem.AttendanceGroupShiftItemDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaybalancesetting.HolidayBalanceSettingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysetting.HolidaySettingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayuserrecord.HolidayUserRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.group.AttendanceGroupMapper;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupuser.AttendanceGroupUserMapper;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper;
import cn.iocoder.yudao.module.system.job.holiday.dto.HolidayRemindDTO;
import cn.iocoder.yudao.module.system.service.attendance.AttendanceService;
import cn.iocoder.yudao.module.system.service.attendance.fixed.AttendanceFixedService;
import cn.iocoder.yudao.module.system.service.attendance.groupshiftitem.AttendanceGroupShiftItemService;
import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnTheDayDTO;
import cn.iocoder.yudao.module.system.service.attendance.scheduling.AttendanceSchedulingService;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.holiday.holidaybalancesetting.HolidayBalanceSettingService;
import cn.iocoder.yudao.module.system.service.holiday.holidaysetting.HolidaySettingService;
import cn.iocoder.yudao.module.system.service.holiday.holidaysettingrange.HolidaySettingRangeService;
import cn.iocoder.yudao.module.system.service.holiday.holidayuserrecord.HolidayUserRecordService;
import cn.iocoder.yudao.module.system.service.holiday.holidayworkingage.HolidayWorkingAgeService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;

View File

@ -14,12 +14,14 @@ import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminWxMpInfoDO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
import cn.iocoder.yudao.module.system.service.member.MemberService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
@ -65,6 +67,10 @@ public class AdminAuthServiceImpl implements AdminAuthService {
private CaptchaService captchaService;
@Resource
private SmsCodeApi smsCodeApi;
@Resource
private AdminOauthUserOtherInfoService adminOauthUserOtherInfoService;
@Resource
private AdminWxMpInfoService adminWxMpInfoService;
/**
* 验证码的开关默认为 true
@ -110,13 +116,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
}
if (reqVO.getOpenId() != null && !"yhtyyds".equals(reqVO.getPassword())) {
//清空openId
userService.emptyOpenId(reqVO.getOpenId());
//绑定用户openId
userService.updateUserOpenId(user.getId(), reqVO.getOpenId());
}
// 创建 Token 令牌记录登录日志
return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
}
@ -263,9 +262,10 @@ public class AdminAuthServiceImpl implements AdminAuthService {
@Resource
private SocialClientService socialClientService;
@Override
public AuthLoginRespVO miniAppQuickLogin(AuthSocialLoginReqVO reqVO) {
//获取微信小程序授权手机号
WxMaPhoneNumberInfo wxMaPhoneNumberInfo = socialClientService.getWxMaPhoneNumberInfo(2, reqVO.getCode());
WxMaPhoneNumberInfo wxMaPhoneNumberInfo = socialClientService.getWxMaPhoneNumberInfo(reqVO.getType(), 2, reqVO.getCode());
String phoneNumber = wxMaPhoneNumberInfo.getPhoneNumber(); //授权手机号
//phoneNumber = "18611845857" ;
String appId = wxMaPhoneNumberInfo.getWatermark().getAppid(); //小程序的appId
@ -289,11 +289,25 @@ public class AdminAuthServiceImpl implements AdminAuthService {
createLoginLog(null, phoneNumber, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
throw exception(AUTH_MOBILE_NOT_EXISTS);
}
// 检查 - 保存用户三方登录信息 -
adminOauthUserOtherInfoService.checkInsert(user.getId(), appId, reqVO.getOpenId(), reqVO.getType());
if (user.getUnionId() == null) {
user.setUnionId(reqVO.getUnionId());
userService.updateUnionId(user.getId(), reqVO.getUnionId());
// -- 插入unionId 看看 - 有没有相关的 公众号openId
String wxMpAppId = socialClientService.getWxMpService().getWxMpConfigStorage().getAppId();
// -- 查询是否有数据
AdminWxMpInfoDO adminWxMpInfoDO = adminWxMpInfoService.getByCondition(wxMpAppId, reqVO.getUnionId());
if (adminWxMpInfoDO != null) {
adminOauthUserOtherInfoService.checkInsert(user.getId(), wxMpAppId, adminWxMpInfoDO.getOpenId(), SocialTypeEnum.WECHAT_MP.getType());
adminWxMpInfoService.del(wxMpAppId, reqVO.getUnionId());
}
}
// TODO: 2024/11/22 这个操作有问题
//清空openId
userService.emptyOpenId(reqVO.getOpenId());
//绑定用户openId
userService.updateUserOpenId(user.getId(), reqVO.getOpenId());
// //清空openId
// userService.emptyOpenId(reqVO.getOpenId());
// //绑定用户openId
// userService.updateUserOpenId(user.getId(), reqVO.getOpenId());
/** 创建 Token 令牌,记录登录日志 */
Long userId = user.getId();
@ -309,6 +323,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
@Override
public WxMaJscode2SessionResult miniAppCode2Session(AuthSocialLoginReqVO reqVO) {
return socialClientService.getWxMaJscode2SessionResult(reqVO.getCode());
return socialClientService.getWxMaJscode2SessionResult(reqVO.getType(), reqVO.getCode());
}
}

View File

@ -0,0 +1,43 @@
package cn.iocoder.yudao.module.system.service.auth;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminOauthUserOtherInfoDO;
import cn.iocoder.yudao.module.system.service.auth.dto.AdminOauthUserOtherInfoDTO;
import java.util.List;
/**
* 用户三方登录信息 Service 接口
*
* @author 艾楷
*/
public interface AdminOauthUserOtherInfoService {
/**
* 保存修改用户三方登录信息
*
* @param userId
* @param appId
* @param openId
* @param socialType
*/
void checkInsert(Long userId, String appId, String openId, Integer socialType);
AdminOauthUserOtherInfoDO getByCondition(Long userId, String appId, String openId, Integer socialType);
/**
* 通过社交类型+用户状态获取用户社交信息
*
* @param dto
* @return
*/
List<AdminOauthUserOtherInfoDO> getOpenIdByCondition(AdminOauthUserOtherInfoDTO dto);
/**
* 根据条件删除
*
* @param userId
* @param appId
* @param openId
* @param socialType
*/
void delByCondition(Long userId, String appId, String openId, Integer socialType);
}

View File

@ -0,0 +1,61 @@
package cn.iocoder.yudao.module.system.service.auth;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminOauthUserOtherInfoDO;
import cn.iocoder.yudao.module.system.dal.mysql.auth.AdminOauthUserOtherInfoMapper;
import cn.iocoder.yudao.module.system.service.auth.dto.AdminOauthUserOtherInfoDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.List;
/**
* 用户三方登录信息 Service 实现类
*
* @author 艾楷
*/
@Service
@Validated
public class AdminOauthUserOtherInfoServiceImpl implements AdminOauthUserOtherInfoService {
@Resource
private AdminOauthUserOtherInfoMapper adminOauthUserOtherInfoMapper;
@Override
public void checkInsert(Long userId, String appId, String openId, Integer socialType) {
AdminOauthUserOtherInfoDO adminOauthUserOtherInfoDOS = this.getByCondition(userId, appId, openId, socialType);
if (adminOauthUserOtherInfoDOS == null) {
adminOauthUserOtherInfoMapper.insert(new AdminOauthUserOtherInfoDO()
.setUserId(userId)
.setAppId(appId)
.setOpenId(openId)
.setSocialType(socialType));
}
}
@Override
public AdminOauthUserOtherInfoDO getByCondition(Long userId, String appId, String openId, Integer socialType) {
return adminOauthUserOtherInfoMapper.selectOne(new LambdaQueryWrapper<AdminOauthUserOtherInfoDO>()
.eq(AdminOauthUserOtherInfoDO::getUserId, userId)
.eq(AdminOauthUserOtherInfoDO::getAppId, appId)
.eq(AdminOauthUserOtherInfoDO::getOpenId, openId)
.eq(AdminOauthUserOtherInfoDO::getSocialType, socialType));
}
@Override
public List<AdminOauthUserOtherInfoDO> getOpenIdByCondition(AdminOauthUserOtherInfoDTO dto) {
return adminOauthUserOtherInfoMapper.getOpenIdByCondition(dto);
}
@Override
public void delByCondition(Long userId, String appId, String openId, Integer socialType) {
adminOauthUserOtherInfoMapper.delete(new LambdaQueryWrapper<AdminOauthUserOtherInfoDO>()
.eq(AdminOauthUserOtherInfoDO::getUserId, userId)
.eq(AdminOauthUserOtherInfoDO::getAppId, appId)
.eq(AdminOauthUserOtherInfoDO::getOpenId, openId)
.eq(AdminOauthUserOtherInfoDO::getSocialType, socialType));
}
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.system.service.auth;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminWxMpInfoDO;
/**
* 微信公众号用户信息表(用户暂存没有注册用户的关注信息) Service 接口
*
* @author 艾楷
*/
public interface AdminWxMpInfoService {
/**
* 新增
*
* @param adminWxMpInfoDO
*/
void save(AdminWxMpInfoDO adminWxMpInfoDO);
/**
* 删除
*
* @param appId
* @param unionId
*/
void del(String appId, String unionId);
/**
* 查询
*
* @param wxMpAppId
* @param unionId
* @return
*/
AdminWxMpInfoDO getByCondition(String wxMpAppId, String unionId);
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.system.service.auth;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminWxMpInfoDO;
import cn.iocoder.yudao.module.system.dal.mysql.auth.AdminWxMpInfoMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 微信公众号用户信息表(用户暂存没有注册用户的关注信息) Service 实现类
*
* @author 艾楷
*/
@Service
@Validated
public class AdminWxMpInfoServiceImpl implements AdminWxMpInfoService {
@Resource
private AdminWxMpInfoMapper adminWxMpInfoMapper;
@Override
public void save(AdminWxMpInfoDO adminWxMpInfoDO) {
adminWxMpInfoMapper.insert(adminWxMpInfoDO);
}
@Override
public void del(String appId, String unionId) {
adminWxMpInfoMapper.delete(new LambdaQueryWrapper<AdminWxMpInfoDO>()
.eq(AdminWxMpInfoDO::getAppId, appId)
.eq(AdminWxMpInfoDO::getUnionId, unionId));
}
@Override
public AdminWxMpInfoDO getByCondition(String wxMpAppId, String unionId) {
return adminWxMpInfoMapper.selectOne(new LambdaQueryWrapper<AdminWxMpInfoDO>()
.eq(AdminWxMpInfoDO::getAppId, wxMpAppId)
.eq(AdminWxMpInfoDO::getUnionId, unionId));
}
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.system.service.auth.dto;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@Data
@Accessors(chain = true)
public class AdminOauthUserOtherInfoDTO {
/**
* 社交平台的类型 (参见 {@link SocialTypeEnum} 枚举)
*/
private Integer socialType;
/**
* 用户状态 0开启 1关闭
*/
private Integer status;
/**
* 用户类型 1公司用户 2工厂用户
*/
private Integer userType;
/**
* 部门ids
*/
private List<Long> deptIds;
/**
* 用户ids
*/
private List<Long> userIds;
}

View File

@ -1,8 +1,15 @@
package cn.iocoder.yudao.module.system.service.comment;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.template.WxMiNiMsgTemplate;
import cn.iocoder.yudao.framework.common.template.dto.MessageUnreadReminderDTO;
import cn.iocoder.yudao.framework.common.template.vo.SubscribeMessageReqDTO;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
@ -12,11 +19,13 @@ import cn.iocoder.yudao.module.system.controller.app.comment.vo.CommentPageListV
import cn.iocoder.yudao.module.system.controller.app.comment.vo.CommentTypeCountVO;
import cn.iocoder.yudao.module.system.controller.app.comment.vo.WorkLogCommentPageReqVO;
import cn.iocoder.yudao.module.system.controller.app.comment.vo.WorkLogCommentSaveReqVO;
import cn.iocoder.yudao.module.system.convert.worklog.LogCommentConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminOauthUserOtherInfoDO;
import cn.iocoder.yudao.module.system.dal.dataobject.comment.WorkLogCommentDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.worklog.LogFormDO;
import cn.iocoder.yudao.module.system.dal.mysql.comment.WorkLogCommentMapper;
import cn.iocoder.yudao.module.system.service.auth.AdminOauthUserOtherInfoService;
import cn.iocoder.yudao.module.system.service.auth.dto.AdminOauthUserOtherInfoDTO;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.module.system.service.worklog.LogFormService;
import cn.iocoder.yudao.module.system.service.worklog.LogInstanceService;
@ -28,10 +37,7 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -57,6 +63,8 @@ public class WorkLogCommentServiceImpl implements WorkLogCommentService {
@Resource
private SubscribeMessageSendApi subscribeMessageSendApi;
@Resource
private AdminOauthUserOtherInfoService adminOauthUserOtherInfoService;
@Override
public Long createWorkLogComment(WorkLogCommentSaveReqVO createReqVO) {
@ -164,29 +172,39 @@ public class WorkLogCommentServiceImpl implements WorkLogCommentService {
* 评论或回复 发送消息通知
*/
private void sendMessage(WorkLogCommentDO workLogComment) {
//获得日志详情
LogInstanceRespVO instanceDO = logInstanceService.getLogInstance(workLogComment.getWorkLogId());
//获得 userMap
Map<Long, AdminUserDO> userMap = userService.getUserListByIds(Arrays.asList(instanceDO.getStartUserId(), workLogComment.getCommentUserId(), workLogComment.getUserId()));
List<Long> userIds = new ArrayList<>(userMap.keySet());
List<AdminOauthUserOtherInfoDO> adminOauthUserOtherInfoDOS = new ArrayList<>();
if (CollectionUtil.isNotEmpty(userIds)) {
adminOauthUserOtherInfoDOS = adminOauthUserOtherInfoService.getOpenIdByCondition(new AdminOauthUserOtherInfoDTO()
.setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType())
.setUserIds(userIds)
.setStatus(CommonStatusEnum.ENABLE.getStatus()));
}
Map<Long, String> openIdMap = adminOauthUserOtherInfoDOS.stream().collect(Collectors.toMap(AdminOauthUserOtherInfoDO::getUserId, AdminOauthUserOtherInfoDO::getOpenId));
String openId = null;
if (!workLogComment.getType()) {
openId = userMap.get(instanceDO.getStartUserId()).getOpenId();
openId = openIdMap.get(instanceDO.getStartUserId());
} else {
openId = userMap.get(workLogComment.getCommentUserId()).getOpenId();
openId = openIdMap.get(workLogComment.getCommentUserId());
}
if (openId != null) {
try {
SubscribeMessageReqDTO dto = WxMiNiMsgTemplate.INSTANCE.convertMessageUnreadReminder(new MessageUnreadReminderDTO()
.setOpenId(openId)
.setMsgType(workLogComment.getType() ? "评论回复" : "日志评论")
.setSender(userMap.get(workLogComment.getUserId()).getNickname())
.setComment(workLogComment.getComment())
.setSendingTime(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND))
.setPage("/subPages/workLogDetail/workLogDetail?id=" + workLogComment.getWorkLogId())
.setMiniProgramState("formal"));
//发送消息通知
subscribeMessageSendApi.sendWorkLogComment(LogCommentConvert.INSTANCE.convertLogComment(
openId, workLogComment, userMap.get(workLogComment.getUserId()).getNickname(),
"formal"));
subscribeMessageSendApi.sendMsg(dto);
} catch (Exception e) {
log.error("发送消息通知失败", e);
}

View File

@ -1,7 +1,13 @@
package cn.iocoder.yudao.module.system.service.notice;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.template.WxMiNiMsgTemplate;
import cn.iocoder.yudao.framework.common.template.dto.CompanyAnnouncementNoticeDTO;
import cn.iocoder.yudao.framework.common.template.vo.SubscribeMessageReqDTO;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
@ -9,12 +15,14 @@ import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticePushReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticeSaveReqVO;
import cn.iocoder.yudao.module.system.convert.notice.NoticeConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminOauthUserOtherInfoDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.dal.dataobject.notice.NoticeDO;
import cn.iocoder.yudao.module.system.dal.dataobject.notice.NoticeGroupDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.notice.NoticeMapper;
import cn.iocoder.yudao.module.system.service.auth.AdminOauthUserOtherInfoService;
import cn.iocoder.yudao.module.system.service.auth.dto.AdminOauthUserOtherInfoDTO;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.google.common.annotations.VisibleForTesting;
@ -23,6 +31,7 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@ -32,8 +41,6 @@ import static cn.iocoder.yudao.module.system.framework.ThreadPool.config.AsyncCo
/**
* 通知公告 Service 实现类
*
*/
@Service
public class NoticeServiceImpl implements NoticeService {
@ -49,6 +56,15 @@ public class NoticeServiceImpl implements NoticeService {
@Resource
private DictDataService dictDataService;
/**
* 添加小程序发送公告通知 add by yj 2024-04-07
*/
@Resource
private AdminUserService userService;
@Resource
private SubscribeMessageSendApi subscribeMessageSendApi;
@Resource
private AdminOauthUserOtherInfoService adminOauthUserOtherInfoService;
@Override
public Long createNotice(NoticeSaveReqVO createReqVO) {
@ -95,62 +111,68 @@ public class NoticeServiceImpl implements NoticeService {
}
}
/** 添加小程序发送公告通知 add by yj 2024-04-07*/
@Resource
private AdminUserService userService;
@Resource
private SubscribeMessageSendApi subscribeMessageSendApi;
@Override
public void sendNotice(NoticePushReqVO pushReqVO) {
//获得公告信息
NoticeDO notice = getNotice(pushReqVO.getId());
if (notice == null) {
throw exception(NOTICE_NOT_FOUND);
}
// 获得公告类型 字典label
DictDataDO dictDataDO = dictDataService.getDictData("system_notice_type", String.valueOf(notice.getType()));
//获取当前登陆用户的名称
LoginUser user = SecurityFrameworkUtils.getLoginUser() ;
AdminUserDO currentUser = userService.getUser(user.getId()) ;
List<AdminUserDO> userDOs = new ArrayList<>();
LoginUser user = SecurityFrameworkUtils.getLoginUser();
AdminUserDO currentUser = userService.getUser(user.getId());
List<AdminOauthUserOtherInfoDO> list = new ArrayList<>();
switch (pushReqVO.getType()) {
//全员推送
case 0:
//获得用户信息
userDOs = userService.getUserListByStatus(null, null, CommonStatusEnum.ENABLE.getStatus());
list = adminOauthUserOtherInfoService.getOpenIdByCondition(new AdminOauthUserOtherInfoDTO()
.setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType())
.setStatus(CommonStatusEnum.ENABLE.getStatus()));
break;
//部门推送
case 1:
//获得用户信息
userDOs = userService.getUserListByDeptIds(pushReqVO.getDeptIds(), CommonStatusEnum.ENABLE.getStatus());
if (CollUtil.isNotEmpty(pushReqVO.getDeptIds())) {
list = adminOauthUserOtherInfoService.getOpenIdByCondition(new AdminOauthUserOtherInfoDTO()
.setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType())
.setUserType(1)
.setDeptIds(pushReqVO.getDeptIds())
.setStatus(CommonStatusEnum.ENABLE.getStatus()));
}
break;
//用户组推送
case 2:
//获得用户组信息
List<NoticeGroupDO> groupDOs = noticeGroupService.getUserGroupList(pushReqVO.getGroupId());
//获得用户组中 用户信息
userDOs = userService.getUserList(groupDOs.stream().flatMap(group -> group.getMemberUserIds().stream()).collect(Collectors.toSet()));
List<Long> userIds = groupDOs.stream().flatMap(group -> group.getMemberUserIds().stream()).collect(Collectors.toList());
if (CollUtil.isNotEmpty(userIds)) {
list = adminOauthUserOtherInfoService.getOpenIdByCondition(new AdminOauthUserOtherInfoDTO()
.setUserIds(userIds));
}
break;
}
for(AdminUserDO adminUserDO : userDOs) {
if( adminUserDO.getOpenId() != null && !adminUserDO.getOpenId().isEmpty()) {
threadPoolTaskExecutor.execute(() -> {
List<AdminOauthUserOtherInfoDO> finalList = list;
threadPoolTaskExecutor.execute(() -> {
for (AdminOauthUserOtherInfoDO otherInfoDO : finalList) {
if (otherInfoDO.getOpenId() != null && !otherInfoDO.getOpenId().isEmpty()) {
//获取openId有值的用户
subscribeMessageSendApi.sendCompanyNotice(NoticeConvert.INSTANCE.convertCompanyNotice(
adminUserDO.getOpenId(), notice, dictDataDO.getLabel(), currentUser.getNickname(),
"formal"));
});
SubscribeMessageReqDTO dto = WxMiNiMsgTemplate.INSTANCE.convertCompanyAnnouncementNotice(new CompanyAnnouncementNoticeDTO()
.setOpenId(otherInfoDO.getOpenId())
.setNoticeType(dictDataDO.getLabel())
.setTitle(notice.getTitle())
.setNickname(currentUser.getNickname())
.setSendingTime(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND))
.setMiniProgramState("formal")
.setPage("/subPages/notice/detail?id=" + notice.getId())
);
subscribeMessageSendApi.sendMsg(dto);
}
}
}
});
}
}

View File

@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import com.xingyuv.jushauth.model.AuthUser;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.mp.api.WxMpService;
@ -16,16 +16,14 @@ import javax.validation.Valid;
/**
* 社交应用 Service 接口
*
*/
public interface SocialClientService {
/**
* 获得社交平台的授权 URL
*
* @param socialType 社交平台的类型 {@link SocialTypeEnum}
* @param userType 用户类型
* @param socialType 社交平台的类型 {@link SocialTypeEnum}
* @param userType 用户类型
* @param redirectUri 重定向 URL
* @return 社交平台的授权 URL
*/
@ -35,9 +33,9 @@ public interface SocialClientService {
* 请求社交平台获得授权的用户
*
* @param socialType 社交平台的类型
* @param userType 用户类型
* @param code 授权码
* @param state 授权 state
* @param userType 用户类型
* @param code 授权码
* @param state 授权 state
* @return 授权的用户
*/
AuthUser getAuthUser(Integer socialType, Integer userType, String code, String state);
@ -48,40 +46,44 @@ public interface SocialClientService {
* 创建微信公众号的 JS SDK 初始化所需的签名
*
* @param userType 用户类型
* @param url 访问的 URL 地址
* @param url 访问的 URL 地址
* @return 签名
*/
WxJsapiSignature createWxMpJsapiSignature(Integer userType, String url);
/**
* 获取WxMpService
*
* @return
*/
WxMpService getWxMpService() ;
WxMpService getWxMpService();
// =================== 微信小程序独有 ===================
/**
* 获得微信小程序的手机信息
*
* @param userType 用户类型
* @param userType 用户类型
* @param phoneCode 手机授权码
* @return 手机信息
*/
WxMaPhoneNumberInfo getWxMaPhoneNumberInfo(Integer userType, String phoneCode);
WxMaPhoneNumberInfo getWxMaPhoneNumberInfo(Integer socialType, Integer userType, String phoneCode);
/**
* 获取微信小程序的用户唯一标识 openId
*
* @param type
* @param jsCode 登录时获取的 code可通过wx.login获取
* @return
*/
WxMaJscode2SessionResult getWxMaJscode2SessionResult(String jsCode) ;
WxMaJscode2SessionResult getWxMaJscode2SessionResult(Integer type, String jsCode);
/**
* 获取WxMaService
*
* @return
*/
WxMaService getWxMaService() ;
WxMaService getWxMaService();
// =================== 客户端管理 ===================

View File

@ -18,7 +18,7 @@ import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialCl
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
import com.google.common.annotations.VisibleForTesting;
@ -52,8 +52,6 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
/**
* 社交应用 Service 实现类
*
*/
@Service
@Slf4j
@ -71,14 +69,15 @@ public class SocialClientServiceImpl implements SocialClientService {
@Override
public WxMpService getWxMpService() {
return getWxMpService(2) ;
return getWxMpService(2);
}
/**
* 缓存 WxMpService 对象
*
* <p>
* key使用微信公众号的 appId + secret 拼接 {@link SocialClientDO} clientId clientSecret 属性
* 为什么 key 使用这种格式因为 {@link SocialClientDO} 在管理后台可以变更通过这个 key 存储它的单例
*
* <p>
* 为什么要做 WxMpService 缓存因为 WxMpService 构建成本比较大所以尽量保证它是单例
*/
private final LoadingCache<String, WxMpService> wxMpServiceCache = CacheUtils.buildAsyncReloadingCache(
@ -100,11 +99,12 @@ public class SocialClientServiceImpl implements SocialClientService {
@Override
public WxMaService getWxMaService() {
return getWxMaService(2) ;
return getWxMaService(2);
}
/**
* 缓存 WxMaService 对象
*
* <p>
* 说明同 {@link #wxMpServiceCache} 变量
*/
private final LoadingCache<String, WxMaService> wxMaServiceCache = CacheUtils.buildAsyncReloadingCache(
@ -150,7 +150,7 @@ public class SocialClientServiceImpl implements SocialClientService {
* 构建 AuthRequest 对象支持多租户配置
*
* @param socialType 社交类型
* @param userType 用户类型
* @param userType 用户类型
* @return AuthRequest 对象
*/
@VisibleForTesting
@ -207,7 +207,7 @@ public class SocialClientServiceImpl implements SocialClientService {
/**
* 创建 clientId + clientSecret 对应的 WxMpService 对象
*
* @param clientId 微信公众号 appId
* @param clientId 微信公众号 appId
* @param clientSecret 微信公众号 secret
* @return WxMpService 对象
*/
@ -228,8 +228,8 @@ public class SocialClientServiceImpl implements SocialClientService {
// =================== 微信小程序独有 ===================
@Override
public WxMaPhoneNumberInfo getWxMaPhoneNumberInfo(Integer userType, String phoneCode) {
WxMaService service = getWxMaService(userType);
public WxMaPhoneNumberInfo getWxMaPhoneNumberInfo(Integer socialType, Integer userType, String phoneCode) {
WxMaService service = getWxMaService(socialType, userType);
try {
return service.getUserService().getPhoneNoInfo(phoneCode);
} catch (WxErrorException e) {
@ -256,10 +256,28 @@ public class SocialClientServiceImpl implements SocialClientService {
return wxMaService;
}
/**
* 获得 clientId + clientSecret 对应的 WxMpService 对象
*
* @param userType 用户类型
* @return WxMpService 对象
*/
@VisibleForTesting
WxMaService getWxMaService(Integer socialType, Integer userType) {
// 第一步查询 DB 的配置项获得对应的 WxMaService 对象
SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
socialType, userType);
if (client != null && Objects.equals(client.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
return wxMaServiceCache.getUnchecked(client.getClientId() + ":" + client.getClientSecret());
}
// 第二步不存在 DB 配置项则使用 application-*.yaml 对应的 WxMaService 对象
return wxMaService;
}
/**
* 创建 clientId + clientSecret 对应的 WxMaService 对象
*
* @param clientId 微信小程序 appId
* @param clientId 微信小程序 appId
* @param clientSecret 微信小程序 secret
* @return WxMaService 对象
*/
@ -318,11 +336,11 @@ public class SocialClientServiceImpl implements SocialClientService {
/**
* 校验社交应用是否重复需要保证 userType + socialType 唯一
*
* <p>
* 原因是不同端userType选择某个社交登录socialType需要通过 {@link #buildAuthRequest(Integer, Integer)} 构建对应的请求
*
* @param id 编号
* @param userType 用户类型
* @param id 编号
* @param userType 用户类型
* @param socialType 社交类型
*/
private void validateSocialClientUnique(Long id, Integer userType, Integer socialType) {
@ -349,9 +367,8 @@ public class SocialClientServiceImpl implements SocialClientService {
@SneakyThrows
@Override
public WxMaJscode2SessionResult getWxMaJscode2SessionResult(String jsCode) {
WxMaService wxMaService = getWxMaService(2) ;
WxMaJscode2SessionResult result = wxMaService.jsCode2SessionInfo(jsCode) ;
return result ;
public WxMaJscode2SessionResult getWxMaJscode2SessionResult(Integer type, String jsCode) {
WxMaService wxMaService = getWxMaService(type, 2);
return wxMaService.jsCode2SessionInfo(jsCode);
}
}

View File

@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import javax.validation.Valid;
import java.util.List;

View File

@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import com.xingyuv.jushauth.model.AuthUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@ -32,7 +32,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USE
/**
* 社交用户 Service 实现类
*
*/
@Service
@Validated

View File

@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserApiDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserPageApiDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.user.dto.UserDTO;
import cn.iocoder.yudao.module.system.controller.admin.user.dto.UserPageDTO;
@ -147,13 +146,6 @@ public interface AdminUserService {
*/
AdminUserDO getUserByMobile(String mobile);
/**
* 根据opneId获取用户
*
* @param openId 微信小程序用户唯一id
* @return 用户对象信息
*/
AdminUserDO getUserByOpenId(String openId);
/**
* 获得用户分页列表
@ -428,4 +420,14 @@ public interface AdminUserService {
List<Long> getUserListBySubordinateIds(Long adminId);
List<AdminUserRespDTO> getUserListBySubordinate(Long id);
/**
* 更新用户unionId
*
* @param id
* @param unionId
*/
void updateUnionId(Long id, String unionId);
AdminUserDO getUserByUnionId(String unionId);
}

View File

@ -101,14 +101,6 @@ public class AdminUserServiceImpl implements AdminUserService {
userMapper.updateById(new AdminUserDO().setId(id).setOpenId(openId));
}
@Override
public AdminUserDO getUserByOpenId(String openId) {
if (openId == null) {
return null;
}
return userMapper.sgetByOpenId(openId);
}
@Override
@Transactional(rollbackFor = Exception.class)
public Long createUser(UserSaveReqVO createReqVO) {
@ -859,4 +851,15 @@ public class AdminUserServiceImpl implements AdminUserService {
users.removeIf(item -> ObjUtil.equal(item.getId(), id)); // 排除自己
return BeanUtils.toBean(users, AdminUserRespDTO.class);
}
@Override
public void updateUnionId(Long id, String unionId) {
userMapper.updateById(new AdminUserDO().setId(id).setUnionId(unionId));
}
@Override
public AdminUserDO getUserByUnionId(String unionId) {
return userMapper.selectOne(new LambdaQueryWrapper<AdminUserDO>()
.eq(AdminUserDO::getUnionId, unionId));
}
}

View File

@ -129,6 +129,8 @@ wx:
# secret: 5abee519483bc9f8cb37ce280e814bd0
app-id: wx9943f95048ba8472
secret: f1f5625f210142b6ae31a06c699826df
token: aikaidevtest
aesKey: RmC9DkIpsq6pK2PGxyI4HQaDHrv5W7de8PXeAO3lqM9
# 存储配置,解决 AccessToken 的跨节点的共享
config-storage:
type: RedisTemplate # 采用 RedisTemplate 操作 Redis会自动从 Spring 中获取

View File

@ -125,6 +125,8 @@ wx:
# secret: 5abee519483bc9f8cb37ce280e814bd0
app-id: wx5b23ba7a5589ecbb # 测试号
secret: 2a7b3b20c537e52e74afd395eb85f61f
token: aikaidevtest
aesKey: RmC9DkIpsq6pK2PGxyI4HQaDHrv5W7de8PXeAO3lqM9
# 存储配置,解决 AccessToken 的跨节点的共享
config-storage:
type: RedisTemplate # 采用 RedisTemplate 操作 Redis会自动从 Spring 中获取

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.system.dal.mysql.auth.AdminOauthUserOtherInfoMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
<select id="getOpenIdBySocialType"
resultType="cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminOauthUserOtherInfoDO">
select
a.*
from system_oauth_user_other_info as a
left join system_users as b on a.user_id = b.id
<where>
a.deleted = 0
and b.deleted = 0
<if test="type != null">
and a.social_type = #{type}
</if>
<if test="status != null">
and b.status = #{status}
</if>
</where>
</select>
<select id="getOpenIdByCondition"
resultType="cn.iocoder.yudao.module.system.dal.dataobject.auth.AdminOauthUserOtherInfoDO">
select
a.*
from system_oauth_user_other_info as a
left join system_users as b on a.user_id = b.id
<where>
a.deleted = 0
and b.deleted = 0
<if test="dto.socialType != null">
and a.social_type = #{dto.socialType}
</if>
<if test="dto.status != null">
and b.status = #{dto.status}
</if>
<if test="dto.userType != null">
and b.user_type = #{dto.userType}
</if>
<if test="dto.deptIds != null">
and b.dept_id in
<foreach collection="dto.deptIds" item="deptId" open="(" close=")" separator=",">
#{deptId}
</foreach>
</if>
<if test="dto.userIds != null">
and b.id in
<foreach collection="dto.userIds" item="userId" open="(" close=")" separator=",">
#{userId}
</foreach>
</if>
</where>
</select>
</mapper>

View File

@ -1,53 +0,0 @@
package cn.iocoder.yudao.module.system.job;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager;
import cn.iocoder.yudao.module.system.job.auth.UserSessionTimeoutJob;
import cn.iocoder.yudao.module.system.test.BaseDbUnitTest;
import org.junit.jupiter.api.Test;
import org.quartz.SchedulerException;
import javax.annotation.Resource;
public class SchedulerManagerTest extends BaseDbUnitTest {
@Resource
private SchedulerManager schedulerManager;
@Test
public void testAddJob() throws SchedulerException {
String jobHandlerName = StrUtil.lowerFirst(UserSessionTimeoutJob.class.getSimpleName());
schedulerManager.addJob(1L, jobHandlerName, "test", "0/10 * * * * ? *", 0, 0);
}
@Test
public void testUpdateJob() throws SchedulerException {
String jobHandlerName = StrUtil.lowerFirst(UserSessionTimeoutJob.class.getSimpleName());
schedulerManager.updateJob(jobHandlerName, "hahaha", "0/20 * * * * ? *", 0, 0);
}
@Test
public void testDeleteJob() throws SchedulerException {
String jobHandlerName = StrUtil.lowerFirst(UserSessionTimeoutJob.class.getSimpleName());
schedulerManager.deleteJob(jobHandlerName);
}
@Test
public void testPauseJob() throws SchedulerException {
String jobHandlerName = StrUtil.lowerFirst(UserSessionTimeoutJob.class.getSimpleName());
schedulerManager.pauseJob(jobHandlerName);
}
@Test
public void testResumeJob() throws SchedulerException {
String jobHandlerName = StrUtil.lowerFirst(UserSessionTimeoutJob.class.getSimpleName());
schedulerManager.resumeJob(jobHandlerName);
}
@Test
public void testTriggerJob() throws SchedulerException {
String jobHandlerName = StrUtil.lowerFirst(UserSessionTimeoutJob.class.getSimpleName());
schedulerManager.triggerJob(1L, jobHandlerName, "niubi!!!");
}
}

View File

@ -1,62 +0,0 @@
package cn.iocoder.yudao.module.system.mq;
import cn.hutool.core.thread.ThreadUtil;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import cn.iocoder.yudao.module.system.mq.consumer.mail.MailSendConsumer;
import cn.iocoder.yudao.module.system.mq.consumer.sms.SmsSendConsumer;
import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage;
import cn.iocoder.yudao.module.system.test.BaseRedisIntegrationTest;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.core.RedisTemplate;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
public class RedisStreamTest {
@Import({SmsSendConsumer.class, MailSendConsumer.class})
@Disabled
public static class ConsumerTest extends BaseRedisIntegrationTest {
@Test
public void testConsumer() {
ThreadUtil.sleep(1, TimeUnit.DAYS);
}
}
@Disabled
public static class ProducerTest extends BaseRedisIntegrationTest {
@Resource
private RedisMQTemplate redisMQTemplate;
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Test
public void testProducer01() {
for (int i = 0; i < 100; i++) {
// 创建消息
SmsSendMessage message = new SmsSendMessage();
message.setMobile("15601691300").setApiTemplateId("test:" + i);
// 发送消息
redisMQTemplate.send(message);
}
}
@Test
public void testProducer02() {
// 创建消息
MailSendMessage message = new MailSendMessage();
message.setAddress("fangfang@mihayou.com").setTemplateCode("test");
// 发送消息
redisMQTemplate.send(message);
}
}
}

View File

@ -1,4 +0,0 @@
/**
* 占位
*/
package cn.iocoder.yudao.module.system.service;

View File

@ -1,55 +0,0 @@
package cn.iocoder.yudao.module.system.service.sms;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.sms.config.YudaoSmsAutoConfiguration;
import cn.iocoder.yudao.module.system.test.BaseDbAndRedisIntegrationTest;
import cn.iocoder.yudao.module.system.mq.consumer.sms.SmsSendConsumer;
import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.TimeUnit;
// TODO @芋艿需要迁移
@Import({YudaoSmsAutoConfiguration.class,
SmsChannelServiceImpl.class, SmsSendServiceImpl.class, SmsTemplateServiceImpl.class, SmsLogServiceImpl.class,
SmsProducer.class, SmsSendConsumer.class})
public class SmsServiceIntegrationTest extends BaseDbAndRedisIntegrationTest {
@Resource
private SmsSendServiceImpl smsService;
@Resource
private SmsChannelServiceImpl smsChannelService;
@MockBean
private AdminUserService userService;
@Test
public void testSendSingleSms_aliyunSuccess() {
// 参数准备
String mobile = "15601691399";
Long userId = 1L;
Integer userType = UserTypeEnum.ADMIN.getValue();
String templateCode = "test_02";
Map<String, Object> templateParams = MapUtil.<String, Object>builder()
.put("code", "1234").build();
// 调用
smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);
// 等待 MQ 消费
ThreadUtil.sleep(1, TimeUnit.HOURS);
}
// @Test
// public void testDoSendSms() {
// // 等待 MQ 消费
// ThreadUtil.sleep(1, TimeUnit.HOURS);
// }
}

View File

@ -1,38 +0,0 @@
package cn.iocoder.yudao.module.system.test;
import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration;
import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration;
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisIntegrationTest.Application.class)
@ActiveProfiles("integration-test") // 设置使用 application-integration-test 配置文件
public class BaseDbAndRedisIntegrationTest {
@Import({
// DB 配置类
DynamicDataSourceAutoConfiguration.class, // Dynamic Datasource 配置类
YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类
DataSourceAutoConfiguration.class, // Spring DB 自动配置类
DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类
// MyBatis 配置类
YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类
MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
// Redis 配置类
RedisAutoConfiguration.class, // Spring Redis 自动配置类
YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
RedissonAutoConfiguration.class, // Redisson 自动高配置类
})
public static class Application {
}
}

View File

@ -1,23 +0,0 @@
package cn.iocoder.yudao.module.system.test;
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseRedisIntegrationTest.Application.class)
@ActiveProfiles("integration-test") // 设置使用 application-integration-test 配置文件
public class BaseRedisIntegrationTest {
@Import({
// Redis 配置类
RedisAutoConfiguration.class, // Spring Redis 自动配置类
YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
RedissonAutoConfiguration.class, // Redisson 自动高配置类
})
public static class Application {
}
}

View File

@ -1,108 +0,0 @@
spring:
main:
lazy-initialization: true # 开启懒加载,加快速度
banner-mode: off # 单元测试,禁用 Banner
--- #################### 数据库相关配置 ####################
spring:
# 数据源配置项
autoconfigure:
exclude:
- com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
enabled: true
stat-view-servlet:
enabled: true
allow: # 设置白名单,不填则允许所有访问
url-pattern: /druid/*
login-username: # 控制台管理用户名和密码
login-password:
filter:
stat:
enabled: true
log-slow-sql: true # 慢 SQL 记录
slow-sql-millis: 100
merge-sql: true
wall:
config:
multi-statement-allow: true
dynamic: # 多数据源配置
druid: # Druid 【连接池】相关的全局配置
initial-size: 5 # 初始连接数
min-idle: 10 # 最小连接池数量
max-active: 20 # 最大连接池数量
max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒
time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒
min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒
max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒
validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效
test-while-idle: true
test-on-borrow: false
test-on-return: false
primary: master
datasource:
master:
name: ruoyi-vue-pro
url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
slave: # 模拟从库,可根据自己需要修改
name: ruoyi-vue-pro
url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:
host: 127.0.0.1 # 地址
port: 6379 # 端口
database: 0 # 数据库索引
mybatis:
lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试
--- #################### 定时任务相关配置 ####################
--- #################### 配置中心相关配置 ####################
--- #################### 服务保障相关配置 ####################
# Lock4j 配置项(单元测试,禁用 Lock4j
# Resilience4j 配置项
resilience4j:
ratelimiter:
instances:
backendA:
limit-for-period: 1 # 每个周期内,允许的请求数。默认为 50
limit-refresh-period: 60s # 每个周期的时长,单位:微秒。默认为 500
timeout-duration: 1s # 被限流时,阻塞等待的时长,单位:微秒。默认为 5s
register-health-indicator: true # 是否注册到健康监测
--- #################### 监控相关配置 ####################
--- #################### 芋道相关配置 ####################
# 芋道配置项,设置当前项目所有自定义的配置
yudao:
security:
token-header: Authorization
token-secret: abcdefghijklmnopqrstuvwxyz
token-timeout: 1d
session-timeout: 30m
mock-enable: true
mock-secret: test
swagger:
enable: false # 单元测试,禁用 Swagger
file:
base-path: http://127.0.0.1:${server.port}/${yudao.web.api-prefix}/file/get/
xss:
enable: false
exclude-urls: # 如下两个 url仅仅是为了演示去掉配置也没关系
- ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求
- ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求

View File

@ -13,7 +13,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
import cn.iocoder.yudao.module.system.service.member.MemberService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;

View File

@ -12,7 +12,7 @@ import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialCl
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
import com.xingyuv.jushauth.config.AuthConfig;
@ -44,8 +44,6 @@ import static org.mockito.Mockito.*;
/**
* {@link SocialClientServiceImpl} 的单元测试类
*
*/
@Import(SocialClientServiceImpl.class)
public class SocialClientServiceImplTest extends BaseDbUnitTest {
@ -278,7 +276,7 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
when(userService.getPhoneNoInfo(eq(phoneCode))).thenReturn(phoneNumber);
// 调用
WxMaPhoneNumberInfo result = socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode);
WxMaPhoneNumberInfo result = socialClientService.getWxMaPhoneNumberInfo(SocialTypeEnum.WECHAT_MINI_APP.getType(), userType, phoneCode);
// 断言
assertSame(phoneNumber, result);
}
@ -295,7 +293,7 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
when(userService.getPhoneNoInfo(eq(phoneCode))).thenThrow(wxErrorException);
// 调用并断言异常
assertServiceException(() -> socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode),
assertServiceException(() -> socialClientService.getWxMaPhoneNumberInfo(SocialTypeEnum.WECHAT_MINI_APP.getType(), userType, phoneCode),
SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR);
}

View File

@ -10,7 +10,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import com.xingyuv.jushauth.model.AuthUser;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;