tjx
2025-11-18 b6178a1aae26fb1392c599799bf0b472ace0f57d
src/main/java/com/gs/xky/service/Impl/DingtalkInfoServiceImpl.java
@@ -14,11 +14,13 @@
import com.gs.xky.mapper.MesStaffMapper;
import com.gs.xky.service.DingtalkInfoService;
import com.gs.xky.service.SimpleExample;
import com.taobao.api.FileItem;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
@@ -130,6 +132,95 @@
        }
    }
    @Override
    public boolean sendActionCardMessage() {
        try {
            // 1. 获取需要推送的用户列表(可以是固定推送用户)
            List<DingtalkInfo> fixedList = baseMapper.selectList(
                    new LambdaQueryWrapper<DingtalkInfo>().eq(DingtalkInfo::getIsHead, 1)
            );
            List<Long> sidList = fixedList.stream()
                    .map(DingtalkInfo::getSid)
                    .collect(Collectors.toList());
            List<String> userIdList = getDingtalkUserIdListBySids(sidList);
            if (userIdList == null || userIdList.isEmpty()) {
                log.warn("没有需要发送钉钉消息的用户");
                return false;
            }
            String userIdListStr = String.join(",", userIdList);
            // 2. 构建消息内容
            String title = "生产数据看板";
            String markdown = "请点击下方按钮查看详细BI报表";
            String singleTitle = "查看报表";
            String singleUrl = "http://192.168.1.22:8081/design?fid=rpte6045ab079b211f0824bd3cfd50c6b93&fserid=4b198960bedd11f09f6f792bfe147b64&fsharetype=3";
            // 3. 发送消息
            OapiMessageCorpconversationAsyncsendV2Response rsp =
                    sendActionCardMessage(userIdListStr, title, markdown, singleTitle, singleUrl);
            log.info("成功发送ActionCard消息: {}", rsp.getBody());
            return true;
        } catch (Exception e) {
            log.error("发送ActionCard消息失败", e);
            return false;
        }
    }
    @Override
    public boolean sendFileMessage(String filePath) throws Exception {
        try {
            // 1. 检查文件是否存在
            File file = new File(filePath);
            if (!file.exists()) {
                log.error("文件不存在: {}", filePath);
                return false;
            }
            // 2. 获取需要推送的用户列表(可根据实际需求调整,这里使用isHead=1的用户)
            List<DingtalkInfo> fixedList = baseMapper.selectList(
                    new LambdaQueryWrapper<DingtalkInfo>().eq(DingtalkInfo::getIsHead, 1)
            );
            if (fixedList == null || fixedList.isEmpty()) {
                log.warn("没有需要发送文件的用户(isHead=1)");
                return false;
            }
            List<String> sidList = fixedList.stream()
                    .map(DingtalkInfo::getPhone)
                    .collect(Collectors.toList());
            List<String> userIdList = getDingtalkUserIdListByPhones(sidList);
            if (userIdList == null || userIdList.isEmpty()) {
                log.warn("没有有效的钉钉用户ID");
                return false;
            }
            String userIdListStr = String.join(",", userIdList);
            // 3. 上传文件到钉钉服务器
            log.info("开始上传文件: {}", filePath);
            String mediaId = uploadMedia(filePath, "file");
            // 4. 发送文件消息
            log.info("开始发送文件消息,mediaId: {}", mediaId);
            OapiMessageCorpconversationAsyncsendV2Response response = sendFileMessageByMediaId(userIdListStr, mediaId);
            log.info("文件消息发送响应: {}", response.getBody());
            return response.getErrcode() == 0;
        } catch (Exception e) {
            log.error("发送文件消息失败", e);
            throw e;
        }
    }
    /**
     * 根据指定的sid列表获取钉钉用户ID列表
     *
@@ -194,13 +285,72 @@
        }
    }
    private List<String> getDingtalkUserIdListByPhones(List<String> phoneList) {
        try {
            if (phoneList == null || phoneList.isEmpty()) {
                return new ArrayList<>();
            }
            // 去重
            phoneList = phoneList.stream().distinct().collect(Collectors.toList());
            // 根据sid查询DingtalkInfo
            List<DingtalkInfo> list = baseMapper.selectList(
                    new LambdaQueryWrapper<DingtalkInfo>().in(DingtalkInfo::getPhone, phoneList)
            );
            if (list == null || list.isEmpty()) {
                return new ArrayList<>();
            }
            // 使用stream流过滤出list中dingtalkId为空的数据
            List<DingtalkInfo> emptyDingtalkIdList = list.stream()
                    .filter(info -> !StringUtils.hasText(info.getDingtalkId()))
                    .collect(Collectors.toList());
            // 如果存在为空的数据就通过钉钉的接口获取,为dingtalkId赋值,并且更新数据库
            if (!emptyDingtalkIdList.isEmpty()) {
                String accessToken = simpleExample.getAccessToken();
                for (DingtalkInfo info : emptyDingtalkIdList) {
                    if (StringUtils.hasText(info.getPhone())) {
                        try {
                            // 通过手机号获取钉钉用户ID
                            com.dingtalk.api.response.OapiV2UserGetbymobileResponse response =
                                    simpleExample.getOapiV2UserGetbymobileResponse(info.getPhone(), accessToken);
                            if (response != null && response.getResult() != null) {
                                info.setDingtalkId(response.getResult().getUserid());
                                // 更新数据库
                                updateById(info);
                            }
                        } catch (Exception e) {
                            log.error("获取钉钉用户ID失败,手机号:{}", info.getPhone(), e);
                        }
                    }
                }
            }
            // 不存在为空的数据或者处理完空数据后,返回所有有效的dingtalkId列表
            return list.stream()
                    .map(DingtalkInfo::getDingtalkId)
                    .filter(StringUtils::hasText)
                    .distinct()
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("获取钉钉用户列表失败", e);
            return new ArrayList<>();
        }
    }
    private OapiMessageCorpconversationAsyncsendV2Response sendMessage(String userIdListStr, String message) throws Exception {
        String accessToken = simpleExample.getAccessToken();
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
        OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
        request.setAgentId(3917187842L);
        request.setAgentId(4104598880L);
        request.setUseridList(userIdListStr);
        request.setToAllUser(false);
@@ -215,6 +365,135 @@
    }
    /**
     * 发送link消息(在钉钉内置浏览器中打开)
     *
     * @param userIdListStr 用户ID列表,逗号分隔
     * @param title         消息标题
     * @param text          消息内容
     * @param messageUrl    点击消息后跳转的URL
     * @param picUrl        图片URL(可选)
     * @return 响应结果
     * @throws Exception 异常
     */
    private OapiMessageCorpconversationAsyncsendV2Response sendLinkMessage(String userIdListStr, String title, String text, String messageUrl, String picUrl) throws Exception {
        String accessToken = simpleExample.getAccessToken();
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
        OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
        request.setAgentId(4104598880L);
        request.setUseridList(userIdListStr);
        request.setToAllUser(false);
        OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
        msg.setMsgtype("link");
        msg.setLink(new OapiMessageCorpconversationAsyncsendV2Request.Link());
        msg.getLink().setTitle(title);
        msg.getLink().setText(text);
        msg.getLink().setMessageUrl(messageUrl);
        if (StringUtils.hasText(picUrl)) {
            msg.getLink().setPicUrl(picUrl);
        }
        request.setMsg(msg);
        return client.execute(request, accessToken);
    }
    /**
     * 发送ActionCard消息(在外部浏览器中打开链接,适合BI等外部系统)
     *
     * @param userIdListStr 用户ID列表,逗号分隔
     * @param title         消息标题
     * @param markdown      消息内容(支持Markdown格式)
     * @param singleTitle   按钮文字,例如:"查看详情"
     * @param singleUrl     点击按钮后跳转的URL(外部链接)
     * @return 响应结果
     * @throws Exception 异常
     */
    private OapiMessageCorpconversationAsyncsendV2Response sendActionCardMessage(String userIdListStr, String title, String markdown, String singleTitle, String singleUrl) throws Exception {
        String accessToken = simpleExample.getAccessToken();
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
        OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
        request.setAgentId(4104598880L);
        request.setUseridList(userIdListStr);
        request.setToAllUser(false);
        OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
        msg.setMsgtype("action_card");
        msg.setActionCard(new OapiMessageCorpconversationAsyncsendV2Request.ActionCard());
        msg.getActionCard().setTitle(title);
        msg.getActionCard().setMarkdown(markdown);
        msg.getActionCard().setSingleTitle(singleTitle);
        msg.getActionCard().setSingleUrl(singleUrl);
        request.setMsg(msg);
        return client.execute(request, accessToken);
    }
    /**
     * 上传文件到钉钉服务器,获取media_id
     *
     * @param filePath 本地文件路径
     * @param fileType 文件类型:file(普通文件), voice(语音文件), video(视频文件), image(图片文件)
     * @return media_id
     * @throws Exception 异常
     */
    private String uploadMedia(String filePath, String fileType) throws Exception {
        String accessToken = simpleExample.getAccessToken();
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/media/upload");
        com.dingtalk.api.request.OapiMediaUploadRequest request = new com.dingtalk.api.request.OapiMediaUploadRequest();
        request.setType(fileType);
        // 使用 FileItem 包装文件
        File file = new File(filePath);
        FileItem fileItem = new FileItem(file);
        request.setMedia(fileItem);
        com.dingtalk.api.response.OapiMediaUploadResponse response = client.execute(request, accessToken);
        if (response.getErrcode() == 0) {
            log.info("文件上传成功,media_id: {}", response.getMediaId());
            return response.getMediaId();
        } else {
            log.error("文件上传失败,错误码: {}, 错误信息: {}", response.getErrcode(), response.getErrmsg());
            throw new Exception("文件上传失败: " + response.getErrmsg());
        }
    }
    /**
     * 通过media_id发送文件消息
     *
     * @param userIdListStr 用户ID列表,逗号分隔
     * @param mediaId       文件的media_id(通过uploadMedia方法获取)
     * @return 响应结果
     * @throws Exception 异常
     */
    private OapiMessageCorpconversationAsyncsendV2Response sendFileMessageByMediaId(String userIdListStr, String mediaId) throws Exception {
        String accessToken = simpleExample.getAccessToken();
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
        OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
        request.setAgentId(4104598880L);
        request.setUseridList(userIdListStr);
        request.setToAllUser(false);
        OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
        msg.setMsgtype("file");
        msg.setFile(new OapiMessageCorpconversationAsyncsendV2Request.File());
        msg.getFile().setMediaId(mediaId);
        request.setMsg(msg);
        return client.execute(request, accessToken);
    }
    /**
     * 获取isSendDingtalk=1的用户的钉钉用户ID列表(保留原有方法,向后兼容)
     */
    private List<String> getDingtalkUserIdList() {