package com.ruoyi.system.service.impl;
|
|
import com.ruoyi.common.config.WechatConfig;
|
import com.ruoyi.common.core.domain.entity.SysUser;
|
import com.ruoyi.common.utils.DateUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.WechatUtils;
|
import com.ruoyi.system.domain.SysConfig;
|
import com.ruoyi.system.mapper.SysConfigMapper;
|
import com.ruoyi.system.mapper.SysTaskEmergencyMapper;
|
import com.ruoyi.system.mapper.SysTaskMapper;
|
import com.ruoyi.system.domain.SysTask;
|
import com.ruoyi.system.domain.SysTaskEmergency;
|
import com.ruoyi.system.mapper.SysUserMapper;
|
import com.ruoyi.system.service.IWechatTaskNotifyService;
|
import com.ruoyi.system.service.ISysConfigService;
|
import com.ruoyi.system.mapper.SysConfigMapper;
|
import com.ruoyi.system.domain.SysConfig;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
|
/**
|
* 微信任务通知服务实现
|
* 统一管理所有任务相关的微信订阅消息发送逻辑
|
*
|
* @author ruoyi
|
* @date 2025-11-30
|
*/
|
@Service
|
public class WechatTaskNotifyServiceImpl implements IWechatTaskNotifyService {
|
|
private static final Logger log = LoggerFactory.getLogger(WechatTaskNotifyServiceImpl.class);
|
|
@Autowired
|
private SysTaskMapper sysTaskMapper;
|
|
@Autowired
|
private SysTaskEmergencyMapper sysTaskEmergencyMapper;
|
|
@Autowired
|
private SysUserMapper sysUserMapper;
|
|
@Autowired
|
private WechatConfig wechatConfig;
|
|
@Autowired
|
private ISysConfigService configService;
|
|
@Autowired
|
private SysConfigMapper configMapper;
|
|
|
/**
|
* 获取应用级微信AccessToken(带缓存)
|
* 优先从sys_config读取并判断有效期;过期则重新获取并写回sys_config
|
*/
|
private String getAppAccessToken() {
|
try {
|
String appId = wechatConfig.getAppId();
|
String tokenKey = "weixin.access_token." + appId;
|
String expireKey = "weixin.access_token_expires." + appId;
|
|
String cachedToken = configService.selectConfigByKey(tokenKey);
|
String cachedExpireStr = configService.selectConfigByKey(expireKey);
|
long now = System.currentTimeMillis();
|
long expireTs = 0L;
|
if (StringUtils.isNotEmpty(cachedExpireStr)) {
|
try {
|
expireTs = Long.parseLong(cachedExpireStr);
|
} catch (NumberFormatException e) {
|
expireTs = 0L;
|
}
|
}
|
|
// 缓存有效且未过期(预留60秒安全边界)
|
if (StringUtils.isNotEmpty(cachedToken) && expireTs > now + 60000L) {
|
return cachedToken;
|
}
|
|
// 重新获取,并写入sys_config
|
String newToken = WechatUtils.getAccessToken(wechatConfig.getAppId(), wechatConfig.getAppSecret());
|
if (StringUtils.isEmpty(newToken)) {
|
return null;
|
}
|
long newExpireTs = now + 7200L * 1000L; // 7200秒
|
upsertConfig(tokenKey, newToken);
|
upsertConfig(expireKey, String.valueOf(newExpireTs));
|
return newToken;
|
} catch (Exception e) {
|
log.error("获取应用级微信AccessToken失败", e);
|
return null;
|
}
|
}
|
|
/**
|
* 根据configKey写入或更新sys_config
|
*/
|
private void upsertConfig(String key, String value) {
|
SysConfig exist = configMapper.checkConfigKeyUnique(key);
|
if (exist != null && exist.getConfigId() != null) {
|
exist.setConfigValue(value);
|
configMapper.updateConfig(exist);
|
} else {
|
SysConfig cfg = new SysConfig();
|
cfg.setConfigKey(key);
|
cfg.setConfigName(key);
|
cfg.setConfigValue(value);
|
cfg.setConfigType("Y"); // 内置参数
|
configMapper.insertConfig(cfg);
|
}
|
}
|
|
/**
|
* 发送任务通知消息给指定用户列表
|
*
|
* @param taskId 任务ID
|
* @param userIds 接收用户ID列表
|
* @param excludeUserId 排除的用户ID(可选,如创建人)
|
* @return 成功发送的消息数量
|
*/
|
@Override
|
public int sendTaskNotifyMessage(Long taskId, List<Long> userIds, Long excludeUserId) {
|
if (taskId == null || userIds == null || userIds.isEmpty()) {
|
log.warn("发送微信任务通知参数不完整,taskId={}, userIds={}", taskId, userIds);
|
return 0;
|
}
|
|
// 查询任务信息
|
SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
|
if (task == null) {
|
log.warn("微信通知失败,任务不存在,taskId={}", taskId);
|
return 0;
|
}
|
|
// 查询急救信息
|
SysTaskEmergency emergency = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
|
|
// 获取微信AccessToken(走应用级缓存)
|
String accessToken = getAppAccessToken();
|
if (StringUtils.isEmpty(accessToken)) {
|
log.error("获取微信AccessToken失败,无法发送任务通知");
|
return 0;
|
}
|
|
// 构造消息数据
|
Map<String, String> data = buildTaskNotifyData(task, emergency);
|
|
// 获取模板配置
|
String page = wechatConfig.getTaskDetailPage() + "?id=" + taskId;
|
String templateId = wechatConfig.getTaskNotifyTemplateId();
|
|
// 发送消息给每个用户
|
int successCount = 0;
|
for (Long userId : userIds) {
|
// 排除指定用户
|
if (excludeUserId != null && excludeUserId.equals(userId)) {
|
log.debug("跳过排除用户,userId={}", userId);
|
continue;
|
}
|
|
// 查询用户信息
|
SysUser user = sysUserMapper.selectUserById(userId);
|
if (user == null || StringUtils.isEmpty(user.getOpenId())) {
|
log.debug("用户未绑定微信openId,跳过发送,userId={}", userId);
|
continue;
|
}
|
|
// 发送订阅消息
|
try {
|
WechatUtils.sendSubscribeMessage(accessToken, user.getOpenId(), templateId, page, data);
|
successCount++;
|
log.info("微信任务通知发送成功,taskId={}, userId={}, userName={}", taskId, userId, user.getUserName());
|
} catch (Exception e) {
|
log.error("微信任务通知发送失败,taskId={}, userId={}", taskId, userId, e);
|
}
|
}
|
|
log.info("微信任务通知批量发送完成,taskId={}, 总数={}, 成功={}", taskId, userIds.size(), successCount);
|
return successCount;
|
}
|
|
/**
|
* 发送任务通知消息给指定用户列表(不排除任何用户)
|
*
|
* @param taskId 任务ID
|
* @param userIds 接收用户ID列表
|
* @return 成功发送的消息数量
|
*/
|
@Override
|
public int sendTaskNotifyMessage(Long taskId, List<Long> userIds) {
|
return sendTaskNotifyMessage(taskId, userIds, null);
|
}
|
|
/**
|
* 构造任务通知的消息数据
|
*
|
* @param task 任务信息
|
* @param emergency 急救信息(可选)
|
* @return 消息数据Map
|
*/
|
private Map<String, String> buildTaskNotifyData(SysTask task, SysTaskEmergency emergency) {
|
// 事项描述
|
String problemDesc = "您有新的转运任务,请及时处理";
|
|
// 地点信息
|
String location;
|
if (emergency != null && StringUtils.isNotEmpty(emergency.getHospitalOutName()) && StringUtils.isNotEmpty(emergency.getHospitalInName())) {
|
location = emergency.getHospitalOutName() + " → " + emergency.getHospitalInName();
|
} else if (StringUtils.isNotEmpty(task.getDepartureAddress()) && StringUtils.isNotEmpty(task.getDestinationAddress())) {
|
location = task.getDepartureAddress() + " → " + task.getDestinationAddress();
|
} else {
|
location = "未知地点";
|
}
|
|
// 时间信息
|
String startTimeStr;
|
if (task.getPlannedStartTime() != null) {
|
startTimeStr = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm", task.getPlannedStartTime());
|
} else {
|
startTimeStr = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm", new java.util.Date());
|
}
|
|
// 运单号
|
String waybillNo = StringUtils.isNotEmpty(task.getTaskCode()) ? task.getTaskCode() : String.valueOf(task.getTaskId());
|
|
// 组装数据(应用thing类型字段的长度限制)
|
Map<String, String> data = new HashMap<>();
|
// data.put("thing1", WechatUtils.truncateThingValue(problemDesc)); // 截断thing类型字段
|
// data.put("thing10", WechatUtils.truncateThingValue(location)); // 截断thing类型字段
|
data.put("time8", startTimeStr);
|
data.put("character_string1", waybillNo);
|
|
return data;
|
}
|
}
|