diff --git a/ruoyi-admin/ruoyi-admin.iml b/ruoyi-admin/ruoyi-admin.iml index 37e8d48..6a2d24e 100644 --- a/ruoyi-admin/ruoyi-admin.iml +++ b/ruoyi-admin/ruoyi-admin.iml @@ -4,7 +4,10 @@ - + + + + @@ -15,13 +18,13 @@ - - + + - - + + @@ -99,6 +102,9 @@ + + + @@ -119,40 +125,13 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/AppreciateController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/AppreciateController.java index 2afb0ba..f66acee 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/AppreciateController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/AppreciateController.java @@ -37,7 +37,7 @@ public class AppreciateController { public RestResponse getList(@RequestBody Map map){ Long visitStore=Long.parseLong(map.get("visitStore").toString()); List list= service.list(new QueryWrapper() - .select("id,title,image,read_num,start_time") + .select("id,title,image,read_num,start_time,modify_time") .eq("dept_id",visitStore) .eq("status",true) .orderByDesc("modify_time")); diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/HealthyController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/HealthyController.java index 6ec6cc3..add59da 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/HealthyController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/HealthyController.java @@ -38,7 +38,7 @@ public class HealthyController { public RestResponse getList(@RequestBody Map map){ Long visitStore=Long.parseLong(map.get("visitStore").toString()); List list= service.list(new QueryWrapper() - .select("id,title,image,read_num,start_time") + .select("id,title,image,read_num,start_time,modify_time") .eq("dept_id",visitStore) .eq("status",true) .orderByDesc("modify_time")); diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/InheritController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/InheritController.java index 4efc24c..165ed66 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/InheritController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/InheritController.java @@ -37,7 +37,7 @@ public class InheritController { public RestResponse getList(@RequestBody Map map){ Long visitStore=Long.parseLong(map.get("visitStore").toString()); List list= inheritService.list(new QueryWrapper() - .select("id,title,image,read_num,start_time") + .select("id,title,image,read_num,start_time,modify_time") .eq("dept_id",visitStore) .eq("status",true) .orderByDesc("modify_time")); diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/MyController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/MyController.java index 428cade..159fc95 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/MyController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/MyController.java @@ -140,7 +140,7 @@ public class MyController extends BaseController { */ @PostMapping("/confirmClass") public RestResponse confirmClass(@RequestBody Map map){ - Long courseTimeId=(Long)map.get("courseTimeId"); + Long courseTimeId=Long.parseLong(map.get("courseTimeId").toString()); String startTime=map.get("startTime").toString();//HH:mm:ss String endTime=map.get("endTime").toString();//HH:mm:ss if (StrUtil.hasEmpty(startTime,endTime)){ diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/PracticeMomentsController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/PracticeMomentsController.java index 9f1da6d..b45521e 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/PracticeMomentsController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/PracticeMomentsController.java @@ -38,7 +38,7 @@ public class PracticeMomentsController { public RestResponse getList(@RequestBody Map map){ Long visitStore=Long.parseLong(map.get("visitStore").toString()); List list=momentsService.list(new QueryWrapper() - .select("id,title,image,read_num,start_time") + .select("id,title,image,read_num,start_time,modify_time") .eq("dept_id",visitStore) .eq("status",true) .orderByDesc("modify_time")); diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/SenseController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/SenseController.java index b53d167..01b300e 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/SenseController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/basic/SenseController.java @@ -36,7 +36,7 @@ public class SenseController { public RestResponse getList(@RequestBody Map map){ Long visitStore=Long.parseLong(map.get("visitStore").toString()); List list= service.list(new QueryWrapper() - .select("id,title,image,read_num,start_time") + .select("id,title,image,read_num,start_time,modify_time") .eq("dept_id",visitStore) .eq("status",true) .orderByDesc("modify_time")); diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/course/CourseController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/course/CourseController.java index d7a8a8f..60c547a 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/course/CourseController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/course/CourseController.java @@ -92,7 +92,7 @@ public class CourseController extends BaseController { */ @PostMapping("/cancelCourse") public RestResponse cancelCourse(@RequestBody Map map){ - Long courseTimeId =(Long)map.get("courseTimeId"); + Long courseTimeId =Long.parseLong(map.get("courseTimeId").toString()); return scClaTimeService.cancelCourse(courseTimeId); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FriendController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FriendController.java index 84d2549..8996f87 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FriendController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/FriendController.java @@ -6,6 +6,7 @@ import com.ruoyi.common.annotation.RepeatSubmit; import com.ruoyi.common.core.domain.entity.AppUser; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.im.domain.vo.FriendVO; +import com.ruoyi.im.domain.vo.OnlineTerminalVO; import com.ruoyi.im.domain.vo.UserVO; import com.ruoyi.im.service.FriendService; import com.ruoyi.web.controller.im.result.Result; @@ -53,12 +54,13 @@ public class FriendController { @GetMapping("/find/{friendId}") @Operation(summary = "查找好友信息", description = "查找好友信息") - public Result findFriend(@NotNull(message = "好友id不可为空") @PathVariable Long friendId) { + public Result findFriend(@NotNull(message = "好友id不可为空") @PathVariable String friendId) { Long userId= SecurityUtils.getAppLoginUser().getAppUser().getId(); - if (friendId.equals(userId)) { + Long fId=Long.valueOf(friendId); + if (fId.equals(userId)) { return null; } - return ResultUtils.success(friendService.findFriend(userId,friendId)); + return ResultUtils.success(friendService.findFriend(userId,fId)); } @@ -68,5 +70,9 @@ public class FriendController { friendService.delFriend(friendId); return ResultUtils.success(); } - + @GetMapping("/terminal/online") + @Operation(summary = "判断用户哪个终端在线", description = "返回在线的用户id的终端集合") + public Result> getOnlineTerminal(@NotNull @RequestParam("userIds") String userIds) { + return ResultUtils.success(friendService.getOnlineTerminals(userIds)); + } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupController.java index cc45975..26c2e76 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupController.java @@ -1,6 +1,7 @@ package com.ruoyi.web.controller.im; import com.ruoyi.common.annotation.RepeatSubmit; +import com.ruoyi.im.domain.vo.GroupMemberVO; import com.ruoyi.im.domain.vo.GroupVO; import com.ruoyi.im.service.GroupService; import com.ruoyi.web.controller.im.result.Result; @@ -42,6 +43,11 @@ public class GroupController { return ResultUtils.success(groupService.findGroups()); } - + @Operation(summary = "查询群聊成员", description = "查询群聊成员") + @GetMapping("/members/{groupId}") + public Result> findGroupMembers( + @NotNull(message = "群聊id不能为空") @PathVariable Long groupId) { + return ResultUtils.success(groupService.findGroupMembers(groupId)); + } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupMessageController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupMessageController.java index bb28ee3..bb4c255 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupMessageController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/GroupMessageController.java @@ -31,21 +31,21 @@ public class GroupMessageController { @GetMapping("/maxReadedId") @Operation(summary = "获取最大已读消息的id", description = "获取某个会话中已读消息的最大id") - public Result getMaxReadedId(@RequestParam Long groupId) { - return ResultUtils.success(groupMessageService.getMaxReadedId(groupId),"成功"); + public Result getMaxReadedId(@RequestParam String groupId) { + return ResultUtils.success(groupMessageService.getMaxReadedId(Long.parseLong(groupId.toString())),"成功"); } @GetMapping("/pullOfflineMessage") @Operation(summary = "拉取离线消息", description = "拉取离线消息,消息将通过webscoket异步推送") - public Result pullOfflineMessage(@RequestParam Long minId) { - groupMessageService.pullOfflineMessage(minId); + public Result pullOfflineMessage(@RequestParam String minId) { + groupMessageService.pullOfflineMessage(Long.parseLong(minId.toString())); return ResultUtils.success(); } @PutMapping("/readed") @Operation(summary = "消息已读", description = "将群聊中的消息状态置为已读") - public Result readedMessage(@RequestParam Long groupId) { - groupMessageService.readedMessage(groupId); + public Result readedMessage(@RequestParam String groupId) { + groupMessageService.readedMessage(Long.parseLong(groupId.toString())); return ResultUtils.success(); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/PrivateMessageController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/PrivateMessageController.java index d9fdb9b..62b7291 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/PrivateMessageController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/im/PrivateMessageController.java @@ -55,23 +55,23 @@ public class PrivateMessageController { */ @GetMapping("/pullOfflineMessage") @Operation(summary = "拉取离线消息", description = "拉取离线消息,消息将通过webscoket异步推送") - public Result pullOfflineMessage(@RequestParam Long minId) { - privateMessageService.pullOfflineMessage(minId); + public Result pullOfflineMessage(@RequestParam String minId) { + privateMessageService.pullOfflineMessage(Long.parseLong(minId.toString())); return ResultUtils.success(); } @PutMapping("/readed") @Operation(summary = "消息已读", description = "将会话中接收的消息状态置为已读") - public Result readedMessage(@RequestParam Long friendId) { - privateMessageService.readedMessage(friendId); + public Result readedMessage(@RequestParam String friendId) { + privateMessageService.readedMessage(Long.parseLong(friendId.toString())); return ResultUtils.success(); } @GetMapping("/maxReadedId") @Operation(summary = "获取最大已读消息的id", description = "获取某个会话中已读消息的最大id") - public Result getMaxReadedId(@RequestParam Long friendId) { - return ResultUtils.success(privateMessageService.getMaxReadedId(friendId)); + public Result getMaxReadedId(@RequestParam String friendId) { + return ResultUtils.success(privateMessageService.getMaxReadedId(Long.parseLong(friendId.toString()))); } // @GetMapping("/history") diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/AppLoginController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/AppLoginController.java index 21ba4d1..b746354 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/AppLoginController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/AppLoginController.java @@ -1,6 +1,8 @@ package com.ruoyi.web.controller.login; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.im.util.BeanUtils; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -12,6 +14,7 @@ import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.AppUser; import com.ruoyi.common.core.domain.model.AppLoginUser; import com.ruoyi.common.core.domain.model.AppUserLoginBody; +import com.ruoyi.common.utils.JpushClientUtil; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.framework.web.service.AppLoginService; import com.ruoyi.basic.domain.YjStore; @@ -65,6 +68,7 @@ public class AppLoginController { } AppUser appUser=new AppUser(); appUser.setPhoneNumber(loginBody.getPhonenumber()); + appUser.setNickName(loginBody.getPhonenumber()); appUser.setPassword(SecurityUtils.encryptPassword(loginBody.getPassword())); appUser.setStatus(1); appUserService.save(appUser); @@ -83,6 +87,17 @@ public class AppLoginController { AjaxResult ajax = AjaxResult.success(); String token=appLoginService.login(loginBody.getPhonenumber(),loginBody.getPassword(),loginBody.getCode(),loginBody.getUuid(),loginBody.getRegisterId(),loginBody.getMiniAppCode()); ajax.put(Constants.TOKEN, token); + + // 保存设备id绑定别名,便于推送消息 + if (StrUtil.isNotEmpty(loginBody.getRegisterId())){ + appUserService.update(new UpdateWrapper().eq("phone_number",loginBody.getPhonenumber()) + .set("register_id",loginBody.getRegisterId()) + .set(StrUtil.isNotEmpty(loginBody.getLoginSysPlatform()),"login_sys_platform",loginBody.getLoginSysPlatform()) + ); + // 极光推送注册设备id绑定别名,便于推送消息 + JpushClientUtil.bindAlias(loginBody.getRegisterId(),loginBody.getPhonenumber()); + } + return ajax; } @@ -103,7 +118,8 @@ public class AppLoginController { appUser.setPhonenumber(user.getAppUser().getPhoneNumber()); // 角色集合 appUser.setRoleId(user.getRoles()); - //管理人员(教练、店长、顾问)默认访问门店 + //管理人员(教练、店长、顾问)默认访问门店. + // if (ObjectUtil.isNotEmpty(user.getManageAccountId())&&ObjectUtil.isNotEmpty(appUser.getVisitStore())){ // Long deptId= userService.selectUserById(user.getManageAccountId()).getDeptId(); // appUser.setVisitStore(deptId); diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/CaptchaController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/CaptchaController.java index b003898..f92b63c 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/CaptchaController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/login/CaptchaController.java @@ -8,6 +8,7 @@ import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.redis.RedisCache; +import com.ruoyi.common.utils.JpushClientUtil; import com.ruoyi.common.utils.sign.Base64; import com.ruoyi.common.utils.uuid.IdUtils; import com.ruoyi.system.service.ISysConfigService; @@ -20,8 +21,7 @@ import javax.annotation.Resource; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import java.util.concurrent.TimeUnit; /** @@ -92,11 +92,31 @@ public class CaptchaController { return AjaxResult.error(e.getMessage()); } - + testBindAlias(); ajax.put("uuid", uuid); ajax.put("img", Base64.encode(os.toByteArray())); return ajax; } + public void testBindAlias() { + + +// JpushClientUtil.bindAlias("reg_123", "user_888"); +// JpushClientUtil.pushToAll("瑜伽汇","这是java广播消息",null); +// JpushClientUtil.pushByRegistrationId(Arrays.asList("170976fa8bac0ade1e0"),"瑜伽汇","这是RegistrationId广播消息",null); +// JpushClientUtil.bindAlias("160a3797c9280401a82","15004070936"); +// JpushClientUtil.pushToUser("15004070936","瑜伽汇","这是Alias消息",null); +// JpushClientUtil.pushToUsers(Arrays.asList("15004070936","mumu"),"瑜伽汇","瑜伽汇群组推送",null); + +// String msg = String.format( +// "%s:%s", +// "普拉提", "课程预约成功!" +// ); +// Map extras=new HashMap<>(); +// extras.put("type","bookCourses");//type推送类型:bookCourses 预约课程 groupMessage群聊消息 privateMessage私信消息 +// extras.put("pagePath","/pages/book/book");//pagePath跳转页面 +// extras.put("bookId","123456789");//bookId预约id +// JpushClientUtil.pushByRegistrationId(Arrays.asList("160a3797c9280401a82"),"瑜伽汇",msg,extras); + } } diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 193ea05..6ab1d8d 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -146,3 +146,4 @@ xss: wechat: token: runpeng + diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index fe0a1c8..f382f65 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -159,16 +159,15 @@ - cn.jpush.api - jiguang-common - 1.1.7 + io.github.jpush + jiguang-sdk + 5.3.0 - cn.jpush.api - jpush-client - 3.4.3 + com.google.code.gson + gson + 2.8.9 - io.springfox diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/AppUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/AppUser.java index 8869588..097b6f0 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/AppUser.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/AppUser.java @@ -94,7 +94,12 @@ public class AppUser{ @TableField(exist = false) private String newPassword; - + //安卓:android; + //iOS:ios ; + //鸿蒙:harmonyos ; + //微信小程序:weixin; + @TableField("login_sys_platform") + private String loginSysPlatform; diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/AppUserLoginBody.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/AppUserLoginBody.java index 7f164b2..0abe9a8 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/AppUserLoginBody.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/AppUserLoginBody.java @@ -1,5 +1,6 @@ package com.ruoyi.common.core.domain.model; +import com.baomidou.mybatisplus.annotation.TableField; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -66,4 +67,8 @@ public class AppUserLoginBody */ private String visitStoreId; + private String loginSysPlatform; + + + } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/db/SshContextListener.java b/ruoyi-common/src/main/java/com/ruoyi/common/db/SshContextListener.java index 860d1e1..a71c384 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/db/SshContextListener.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/db/SshContextListener.java @@ -7,8 +7,8 @@ import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; -@Component//尽量加上这个 -@WebListener//声明为监听器 implements ServletContextListener +//@Component//尽量加上这个 +//@WebListener//声明为监听器 implements ServletContextListener public class SshContextListener implements ServletContextListener{ private SshTunnelConfig sshConnectionConfig; diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMPrivateMessage.java b/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMPrivateMessage.java index 9800e46..fa32745 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMPrivateMessage.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMPrivateMessage.java @@ -1,6 +1,8 @@ package com.ruoyi.common.im.model; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.ruoyi.common.im.enums.IMTerminalType; import lombok.Data; @@ -17,6 +19,7 @@ public class IMPrivateMessage { /** * 接收者id */ + @JsonSerialize(using = ToStringSerializer.class) private Long recvId; diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMUserInfo.java b/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMUserInfo.java index a999afc..3079369 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMUserInfo.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/im/model/IMUserInfo.java @@ -1,14 +1,11 @@ package com.ruoyi.common.im.model; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -/** - * @author: Blue - * @date: 2023-09-24 09:23:11 - * @version: 1.0 - */ @Data @NoArgsConstructor @AllArgsConstructor @@ -17,6 +14,7 @@ public class IMUserInfo { /** * 用户id */ + @JsonSerialize(using = ToStringSerializer.class) private Long id; /** diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/JpushClientUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/JpushClientUtil.java index 9e3d355..d0a83db 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/JpushClientUtil.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/JpushClientUtil.java @@ -1,592 +1,294 @@ package com.ruoyi.common.utils; -import cn.jiguang.common.resp.APIConnectionException; -import cn.jiguang.common.resp.APIRequestException; -import cn.jiguang.common.resp.BooleanResult; -import cn.jiguang.common.resp.DefaultResult; -import cn.jpush.api.JPushClient; -import cn.jpush.api.device.TagAliasResult; -import cn.jpush.api.push.PushResult; -import cn.jpush.api.push.model.Message; -import cn.jpush.api.push.model.Options; -import cn.jpush.api.push.model.Platform; -import cn.jpush.api.push.model.PushPayload; -import cn.jpush.api.push.model.audience.Audience; -import cn.jpush.api.push.model.notification.AndroidNotification; -import cn.jpush.api.push.model.notification.IosNotification; -import cn.jpush.api.push.model.notification.Notification; -import cn.jpush.api.schedule.ScheduleResult; +import cn.hutool.core.bean.BeanUtil; +import cn.jiguang.sdk.api.DeviceApi; +import cn.jiguang.sdk.api.PushApi; +import cn.jiguang.sdk.bean.push.PushSendParam; +import cn.jiguang.sdk.bean.push.PushSendParam; +import cn.jiguang.sdk.bean.push.PushSendResult; +import cn.jiguang.sdk.exception.ApiErrorException; +import com.google.gson.Gson; +import okhttp3.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.List; +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.util.*; /** - * 极光推送工具类 + * 极光推送工具类 (适配 SDK 5.3.0) + * 用于 IM 系统的离线消息推送 */ +@Component public class JpushClientUtil { - private static Logger logger = LoggerFactory.getLogger(JpushClientUtil.class); + + private static final Logger log = LoggerFactory.getLogger(JpushClientUtil.class); + private static final Gson gson = new Gson(); + private static final String DEVICE_API_URL = "https://device.jpush.cn/v3/devices/"; + private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8"); + + // 静态变量,由 Spring 初始化 + private static String appKey; + private static String masterSecret; + private static boolean apnsProduction; + private static PushApi pushApi; + + private static OkHttpClient httpClient; + + // 注入的属性 +// @Value("${jpush.appKey}") +// private String injectedAppKey; +// +// @Value("${jpush.masterSecret}") +// private String injectedMasterSecret; +// private final static String injectedAppKey = "e75debc0daaed0a2a888d2f3"; +// private final static String injectedMasterSecret = "e8728877c098e641cc6c51e5"; + private final static String injectedAppKey = "d5edb270e4b1cc29616e1dd5"; + private final static String injectedMasterSecret = "a49a9fd3df40747fb6e0d180"; + +// private final static String customAction = "com.test.java.sdk."; +// private final static String targetPackage = "com.test.java.sdk"; +// private final static String targetActivity = "Activity 组件路径;"; +// private final static String extrasParam = "S.key1=value;i.key2=3;"; +// @Value("${jpush.apnsProduction:true}") + private final static boolean injectedApnsProduction = true; + + + @PostConstruct + public void init() { + // 将注入的值赋给静态变量 + appKey = injectedAppKey; + masterSecret = injectedMasterSecret; + apnsProduction = injectedApnsProduction; + + // 初始化 PushApi + pushApi = new PushApi.Builder() + .setAppKey(appKey) + .setMasterSecret(masterSecret) + .build(); + + // 初始化 OkHttpClient + httpClient = new OkHttpClient.Builder() + .connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS) + .readTimeout(10, java.util.concurrent.TimeUnit.SECONDS) + .writeTimeout(10, java.util.concurrent.TimeUnit.SECONDS) + .build(); + + log.info("极光推送工具类初始化完成"); + } + +// ==================== 别名绑定方法 ==================== + /** - * 设置好账号的app_key和masterSecret是必须的 + * 服务端直接绑定别名,将 registrationId 与 alias 关联。 + * 调用时机:用户登录成功后,客户端上报 registrationId 即可调用。 + * + * @param registrationId 客户端上报的设备唯一标识 + * @param alias 别名,如用户ID或手机号 */ - private final static String APPKER = "c2e673cd0e77c762ffe1a857"; - private final static String MASTERSECRET = "34aace4d60d847468ab96097"; + public static void bindAlias(String registrationId, String alias) { + if (registrationId == null || registrationId.isEmpty() || alias == null || alias.isEmpty()) { + log.warn("绑定别名失败: registrationId 或 alias 为空"); + return; + } + + // 构建请求体 + Map bodyMap = new HashMap<>(); + bodyMap.put("alias", alias); + String jsonBody = gson.toJson(bodyMap); + + // Basic 认证 + String auth = Base64.getEncoder().encodeToString((appKey + ":" + masterSecret).getBytes()); + + RequestBody requestBody = RequestBody.create(JSON_MEDIA_TYPE,jsonBody); + Request request = new Request.Builder() + .url(DEVICE_API_URL + registrationId) + .addHeader("Authorization", "Basic " + auth) + .post(requestBody) + .build(); + + try (Response response = httpClient.newCall(request).execute()) { + if (response.isSuccessful()) { + log.info("别名绑定成功 | registrationId: {}, alias: {}", registrationId, alias); + } else { + // 极光 API 有时返回 404 但仍视为成功 + String respBody = response.body() != null ? response.body().string() : ""; + log.warn("别名绑定响应非成功,可能已成功 | registrationId: {}, alias: {}, code: {}, body: {}", + registrationId, alias, response.code(), respBody); + } + } catch (IOException e) { + log.error("别名绑定请求异常 | registrationId: {}, alias: {}, error: {}", + registrationId, alias, e.getMessage(), e); + } + } + + + // ==================== 单聊推送:按别名 ==================== + + /** - * ApnsProduction - * 此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义 - * 上线之后要改为 true + * 推送到单个用户 (别名,即 userId) + * @param alias 用户别名 + * @param title 通知标题 + * @param content 通知内容 + * @param extras 额外参数 (如会话类型、消息类型等) */ - private final static Boolean ApnsProduction = false; - - private static JPushClient jPushClient = new JPushClient(MASTERSECRET,APPKER); - - private JpushClientUtil() { + public static void pushToUser(String alias, String title, String content, Map extras) { + PushSendParam param = buildPushParamWithAlias(alias, title, content, extras); + sendPush(param, "user", alias); + } - throw new AssertionError("不能产生该对象"); + // ==================== 群聊推送:按别名批量 ==================== + + /** + * 推送到多个用户 (别名批量,适合群聊离线推送) + * @param aliases 用户别名集合 + * @param title 通知标题 + * @param content 通知内容 + * @param extras 额外参数 + */ + public static void pushToUsers(List aliases, String title, String content, Map extras) { + if (aliases == null || aliases.isEmpty()) return; + PushSendParam param = buildPushParamWithAliases(aliases, title, content, extras); + sendPush(param, "group-users", aliases.size() + " users"); } - /** - * 绑定电话 - */ - public static void testBindMobile() { - try { - DefaultResult result = jPushClient.bindMobile("100d855909a0c6d0655", "15004070936"); - System.out.println("Got result " + result); - } catch (APIConnectionException e) { - logger.error("Connection error. Should retry later. ", e); - } catch (APIRequestException e) { - logger.error("Error response from JPush server. Should review and fix it. ", e); - logger.info("HTTP Status: " + e.getStatus()); - logger.info("Error Code: " + e.getErrorCode()); - logger.info("Error Message: " + e.getErrorMessage()); - } - } - /** - * - * @param - * @return - *生成别名 - */ - public static boolean bindAlias(String registerId,String phoneNumber) { - try { - DefaultResult defaultResult = jPushClient.updateDeviceTagAlias(registerId, phoneNumber, null, - null); - logger.info("Got result"+defaultResult); - } catch (APIConnectionException e) { - logger.error("Connection error. Should retry later. ", e); - e.printStackTrace(); - } catch (APIRequestException e) { - logger.error("Error response from JPush server. Should review and fix it. ", e); - e.printStackTrace(); - }finally { - jPushClient.close(); - } - return false; - } - - public static BooleanResult hasMobile() { - BooleanResult deviceInTag = null; - try { - deviceInTag = jPushClient.isDeviceInTag( - String.valueOf(jPushClient.getDeviceTagAlias("100d855909a0c6d0655").alias), "100d855909a0c6d0655"); - logger.info("Got result" + deviceInTag); - return deviceInTag ; - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIRequestException e) { - e.printStackTrace(); - }finally { - jPushClient.close(); - } - return deviceInTag ; - } - - public static void testGetDeviceTagAlias() { - try { - TagAliasResult result = jPushClient.getDeviceTagAlias("100d855909a0c6d0655"); - - logger.info(result.alias); - logger.info(result.tags.toString()); - - } catch (APIConnectionException e) { - logger.error("Connection error. Should retry later. ", e); - - } catch (APIRequestException e) { - logger.error("Error response from JPush server. Should review and fix it. ", e); - logger.info("HTTP Status: " + e.getStatus()); - logger.info("Error Code: " + e.getErrorCode()); - logger.info("Error Message: " + e.getErrorMessage()); - } - } + // ==================== 全量推送 (谨慎使用) ==================== /** - * 推送给设备标识(别名)参数的用户 - * @param alias 设备标识(别名) - * @param notification_title 通知内容标题 - * @param msg_title 消息内容标题 - * @param msg_content 消息内容 - * @param extrasparam 扩展字段(通常传跳转的链接) - * @return 0推送失败,1推送成功 + * 推送给所有设备 */ - public static int sendToAlias( List alias,String notification_title, String msg_title, - String msg_content, String extrasparam) { - JPushClient jPushClient = new JPushClient(MASTERSECRET,APPKER); - int result = 0; - try { - PushPayload pushPayload= JpushClientUtil.buildPushObject_all_alias_alertWithTitle( - alias,notification_title,msg_title,msg_content,extrasparam); - PushResult pushResult = jPushClient.sendPush(pushPayload); - if(pushResult.getResponseCode()==200){ - result = 1; - } - logger.info("[极光推送]PushResult result is " + pushResult); - } catch (APIConnectionException e) { - logger.error("[极光推送]Connection error. Should retry later. ", e); - } catch (APIRequestException e) { - logger.error("[极光推送]Error response from JPush server. Should review and fix it. ", e); - logger.info("[极光推送]HTTP Status: " + e.getStatus()); - logger.info("[极光推送]Error Code: " + e.getErrorCode()); - logger.info("[极光推送]Error Message: " + e.getErrorMessage()); - } - return result; + public static void pushToAll(String title, String content, Map extras) { + PushSendParam param = buildPushParamWithAll(title, content, extras); + sendPush(param, "all", null); } - + // ==================== 根据 Registration ID 推送 (备用) ==================== + /** - * 推送给设备标识(别名)参数的用户(定时) - * @param alias 设备标识(别名) - * @param notification_title 通知内容标题 - * @param msg_title 消息内容标题 - * @param msg_content 消息内容 - * @param extrasparam 扩展字段 - * @param time 格式:yyyy-MM-dd HH:mm:ss - * @return 0推送失败,1推送成功 + * 按 Registration ID 推送 (适用于未绑定别名的场景) */ - public static int sendToAlias2( List alias,String notification_title, String msg_title, String msg_content, String extrasparam, String time) { - JPushClient jPushClient = new JPushClient(MASTERSECRET,APPKER); - int result = 0; - try { - PushPayload pushPayload= JpushClientUtil.buildPushObject_all_alias_alertWithTitle(alias,notification_title,msg_title,msg_content,extrasparam); - ScheduleResult scheduleResult=jPushClient.createSingleSchedule("点呗生活", time, pushPayload); - if(scheduleResult.getResponseCode()==200){ - result=1; - } - logger.info("[极光推送]ScheduleResult result is " + scheduleResult); - } catch (APIConnectionException e) { - logger.error("[极光推送]Connection error. Should retry later. ", e); - } catch (APIRequestException e) { - logger.error("[极光推送]Error response from JPush server. Should review and fix it. ", e); - logger.info("[极光推送]HTTP Status: " + e.getStatus()); - logger.info("[极光推送]Error Code: " + e.getErrorCode()); - logger.info("[极光推送]Error Message: " + e.getErrorMessage()); - } - return result; + public static void pushByRegistrationId(List regId, String title, String content, Map extras) { + PushSendParam param = buildPushParamWithRegistrationId(regId, title, content, extras); + sendPush(param, "regId", regId.size()+ " users"); } - + + // ==================== 内部构建方法 (核心适配) ==================== + /** - * 推送给设备RegistrationIds参数的用户 - * @param registrationIdList 设备注册ID - * @param notification_title 通知内容标题 - * @param msg_title 消息内容标题 - * @param msg_content 消息内容 - * @param extrasparam 扩展字段 - * @return 0推送失败,1推送成功 + * 构建单个别名的推送参数 */ - public static int sendToRegistrationIds( List registrationIdList,String notification_title, String msg_title, String msg_content, String extrasparam) { - JPushClient jPushClient = new JPushClient(MASTERSECRET,APPKER); - int result = 0; - try { - PushPayload pushPayload= JpushClientUtil.buildPushObject_all_registrationIds_alertWithTitle(registrationIdList,notification_title,msg_title,msg_content,extrasparam); - PushResult pushResult=jPushClient.sendPush(pushPayload); - if(pushResult.getResponseCode()==200){ - result=1; - } - logger.info("[极光推送]PushResult result is " + pushResult); - } catch (APIConnectionException e) { - logger.error("[极光推送]Connection error. Should retry later. ", e); - } catch (APIRequestException e) { - logger.error("[极光推送]Error response from JPush server. Should review and fix it. ", e); - logger.info("[极光推送]HTTP Status: " + e.getStatus()); - logger.info("[极光推送]Error Code: " + e.getErrorCode()); - logger.info("[极光推送]Error Message: " + e.getErrorMessage()); - } - return result; + private static PushSendParam buildPushParamWithAlias(String alias, String title, String content, Map extras) { + Map pushBody = buildCommonPushBody(title, content, extras); + Map map= new HashMap<>(); + map.put("alias", Arrays.asList(alias)); + pushBody.put("audience", map); + PushSendParam param = BeanUtil.toBean(pushBody, PushSendParam.class); + return param; } -// public static void main(String[] agrs){ -// -// List strings=new ArrayList<>(); -// strings.add("13065ffa4ee0d41a70c"); -// String notification_title="通知内容标题";//通知内容标题 -// String msg_title="消息内容标题";//消息内容标题 -// String msg_content="消息内容";//消息内容 -// String extrasparam="扩展字段";//扩展字段 -// int i=sendToRegistrationIds(strings,notification_title,msg_title,msg_content,extrasparam); -// System.out.println(i==0?"0推送失败":"1推送成功"); -// } + /** + * 构建多个别名的推送参数 + */ + private static PushSendParam buildPushParamWithAliases(List aliases, String title, String content, Map extras) { + Map pushBody = buildCommonPushBody(title, content, extras); + Map map= new HashMap<>(); + map.put("alias", aliases); + pushBody.put("audience", map); + return BeanUtil.toBean(pushBody, PushSendParam.class); + } /** - * 发送给所有安卓用户 - * @param notification_title 通知内容标题 - * @param msg_title 消息内容标题 - * @param msg_content 消息内容 - * @param extrasparam 扩展字段 - * @return 0推送失败,1推送成功 + * 构建全量推送的参数 */ - public static int sendToAllAndroid( String notification_title, String msg_title, String msg_content, String extrasparam) { - int result = 0; - try { - PushPayload pushPayload= JpushClientUtil.buildPushObject_android_all_alertWithTitle(notification_title,msg_title,msg_content,extrasparam); - PushResult pushResult=jPushClient.sendPush(pushPayload); - if(pushResult.getResponseCode()==200){ - result=1; - } - logger.info("[极光推送]PushResult result is " + pushResult); - } catch (APIConnectionException e) { - logger.error("[极光推送]Connection error. Should retry later. ", e); - } catch (APIRequestException e) { - logger.error("[极光推送]Error response from JPush server. Should review and fix it. ", e); - logger.info("[极光推送]HTTP Status: " + e.getStatus()); - logger.info("[极光推送]Error Code: " + e.getErrorCode()); - logger.info("[极光推送]Error Message: " + e.getErrorMessage()); - } - return result; + private static PushSendParam buildPushParamWithAll(String title, String content, Map extras) { + Map pushBody = buildCommonPushBody(title, content, extras); + pushBody.put("audience", "all"); + return BeanUtil.toBean(pushBody, PushSendParam.class); } - + /** - * 发送给所有IOS用户 - * @param notification_title 通知内容标题 - * @param msg_title 消息内容标题 - * @param msg_content 消息内容 - * @param extrasparam 扩展字段 - * @return 0推送失败,1推送成功 + * 构建 Registration ID 推送的参数 */ - public static int sendToAllIos(String notification_title, String msg_title, String msg_content, String extrasparam) { - int result = 0; - try { - PushPayload pushPayload= JpushClientUtil.buildPushObject_ios_all_alertWithTitle(notification_title,msg_title,msg_content,extrasparam); - PushResult pushResult=jPushClient.sendPush(pushPayload); - if(pushResult.getResponseCode()==200){ - result=1; - } - logger.info("[极光推送]PushResult result is " + pushResult); - } catch (APIConnectionException e) { - logger.error("[极光推送]Connection error. Should retry later. ", e); - } catch (APIRequestException e) { - logger.error("[极光推送]Error response from JPush server. Should review and fix it. ", e); - logger.info("[极光推送]HTTP Status: " + e.getStatus()); - logger.info("[极光推送]Error Code: " + e.getErrorCode()); - logger.info("[极光推送]Error Message: " + e.getErrorMessage()); - } - return result; + private static PushSendParam buildPushParamWithRegistrationId(List regId, String title, String content, Map extras) { + Map pushBody = buildCommonPushBody(title, content, extras); + Map map= new HashMap<>(); + map.put("registration_id", regId); + pushBody.put("audience", map); + return BeanUtil.toBean(pushBody, PushSendParam.class); } - + + /** - * 发送给所有用户 - * @param notification_title 通知内容标题 - * @param msg_title 消息内容标题 - * @param msg_content 消息内容 - * @param extrasparam 扩展字段 - * @return 0推送失败,1推送成功 + * 构建通用的推送 body (包含通知和公共参数) */ - public static int sendToAll( String notification_title, String msg_title, String msg_content, String extrasparam) { - int result = 0; - try { - PushPayload pushPayload= JpushClientUtil.buildPushObject_android_and_ios(notification_title,msg_title,msg_content,extrasparam); - PushResult pushResult=jPushClient.sendPush(pushPayload); - if(pushResult.getResponseCode()==200){ - result=1; - } - logger.info("[极光推送]PushResult result is " + pushResult); - } catch (APIConnectionException e) { - logger.error("[极光推送]Connection error. Should retry later. ", e); - } catch (APIRequestException e) { - logger.error("[极光推送]Error response from JPush server. Should review and fix it. ", e); - logger.info("[极光推送]HTTP Status: " + e.getStatus()); - logger.info("[极光推送]Error Code: " + e.getErrorCode()); - logger.info("[极光推送]Error Message: " + e.getErrorMessage()); + private static Map buildCommonPushBody(String title, String content, Map extras) { + Map pushBody = new HashMap<>(); + pushBody.put("platform", "all"); // 全平台 + + // 构建通知体 + Map notification = new HashMap<>(); + notification.put("alert", content); + + // Android 通知 + Map android = new HashMap<>(); + android.put("alert", content); + android.put("title", title); +// //点击消息跳转至 +// Map intent= new HashMap<>(); +// String intentUrl = String.format( +// "intent:#Intent;action=%s;component=%s/%s;S.userId=%s;end", +// customAction, targetPackage, targetActivity, extrasParam +// ); +// intent.put("url",intentUrl); +// android.put("intent",intent); + if (extras != null) { + android.put("extras", extras); } - return result; + notification.put("android", android); + + // iOS 通知 + Map ios = new HashMap<>(); + ios.put("alert", title); + ios.put("sound", "default"); + ios.put("badge", "+1"); + if (extras != null) { + ios.put("extras", extras); + } + notification.put("ios", ios); + + pushBody.put("notification", notification); + + // 选项 + Map options = new HashMap<>(); + options.put("time_to_live", 86400); + options.put("apns_production", apnsProduction); + pushBody.put("options", options); + + return pushBody; } - + /** - * 发送给所有用户(定时推送) - * @param notification_title 通知内容标题 - * @param msg_title 消息内容标题 - * @param msg_content 消息内容 - * @param extrasparam 扩展字段 - * @param time 格式:yyyy-MM-dd HH:mm:ss - * @return 0推送失败,1推送成功 + * 统一发送和异常处理 */ - public static int sendToAll2( String notification_title, String msg_title, String msg_content, String extrasparam, String time) { - int result = 0; + private static void sendPush(PushSendParam param, String type, String target) { try { - PushPayload pushPayload= JpushClientUtil.buildPushObject_android_and_ios(notification_title,msg_title,msg_content,extrasparam); - ScheduleResult scheduleResult=jPushClient.createSingleSchedule("测试", time, pushPayload); - if(scheduleResult.getResponseCode()==200){ - result=1; - } - logger.info("[极光推送]scheduleResult result is " + scheduleResult); - } catch (APIConnectionException e) { - logger.error("[极光推送]Connection error. Should retry later. ", e); - } catch (APIRequestException e) { - logger.error("[极光推送]Error response from JPush server. Should review and fix it. ", e); - logger.info("[极光推送]HTTP Status: " + e.getStatus()); - logger.info("[极光推送]Error Code: " + e.getErrorCode()); - logger.info("[极光推送]Error Message: " + e.getErrorMessage()); + // 调用 PushApi 的 send 方法进行推送 + PushSendResult result = pushApi.send(param); + log.info("极光推送成功 | type: {} | target: {} | msgId: {}", type, target, result.getMessageId()); + } catch (ApiErrorException e) { + // 处理 API 错误,可获取错误码、HTTP状态码和限流信息 + int httpStatus = e.getStats(); + int errorCode = e.getApiError().getError().getCode(); + String errorMessage = e.getApiError().getError().getMessage(); + log.error("极光推送失败 | type: {} | target: {} | httpStatus: {} | errorCode: {} | error: {}", + type, target, httpStatus, errorCode, errorMessage, e); + // 此处可接入重试机制或报警 } - return result; - } - - - public static PushPayload buildPushObject_android_and_ios(String notification_title, String msg_title, String msg_content, String extrasparam) { - return PushPayload.newBuilder() - .setPlatform(Platform.android_ios()) - .setAudience(Audience.all()) - .setNotification(Notification.newBuilder() - .setAlert(msg_content) - .addPlatformNotification(AndroidNotification.newBuilder() - .setAlert(msg_content) - .setTitle(notification_title) - //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value) - .addExtra("url",extrasparam) - .build() - ) - .addPlatformNotification(IosNotification.newBuilder() - //传一个IosAlert对象,指定apns title、title、subtitle等 - .setAlert(msg_content) - //直接传alert - //此项是指定此推送的badge自动加1 - .incrBadge(1) - //此字段的值default表示系统默认声音;传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒, - // 如果系统没有此音频则以系统默认声音提醒;此字段如果传空字符串,iOS9及以上的系统是无声音提醒,以下的系统是默认声音 - .setSound("sound.caf") - //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value) - .addExtra("url",extrasparam) - //此项说明此推送是一个background推送,想了解background看:http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification - // .setContentAvailable(true) - .build() - ) - .build() - ) - //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息, - // sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的 - // [通知与自定义消息有什么区别?]了解通知和自定义消息的区别 - .setMessage(Message.newBuilder() - .setMsgContent(msg_content) - .setTitle(msg_title) - .addExtra("url",extrasparam) - .build()) - .setOptions(Options.newBuilder() - //此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义 - .setApnsProduction(ApnsProduction) - //此字段是给开发者自己给推送编号,方便推送者分辨推送记录 - .setSendno(1) - //此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天,单位为秒 - .setTimeToLive(86400) - .build() - ) - .build(); - } - - private static PushPayload buildPushObject_all_alias_alertWithTitle(List alias,String notification_title, String msg_title, String msg_content, String extrasparam) { - //创建一个IosAlert对象,可指定APNs的alert、title等字段 - //IosAlert iosAlert = IosAlert.newBuilder().setTitleAndBody("title", "alert body").build(); - return PushPayload.newBuilder() - //指定要推送的平台,all代表当前应用配置了的所有平台,也可以传android等具体平台 - .setPlatform(Platform.all()) - //指定推送的接收对象,all代表所有人,也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id - .setAudience(Audience.alias(alias)) - //.setAudience(Audience.registrationId(registrationId)) - //jpush的通知,android的由jpush直接下发,iOS的由apns服务器下发,Winphone的由mpns下发 - .setNotification(Notification.newBuilder() - //指定当前推送的android通知 - .addPlatformNotification(AndroidNotification.newBuilder() - .setAlert(msg_content) - .setTitle(notification_title) - //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value) - .addExtra("url",extrasparam) - .build()) - //指定当前推送的iOS通知 - .addPlatformNotification(IosNotification.newBuilder() - //传一个IosAlert对象,指定apns title、title、subtitle等 - .setAlert(msg_content) - //直接传alert - //此项是指定此推送的badge自动加1 - .incrBadge(1) - //此字段的值default表示系统默认声音;传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒, - // 如果系统没有此音频则以系统默认声音提醒;此字段如果传空字符串,iOS9及以上的系统是无声音提醒,以下的系统是默认声音 - .setSound("sound.caf") - //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value) - .addExtra("url",extrasparam) - //此项说明此推送是一个background推送,想了解background看:http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification - //取消此注释,消息推送时ios将无法在锁屏情况接收 - // .setContentAvailable(true) - .build()) - .build()) - //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息, - // sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的 - // [通知与自定义消息有什么区别?]了解通知和自定义消息的区别 - .setMessage(Message.newBuilder() - .setMsgContent(msg_content) - .setTitle(msg_title) - .addExtra("url",extrasparam) - .build()) - .setOptions(Options.newBuilder() - //此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义 - .setApnsProduction(ApnsProduction) - //此字段是给开发者自己给推送编号,方便推送者分辨推送记录 - .setSendno(1) - //此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天; - .setTimeToLive(86400) - .build()) - .build(); } - - private static PushPayload buildPushObject_all_registrationIds_alertWithTitle(List registrationIds,String notification_title, String msg_title, String msg_content, String extrasparam) { - //创建一个IosAlert对象,可指定APNs的alert、title等字段 - //IosAlert iosAlert = IosAlert.newBuilder().setTitleAndBody("title", "alert body").build(); - return PushPayload.newBuilder() - //指定要推送的平台,all代表当前应用配置了的所有平台,也可以传android等具体平台 - .setPlatform(Platform.all()) - //指定推送的接收对象,all代表所有人,也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id - .setAudience(Audience.registrationId(registrationIds)) - //jpush的通知,android的由jpush直接下发,iOS的由apns服务器下发,Winphone的由mpns下发 - .setNotification(Notification.newBuilder() - //指定当前推送的android通知 - .addPlatformNotification(AndroidNotification.newBuilder() - .setAlert(msg_content) - .setTitle(notification_title) - //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value) - .addExtra("url",extrasparam) - .build()) - //指定当前推送的iOS通知 - .addPlatformNotification(IosNotification.newBuilder() - //传一个IosAlert对象,指定apns title、title、subtitle等 - .setAlert(msg_content) - //直接传alert - //此项是指定此推送的badge自动加1 - .incrBadge(1) - //此字段的值default表示系统默认声音;传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒, - // 如果系统没有此音频则以系统默认声音提醒;此字段如果传空字符串,iOS9及以上的系统是无声音提醒,以下的系统是默认声音 - .setSound("sound.caf") - //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value) - .addExtra("url",extrasparam) - //此项说明此推送是一个background推送,想了解background看:http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification - //取消此注释,消息推送时ios将无法在锁屏情况接收 - // .setContentAvailable(true) - .build()) - .build()) - //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息, - // sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的 - // [通知与自定义消息有什么区别?]了解通知和自定义消息的区别 - .setMessage(Message.newBuilder() - .setMsgContent(msg_content) - .setTitle(msg_title) - .addExtra("url",extrasparam) - .build()) - .setOptions(Options.newBuilder() - //此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义 - .setApnsProduction(ApnsProduction) - //此字段是给开发者自己给推送编号,方便推送者分辨推送记录 - .setSendno(1) - //此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天; - .setTimeToLive(86400) - .build()) - .build(); - } - - private static PushPayload buildPushObject_android_all_alertWithTitle(String notification_title, String msg_title, String msg_content, String extrasparam) { - List rids=new ArrayList<>(); - return PushPayload.newBuilder() - //指定要推送的平台,all代表当前应用配置了的所有平台,也可以传android等具体平台 - .setPlatform(Platform.android()) - //指定推送的接收对象,all代表所有人,也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id - .setAudience(Audience.all()) - //jpush的通知,android的由jpush直接下发,iOS的由apns服务器下发,Winphone的由mpns下发 - .setNotification(Notification.newBuilder() - //指定当前推送的android通知 - .addPlatformNotification(AndroidNotification.newBuilder() - .setAlert(msg_content) - .setTitle(notification_title) - //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value) - .addExtra("url",extrasparam) - .build()) - .build() - ) - //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息, - // sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的 - // [通知与自定义消息有什么区别?]了解通知和自定义消息的区别 - .setMessage(Message.newBuilder() - .setMsgContent(msg_content) - .setTitle(msg_title) - .addExtra("url",extrasparam) - .build()) - .setOptions(Options.newBuilder() - //此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义 - .setApnsProduction(ApnsProduction) - //此字段是给开发者自己给推送编号,方便推送者分辨推送记录 - .setSendno(1) - //此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天,单位为秒 - .setTimeToLive(86400) - .build()) - .build(); - } - - private static PushPayload buildPushObject_ios_all_alertWithTitle( String notification_title, String msg_title, String msg_content, String extrasparam) { - return PushPayload.newBuilder() - //指定要推送的平台,all代表当前应用配置了的所有平台,也可以传android等具体平台 - .setPlatform(Platform.ios()) - //指定推送的接收对象,all代表所有人,也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id - .setAudience(Audience.all()) - //jpush的通知,android的由jpush直接下发,iOS的由apns服务器下发,Winphone的由mpns下发 - .setNotification(Notification.newBuilder() - //指定当前推送的android通知 - .addPlatformNotification(IosNotification.newBuilder() - //传一个IosAlert对象,指定apns title、title、subtitle等 - .setAlert(msg_content) - //直接传alert - //此项是指定此推送的badge自动加1 - .incrBadge(1) - //此字段的值default表示系统默认声音;传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒, - // 如果系统没有此音频则以系统默认声音提醒;此字段如果传空字符串,iOS9及以上的系统是无声音提醒,以下的系统是默认声音 - .setSound("sound.caf") - //此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value) - .addExtra("url",extrasparam) - //此项说明此推送是一个background推送,想了解background看:http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification - // .setContentAvailable(true) - .build()) - .build() - ) - //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息, - // sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的 - // [通知与自定义消息有什么区别?]了解通知和自定义消息的区别 - .setMessage(Message.newBuilder() - .setMsgContent(msg_content) - .setTitle(msg_title) - .addExtra("url",extrasparam) - .build()) - .setOptions(Options.newBuilder() - //此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义 - .setApnsProduction(ApnsProduction) - //此字段是给开发者自己给推送编号,方便推送者分辨推送记录 - .setSendno(1) - //此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天,单位为秒 - .setTimeToLive(86400) - .build()) - .build(); - } - - public static Boolean sendMessage(String phone,String notification_title,String msg_content){ - List strings=new ArrayList<>(); - strings.add(phone); - String msg_title="";//消息内容标题 - String extrasparam="";//扩展字段 - int i= sendToAlias(strings,notification_title,msg_title,msg_content,extrasparam); - System.out.println(i==0?"0推送失败":"1推送成功"); - return i==0?false:true; - } -} \ No newline at end of file +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AppUserDetailsServiceImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AppUserDetailsServiceImpl.java index d47a7dc..4015133 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AppUserDetailsServiceImpl.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AppUserDetailsServiceImpl.java @@ -8,6 +8,7 @@ import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.model.AppLoginUser; import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.JpushClientUtil; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.course.service.IScStudentService; import com.ruoyi.system.service.SysTeacherService; @@ -84,6 +85,7 @@ public class AppUserDetailsServiceImpl implements UserDetailsService SysUser user1=new SysUser(); user1.setPassword(user.getPassword()); passwordService.validate(user1); + return createLoginUser(user,roles.toArray(new Long[roles.size()]) ,studentId); } diff --git a/ruoyi-im-client/src/main/java/com/ruoyi/imclient/sender/IMSender.java b/ruoyi-im-client/src/main/java/com/ruoyi/imclient/sender/IMSender.java index 97b291a..0d546c2 100644 --- a/ruoyi-im-client/src/main/java/com/ruoyi/imclient/sender/IMSender.java +++ b/ruoyi-im-client/src/main/java/com/ruoyi/imclient/sender/IMSender.java @@ -11,6 +11,7 @@ import com.ruoyi.common.im.enums.IMSendCode; import com.ruoyi.common.im.enums.IMTerminalType; import com.ruoyi.common.im.model.*; import com.ruoyi.common.im.mq.RedisMQTemplate; +import com.ruoyi.common.utils.JpushClientUtil; import com.ruoyi.imclient.listener.MessageListenerMulticaster; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; @@ -83,7 +84,7 @@ public class IMSender { } } - + public void sendPrivateMessage(IMPrivateMessage message) { List results = new LinkedList<>(); if(!Objects.isNull(message.getRecvId())){ @@ -257,7 +258,7 @@ public class IMSender { public Boolean isOnline(Long userId) { String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, userId.toString(), "*"); - return !Objects.requireNonNull(redisMQTemplate.keys(key)).isEmpty(); + return !Objects.requireNonNull(redisMQTemplate.keys(key)).isEmpty();//null.isEmpty()->ture->!->false->! ->ture ->不在线 } public List getOnlineUser(List userIds){ diff --git a/ruoyi-im-client/target/classes/com/ruoyi/imclient/sender/IMSender.class b/ruoyi-im-client/target/classes/com/ruoyi/imclient/sender/IMSender.class index a46cce5..afdc805 100644 Binary files a/ruoyi-im-client/target/classes/com/ruoyi/imclient/sender/IMSender.class and b/ruoyi-im-client/target/classes/com/ruoyi/imclient/sender/IMSender.class differ diff --git a/ruoyi-im-server/src/main/java/com/ruoyi/imserver/netty/processor/GroupMessageProcessor.java b/ruoyi-im-server/src/main/java/com/ruoyi/imserver/netty/processor/GroupMessageProcessor.java index 2bb6c3d..c7a2380 100644 --- a/ruoyi-im-server/src/main/java/com/ruoyi/imserver/netty/processor/GroupMessageProcessor.java +++ b/ruoyi-im-server/src/main/java/com/ruoyi/imserver/netty/processor/GroupMessageProcessor.java @@ -10,6 +10,7 @@ import com.ruoyi.common.im.model.IMSendResult; import com.ruoyi.common.im.model.IMUserInfo; import com.ruoyi.common.im.mq.RedisMQTemplate; import com.ruoyi.imserver.netty.UserChannelCtxMap; +import com.ruoyi.imserver.util.LongToStringConverter; import io.netty.channel.ChannelHandlerContext; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -37,7 +38,7 @@ public class GroupMessageProcessor extends AbstractMessageProcessor // 推送消息到用户 IMSendInfo sendInfo = new IMSendInfo<>(); sendInfo.setCmd(IMCmdType.GROUP_MESSAGE.code()); - sendInfo.setData(recvInfo.getData()); + sendInfo.setData(LongToStringConverter.convertLongToString(recvInfo.getData())); channelCtx.channel().writeAndFlush(sendInfo); // 消息发送成功确认 sendResult(recvInfo, receiver, IMSendCode.SUCCESS); @@ -62,6 +63,7 @@ public class GroupMessageProcessor extends AbstractMessageProcessor result.setSender(recvInfo.getSender()); result.setReceiver(receiver); result.setCode(sendCode.code()); +// result.setData(LongToStringConverter.convertLongToString(recvInfo.getData())); result.setData(recvInfo.getData()); // 推送到结果队列 String key = StrUtil.join(":", IMRedisKey.IM_RESULT_GROUP_QUEUE,recvInfo.getServiceName()); diff --git a/ruoyi-im-server/src/main/java/com/ruoyi/imserver/netty/processor/PrivateMessageProcessor.java b/ruoyi-im-server/src/main/java/com/ruoyi/imserver/netty/processor/PrivateMessageProcessor.java index e932175..203fb79 100644 --- a/ruoyi-im-server/src/main/java/com/ruoyi/imserver/netty/processor/PrivateMessageProcessor.java +++ b/ruoyi-im-server/src/main/java/com/ruoyi/imserver/netty/processor/PrivateMessageProcessor.java @@ -11,6 +11,7 @@ import com.ruoyi.common.im.model.IMSendResult; import com.ruoyi.common.im.model.IMUserInfo; import com.ruoyi.common.im.mq.RedisMQTemplate; import com.ruoyi.imserver.netty.UserChannelCtxMap; +import com.ruoyi.imserver.util.LongToStringConverter; import io.netty.channel.ChannelHandlerContext; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -36,7 +37,7 @@ public class PrivateMessageProcessor extends AbstractMessageProcessor sendInfo = new IMSendInfo<>(); sendInfo.setCmd(IMCmdType.PRIVATE_MESSAGE.code()); - sendInfo.setData(recvInfo.getData()); + sendInfo.setData(LongToStringConverter.convertLongToString(recvInfo.getData())); channelCtx.channel().writeAndFlush(sendInfo); // 消息发送成功确认 sendResult(recvInfo, IMSendCode.SUCCESS); @@ -59,10 +60,13 @@ public class PrivateMessageProcessor extends AbstractMessageProcessor convertLongToString(Object data) { + // 利用 Jackson 的树模型,将所有数字节点转为字符串 + JsonNode node = MAPPER.valueToTree(data); + convertNumberNodesToString(node); + return MAPPER.convertValue(node, new TypeReference>() {}); + } + + private static void convertNumberNodesToString(JsonNode node) { + if (node.isObject()) { + ObjectNode obj = (ObjectNode) node; + obj.fieldNames().forEachRemaining(fieldName -> { + JsonNode child = obj.get(fieldName); + if (child.isNumber()) { + obj.put(fieldName, child.asText()); // 数字转字符串 + } else if (child.isObject() || child.isArray()) { + convertNumberNodesToString(child); + } + }); + } else if (node.isArray()) { + ArrayNode array = (ArrayNode) node; + for (int i = 0; i < array.size(); i++) { + JsonNode element = array.get(i); + if (element.isNumber()) { + array.set(i, TextNode.valueOf(element.asText())); // 数组内数字元素 → 字符串 + } else if (element.isObject() || element.isArray()) { + convertNumberNodesToString(element); + } + } + } + } +} diff --git a/ruoyi-im-server/src/main/resources/application-druid.yml b/ruoyi-im-server/src/main/resources/application-druid.yml index fffaa94..8ae77c1 100644 --- a/ruoyi-im-server/src/main/resources/application-druid.yml +++ b/ruoyi-im-server/src/main/resources/application-druid.yml @@ -6,7 +6,7 @@ spring: druid: # 主库数据源 master: - url: jdbc:mysql://127.0.0.1:32769/yoga?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + url: jdbc:mysql://127.0.0.1:32768/yoga?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 # url: jdbc:mysql://127.0.0.1:3306/yj?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: '!Runpeng888' diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionAnswerSheet.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionAnswerSheet.java index 8d04695..55fbaa5 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionAnswerSheet.java +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionAnswerSheet.java @@ -15,6 +15,6 @@ public class QuestionAnswerSheet { private String sessionId; private LocalDateTime submitTime; private String ipAddress; - private String resultType; - private String resultText; + private String resultType;//结果类型:pinghe, qixu, yangxu, yinxu, tanshi, shire, xueyu, qiyu, tebing, multiple + private String resultText;//结果描述文本 } diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionConstitutionScore.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionConstitutionScore.java index f525775..410a6b4 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionConstitutionScore.java +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionConstitutionScore.java @@ -10,5 +10,5 @@ public class QuestionConstitutionScore { private Long id; private Long sheetId; private Long constitutionId; - private Integer totalScore; + private Integer totalScore;//总分 0-10 } diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionConstitutionType.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionConstitutionType.java index f102534..37d4728 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionConstitutionType.java +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionConstitutionType.java @@ -9,8 +9,8 @@ public class QuestionConstitutionType { @TableId(type = IdType.AUTO) private Long id; private Long surveyId; - private String name; - private String alias; - private String description; - private Integer sortOrder; + private String name;//模块名称 + private String alias;//唯一标识,如pinghe + private String description;//模块说明 + private Integer sortOrder;//排序 } diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionQuestion.java b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionQuestion.java index d1ea8c5..d1a350b 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionQuestion.java +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/domain/question/QuestionQuestion.java @@ -10,6 +10,6 @@ public class QuestionQuestion { private Long id; private Long constitutionId; private Integer serialNumber; - private String content; - private Integer fullScore; + private String content;//题目内容 + private Integer fullScore;//满分 } diff --git a/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/QuestionnaireServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/QuestionnaireServiceImpl.java index 6ecec67..0d47dde 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/QuestionnaireServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/basic/service/impl/QuestionnaireServiceImpl.java @@ -304,7 +304,8 @@ public class QuestionnaireServiceImpl extends ServiceImpl highKey = biasedScores.entrySet().stream() - .filter(e -> e.getValue() >= 8) .map(Map.Entry::getKey).findFirst(); + .filter(e -> e.getValue() >= 8) .max(Map.Entry.comparingByValue()).map(Map.Entry::getKey); + if (highKey.isPresent()) { String alias = highKey.get(); String name = constitutionMap.values().stream() @@ -312,16 +313,25 @@ public class QuestionnaireServiceImpl extends ServiceImpl v >= 7).count(); - if (count >= 2) { - String text = "亲爱的伽人您好,您的体质为复合型体质典型,建议综合调理。请联系您的馆主或教练,领取训练及生活方案,快速调整哦。"; + List keys = biasedScores.entrySet().stream() + .filter(e -> e.getValue() >= 7) .map(Map.Entry::getKey).collect(Collectors.toList()); +// long count = biasedScores.values().stream().filter(v -> v >= 7).count(); + if (keys.size() >= 1) { + String nameStr=constitutionMap.values().stream() + .filter(ct -> keys.contains(ct.getAlias())) + .map(QuestionConstitutionType::getName) + .collect(Collectors.joining(",")); + String isGrOne=keys.size()==1?nameStr:String.format("复合型体质(%s)",nameStr); + String text = String.format("亲爱的伽人您好,您的体质为%s,建议综合调理。请联系您的馆主或教练,领取训练及生活方案,快速调整哦。", isGrOne); return buildResult("multiple", text, scores, constitutionMap); } // 规则3: 某偏颇体质总分在 6~7 之间 Optional midKey = biasedScores.entrySet().stream() .filter(e -> e.getValue() >= 6 && e.getValue() <= 7) .map(Map.Entry::getKey).findFirst(); + if (midKey.isPresent()) { String alias = midKey.get(); String name = constitutionMap.values().stream() @@ -330,8 +340,6 @@ public class QuestionnaireServiceImpl extends ServiceImpl未知;1->女;2->男 private String sex; private String phone; diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespStuBook.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespStuBook.java index bff138b..0313316 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespStuBook.java +++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/res/RespStuBook.java @@ -13,6 +13,7 @@ public class RespStuBook { private Long studentId; private Long bookId; + private Long appUserId; private String studentName; @@ -24,6 +25,6 @@ public class RespStuBook { private int checkIn; private Date checkInTime; - + } diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeBookItem.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeBookItem.java index 0a0c5b1..c105f9f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeBookItem.java +++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/ClaTimeBookItem.java @@ -64,6 +64,7 @@ public class ClaTimeBookItem { //老师信息 private Long teacherId; + private Long teacherAppId; private String teacherName; //*0未签到 1签到 diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/StudentOrderItem.java b/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/StudentOrderItem.java index 113dcf5..74781ea 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/StudentOrderItem.java +++ b/ruoyi-system/src/main/java/com/ruoyi/course/domain/time/StudentOrderItem.java @@ -20,6 +20,7 @@ public class StudentOrderItem { private Integer sex; private String phone; private String courseName; + private String cardNo; //收费模式 hour:课时 date:时间 cycle:期 private String chargeType; //开始时间 @@ -28,6 +29,13 @@ public class StudentOrderItem { private String expireDate; //收款金额 private BigDecimal receiptFee; + private BigDecimal totalFee;//储值 + private BigDecimal remainingTotalFee;//储值 + private BigDecimal count;//次数 + private BigDecimal remainingCount;//次数 + private int days;//天数 + + diff --git a/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeServiceImpl.java index 8bf51eb..9ff67f9 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/course/service/impl/ScClaTimeServiceImpl.java @@ -270,6 +270,7 @@ public class ScClaTimeServiceImpl extends ServiceImpl> cardMap =cardList.stream().collect(Collectors.groupingBy(ScMemberCard::getCardNo)); @@ -440,6 +441,7 @@ public class ScClaTimeServiceImpl extends ServiceImpl extras=new HashMap<>(); + extras.put("type","bookCourses");//type推送类型:bookCourses 预约课程 groupMessage群聊消息 privateMessage私信消息 + extras.put("pagePath","/pages/book/book");//pagePath跳转页面 + extras.put("bookId",bookId.toString());//bookId预约id + JpushClientUtil.pushByRegistrationId(Arrays.asList(recvUser.getRegisterId()),"瑜伽汇",msg,extras); + } + } //约课次数 public Boolean checkBookNum(Long cardTypeId,String cardNo){ RespMemberTypeCourses type= memberCardsMapper.getMemberTypeById(cardTypeId); @@ -660,25 +679,25 @@ public class ScClaTimeServiceImpl extends ServiceImpl0){ - return new RestResponse().setSuccess(true).setMessage("成功!"); - }else { return new RestResponse().setSuccess(false).setMessage("请刷新预约状态!"); - } + } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/GroupMessage.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/GroupMessage.java index 43d4385..09b4451 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/domain/GroupMessage.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/GroupMessage.java @@ -2,6 +2,8 @@ package com.ruoyi.im.domain; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import lombok.Data; import java.util.Date; @@ -23,16 +25,19 @@ public class GroupMessage { * id */ @TableId + @JsonSerialize(using = ToStringSerializer.class) private Long id; /** * 群id */ + @JsonSerialize(using = ToStringSerializer.class) private Long groupId; /** * 发送用户id */ + @JsonSerialize(using = ToStringSerializer.class) private Long sendId; /** diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/PrivateMessage.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/PrivateMessage.java index 75b5fc3..48bf39d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/domain/PrivateMessage.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/PrivateMessage.java @@ -1,6 +1,8 @@ package com.ruoyi.im.domain; import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import lombok.Data; import java.util.Date; @@ -20,16 +22,19 @@ public class PrivateMessage { /** * id */ + @JsonSerialize(using = ToStringSerializer.class) private Long id; /** * 发送用户id */ + @JsonSerialize(using = ToStringSerializer.class) private Long sendId; /** * 接收用户id */ + @JsonSerialize(using = ToStringSerializer.class) private Long recvId; /** diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/GroupMessageDTO.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/GroupMessageDTO.java index a2bd8e8..b25932a 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/GroupMessageDTO.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/dto/GroupMessageDTO.java @@ -27,7 +27,7 @@ public class GroupMessageDTO { private Integer type; @Schema(description = "是否回执消息") - private Boolean receipt = false; + private Boolean receipt = true; @Size(max = 20, message = "一次最多只能@20个小伙伴哦") @Schema(description = "被@用户列表") diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/FriendVO.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/FriendVO.java index d98e14d..2ae1635 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/FriendVO.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/FriendVO.java @@ -1,5 +1,6 @@ package com.ruoyi.im.domain.vo; +import com.baomidou.mybatisplus.annotation.TableField; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -23,4 +24,9 @@ public class FriendVO { @Schema(description = "是否已删除") private Boolean deleted; + + + private Long roleId; + + private Long storeId; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/GroupMessageVO.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/GroupMessageVO.java index 11ece7d..a39c30f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/GroupMessageVO.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/GroupMessageVO.java @@ -1,6 +1,7 @@ package com.ruoyi.im.domain.vo; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.ruoyi.common.serializer.DateToLongSerializer; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -12,14 +13,20 @@ import java.util.List; public class GroupMessageVO { @Schema(description = "消息id") + @JsonSerialize(using = ToStringSerializer.class) private Long id; @Schema(description = "群聊id") + @JsonSerialize(using = ToStringSerializer.class) private Long groupId; @Schema(description = " 发送者id") + @JsonSerialize(using = ToStringSerializer.class) private Long sendId; + @Schema(description = " 已读者id") + private Long readedId; + @Schema(description = " 发送者昵称") private String sendNickName; diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/OnlineTerminalVO.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/OnlineTerminalVO.java new file mode 100644 index 0000000..6c0f283 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/OnlineTerminalVO.java @@ -0,0 +1,19 @@ +package com.ruoyi.im.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.List; + +@Data +@AllArgsConstructor +public class OnlineTerminalVO { + + @Schema(description = "用户id") + private Long userId; + + @Schema(description = "在线终端类型") + private List terminals; + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/PrivateMessageVO.java b/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/PrivateMessageVO.java index 5cbd71f..a300d49 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/PrivateMessageVO.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/domain/vo/PrivateMessageVO.java @@ -2,6 +2,7 @@ package com.ruoyi.im.domain.vo; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.ruoyi.common.serializer.DateToLongSerializer; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -13,12 +14,15 @@ import java.util.Date; public class PrivateMessageVO { @Schema(description = " 消息id") + @JsonSerialize(using = ToStringSerializer.class) private Long id; @Schema(description = " 发送者id") + @JsonSerialize(using = ToStringSerializer.class) private Long sendId; @Schema(description = " 接收者id") + @JsonSerialize(using = ToStringSerializer.class) private Long recvId; @Schema(description = " 发送内容") diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/mapper/FriendMapper.java b/ruoyi-system/src/main/java/com/ruoyi/im/mapper/FriendMapper.java index 0690ff5..032604b 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/mapper/FriendMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/mapper/FriendMapper.java @@ -2,12 +2,13 @@ package com.ruoyi.im.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.im.domain.Friend; +import com.ruoyi.im.domain.vo.FriendVO; import java.util.List; public interface FriendMapper extends BaseMapper { - List getFriendListForConsumer(Long storeId); - List getFriendListForManage(Long userId); + List getFriendListForConsumer(Long storeId); + List getFriendListForManage(Long userId); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/FriendService.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/FriendService.java index 834d5db..f393a91 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/service/FriendService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/FriendService.java @@ -3,6 +3,7 @@ package com.ruoyi.im.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.im.domain.Friend; import com.ruoyi.im.domain.vo.FriendVO; +import com.ruoyi.im.domain.vo.OnlineTerminalVO; import com.sun.javafx.collections.MappingChange; import java.util.List; @@ -67,5 +68,11 @@ public interface FriendService extends IService { */ void bindFriend(Long userId, Long friendId); - + /** + * 获取用户在线的终端类型 + * + * @param userIds 用户id,多个用‘,’分割 + * @return 在线用户终端 + */ + List getOnlineTerminals(String userIds); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupService.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupService.java index 7cbb487..c9b4c33 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/GroupService.java @@ -3,6 +3,7 @@ package com.ruoyi.im.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.im.domain.Group; import com.ruoyi.im.domain.dto.GroupInviteDTO; +import com.ruoyi.im.domain.vo.GroupMemberVO; import com.ruoyi.im.domain.vo.GroupVO; import java.util.List; @@ -42,5 +43,11 @@ public interface GroupService extends IService { */ Group getAndCheckById(Long groupId); - + /** + * 查询群成员 + * + * @param groupId 群聊id + * @return List + **/ + List findGroupMembers(Long groupId); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FriendServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FriendServiceImpl.java index 8fd5b51..60949e8 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FriendServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/FriendServiceImpl.java @@ -11,11 +11,14 @@ import com.ruoyi.basic.service.YjAppUserService; import com.ruoyi.common.core.domain.entity.AppUser; import com.ruoyi.common.im.constant.RedisKey; import com.ruoyi.common.exception.GlobalException; +import com.ruoyi.common.im.enums.IMTerminalType; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.im.domain.Friend; import com.ruoyi.im.domain.vo.FriendVO; +import com.ruoyi.im.domain.vo.OnlineTerminalVO; import com.ruoyi.im.service.FriendService; import com.ruoyi.im.mapper.FriendMapper; +import com.ruoyi.imclient.IMClient; import com.ruoyi.system.service.SysTeacherService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -26,10 +29,7 @@ import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; @Slf4j @@ -38,29 +38,31 @@ import java.util.stream.Collectors; @CacheConfig(cacheNames = RedisKey.IM_CACHE_FRIEND) public class FriendServiceImpl extends ServiceImpl implements FriendService { - + private final IMClient imClient; private final YjAppUserService yjAppUserService; private final SysTeacherService t; @Override public Map findAllFriends() { Long userId= SecurityUtils.getAppLoginUser().getAppUser().getId(); - Map> map=new HashMap<>(); + Map> map=new HashMap<>(); Long manageId= SecurityUtils.getAppLoginUser().getAppUser().getManageAccountId(); if (ObjectUtil.isNotEmpty(manageId)){ - List list=baseMapper.getFriendListForManage(userId); + List list=baseMapper.getFriendListForManage(userId); map.put("consumer",list); + map.put("all",list);//所有好友 return map; } Long storeId=SecurityUtils.getAppLoginUser().getAppUser().getVisitStore(); - List list=baseMapper.getFriendListForConsumer(storeId); - Map> friendMap = list.stream().collect(Collectors.groupingBy(Friend::getRoleId)); + List list=baseMapper.getFriendListForConsumer(storeId); + Map> friendMap = list.stream().collect(Collectors.groupingBy(FriendVO::getRoleId)); map.put("storeManager",friendMap.get(105l));//店长 map.put("coach",friendMap.get(104l));//教练 map.put("adviser",friendMap.get(103l));//课程顾问 map.put("customerService",friendMap.get(108l));//客服 + map.put("all",list);//所有好友 return map; @@ -268,4 +270,17 @@ public class FriendServiceImpl extends ServiceImpl impleme // imClient.sendPrivateMessage(sendMessage); } + @Override + public List getOnlineTerminals(String userIds) { + List userIdList = Arrays.stream(userIds.split(",")).map(Long::parseLong).collect(Collectors.toList()); + // 查询在线的终端 + Map> terminalMap = imClient.getOnlineTerminal(userIdList); + // 组装vo + List vos = new LinkedList<>(); + terminalMap.forEach((userId, types) -> { + List terminals = types.stream().map(IMTerminalType::code).collect(Collectors.toList()); + vos.add(new OnlineTerminalVO(userId, terminals)); + }); + return vos; + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java index 22572cc..efd30b9 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/GroupMessageServiceImpl.java @@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.basic.service.YjAppUserService; import com.ruoyi.common.core.domain.entity.AppUser; import com.ruoyi.common.exception.GlobalException; import com.ruoyi.common.im.constant.IMConstant; @@ -21,6 +22,7 @@ import com.ruoyi.common.im.model.IMUserInfo; import com.ruoyi.common.im.util.BeanUtils; import com.ruoyi.common.im.util.CommaTextUtils; import com.ruoyi.common.im.util.ThreadPoolExecutorFactory; +import com.ruoyi.common.utils.JpushClientUtil; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.im.domain.Group; import com.ruoyi.im.domain.GroupMember; @@ -52,6 +54,7 @@ import java.util.stream.Collectors; public class GroupMessageServiceImpl extends ServiceImpl implements GroupMessageService { private final GroupService groupService; + private final YjAppUserService appUserService; private final GroupMemberService groupMemberService; private final RedisTemplate redisTemplate; private final IMClient imClient; @@ -96,25 +99,41 @@ public class GroupMessageServiceImpl extends ServiceImpl recvIds){ + List recvUsers= appUserService.listByIds(recvIds); + List registerIds=recvUsers.stream().filter(user->StrUtil.isNotBlank(user.getRegisterId())).map(it -> it.getRegisterId()).collect(Collectors.toList()); + if (registerIds.size()>0){ + String msg = String.format( + "%s:%s", + groupName, contentd + ); + Map extras=new HashMap<>(); + extras.put("type","groupMessage"); + extras.put("groupId",groupId.toString()); + extras.put("pagePath","/pages/chatbox/chat-box"); + JpushClientUtil.pushByRegistrationId(registerIds,"瑜伽汇",msg,extras); + } + } @Transactional @Override public GroupMessageVO recallMessage(Long id) { + AppUser session = SecurityUtils.getAppLoginUser().getAppUser(); GroupMessage msg = this.getById(id); if (Objects.isNull(msg)) { throw new GlobalException("消息不存在"); } - if (!msg.getSendId().equals(SecurityUtils.getAppLoginUser().getAppUserId())) { + if (!msg.getSendId().equals(session.getId())) { throw new GlobalException("这条消息不是由您发送,无法撤回"); } if (System.currentTimeMillis() - msg.getSendTime().getTime() > IMConstant.ALLOW_RECALL_SECOND * 1000) { throw new GlobalException("消息已发送超过5分钟,无法撤回"); } // 判断是否在群里 - GroupMember member = groupMemberService.findByGroupAndUserId(msg.getGroupId(), SecurityUtils.getAppLoginUser().getAppUserId()); + GroupMember member = groupMemberService.findByGroupAndUserId(msg.getGroupId(), session.getId()); if (Objects.isNull(member) || Boolean.TRUE.equals(member.getQuit())) { throw new GlobalException("您已不在群聊里面,无法撤回消息"); } @@ -126,7 +145,7 @@ public class GroupMessageServiceImpl extends ServiceImpl userIds = groupMemberService.findUserIdsByGroupId(msg.getGroupId()); GroupMessageVO msgInfo = BeanUtils.copyProperties(recallMsg, GroupMessageVO.class); IMGroupMessage sendMessage = new IMGroupMessage<>(); - sendMessage.setSender(new IMUserInfo(SecurityUtils.getAppLoginUser().getAppUserId(), 1)); + sendMessage.setSender(new IMUserInfo(session.getId(), 1)); sendMessage.setRecvIds(userIds); sendMessage.setData(msgInfo); imClient.sendGroupMessage(sendMessage); - log.info("撤回群聊消息,发送id:{},群聊id:{},内容:{}", SecurityUtils.getAppLoginUser().getAppUserId(), msg.getGroupId(), msg.getContent()); + log.info("撤回群聊消息,发送id:{},群聊id:{},内容:{}", session.getId(), msg.getGroupId(), msg.getContent()); return msgInfo; } @@ -159,6 +178,7 @@ public class GroupMessageServiceImpl extends ServiceImpl { + // 第一次拉取时,一个群最多推送1w条消息,防止前端接收能力溢出导致卡顿 List sendMessages = groupMessages; if (minId <= 0 && groupMessages.size() > 10000) { @@ -198,24 +219,32 @@ public class GroupMessageServiceImpl extends ServiceImpl maxIdMap = null; + for (GroupMessage m : sendMessages) { + // 排除加群之前的消息 GroupMember member = groupMemberMap.get(m.getGroupId()); if (DateUtil.compare(member.getCreatedTime(), m.getSendTime()) > 0) { continue; } + // 排除不需要接收的消息 List recvIds = CommaTextUtils.asList(m.getRecvIds()); if (!recvIds.isEmpty() && !recvIds.contains(session.getId().toString())) { continue; } + // 组装vo GroupMessageVO vo = BeanUtils.copyProperties(m, GroupMessageVO.class); + // 被@用户列表 List atIds = CommaTextUtils.asList(m.getAtUserIds()); + vo.setAtUserIds(atIds.stream().map(Long::parseLong).collect(Collectors.toList())); + // 填充状态 vo.setStatus(readedMaxId >= m.getId() ? MessageStatus.READED.code() : MessageStatus.UNSEND.code()); + // 针对回执消息填充已读人数 if (m.getReceipt()) { if (Objects.isNull(maxIdMap)) { @@ -224,6 +253,7 @@ public class GroupMessageServiceImpl extends ServiceImpl sendMessage = new IMGroupMessage<>(); sendMessage.setSender(new IMUserInfo(m.getSendId(), IMTerminalType.WEB.code())); @@ -235,15 +265,17 @@ public class GroupMessageServiceImpl extends ServiceImpl wrapper = Wrappers.lambdaQuery(); wrapper.eq(GroupMessage::getGroupId, groupId).orderByDesc(GroupMessage::getId).last("limit 1") @@ -256,10 +288,10 @@ public class GroupMessageServiceImpl extends ServiceImpl sendMessage = new IMGroupMessage<>(); - sendMessage.setSender(new IMUserInfo(SecurityUtils.getAppLoginUser().getAppUserId(), 1)); + sendMessage.setSender(new IMUserInfo(session.getId(), 1)); sendMessage.setSendToSelf(true); sendMessage.setData(msgInfo); sendMessage.setSendResult(true); @@ -267,9 +299,9 @@ public class GroupMessageServiceImpl extends ServiceImpl(); - sendMessage.setSender(new IMUserInfo(SecurityUtils.getAppLoginUser().getAppUserId(), 1)); + sendMessage.setSender(new IMUserInfo(session.getId(), 1)); sendMessage.setRecvIds(userIds); sendMessage.setData(msgInfo); sendMessage.setSendToSelf(false); @@ -308,12 +341,13 @@ public class GroupMessageServiceImpl extends ServiceImpl findReadedUsers(Long groupId, Long messageId) { + AppUser session = SecurityUtils.getAppLoginUser().getAppUser(); GroupMessage message = this.getById(messageId); if (Objects.isNull(message)) { throw new GlobalException("消息不存在"); } // 是否在群聊里面 - GroupMember member = groupMemberService.findByGroupAndUserId(groupId, SecurityUtils.getAppLoginUser().getAppUserId()); + GroupMember member = groupMemberService.findByGroupAndUserId(groupId, session.getId()); if (Objects.isNull(member) || member.getQuit()) { throw new GlobalException("您已不在群聊里面"); } @@ -327,9 +361,10 @@ public class GroupMessageServiceImpl extends ServiceImpl findHistoryMessage(Long groupId, Long page, Long size) { + AppUser session = SecurityUtils.getAppLoginUser().getAppUser(); page = page > 0 ? page : 1; size = size > 0 ? size : 10; - Long userId = SecurityUtils.getAppLoginUser().getAppUserId(); + Long userId = session.getId(); long stIdx = (page - 1) * size; // 群聊成员信息 GroupMember member = groupMemberService.findByGroupAndUserId(groupId, userId); @@ -373,15 +408,17 @@ public class GroupMessageServiceImpl extends ServiceImpl implements } private GroupVO convert(Group group, GroupMember member) { + List members = groupMemberService.findUserIdsByGroupId(group.getId()); + List OtherMembers=members.stream().filter(it->!it.equals(member.getUserId())).collect(Collectors.toList()); GroupVO vo = BeanUtils.copyProperties(group, GroupVO.class); vo.setRemarkGroupName(member.getRemarkGroupName()); vo.setRemarkNickName(member.getRemarkNickName()); vo.setShowNickName(member.getShowNickName()); vo.setShowGroupName(StrUtil.blankToDefault(member.getRemarkGroupName(), group.getName())); vo.setQuit(member.getQuit()); + vo.setCustomerService(OtherMembers.get(0));//客服id + vo.setInstructor(OtherMembers.get(1));//教练id return vo; } @@ -224,5 +229,19 @@ public class GroupServiceImpl extends ServiceImpl implements sendMessage.setSendToSelf(sendToSelf); imClient.sendGroupMessage(sendMessage); } + @Override + public List findGroupMembers(Long groupId) { + Group group = getAndCheckById(groupId); + List members = groupMemberService.findByGroupId(groupId); + List userIds = members.stream().map(GroupMember::getUserId).collect(Collectors.toList()); + List onlineUserIds = imClient.getOnlineUser(userIds); + return members.stream().map(m -> { + GroupMemberVO vo = BeanUtils.copyProperties(m, GroupMemberVO.class); + vo.setShowNickName(m.getShowNickName()); + vo.setShowGroupName(StrUtil.blankToDefault(m.getRemarkGroupName(), group.getName())); + vo.setOnline(onlineUserIds.contains(m.getUserId())); + return vo; + }).sorted((m1, m2) -> m2.getOnline().compareTo(m1.getOnline())).collect(Collectors.toList()); + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/PrivateMessageServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/PrivateMessageServiceImpl.java index 8392a26..b3f67dd 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/PrivateMessageServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/im/service/impl/PrivateMessageServiceImpl.java @@ -1,11 +1,15 @@ package com.ruoyi.im.service.impl; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException; +import com.ruoyi.basic.service.YjAppUserService; import com.ruoyi.common.core.domain.entity.AppUser; import com.ruoyi.common.im.constant.IMConstant; import com.ruoyi.common.im.enums.IMTerminalType; @@ -15,6 +19,7 @@ import com.ruoyi.common.im.enums.MessageStatus; import com.ruoyi.common.im.enums.MessageType; import com.ruoyi.common.exception.GlobalException; import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.JpushClientUtil; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.im.util.BeanUtils; import com.ruoyi.common.im.util.ThreadPoolExecutorFactory; @@ -42,6 +47,7 @@ import com.ruoyi.mall.service.impl.OrderService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DeadlockLoserDataAccessException; import org.springframework.data.domain.PageImpl; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -57,22 +63,23 @@ public class PrivateMessageServiceImpl extends ServiceImpl sendMessage = new IMPrivateMessage<>(); - sendMessage.setSender(new IMUserInfo(userId,1)); + sendMessage.setSender(new IMUserInfo(appUser.getId(),1)); sendMessage.setRecvId(msgInfo.getRecvId()); sendMessage.setSendToSelf(true); sendMessage.setData(msgInfo); sendMessage.setSendResult(true); imClient.sendPrivateMessage(sendMessage); - log.info("发送私聊消息,发送id:{},接收id:{},内容:{}", userId, dto.getRecvId(), dto.getContent()); + jpush(appUser.getId(),appUser.getNickName(),msg.getContent(),dto.getRecvId()); + log.info("发送私聊消息,发送id:{},接收id:{},内容:{}", appUser.getId(), dto.getRecvId(), dto.getContent()); return msgInfo; } + public void jpush(Long sendId,String senderName,String contentd,Long recvId){ + if (ObjectUtil.isNotEmpty(recvId)){ + String registerId= appUserService.getById(recvId).getRegisterId(); + if (StrUtil.isNotBlank(registerId)){ + String msg = String.format( + "%s:%s", + senderName, contentd + ); + Map extras=new HashMap<>(); + extras.put("type","privateMessage"); + extras.put("senderId",sendId.toString()); + extras.put("pagePath","/pages/chatbox/chat-box"); + JpushClientUtil.pushByRegistrationId(Arrays.asList(registerId),"瑜伽汇",msg,extras); + } + } + + } @Transactional @Override public PrivateMessageVO recallMessage(Long id) { @@ -188,6 +213,7 @@ public class PrivateMessageServiceImpl extends ServiceImpl(); - sendMessage.setSender(new IMUserInfo(friendId, 1)); - sendMessage.setRecvId(session.getId()); + sendMessage.setSender(new IMUserInfo(session.getId(), 1)); + sendMessage.setRecvId(friendId); sendMessage.setSendToSelf(false); sendMessage.setSendResult(false); sendMessage.setData(msgInfo); @@ -230,8 +256,8 @@ public class PrivateMessageServiceImpl extends ServiceImpl wrapper = Wrappers.lambdaQuery(); wrapper - .eq(PrivateMessage::getSendId, friendId) - .eq(PrivateMessage::getRecvId, session.getId()) + .eq(PrivateMessage::getSendId, session.getId()) + .eq(PrivateMessage::getRecvId, friendId) .eq(PrivateMessage::getStatus, MessageStatus.READED.code()) .orderByDesc(PrivateMessage::getId) .select(PrivateMessage::getId).last("limit 1"); diff --git a/ruoyi-system/src/main/resources/mapper/cource/ScBookCourseMapper.xml b/ruoyi-system/src/main/resources/mapper/cource/ScBookCourseMapper.xml index e216e8b..c7c482c 100644 --- a/ruoyi-system/src/main/resources/mapper/cource/ScBookCourseMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/cource/ScBookCourseMapper.xml @@ -19,7 +19,8 @@ c.room_name, b.teacher_name, b.avatar_img as pic, - d.store_name + d.store_name, + (select app_user_id from yj_app_user where manage_account_id= b.user_id) as teacher_app_id from sc_book_course a, diff --git a/ruoyi-system/src/main/resources/mapper/cource/ScClaTimeMapper.xml b/ruoyi-system/src/main/resources/mapper/cource/ScClaTimeMapper.xml index ccf7c21..cb2d62c 100644 --- a/ruoyi-system/src/main/resources/mapper/cource/ScClaTimeMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/cource/ScClaTimeMapper.xml @@ -141,6 +141,7 @@ b.sex, b.phone, b.sex, + b.app_user_id, a.id as book_id, a.book_status, a.check_in, @@ -183,10 +184,15 @@ year(curdate())-year(c.birth_day) as age, c.sex, c.phone, - b.card_no as course_name, + b.card_no , b.charge_type, + b.total_fee, + b.remaining_total_fee, + b.total_count as count, + b.remaining_count, + b.total_days as days, b.activation_date as begin_date, - b.expiry_date as end_date, + b.expiry_date as expire_date, a.receipt_fee -- from sc_order a,sc_order_detail b,sc_student c from sc_order a,sc_member_cards b,sc_student c @@ -252,8 +258,11 @@ c.student_id, c.student_name, c.sex, - c.phone - from sc_cla_time a,sc_book_course b,sc_student c + c.phone, + c.app_user_id + from sc_cla_time a, + sc_book_course b, + sc_student c WHERE a.course_time_id=b.course_time_id and b.student_id=c.student_id -- and b.book_status=0 and a.teacher_id=#{teacherId} @@ -277,7 +286,8 @@ c.student_id, c.student_name, c.sex, - c.phone + c.phone, + c.app_user_id from sc_cla_time a,sc_book_course b,sc_student c WHERE a.course_time_id=b.course_time_id and b.student_id=c.student_id diff --git a/ruoyi-system/src/main/resources/mapper/im/FriendMapper.xml b/ruoyi-system/src/main/resources/mapper/im/FriendMapper.xml index 636b7cd..e173ca8 100644 --- a/ruoyi-system/src/main/resources/mapper/im/FriendMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/im/FriendMapper.xml @@ -22,12 +22,12 @@ and a.user_id=#{userId} - select - d.app_user_id as friend_id, + d.app_user_id as id, -- CONCAT(d.nick_name,'(',b.store_name,')') as friend_nick_name, - d.nick_name as friend_nick_name, - d.avatar as friend_head_image, + d.nick_name as nick_name, + d.avatar as head_image, e.role_id, b.dept_id as store_id from yj_store b @@ -40,12 +40,12 @@ and b.dept_id=#{storeId} - + select + b.app_user_id as id, + b.nick_name as nick_name, + b.avatar as head_image, + a.deleted from im_friend a, yj_app_user b WHERE a.friend_id=b.app_user_id