Pārlūkot izejas kodu

Merge branch 'dev_v1.3.5_20220927' into ponline

# Conflicts:
#	cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImGroupService.java
#	cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImGroupServiceImpl.java
Eric 2 gadi atpakaļ
vecāks
revīzija
113b2d12e5
71 mainītis faili ar 1692 papildinājumiem un 186 dzēšanām
  1. 9 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/TeacherFeignService.java
  2. 3 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/dto/UserFriendInfoVO.java
  3. 11 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/fallback/TeacherFeignServiceFallback.java
  4. 11 0
      cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/dto/UserSetReq.java
  5. 27 0
      cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/vo/SysUserVo.java
  6. 27 0
      cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/config/AppGlobalServiceConfig.java
  7. 2 2
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/handler/BaseAuthenticationSuccessEventHandler.java
  8. 1 1
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/provider/PhoneAuthenticationProvider.java
  9. 62 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/enums/EClientType.java
  10. 12 2
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/SysUserService.java
  11. 70 5
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/impl/SysUserServiceImpl.java
  12. 45 24
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/web/controller/TokenController.java
  13. 2 1
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/ImGroupController.java
  14. 3 1
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/ImUserFriendController.java
  15. 3 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/io/request/im/UserFriendInfoVO.java
  16. 4 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/ImGroupMemberDao.java
  17. 2 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/ImNetworkRoomMemberDao.java
  18. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/BasicUserInfo.java
  19. 12 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImGroupSearchDto.java
  20. 12 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkBaseDto.java
  21. 12 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkCustomMessage.java
  22. 16 4
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkDeviceControlDto.java
  23. 12 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkDisplayDataDto.java
  24. 14 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkMusicSheetDto.java
  25. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ImGroupMember.java
  26. 12 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ImNetworkRoomMember.java
  27. 42 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ImUserFriend.java
  28. 9 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/ClientEnum.java
  29. 2 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImGroupMemberAuditService.java
  30. 9 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImGroupMemberService.java
  31. 11 3
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImGroupService.java
  32. 5 4
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImNetworkRoomService.java
  33. 15 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImUserFriendService.java
  34. 9 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseGroupServiceImpl.java
  35. 16 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseHomeworkServiceImpl.java
  36. 45 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseScheduleServiceImpl.java
  37. 4 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImGroupMemberAuditServiceImpl.java
  38. 83 4
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImGroupMemberServiceImpl.java
  39. 104 7
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImGroupServiceImpl.java
  40. 11 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImNetworkRoomMemberServiceImpl.java
  41. 194 47
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImNetworkRoomServiceImpl.java
  42. 116 15
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImUserFriendServiceImpl.java
  43. 6 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/StudentServiceImpl.java
  44. 3 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TeacherServiceImpl.java
  45. 10 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/CourseHomeworkDetailVo.java
  46. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/CourseHomeworkVo.java
  47. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/CourseStudent.java
  48. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/LiveCourseInfoVo.java
  49. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/MyCourseVo.java
  50. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/StudentHomeVo.java
  51. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/TeacherHomeVo.java
  52. 118 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/im/ImUserFriendVO.java
  53. 73 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/im/ImUserWrapper.java
  54. 1 1
      cooleshow-user/user-biz/src/main/resources/config/mybatis/CourseScheduleStudentPaymentMapper.xml
  55. 4 1
      cooleshow-user/user-biz/src/main/resources/config/mybatis/ImGroupMapper.xml
  56. 3 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/ImGroupMemberAuditMapper.xml
  57. 6 3
      cooleshow-user/user-biz/src/main/resources/config/mybatis/ImGroupMemberMapper.xml
  58. 4 3
      cooleshow-user/user-biz/src/main/resources/config/mybatis/ImNetworkRoomMemberMapper.xml
  59. 3 7
      cooleshow-user/user-biz/src/main/resources/config/mybatis/ImUserFriendMapper.xml
  60. 90 5
      cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/controller/ImNetworkRoomController.java
  61. 13 1
      cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/CourseHomeworkController.java
  62. 30 3
      cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/ImGroupController.java
  63. 1 1
      cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/ImGroupMemberAuditController.java
  64. 27 6
      cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/ImGroupMemberController.java
  65. 43 6
      cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/ImUserFriendController.java
  66. 14 1
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/CourseHomeworkController.java
  67. 6 1
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/ImGroupController.java
  68. 1 1
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/ImGroupMemberAuditController.java
  69. 26 8
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/ImGroupMemberController.java
  70. 41 5
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/ImUserFriendController.java
  71. 22 0
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/open/OpenShareController.java

+ 9 - 0
cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/TeacherFeignService.java

@@ -6,6 +6,7 @@ import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.toolset.feign.config.FeignConfiguration;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
 
 @FeignClient(name = AppConstant.APPLICATION_TEACHER + AppConstant.SERVER, configuration = FeignConfiguration.class, fallback = TeacherFeignServiceFallback.class)
 public interface TeacherFeignService {
@@ -63,4 +64,12 @@ public interface TeacherFeignService {
      */
     @GetMapping("/task/teacherSalary")
     HttpResponseResult<Object> teacherSalary();
+
+    /**
+     * 用户老师身份
+     * @param userId 用户ID
+     * @return HttpResponseResult<Boolean>
+     */
+    @GetMapping("/open/teacher/identity/{ID}")
+    HttpResponseResult<Boolean> userTeacherIdentityInfo(@PathVariable("ID") Long userId);
 }

+ 3 - 0
cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/dto/UserFriendInfoVO.java

@@ -21,6 +21,9 @@ public class UserFriendInfoVO implements Serializable {
     // 新用户ID
     private Long userId;
 
+    // 客户端类型
+    private String clientType;
+
     // 好友ID
     private List<Long> friendIds;
 

+ 11 - 0
cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/fallback/TeacherFeignServiceFallback.java

@@ -41,4 +41,15 @@ public class TeacherFeignServiceFallback implements TeacherFeignService {
     public HttpResponseResult<Object> teacherSalary() {
         return null;
     }
+
+    /**
+     * 用户老师身份
+     *
+     * @param userId 用户ID
+     * @return HttpResponseResult<Boolean>
+     */
+    @Override
+    public HttpResponseResult<Boolean> userTeacherIdentityInfo(Long userId) {
+        return null;
+    }
 }

+ 11 - 0
cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/dto/UserSetReq.java

@@ -29,6 +29,9 @@ public class UserSetReq {
     @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
     private Date birthdate;
 
+    @ApiModelProperty("客户端类型: TEACHER, STUDENT")
+    private String clientType;
+
     public String getClientId() {
         return clientId;
     }
@@ -68,4 +71,12 @@ public class UserSetReq {
     public void setBirthdate(Date birthdate) {
         this.birthdate = birthdate;
     }
+
+    public String getClientType() {
+        return clientType;
+    }
+
+    public void setClientType(String clientType) {
+        this.clientType = clientType;
+    }
 }

+ 27 - 0
cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/vo/SysUserVo.java

@@ -0,0 +1,27 @@
+package com.yonge.cooleshow.auth.api.vo;
+
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * Created by Eric.Shang on 2022/10/17.
+ */
+public class SysUserVo extends SysUser {
+
+    @ApiModelProperty("IM用户ID")
+    private String imUserId;
+
+    public String getImUserId() {
+        return imUserId;
+    }
+
+    public void setImUserId(String imUserId) {
+        this.imUserId = imUserId;
+    }
+
+
+    public SysUserVo imUserId(String imUserId) {
+        this.imUserId = imUserId;
+        return this;
+    }
+}

+ 27 - 0
cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/config/AppGlobalServiceConfig.java

@@ -0,0 +1,27 @@
+package com.yonge.cooleshow.auth.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Optional;
+
+/**
+ * 应用全局功能配置
+ *
+ * Created by Eric.Shang on 2022/9/28.
+ */
+@Data
+@RefreshScope
+@Configuration
+@ConfigurationProperties(prefix = "app")
+public class AppGlobalServiceConfig {
+
+    /**
+     * 用户加入群组功能
+     */
+    @Value("${group.member.join:true}")
+    private Boolean groupMemberJoin;
+}

+ 2 - 2
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/handler/BaseAuthenticationSuccessEventHandler.java

@@ -84,9 +84,9 @@ public class BaseAuthenticationSuccessEventHandler extends SavedRequestAwareAuth
 			sysUser = sysUserService.queryLockByPhone(username.split(":")[1]);
 		}
 		if(StringUtils.isEmpty(sysUser.getImToken())){
-			String name = sysUser.getRealName();
+			String name = sysUser.getUsername();
 			if(StringUtils.isEmpty(name)){
-				name = sysUser.getUsername();
+				name = sysUser.getRealName();
 			}
 			try {
 				TokenResult result = RongCloudConfig.rongCloud.user.register(new UserModel(sysUser.getId().toString(), name, sysUser.getAvatar()));

+ 1 - 1
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/provider/PhoneAuthenticationProvider.java

@@ -80,7 +80,7 @@ public class PhoneAuthenticationProvider extends AbstractAuthenticationProvider
 
             if (Objects.nonNull(userInfo.getSysUser())) {
                 // 自动添加系统默认IM帐号为好友,并自动发送通知消息
-                sysUserService.sendSysCustomerServiceFriendMessage(userInfo.getSysUser());
+                sysUserService.sendSysCustomerServiceFriendMessage(userInfo.getSysUser(), clientId.toUpperCase());
             }
 
             if (StringUtils.isNotBlank(deviceNum)) {

+ 62 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/enums/EClientType.java

@@ -0,0 +1,62 @@
+package com.yonge.cooleshow.auth.enums;
+
+import com.yonge.toolset.base.enums.BaseEnum;
+
+/**
+ * Description
+ *
+ * @author liujunchi
+ * @date 2022-04-28
+ */
+public enum EClientType implements BaseEnum<String, EClientType> {
+    TEACHER("老师端"),
+    STUDENT("学生端"),
+    SYSTEM("平台端"),
+    WEBSITE("官网"),
+    ;
+    private String code;
+    private String msg;
+
+    EClientType(String msg) {
+        this.code = this.name();
+        this.msg = msg;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    /**
+     * 校验客户端类型合法性
+     * @param clientType 客户端类型
+     * @return boolean
+     */
+    public static boolean invalid(String clientType) {
+
+        EClientType[] values = EClientType.values();
+
+        for (EClientType item : values) {
+
+            if (item.getCode().equals(clientType)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * 客户端类型匹配
+     * @param type 类型
+     * @return boolean
+     */
+    public boolean match(String type) {
+
+        return getCode().equals(type);
+    }
+
+}

+ 12 - 2
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/SysUserService.java

@@ -8,6 +8,7 @@ import com.yonge.cooleshow.auth.api.dto.SysUserQueryInfo;
 import com.yonge.cooleshow.auth.api.dto.UserSetReq;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.auth.api.vo.UserSetVo;
+import com.yonge.cooleshow.auth.enums.EClientType;
 import com.yonge.cooleshow.common.entity.ImUserModel;
 import com.yonge.cooleshow.common.enums.SysUserType;
 import com.yonge.cooleshow.common.enums.UserLockFlag;
@@ -123,8 +124,9 @@ public interface SysUserService extends BaseService<Long, SysUser> {
     /**
      * 添加系统客服好友消息
      * @param sysUser SysUser
+     * @param clientType 客户端类型
      */
-    void sendSysCustomerServiceFriendMessage(SysUser sysUser);
+    void sendSysCustomerServiceFriendMessage(SysUser sysUser, String clientType);
 
     /**
      * 刷新token
@@ -176,7 +178,7 @@ public interface SysUserService extends BaseService<Long, SysUser> {
     void submitSetDetail(UserSetReq setReq, Long id);
 
     //修改融云用户基本信息
-    void updateRongCloudUserInfo(Long userId);
+    void updateRongCloudUserInfo(Long userId, String clientType);
 
     /**
      * 商城同步管理用户
@@ -201,4 +203,12 @@ public interface SysUserService extends BaseService<Long, SysUser> {
     void logoffById(Long id);
 
     void updateLockStatus(Long userId, Integer lockFlag, String sysUserType);
+
+    /**
+     * 用户信息
+     * @param userId 用户ID
+     * @param clientType 客户端类型
+     * @return SysUser
+     */
+    SysUser queryUserInfoWithIMToken(Long userId, EClientType clientType);
 }

+ 70 - 5
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/impl/SysUserServiceImpl.java

@@ -3,6 +3,7 @@ package com.yonge.cooleshow.auth.service.impl;
 import com.alibaba.fastjson.JSON;
 import com.google.common.collect.Lists;
 import com.yonge.cooleshow.api.feign.AdminFeignService;
+import com.yonge.cooleshow.api.feign.TeacherFeignService;
 import com.yonge.cooleshow.api.feign.dto.UserFriendInfoVO;
 import com.yonge.cooleshow.auth.api.dto.QRLoginDto;
 import com.yonge.cooleshow.auth.api.dto.RealnameAuthReq;
@@ -14,6 +15,7 @@ import com.yonge.cooleshow.auth.api.vo.UserSetVo;
 import com.yonge.cooleshow.auth.config.CustomerServiceConfig;
 import com.yonge.cooleshow.auth.config.RongCloudConfig;
 import com.yonge.cooleshow.auth.dal.dao.SysUserDao;
+import com.yonge.cooleshow.auth.enums.EClientType;
 import com.yonge.cooleshow.auth.service.SysConfigService;
 import com.yonge.cooleshow.auth.service.SysRoleMenuService;
 import com.yonge.cooleshow.auth.service.SysUserRoleService;
@@ -28,6 +30,7 @@ import com.yonge.toolset.base.exception.BizException;
 import com.yonge.toolset.base.util.ThreadPool;
 import com.yonge.toolset.mybatis.dal.BaseDAO;
 import com.yonge.toolset.mybatis.service.impl.BaseServiceImpl;
+import io.rong.models.response.TokenResult;
 import io.rong.models.user.UserModel;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
@@ -36,10 +39,10 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
-import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
+import java.text.MessageFormat;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
@@ -65,6 +68,8 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
     private AdminFeignService adminFeignService;
     @Autowired
     private CustomerServiceConfig customerServiceConfig;
+    @Autowired
+    private TeacherFeignService teacherFeignService;
 
     @Override
     public BaseDAO<Long, SysUser> getDAO() {
@@ -206,7 +211,7 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
      * 添加系统客服好友消息
      * @param sysUser SysUser
      */
-    public void sendSysCustomerServiceFriendMessage(SysUser sysUser) {
+    public void sendSysCustomerServiceFriendMessage(SysUser sysUser, String clientType) {
 
         try {
 
@@ -226,6 +231,7 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
                     // 发送添加系统客服好友消息
                     HttpResponseResult<Boolean> result = adminFeignService.customerService(UserFriendInfoVO.builder()
                             .userId(sysUser.getId())
+                            .clientType(clientType)
                             .friendIds(Lists.newArrayList(friend.getId()))
                             .build());
                     log.info("sendSysCustomerServiceFriendMessage mobile={}, ret={}", mobile, JSON.toJSONString(result));
@@ -278,19 +284,29 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
     @Override
     public void submitSetDetail(UserSetReq setReq, Long id) {
         sysUserDao.updatetSetDetail(setReq, id);
+
+        if (StringUtils.isEmpty(setReq.getClientType())) {
+            setReq.setClientType(EClientType.TEACHER.name());
+        }
         //更新融云用户基本信息
-        this.updateRongCloudUserInfo(id);
+        this.updateRongCloudUserInfo(id, setReq.getClientType());
     }
 
     @Override
-    public void updateRongCloudUserInfo(Long userId) {
+    public void updateRongCloudUserInfo(Long userId, String clientType) {
         UserSetVo setDetail = this.getSetDetail(userId);
         //更新imGroupMember表用户头像
         sysUserDao.updateImGroupMember(userId, setDetail.getUsername(), setDetail.getAvatar());
         //更新imUserFriend表用户头像
         sysUserDao.updateImUserFriend(userId, setDetail.getUsername(), setDetail.getAvatar());
         try {
-            RongCloudConfig.rongCloud.user.update(new UserModel(userId.toString(), setDetail.getUsername(), setDetail.getAvatar()));
+
+            String imUserId = String.valueOf(userId);
+            if (EClientType.STUDENT.match(clientType)) {
+                imUserId = MessageFormat.format("{0}:{1}", imUserId, EClientType.STUDENT.name());
+            }
+
+            RongCloudConfig.rongCloud.user.update(new UserModel(imUserId, setDetail.getUsername(), setDetail.getAvatar()));
         } catch (Exception e) {
             throw new BizException("更新用户信息失败");
         }
@@ -347,4 +363,53 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
     public void updateLockStatus(Long userId, Integer lockFlag, String sysUserType) {
         sysUserDao.updateLockStatus(userId, lockFlag, sysUserType);
     }
+
+    /**
+     * 用户信息
+     *
+     * @param userId     用户ID
+     * @param clientType 客户端类型
+     * @return SysUser
+     */
+    @Override
+    public SysUser queryUserInfoWithIMToken(Long userId, EClientType clientType) {
+
+        // 查询用户基本信息
+        SysUser sysUser = sysUserDao.get(userId);
+
+        if (EClientType.STUDENT == clientType && Objects.nonNull(sysUser)) {
+
+            // 重新请求生成IM会话TOKEN
+            try {
+
+                /*HttpResponseResult<Boolean> recv = teacherFeignService.userTeacherIdentityInfo(userId);
+
+                if (Objects.nonNull(recv) && recv.getData()) {
+                    // 同时一个手机号,拥手老师、学生身份时,为学生创建新的IMToken
+
+                }*/
+
+                String name = sysUser.getUsername();
+                if(StringUtils.isEmpty(name)){
+                    name = sysUser.getRealName();
+                }
+
+                // IM用户ID
+                String imIdentity = MessageFormat.format("{0}:{1}", String.valueOf(sysUser.getId()), clientType.name());
+
+                TokenResult result = RongCloudConfig.rongCloud.user.register(new UserModel(imIdentity, name, sysUser.getAvatar()));
+                if(result.code.equals(200)){
+
+                    sysUser.setImToken(result.getToken());
+                } else {
+                    log.warn("queryUserInfoWithIMToken 获取用户token失败:{}", result.errorMessage);
+                }
+
+            } catch (Exception e) {
+                log.error("queryUserInfoWithIMToken 获取用户token失败, userId={}", userId, e);
+            }
+        }
+
+        return sysUser;
+    }
 }

+ 45 - 24
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/web/controller/TokenController.java

@@ -1,22 +1,25 @@
 package com.yonge.cooleshow.auth.web.controller;
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
-import com.google.gson.JsonObject;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.yonge.cooleshow.auth.api.dto.QRLoginDto;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.auth.api.vo.SysUserVo;
+import com.yonge.cooleshow.auth.core.service.CustomTokenServices;
+import com.yonge.cooleshow.auth.enums.EClientType;
+import com.yonge.cooleshow.auth.service.SysUserService;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.enums.CacheNameEnum;
-import com.yonge.cooleshow.common.util.TokenUtil;
+import com.yonge.cooleshow.common.security.AuthUser;
+import com.yonge.cooleshow.common.security.SecurityUtils;
 import com.yonge.toolset.base.util.StringUtil;
-import io.swagger.annotations.*;
-
-import java.io.IOException;
-import java.util.Base64;
-import java.util.Calendar;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-
-import javax.servlet.http.HttpServletRequest;
-
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
 import org.apache.commons.lang3.StringUtils;
 import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -31,17 +34,21 @@ import org.springframework.security.oauth2.provider.token.ResourceServerTokenSer
 import org.springframework.security.oauth2.provider.token.TokenStore;
 import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.client.RestTemplate;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.yonge.cooleshow.auth.api.entity.SysUser;
-import com.yonge.cooleshow.auth.core.service.CustomTokenServices;
-import com.yonge.cooleshow.auth.service.SysUserService;
-import com.yonge.cooleshow.common.controller.BaseController;
-import com.yonge.cooleshow.common.entity.HttpResponseResult;
-import com.yonge.cooleshow.common.security.AuthUser;
-import com.yonge.cooleshow.common.security.SecurityUtils;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.Base64;
+import java.util.Calendar;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
 
 @RestController
 @Api(tags = "认证服务")
@@ -93,10 +100,24 @@ public class TokenController extends BaseController {
 
     @ApiOperation(value = "获取用户信息")
     @GetMapping("/api/queryUserInfo")
-    public Object apiQueryUserInfo() {
+    public Object apiQueryUserInfo(@RequestParam(value = "clientType", required = false, defaultValue = "TEACHER") String clientType) {
+
+        // 校验客户端类型
+        if (EClientType.invalid(clientType)) {
+            return failed("无效的客户端类型");
+        }
+
         AuthUser authUser = SecurityUtils.getUser();
         if (authUser != null) {
-            return succeed(userService.queryUserInfo(authUser.getUserId()));
+            SysUser sysUser = userService.queryUserInfoWithIMToken(authUser.getUserId(), EClientType.valueOf(clientType));
+
+            String imUserId = String.valueOf(sysUser.getId());
+            if (EClientType.STUDENT.match(clientType)) {
+                imUserId = MessageFormat.format("{0}:{1}",imUserId, clientType);
+            }
+
+            // 封装返回参数
+            return succeed(JSON.parseObject(JSON.toJSONString(sysUser), SysUserVo.class).imUserId(imUserId));
         }
         return failed("获取用户信息失败");
     }

+ 2 - 1
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/ImGroupController.java

@@ -3,6 +3,7 @@ package com.yonge.cooleshow.admin.controller;
 
 import com.yonge.cooleshow.biz.dal.dto.ImGroupSearchDto;
 import com.yonge.cooleshow.biz.dal.entity.ImGroup;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.ImGroupService;
 import com.yonge.cooleshow.biz.dal.service.SysUserService;
 import com.yonge.cooleshow.common.controller.BaseController;
@@ -61,7 +62,7 @@ public class ImGroupController extends BaseController {
     @ApiOperation("退出群聊")
     @PostMapping(value = "/quit/{groupId}")
     public HttpResponseResult quit(@ApiParam(value = "群编号", required = true) @PathVariable("groupId") String groupId) throws Exception {
-        imGroupService.quit(groupId,sysUserService.getUserId());
+        imGroupService.quit(groupId,sysUserService.getUserId(), ClientEnum.STUDENT);
         return succeed();
     }
 }

+ 3 - 1
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/ImUserFriendController.java

@@ -2,6 +2,7 @@ package com.yonge.cooleshow.admin.controller.open;
 
 import com.yonge.cooleshow.admin.io.request.im.IMNotifyMessageVO;
 import com.yonge.cooleshow.admin.io.request.im.UserFriendInfoVO;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.ImUserFriendService;
 import com.yonge.cooleshow.biz.dal.wrapper.im.CustomerService;
 import com.yonge.cooleshow.common.controller.BaseController;
@@ -42,7 +43,8 @@ public class ImUserFriendController extends BaseController {
         }
 
         // 新用户自动绑定系统客服
-        int ret = imUserFriendService.registerUserBindCustomerService(info.getUserId(), info.getFriendIds());
+        int ret = imUserFriendService.registerUserBindCustomerService(info.getUserId(),
+                info.getFriendIds(), ClientEnum.valueOf(info.getClientType()));
 
         return succeed(ret > 0);
     }

+ 3 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/io/request/im/UserFriendInfoVO.java

@@ -22,6 +22,9 @@ public class UserFriendInfoVO implements Serializable {
     @ApiModelProperty(value = "新用户ID")
     private Long userId;
 
+    @ApiModelProperty("客户端类型")
+    private String clientType;
+
     @ApiModelProperty(value = "好友ID")
     private List<Long> friendIds;
 

+ 4 - 2
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/ImGroupMemberDao.java

@@ -2,6 +2,8 @@ package com.yonge.cooleshow.biz.dal.dao;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.yonge.cooleshow.biz.dal.entity.ImGroupMember;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
 import io.rong.models.group.GroupMember;
 import org.apache.ibatis.annotations.Param;
 
@@ -45,9 +47,9 @@ public interface ImGroupMemberDao extends BaseMapper<ImGroupMember> {
                                            @Param("userIds") Set<Long> userIds,
                                            @Param("roleType") String roleType);
 
-    ImGroupMember findByUserIdAndGroupId(@Param("userId") Long userId, @Param("groupId") String groupId);
+    ImGroupMember findByUserIdAndGroupId(@Param("userId") Long userId, @Param("groupId") String groupId, @Param("clientType") ClientEnum clientType);
 
     //删除群成员
-    int delByGroupIdAndUserId(@Param("groupId") String groupId, @Param("userId") Long userId);
+    int delByGroupIdAndUserId(@Param("groupId") String groupId, @Param("userId") Long userId, @Param("roleType") ImGroupMemberRoleType roleType);
 }
 

+ 2 - 2
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/ImNetworkRoomMemberDao.java

@@ -18,11 +18,11 @@ public interface ImNetworkRoomMemberDao extends BaseMapper<ImNetworkRoomMember>
 
     int insert(@Param("entity") ImNetworkRoomMember roomMember);
 
-    ImNetworkRoomMember findByRidAndUid(@Param("roomId") String roomId, @Param("userId") Long userId);
+    ImNetworkRoomMember findByRidAndUid(@Param("roomId") String roomId, @Param("userId") Long userId, @Param("userRole") Integer userRole);
 
     List<ImNetworkRoomMember> queryByRoomId(@Param("roomId") String roomId);
 
-    void delByRidAndUid(@Param("roomId") String roomId, @Param("userId") Long userId);
+    void delByRidAndUid(@Param("roomId") String roomId, @Param("userId") Long userId, @Param("userRole") Integer userRole);
 
     int countByRoomId(@Param("roomId") String roomId);
 

+ 11 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/BasicUserInfo.java

@@ -20,6 +20,9 @@ public class BasicUserInfo {
     @ApiModelProperty(value = "用户头像", required = true)
     private String avatar;
 
+    @ApiModelProperty("IM用户ID")
+    private String imUserId;
+
     public String getAvatar() {
         return avatar;
     }
@@ -51,4 +54,12 @@ public class BasicUserInfo {
     public void setRealName(String realName) {
         this.realName = realName;
     }
+
+    public String getImUserId() {
+        return imUserId;
+    }
+
+    public void setImUserId(String imUserId) {
+        this.imUserId = imUserId;
+    }
 }

+ 12 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImGroupSearchDto.java

@@ -1,6 +1,7 @@
 package com.yonge.cooleshow.biz.dal.dto;
 
 
+import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
 import io.swagger.annotations.ApiModelProperty;
 
 import javax.validation.constraints.NotNull;
@@ -19,6 +20,9 @@ public class ImGroupSearchDto {
     @ApiModelProperty(value = "创建人(群创建者)")
     private Long createUserId;
 
+    @ApiModelProperty(value = "群角色TEACHER老师、STUDENT学生")
+    private ImGroupMemberRoleType roleType;
+
     public String getType() {
         return type;
     }
@@ -50,5 +54,13 @@ public class ImGroupSearchDto {
     public void setUserId(Long userId) {
         this.userId = userId;
     }
+
+    public ImGroupMemberRoleType getRoleType() {
+        return roleType;
+    }
+
+    public void setRoleType(ImGroupMemberRoleType roleType) {
+        this.roleType = roleType;
+    }
 }
 

+ 12 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkBaseDto.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.dto;
 
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import io.swagger.annotations.ApiModelProperty;
 
 public class ImNetworkBaseDto {
@@ -7,6 +8,9 @@ public class ImNetworkBaseDto {
     @ApiModelProperty(value = "房间号(课程编号)",required = true)
     private Long roomId;
 
+    @ApiModelProperty("客户端类型 ")
+    private ClientEnum clientType;
+
     public Long getRoomId() {
         return roomId;
     }
@@ -14,4 +18,12 @@ public class ImNetworkBaseDto {
     public void setRoomId(Long roomId) {
         this.roomId = roomId;
     }
+
+    public ClientEnum getClientType() {
+        return clientType;
+    }
+
+    public void setClientType(ClientEnum clientType) {
+        this.clientType = clientType;
+    }
 }

+ 12 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkCustomMessage.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.dto;
 
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import io.rong.messages.BaseMessage;
 import io.swagger.annotations.ApiModelProperty;
 import org.apache.commons.lang3.StringUtils;
@@ -23,6 +24,9 @@ public class ImNetworkCustomMessage extends BaseMessage {
     @ApiModelProperty(value = "房间号(课程编号)",required = true)
     private Long roomId;
 
+    @ApiModelProperty("客户端类型")
+    private ClientEnum clientType;
+
     public Long getRoomId() {
         return roomId;
     }
@@ -71,6 +75,14 @@ public class ImNetworkCustomMessage extends BaseMessage {
         this.userId = userId;
     }
 
+    public ClientEnum getClientType() {
+        return clientType;
+    }
+
+    public void setClientType(ClientEnum clientType) {
+        this.clientType = clientType;
+    }
+
     @Override
     public String getType() {
         return "DY:PlayMidiMessage";

+ 16 - 4
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkDeviceControlDto.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.dto;
 
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.ImNetworkDeviceTypeEnum;
 import io.swagger.annotations.ApiModelProperty;
 
@@ -13,8 +14,8 @@ public class ImNetworkDeviceControlDto {
 	@ApiModelProperty(value = "房间号",required = true)
 	private String roomId;
 
-	@ApiModelProperty(value = "用户编号",required = true)
-	private Long userId;
+	@ApiModelProperty(value = "IM用户ID",required = true)
+	private String userId;
 
 	@ApiModelProperty(value = "ticket",required = true)
 	private String ticket;
@@ -31,6 +32,9 @@ public class ImNetworkDeviceControlDto {
 	@ApiModelProperty(value = "伴奏音量",required = true)
 	private Integer soundVolume = 100;
 
+	@ApiModelProperty("客户端类型 ")
+	private ClientEnum clientType;
+
 	public ImNetworkDeviceTypeEnum getDeviceType() {
 		return deviceType;
 	}
@@ -55,11 +59,11 @@ public class ImNetworkDeviceControlDto {
 		this.roomId = roomId;
 	}
 
-	public Long getUserId() {
+	public String getUserId() {
 		return userId;
 	}
 
-	public void setUserId(Long userId) {
+	public void setUserId(String userId) {
 		this.userId = userId;
 	}
 
@@ -102,4 +106,12 @@ public class ImNetworkDeviceControlDto {
 	public void setSoundVolume(Integer soundVolume) {
 		this.soundVolume = soundVolume;
 	}
+
+	public ClientEnum getClientType() {
+		return clientType;
+	}
+
+	public void setClientType(ClientEnum clientType) {
+		this.clientType = clientType;
+	}
 }

+ 12 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkDisplayDataDto.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.dto;
 
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.ImNetworkDisplayEnum;
 import io.swagger.annotations.ApiModelProperty;
 
@@ -17,6 +18,9 @@ public class ImNetworkDisplayDataDto {
 	@ApiModelProperty(value = "display uri",required = true)
     private String uri;
 
+	@ApiModelProperty("客户端类型 ")
+	private ClientEnum clientType;
+
 	public String getRoomId() {
 		return roomId;
 	}
@@ -49,6 +53,14 @@ public class ImNetworkDisplayDataDto {
 		this.uri = uri;
 	}
 
+	public ClientEnum getClientType() {
+		return clientType;
+	}
+
+	public void setClientType(ClientEnum clientType) {
+		this.clientType = clientType;
+	}
+
 	@Override
 	public String toString() {
 		return "ImNetworkDisplayDataDto{" +

+ 14 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkMusicSheetDto.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.dto;
 
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import io.swagger.annotations.ApiModelProperty;
 
 public class ImNetworkMusicSheetDto extends ImNetworkBaseDto{
@@ -10,6 +11,9 @@ public class ImNetworkMusicSheetDto extends ImNetworkBaseDto{
     @ApiModelProperty(value = "伴奏下载状态(1下载成功0下载中2下载失败)",required = true)
     private Integer status;
 
+    @ApiModelProperty("客户端类型 ")
+    private ClientEnum clientType;
+
     public Long getAccompanimentId() {
         return accompanimentId;
     }
@@ -27,6 +31,16 @@ public class ImNetworkMusicSheetDto extends ImNetworkBaseDto{
     }
 
     @Override
+    public ClientEnum getClientType() {
+        return clientType;
+    }
+
+    @Override
+    public void setClientType(ClientEnum clientType) {
+        this.clientType = clientType;
+    }
+
+    @Override
     public String toString() {
         return "ImNetworkMusicSheetDto{" +
                 "accompanimentId=" + accompanimentId +

+ 11 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ImGroupMember.java

@@ -56,6 +56,10 @@ public class ImGroupMember implements Serializable {
     @ApiModelProperty(value = "修改时间;")
     private Date updateTime;
 
+    @TableField(exist = false)
+    @ApiModelProperty(value = "IM用户ID")
+    private String imUserId;
+
     public ImGroupMember() {
     }
 
@@ -142,5 +146,12 @@ public class ImGroupMember implements Serializable {
         this.updateTime = updateTime;
     }
 
+    public String getImUserId() {
+        return imUserId;
+    }
+
+    public void setImUserId(String imUserId) {
+        this.imUserId = imUserId;
+    }
 }
 

+ 12 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ImNetworkRoomMember.java

@@ -72,6 +72,10 @@ public class ImNetworkRoomMember implements Serializable {
     @ApiModelProperty(value = "当前用户伴奏信息")
     private List<CourseScheduleStudentMusicSheetResult> musicSheetResults;
 
+    @TableField(exist = false)
+    @ApiModelProperty(value = "IM用户ID")
+    private String imUserId;
+
     public List<CourseScheduleStudentMusicSheetResult> getMusicSheetResults() {
         return musicSheetResults;
     }
@@ -175,5 +179,13 @@ public class ImNetworkRoomMember implements Serializable {
     public void setHandFlag(boolean handFlag) {
         this.handFlag = handFlag;
     }
+
+    public String getImUserId() {
+        return imUserId;
+    }
+
+    public void setImUserId(String imUserId) {
+        this.imUserId = imUserId;
+    }
 }
 

+ 42 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ImUserFriend.java

@@ -5,6 +5,7 @@ import java.util.Date;
 
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import com.baomidou.mybatisplus.annotation.TableId;
@@ -27,10 +28,22 @@ public class ImUserFriend implements Serializable {
     @ApiModelProperty(value = "当前用户编号")
     private Long userId;
 
+    @TableField("client_type_")
+    @ApiModelProperty(value = "客户端类型")
+    private ClientEnum clientType;
+
     @TableField("friend_id_")
     @ApiModelProperty(value = "好友编号")
     private Long friendId;
 
+    @TableField("friend_type_")
+    @ApiModelProperty(value = "好友身份")
+    private ClientEnum friendType;
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "融云好友编号")
+    private String imFriendId;
+
     @TableField("friend_avatar_")
     @ApiModelProperty(value = "好友头像")
     private String friendAvatar;
@@ -115,5 +128,34 @@ public class ImUserFriend implements Serializable {
         this.updateTime = updateTime;
     }
 
+    public String getImFriendId() {
+        return imFriendId;
+    }
+
+    public void setImFriendId(String imFriendId) {
+        this.imFriendId = imFriendId;
+    }
+
+    public ClientEnum getClientType() {
+        return clientType;
+    }
+
+    public void setClientType(ClientEnum clientType) {
+        this.clientType = clientType;
+    }
+
+
+    public ImUserFriend clientType(ClientEnum clientType) {
+        this.clientType = clientType;
+        return this;
+    }
+
+    public ClientEnum getFriendType() {
+        return friendType;
+    }
+
+    public void setFriendType(ClientEnum friendType) {
+        this.friendType = friendType;
+    }
 }
 

+ 9 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/ClientEnum.java

@@ -51,4 +51,13 @@ public enum ClientEnum implements BaseEnum<String, ClientEnum> {
 
         return true;
     }
+
+    /**
+     * 客户端类型匹配
+     * @param dataType 数据类型
+     * @return boolean
+     */
+    public boolean match(String dataType) {
+        return getCode().equals(dataType);
+    }
 }

+ 2 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImGroupMemberAuditService.java

@@ -21,11 +21,12 @@ public interface ImGroupMemberAuditService extends IService<ImGroupMemberAudit>
     /**
     * @description: 申请入群
      * @param imGroupMemberAudit
+     * @param autoJoin 自动加群
     * @return void
     * @author zx
     * @date 2022/3/22 17:34
     */
-    void apply(ImGroupMemberAudit imGroupMemberAudit) throws Exception;
+    void apply(ImGroupMemberAudit imGroupMemberAudit, Boolean autoJoin) throws Exception;
 
     /**
     * @description: 入群审核

+ 9 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImGroupMemberService.java

@@ -7,6 +7,7 @@ import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
 import io.rong.models.group.GroupMember;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -78,6 +79,13 @@ public interface ImGroupMemberService extends IService<ImGroupMember> {
     * @author zx
     * @date 2022/3/24 13:53
     */
-    ImGroupMember getUserDetail(Long userId, String groupId);
+    ImGroupMember getUserDetail(String userId, String groupId);
+
+    /**
+     * 群组成员信息
+     * @param params Map<String, Object>
+     * @return List<ImGroupMember>
+     */
+    List<ImGroupMember> findChatGroupAllMemberInfo(Map<String, Object> params);
 }
 

+ 11 - 3
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImGroupService.java

@@ -5,6 +5,7 @@ import com.yonge.cooleshow.biz.dal.dao.ImGroupDao;
 import com.yonge.cooleshow.biz.dal.dto.ImGroupResultDto;
 import com.yonge.cooleshow.biz.dal.dto.ImGroupSearchDto;
 import com.yonge.cooleshow.biz.dal.entity.ImGroup;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 
 import java.util.List;
 
@@ -69,13 +70,20 @@ public interface ImGroupService extends IService<ImGroup> {
      */
     ImGroup getByCourseGroupId(Long courseGroupId);
 
-    //退群
-    void quit(String groupId,Long userId) throws Exception;
-
     /**
      * 旧数据创建粉丝群
      */
     void setTeacherFansGroup() throws Exception;
 
+    //退群
+    void quit(String groupId, Long userId, ClientEnum clientType) throws Exception;
+
+    /**
+     * 用户群组信息
+     * @param groupId 群组ID
+     * @param userId 用户ID
+     * @return ImGroup
+     */
+    ImGroup findGroupInfoById(String groupId, Long userId);
 }
 

+ 5 - 4
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImNetworkRoomService.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.yonge.cooleshow.biz.dal.dao.ImNetworkRoomDao;
 import com.yonge.cooleshow.biz.dal.dto.*;
 import com.yonge.cooleshow.biz.dal.entity.ImNetworkRoom;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.UserRoleEnum;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 
@@ -20,16 +21,16 @@ public interface ImNetworkRoomService extends IService<ImNetworkRoom> {
     ImNetworkRoomDao getDao();
 
     //加入网络教室
-    HttpResponseResult<ImNetworkRoomResult> joinRoom(Long courseScheduleId) throws Exception;
+    HttpResponseResult<ImNetworkRoomResult> joinRoom(Long courseScheduleId, ClientEnum clientType) throws Exception;
 
     //加入网络教室成功
-    void joinRoomSuccess(String roomId,Long userId) throws Exception;
+    void joinRoomSuccess(String roomId, String imUserId) throws Exception;
 
     //加入网络教室失败
-    void joinRoomFailure(String roomId);
+    void joinRoomFailure(String roomId, ClientEnum clientType);
 
     //退出房间成功
-    void quitRoomSuccess(String roomId, Long userId) throws Exception;
+    void quitRoomSuccess(String roomId, String imUserId) throws Exception;
 
     //控制用户节拍器
     void sendImPlayMidiMessage(ImNetworkCustomMessage customMessage) throws Exception;

+ 15 - 2
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImUserFriendService.java

@@ -3,9 +3,12 @@ package com.yonge.cooleshow.biz.dal.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.yonge.cooleshow.biz.dal.dao.ImUserFriendDao;
 import com.yonge.cooleshow.biz.dal.entity.ImUserFriend;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.wrapper.im.CustomerService;
+import com.yonge.cooleshow.biz.dal.wrapper.im.ImUserWrapper;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -35,15 +38,16 @@ public interface ImUserFriendService extends IService<ImUserFriend> {
     * @author zx
     * @date 2022/3/24 12:03
     */
-    ImUserFriend getDetail(Long userId);
+    ImUserFriend getDetail(String userId, ClientEnum clientType);
 
     /**
      * 新用户自动添加客服
      * @param userId 新用户ID
      * @param friendIds 好友ID
+     * @param clientType 客户端类型
      * @return Integer
      */
-    Integer registerUserBindCustomerService(Long userId, List<Long> friendIds);
+    Integer registerUserBindCustomerService(Long userId, List<Long> friendIds, ClientEnum clientType);
 
     /**
      * 发送系统客服消息
@@ -51,5 +55,14 @@ public interface ImUserFriendService extends IService<ImUserFriend> {
      * @param info CustomerService.NotifyMessage
      */
     void sendCustomerServiceNotifyMessage(String sender, CustomerService.NotifyMessage info);
+
+    /**
+     * 用户IM好友列表
+     * @param clientType 客户端类型
+     * @param userId 用户ID
+     * @param paramMap Map<String, Object>
+     * @return List<ImUserWrapper.ImUserFriend>
+     */
+    List<ImUserWrapper.ImUserFriend> findUserAllImFriendInfo(ClientEnum clientType, Long userId, Map<String, Object> paramMap);
 }
 

+ 9 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseGroupServiceImpl.java

@@ -45,6 +45,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.text.MessageFormat;
 import java.time.LocalDate;
 import java.time.ZoneId;
 import java.util.*;
@@ -174,6 +175,14 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
         param.put("groupId", groupId);
         param.put("orderState", OrderStatusEnum.PAID.getCode());
         result.setStudentList(courseScheduleStudentPaymentService.queryStudentInfoByGroupId(param));
+
+        if (CollectionUtils.isNotEmpty(result.getStudentList())) {
+
+            for (LiveCourseInfoVo.CourseBuyStudentVo item : result.getStudentList()) {
+
+                item.setImUserId(MessageFormat.format("{0}:{1}", String.valueOf(item.getStudentId()), ClientEnum.STUDENT.name()));
+            }
+        }
         //查询是否购买过该课程组
         Long id = sysUser.getId();
 

+ 16 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseHomeworkServiceImpl.java

@@ -38,6 +38,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 
+import java.text.MessageFormat;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -103,6 +104,12 @@ public class CourseHomeworkServiceImpl extends ServiceImpl<CourseHomeworkDao, Co
         if (CollectionUtils.isEmpty(studentInfoList)) {
             studentInfoList = new ArrayList<>();
         }
+
+        for (CourseHomeworkVo item : studentInfoList) {
+
+            item.setImUserId(MessageFormat.format("{0}:{1}", String.valueOf(item.getStudentId()), ClientEnum.STUDENT.name()));
+        }
+
         Map<Long, List<CourseHomeworkVo>> studentCollect = studentInfoList.stream()
                 .collect(Collectors.groupingBy( CourseHomeworkVo::getCourseId));
 
@@ -111,6 +118,12 @@ public class CourseHomeworkServiceImpl extends ServiceImpl<CourseHomeworkDao, Co
         if (CollectionUtils.isEmpty(teacherInfoList)) {
             teacherInfoList = new ArrayList<>();
         }
+
+        for (CourseHomeworkVo item : teacherInfoList) {
+
+            item.setImUserId(String.valueOf(item.getTeacherId()));
+        }
+
         Map<Long, List<CourseHomeworkVo>> teacherCollect = teacherInfoList.stream()
                       .collect(Collectors.groupingBy( CourseHomeworkVo::getCourseId));
 
@@ -180,6 +193,9 @@ public class CourseHomeworkServiceImpl extends ServiceImpl<CourseHomeworkDao, Co
             throw  new BizException("未找到作业信息");
         }
 
+        // 设置用户IM聊天ID
+        courseHomeworkDetailVo.setImUserId(MessageFormat.format("{0}:{1}", String.valueOf(studentId), ClientEnum.STUDENT.name()));
+
         // 课程组的群聊
         ImGroup imGroup = imGroupService.getByCourseGroupId(courseHomeworkDetailVo.getCourseGroupId());
         if (imGroup != null) {

+ 45 - 2
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseScheduleServiceImpl.java

@@ -51,6 +51,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.text.MessageFormat;
 import java.text.SimpleDateFormat;
 import java.time.Instant;
 import java.time.LocalDate;
@@ -706,6 +707,12 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
         if (replied != null) {
             search.setStatus(CourseScheduleEnum.COMPLETE.getCode());
             List<MyCourseVo> list = baseMapper.queryTeacherPracticeCourse(page, monthToDate(search));
+
+            for (MyCourseVo item : list) {
+
+                item.setImUserId(MessageFormat.format("{0}:{1}", String.valueOf(item.getUserId()), ClientEnum.STUDENT.name()));
+            }
+
             if (replied == 0) {//未评价
                 return page.setRecords(list.stream().filter(s -> {
                     return s.getTeacherReplied() == 0;
@@ -719,7 +726,13 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
             }
         }
 
-        return page.setRecords(baseMapper.queryTeacherPracticeCourse(page, monthToDate(search)));
+        List<MyCourseVo> records = baseMapper.queryTeacherPracticeCourse(page, monthToDate(search));
+        for (MyCourseVo item : records) {
+
+            item.setImUserId(MessageFormat.format("{0}:{1}", String.valueOf(item.getUserId()), ClientEnum.STUDENT.name()));
+        }
+
+        return page.setRecords(records);
     }
 
     @Override
@@ -769,7 +782,19 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
      * @Date: 2022/4/13
      */
     public IPage<MyCourseVo> queryStudentPracticeCourse(IPage<MyCourseVo> page, MyCourseSearch search) {
-        return page.setRecords(baseMapper.queryStudentPracticeCourse(page, monthToDate(search)));
+
+        List<MyCourseVo> records = baseMapper.queryStudentPracticeCourse(page, monthToDate(search));
+
+        // 陪练课老师IM聊天ID
+        if (CollectionUtils.isNotEmpty(records)) {
+
+            for (MyCourseVo item : records) {
+
+                item.setImUserId(String.valueOf(item.getUserId()));
+            }
+        }
+
+        return page.setRecords(records);
     }
 
     @Override
@@ -813,6 +838,14 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
     public Map<String, Object> queryCourseUser(MyCourseSearch search) {
         List<CourseStudent> studentList = baseMapper.queryCourseUser(search);
 
+        if (CollectionUtils.isNotEmpty(studentList)) {
+
+            for (CourseStudent item : studentList) {
+
+                item.setImUserId(MessageFormat.format("{0}:{1}", item.getUserId(), ClientEnum.STUDENT.name()));
+            }
+        }
+
         Map<String, String> sysConfig = new HashMap<>();
         //提前XX分钟创建/进入陪练课房间时间
         sysConfig.put("practiceStartTime", sysConfigService.findConfigValue(SysConfigConstant.PRE_CREATE_PRACTICE_ROOM_MINUTE));
@@ -860,6 +893,16 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
      */
     public Map<String, Object> queryCourseTeacher(MyCourseSearch search) {
         List<CourseStudent> teacherList = baseMapper.queryCourseTeacher(search);
+
+        // 设置IM聊天用户ID
+        if (CollectionUtils.isNotEmpty(teacherList)) {
+
+            for (CourseStudent item : teacherList) {
+
+                item.setImUserId(item.getUserId());
+            }
+        }
+
         Map<String, String> sysConfig = new HashMap<>();
         //提前XX分钟创建/进入陪练课房间时间
         sysConfig.put("practiceStartTime", sysConfigService.findConfigValue(SysConfigConstant.PRE_CREATE_PRACTICE_ROOM_MINUTE));

+ 4 - 2
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImGroupMemberAuditServiceImpl.java

@@ -55,7 +55,7 @@ public class ImGroupMemberAuditServiceImpl extends ServiceImpl<ImGroupMemberAudi
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void apply(ImGroupMemberAudit imGroupMemberAudit) throws Exception {
+    public void apply(ImGroupMemberAudit imGroupMemberAudit, Boolean autoJoin) throws Exception {
         String groupId = imGroupMemberAudit.getGroupId();
         ImGroup imGroup = imGroupService.getById(groupId);
         if(Objects.isNull(imGroup)){
@@ -65,6 +65,7 @@ public class ImGroupMemberAuditServiceImpl extends ServiceImpl<ImGroupMemberAudi
         Map<String,Object> groupMemberParams = new HashMap<>(2);
         groupMemberParams.put("groupId",groupId);
         groupMemberParams.put("userId",imGroupMemberAudit.getUserId());
+        groupMemberParams.put("roleType",imGroupMemberAudit.getRoleType().getCode());
         if(Objects.nonNull(imGroupMemberService.getDao().findOne(groupMemberParams))){
             throw new BizException("您已经在群聊中,请勿重复添加");
         }
@@ -72,6 +73,7 @@ public class ImGroupMemberAuditServiceImpl extends ServiceImpl<ImGroupMemberAudi
         Map<String,Object> auditParams = new HashMap<>(3);
         auditParams.put("groupId",groupId);
         auditParams.put("userId",imGroupMemberAudit.getUserId());
+        groupMemberParams.put("roleType",imGroupMemberAudit.getRoleType().getCode());
         auditParams.put("auditStatus",AuditStatusEnum.AUDITING.getCode());
         if(Objects.nonNull(baseMapper.findOne(auditParams))){
             throw new BizException("您有待审核的申请,请勿重复提交");
@@ -82,7 +84,7 @@ public class ImGroupMemberAuditServiceImpl extends ServiceImpl<ImGroupMemberAudi
         imGroupMemberAudit.setUpdateTime(date);
         imGroupMemberAudit.setCreateTime(date);
         baseMapper.insert(imGroupMemberAudit);
-        if(imGroup.getAutoPassFlag()){
+        if(imGroup.getAutoPassFlag() && Optional.ofNullable(autoJoin).orElse(false)){
             //处理本地群成员
             List<GroupMember> groupMembers = imGroupMemberService.initGroupMember(imGroup.getId(),
                     imGroupMemberAudit.getUserId(), false,

+ 83 - 4
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImGroupMemberServiceImpl.java

@@ -1,12 +1,16 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.common.collect.Lists;
 import com.yonge.cooleshow.biz.dal.config.RongCloudConfig;
 import com.yonge.cooleshow.biz.dal.dao.ImGroupDao;
 import com.yonge.cooleshow.biz.dal.dao.ImGroupMemberDao;
 import com.yonge.cooleshow.biz.dal.dao.TeacherDao;
 import com.yonge.cooleshow.biz.dal.dto.BasicUserInfo;
 import com.yonge.cooleshow.biz.dal.entity.ImGroupMember;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
 import com.yonge.cooleshow.biz.dal.service.ImGroupMemberService;
 import com.yonge.toolset.base.exception.BizException;
@@ -20,6 +24,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
+import java.text.MessageFormat;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -66,7 +71,13 @@ public class ImGroupMemberServiceImpl extends ServiceImpl<ImGroupMemberDao, ImGr
         this.baseMapper.insert(imGroupMember);
         //加入融云群
         List<GroupMember> groupMemberList = new ArrayList<>();
-        groupMemberList.add(new GroupMember(userId.toString(),imGroupId,null));
+
+        String imUserId = String.valueOf(userId);
+        if (ImGroupMemberRoleType.STUDENT == roleType) {
+            imUserId = MessageFormat.format("{0}:{1}", imUserId, ClientEnum.STUDENT.name());
+        }
+
+        groupMemberList.add(new GroupMember(imUserId,imGroupId,null));
         return groupMemberList;
     }
 
@@ -76,9 +87,26 @@ public class ImGroupMemberServiceImpl extends ServiceImpl<ImGroupMemberDao, ImGr
         //记录群成员
         List<ImGroupMember> imGroupMembers = baseMapper.initImGroupMember(imGroupId,userIds,roleType.getCode());
         if(CollectionUtils.isNotEmpty(imGroupMembers)){
+
+            for (ImGroupMember item : imGroupMembers) {
+
+                // 用户身份
+                item.setRoleType(roleType);
+                // 管理员村识
+                item.setIsAdmin(ImGroupMemberRoleType.TEACHER == roleType);
+            }
             baseMapper.insertBatch(imGroupMembers);
+
             //加入融云群
-            Function<Long,GroupMember> func = (userId) -> new GroupMember(userId.toString(),imGroupId,null);
+            Function<Long,GroupMember> func = (userId) -> {
+
+                String imUserId = String.valueOf(userId);
+                if (ImGroupMemberRoleType.STUDENT == roleType) {
+                    imUserId = MessageFormat.format("{0}:{1}", imUserId, ClientEnum.STUDENT.name());
+                }
+
+                return  new GroupMember(imUserId,imGroupId,null);
+            };
             return userIds.stream().map(func).collect(Collectors.toList());
         }
         return new ArrayList<>();
@@ -106,8 +134,21 @@ public class ImGroupMemberServiceImpl extends ServiceImpl<ImGroupMemberDao, ImGr
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public ImGroupMember getUserDetail(Long userId, String groupId) {
-        ImGroupMember imGroupMember = baseMapper.findByUserIdAndGroupId(userId,groupId);
+    public ImGroupMember getUserDetail(String imUserId, String groupId) {
+
+        String[] values = imUserId.split(":");
+        // 用户ID
+        long userId = Long.parseLong(values[0]);
+
+        ClientEnum clientType = ClientEnum.TEACHER;
+        if (values.length > 1 && ClientEnum.STUDENT.match(values[1])) {
+            clientType = ClientEnum.STUDENT;
+        }
+
+        // 群组信息
+        ImGroupMember imGroupMember = baseMapper.findByUserIdAndGroupId(userId, groupId, clientType);
+
+        // 用户基本信息
         BasicUserInfo basicUserInfo = teacherDao.getBasicUserInfo(userId);
         if(Objects.isNull(imGroupMember)){
             imGroupMember = new ImGroupMember();
@@ -121,6 +162,10 @@ public class ImGroupMemberServiceImpl extends ServiceImpl<ImGroupMemberDao, ImGr
             imGroupMember.setUpdateTime(new Date());
             baseMapper.updateById(imGroupMember);
         }
+
+        // 设置IM好友ID
+        imGroupMember.setImUserId(imUserId);
+
         return imGroupMember;
     }
 
@@ -128,5 +173,39 @@ public class ImGroupMemberServiceImpl extends ServiceImpl<ImGroupMemberDao, ImGr
     public void startTransactional(Runnable runnable){
         runnable.run();
     }
+
+
+    /**
+     * 群组成员信息
+     *
+     * @param params Map<String, Object>
+     * @return List<ImGroupMember>
+     */
+    @Override
+    public List<ImGroupMember> findChatGroupAllMemberInfo(Map<String, Object> params) {
+
+        Object search = params.get("search");
+        List<ImGroupMember> members = getBaseMapper().selectList(Wrappers.<ImGroupMember>query().lambda()
+                .and(Objects.nonNull(search) && StringUtils.isNotEmpty(search.toString()),
+                        e->e.eq(ImGroupMember::getUserId, search).or()
+                                .like(ImGroupMember::getNickname, search))
+                .eq(ImGroupMember::getGroupId,params.get("groupId")).orderByDesc(ImGroupMember::getId));
+
+        if (CollectionUtils.isNotEmpty(members)) {
+
+            for (ImGroupMember item : members) {
+
+                item.setImUserId(String.valueOf(item.getUserId()));
+
+                if (ImGroupMemberRoleType.STUDENT == item.getRoleType()) {
+
+                    item.setImUserId(MessageFormat.format("{0}:{1}", String.valueOf(item.getUserId()),
+                            ClientEnum.STUDENT.getCode()));
+                }
+            }
+        }
+
+        return Optional.ofNullable(members).orElse(Lists.newArrayList());
+    }
 }
 

+ 104 - 7
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImGroupServiceImpl.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.google.common.collect.Lists;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.auth.config.AppGlobalServiceConfig;
 import com.yonge.cooleshow.biz.dal.config.RongCloudConfig;
 import com.yonge.cooleshow.biz.dal.dao.CourseScheduleStudentPaymentDao;
 import com.yonge.cooleshow.biz.dal.dao.ImGroupDao;
@@ -13,6 +14,8 @@ import com.yonge.cooleshow.biz.dal.dto.ImGroupSearchDto;
 import com.yonge.cooleshow.biz.dal.entity.CourseGroup;
 import com.yonge.cooleshow.biz.dal.entity.ImGroup;
 import com.yonge.cooleshow.biz.dal.entity.ImGroupMember;
+import com.yonge.cooleshow.biz.dal.entity.Teacher;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
 import com.yonge.cooleshow.biz.dal.enums.ImGroupType;
 import com.yonge.cooleshow.biz.dal.service.*;
@@ -34,6 +37,8 @@ import io.rong.models.Result;
 import io.rong.models.group.GroupMember;
 import io.rong.models.group.GroupModel;
 import org.apache.commons.collections.CollectionUtils;
+import org.redisson.api.RBucket;
+import org.redisson.api.RedissonClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -50,6 +55,7 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
 import java.util.stream.Collectors;
+import java.util.concurrent.TimeUnit;
 
 /**
  * 即时通讯群组(ImGroup)表服务实现类
@@ -72,8 +78,16 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
     private ImGroupMemberAuditDao imGroupMemberAuditDao;
     @Resource
     private SysUserService sysUserService;
+    @Autowired
+    private ImGroupService imGroupService;
+    @Autowired
+    private TeacherService teacherService;
     @Resource
     private CourseScheduleStudentPaymentDao courseScheduleStudentPaymentDao;
+    @Autowired
+    private AppGlobalServiceConfig appGlobalServiceConfig;
+    @Autowired
+    private RedissonClient redissonClient;
 
     @Autowired
     private SysUserFeignService sysUserFeignService;
@@ -81,9 +95,6 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
     @Autowired
     private StudentStarService studentStarService;
 
-    @Autowired
-    private TeacherService teacherService;
-
     @Override
     public ImGroupDao getDao() {
         return this.baseMapper;
@@ -138,10 +149,12 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
         imGroup.setId(imGroupId);
         imGroup.setCourseGroupId(courseGroupId);
         this.baseMapper.insert(imGroup);
-        //保存老师学员关联的通讯录
+        //保存老师学员关联的通讯录xz
         imUserFriendService.saveUserFriend(teacherId, studentIds);
         //处理本地群成员列表
+        // 添加老师
         List<GroupMember> groupMembers = imGroupMemberService.initGroupMember(imGroupId, imGroup.getCreateBy(), true, ImGroupMemberRoleType.TEACHER);
+        // 添加学生
         groupMembers.addAll(imGroupMemberService.initGroupMembers(imGroupId, studentIds, ImGroupMemberRoleType.STUDENT));
         //创建融云群
         this.rtcCreate(courseGroup.getTeacherId(), imGroupId, imGroup.getName());
@@ -213,14 +226,31 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void quit(String groupId, Long userId) throws Exception {
-        if(imGroupMemberService.getDao().delByGroupIdAndUserId(groupId, userId) < 1){
+    public void quit(String groupId, Long userId, ClientEnum clientType) throws Exception {
+
+        ImGroupMemberRoleType roleType = ImGroupMemberRoleType.valueOf(clientType.name());
+        // 查询群成员用户身份
+        ImGroupMember groupMember = imGroupMemberService.lambdaQuery()
+                .eq(ImGroupMember::getGroupId, groupId)
+                .eq(ImGroupMember::getUserId, userId)
+                .eq(ImGroupMember::getRoleType, roleType)
+                .one();
+
+        String imUserId = String.valueOf(userId);
+        if (Objects.nonNull(groupMember)
+                && ImGroupMemberRoleType.STUDENT == groupMember.getRoleType()) {
+
+            imUserId = MessageFormat.format("{0}:{1}", imUserId, ClientEnum.STUDENT.name());
+        }
+
+        if(imGroupMemberService.getDao().delByGroupIdAndUserId(groupId, userId, roleType) < 1){
             throw new BizException("操作失败:用户不在此群组");
         }
         //修改群成员数
         baseMapper.updateMemberNum(groupId);
+
         GroupModel groupModel = new GroupModel(groupId,0);
-        GroupMember[] groupMembers = new GroupMember[]{new GroupMember(userId.toString(),groupId,null)};
+        GroupMember[] groupMembers = new GroupMember[]{new GroupMember(imUserId,groupId,null)};
         groupModel.setMembers(groupMembers);
         Result result = RongCloudConfig.rongCloud.group.quit(groupModel);
         if(!result.code.equals(200)){
@@ -288,5 +318,72 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
 
     }
 
+    /**
+     * 用户群组信息
+     *
+     * @param groupId 群组ID
+     * @param userId  用户ID
+     * @return ImGroup
+     */
+    @Override
+    public ImGroup findGroupInfoById(String groupId, Long userId) {
+
+        ImGroup group = imGroupService.getById(groupId);
+
+        // 异步执行自动加入群组功能
+        ThreadPool.getExecutor().submit(() -> {
+            try {
+
+                if (Objects.nonNull(group) && appGlobalServiceConfig.getGroupMemberJoin()) {
+
+                    // 若用户群组存在,判定用户是否拥有老师身份,自动加入群组
+                    int count = teacherService.lambdaQuery().eq(Teacher::getUserId, userId).count();
+
+                    // 用户是否已加入该群组
+                    ImGroupMember groupMember = imGroupMemberService.lambdaQuery()
+                            .eq(ImGroupMember::getGroupId, groupId)
+                            .eq(ImGroupMember::getUserId, userId)
+                            .eq(ImGroupMember::getRoleType, ImGroupMemberRoleType.STUDENT)
+                            .one();
+
+                    if (Objects.nonNull(groupMember)) {
+
+                        String imIdentity = MessageFormat.format("{0}:{1}", String.valueOf(userId), ClientEnum.STUDENT.name());
+                        // 缓存用户重新入群标识
+                        String userKey = MessageFormat.format("{0}:{1}", groupId, imIdentity);
+                        RBucket<Object> bucket = redissonClient.getBucket(userKey);
+                        if (bucket.isExists()) {
+                            return;
+                        }
+
+                        // 自动加入该群组
+                        imGroupMemberService.join(Lists.newArrayList(new GroupMember(imIdentity, groupId, null)), groupId);
+
+                        Integer numbers = imGroupMemberService.lambdaQuery()
+                                .eq(ImGroupMember::getGroupId, groupId)
+                                .eq(ImGroupMember::getUserId, userId)
+                                .eq(ImGroupMember::getIsAdmin, true)
+                                .count();
+                        // 拥有老师身份,且非群主时,需要主动退出群聊
+                        if (count > 0 && numbers <= 0) {
+
+                            GroupModel groupModel = new GroupModel(groupId,0);
+                            GroupMember[] groupMembers = new GroupMember[]{new GroupMember(String.valueOf(userId), groupId,null)};
+                            groupModel.setMembers(groupMembers);
+                            RongCloudConfig.rongCloud.group.quit(groupModel);
+                        }
+
+                        // 缓存重新入群标识, 默认有效期为120天
+                        bucket.set(userKey, 120, TimeUnit.DAYS);
+                    }
+                }
+
+            } catch (Exception e) {
+                log.error("findGroupInfoById groupId={}, userId={}", group, userId, e);
+            }
+        });
+
+        return group;
+    }
 }
 

+ 11 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImNetworkRoomMemberServiceImpl.java

@@ -5,6 +5,7 @@ import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dao.ImNetworkRoomMemberDao;
 import com.yonge.cooleshow.biz.dal.dto.BasicUserInfo;
 import com.yonge.cooleshow.biz.dal.entity.ImNetworkRoomMember;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.UserRoleEnum;
 import com.yonge.cooleshow.biz.dal.service.ImNetworkRoomMemberService;
 import org.springframework.stereotype.Service;
@@ -13,6 +14,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.text.MessageFormat;
 import java.util.Date;
 import java.util.Objects;
 
@@ -35,7 +37,7 @@ public class ImNetworkRoomMemberServiceImpl extends ServiceImpl<ImNetworkRoomMem
     @Override
     @Transactional(rollbackFor = Exception.class)
     public ImNetworkRoomMember initRoomMember(String roomId, BasicUserInfo sysUser, UserRoleEnum userRole) {
-        ImNetworkRoomMember roomMember = baseMapper.findByRidAndUid(roomId, sysUser.getUserId());
+        ImNetworkRoomMember roomMember = baseMapper.findByRidAndUid(roomId, sysUser.getUserId(), userRole.ordinal());
         if(Objects.isNull(roomMember)){
             roomMember = new ImNetworkRoomMember();
             roomMember.setRoomId(roomId);
@@ -50,7 +52,15 @@ public class ImNetworkRoomMemberServiceImpl extends ServiceImpl<ImNetworkRoomMem
             roomMember.setAvatar(sysUser.getAvatar());
             roomMember.setCourseScheduleId(Long.parseLong(roomId));
             baseMapper.insert(roomMember);
+
+        }
+
+        String imUserId = String.valueOf(sysUser.getUserId());
+        if (UserRoleEnum.STUDENT == userRole) {
+            imUserId = MessageFormat.format("{0}:{1}", imUserId, ClientEnum.STUDENT.name());
         }
+        roomMember.setImUserId(imUserId);
+
         return roomMember;
     }
 

+ 194 - 47
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImNetworkRoomServiceImpl.java

@@ -13,6 +13,7 @@ import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.support.IMHelper;
 import com.yonge.cooleshow.common.constant.SysConfigConstant;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.cooleshow.common.enums.EStatus;
 import com.yonge.toolset.base.exception.BizException;
 import com.yonge.toolset.utils.date.DateUtil;
 import org.apache.commons.lang3.StringUtils;
@@ -25,6 +26,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
+import java.text.MessageFormat;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
@@ -74,12 +76,16 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public HttpResponseResult<ImNetworkRoomResult> joinRoom(Long courseScheduleId) throws Exception {
+    public HttpResponseResult<ImNetworkRoomResult> joinRoom(Long courseScheduleId, ClientEnum clientType) throws Exception {
+
+        // 当前登录用户ID
         Long userId = sysUserService.getUserId();
         CourseSchedule courseSchedule = Optional.ofNullable(courseScheduleService.getById(courseScheduleId)).
                 orElseThrow(()->new BizException("房间信息不存在"));
+
         UserRoleEnum userRole = UserRoleEnum.STUDENT;
-        if(courseSchedule.getTeacherId().equals(userId)){
+        if(courseSchedule.getTeacherId().equals(userId) && ClientEnum.TEACHER == clientType){
+            // 与老师帐号匹配,且来自老师客户端
             userRole = UserRoleEnum.TEACHER;
         }
         log.info("joinRoom params:courseScheduleId:{},userRole:{},userId:{}",courseScheduleId,userRole,userId);
@@ -104,6 +110,16 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
         joinRoomResult.setSurplusTime(DateUtil.secondsBetween(now, courseSchedule.getEndTime()));
         //获取房间所有成员
         List<ImNetworkRoomMember> roomMemberList = imNetworkRoomMemberService.getDao().queryByRoomId(roomId);
+        for (ImNetworkRoomMember item : roomMemberList) {
+            if (EStatus.ENABLE.match(item.getRole())) {
+                // 老师
+                item.setImUserId(String.valueOf(item.getUserId()));
+            } else {
+                // 学生
+                item.setImUserId(MessageFormat.format("{0}:{1}", String.valueOf(item.getUserId()), ClientEnum.STUDENT.name()));
+            }
+
+        }
         joinRoomResult.setRoomMemberList(roomMemberList);
         //如果是老师,重置节拍器数据
         if(userRole == UserRoleEnum.TEACHER){
@@ -112,12 +128,20 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
             setMusicSheetList(roomMemberList,courseScheduleId);
         }else {
             //获取节拍器信息
-            joinRoomResult.setMidiJson(courseScheduleStudentPaymentService.getMemberMidi(courseScheduleId,sysUser.getUserId()));
+            joinRoomResult.setMidiJson(courseScheduleStudentPaymentService.getMemberMidi(courseScheduleId, sysUser.getUserId()));
         }
         //课程结束后关闭教室的时间
         joinRoomResult.setAutoCloseNetworkRoomTime(sysConfigDao.findConfigValue(SysConfigConstant.DESTROY_EXPIRED_PRACTICE_ROOM_MINUTE));
+
+        // IM用户ID
+        String imUserId = sysUser.getUserId().toString();
+        if (UserRoleEnum.STUDENT == userRole) {
+            imUserId = MessageFormat.format("{0}:{1}", imUserId, ClientEnum.STUDENT.name());
+        }
+        roomMember.setImUserId(imUserId);
+
         //创建、加入群聊
-        IMApiResultInfo resultInfo = imHelper.joinGroup(new String[]{sysUser.getUserId().toString()}, roomId, roomId);
+        IMApiResultInfo resultInfo = imHelper.joinGroup(new String[]{imUserId}, roomId, roomId);
         if(resultInfo.getCode() != 200){
             log.error("加入群聊失败 resultInfo:{}",resultInfo);
         }
@@ -141,14 +165,29 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void joinRoomSuccess(String roomId,Long userId) throws Exception {
+    public void joinRoomSuccess(String roomId, String imUserId) throws Exception {
+
+        String[] values = imUserId.split(":");
+        // 用户ID
+        long userId = Long.parseLong(values[0]);
+
+        // 客户端类型
+        ClientEnum clientType = ClientEnum.TEACHER;
+        if (values.length > 1 && ClientEnum.STUDENT.match(values[1])) {
+
+            clientType = ClientEnum.STUDENT;
+        }
+
         log.info("joinRoomSuccess: roomId={}, userId={}", roomId, userId);
         CourseSchedule courseSchedule = Optional.ofNullable(courseScheduleService.getById(roomId)).
                 orElseThrow(()->new BizException("房间信息不存在"));
         BasicUserInfo sysUser = Optional.ofNullable(teacherDao.getBasicUserInfo(userId)).
                 orElseThrow(()-> new BizException("用户信息不存在"));
+
         UserRoleEnum userRole = UserRoleEnum.STUDENT;
-        if(Objects.equals(courseSchedule.getTeacherId(),userId)){
+        if(Objects.equals(courseSchedule.getTeacherId(),userId)
+                && ClientEnum.TEACHER == clientType){
+
             userRole = UserRoleEnum.TEACHER;
             teacherAttendanceService.signIn(userId,courseSchedule);
         }else {
@@ -159,10 +198,12 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
         ImNetworkRoom room = this.initRoom(roomId, Long.parseLong(roomId), userRole, userId, now);
         //获取房间用户信息
         ImNetworkRoomMember roomMember = imNetworkRoomMemberService.initRoomMember(roomId,sysUser,userRole);
+        // IM用户ID
+        roomMember.setImUserId(imUserId);
         //发送人员变动消息
         publishMemberChangedMessage(roomMember);
         //sendDisplay
-        this.sendDisplay(userId,room);
+        this.sendDisplay(imUserId, room);
     }
 
     //发送人员变动消息
@@ -174,20 +215,46 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
         //获取伴奏信息
         ImNetworkRoomMusicSheetDownloadData musicSheetDownloadData = courseScheduleStudentPaymentService.getMemberExamSong(Long.parseLong(roomMember.getRoomId()), roomMember.getUserId());
         msg.setExamSongSwitch(musicSheetDownloadData.getEnable());
-        imHelper.publishMessage(roomMember.getUserId().toString(), roomMember.getRoomId(), msg);
+        imHelper.publishMessage(roomMember.getImUserId(), roomMember.getRoomId(), msg);
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void joinRoomFailure(String roomId) {
+    public void joinRoomFailure(String roomId, ClientEnum clientType) {
+
+        // 当前登录用户ID
         Long userId = sysUserService.getUserId();
         log.info("joinRoomFailure: roomId={}, userId={}", roomId, userId);
-        imNetworkRoomMemberService.getDao().delByRidAndUid(roomId, userId);
+
+        // 网络教室用户身份
+        UserRoleEnum userRole = UserRoleEnum.TEACHER;
+        if (ClientEnum.STUDENT == clientType) {
+            userRole = UserRoleEnum.STUDENT;
+        }
+
+        // 删除网络教室学员
+        imNetworkRoomMemberService.getDao().delByRidAndUid(roomId, userId, userRole.ordinal());
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void quitRoomSuccess(String roomId, Long userId) throws Exception {
+    public void quitRoomSuccess(String roomId, String imUserId) throws Exception {
+
+        String[] values = imUserId.split(":");
+        // 用户ID
+        long userId = Long.parseLong(values[0]);
+
+
+        // 客户端类型
+        UserRoleEnum userRole = UserRoleEnum.TEACHER;
+        ClientEnum clientType = ClientEnum.TEACHER;
+        if (values.length > 1 && ClientEnum.STUDENT.match(values[1])) {
+
+            clientType = ClientEnum.STUDENT;
+
+            userRole = UserRoleEnum.STUDENT;
+        }
+
         log.info("quitRoomSuccess: roomId={}, userId={}", roomId, userId);
         //防止幂等
         StringBuffer sb  = new StringBuffer(QUIT_ROOM_SUCCESS).append(roomId).append(userId);
@@ -195,15 +262,21 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
             log.info("quitRoomSuccess break: roomId={}, userId={}", roomId, userId);
             return;
         }
-        ImNetworkRoomMember roomMember = imNetworkRoomMemberService.getDao().findByRidAndUid(roomId, userId);
+
+        ImNetworkRoomMember roomMember = imNetworkRoomMemberService.getDao().findByRidAndUid(roomId, userId, userRole.ordinal());
         if(Objects.isNull(roomMember)){
             return;
         }
+        // 设置IM用户ID
+        roomMember.setImUserId(imUserId);
+
         CourseSchedule courseSchedule = Optional.ofNullable(courseScheduleService.getById(roomId))
                 .orElseThrow(()->new BizException("房间信息不存在"));
         Long courseScheduleId = courseSchedule.getId();
         UserRoleEnum roleEnum = UserRoleEnum.STUDENT;
-        if(Objects.equals(courseSchedule.getTeacherId(),userId)){
+        if(Objects.equals(courseSchedule.getTeacherId(),userId)
+                && ClientEnum.TEACHER == clientType){
+
             roleEnum = UserRoleEnum.TEACHER;
             teacherAttendanceService.signOut(userId,courseSchedule);
         }else {
@@ -218,20 +291,20 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
             courseScheduleStudentPaymentService.getDao().adjustExamSong(courseScheduleId, null, null);
             if (isUserDisplay(room.getDisplay(), userId)) {
                 room.setDisplay("");
-                this.updateDisplay(userId,room);
+                this.updateDisplay(imUserId,room);
             }
             //老师退出房间,初始化节拍器和伴奏播放配置
             courseScheduleStudentPaymentService.adjustPlayMidiAndMusicSheet(courseSchedule.getId(), null, null,"");
         }
         int memberNum = imNetworkRoomMemberService.getDao().countByRoomId(roomId);
         if (memberNum <= 1) {
-            imHelper.dismiss(userId.toString(), roomId);
+            imHelper.dismiss(imUserId, roomId);
             courseScheduleStudentMusicSheetService.getDao().closePlayStatus(courseSchedule.getId(),null);
             log.info("leaveRoomSuccess dismiss the room: {},userId: {}", roomId, userId);
         } else {
             ImNetworkRoomMemberChangedMessage msg = new ImNetworkRoomMemberChangedMessage(roomMember,ImNetworkRoomMemberChangedEnum.LEAVE);
-            imHelper.publishMessage(userId.toString(), roomId, msg);
-            imHelper.quit(new String[]{userId.toString()}, roomId);
+            imHelper.publishMessage(imUserId, roomId, msg);
+            imHelper.quit(new String[]{imUserId}, roomId);
             log.info("leaveRoomSuccess quit group: roomId={},userId: {}", roomId, userId);
         }
         //删房间用户信息
@@ -245,9 +318,19 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
         Long roomId = customMessage.getRoomId();
         log.info("sendImPlayMidiMessage: roomId={}, userId={}", roomId, userId);
         ImNetworkMetronomeMessage displayMessage = new ImNetworkMetronomeMessage(customMessage);
-        imHelper.publishMessage(userId.toString(), roomId.toString(), displayMessage, 1);
+
+        String imUserId = String.valueOf(userId);
+        if (ClientEnum.STUDENT == customMessage.getClientType()) {
+            imUserId = MessageFormat.format("{0}:{1}", imUserId, ClientEnum.STUDENT.name());
+        }
+        // 用户ID
+        imHelper.publishMessage(imUserId, roomId.toString(), displayMessage, 1);
+
         //记录节拍器信息
-        courseScheduleStudentPaymentService.getDao().adjustPlayMidi(roomId,customMessage.getUserId(),customMessage.toString());
+        String collect = Arrays.stream(customMessage.getUserId().split(","))
+                .map(x -> x.split(":")[0]).collect(Collectors.joining(","));
+
+        courseScheduleStudentPaymentService.getDao().adjustPlayMidi(roomId, collect, customMessage.toString());
     }
 
     @Override
@@ -284,7 +367,14 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
         }
         ImNetworkMusicSheetDownloadMessage msg = new ImNetworkMusicSheetDownloadMessage(
                 JSON.parseObject(JSON.toJSONString(accompaniment), ImNetworkMusicSheetDownloadMessageContent.class));
-        imHelper.publishMessage(userId.toString(), courseScheduleId.toString(), msg, 0);
+
+        // IM用户ID
+        String imUserId = String.valueOf(userId);
+        if (ClientEnum.STUDENT == musicSheetDto.getClientType()) {
+            imUserId = MessageFormat.format("{0}:{1}", imUserId, ClientEnum.STUDENT.name());
+        }
+
+        imHelper.publishMessage(imUserId, courseScheduleId.toString(), msg, 0);
     }
 
     @Override
@@ -317,14 +407,20 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
         }
         ImNetworkRoom room = baseMapper.findByRoomId(displayData.getRoomId());
         room.setDisplay(display.toString());
-        this.updateDisplay(userId,room);
+
+        String imUserId = String.valueOf(userId);
+        if (ClientEnum.STUDENT == displayData.getClientType()) {
+            imUserId = MessageFormat.format("{0}:{1}", imUserId, ClientEnum.STUDENT.name());
+        }
+
+        this.updateDisplay(imUserId,room);
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void batchControlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception {
         ImNetworkDeviceTypeEnum deviceType = deviceControl.getDeviceType();
-        if (deviceControl.getUserId() != null) {
+        if (StringUtils.isNotEmpty(deviceControl.getUserId())) {
             controlDevice(deviceControl);
         } else {
             if (deviceType == ImNetworkDeviceTypeEnum.EXAM_SONG ||
@@ -333,15 +429,15 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
                 List<CourseScheduleStudentPayment> studentPayments = courseScheduleStudentPaymentService.getDao().queryByCourseId(Long.parseLong(deviceControl.getRoomId()));
 
                 for (CourseScheduleStudentPayment studentPayment : studentPayments) {
-                    deviceControl.setUserId(studentPayment.getUserId());
+                    deviceControl.setUserId(MessageFormat.format("{0}:{1}", String.valueOf(studentPayment.getUserId()), ClientEnum.STUDENT.name()));
                     controlDevice(deviceControl);
                 }
-                return;
+
             }else {
                 List<ImNetworkRoomMember> roomMembers = imNetworkRoomMemberService.getDao().findByRoomAndRole(deviceControl.getRoomId(), 0);
                 if (!CollectionUtils.isEmpty(roomMembers)) {
                     for (ImNetworkRoomMember roomMember : roomMembers) {
-                        deviceControl.setUserId(roomMember.getUserId());
+                        deviceControl.setUserId(MessageFormat.format("{0}:{1}", String.valueOf(roomMember.getUserId()), ClientEnum.STUDENT.name()));
                         controlDevice(deviceControl);
                     }
                 }
@@ -352,21 +448,34 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void controlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception {
+        // 老师信息
         SysUser sysUser = sysUserService.getUser();
         String roomId = deviceControl.getRoomId();
-        Long userId = deviceControl.getUserId();
+
+        String[] values = deviceControl.getUserId().split(":");
+        // 学生信息
+        Long userId = Long.parseLong(values[0]);
         Boolean enable = deviceControl.getEnable();
         log.info("controlDevice: roomId:{} ,deviceType:{} ,enable:{} ,userId:{}", roomId,deviceControl.getDeviceType(),enable,userId);
+
+        UserRoleEnum userRole = UserRoleEnum.TEACHER;
+        if (values.length > 1 && ClientEnum.STUDENT.match(values[1])) {
+
+            userRole = UserRoleEnum.STUDENT;
+        }
+        // IM用户ID
+        String imUserId = deviceControl.getUserId();
+
         if(enable){
             long scheduleId = Long.parseLong(roomId);
             ImNetworkDeviceStateChangedMessage deviceResourceMessage = new ImNetworkDeviceStateChangedMessage(deviceControl.getDeviceType().ordinal(),enable);
-            deviceResourceMessage.setUserId(userId.toString());
+            deviceResourceMessage.setUserId(imUserId);
             switch (deviceControl.getDeviceType()) {
                 case EXAM_SONG:
                     ImNetworkRoomMusicSheetDownloadData msg = courseScheduleStudentPaymentService.getMemberExamSong(scheduleId, userId);
                     msg.setEnable(enable);
                     courseScheduleStudentPaymentService.getDao().adjustExamSong(scheduleId,userId, JSON.toJSONString(msg));
-                    imHelper.publishMessage(userId.toString(), roomId, deviceResourceMessage, 1);
+                    imHelper.publishMessage(imUserId, roomId, deviceResourceMessage, 1);
                     break;
                 case MUSIC_SHEET:
                     Integer musicSheetId = Optional.ofNullable(deviceControl.getMusicSheetAccompanimentId()).
@@ -376,7 +485,7 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
                     //打开原音
                     courseScheduleStudentMusicSheetService.getDao().openPlayStatus(scheduleId,musicSheetId,userId);
                     deviceResourceMessage.setMusicSheetAccompanimentId(musicSheetId);
-                    deviceResourceMessage.setUserId(userId.toString());
+                    deviceResourceMessage.setUserId(imUserId);
                     deviceResourceMessage.setSoundVolume(deviceControl.getSoundVolume());
                     imHelper.publishMessage(sysUser.getId().toString(), roomId, deviceResourceMessage, 1);
                     break;
@@ -388,7 +497,7 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
                     //打开伴奏
                     courseScheduleStudentMusicSheetService.getDao().openAccompanimentPlayStatus(scheduleId,musicSheetAccompanimentId,userId);
                     deviceResourceMessage.setMusicSheetAccompanimentId(musicSheetAccompanimentId);
-                    deviceResourceMessage.setUserId(userId.toString());
+                    deviceResourceMessage.setUserId(imUserId);
                     deviceResourceMessage.setSoundVolume(deviceControl.getSoundVolume());
                     imHelper.publishMessage(sysUser.getId().toString(), roomId, deviceResourceMessage, 1);
                     break;
@@ -398,11 +507,11 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
                     message.setType(deviceControl.getDeviceType().ordinal());
                     message.setOpUserId(sysUser.getId().toString());
                     message.setOpUserName(sysUser.getUsername());
-                    imHelper.publishMessage(sysUser.getId().toString(), userId.toString(), roomId, message);
+                    imHelper.publishMessage(sysUser.getId().toString(), imUserId, roomId, message);
                     break;
             }
         }else {
-            ImNetworkRoomMember roomMember = Optional.ofNullable(imNetworkRoomMemberService.getDao().findByRidAndUid(roomId, userId))
+            ImNetworkRoomMember roomMember = Optional.ofNullable(imNetworkRoomMemberService.getDao().findByRidAndUid(roomId, userId, userRole.ordinal()))
                     .orElseThrow(()-> new BizException("用户不在房间内"));
             long scheduleId = Long.parseLong(roomId);
             switch (deviceControl.getDeviceType()) {
@@ -435,7 +544,7 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
                 imNetworkRoomMemberService.getDao().updateById(roomMember);
             }
             ImNetworkDeviceStateChangedMessage deviceResourceMessage = new ImNetworkDeviceStateChangedMessage(deviceControl.getDeviceType().ordinal(),deviceControl.getEnable());
-            deviceResourceMessage.setUserId(userId.toString());
+            deviceResourceMessage.setUserId(imUserId);
             BasicUserInfo basicUserInfo = teacherDao.getBasicUserInfo(userId);
             if (Objects.nonNull(basicUserInfo)) {
                 deviceResourceMessage.setUserName(basicUserInfo.getUsername());
@@ -449,7 +558,17 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
     public void approveControlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception {
         log.info("approveControlDevice: roomId:{} ,deviceType:{} ,enable:{}", deviceControl.getRoomId(),deviceControl.getDeviceType(),deviceControl.getEnable());
         SysUser sysUser = sysUserService.getUser();
-        ImNetworkRoomMember roomMember = Optional.ofNullable(imNetworkRoomMemberService.getDao().findByRidAndUid(deviceControl.getRoomId(), sysUser.getId())).
+
+        String imUserId = String.valueOf(sysUser.getId());
+        UserRoleEnum userRole = UserRoleEnum.TEACHER;
+        if (ClientEnum.STUDENT == deviceControl.getClientType()) {
+            imUserId = MessageFormat.format("{0}:{1}", imUserId, ClientEnum.STUDENT.name());
+
+            userRole = UserRoleEnum.STUDENT;
+        }
+
+        ImNetworkRoomMember roomMember = Optional.ofNullable(imNetworkRoomMemberService.getDao().findByRidAndUid(deviceControl.getRoomId(), sysUser.getId(),
+                        userRole.ordinal())).
                 orElseThrow(()-> new BizException("用户不在房间内"));
         switch (deviceControl.getDeviceType()) {
             case CAMERA:
@@ -477,10 +596,10 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
         Long teacherId = Optional.ofNullable(courseScheduleService.getById(deviceControl.getRoomId())).
                 map(CourseSchedule::getTeacherId).
                 orElseThrow(()->new BizException("房间信息不存在"));
-        imHelper.publishMessage(sysUser.getId().toString(),teacherId.toString(), deviceControl.getRoomId(), msg);
+        imHelper.publishMessage(imUserId, teacherId.toString(), deviceControl.getRoomId(), msg);
 
         //发送设备状态变更消息
-        this.sendDeviceStateChangedMessage(deviceControl, sysUser.getId());
+        this.sendDeviceStateChangedMessage(deviceControl, imUserId);
     }
 
     @Override
@@ -488,9 +607,18 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
     public void deviceStatusSync(ImNetworkDeviceControlDto deviceStatusSync) throws Exception {
         log.info("deviceStatusSync: enable:{} ,roomId:{} ,deviceType:{}", deviceStatusSync.getEnable(),deviceStatusSync.getRoomId(),deviceStatusSync.getDeviceType());
         Long userId = sysUserService.getUserId();
+
+        UserRoleEnum userRole = UserRoleEnum.TEACHER;
+        String imUserId = String.valueOf(userId);
+        if (ClientEnum.STUDENT == deviceStatusSync.getClientType()) {
+            imUserId = MessageFormat.format("{0}:{1}", imUserId, ClientEnum.STUDENT.name());
+
+            userRole = UserRoleEnum.STUDENT;
+        }
+
         ImNetworkDeviceTypeEnum deviceType = deviceStatusSync.getDeviceType();
         ImNetworkRoomMember roomMember = Optional.ofNullable(imNetworkRoomMemberService.getDao().
-                        findByRidAndUid(deviceStatusSync.getRoomId(), userId))
+                        findByRidAndUid(deviceStatusSync.getRoomId(), userId, userRole.ordinal()))
                 .orElseThrow(()-> new BizException("用户不在房间内"));
         switch (deviceType) {
             case CAMERA:
@@ -519,21 +647,30 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
             imNetworkRoomMemberService.getDao().updateById(roomMember);
         }
         //发送设备状态同步消息
-        this.sendDeviceStateChangedMessage(deviceStatusSync,userId);
+        this.sendDeviceStateChangedMessage(deviceStatusSync, imUserId);
     }
 
     @Override
     public List<BasicUserInfo> queryNoJoinStu(Long roomId) {
-        return courseScheduleStudentPaymentService.getDao().queryNoJoinStu(roomId);
+
+        List<BasicUserInfo> userInfos = courseScheduleStudentPaymentService.getDao().queryNoJoinStu(roomId);
+
+        for (BasicUserInfo item : userInfos) {
+
+            item.setImUserId(MessageFormat.format("{0}:{1}", String.valueOf(item.getUserId()),
+                    ClientEnum.STUDENT.name()));
+        }
+
+        return userInfos;
     }
 
     //发送设备状态同步消息
-    private void sendDeviceStateChangedMessage(ImNetworkDeviceControlDto deviceStatusSync,Long userId) throws Exception {
+    private void sendDeviceStateChangedMessage(ImNetworkDeviceControlDto deviceStatusSync,String imUserId) throws Exception {
         ImNetworkRoom room = baseMapper.findByRoomId(deviceStatusSync.getRoomId());
         ImNetworkDeviceStateChangedMessage deviceResourceMessage = new ImNetworkDeviceStateChangedMessage(deviceStatusSync.getDeviceType().ordinal(),deviceStatusSync.getEnable());
-        deviceResourceMessage.setUserId(userId.toString());
+        deviceResourceMessage.setUserId(imUserId);
         deviceResourceMessage.setSoundVolume(room.getSoundVolume());
-        imHelper.publishMessage(userId.toString(), deviceStatusSync.getRoomId(), deviceResourceMessage, 1);
+        imHelper.publishMessage(imUserId, deviceStatusSync.getRoomId(), deviceResourceMessage, 1);
     }
 
     @Override
@@ -573,7 +710,14 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
         //给老师发送学员曲目下载状态
         CourseSchedule courseSchedule = courseScheduleService.getById(roomId);
         ImNetworkMusicSheetDownloadStatusMessage statusMessage = new ImNetworkMusicSheetDownloadStatusMessage(status,studentMusicSheetResults);
-        imHelper.publishMessage(userId.toString(), courseSchedule.getTeacherId().toString(), roomId.toString(), statusMessage);
+
+        // IM用户ID
+        String imUserId = String.valueOf(userId);
+        if (ClientEnum.STUDENT == musicSheetDto.getClientType()) {
+            imUserId = MessageFormat.format("{0}:{1}", imUserId, ClientEnum.STUDENT.name());
+        }
+
+        imHelper.publishMessage(imUserId, courseSchedule.getTeacherId().toString(), roomId.toString(), statusMessage);
     }
 
     //校验用户是否提前进入教室
@@ -616,15 +760,18 @@ public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNe
     }
 
     //修改节拍器
-    public void updateDisplay(Long userId,ImNetworkRoom room) throws Exception {
+    public void updateDisplay(String imUserId,ImNetworkRoom room) throws Exception {
         baseMapper.updateById(room);
-        this.sendDisplay(userId,room);
+
+        // IM发送用户消息
+        this.sendDisplay(imUserId,room);
     }
 
-    public void sendDisplay(Long userId,ImNetworkRoom room) throws Exception {
+    public void sendDisplay(String imUserId,ImNetworkRoom room) throws Exception {
         //发送display改动通知
         ImNetworkDisplayMessage displayMessage = new ImNetworkDisplayMessage(room.getDisplay());
-        imHelper.publishMessage(userId.toString(), room.getRoomId(), displayMessage, 0);
+
+        imHelper.publishMessage(imUserId, room.getRoomId(), displayMessage, 0);
     }
 
     public boolean isUserDisplay(String display, Long userId) {

+ 116 - 15
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImUserFriendServiceImpl.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -13,15 +14,15 @@ import com.yonge.cooleshow.biz.dal.dao.ImUserFriendDao;
 import com.yonge.cooleshow.biz.dal.dao.TeacherDao;
 import com.yonge.cooleshow.biz.dal.dto.BasicUserInfo;
 import com.yonge.cooleshow.biz.dal.entity.ImUserFriend;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.MK;
 import com.yonge.cooleshow.biz.dal.mapper.SysUserMapper;
 import com.yonge.cooleshow.biz.dal.service.ImUserFriendService;
 import com.yonge.cooleshow.biz.dal.wrapper.im.CustomerService;
+import com.yonge.cooleshow.biz.dal.wrapper.im.ImUserWrapper;
 import com.yonge.toolset.base.exception.BizException;
 import io.rong.messages.BaseMessage;
-import io.rong.messages.FileMessage;
 import io.rong.messages.ImgMessage;
-import io.rong.messages.ImgTextMessage;
 import io.rong.messages.TxtMessage;
 import io.rong.models.message.PrivateMessage;
 import io.rong.models.message.PushExt;
@@ -41,11 +42,13 @@ import java.awt.image.BufferedImage;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.net.URL;
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -67,6 +70,8 @@ public class ImUserFriendServiceImpl extends ServiceImpl<ImUserFriendDao, ImUser
     private CustomerServiceConfig customerServiceConfig;
     @Autowired
     private SysUserMapper sysUserMapper;
+    @Autowired
+    private ImUserFriendService imUserFriendService;
 
     @Override
     public ImUserFriendDao getDao() {
@@ -79,10 +84,10 @@ public class ImUserFriendServiceImpl extends ServiceImpl<ImUserFriendDao, ImUser
         Date now = new Date();
         //老师添加学员联系人
         List<ImUserFriend> imUserFriends = new ArrayList<>();
-        BasicUserInfo basicUserInfo = teacherDao.getBasicUserInfo(teacherId);
-        List<BasicUserInfo> basicUserInfoList = teacherDao.findBasicUserInfo(studentIds);
-        basicUserInfoList.add(basicUserInfo);
-        Map<Long, List<BasicUserInfo>> basicUserInfoMap = basicUserInfoList.stream().collect(Collectors.groupingBy(BasicUserInfo::getUserId));
+        BasicUserInfo teacherInfo = teacherDao.getBasicUserInfo(teacherId);
+        List<BasicUserInfo> studentInfos = teacherDao.findBasicUserInfo(studentIds);
+        studentInfos.add(teacherInfo);
+        Map<Long, List<BasicUserInfo>> basicUserInfoMap = studentInfos.stream().collect(Collectors.groupingBy(BasicUserInfo::getUserId));
         for(Long studentId : studentIds){
             //老师关联学员
             ImUserFriend teacherFriend = new ImUserFriend();
@@ -93,15 +98,20 @@ public class ImUserFriendServiceImpl extends ServiceImpl<ImUserFriendDao, ImUser
                 BasicUserInfo info = basicUserInfos.get(0);
                 teacherFriend.setFriendAvatar(info.getAvatar());
                 teacherFriend.setFriendNickname(info.getUsername());
-                studentFriend.setFriendAvatar(basicUserInfo.getAvatar());
-                studentFriend.setFriendNickname(basicUserInfo.getUsername());
+
+                studentFriend.setFriendAvatar(teacherInfo.getAvatar());
+                studentFriend.setFriendNickname(teacherInfo.getUsername());
             }
+            teacherFriend.setClientType(ClientEnum.TEACHER);
             teacherFriend.setFriendId(studentId);
+            teacherFriend.setFriendType(ClientEnum.STUDENT);
             teacherFriend.setUserId(teacherId);
             teacherFriend.setCreateTime(now);
             teacherFriend.setUpdateTime(now);
 
+            studentFriend.setClientType(ClientEnum.STUDENT);
             studentFriend.setFriendId(teacherId);
+            studentFriend.setFriendType(ClientEnum.TEACHER);
             studentFriend.setUserId(studentId);
             studentFriend.setCreateTime(now);
             studentFriend.setUpdateTime(now);
@@ -113,24 +123,49 @@ public class ImUserFriendServiceImpl extends ServiceImpl<ImUserFriendDao, ImUser
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public ImUserFriend getDetail(Long userId) {
+    public ImUserFriend getDetail(String imUserId, ClientEnum clientType) {
+
+        String[] values = imUserId.split(":");
+        // 用户ID
+        long userId = Long.parseLong(values[0]);
+
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         BasicUserInfo basicUserInfo = teacherDao.getBasicUserInfo(userId);
         if(sysUser != null && sysUser.getId() != null){
-            ImUserFriend imUserFriend = baseMapper.findByUserIdAndFriendId(sysUser.getId(),userId);
+
+            ImUserFriend imUserFriend = lambdaQuery()
+                    .eq(ImUserFriend::getUserId, sysUser.getId())
+                    .eq(ImUserFriend::getClientType, clientType)
+                    .eq(ImUserFriend::getFriendId, userId)
+                    .one();
             if(Objects.nonNull(imUserFriend)){
                 //更新当前用户关联的该用户的详情信息
                 imUserFriend.setFriendAvatar(basicUserInfo.getAvatar());
                 imUserFriend.setFriendNickname(basicUserInfo.getUsername());
                 imUserFriend.setUpdateTime(new Date());
                 baseMapper.updateById(imUserFriend);
+
+                // 设置融云IM好友ID
+                imUserFriend.setImFriendId(imUserId);
+
                 return imUserFriend;
             }
         }
+
+        // 好友身份类型
+        ClientEnum friendType = ClientEnum.TEACHER;
+        if (values.length > 1 && ClientEnum.STUDENT.match(values[1])) {
+            friendType = ClientEnum.STUDENT;
+        }
+        // 返回当前登录用户信息
         ImUserFriend imUserFriend = new ImUserFriend();
         imUserFriend.setFriendAvatar(basicUserInfo.getAvatar());
         imUserFriend.setFriendNickname(basicUserInfo.getUsername());
         imUserFriend.setFriendId(userId);
+        imUserFriend.setFriendType(friendType);
+        // 设置融云IM好友ID
+        imUserFriend.setImFriendId(imUserId);
+
         return imUserFriend;
     }
 
@@ -139,13 +174,29 @@ public class ImUserFriendServiceImpl extends ServiceImpl<ImUserFriendDao, ImUser
      *
      * @param userId    新用户ID
      * @param friendIds 好友ID
+     * @param clientType 客户端类型
      * @return Integer
      */
     @Override
-    public Integer registerUserBindCustomerService(Long userId, List<Long> friendIds) {
+    public Integer registerUserBindCustomerService(Long userId, List<Long> friendIds, ClientEnum clientType) {
+
+        // 添加新用户好友,客服默认为老师身份
+        for (Long teacherId : friendIds) {
+
+            saveUserFriend(teacherId, Sets.newHashSet(userId));
 
-        // 添加新用户好友
-        saveUserFriend(userId, Sets.newHashSet(friendIds));
+            // 新注册用户为老师身份时,更新好友关系为老师身份
+            if (ClientEnum.TEACHER == clientType) {
+
+                imUserFriendService.lambdaUpdate()
+                        .eq(ImUserFriend::getUserId, userId)
+                        .eq(ImUserFriend::getClientType, ClientEnum.STUDENT)
+                        .eq(ImUserFriend::getFriendId, teacherId)
+                        .eq(ImUserFriend::getFriendType, ClientEnum.TEACHER)
+                        .set(ImUserFriend::getClientType, ClientEnum.TEACHER)
+                        .update();
+            }
+        }
 
         try {
 
@@ -169,10 +220,14 @@ public class ImUserFriendServiceImpl extends ServiceImpl<ImUserFriendDao, ImUser
                     new PushExt.APNs("", ""),
                     new PushExt.OPPO(""));
 
+            String imUserId = String.valueOf(userId);
+            if (ClientEnum.STUDENT == clientType) {
+                imUserId = MessageFormat.format("{0}:{1}", imUserId, ClientEnum.STUDENT.name());
+            }
             // 发送用户IM通知消息
             PrivateMessage privateMessage = new PrivateMessage()
                     .setSenderId(String.valueOf(friendIds.get(0)))
-                    .setTargetId(new String[]{String.valueOf(userId)})
+                    .setTargetId(new String[]{imUserId})
                     .setObjectName(txtMessage.getType())
                     .setContent(txtMessage)
                     .setPushExt(pushExt)
@@ -288,7 +343,53 @@ public class ImUserFriendServiceImpl extends ServiceImpl<ImUserFriendDao, ImUser
         return new String(encoder.encode((baos.toByteArray())));
     }
 
+    /**
+     * 用户IM好友列表
+     *
+     * @param clientType 客户端类型
+     * @param userId 用户ID
+     * @param paramMap   Map<String, Object>
+     * @return List<ImUserWrapper.ImUserFriend>
+     */
+    @Override
+    public List<ImUserWrapper.ImUserFriend> findUserAllImFriendInfo(ClientEnum clientType, Long userId, Map<String, Object> paramMap) {
+
+        // 用户好友匹配条件
+        Object search = paramMap.get("search");
+
+        // 查询用户好友列表
+        List<ImUserFriend> records = lambdaQuery()
+                .eq(ImUserFriend::getUserId, userId)
+                .eq(ImUserFriend::getClientType, clientType)
+                .and(Objects.nonNull(search) && StringUtils.isNotEmpty(search.toString()),
+                        e -> e.eq(ImUserFriend::getFriendId, search).or().like(ImUserFriend::getFriendNickname, search))
+                .orderByDesc(ImUserFriend::getId).list();
+
+        List<ImUserWrapper.ImUserFriend> userFriends = JSON.parseArray(JSON.toJSONString(records), ImUserWrapper.ImUserFriend.class);
+
+        for (ImUserWrapper.ImUserFriend item : userFriends) {
+
+            switch (clientType) {
+                case TEACHER:
+                    {
+                        // 老师查询学生好友
+                        item.friendType(Optional.ofNullable(item.getFriendType()).orElse(ClientEnum.STUDENT))
+                                .setImFriendId(MessageFormat.format("{0}:{1}", String.valueOf(item.getFriendId()), ClientEnum.STUDENT.name()));
+                    }
+                    break;
+                case STUDENT:
+                    {
+                        // 查询学生老师好友
+                        item.friendType(Optional.ofNullable(item.getFriendType()).orElse(ClientEnum.TEACHER))
+                                .setImFriendId(MessageFormat.format("{0}", String.valueOf(item.getFriendId())));
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
 
-
+        return userFriends;
+    }
 }
 

+ 6 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/StudentServiceImpl.java

@@ -12,6 +12,7 @@ import com.yonge.cooleshow.biz.dal.dto.search.StudentSearch;
 import com.yonge.cooleshow.biz.dal.entity.StudentTotal;
 import com.yonge.cooleshow.biz.dal.entity.Subject;
 import com.yonge.cooleshow.biz.dal.entity.UserBindingTeacher;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.ImUserFriendService;
 import com.yonge.cooleshow.biz.dal.service.TeacherService;
 import com.yonge.cooleshow.common.enums.CacheNameEnum;
@@ -32,6 +33,7 @@ import com.yonge.cooleshow.biz.dal.dao.StudentDao;
 import com.yonge.cooleshow.biz.dal.service.StudentService;
 
 import javax.annotation.Resource;
+import java.text.MessageFormat;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 
@@ -93,6 +95,10 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
         studentHomeVo.setStarTeacherNum(null == total.getStarTeacherNum() ? 0 : total.getStarTeacherNum());
         studentHomeVo.setMusicAlbumNum(null == total.getMusicAlbumNum() ? 0 : total.getMusicAlbumNum());
         studentHomeVo.setMusicSheetNum(null == total.getMusicSheetNum() ? 0 : total.getMusicSheetNum());
+
+        // IM聊天用户ID
+        studentHomeVo.setImUserId(MessageFormat.format("{0}:{1}", String.valueOf(detail.getUserId()), ClientEnum.STUDENT.name()));
+
         return studentHomeVo;
     }
 

+ 3 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TeacherServiceImpl.java

@@ -167,6 +167,9 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
         TeacherHomeVo teacherHomeVo = new TeacherHomeVo();
         BeanUtils.copyProperties(teacher, teacherHomeVo);
 
+        // 设置IM用户ID
+        teacherHomeVo.setImUserId(String.valueOf(teacher.getUserId()));
+
         teacherHomeVo.setDegreeDate(teacher.getDegreeDate());
         teacherHomeVo.setTeacherDate(teacher.getTeacherDate());
         //身份证号、手机号脱敏

+ 10 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/CourseHomeworkDetailVo.java

@@ -121,6 +121,8 @@ public class CourseHomeworkDetailVo {
     @ApiModelProperty("作业过期 1:已过期 0:未过期")
     private Integer homeworkExpire;
 
+    @ApiModelProperty(value = "IM聊天用户ID")
+    private String imUserId;
 
     public String getCourseGroupName() {
         return courseGroupName;
@@ -369,4 +371,12 @@ public class CourseHomeworkDetailVo {
     public void setDecorateTime(Date decorateTime) {
         this.decorateTime = decorateTime;
     }
+
+    public String getImUserId() {
+        return imUserId;
+    }
+
+    public void setImUserId(String imUserId) {
+        this.imUserId = imUserId;
+    }
 }

+ 11 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/CourseHomeworkVo.java

@@ -92,6 +92,9 @@ public class CourseHomeworkVo{
 	@ApiModelProperty("作业提交时间")
 	private Date submitTime;
 
+	@ApiModelProperty("IM用户ID")
+	private String imUserId;
+
 	public String getImGroupId() {
 		return imGroupId;
 	}
@@ -267,4 +270,12 @@ public class CourseHomeworkVo{
 	public void setBackgroundPic(String backgroundPic) {
 		this.backgroundPic = backgroundPic;
 	}
+
+	public String getImUserId() {
+		return imUserId;
+	}
+
+	public void setImUserId(String imUserId) {
+		this.imUserId = imUserId;
+	}
 }

+ 11 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/CourseStudent.java

@@ -70,6 +70,9 @@ public class CourseStudent implements Serializable {
     @ApiModelProperty(value = "课程名称")
     private String courseName;
 
+    @ApiModelProperty(value = "IM聊天用户ID")
+    private String imUserId;
+
     public Integer getStudentReplied() {
         return studentReplied;
     }
@@ -222,5 +225,13 @@ public class CourseStudent implements Serializable {
     public void setCourseName(String courseName) {
         this.courseName = courseName;
     }
+
+    public String getImUserId() {
+        return imUserId;
+    }
+
+    public void setImUserId(String imUserId) {
+        this.imUserId = imUserId;
+    }
 }
 

+ 11 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/LiveCourseInfoVo.java

@@ -167,6 +167,9 @@ public class LiveCourseInfoVo extends CourseGroupVo implements Serializable {
         @ApiModelProperty(value = "购买时间")
         private Date createTime;
 
+        @ApiModelProperty("IM用户ID")
+        private String imUserId;
+
         public Long getStudentId() {
             return studentId;
         }
@@ -206,6 +209,14 @@ public class LiveCourseInfoVo extends CourseGroupVo implements Serializable {
         public void setCreateTime(Date createTime) {
             this.createTime = createTime;
         }
+
+        public String getImUserId() {
+            return imUserId;
+        }
+
+        public void setImUserId(String imUserId) {
+            this.imUserId = imUserId;
+        }
     }
 
     public List<PlanVo> getPlanList() {

+ 11 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/MyCourseVo.java

@@ -59,6 +59,9 @@ public class MyCourseVo implements Serializable {
     @ApiModelProperty(value = "老师评价 0:未评价 1:已评价")
     private Integer teacherReplied;
 
+    @ApiModelProperty(value = "IM聊天用户ID")
+    private String imUserId;
+
     public Integer getStudentReplied() {
         return studentReplied;
     }
@@ -186,5 +189,13 @@ public class MyCourseVo implements Serializable {
     public void setSubjectName(String subjectName) {
         this.subjectName = subjectName;
     }
+
+    public String getImUserId() {
+        return imUserId;
+    }
+
+    public void setImUserId(String imUserId) {
+        this.imUserId = imUserId;
+    }
 }
 

+ 11 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/StudentHomeVo.java

@@ -56,6 +56,9 @@ public class StudentHomeVo extends Student {
     @ApiModelProperty(value = "是否会员 0否 1是")
     private YesOrNoEnum isVip;
 
+    @ApiModelProperty(value = "IM用户ID")
+    private String imUserId;
+
     public String getHeardUrl() {
         return heardUrl;
     }
@@ -221,4 +224,12 @@ public class StudentHomeVo extends Student {
     public void setIsVip(YesOrNoEnum isVip) {
         this.isVip = isVip;
     }
+
+    public String getImUserId() {
+        return imUserId;
+    }
+
+    public void setImUserId(String imUserId) {
+        this.imUserId = imUserId;
+    }
 }

+ 11 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/TeacherHomeVo.java

@@ -78,6 +78,9 @@ public class TeacherHomeVo extends Teacher implements Serializable {
     @ApiModelProperty(value = "学生 STUDENT 老师 TEACHER 系统用户 STSTEM")
     private String userType;
 
+    @ApiModelProperty(value = "IM用户ID")
+    private String imUserId;
+
     public Integer getMembershipDays() {
         return membershipDays;
     }
@@ -302,4 +305,12 @@ public class TeacherHomeVo extends Teacher implements Serializable {
     public void setStudentNums(Integer studentNums) {
         this.studentNums = studentNums;
     }
+
+    public String getImUserId() {
+        return imUserId;
+    }
+
+    public void setImUserId(String imUserId) {
+        this.imUserId = imUserId;
+    }
 }

+ 118 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/im/ImUserFriendVO.java

@@ -0,0 +1,118 @@
+package com.yonge.cooleshow.biz.dal.vo.im;
+
+import com.alibaba.fastjson.JSON;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Optional;
+
+/**
+ * Created by Eric.Shang on 2022/9/28.
+ */
+public class ImUserFriendVO {
+
+    /**
+     * 用户好友信息
+     */
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class ImUserFriend implements Serializable {
+
+        @ApiModelProperty(value = "主键;")
+        private Long id;
+
+        @ApiModelProperty(value = "当前用户编号")
+        private Long userId;
+
+        @ApiModelProperty(value = "好友编号")
+        private String friendId;
+
+        @ApiModelProperty(value = "融云好友编号")
+        private String imFriendId;
+
+        @ApiModelProperty(value = "好友身份")
+        private ClientEnum friendType;
+
+        @ApiModelProperty(value = "好友身份")
+        private ClientEnum roleType;
+
+        @ApiModelProperty(value = "好友头像")
+        private String friendAvatar;
+
+        @ApiModelProperty(value = "好友昵称")
+        private String friendNickname;
+
+        @ApiModelProperty(value = "备注")
+        private String memo;
+
+        @ApiModelProperty(value = "创建时间;")
+        private Date createTime;
+
+        @ApiModelProperty(value = "修改时间;")
+        private Date updateTime;
+
+        public static ImUserFriend from(String record) {
+
+            return JSON.parseObject(record, ImUserFriend.class);
+        }
+
+        public ClientEnum getRoleType() {
+            return getFriendType();
+        }
+    }
+
+    /**
+     * 群组成员信息
+     */
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class ImGroupMember implements Serializable {
+
+        @ApiModelProperty(value = "主键;")
+        private Long id;
+
+        @ApiModelProperty(value = "群编号;")
+        private String groupId;
+
+        @ApiModelProperty(value = "用户编号;")
+        private String userId;
+
+        @ApiModelProperty(value = "昵称;")
+        private String nickname;
+
+        @ApiModelProperty(value = "用户头像;")
+        private String avatar;
+
+        @ApiModelProperty(value = "是否是管理员")
+        private Boolean isAdmin;
+
+        @ApiModelProperty(value = "群角色TEACHER老师、STUDENT学生")
+        private ImGroupMemberRoleType roleType;
+
+        @ApiModelProperty(value = "创建时间;")
+        private Date createTime;
+
+        @ApiModelProperty(value = "修改时间;")
+        private Date updateTime;
+
+        @ApiModelProperty(value = "IM用户ID")
+        private String imUserId;
+
+        public static ImGroupMember from(String recv) {
+
+            return JSON.parseObject(recv, ImGroupMember.class);
+        }
+
+        public String getUserId() {
+            return Optional.ofNullable(getImUserId()).orElse(userId);
+        }
+    }
+}

+ 73 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/im/ImUserWrapper.java

@@ -0,0 +1,73 @@
+package com.yonge.cooleshow.biz.dal.wrapper.im;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.MK;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * Created by Eric.Shang on 2022/10/17.
+ */
+public class ImUserWrapper {
+
+    /**
+     * IM好友用户列表
+     */
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class ImUserFriend implements Serializable {
+
+        @ApiModelProperty(value = "主键;")
+        private Long id;
+
+        @ApiModelProperty(value = "当前用户编号")
+        private Long userId;
+
+        @ApiModelProperty(value = "好友编号")
+        private Long friendId;
+
+        @ApiModelProperty(value = "IM用户ID")
+        private String imFriendId;
+
+        @ApiModelProperty(value = "好友头像")
+        private String friendAvatar;
+
+        @ApiModelProperty(value = "好友昵称")
+        private String friendNickname;
+
+        @ApiModelProperty(value = "备注")
+        private String memo;
+
+        @ApiModelProperty(value = "创建时间;")
+        @JsonFormat(pattern = MK.TIME_PATTERN, timezone = MK.TIME_ZONE)
+        private Date createTime;
+
+        @ApiModelProperty(value = "修改时间;")
+        @JsonFormat(pattern = MK.TIME_PATTERN, timezone = MK.TIME_ZONE)
+        private Date updateTime;
+
+        @ApiModelProperty("好友身份")
+        private ClientEnum roleType;
+
+        @ApiModelProperty(value = "好友身份")
+        private ClientEnum friendType;
+
+        public ClientEnum getRoleType() {
+            return getFriendType();
+        }
+
+
+        public ImUserFriend friendType(ClientEnum friendType) {
+            this.friendType = friendType;
+            return this;
+        }
+    }
+
+}

+ 1 - 1
cooleshow-user/user-biz/src/main/resources/config/mybatis/CourseScheduleStudentPaymentMapper.xml

@@ -174,6 +174,6 @@
         FROM course_schedule_student_payment cssp
         LEFT JOIN sys_user su ON su.id_ = cssp.user_id_
         WHERE cssp.course_id_ = #{scheduleId}
-        AND NOT EXISTS (SELECT rm.user_id_ FROM im_network_room_member rm WHERE rm.room_id_ = #{scheduleId} AND rm.user_id_ = cssp.user_id_)
+        AND NOT EXISTS (SELECT rm.user_id_ FROM im_network_room_member rm WHERE rm.room_id_ = #{scheduleId} AND rm.user_id_ = cssp.user_id_ AND rm.role_ = 0)
     </select>
 </mapper>

+ 4 - 1
cooleshow-user/user-biz/src/main/resources/config/mybatis/ImGroupMapper.xml

@@ -61,6 +61,9 @@
             <if test="imGroupDto.userId != null">
                 AND igm.user_id_ = #{imGroupDto.userId}
             </if>
+            <if test="imGroupDto.roleType != null">
+                AND igm.role_type_ = #{imGroupDto.roleType}
+            </if>
             <if test="imGroupDto.search != null and imGroupDto.search != ''">
                 AND (ig.id_ = #{imGroupDto.search} OR
                 ig.name_ LIKE CONCAT('%',#{imGroupDto.search},'%') OR ig.introduce_ LIKE CONCAT('%',#{imGroupDto.search},'%'))
@@ -77,7 +80,7 @@
                CASE WHEN igm.id_ IS NULL THEN 0 ELSE 1 END existFlag,
                CASE WHEN igma.id_ IS NULL THEN 0 ELSE 1 END hasWaitAuditFlag
         FROM im_group ig
-                 LEFT JOIN im_group_member igm ON ig.id_ = igm.group_id_ AND igm.user_id_ = #{imGroupDto.userId}
+                 LEFT JOIN im_group_member igm ON (ig.id_ = igm.group_id_ AND igm.user_id_ = #{imGroupDto.userId} <if test="imGroupDto.roleType != null"> AND igm.role_type_ = #{imGroupDto.roleType} </if>)
                  LEFT JOIN im_group_member_audit igma ON igma.group_id_ = ig.id_ AND igma.audit_status_ = 'AUDITING' AND igma.user_id_ = igm.user_id_
         WHERE ig.create_by_ = #{imGroupDto.createUserId}
         <if test="imGroupDto.type != null and imGroupDto.type != ''">

+ 3 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/ImGroupMemberAuditMapper.xml

@@ -47,6 +47,9 @@
             <if test="userId != null">
                 AND user_id_ = #{userId}
             </if>
+            <if test="roleType != null">
+                AND role_type_ = #{roleType}
+            </if>
             <if test="auditStatus != null and auditStatus != ''">
                 AND audit_status_ = #{auditStatus}
             </if>

+ 6 - 3
cooleshow-user/user-biz/src/main/resources/config/mybatis/ImGroupMemberMapper.xml

@@ -25,15 +25,15 @@
             (#{entity.groupId}, #{entity.userId}, #{entity.avatar}, #{entity.nickname}, #{entity.isAdmin}, #{entity.roleType},NOW(), NOW())
         </foreach>
         ON DUPLICATE KEY UPDATE
+        group_id_ = VALUES(group_id_),
         user_id_ = VALUES(user_id_),
-        nickname_ = VALUES(nickname_),
         role_type_ = VALUES(role_type_)
     </insert>
     <delete id="delByGroupId">
         DELETE FROM im_group_member WHERE group_id_ = #{groupId}
     </delete>
     <delete id="delByGroupIdAndUserId">
-        DELETE FROM im_group_member WHERE group_id_ = #{groupId} AND user_id_ = #{userId}
+        DELETE FROM im_group_member WHERE group_id_ = #{groupId} AND user_id_ = #{userId} AND role_type_ = #{roleType}
     </delete>
     <select id="findOne" resultMap="BaseResultMap">
         SELECT <include refid="Base_Column_List"/> FROM im_group_member
@@ -44,6 +44,9 @@
             <if test="userId != null">
                 AND user_id_ = #{userId}
             </if>
+            <if test="roleType != null">
+                AND role_type_ = #{roleType}
+            </if>
         </where>
         LIMIT 1
     </select>
@@ -74,6 +77,6 @@
         </foreach>
     </select>
     <select id="findByUserIdAndGroupId" resultMap="ImGroupMember">
-        SELECT <include refid="Base_Column_List"/> FROM im_group_member WHERE group_id_ = #{groupId} AND user_id_ = #{userId} LIMIT 1
+        SELECT <include refid="Base_Column_List"/> FROM im_group_member WHERE group_id_ = #{groupId} AND user_id_ = #{userId} AND role_type_ = #{clientType} LIMIT 1
     </select>
 </mapper>

+ 4 - 3
cooleshow-user/user-biz/src/main/resources/config/mybatis/ImNetworkRoomMemberMapper.xml

@@ -40,14 +40,15 @@
                 #{entity.cameraFlag}, #{entity.micFlag}, #{entity.musicModeFlag}, #{entity.handFlag}, #{entity.username}, #{entity.avatar})
         ON DUPLICATE KEY UPDATE
         room_id_ = VALUES(room_id_),
-        user_id_ = VALUES(user_id_)
+        user_id_ = VALUES(user_id_),
+        role_ = VALUES(role_)
     </insert>
     <delete id="delByRidAndUid">
-        DELETE FROM im_network_room_member WHERE room_id_ = #{roomId} AND user_id_ = #{userId}
+        DELETE FROM im_network_room_member WHERE room_id_ = #{roomId} AND user_id_ = #{userId} AND role_ = #{userRole}
     </delete>
     <select id="findByRidAndUid" resultMap="BaseResultMap">
         SELECT <include refid="Base_Column_List"/> FROM im_network_room_member
-        WHERE room_id_ = #{roomId} AND user_id_ = #{userId} LIMIT 1
+        WHERE room_id_ = #{roomId} AND user_id_ = #{userId} AND role_ = #{userRole} LIMIT 1
     </select>
     <select id="queryByRoomId" resultMap="BaseResultMap">
         SELECT <include refid="Base_Column_List"/> FROM im_network_room_member WHERE room_id_ = #{roomId}

+ 3 - 7
cooleshow-user/user-biz/src/main/resources/config/mybatis/ImUserFriendMapper.xml

@@ -18,15 +18,11 @@
 
     <insert id="insertBatch" keyColumn="id_" keyProperty="id" useGeneratedKeys="true"
             parameterType="com.yonge.cooleshow.biz.dal.entity.ImUserFriend">
-        INSERT INTO im_user_friend(user_id_, friend_id_, friend_nickname_,friend_avatar_, memo_, create_time_, update_time_)
-        VALUES
+        INSERT INTO im_user_friend(user_id_, client_type_, friend_id_, friend_type_, friend_nickname_,friend_avatar_, memo_, create_time_, update_time_) VALUES
         <foreach collection="entities" item="entity" separator=",">
-            (#{entity.userId}, #{entity.friendId}, #{entity.friendNickname}, #{entity.friendAvatar}, #{entity.memo}, #{entity.createTime},
-            #{entity.updateTime})
+            (#{entity.userId}, #{entity.clientType}, #{entity.friendId}, #{entity.friendType}, #{entity.friendNickname}, #{entity.friendAvatar}, #{entity.memo}, #{entity.createTime}, #{entity.updateTime})
         </foreach>
-        ON DUPLICATE KEY UPDATE
-        user_id_ = VALUES(user_id_),
-        friend_id_ = VALUES(friend_id_)
+        ON DUPLICATE KEY UPDATE user_id_ = VALUES(user_id_), client_type_ = VALUES(client_type_), friend_id_ = VALUES(friend_id_), friend_type_ = VALUES(friend_type_)
     </insert>
     <select id="findByUserIdAndFriendId" resultMap="BaseResultMap">
         SELECT <include refid="Base_Column_List"/> FROM im_user_friend WHERE user_id_ = #{userId} AND friend_id_ = #{friendId} LIMIT 1

+ 90 - 5
cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/controller/ImNetworkRoomController.java

@@ -3,6 +3,7 @@ package com.yonge.cooleshow.classroom.controller;
 
 import com.alibaba.fastjson.JSONObject;
 import com.yonge.cooleshow.biz.dal.dto.*;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.ImNetworkRoomService;
 import com.yonge.cooleshow.biz.dal.service.SysUserService;
 import com.yonge.cooleshow.common.controller.BaseController;
@@ -18,6 +19,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
+import java.text.MessageFormat;
+import java.util.Objects;
 import java.util.Optional;
 
 /**
@@ -43,9 +46,15 @@ public class ImNetworkRoomController extends BaseController {
     @ApiOperation("加入网络教室")
     @PostMapping(value = "/join")
     public HttpResponseResult<ImNetworkRoomResult> joinRoom(@RequestBody ImNetworkBaseDto imNetworkBaseDto) throws Exception {
+
+        // 设置请求客户端来源
+        if (Objects.isNull(imNetworkBaseDto.getClientType())) {
+            imNetworkBaseDto.setClientType(ClientEnum.STUDENT);
+        }
+
         return imNetworkRoomService.joinRoom(Optional.ofNullable(imNetworkBaseDto)
                 .map(ImNetworkBaseDto::getRoomId)
-                .orElseThrow(()->new BizException("房间号不可为空")));
+                .orElseThrow(()->new BizException("房间号不可为空")), imNetworkBaseDto.getClientType());
     }
 
 //    @ApiOperation("加入网络教室状态回调")
@@ -58,9 +67,15 @@ public class ImNetworkRoomController extends BaseController {
     @ApiOperation("加入网络教室状态回调")
     @PostMapping(value = "joinRoomFailure")
     public HttpResponseResult joinRoomFailure(@RequestBody ImNetworkBaseDto imNetworkBaseDto){
+
+        // 设置请求客户端来源
+        if (Objects.isNull(imNetworkBaseDto.getClientType())) {
+            imNetworkBaseDto.setClientType(ClientEnum.STUDENT);
+        }
+
         imNetworkRoomService.joinRoomFailure(Optional.ofNullable(imNetworkBaseDto)
                 .map(ImNetworkBaseDto::getRoomId)
-                .orElseThrow(()->new BizException("房间号不可为空")).toString());
+                .orElseThrow(()->new BizException("房间号不可为空")).toString(), imNetworkBaseDto.getClientType());
         return succeed();
     }
 
@@ -69,14 +84,15 @@ public class ImNetworkRoomController extends BaseController {
     public void statusSync(@RequestBody String body) throws Exception {
         log.info("statusSync body: {}",body);
         ImChannelStateNotify notify = JSONObject.parseObject(body, ImChannelStateNotify.class);
+
         switch (notify.getEvent()) {
             case 11:
                 //成员加入
-                imNetworkRoomService.joinRoomSuccess(notify.getRoomId(),Long.parseLong(notify.getUserId()));
+                imNetworkRoomService.joinRoomSuccess(notify.getRoomId(), notify.getUserId());
                 break;
             case 12:
                 //成员退出
-                imNetworkRoomService.quitRoomSuccess(notify.getRoomId(),Long.parseLong(notify.getUserId()));
+                imNetworkRoomService.quitRoomSuccess(notify.getRoomId(), notify.getUserId());
                 break;
         }
     }
@@ -84,15 +100,36 @@ public class ImNetworkRoomController extends BaseController {
     @ApiOperation("退出网络教室")
     @PostMapping(value = "/leave")
     public HttpResponseResult leaveRoom(@RequestBody ImNetworkBaseDto imNetworkBaseDto) throws Exception {
+
+        // 设置请求客户端来源
+        if (Objects.isNull(imNetworkBaseDto.getClientType())) {
+            imNetworkBaseDto.setClientType(ClientEnum.STUDENT);
+        }
+
+        // 用户ID
+        Long userId = sysUserService.getUserId();
+
+        // IM用户ID
+        String imUserId = String.valueOf(userId);
+        if (ClientEnum.STUDENT == imNetworkBaseDto.getClientType()) {
+            imUserId = MessageFormat.format("{0}:{1}", imUserId, ClientEnum.STUDENT.name());
+        }
+
         imNetworkRoomService.quitRoomSuccess(Optional.ofNullable(imNetworkBaseDto)
                 .map(ImNetworkBaseDto::getRoomId)
-                .orElseThrow(()->new BizException("房间号不可为空")).toString(),sysUserService.getUserId());
+                .orElseThrow(()->new BizException("房间号不可为空")).toString(), imUserId);
         return succeed();
     }
 
     @ApiOperation("控制学员节拍器")
     @PostMapping(value = "/sendImPlayMidiMessage")
     public HttpResponseResult sendImPlayMidiMessage(@RequestBody ImNetworkCustomMessage customMessage) throws Exception {
+
+        // 设置客户端类型
+        if (Objects.isNull(customMessage.getClientType())) {
+            customMessage.setClientType(ClientEnum.TEACHER);
+        }
+
         imNetworkRoomService.sendImPlayMidiMessage(customMessage);
         return succeed();
     }
@@ -100,6 +137,12 @@ public class ImNetworkRoomController extends BaseController {
     @ApiOperation("移动端用来渲染页面")
     @PostMapping(value = "/display")
     public HttpResponseResult display(@RequestBody ImNetworkDisplayDataDto displayData) throws Exception {
+
+        // 设置客户端类型
+        if (Objects.isNull(displayData.getClientType())) {
+            displayData.setClientType(ClientEnum.TEACHER);
+        }
+
         imNetworkRoomService.display(displayData);
         return succeed();
     }
@@ -107,6 +150,12 @@ public class ImNetworkRoomController extends BaseController {
     @ApiOperation(value = "批量控制学员设备开关")
     @PostMapping(value = "/device/batchControl")
     public Object batchControlDevice(@RequestBody ImNetworkDeviceControlDto deviceControl)throws Exception {
+
+        // 设置客户端类型
+        if (Objects.isNull(deviceControl.getClientType())) {
+            deviceControl.setClientType(ClientEnum.TEACHER);
+        }
+
         imNetworkRoomService.batchControlDevice(deviceControl);
         return succeed();
     }
@@ -115,6 +164,12 @@ public class ImNetworkRoomController extends BaseController {
     @PostMapping(value = "/device/control")
     public HttpResponseResult controlDevice(@RequestBody ImNetworkDeviceControlDto deviceControl)
             throws Exception {
+
+        // 设置客户端类型
+        if (Objects.isNull(deviceControl.getClientType())) {
+            deviceControl.setClientType(ClientEnum.TEACHER);
+        }
+
         imNetworkRoomService.controlDevice(deviceControl);
         return succeed();
     }
@@ -123,6 +178,12 @@ public class ImNetworkRoomController extends BaseController {
     @PostMapping(value = "/device/approve")
     public HttpResponseResult approveControlDevice(@RequestBody ImNetworkDeviceControlDto deviceControl) throws Exception {
         deviceControl.setEnable(true);
+
+        // 设置客户端类型
+        if (Objects.isNull(deviceControl.getClientType())) {
+            deviceControl.setClientType(ClientEnum.STUDENT);
+        }
+
         imNetworkRoomService.approveControlDevice(deviceControl);
         return succeed();
     }
@@ -132,6 +193,12 @@ public class ImNetworkRoomController extends BaseController {
     public HttpResponseResult rejectControlDevice(@RequestBody ImNetworkDeviceControlDto deviceControl)
             throws Exception {
         deviceControl.setEnable(false);
+
+        // 设置客户端类型
+        if (Objects.isNull(deviceControl.getClientType())) {
+            deviceControl.setClientType(ClientEnum.STUDENT);
+        }
+
         imNetworkRoomService.rejectControlDevice(deviceControl);
         return succeed();
     }
@@ -140,6 +207,12 @@ public class ImNetworkRoomController extends BaseController {
     @PostMapping(value = "/device/sync")
     public Object deviceStatusSync(@RequestBody ImNetworkDeviceControlDto deviceControl)
             throws Exception {
+
+        // 设置客户端类型
+        if (Objects.isNull(deviceControl.getClientType())) {
+            deviceControl.setClientType(ClientEnum.STUDENT);
+        }
+
         imNetworkRoomService.deviceStatusSync(deviceControl);
         return succeed();
     }
@@ -147,6 +220,12 @@ public class ImNetworkRoomController extends BaseController {
     @ApiOperation(value = "老师在网络教室选择完伴奏后、通知学员下载伴奏")
     @PostMapping(value = "pushDownloadMusicSheetMsg")
     public HttpResponseResult pushDownloadMusicSheetMsg(@RequestBody ImNetworkMusicSheetDto musicSheetDto) throws Exception {
+
+        // 设置客户端类型
+        if (Objects.isNull(musicSheetDto.getClientType())) {
+            musicSheetDto.setClientType(ClientEnum.TEACHER);
+        }
+
         imNetworkRoomService.pushDownloadMusicSheetMsg(musicSheetDto);
         return succeed();
     }
@@ -154,6 +233,12 @@ public class ImNetworkRoomController extends BaseController {
     @ApiOperation(value = "学员伴奏下载状态回调")
     @PostMapping(value = "musicSheetDownNotify")
     public HttpResponseResult adjustMusicScore(@RequestBody ImNetworkMusicSheetDto musicSheetDto) throws Exception {
+
+        // 设置客户端类型
+        if (Objects.isNull(musicSheetDto.getClientType())) {
+            musicSheetDto.setClientType(ClientEnum.STUDENT);
+        }
+
         imNetworkRoomService.musicSheetDownNotify(musicSheetDto);
         return succeed();
     }

+ 13 - 1
cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/CourseHomeworkController.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.student.controller;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.CourseHomeworkSubmitDto;
@@ -17,6 +18,7 @@ import com.yonge.toolset.base.page.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
+import org.apache.commons.collections.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
@@ -91,7 +93,17 @@ public class CourseHomeworkController extends BaseController {
         list.add(CourseScheduleEnum.PIANO_ROOM_CLASS);
         list.add(CourseScheduleEnum.PRACTICE);
         query.setCourseType(list);
-        return succeed(PageUtil.pageInfo(courseHomeworkService.selectPage(PageUtil.getPage(query),query)));
+
+        IPage<CourseHomeworkVo> page = courseHomeworkService.selectPage(PageUtil.getPage(query), query);
+        if (CollectionUtils.isNotEmpty(page.getRecords())) {
+
+            for (CourseHomeworkVo item : page.getRecords()) {
+
+                item.setImUserId(String.valueOf(item.getTeacherId()));
+            }
+        }
+
+        return succeed(PageUtil.pageInfo(page));
     }
 
 

+ 30 - 3
cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/ImGroupController.java

@@ -1,9 +1,13 @@
 package com.yonge.cooleshow.student.controller;
 
 
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.ImGroupResultDto;
 import com.yonge.cooleshow.biz.dal.dto.ImGroupSearchDto;
 import com.yonge.cooleshow.biz.dal.entity.ImGroup;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
 import com.yonge.cooleshow.biz.dal.service.ImGroupService;
 import com.yonge.cooleshow.biz.dal.service.SysUserService;
 import com.yonge.cooleshow.common.controller.BaseController;
@@ -13,9 +17,14 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.validation.BindingResult;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
@@ -38,11 +47,21 @@ public class ImGroupController extends BaseController {
     private ImGroupService imGroupService;
     @Resource
     private SysUserService sysUserService;
+    @Autowired
+    private SysUserFeignService sysUserFeignService;
 
     @ApiOperation("获取群详情")
     @PostMapping(value = "/getDetail/{groupId}")
     public HttpResponseResult<ImGroup> getDetail(@ApiParam(value = "群编号", required = true) @PathVariable("groupId") String groupId) throws Exception {
-        ImGroup group = imGroupService.getById(groupId);
+
+        // 获取用户ID
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        if (sysUser == null  || sysUser.getId() == null) {
+            return failed("用户信息获取失败");
+        }
+
+        ImGroup group = imGroupService.findGroupInfoById(groupId, sysUser.getId());
+        // ImGroup group = imGroupService.getById(groupId);
         if (group == null) {
             return failed(HttpStatus.NO_CONTENT, "群组不存在");
         }
@@ -54,22 +73,30 @@ public class ImGroupController extends BaseController {
     public HttpResponseResult<List<ImGroup>> queryAll(@Valid @RequestBody ImGroupSearchDto imGroupSearchDto, BindingResult bindingResult) throws Exception {
         ValidationKit.ignoreFields(bindingResult,"createUserId");
         imGroupSearchDto.setUserId(sysUserService.getUserId());
+
+        // 设置群组成员身份
+        imGroupSearchDto.setRoleType(ImGroupMemberRoleType.STUDENT);
         return succeed(imGroupService.queryAll(imGroupSearchDto));
     }
 
     @ApiOperation("获取指定用户的群列表")
     @PostMapping(value = "/queryTeacherGroup")
     public HttpResponseResult<List<ImGroupResultDto>> queryTeacherGroup(@RequestBody ImGroupSearchDto imGroupSearchDto) throws Exception {
+
+        // 群类型
         if (StringUtils.isEmpty(imGroupSearchDto.getType())) {
             imGroupSearchDto.setType("FAN");
         }
+        // 用户群身份
+        imGroupSearchDto.setRoleType(ImGroupMemberRoleType.STUDENT);
+
         return succeed(imGroupService.queryTeacherFun(imGroupSearchDto));
     }
 
     @ApiOperation("退出群聊")
     @PostMapping(value = "/quit/{groupId}")
     public HttpResponseResult quit(@ApiParam(value = "群编号", required = true) @PathVariable("groupId") String groupId) throws Exception {
-        imGroupService.quit(groupId,sysUserService.getUserId());
+        imGroupService.quit(groupId,sysUserService.getUserId(), ClientEnum.STUDENT);
         return succeed();
     }
 }

+ 1 - 1
cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/ImGroupMemberAuditController.java

@@ -41,7 +41,7 @@ public class ImGroupMemberAuditController extends BaseController {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         imGroupMemberAudit.setRoleType(ImGroupMemberRoleType.STUDENT);
         imGroupMemberAudit.setUserId(sysUser.getId());
-        imGroupMemberAuditService.apply(imGroupMemberAudit);
+        imGroupMemberAuditService.apply(imGroupMemberAudit, false);
         return succeed();
     }
 }

+ 27 - 6
cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/ImGroupMemberController.java

@@ -1,17 +1,22 @@
 package com.yonge.cooleshow.student.controller;
 
 
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.yonge.cooleshow.biz.dal.entity.ImGroupMember;
+import com.yonge.cooleshow.biz.dal.enums.MK;
 import com.yonge.cooleshow.biz.dal.service.ImGroupMemberService;
+import com.yonge.cooleshow.biz.dal.vo.im.ImUserFriendVO;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.toolset.base.exception.BizException;
+import com.yonge.toolset.utils.collection.MapUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections.MapUtils;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -44,12 +49,24 @@ public class ImGroupMemberController extends BaseController {
     })
     @ApiOperation("获取好友详情")
     @PostMapping(value = "/getUserDetail")
-    public HttpResponseResult<ImGroupMember> getUserDetail(@RequestBody Map<String,Object> params) throws Exception {
+    public HttpResponseResult<ImUserFriendVO.ImGroupMember> getUserDetail(@RequestBody Map<String,Object> params) {
         if(Objects.isNull(params.get("groupId")) || Objects.isNull(params.get("userId"))){
             throw new BizException("参数校验失败");
         }
-        return succeed(imGroupMemberService.getUserDetail(Long.parseLong(params.get("userId").toString()),
-                params.get("groupId").toString()));
+
+        String userId = MapUtils.getString(params, "userId", "");
+
+        String ret = userId.split(":")[0];
+        if (!ret.matches(MK.EXP_INT)) {
+            return failed("无效的用户ID");
+        }
+
+        ImGroupMember groupMember = imGroupMemberService.getUserDetail(userId, params.get("groupId").toString());
+        if (Objects.isNull(groupMember)) {
+            return failed("用户无当前群组权限");
+        }
+
+        return succeed(ImUserFriendVO.ImGroupMember.from(JSON.toJSONString(groupMember)));
     }
 
 
@@ -63,13 +80,17 @@ public class ImGroupMemberController extends BaseController {
         if(Objects.isNull(params.get("groupId"))){
             throw new BizException("参数校验失败");
         }
-        Object search = params.get("search");
+
+        // 群组成员信息
+        List<ImGroupMember> groupMembers = imGroupMemberService.findChatGroupAllMemberInfo(params);
+
+        /*Object search = params.get("search");
         List<ImGroupMember> iPage = imGroupMemberService.getBaseMapper().selectList(Wrappers.<ImGroupMember>query().lambda()
                 .and(Objects.nonNull(search) && StringUtils.isNotEmpty(search.toString()),
                         e->e.eq(ImGroupMember::getUserId, search).or()
                         .like(ImGroupMember::getNickname, search))
-                .eq(ImGroupMember::getGroupId,params.get("groupId")).orderByDesc(ImGroupMember::getId));
-        return succeed(iPage);
+                .eq(ImGroupMember::getGroupId,params.get("groupId")).orderByDesc(ImGroupMember::getId));*/
+        return succeed(groupMembers);
     }
 }
 

+ 43 - 6
cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/ImUserFriendController.java

@@ -1,18 +1,24 @@
 package com.yonge.cooleshow.student.controller;
 
 
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.entity.ImUserFriend;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.MK;
 import com.yonge.cooleshow.biz.dal.service.ImUserFriendService;
+import com.yonge.cooleshow.biz.dal.vo.im.ImUserFriendVO;
+import com.yonge.cooleshow.biz.dal.wrapper.im.ImUserWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import io.swagger.annotations.*;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
+import java.text.MessageFormat;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -40,21 +46,52 @@ public class ImUserFriendController extends BaseController {
     })
     @ApiOperation("获取通讯录成员列表")
     @PostMapping(value = "/queryAll")
-    public HttpResponseResult<List<ImUserFriend>> queryAll(@RequestBody Map<String,Object> params) throws Exception {
+    public HttpResponseResult<List<ImUserWrapper.ImUserFriend>> queryAll(@RequestBody Map<String,Object> params) throws Exception {
+
+        // 用户ID
         SysUser sysUser = sysUserFeignService.queryUserInfo();
-        Object search = params.get("search");
-        List<ImUserFriend> iPage = imUserFriendService.getBaseMapper().selectList(Wrappers.<ImUserFriend>query().lambda()
+        if (Objects.isNull(sysUser)) {
+            return failed("请登录");
+        }
+
+        // 学生好友列表
+        List<ImUserWrapper.ImUserFriend> userFriends = imUserFriendService.findUserAllImFriendInfo(ClientEnum.STUDENT, sysUser.getId(), params);
+
+        /*Object search = params.get("search");
+        List<ImUserFriend> userFriends = imUserFriendService.getBaseMapper().selectList(Wrappers.<ImUserFriend>query().lambda()
                 .and(Objects.nonNull(search) && StringUtils.isNotEmpty(search.toString()),
                         e->e.eq(ImUserFriend::getFriendId, search).or()
                         .like(ImUserFriend::getFriendNickname, search))
                 .eq(ImUserFriend::getUserId,sysUser.getId()).orderByDesc(ImUserFriend::getId));
-        return succeed(iPage);
+
+        for (ImUserFriend item : userFriends) {
+            // 学生目前添加好友都为老师
+            item.clientType(ClientEnum.TEACHER)
+                    .setImFriendId(MessageFormat.format("{0}", String.valueOf(item.getFriendId())));
+        }*/
+
+        return succeed(userFriends);
     }
 
     @ApiOperation("获取好友详情")
     @PostMapping(value = "/getDetail/{userId}")
-    public HttpResponseResult<ImUserFriend> getDetail(@ApiParam(value = "用户编号", required = true) @PathVariable("userId") Long userId) throws Exception {
-        return succeed(imUserFriendService.getDetail(userId));
+    public HttpResponseResult<ImUserFriendVO.ImUserFriend> getDetail(@ApiParam(value = "用户编号", required = true) @PathVariable("userId") String userId) {
+
+        String ret = userId.split(":")[0];
+        if (!ret.matches(MK.EXP_INT)) {
+            return failed("无效的用户ID");
+        }
+
+        ImUserFriend userFriend = imUserFriendService.getDetail(userId, ClientEnum.STUDENT);
+        if (Objects.isNull(userFriend)) {
+            return failed("当前好友不存在");
+        }
+
+        if (Objects.isNull(userFriend.getFriendType())) {
+            userFriend.setFriendType(ClientEnum.TEACHER);
+        }
+
+        return succeed(ImUserFriendVO.ImUserFriend.from(JSON.toJSONString(userFriend)));
     }
 }
 

+ 14 - 1
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/CourseHomeworkController.java

@@ -1,11 +1,13 @@
 package com.yonge.cooleshow.teacher.controller;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.CourseHomeworkReviewDto;
 import com.yonge.cooleshow.biz.dal.dto.CourseHomeworkSaveDto;
 import com.yonge.cooleshow.biz.dal.dto.CourseScheduleHomeworkSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.HomeworkSearch;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.CourseScheduleEnum;
 import com.yonge.cooleshow.biz.dal.service.CourseHomeworkService;
 import com.yonge.cooleshow.biz.dal.service.CourseScheduleService;
@@ -21,10 +23,12 @@ import com.yonge.toolset.base.page.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
+import org.apache.commons.collections.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import javax.validation.Valid;
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -137,7 +141,16 @@ public class CourseHomeworkController extends BaseController {
         list.add(CourseScheduleEnum.PRACTICE);
         query.setCourseType(list);
 
-        return succeed(PageUtil.pageInfo(courseHomeworkService.selectPage(PageUtil.getPage(query),query)));
+        IPage<CourseHomeworkVo> page = courseHomeworkService.selectPage(PageUtil.getPage(query), query);
+        if (CollectionUtils.isNotEmpty(page.getRecords())) {
+
+            for (CourseHomeworkVo item : page.getRecords()) {
+
+                item.setImUserId(MessageFormat.format("{0}:{1}", String.valueOf(item.getStudentId()), ClientEnum.STUDENT.name()));
+            }
+        }
+
+        return succeed(PageUtil.pageInfo(page));
     }
 
 

+ 6 - 1
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/ImGroupController.java

@@ -4,6 +4,8 @@ package com.yonge.cooleshow.teacher.controller;
 import com.yonge.cooleshow.biz.dal.dto.ImGroupResultDto;
 import com.yonge.cooleshow.biz.dal.dto.ImGroupSearchDto;
 import com.yonge.cooleshow.biz.dal.entity.ImGroup;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
 import com.yonge.cooleshow.biz.dal.service.ImGroupService;
 import com.yonge.cooleshow.biz.dal.service.SysUserService;
 import com.yonge.cooleshow.common.controller.BaseController;
@@ -58,7 +60,7 @@ public class ImGroupController extends BaseController {
     @ApiOperation("退出群聊")
     @PostMapping(value = "/quit/{groupId}")
     public HttpResponseResult quit(@ApiParam(value = "群编号", required = true) @PathVariable("groupId") String groupId) throws Exception {
-        imGroupService.quit(groupId,sysUserService.getUserId());
+        imGroupService.quit(groupId,sysUserService.getUserId(), ClientEnum.TEACHER);
         return succeed();
     }
 
@@ -77,6 +79,9 @@ public class ImGroupController extends BaseController {
     public HttpResponseResult<List<ImGroup>> queryAll(@Valid @RequestBody ImGroupSearchDto imGroupSearchDto, BindingResult bindingResult) throws Exception {
         ValidationKit.ignoreFields(bindingResult,"createUserId");
         imGroupSearchDto.setUserId(sysUserService.getUserId());
+        // 设置群组成员身份
+        imGroupSearchDto.setRoleType(ImGroupMemberRoleType.TEACHER);
+
         return succeed(imGroupService.queryAll(imGroupSearchDto));
     }
 

+ 1 - 1
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/ImGroupMemberAuditController.java

@@ -46,7 +46,7 @@ public class ImGroupMemberAuditController extends BaseController {
     public HttpResponseResult apply(@Valid @RequestBody ImGroupMemberAudit imGroupMemberAudit) throws Exception {
         imGroupMemberAudit.setRoleType(ImGroupMemberRoleType.TEACHER);
         imGroupMemberAudit.setUserId(sysUserService.getUserId());
-        imGroupMemberAuditService.apply(imGroupMemberAudit);
+        imGroupMemberAuditService.apply(imGroupMemberAudit, false);
         return succeed();
     }
 

+ 26 - 8
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/ImGroupMemberController.java

@@ -1,12 +1,13 @@
 package com.yonge.cooleshow.teacher.controller;
 
 
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.yonge.cooleshow.biz.dal.entity.ImGroupMember;
-import com.yonge.cooleshow.biz.dal.entity.ImUserFriend;
+import com.yonge.cooleshow.biz.dal.enums.MK;
 import com.yonge.cooleshow.biz.dal.service.ImGroupMemberService;
+import com.yonge.cooleshow.biz.dal.vo.im.ImUserFriendVO;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.toolset.base.exception.BizException;
@@ -14,6 +15,7 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections.MapUtils;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -46,12 +48,24 @@ public class ImGroupMemberController extends BaseController {
     })
     @ApiOperation("获取好友详情")
     @PostMapping(value = "/getUserDetail")
-    public HttpResponseResult<ImGroupMember> getUserDetail(@RequestBody Map<String,Object> params) throws Exception {
+    public HttpResponseResult<ImUserFriendVO.ImGroupMember> getUserDetail(@RequestBody Map<String,Object> params) {
         if(Objects.isNull(params.get("groupId")) || Objects.isNull(params.get("userId"))){
             throw new BizException("参数校验失败");
         }
-        return succeed(imGroupMemberService.getUserDetail(Long.parseLong(params.get("userId").toString()),
-                params.get("groupId").toString()));
+
+        String userId = MapUtils.getString(params, "userId", "");
+
+        String ret = userId.split(":")[0];
+        if (!ret.matches(MK.EXP_INT)) {
+            return failed("无效的用户ID");
+        }
+
+        ImGroupMember groupMember = imGroupMemberService.getUserDetail(userId, params.get("groupId").toString());
+        if (Objects.isNull(groupMember)) {
+            return failed("用户无当前群组权限");
+        }
+
+        return succeed(ImUserFriendVO.ImGroupMember.from(JSON.toJSONString(groupMember)));
     }
 
     @ApiImplicitParams({
@@ -64,13 +78,17 @@ public class ImGroupMemberController extends BaseController {
         if(Objects.isNull(params.get("groupId"))){
             throw new BizException("参数校验失败");
         }
-        Object search = params.get("search");
+
+        // 群组成员信息
+        List<ImGroupMember> groupMembers = imGroupMemberService.findChatGroupAllMemberInfo(params);
+
+        /*Object search = params.get("search");
         List<ImGroupMember> iPage = imGroupMemberService.list(new QueryWrapper<ImGroupMember>().lambda()
                 .and(Objects.nonNull(search) && StringUtils.isNotEmpty(search.toString()),e->e.
                         eq(ImGroupMember::getUserId, search).or()
                         .like(ImGroupMember::getNickname, search))
-                .eq(ImGroupMember::getGroupId,params.get("groupId")).orderByDesc(ImGroupMember::getId));
-        return succeed(iPage);
+                .eq(ImGroupMember::getGroupId,params.get("groupId")).orderByDesc(ImGroupMember::getId));*/
+        return succeed(groupMembers);
     }
 }
 

+ 41 - 5
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/ImUserFriendController.java

@@ -1,17 +1,23 @@
 package com.yonge.cooleshow.teacher.controller;
 
 
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.yonge.cooleshow.biz.dal.entity.ImUserFriend;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.MK;
 import com.yonge.cooleshow.biz.dal.service.ImUserFriendService;
 import com.yonge.cooleshow.biz.dal.service.SysUserService;
+import com.yonge.cooleshow.biz.dal.vo.im.ImUserFriendVO;
+import com.yonge.cooleshow.biz.dal.wrapper.im.ImUserWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import io.swagger.annotations.*;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
+import java.text.MessageFormat;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -40,21 +46,51 @@ public class ImUserFriendController extends BaseController {
     })
     @ApiOperation("获取通讯录成员列表")
     @PostMapping(value = "/queryAll")
-    public HttpResponseResult<List<ImUserFriend>> queryAll(@RequestBody Map<String, Object> params) {
-        Object search = params.get("search");
+    public HttpResponseResult<List<ImUserWrapper.ImUserFriend>> queryAll(@RequestBody Map<String, Object> params) {
+
+        // 用户ID
+        Long userId = sysUserService.getUserId();
+
+        // 学生好友列表
+        List<ImUserWrapper.ImUserFriend> userFriends = imUserFriendService.findUserAllImFriendInfo(ClientEnum.TEACHER, userId, params);
+
+        /*Object search = params.get("search");
         List<ImUserFriend> record = imUserFriendService.list(Wrappers.<ImUserFriend>query().lambda()
                 .eq(ImUserFriend::getUserId, sysUserService.getUserId())
                 .and(Objects.nonNull(search) && StringUtils.isNotEmpty(search.toString()),
                         e -> e.eq(ImUserFriend::getFriendId, search)
                                 .or().like(ImUserFriend::getFriendNickname, search))
                 .orderByDesc(ImUserFriend::getId));
-        return succeed(record);
+
+        for (ImUserFriend item : record) {
+
+            // 老师端添加好友,可能为老师客服或者学生
+            item.clientType(ClientEnum.STUDENT)
+                    .setImFriendId(MessageFormat.format("{0}:{1}", String.valueOf(item.getFriendId()), ClientEnum.STUDENT.name()));
+        }*/
+
+        return succeed(userFriends);
     }
 
     @ApiOperation("获取好友详情")
     @PostMapping(value = "/getDetail/{userId}")
-    public HttpResponseResult<ImUserFriend> getDetail(@ApiParam(value = "用户编号", required = true) @PathVariable("userId") Long userId) throws Exception {
-        return succeed(imUserFriendService.getDetail(userId));
+    public HttpResponseResult<ImUserFriendVO.ImUserFriend> getDetail(@ApiParam(value = "用户编号", required = true) @PathVariable("userId") String userId) {
+
+        String ret = userId.split(":")[0];
+        if (!ret.matches(MK.EXP_INT)) {
+            return failed("无效的用户ID");
+        }
+
+        ImUserFriend userFriend = imUserFriendService.getDetail(userId, ClientEnum.TEACHER);
+        if (Objects.isNull(userFriend)) {
+            return failed("当前好友不存在");
+        }
+
+        if (Objects.isNull(userFriend.getFriendType())) {
+            userFriend.setFriendType(ClientEnum.STUDENT);
+        }
+
+        return succeed(ImUserFriendVO.ImUserFriend.from(JSON.toJSONString(userFriend)));
     }
 
 }

+ 22 - 0
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/open/OpenShareController.java

@@ -1,10 +1,12 @@
 package com.yonge.cooleshow.teacher.controller.open;
 
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.MusicImgDto;
 import com.yonge.cooleshow.biz.dal.dto.search.ShareProfitParam;
 import com.yonge.cooleshow.biz.dal.entity.SysConfig;
+import com.yonge.cooleshow.biz.dal.entity.Teacher;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.vo.CheckVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicActivityVo;
@@ -25,6 +27,8 @@ import javax.validation.Valid;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
 
 @RestController
 @RequestMapping("/open")
@@ -48,6 +52,8 @@ public class OpenShareController extends BaseController {
     private ActivityPlanService activityPlanService;
     @Autowired
     private SysConfigService sysConfigService;
+    @Autowired
+    private TeacherService teacherService;
 
     @Autowired
     private MusicAlbumService musicAlbumService;
@@ -152,4 +158,20 @@ public class OpenShareController extends BaseController {
         List<SysConfig> configs = sysConfigService.findAll(params);
         return succeed(configs);
     }
+
+    @ApiOperation(value = "用户老师身份查询")
+    @GetMapping("/teacher/identity/{ID}")
+    public HttpResponseResult<Boolean> userTeacherIdentityInfo(@PathVariable("ID") Long userId) {
+
+        // 校验请求参数
+        if (Optional.ofNullable(userId).orElse(0L) <= 0) {
+            return succeed(false);
+        }
+
+        // 根据用户ID,查询老师身份信息
+        Teacher teacher = teacherService.getOne(Wrappers.<Teacher>lambdaQuery().eq(Teacher::getUserId, userId));
+
+        // 响应数据
+        return succeed(Objects.nonNull(teacher));
+    }
 }