liu
2026-09-30 91491239c5d4611b5b1404a7abeb2bb23d0edad5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package cn.iocoder.yudao.module.wxcp.service.notify;
 
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
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 jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.message.WxCpMessage;
import me.chanjar.weixin.cp.bean.message.WxCpMessageSendResult;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
 
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
 
/**
 * 企业微信消息通知服务
 *
 * @author 超级管理员
 */
@Service
@Slf4j
public class WxCpNotifyService {
 
    @Resource
    private WxCpService wxCpService;
 
    @Resource
    private SocialUserBindMapper socialUserBindMapper;
 
    @Resource
    private SocialUserMapper socialUserMapper;
 
    /**
     * 发送登录通知消息到企业微信
     *
     * @param userId     系统用户 ID
     * @param username   用户登录名
     * @param loginType  登录方式(如:账号密码、短信、社交)
     */
    @Async
    public void sendLoginNotification(Long userId, String username, String loginType) {
        try {
            // 1. 查询用户绑定的企业微信
            String wxUserId = getWxUserId(userId);
            if (wxUserId == null) {
                log.info("[sendLoginNotification][用户({})未绑定企业微信,跳过通知]", userId);
                return;
            }
 
            // 2. 构造文本消息
            // 注意:不能用 TEXTCARD —— 企业微信要求 textcard 的 url 必填,
            // 留空会返回 41010 missing url,导致通知全部发送失败
            String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            WxCpMessage message = WxCpMessage.TEXT()
                    .toUser(wxUserId)
                    .content(String.format(
                            "【登录通知】您的账号于 %s 通过「%s」方式登录系统。\n如非本人操作,请立即修改密码。",
                            time, loginType))
                    .build();
 
            // 3. 发送消息
            WxCpMessageSendResult result = wxCpService.getMessageService().send(message);
            if (result.getErrCode() == 0) {
                log.info("[sendLoginNotification][企业微信登录通知发送成功 userId={} wxUserId={}]", userId, wxUserId);
            } else {
                log.warn("[sendLoginNotification][企业微信登录通知发送失败 userId={} wxUserId={} errCode={} errMsg={}]",
                        userId, wxUserId, result.getErrCode(), result.getErrMsg());
            }
        } catch (Exception e) {
            log.error("[sendLoginNotification][企业微信登录通知发送异常 userId={}]", userId, e);
        }
    }
 
    /**
     * 发送普通文本消息到企业微信
     *
     * @param userId  系统用户 ID
     * @param content 消息内容
     */
    @Async
    public void sendTextMessage(Long userId, String content) {
        try {
            String wxUserId = getWxUserId(userId);
            if (wxUserId == null) {
                return;
            }
 
            WxCpMessage message = WxCpMessage.TEXT()
                    .toUser(wxUserId)
                    .content(content)
                    .build();
 
            WxCpMessageSendResult result = wxCpService.getMessageService().send(message);
            if (result.getErrCode() == 0) {
                log.info("[sendTextMessage][企业微信文本消息发送成功 userId={}]", userId);
            } else {
                log.warn("[sendTextMessage][企业微信文本消息发送失败 userId={} errCode={} errMsg={}]",
                        userId, result.getErrCode(), result.getErrMsg());
            }
        } catch (Exception e) {
            log.error("[sendTextMessage][企业微信文本消息发送异常 userId={}]", userId, e);
        }
    }
 
    /**
     * 根据系统用户 ID 获取企业微信 UserId
     *
     * @param userId 系统用户 ID
     * @return 企业微信 UserId(即 openid)
     */
    private String getWxUserId(Long userId) {
        // 1. 查绑定关系
        SocialUserBindDO bind = socialUserBindMapper.selectByUserIdAndUserTypeAndSocialType(
                userId, UserTypeEnum.ADMIN.getValue(), SocialTypeEnum.WECHAT_ENTERPRISE.getType());
        if (bind == null) {
            return null;
        }
 
        // 2. 查社交用户信息
        SocialUserDO socialUser = socialUserMapper.selectById(bind.getSocialUserId());
        if (socialUser == null) {
            return null;
        }
 
        return socialUser.getOpenid();
    }
 
}