feat:服务号通知
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
package com.cool.store.enums.wechat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/10/16 15:19
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
public enum WechatTemplateDetailEnum {
|
||||||
|
|
||||||
|
CHARACTER_STRING2("编号","character_string2"),
|
||||||
|
THING10("项目名称","thing10"),
|
||||||
|
TIME14("完成时间","time14"),
|
||||||
|
THING25("客户名称","thing25"),
|
||||||
|
THING60("位置","thing60"),
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(String code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
WechatTemplateDetailEnum(String name, String code) {
|
||||||
|
this.name = name;
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,6 +2,12 @@ package com.cool.store.enums.wechat;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.cool.store.enums.wechat.WechatTemplateDetailEnum.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author suzhuhong
|
* @Author suzhuhong
|
||||||
* @Date 2025/10/10 14:39
|
* @Date 2025/10/10 14:39
|
||||||
@@ -9,24 +15,22 @@ import com.fasterxml.jackson.annotation.JsonValue;
|
|||||||
*/
|
*/
|
||||||
public enum WechatTemplateEnum {
|
public enum WechatTemplateEnum {
|
||||||
|
|
||||||
ORDER_PAY_SUCCESS("ORDER_PAY_SUCCESS", "TM00001", "订单支付成功通知",
|
QUESTION_NOTICE("QUESTION_NOTICE", "T3sp5gBItHKD8oCeEiQMjn7JXpngFiz3dDcaArk84xY", "收到工单通知",
|
||||||
"您的订单已支付成功\n订单号:{{orderNo.DATA}}\n支付金额:{{amount.DATA}}元\n支付时间:{{payTime.DATA}}\n感谢您的购买!"),
|
Arrays.asList(CHARACTER_STRING2,THING10,TIME14,THING25,THING60)),
|
||||||
|
|
||||||
TEST("TEST", "T3sp5gBItHKD8oCeEiQMjn7JXpngFiz3dDcaArk84xY", "收到工单通知",
|
|
||||||
"测试模板"),
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
private final String code;
|
private final String code;
|
||||||
private final String templateId;
|
private final String templateId;
|
||||||
private final String title;
|
private final String title;
|
||||||
private final String content;
|
private final List<WechatTemplateDetailEnum> contentList;
|
||||||
|
|
||||||
WechatTemplateEnum(String code, String templateId, String title, String content) {
|
WechatTemplateEnum(String code, String templateId, String title, List<WechatTemplateDetailEnum> contentList) {
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.templateId = templateId;
|
this.templateId = templateId;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.content = content;
|
this.contentList = contentList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonValue
|
@JsonValue
|
||||||
@@ -42,8 +46,8 @@ public enum WechatTemplateEnum {
|
|||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getContent() {
|
public List<WechatTemplateDetailEnum> getContentList() {
|
||||||
return content;
|
return contentList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.cool.store.dao;
|
package com.cool.store.dao;
|
||||||
|
|
||||||
|
import com.cool.store.dto.wechat.ServiceAccountOpenIdDTO;
|
||||||
import com.cool.store.entity.HyPartnerUserInfoDO;
|
import com.cool.store.entity.HyPartnerUserInfoDO;
|
||||||
import com.cool.store.mapper.HyPartnerUserInfoMapper;
|
import com.cool.store.mapper.HyPartnerUserInfoMapper;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
@@ -112,4 +113,11 @@ public class HyPartnerUserInfoDAO {
|
|||||||
|
|
||||||
return hyPartnerUserInfoMapper.selectPasswordIsNull();
|
return hyPartnerUserInfoMapper.selectPasswordIsNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ServiceAccountOpenIdDTO> selectLastBindRecord(List<String> mobileList){
|
||||||
|
if (CollectionUtils.isEmpty(mobileList)){
|
||||||
|
return Lists.newArrayList();
|
||||||
|
}
|
||||||
|
return hyPartnerUserInfoMapper.selectLastBindRecord(mobileList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.cool.store.mapper;
|
package com.cool.store.mapper;
|
||||||
|
|
||||||
|
import com.cool.store.dto.wechat.ServiceAccountOpenIdDTO;
|
||||||
import com.cool.store.entity.HyPartnerUserInfoDO;
|
import com.cool.store.entity.HyPartnerUserInfoDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
@@ -55,4 +56,6 @@ public interface HyPartnerUserInfoMapper extends tk.mybatis.mapper.common.Mappe
|
|||||||
|
|
||||||
List<HyPartnerUserInfoDO> selectPasswordIsNull();
|
List<HyPartnerUserInfoDO> selectPasswordIsNull();
|
||||||
|
|
||||||
|
List<ServiceAccountOpenIdDTO> selectLastBindRecord(@Param("mobileList") List<String> mobileList);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -195,4 +195,23 @@
|
|||||||
</foreach>
|
</foreach>
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<select id="selectLastBindRecord" resultType="com.cool.store.dto.wechat.ServiceAccountOpenIdDTO">
|
||||||
|
select
|
||||||
|
b.partner_id,
|
||||||
|
b.union_id,
|
||||||
|
.service_account_open_id,
|
||||||
|
MAX(b.update_time)
|
||||||
|
from xfsg_partner_user_info a
|
||||||
|
left join xfsg_partner_user_wechat_bind b
|
||||||
|
on a.partner_id = b.partner_id
|
||||||
|
where b.partner_id is not null
|
||||||
|
and service_account_open_id is not null
|
||||||
|
<if test="mobileList !=null and mobileList.size>0">
|
||||||
|
<foreach collection="mobileList" open="and mobile in (" close=")" separator="," item="mobile">
|
||||||
|
#{mobile}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
GROUP BY b.partner_id
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.cool.store.dto.wechat;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/10/16 14:13
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ServiceAccountOpenIdDTO {
|
||||||
|
|
||||||
|
private String partnerId;
|
||||||
|
|
||||||
|
private String unionId;
|
||||||
|
|
||||||
|
private String serviceAccountOpenId;
|
||||||
|
|
||||||
|
private Date lastUpdateTime;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -10,9 +10,12 @@ import com.cool.store.dto.notice.MessageTemplateCountDTO;
|
|||||||
import com.cool.store.dto.notice.NoticeDTO;
|
import com.cool.store.dto.notice.NoticeDTO;
|
||||||
import com.cool.store.dto.store.AuthStoreUserDTO;
|
import com.cool.store.dto.store.AuthStoreUserDTO;
|
||||||
import com.cool.store.dto.store.StoreAreaDTO;
|
import com.cool.store.dto.store.StoreAreaDTO;
|
||||||
|
import com.cool.store.dto.wechat.ServiceAccountOpenIdDTO;
|
||||||
import com.cool.store.entity.*;
|
import com.cool.store.entity.*;
|
||||||
import com.cool.store.enums.ErrorCodeEnum;
|
import com.cool.store.enums.ErrorCodeEnum;
|
||||||
import com.cool.store.enums.notice.*;
|
import com.cool.store.enums.notice.*;
|
||||||
|
import com.cool.store.enums.wechat.WechatTemplateDetailEnum;
|
||||||
|
import com.cool.store.enums.wechat.WechatTemplateEnum;
|
||||||
import com.cool.store.exception.ServiceException;
|
import com.cool.store.exception.ServiceException;
|
||||||
import com.cool.store.mapper.StoreGroupMappingMapper;
|
import com.cool.store.mapper.StoreGroupMappingMapper;
|
||||||
import com.cool.store.mapper.StoreMapper;
|
import com.cool.store.mapper.StoreMapper;
|
||||||
@@ -20,12 +23,15 @@ import com.cool.store.request.notice.*;
|
|||||||
import com.cool.store.response.bigdata.ApiResponse;
|
import com.cool.store.response.bigdata.ApiResponse;
|
||||||
import com.cool.store.service.MessageTemplateService;
|
import com.cool.store.service.MessageTemplateService;
|
||||||
import com.cool.store.service.StoreService;
|
import com.cool.store.service.StoreService;
|
||||||
|
import com.cool.store.service.wechat.WechatTemplateService;
|
||||||
import com.cool.store.utils.CoolDateUtils;
|
import com.cool.store.utils.CoolDateUtils;
|
||||||
import com.cool.store.utils.RedisUtilPool;
|
import com.cool.store.utils.RedisUtilPool;
|
||||||
|
import com.cool.store.utils.poi.DateUtils;
|
||||||
import com.cool.store.vo.PartnerUserInfoVO;
|
import com.cool.store.vo.PartnerUserInfoVO;
|
||||||
import com.cool.store.vo.notice.*;
|
import com.cool.store.vo.notice.*;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
@@ -70,9 +76,13 @@ public class MessageTemplateServiceImpl implements MessageTemplateService {
|
|||||||
@Resource
|
@Resource
|
||||||
MatterConfigDAO matterConfigDAO;
|
MatterConfigDAO matterConfigDAO;
|
||||||
@Resource
|
@Resource
|
||||||
|
WechatTemplateService wechatTemplateService;
|
||||||
|
@Resource
|
||||||
RedisUtilPool redisUtilPool;
|
RedisUtilPool redisUtilPool;
|
||||||
@Resource
|
@Resource
|
||||||
TaskExecutor noticeThreadPool;
|
TaskExecutor noticeThreadPool;
|
||||||
|
@Resource
|
||||||
|
HyPartnerUserInfoDAO hyPartnerUserInfoDAO;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -207,6 +217,36 @@ public class MessageTemplateServiceImpl implements MessageTemplateService {
|
|||||||
JSONObject.toJSONString(request.getStoreInfoList()),
|
JSONObject.toJSONString(request.getStoreInfoList()),
|
||||||
JSONObject.toJSONString(request.getUserInfoList()),
|
JSONObject.toJSONString(request.getUserInfoList()),
|
||||||
userId);
|
userId);
|
||||||
|
|
||||||
|
//发送通知
|
||||||
|
Set<String> userIds = authUser.values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
//分批 查询用户信息
|
||||||
|
List<String> openIdList = new ArrayList<>();
|
||||||
|
Lists.partition(new ArrayList<>(userIds), 100).forEach(x->{
|
||||||
|
List<EnterpriseUserDO> userInfoByUserIds = enterpriseUserDAO.getUserInfoByUserIds(x);
|
||||||
|
//取出用户的手机号,过滤掉空的手机号
|
||||||
|
List<String> mobileList = userInfoByUserIds.stream().filter(user -> StringUtils.isNotBlank(user.getMobile())).map(EnterpriseUserDO::getMobile).collect(Collectors.toList());
|
||||||
|
if (CollectionUtils.isNotEmpty(mobileList)){
|
||||||
|
List<ServiceAccountOpenIdDTO> serviceAccountOpenIdDTOS = hyPartnerUserInfoDAO.selectLastBindRecord(mobileList);
|
||||||
|
if (CollectionUtils.isNotEmpty(serviceAccountOpenIdDTOS)){
|
||||||
|
//服务号ID
|
||||||
|
openIdList.addAll(serviceAccountOpenIdDTOS.stream().map(ServiceAccountOpenIdDTO::getServiceAccountOpenId).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
MessageTemplateDO messageTemplateDO = list.get(0);
|
||||||
|
Map<String, Object> data = new HashMap<>();
|
||||||
|
data.put(WechatTemplateDetailEnum.CHARACTER_STRING2.getCode(), "ceshi002");
|
||||||
|
data.put(WechatTemplateDetailEnum.THING10.getCode(), messageTemplateDO.getMessageTitle());
|
||||||
|
data.put(WechatTemplateDetailEnum.TIME14.getCode(), DateUtils.parseDateToStr(DateUtils.SPECIAL_DATE_START_1, messageTemplateDO.getDeadline()));
|
||||||
|
data.put(WechatTemplateDetailEnum.THING25.getCode(), "正新管理有限公司");
|
||||||
|
data.put(WechatTemplateDetailEnum.THING60.getCode(), "上海市-松江区");
|
||||||
|
openIdList.forEach(x->{
|
||||||
|
wechatTemplateService.sendMiniAppTemplate(x, WechatTemplateEnum.QUESTION_NOTICE,data,null);
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.info("发布流程异常,已取消发布");
|
log.info("发布流程异常,已取消发布");
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -127,58 +127,4 @@ public class WechatTemplateService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendTemplateMessageAsync(WechatTemplateMessageDTO messageDTO, WechatCallback callback) {
|
|
||||||
String accessToken = getAccessToken();
|
|
||||||
if (accessToken == null) {
|
|
||||||
log.error("获取access_token失败,无法发送模板消息");
|
|
||||||
callback.onFailure(new IOException("获取access_token失败"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String url = String.format("%s?access_token=%s",
|
|
||||||
wechatMpProperties.getSendTemplateMessageUrl(), accessToken);
|
|
||||||
|
|
||||||
okHttpUtil.doPostAsync(url, messageDTO, new okhttp3.Callback() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
|
|
||||||
try {
|
|
||||||
String result = response.body() != null ? response.body().string() : null;
|
|
||||||
log.info("异步发送模板消息响应: {}", result);
|
|
||||||
|
|
||||||
if (response.isSuccessful() && result != null) {
|
|
||||||
callback.onSuccess(Boolean.TRUE);
|
|
||||||
} else {
|
|
||||||
callback.onFailure(new IOException("请求失败,状态码: " + response.code()));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
callback.onFailure(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(okhttp3.Call call, IOException e) {
|
|
||||||
log.error("异步发送模板消息失败", e);
|
|
||||||
callback.onFailure(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendNormalTemplateAsync(String openId, WechatTemplateEnum template,
|
|
||||||
Map<String, Object> data, WechatCallback callback) {
|
|
||||||
WechatTemplateMessageDTO messageDTO = templateMessageBuilder.buildNormalTemplate(openId, template, data);
|
|
||||||
sendTemplateMessageAsync(messageDTO, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendMiniAppTemplateAsync(String openId, WechatTemplateEnum template,
|
|
||||||
Map<String, Object> data, String miniAppPagePath, WechatCallback callback) {
|
|
||||||
WechatTemplateMessageDTO messageDTO = templateMessageBuilder.buildMiniappTemplate(
|
|
||||||
openId, template, data, miniAppPagePath);
|
|
||||||
sendTemplateMessageAsync(messageDTO, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface WechatCallback {
|
|
||||||
void onSuccess(Boolean successFlag);
|
|
||||||
void onFailure(Exception e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -602,7 +602,7 @@ public class PCTestController {
|
|||||||
data.put("time14", "2025-10-01 12:00:00");
|
data.put("time14", "2025-10-01 12:00:00");
|
||||||
data.put("thing25", "正新管理有限公司");
|
data.put("thing25", "正新管理有限公司");
|
||||||
data.put("thing60", "上海市-松江区");
|
data.put("thing60", "上海市-松江区");
|
||||||
wechatTemplateService.sendNormalTemplate("o9_unvpJy1SGdnkeun7igRBSLuB0", WechatTemplateEnum.TEST, data);
|
wechatTemplateService.sendNormalTemplate("o9_unvpJy1SGdnkeun7igRBSLuB0", WechatTemplateEnum.QUESTION_NOTICE, data);
|
||||||
return ApiResponse.success(true);
|
return ApiResponse.success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user