package com.gs.xky.service.Impl;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.dingtalk.api.DefaultDingTalkClient;
|
import com.dingtalk.api.DingTalkClient;
|
import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request;
|
import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response;
|
import com.gs.xky.entity.DingtalkInfo;
|
import com.gs.xky.entity.DingtalkMsg;
|
import com.gs.xky.entity.MesStaff;
|
import com.gs.xky.mapper.DingtalkInfoMapper;
|
import com.gs.xky.mapper.DingtalkMsgMapper;
|
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;
|
import java.util.Optional;
|
import java.util.stream.Collectors;
|
|
/**
|
* @author 28567
|
* @description 针对表【DINGTALK_INFO】的数据库操作Service实现
|
* @createDate 2025-06-20 16:12:48
|
*/
|
@Service
|
@RequiredArgsConstructor
|
@Slf4j
|
public class DingtalkInfoServiceImpl extends ServiceImpl<DingtalkInfoMapper, DingtalkInfo>
|
implements DingtalkInfoService {
|
|
private final SimpleExample simpleExample;
|
private final DingtalkMsgMapper dingtalkMsgMapper;
|
private final MesStaffMapper mesStaffMapper;
|
|
@Override
|
public boolean sendMessage(String releaseNo) {
|
try {
|
// 查询钉钉消息内容
|
LambdaQueryWrapper<DingtalkMsg> msgWrapper = new LambdaQueryWrapper<>();
|
msgWrapper.eq(DingtalkMsg::getReleaseNo, releaseNo);
|
DingtalkMsg dingtalkMsg = dingtalkMsgMapper.selectOne(msgWrapper);
|
|
if (dingtalkMsg == null) {
|
log.error("未找到检验单号为 {} 的钉钉消息内容", releaseNo);
|
return false;
|
}
|
|
// 格式化日期
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
String createDateStr = (dingtalkMsg.getCreateDate() != null) ?
|
dateFormat.format(dingtalkMsg.getCreateDate()) : "未知";
|
|
// 构建消息内容
|
// String message = String.format("供应商[%s] 来料日期[%s] 项目[%s] 料号[%s]的不合格检验单被[%s]审批为[%s],请查收!",
|
// dingtalkMsg.getSuppName(), createDateStr, dingtalkMsg.getProjectCodes(),
|
// dingtalkMsg.getItemNo(), dingtalkMsg.getFname(), dingtalkMsg.getFngHandle());
|
|
String message = String.format(
|
"供应商[%s] 来料日期[%s] 项目[%s] 料号[%s]的不合格检验单被[%s]审批为[%s],请查收!",
|
Optional.ofNullable(dingtalkMsg.getSuppName()).orElse(" 未知供应商"),
|
createDateStr,
|
Optional.ofNullable(dingtalkMsg.getProjectCodes()).orElse(" 未知项目"),
|
Optional.ofNullable(dingtalkMsg.getItemNo()).orElse(" 未知料号"),
|
Optional.ofNullable(dingtalkMsg.getFname()).orElse(" 未知审批人"),
|
Optional.ofNullable(dingtalkMsg.getFngHandle()).orElse(" 未知审批结果"));
|
|
// 收集需要推送的人员sid
|
List<Long> sidList = new ArrayList<>();
|
|
// 1. 固定推送人员(isSendDingtalk=1)
|
List<DingtalkInfo> fixedList = baseMapper.selectList(
|
new LambdaQueryWrapper<DingtalkInfo>().eq(DingtalkInfo::getIsSendDingtalk, 1)
|
);
|
for (DingtalkInfo info : fixedList) {
|
sidList.add(info.getSid());
|
}
|
|
// 2. 采购人员(employeeName)
|
if (StringUtils.hasText(dingtalkMsg.getEmployeeName())) {
|
MesStaff buyer = mesStaffMapper.selectOne(
|
new LambdaQueryWrapper<MesStaff>().eq(MesStaff::getStaffName, dingtalkMsg.getEmployeeName()), false
|
);
|
if (buyer != null) {
|
DingtalkInfo buyerInfo = baseMapper.selectOne(
|
new LambdaQueryWrapper<DingtalkInfo>().eq(DingtalkInfo::getSid, buyer.getId()), false
|
);
|
if (buyerInfo != null) sidList.add(buyerInfo.getSid());
|
}
|
}
|
|
// 3. 审核人(modify1By)
|
if (StringUtils.hasText(dingtalkMsg.getModify1By())) {
|
MesStaff auditor = mesStaffMapper.selectOne(
|
new LambdaQueryWrapper<MesStaff>().eq(MesStaff::getStaffNo, dingtalkMsg.getModify1By())
|
);
|
if (auditor != null) {
|
DingtalkInfo auditorInfo = baseMapper.selectOne(
|
new LambdaQueryWrapper<DingtalkInfo>().eq(DingtalkInfo::getSid, auditor.getId())
|
);
|
if (auditorInfo != null) sidList.add(auditorInfo.getSid());
|
}
|
}
|
|
// 4. 根据收集的sid获取dingtalkId (复用getDingtalkUserIdList的关键逻辑)
|
List<String> userIdList = getDingtalkUserIdListBySids(sidList);
|
|
if (userIdList == null || userIdList.isEmpty()) {
|
log.warn("没有需要发送钉钉消息的用户");
|
return false;
|
}
|
|
// 通过钉钉发送消息
|
String userIdListStr = String.join(",", userIdList);
|
|
OapiMessageCorpconversationAsyncsendV2Response rsp = sendMessage(userIdListStr, message);
|
System.out.println(rsp.getBody());
|
log.info("成功发送钉钉消息: {}", message);
|
return true;
|
} catch (Exception e) {
|
log.error("发送钉钉消息失败", e);
|
return false;
|
}
|
}
|
|
@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列表
|
*
|
* @param sidList sid列表
|
* @return 钉钉用户ID列表
|
*/
|
private List<String> getDingtalkUserIdListBySids(List<Long> sidList) {
|
try {
|
if (sidList == null || sidList.isEmpty()) {
|
return new ArrayList<>();
|
}
|
|
// 去重
|
sidList = sidList.stream().distinct().collect(Collectors.toList());
|
|
// 根据sid查询DingtalkInfo
|
List<DingtalkInfo> list = baseMapper.selectList(
|
new LambdaQueryWrapper<DingtalkInfo>().in(DingtalkInfo::getSid, sidList)
|
);
|
|
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 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(4104598880L);
|
request.setUseridList(userIdListStr);
|
request.setToAllUser(false);
|
|
OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
|
msg.setMsgtype("text");
|
msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
|
msg.getText().setContent(message);
|
request.setMsg(msg);
|
|
return client.execute(request, accessToken);
|
|
}
|
|
/**
|
* 发送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() {
|
try {
|
LambdaQueryWrapper<DingtalkInfo> wrapper = new LambdaQueryWrapper<>();
|
wrapper.ge(DingtalkInfo::getIsSendDingtalk, 1);
|
List<DingtalkInfo> list = list(wrapper);
|
|
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<>();
|
}
|
}
|
}
|