package com.ruoyi.project.system.service.impl; import com.getui.push.v2.sdk.ApiHelper; import com.getui.push.v2.sdk.GtApiConfiguration; import com.getui.push.v2.sdk.api.PushApi; import com.getui.push.v2.sdk.common.ApiResult; import com.getui.push.v2.sdk.dto.req.Audience; import com.getui.push.v2.sdk.dto.req.message.PushChannel; import com.getui.push.v2.sdk.dto.req.message.PushDTO; import com.getui.push.v2.sdk.dto.req.message.PushMessage; import com.getui.push.v2.sdk.dto.req.message.android.AndroidDTO; import com.getui.push.v2.sdk.dto.req.message.android.ThirdNotification; import com.getui.push.v2.sdk.dto.req.message.android.Ups; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.project.system.domain.GetuiConfig; import com.ruoyi.project.system.domain.SysMenu; import com.ruoyi.project.system.domain.SysNotice; import com.ruoyi.project.system.domain.SysUserClient; import com.ruoyi.project.system.mapper.SysMenuMapper; import com.ruoyi.project.system.service.SysUserClientService; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.util.List; import java.util.Map; /** * APP消息推送服务 * * @author deslrey * @version 1.4 * @since 2026/2/9 */ @Slf4j @Component public class UnipushService { @Autowired private SysMenuMapper sysMenuMapper; @Autowired private GetuiConfig getuiConfig; @Autowired private SysUserClientService userClientService; private PushApi pushApi; private static final String DEFAULT_APP_PAGE = "pages/index"; @PostConstruct public void init() { GtApiConfiguration config = new GtApiConfiguration(); config.setAppId(getuiConfig.getAppId()); config.setAppKey(getuiConfig.getAppKey()); config.setMasterSecret(getuiConfig.getMasterSecret()); config.setDomain(getuiConfig.getDomain()); ApiHelper apiHelper = ApiHelper.build(config); this.pushApi = apiHelper.creatApi(PushApi.class); } /** * 批量发送通知公告到移动端 */ @Async public void sendClientMessage(List sysNoticeList) { if (sysNoticeList == null || sysNoticeList.isEmpty()) { return; } for (SysNotice sysNotice : sysNoticeList) { SysUserClient client = userClientService.getById(sysNotice.getConsigneeId()); if (client == null || StringUtils.isEmpty(client.getCid())) { log.warn("用户 {} 未绑定移动端 CID,跳过推送", sysNotice.getConsigneeId()); continue; } // 转换路径 String appPath = convertWebPathToAppPath(sysNotice.getJumpPath()); // 推送 sendRoutingPush( client.getCid(), sysNotice.getNoticeTitle(), sysNotice.getRemark() != null ? sysNotice.getRemark() : sysNotice.getNoticeContent(), appPath ); } } /** * 将 Web 端分层全路径转换为 App 端组件路由 */ public String convertWebPathToAppPath(String webPath) { if (StringUtils.isEmpty(webPath)) { return DEFAULT_APP_PAGE; } String pathOnly = webPath; String queryString = ""; if (webPath.contains("?")) { int index = webPath.indexOf("?"); pathOnly = webPath.substring(0, index); queryString = webPath.substring(index); } String lastSegment; int lastSlashIndex = pathOnly.lastIndexOf("/"); if (lastSlashIndex != -1) { lastSegment = pathOnly.substring(lastSlashIndex + 1); } else { lastSegment = pathOnly; } if (StringUtils.isEmpty(lastSegment)) { return DEFAULT_APP_PAGE; } SysMenu menu = sysMenuMapper.selectMenuByPath(lastSegment); if (menu != null && StringUtils.isNotEmpty(menu.getAppComponent())) { String appPath = menu.getAppComponent(); if (appPath.startsWith("/")) { appPath = appPath.substring(1); } // 拼接 Web 端原始参数并返回 return appPath + queryString; } return DEFAULT_APP_PAGE; } /** * 发送单人路由推送 */ private void sendRoutingPush(String cid, String title, String content, String targetPath) { log.info("准备推送消息: CID={}, Title={}, TargetPath={}", cid, title, targetPath); PushDTO pushDTO = new PushDTO<>(); pushDTO.setRequestId("REQ_" + System.currentTimeMillis()); // 在线透传内容 PushMessage pushMessage = new PushMessage(); String transmissionContent = String.format( "{\"title\":\"%s\",\"content\":\"%s\",\"payload\":\"%s\"}", title, content, targetPath ); pushMessage.setTransmission(transmissionContent); pushDTO.setPushMessage(pushMessage); // 接收人 Audience audience = new Audience(); audience.addCid(cid); pushDTO.setAudience(audience); // 离线推送通道 pushDTO.setPushChannel(getPushChannel(title, content, targetPath)); try { ApiResult>> result = pushApi.pushToSingleByCid(pushDTO); if (result.isSuccess()) { log.info("Unipush 推送成功: CID={}", cid); } else { log.error("Unipush 推送失败: CID={}, Code={}, Msg={}", cid, result.getCode(), result.getMsg()); } } catch (Exception e) { log.error("Unipush 推送异常: ", e); } } @NotNull private PushChannel getPushChannel(String title, String content, String targetPath) { PushChannel pushChannel = new PushChannel(); AndroidDTO androidDTO = new AndroidDTO(); Ups ups = new Ups(); ThirdNotification thirdNotification = new ThirdNotification(); thirdNotification.setTitle(title); thirdNotification.setBody(content); thirdNotification.setClickType("intent"); String intent = "intent:#Intent;launchFlags=0x04000000;" + "component=" + getuiConfig.getIntentComponent() + ";" + "S.UP-OL-P9=true;" + "S.path=" + targetPath + ";" + "S.payload=" + targetPath + ";" + "end"; thirdNotification.setIntent(intent); ups.setNotification(thirdNotification); androidDTO.setUps(ups); pushChannel.setAndroid(androidDTO); return pushChannel; } }