Просмотр исходного кода

Merge branch 'master' of http://git.dayaedu.com/yonge/cooleshow

liujunchi 3 лет назад
Родитель
Сommit
edfbaaa5ba
74 измененных файлов с 3905 добавлено и 83 удалено
  1. 12 0
      cooleshow-gateway/gateway-web/src/main/resources/bootstrap-prod.yml
  2. 1 1
      cooleshow-gateway/gateway-web/src/main/resources/logback-spring.xml
  3. 0 1
      cooleshow-im/.gitignore
  4. 0 26
      cooleshow-im/im-api/pom.xml
  5. 0 22
      cooleshow-im/im-server/pom.xml
  6. 0 26
      cooleshow-im/pom.xml
  7. 1 0
      cooleshow-user/pom.xml
  8. 35 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/CourseScheduleStudentMusicSheetDao.java
  9. 30 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/CourseScheduleStudentPaymentDao.java
  10. 26 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/ImNetworkRoomDao.java
  11. 31 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/ImNetworkRoomMemberDao.java
  12. 1 3
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/MusicSheetAccompanimentDao.java
  13. 50 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/CourseScheduleStudentMusicSheetResult.java
  14. 34 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImChannelStateNotify.java
  15. 62 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkControlDeviceNotifyMessage.java
  16. 88 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkCustomMessage.java
  17. 105 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkDeviceControlDto.java
  18. 71 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkDeviceStateChangedMessage.java
  19. 61 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkDisplayDataDto.java
  20. 25 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkDisplayMessage.java
  21. 38 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkMetronomeMessage.java
  22. 83 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkMusicSheetDownDto.java
  23. 28 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkMusicSheetDownloadMessage.java
  24. 155 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkMusicSheetDownloadMessageContent.java
  25. 38 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkMusicSheetDownloadStatusMessage.java
  26. 67 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkRoomMemberChangedMessage.java
  27. 61 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkRoomMusicSheetData.java
  28. 61 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkRoomMusicSheetDownloadData.java
  29. 76 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkRoomResult.java
  30. 42 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkRoomStatusNotify.java
  31. 54 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/NetworkRoomParamDto.java
  32. 4 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/NetworkRoomResult.java
  33. 156 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/CourseScheduleStudentMusicSheet.java
  34. 23 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/CourseScheduleStudentPayment.java
  35. 8 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/IMApiResultInfo.java
  36. 108 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ImNetworkRoom.java
  37. 166 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ImNetworkRoomMember.java
  38. 12 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/MusicSheetAccompaniment.java
  39. 24 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/ImNetworkActionEnum.java
  40. 28 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/ImNetworkDeviceTypeEnum.java
  41. 33 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/ImNetworkDisplayEnum.java
  42. 73 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/ImNetworkRoomErrorEnum.java
  43. 41 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/ImNetworkRoomMemberChangedEnum.java
  44. 22 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/UserRoleEnum.java
  45. 17 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/CourseScheduleStudentMusicSheetService.java
  46. 27 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/CourseScheduleStudentPaymentService.java
  47. 26 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImNetworkRoomMemberService.java
  48. 62 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImNetworkRoomService.java
  49. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/MusicSheetAccompanimentService.java
  50. 29 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseScheduleStudentMusicSheetServiceImpl.java
  51. 32 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseScheduleStudentPaymentServiceImpl.java
  52. 58 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImNetworkRoomMemberServiceImpl.java
  53. 601 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImNetworkRoomServiceImpl.java
  54. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/MusicSheetAccompanimentServiceImpl.java
  55. 84 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/CourseScheduleStudentMusicSheetDao.xml
  56. 61 1
      cooleshow-user/user-biz/src/main/resources/config/mybatis/CourseScheduleStudentPaymentMapper.xml
  57. 22 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/ImNetworkRoomMapper.xml
  58. 62 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/ImNetworkRoomMemberMapper.xml
  59. 3 2
      cooleshow-user/user-biz/src/main/resources/config/mybatis/MusicSheetAccompanimentMapper.xml
  60. 80 0
      cooleshow-user/user-classroom/pom.xml
  61. 28 0
      cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/ClassroomApplication.java
  62. 43 0
      cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/config/ResourceServerConfig.java
  63. 56 0
      cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/config/WebMvcConfig.java
  64. 166 0
      cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/controller/ImNetworkRoomController.java
  65. 29 0
      cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/controller/ImNetworkRoomMemberController.java
  66. 41 0
      cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/interceptor/MDCInterceptor.java
  67. 31 0
      cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/interceptor/OperationLogInterceptor.java
  68. 12 0
      cooleshow-user/user-classroom/src/main/resources/bootstrap-dev.yml
  69. 13 0
      cooleshow-user/user-classroom/src/main/resources/bootstrap-prod.yml
  70. 61 0
      cooleshow-user/user-classroom/src/main/resources/logback-spring.xml
  71. 29 0
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/CourseScheduleStudentMusicSheetController.java
  72. 166 0
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/ImNetworkRoomController.java
  73. 29 0
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/ImNetworkRoomMemberController.java
  74. 0 1
      pom.xml

+ 12 - 0
cooleshow-gateway/gateway-web/src/main/resources/bootstrap-prod.yml

@@ -0,0 +1,12 @@
+spring:
+  cloud:
+    nacos:
+      config:
+        server-addr: 47.114.1.200:8848
+        namespace: 6f8374a9-598f-4889-bb17-476070ffb8de
+        group: DEFAULT_GROUP
+        prefix: teacher
+        file-extension: yaml
+        refresh:
+          enabled: true
+        enabled: true

+ 1 - 1
cooleshow-gateway/gateway-web/src/main/resources/logback-spring.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <configuration scan="true" scanPeriod="10 seconds">
 
-	<property name="LOG_HOME" value="/mdata/logs/gateway-%d{yyyy-MM-dd_HH}-%i.log" />
+	<property name="LOG_HOME" value="/Users/chenxiaoyu/Documents/logs/gateway-%d{yyyy-MM-dd_HH}-%i.log" />
 	<property name="CONSOLE_LOG_PATTERN"
 		value="[%X{username} %X{ip} %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}] : %msg%n" />
 

+ 0 - 1
cooleshow-im/.gitignore

@@ -1 +0,0 @@
-/bin/

+ 0 - 26
cooleshow-im/im-api/pom.xml

@@ -1,26 +0,0 @@
-<?xml version="1.0"?>
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-  <modelVersion>4.0.0</modelVersion>
-  <parent>
-    <groupId>com.yonge.cooleshow</groupId>
-    <artifactId>cooleshow-im</artifactId>
-    <version>1.0</version>
-  </parent>
-  <groupId>com.yonge.cooleshow</groupId>
-  <artifactId>im-api</artifactId>
-  <version>1.0</version>
-  <name>im-api</name>
-  <url>http://maven.apache.org</url>
-  <properties>
-    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-  </properties>
-  <dependencies>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>3.8.1</version>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-</project>

+ 0 - 22
cooleshow-im/im-server/pom.xml

@@ -1,22 +0,0 @@
-<?xml version="1.0"?>
-<project
-	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
-	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>com.yonge.cooleshow</groupId>
-		<artifactId>cooleshow-im</artifactId>
-		<version>1.0</version>
-	</parent>
-	<groupId>com.yonge.cooleshow</groupId>
-	<artifactId>im-server</artifactId>
-	<version>1.0</version>
-	<name>im-server</name>
-	<url>http://maven.apache.org</url>
-	<properties>
-		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-	</properties>
-	<dependencies>
-	</dependencies>
-
-</project>

+ 0 - 26
cooleshow-im/pom.xml

@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>com.yonge.cooleshow</groupId>
-		<artifactId>cooleshow</artifactId>
-		<version>1.0</version>
-	</parent>
-	<groupId>com.yonge.cooleshow</groupId>
-	<artifactId>cooleshow-im</artifactId>
-	<version>1.0</version>
-	<packaging>pom</packaging>
-
-	<name>cooleshow-im</name>
-	<url>http://maven.apache.org</url>
-	<properties>
-		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-	</properties>
-	<dependencies>
-	</dependencies>
-	<modules>
-		<module>im-api</module>
-		<module>im-server</module>
-	</modules>
-</project>

+ 1 - 0
cooleshow-user/pom.xml

@@ -37,6 +37,7 @@
 	<modules>
 		<module>user-student</module>
 		<module>user-teacher</module>
+		<module>user-classroom</module>
 		<module>user-admin</module>
 		<module>user-biz</module>
 	</modules>

+ 35 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/CourseScheduleStudentMusicSheetDao.java

@@ -0,0 +1,35 @@
+package com.yonge.cooleshow.biz.dal.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.yonge.cooleshow.biz.dal.dto.CourseScheduleStudentMusicSheetResult;
+import com.yonge.cooleshow.biz.dal.entity.CourseScheduleStudentMusicSheet;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * (CourseScheduleStudentMusicSheet)表数据库访问层
+ *
+ * @author zx
+ * @since 2022-04-02 15:56:01
+ */
+public interface CourseScheduleStudentMusicSheetDao extends BaseMapper<CourseScheduleStudentMusicSheet> {
+
+    List<CourseScheduleStudentMusicSheetResult> queryBySheetIdAndCourseId(@Param("musicSheetAccompanimentId") Long musicSheetAccompanimentId,
+                                                                          @Param("courseId") Long courseId,
+                                                                          @Param("userId") Long userId,
+                                                                          @Param("downStatus") Integer downStatus,
+                                                                          @Param("userType") Integer userType);
+    //开启原音播放
+    void openPlayStatus(@Param("scheduleId") Long scheduleId,
+                       @Param("musicScoreAccompanimentId") Integer musicScoreAccompanimentId,
+                       @Param("userId") Long userId);
+    void openAccompanimentPlayStatus(@Param("scheduleId") Long scheduleId,
+                                    @Param("musicScoreAccompanimentId") Integer musicScoreAccompanimentId,
+                                    @Param("userId") Long userId);
+    //关闭伴奏
+    void closePlayStatus(@Param("courseId") Long courseId,@Param("userId") Long userId);
+
+    void batchInsert(@Param("musicSheet") List<CourseScheduleStudentMusicSheetResult> musicSheet);
+}
+

+ 30 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/CourseScheduleStudentPaymentDao.java

@@ -54,5 +54,35 @@ public interface CourseScheduleStudentPaymentDao extends BaseMapper<CourseSchedu
      * @return
      */
     List<String> selectOrderNoByGroupId(Long courseGroupId);
+
+    //重置节拍器设置
+    void cleanPlayMidi(@Param("courseScheduleId") Long courseScheduleId);
+
+    //获取节拍器数据
+    String getMidiByCourseIdAndUserId(@Param("courseScheduleId") Long courseScheduleId, @Param("userId") Long userId);
+
+    //获取伴奏数据
+    String getMusicSheetByCourseIdAndUserId(@Param("courseScheduleId") Long courseScheduleId, @Param("userId") Long userId);
+
+    //调整节拍器
+    void adjustPlayMidi(@Param("courseScheduleId") long courseScheduleId, @Param("userId") Long userId, @Param("content") String content);
+
+    //调整伴奏
+    void adjustExamSong(@Param("courseScheduleId") long courseScheduleId, @Param("userId") Long userId, @Param("examSongJson") String examSongJson);
+
+    //获取课程学员关联
+    List<CourseScheduleStudentPayment> queryByCourseId(@Param("courseScheduleId") Long courseScheduleId);
+
+    /**
+     * @description:
+     * @param scheduleId    课程编号
+     * @param userId    学员编号
+     * @param content   节拍器参数
+     * @param musicSheetJson    伴奏参数
+     * @return void
+     * @author zx
+     * @date 2022/5/7 16:44
+     */
+    void adjustPlayMidiAndMusicSheet(Long scheduleId, Long userId, String content, String musicSheetJson);
 }
 

+ 26 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/ImNetworkRoomDao.java

@@ -0,0 +1,26 @@
+package com.yonge.cooleshow.biz.dal.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.yonge.cooleshow.biz.dal.entity.ImNetworkRoom;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 网络教室房间(ImNetworkRoom)表数据库访问层
+ *
+ * @author zx
+ * @since 2022-03-30 16:36:36
+ */
+public interface ImNetworkRoomDao extends BaseMapper<ImNetworkRoom> {
+
+    /**
+    * @description: 根据房间号获取
+     * @param roomId
+    * @return com.yonge.cooleshow.biz.dal.entity.ImNetworkRoom
+    * @author zx
+    * @date 2022/3/30 17:57
+    */
+    ImNetworkRoom findByRoomId(String roomId);
+}
+

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

@@ -0,0 +1,31 @@
+package com.yonge.cooleshow.biz.dal.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.yonge.cooleshow.biz.dal.entity.ImNetworkRoomMember;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 网络教室成员(ImNetworkRoomMember)表数据库访问层
+ *
+ * @author zx
+ * @since 2022-03-30 16:36:37
+ */
+public interface ImNetworkRoomMemberDao extends BaseMapper<ImNetworkRoomMember> {
+
+    int insertBatch(@Param("entities") List<ImNetworkRoomMember> entities);
+
+    int insert(@Param("entity") ImNetworkRoomMember roomMember);
+
+    ImNetworkRoomMember findByRidAndUid(@Param("roomId") String roomId, @Param("userId") Long userId);
+
+    List<ImNetworkRoomMember> queryByRoomId(@Param("roomId") String roomId);
+
+    void delByRidAndUid(@Param("roomId") String roomId, @Param("userId") Long userId);
+
+    int countByRoomId(@Param("roomId") String roomId);
+
+    List<ImNetworkRoomMember> findByRoomAndRole(@Param("roomId") String roomId, @Param("role") int role);
+}
+

+ 1 - 3
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/MusicSheetAccompanimentDao.java

@@ -1,9 +1,7 @@
 package com.yonge.cooleshow.biz.dal.dao;
 
-import com.yonge.cooleshow.biz.dal.entity.MusicSheetAccompaniment;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-
-import java.util.List;
+import com.yonge.cooleshow.biz.dal.entity.MusicSheetAccompaniment;
 
 /**
  * MusicSheetAccompanimentDao数据库访问类

+ 50 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/CourseScheduleStudentMusicSheetResult.java

@@ -0,0 +1,50 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+import com.yonge.cooleshow.biz.dal.entity.CourseScheduleStudentMusicSheet;
+import io.swagger.annotations.ApiModelProperty;
+
+public class CourseScheduleStudentMusicSheetResult extends CourseScheduleStudentMusicSheet {
+    @ApiModelProperty(value = "原音")
+    private String mp3Url;
+
+    @ApiModelProperty(value = "伴奏")
+    private String audioFileUrl;
+
+    @ApiModelProperty(value = "曲目名")
+    private String musicSheetName;
+
+    @ApiModelProperty(value = "伴奏音量")
+    private Integer soundVolume = 100;
+
+    public Integer getSoundVolume() {
+        return soundVolume;
+    }
+
+    public void setSoundVolume(Integer soundVolume) {
+        this.soundVolume = soundVolume;
+    }
+
+    public String getMp3Url() {
+        return mp3Url;
+    }
+
+    public void setMp3Url(String mp3Url) {
+        this.mp3Url = mp3Url;
+    }
+
+    public String getAudioFileUrl() {
+        return audioFileUrl;
+    }
+
+    public void setAudioFileUrl(String audioFileUrl) {
+        this.audioFileUrl = audioFileUrl;
+    }
+
+    public String getMusicSheetName() {
+        return musicSheetName;
+    }
+
+    public void setMusicSheetName(String musicSheetName) {
+        this.musicSheetName = musicSheetName;
+    }
+}

+ 34 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImChannelStateNotify.java

@@ -0,0 +1,34 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+public class ImChannelStateNotify {
+	//房间号
+	private String channelId;
+	//事件编号11是加入12是退出
+	private int event;
+	//用户编号
+	private String userId;
+
+	public String getChannelId() {
+		return channelId;
+	}
+
+	public void setChannelId(String channelId) {
+		this.channelId = channelId;
+	}
+
+	public int getEvent() {
+		return event;
+	}
+
+	public void setEvent(int event) {
+		this.event = event;
+	}
+
+	public String getUserId() {
+		return userId;
+	}
+
+	public void setUserId(String userId) {
+		this.userId = userId;
+	}
+}

+ 62 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkControlDeviceNotifyMessage.java

@@ -0,0 +1,62 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+
+import com.yonge.cooleshow.biz.dal.entity.BaseMessage;
+
+public class ImNetworkControlDeviceNotifyMessage extends BaseMessage {
+
+    private int action;
+//    private String ticket;
+    private int type;
+    private String opUserId;
+    private String opUserName;
+
+    public ImNetworkControlDeviceNotifyMessage(int action) {
+        this.action = action;
+    }
+
+    public int getAction() {
+        return action;
+    }
+
+    public void setAction(int action) {
+        this.action = action;
+    }
+
+//    public String getTicket() {
+//        return ticket;
+//    }
+//
+//    public void setTicket(String ticket) {
+//        this.ticket = ticket;
+//    }
+
+    public int getType() {
+        return type;
+    }
+
+    public void setType(int type) {
+        this.type = type;
+    }
+
+    public String getOpUserId() {
+        return opUserId;
+    }
+
+    public void setOpUserId(String opUserId) {
+        this.opUserId = opUserId;
+    }
+
+    public String getOpUserName() {
+        return opUserName;
+    }
+
+    public void setOpUserName(String opUserName) {
+        this.opUserName = opUserName;
+    }
+
+    @Override
+    public String getObjectName() {
+        return "SC:CDNMsg";
+    }
+}

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

@@ -0,0 +1,88 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+import io.rong.messages.BaseMessage;
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.StringUtils;
+
+public class ImNetworkCustomMessage extends BaseMessage {
+    @ApiModelProperty(value = "节拍器开关",required = true)
+    private boolean enable;
+
+    @ApiModelProperty(value = "消息类型",required = true)
+    private int customType;
+
+    @ApiModelProperty(value = "速度",required = true)
+    private int rate;
+
+    @ApiModelProperty(value = "音量",required = true)
+    private int playVolume;
+
+    @ApiModelProperty(value = "用户",required = false)
+    private String userId;
+
+    @ApiModelProperty(value = "课程编号",required = true)
+    private Long courseScheduleId;
+
+    public Long getCourseScheduleId() {
+        return courseScheduleId;
+    }
+
+    public void setCourseScheduleId(Long courseScheduleId) {
+        this.courseScheduleId = courseScheduleId;
+    }
+
+    public int getPlayVolume() {
+        return playVolume;
+    }
+
+    public void setPlayVolume(int playVolume) {
+        this.playVolume = playVolume;
+    }
+
+    public Boolean getEnable() {
+        return enable;
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+
+    public int getCustomType() {
+        return customType;
+    }
+
+    public void setCustomType(int customType) {
+        this.customType = customType;
+    }
+
+    public int getRate() {
+        return rate;
+    }
+
+    public void setRate(int rate) {
+        this.rate = rate;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    @Override
+    public String getType() {
+        return "DY:PlayMidiMessage";
+    }
+
+    @Override
+    public String toString() {
+        return "{\"enable\":" + enable +
+                ", \"customType\":" + customType +
+                ", \"rate\":" + rate +
+                ", \"playVolume\":" + playVolume +
+                ", \"userId\":" + (StringUtils.isEmpty(userId)?"\"\"":"\"" + userId + "\"") +
+                '}';
+    }
+}

+ 105 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkDeviceControlDto.java

@@ -0,0 +1,105 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+import com.yonge.cooleshow.biz.dal.enums.ImNetworkDeviceTypeEnum;
+import io.swagger.annotations.ApiModelProperty;
+
+public class ImNetworkDeviceControlDto {
+	@ApiModelProperty(value = "需要操作的类型",required = true)
+	private ImNetworkDeviceTypeEnum deviceType;
+
+	@ApiModelProperty(value = "开关",required = true)
+	private Boolean enable;
+
+	@ApiModelProperty(value = "房间号",required = true)
+	private String roomId;
+
+	@ApiModelProperty(value = "用户编号",required = true)
+	private Long userId;
+
+	@ApiModelProperty(value = "ticket",required = true)
+	private String ticket;
+
+	@ApiModelProperty(value = "状态",required = true)
+	private Integer status;
+
+	@ApiModelProperty(value = "原音",required = true)
+	private Integer examSongId;
+
+	@ApiModelProperty(value = "伴奏",required = true)
+	private Integer musicScoreAccompanimentId;
+
+	@ApiModelProperty(value = "伴奏音量",required = true)
+	private Integer soundVolume = 100;
+
+	public ImNetworkDeviceTypeEnum getDeviceType() {
+		return deviceType;
+	}
+
+	public void setDeviceType(ImNetworkDeviceTypeEnum deviceType) {
+		this.deviceType = deviceType;
+	}
+
+	public Boolean getEnable() {
+		return enable;
+	}
+
+	public void setEnable(Boolean enable) {
+		this.enable = enable;
+	}
+
+	public String getRoomId() {
+		return roomId;
+	}
+
+	public void setRoomId(String roomId) {
+		this.roomId = roomId;
+	}
+
+	public Long getUserId() {
+		return userId;
+	}
+
+	public void setUserId(Long userId) {
+		this.userId = userId;
+	}
+
+	public String getTicket() {
+		return ticket;
+	}
+
+	public void setTicket(String ticket) {
+		this.ticket = ticket;
+	}
+
+	public Integer getStatus() {
+		return status;
+	}
+
+	public void setStatus(Integer status) {
+		this.status = status;
+	}
+
+	public Integer getExamSongId() {
+		return examSongId;
+	}
+
+	public void setExamSongId(Integer examSongId) {
+		this.examSongId = examSongId;
+	}
+
+	public Integer getMusicScoreAccompanimentId() {
+		return musicScoreAccompanimentId;
+	}
+
+	public void setMusicScoreAccompanimentId(Integer musicScoreAccompanimentId) {
+		this.musicScoreAccompanimentId = musicScoreAccompanimentId;
+	}
+
+	public Integer getSoundVolume() {
+		return soundVolume;
+	}
+
+	public void setSoundVolume(Integer soundVolume) {
+		this.soundVolume = soundVolume;
+	}
+}

+ 71 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkDeviceStateChangedMessage.java

@@ -0,0 +1,71 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+
+import com.yonge.cooleshow.biz.dal.entity.BaseMessage;
+
+public class ImNetworkDeviceStateChangedMessage extends BaseMessage {
+    private boolean enable;
+    private int type;
+    private Integer musicScoreAccompanimentId;
+    private String userId;
+    private String userName;
+    private Integer soundVolume = 100;
+
+    public ImNetworkDeviceStateChangedMessage(int type, boolean enable) {
+        this.type = type;
+        this.enable = enable;
+    }
+
+    public boolean isEnable() {
+        return enable;
+    }
+
+    public void setEnable(boolean enable) {
+        this.enable = enable;
+    }
+
+    public int getType() {
+        return type;
+    }
+
+    public void setType(int type) {
+        this.type = type;
+    }
+
+    public Integer getMusicScoreAccompanimentId() {
+        return musicScoreAccompanimentId;
+    }
+
+    public void setMusicScoreAccompanimentId(Integer musicScoreAccompanimentId) {
+        this.musicScoreAccompanimentId = musicScoreAccompanimentId;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public Integer getSoundVolume() {
+        return soundVolume;
+    }
+
+    public void setSoundVolume(Integer soundVolume) {
+        this.soundVolume = soundVolume;
+    }
+
+    @Override
+    public String getObjectName() {
+        return "SC:DRMsg";
+    }
+}

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

@@ -0,0 +1,61 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+import com.yonge.cooleshow.biz.dal.enums.ImNetworkDisplayEnum;
+import io.swagger.annotations.ApiModelProperty;
+
+public class ImNetworkDisplayDataDto {
+
+	@ApiModelProperty(value = "房间号",required = true)
+    private String roomId;
+
+	@ApiModelProperty(value = "类型",required = true)
+    private ImNetworkDisplayEnum type;
+
+	@ApiModelProperty(value = "即将展示的对应人的 userId",required = true)
+    private String userId;
+
+	@ApiModelProperty(value = "display uri",required = true)
+    private String uri;
+
+	public String getRoomId() {
+		return roomId;
+	}
+
+	public void setRoomId(String roomId) {
+		this.roomId = roomId;
+	}
+
+	public ImNetworkDisplayEnum getType() {
+		return type;
+	}
+
+	public void setType(ImNetworkDisplayEnum type) {
+		this.type = type;
+	}
+
+	public String getUserId() {
+		return userId;
+	}
+
+	public void setUserId(String userId) {
+		this.userId = userId;
+	}
+
+	public String getUri() {
+		return uri;
+	}
+
+	public void setUri(String uri) {
+		this.uri = uri;
+	}
+
+	@Override
+	public String toString() {
+		return "ImNetworkDisplayDataDto{" +
+				"roomId='" + roomId + '\'' +
+				", type=" + type +
+				", userId='" + userId + '\'' +
+				", uri='" + uri + '\'' +
+				'}';
+	}
+}

+ 25 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkDisplayMessage.java

@@ -0,0 +1,25 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+import com.yonge.cooleshow.biz.dal.entity.BaseMessage;
+
+public class ImNetworkDisplayMessage extends BaseMessage {
+
+    private String display;
+
+    public String getDisplay() {
+        return display;
+    }
+
+    public void setDisplay(String display) {
+        this.display = display;
+    }
+
+    public ImNetworkDisplayMessage(String display) {
+        this.display = display;
+    }
+
+    @Override
+    public String getObjectName() {
+        return "SC:DisplayMsg";
+    }
+}

+ 38 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkMetronomeMessage.java

@@ -0,0 +1,38 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+import com.yonge.cooleshow.biz.dal.entity.BaseMessage;
+import org.apache.commons.lang3.StringUtils;
+
+//节拍器消息
+public class ImNetworkMetronomeMessage extends BaseMessage {
+    private ImNetworkCustomMessage content;
+
+    private static final transient String TYPE = "DY:PlayMidiMessage";
+
+    public ImNetworkMetronomeMessage(ImNetworkCustomMessage content) {
+        this.content = content;
+    }
+
+    public ImNetworkCustomMessage getContent() {
+        return content;
+    }
+
+    public void setContent(ImNetworkCustomMessage content) {
+        this.content = content;
+    }
+
+    @Override
+    public String toString() {
+        return "{\"enable\":" + content.getEnable() +
+                ", \"customType\":" + content.getCustomType() +
+                ", \"rate\":" + content.getRate() +
+                ", \"playVolume\":" + content.getPlayVolume() +
+                ", \"userId\":" + (StringUtils.isEmpty(content.getUserId())?"\"\"":"\"" + content.getUserId() + "\"") +
+                '}';
+    }
+
+    @Override
+    public String getObjectName() {
+        return TYPE;
+    }
+}

+ 83 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkMusicSheetDownDto.java

@@ -0,0 +1,83 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public class ImNetworkMusicSheetDownDto {
+	@ApiModelProperty(value = "房间号",required = true)
+	private String roomId;
+
+	@ApiModelProperty(value = "伴奏编号",required = true)
+	private Long musicSheetAccompanimentId;
+
+	@ApiModelProperty(value = "曲目编号",required = true)
+	private Long musicSheetId;
+
+	@ApiModelProperty(value = "用户编号",required = true)
+	private Long userId;
+
+	@ApiModelProperty(value = "0学生1老师")
+	private Integer userType;
+
+	@ApiModelProperty(value = "伴奏下载状态(1下载成功0下载中2下载失败)")
+	private Integer status;
+
+	public String getRoomId() {
+		return roomId;
+	}
+
+	public void setRoomId(String roomId) {
+		this.roomId = roomId;
+	}
+
+	public Long getMusicSheetAccompanimentId() {
+		return musicSheetAccompanimentId;
+	}
+
+	public void setMusicSheetAccompanimentId(Long musicSheetAccompanimentId) {
+		this.musicSheetAccompanimentId = musicSheetAccompanimentId;
+	}
+
+	public Long getMusicSheetId() {
+		return musicSheetId;
+	}
+
+	public void setMusicSheetId(Long musicSheetId) {
+		this.musicSheetId = musicSheetId;
+	}
+
+	public Long getUserId() {
+		return userId;
+	}
+
+	public void setUserId(Long userId) {
+		this.userId = userId;
+	}
+
+	public Integer getUserType() {
+		return userType;
+	}
+
+	public void setUserType(Integer userType) {
+		this.userType = userType;
+	}
+
+	public Integer getStatus() {
+		return status;
+	}
+
+	public void setStatus(Integer status) {
+		this.status = status;
+	}
+
+	@Override
+	public String toString() {
+		return "ImNetworkMusicScoreDownDto{" +
+				"roomId='" + roomId + '\'' +
+				", musicSheetAccompanimentId=" + musicSheetAccompanimentId +
+				", musicSheetId=" + musicSheetId +
+				", userId=" + userId +
+				", userType=" + userType +
+				", status=" + status +
+				'}';
+	}
+}

+ 28 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkMusicSheetDownloadMessage.java

@@ -0,0 +1,28 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+
+import com.yonge.cooleshow.biz.dal.entity.BaseMessage;
+
+public class ImNetworkMusicSheetDownloadMessage extends BaseMessage {
+    
+    private ImNetworkMusicSheetDownloadMessageContent content;
+    
+    private static final transient String TYPE = "DY:musicScoreDownloadMessage";
+
+    public ImNetworkMusicSheetDownloadMessage(ImNetworkMusicSheetDownloadMessageContent content) {
+        this.content = content;
+    }
+
+    public ImNetworkMusicSheetDownloadMessageContent getContent() {
+        return content;
+    }
+
+    public void setContent(ImNetworkMusicSheetDownloadMessageContent content) {
+        this.content = content;
+    }
+
+    @Override
+    public String getObjectName() {
+        return TYPE;
+    }
+}

+ 155 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkMusicSheetDownloadMessageContent.java

@@ -0,0 +1,155 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+
+public class ImNetworkMusicSheetDownloadMessageContent{
+    //伴奏编号
+    @ApiModelProperty(value = "伴奏编号")
+    private Integer id;
+
+    //曲目编号
+    @ApiModelProperty(value = "曲目编号")
+    private Integer musicSheetId;
+
+    //声部
+    @ApiModelProperty(value = "声部")
+    private Integer subjectId;
+
+    //声部
+    @ApiModelProperty(value = "声部")
+    private String subjectName;
+
+    //原音url
+    @ApiModelProperty(value = "原音url")
+    private String mp3Url = "";
+
+    //速度
+    @ApiModelProperty(value = "速度")
+    private Integer speed;
+
+    //xmlUrl
+    @ApiModelProperty(value = "xmlUrl")
+    private String xmlUrl = "";
+
+    //曲目名
+    @ApiModelProperty(value = "曲目名")
+    private String examSongName;
+
+    //标签名
+    @ApiModelProperty(value = "标签名")
+    private String categoriesName;
+
+    //标签分类
+    @ApiModelProperty(value = "标签分类")
+    private Integer categoriesId;
+
+    @ApiModelProperty(value = "类型")
+    private String type;
+
+    /**  */
+    @ApiModelProperty(value = "url")
+    private String url = "";
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getMusicSheetId() {
+        return musicSheetId;
+    }
+
+    public void setMusicSheetId(Integer musicSheetId) {
+        this.musicSheetId = musicSheetId;
+    }
+
+    public Integer getSubjectId() {
+        return subjectId;
+    }
+
+    public void setSubjectId(Integer subjectId) {
+        this.subjectId = subjectId;
+    }
+
+    public String getSubjectName() {
+        return subjectName;
+    }
+
+    public void setSubjectName(String subjectName) {
+        this.subjectName = subjectName;
+    }
+
+    public String getMp3Url() {
+        return mp3Url;
+    }
+
+    public void setMp3Url(String mp3Url) {
+        this.mp3Url = mp3Url;
+    }
+
+    public Integer getSpeed() {
+        return speed;
+    }
+
+    public void setSpeed(Integer speed) {
+        this.speed = speed;
+    }
+
+    public String getXmlUrl() {
+        return xmlUrl;
+    }
+
+    public void setXmlUrl(String xmlUrl) {
+        this.xmlUrl = xmlUrl;
+    }
+
+    public String getExamSongName() {
+        return examSongName;
+    }
+
+    public void setExamSongName(String examSongName) {
+        this.examSongName = examSongName;
+    }
+
+    public String getCategoriesName() {
+        return categoriesName;
+    }
+
+    public void setCategoriesName(String categoriesName) {
+        this.categoriesName = categoriesName;
+    }
+
+    public Integer getCategoriesId() {
+        return categoriesId;
+    }
+
+    public void setCategoriesId(Integer categoriesId) {
+        this.categoriesId = categoriesId;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    @Override
+    public String toString() {
+        return ToStringBuilder.reflectionToString(this);
+    }
+}

+ 38 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkMusicSheetDownloadStatusMessage.java

@@ -0,0 +1,38 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+
+import com.yonge.cooleshow.biz.dal.entity.BaseMessage;
+
+import java.util.List;
+
+public class ImNetworkMusicSheetDownloadStatusMessage extends BaseMessage {
+    private Integer studentId;
+
+    private List<CourseScheduleStudentMusicSheetResult> studentMusicScores;
+
+    public ImNetworkMusicSheetDownloadStatusMessage(Integer studentId, List<CourseScheduleStudentMusicSheetResult> studentMusicScores) {
+        this.studentId = studentId;
+        this.studentMusicScores = studentMusicScores;
+    }
+
+    public Integer getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(Integer studentId) {
+        this.studentId = studentId;
+    }
+
+    public List<CourseScheduleStudentMusicSheetResult> getStudentMusicScores() {
+        return studentMusicScores;
+    }
+
+    public void setStudentMusicScores(List<CourseScheduleStudentMusicSheetResult> studentMusicScores) {
+        this.studentMusicScores = studentMusicScores;
+    }
+
+    @Override
+    public String getObjectName() {
+        return "DY:MSDSMsg";
+    }
+}

+ 67 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkRoomMemberChangedMessage.java

@@ -0,0 +1,67 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+import com.yonge.cooleshow.biz.dal.entity.BaseMessage;
+import com.yonge.cooleshow.biz.dal.entity.ImNetworkRoomMember;
+import com.yonge.cooleshow.biz.dal.enums.ImNetworkRoomMemberChangedEnum;
+
+/**
+* @description: 用户房间状态变动消息
+* @author zx
+* @date 2022/4/6 14:02
+*/
+public class ImNetworkRoomMemberChangedMessage extends BaseMessage {
+
+    //节拍器是否开启
+    private boolean metronomeSwitch;
+
+    //伴奏是否开启
+    private boolean examSongSwitch;
+
+    //用户基本信息
+    private ImNetworkRoomMember roomMember;
+
+    //动作
+    private ImNetworkRoomMemberChangedEnum changedEnum;
+
+    public ImNetworkRoomMemberChangedMessage(ImNetworkRoomMember roomMember, ImNetworkRoomMemberChangedEnum changedEnum) {
+        this.roomMember = roomMember;
+        this.changedEnum = changedEnum;
+    }
+
+    public ImNetworkRoomMember getRoomMember() {
+        return roomMember;
+    }
+
+    public void setRoomMember(ImNetworkRoomMember roomMember) {
+        this.roomMember = roomMember;
+    }
+
+    public ImNetworkRoomMemberChangedEnum getChangedEnum() {
+        return changedEnum;
+    }
+
+    public void setChangedEnum(ImNetworkRoomMemberChangedEnum changedEnum) {
+        this.changedEnum = changedEnum;
+    }
+
+    public boolean isMetronomeSwitch() {
+        return metronomeSwitch;
+    }
+
+    public void setMetronomeSwitch(boolean metronomeSwitch) {
+        this.metronomeSwitch = metronomeSwitch;
+    }
+
+    public boolean isExamSongSwitch() {
+        return examSongSwitch;
+    }
+
+    public void setExamSongSwitch(boolean examSongSwitch) {
+        this.examSongSwitch = examSongSwitch;
+    }
+
+    @Override
+    public String getObjectName() {
+        return "SC:RMCMsg";
+    }
+}

+ 61 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkRoomMusicSheetData.java

@@ -0,0 +1,61 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+
+//学员伴奏下载
+public class ImNetworkRoomMusicSheetData {
+	@ApiModelProperty(value = "课程编号")
+	private Long courseScheduleId;
+
+	@ApiModelProperty(value = "伴奏编号")
+	private Integer musicSheetAccompanimentId;
+
+	@ApiModelProperty(value = "用户")
+	private Integer userId;
+
+	@ApiModelProperty(value = "0学生1老师")
+	private Integer userType;
+
+	@ApiModelProperty(value = "伴奏下载状态(1下载成功0下载中2下载失败)")
+	private Integer status;
+
+	public Integer getUserId() {
+		return userId;
+	}
+
+	public void setUserId(Integer userId) {
+		this.userId = userId;
+	}
+
+	public Integer getUserType() {
+		return userType;
+	}
+
+	public void setUserType(Integer userType) {
+		this.userType = userType;
+	}
+
+	public Integer getMusicSheetAccompanimentId() {
+		return musicSheetAccompanimentId;
+	}
+
+	public void setMusicSheetAccompanimentId(Integer musicSheetAccompanimentId) {
+		this.musicSheetAccompanimentId = musicSheetAccompanimentId;
+	}
+
+	public Integer getStatus() {
+		return status;
+	}
+
+	public void setStatus(Integer status) {
+		this.status = status;
+	}
+
+	public Long getCourseScheduleId() {
+		return courseScheduleId;
+	}
+
+	public void setCourseScheduleId(Long courseScheduleId) {
+		this.courseScheduleId = courseScheduleId;
+	}
+}

+ 61 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkRoomMusicSheetDownloadData.java

@@ -0,0 +1,61 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+
+//网络教室伴奏下载信息
+public class ImNetworkRoomMusicSheetDownloadData {
+    @ApiModelProperty(value = "伴奏下载状态(1下载成功0下载中2下载失败)")
+    private Integer status;
+
+    @ApiModelProperty(value = "伴奏原音")
+    private String url;
+
+    @ApiModelProperty(value = "伴奏名")
+    private String musicSheetName;
+
+    @ApiModelProperty(value = "伴奏编号")
+    private Long musicSheetId;
+
+    @ApiModelProperty(value = "是否开启伴奏")
+    private Boolean enable = false;
+
+    public Boolean getEnable() {
+        return enable;
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getMusicSheetName() {
+        return musicSheetName;
+    }
+
+    public void setMusicSheetName(String musicSheetName) {
+        this.musicSheetName = musicSheetName;
+    }
+
+    public Long getMusicSheetId() {
+        return musicSheetId;
+    }
+
+    public void setMusicSheetId(Long musicSheetId) {
+        this.musicSheetId = musicSheetId;
+    }
+}

+ 76 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkRoomResult.java

@@ -0,0 +1,76 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+import com.yonge.cooleshow.biz.dal.entity.ImNetworkRoom;
+import com.yonge.cooleshow.biz.dal.entity.ImNetworkRoomMember;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.List;
+
+public class ImNetworkRoomResult extends ImNetworkRoom {
+
+    @ApiModelProperty(value = "陪练课结束后,XX分钟关闭房间")
+    private String autoCloseNetworkRoomTime = "15";
+
+    @ApiModelProperty(value = "当前课程剩余时长")
+    private Integer surplusTime;
+
+    @ApiModelProperty(value = "房间成员列表,包含当前用户;")
+    private List<ImNetworkRoomMember> roomMemberList;
+
+    @ApiModelProperty(value = "当前用户")
+    private ImNetworkRoomMember roomMember;
+
+    @ApiModelProperty(value = "当前用户伴奏信息")
+    private List<CourseScheduleStudentMusicSheetResult> musicSheetResults;
+
+    @ApiModelProperty(value = "节拍器参数")
+    private ImNetworkCustomMessage midiJson = new ImNetworkCustomMessage();
+
+    public ImNetworkCustomMessage getMidiJson() {
+        return midiJson;
+    }
+
+    public void setMidiJson(ImNetworkCustomMessage midiJson) {
+        this.midiJson = midiJson;
+    }
+
+    public Integer getSurplusTime() {
+        return surplusTime;
+    }
+
+    public void setSurplusTime(Integer surplusTime) {
+        this.surplusTime = surplusTime;
+    }
+
+    public String getAutoCloseNetworkRoomTime() {
+        return autoCloseNetworkRoomTime;
+    }
+
+    public void setAutoCloseNetworkRoomTime(String autoCloseNetworkRoomTime) {
+        this.autoCloseNetworkRoomTime = autoCloseNetworkRoomTime;
+    }
+
+    public List<ImNetworkRoomMember> getRoomMemberList() {
+        return roomMemberList;
+    }
+
+    public void setRoomMemberList(List<ImNetworkRoomMember> roomMemberList) {
+        this.roomMemberList = roomMemberList;
+    }
+
+    public ImNetworkRoomMember getRoomMember() {
+        return roomMember;
+    }
+
+    public void setRoomMember(ImNetworkRoomMember roomMember) {
+        this.roomMember = roomMember;
+    }
+
+    public List<CourseScheduleStudentMusicSheetResult> getMusicSheetResults() {
+        return musicSheetResults;
+    }
+
+    public void setMusicSheetResults(List<CourseScheduleStudentMusicSheetResult> musicSheetResults) {
+        this.musicSheetResults = musicSheetResults;
+    }
+}

+ 42 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/ImNetworkRoomStatusNotify.java

@@ -0,0 +1,42 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+//网络教室状态回调
+public class ImNetworkRoomStatusNotify {
+    private String roomId;
+    private Long userId;
+    //成功、失败
+    private boolean requestStatus;
+
+    public String getRoomId() {
+        return roomId;
+    }
+
+    public void setRoomId(String roomId) {
+        this.roomId = roomId;
+    }
+
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    public boolean isRequestStatus() {
+        return requestStatus;
+    }
+
+    public void setRequestStatus(boolean requestStatus) {
+        this.requestStatus = requestStatus;
+    }
+
+    @Override
+    public String toString() {
+        return "ImNetworkRoomStatusNotify{" +
+                "roomId='" + roomId + '\'' +
+                ", userId=" + userId +
+                ", requestStatus=" + requestStatus +
+                '}';
+    }
+}

+ 54 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/NetworkRoomParamDto.java

@@ -0,0 +1,54 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+public class NetworkRoomParamDto {
+
+    private String userName;
+
+    private String roomId;
+
+    private String userId;
+
+    private boolean audience;
+
+    private boolean disableCamera;
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getRoomId() {
+        return roomId;
+    }
+
+    public void setRoomId(String roomId) {
+        this.roomId = roomId;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public boolean isAudience() {
+        return audience;
+    }
+
+    public void setAudience(boolean audience) {
+        this.audience = audience;
+    }
+
+    public boolean isDisableCamera() {
+        return disableCamera;
+    }
+
+    public void setDisableCamera(boolean disableCamera) {
+        this.disableCamera = disableCamera;
+    }
+}

+ 4 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/NetworkRoomResult.java

@@ -0,0 +1,4 @@
+package com.yonge.cooleshow.biz.dal.dto;
+
+public class NetworkRoomResult {
+}

+ 156 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/CourseScheduleStudentMusicSheet.java

@@ -0,0 +1,156 @@
+package com.yonge.cooleshow.biz.dal.entity;
+
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import com.baomidou.mybatisplus.annotation.TableId;
+
+import java.io.Serializable;
+
+/**
+ * (CourseScheduleStudentMusicSheet)表实体类
+ *
+ * @author zx
+ * @since 2022-04-02 15:56:01
+ */
+@ApiModel(value = "course_schedule_student_music_sheet-${tableInfo.comment}")
+public class CourseScheduleStudentMusicSheet implements Serializable {
+    @TableId(value = "id_", type = IdType.AUTO)
+    @ApiModelProperty(value = "主键")
+    private Long id;
+
+    @TableField("course_schedule_id_")
+    @ApiModelProperty(value = "课程编号")
+    private Long courseScheduleId;
+
+    @TableField("user_id_")
+    @ApiModelProperty(value = "用户编号")
+    private Long userId;
+
+    @TableField("down_status_")
+    @ApiModelProperty(value = "伴奏下载状态(1下载成功0下载中2下载失败)")
+    private Integer downStatus;
+
+    @TableField("music_sheet_accompaniment_id_")
+    @ApiModelProperty(value = "伴奏编号")
+    private Long musicSheetAccompanimentId;
+
+    @TableField("play_status_")
+    @ApiModelProperty(value = "原音播放状态(1是0否)")
+    private Integer playStatus;
+
+    @TableField("accompaniment_play_status_")
+    @ApiModelProperty(value = "伴奏播放状态")
+    private Integer accompanimentPlayStatus;
+
+    @TableField("user_type_")
+    @ApiModelProperty(value = "0学生1老师")
+    private Integer userType;
+
+    @TableField("speed_")
+    @ApiModelProperty(value = "播放速度")
+    private Integer speed;
+
+    @TableField("create_time_")
+    @ApiModelProperty(value = "${column.comment}")
+    private Date createTime;
+
+    @TableField("update_time_")
+    @ApiModelProperty(value = "${column.comment}")
+    private Date updateTime;
+
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getCourseScheduleId() {
+        return courseScheduleId;
+    }
+
+    public void setCourseScheduleId(Long courseScheduleId) {
+        this.courseScheduleId = courseScheduleId;
+    }
+
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    public Integer getDownStatus() {
+        return downStatus;
+    }
+
+    public void setDownStatus(Integer downStatus) {
+        this.downStatus = downStatus;
+    }
+
+    public Long getMusicSheetAccompanimentId() {
+        return musicSheetAccompanimentId;
+    }
+
+    public void setMusicSheetAccompanimentId(Long musicSheetAccompanimentId) {
+        this.musicSheetAccompanimentId = musicSheetAccompanimentId;
+    }
+
+    public Integer getPlayStatus() {
+        return playStatus;
+    }
+
+    public void setPlayStatus(Integer playStatus) {
+        this.playStatus = playStatus;
+    }
+
+    public Integer getAccompanimentPlayStatus() {
+        return accompanimentPlayStatus;
+    }
+
+    public void setAccompanimentPlayStatus(Integer accompanimentPlayStatus) {
+        this.accompanimentPlayStatus = accompanimentPlayStatus;
+    }
+
+    public Integer getUserType() {
+        return userType;
+    }
+
+    public void setUserType(Integer userType) {
+        this.userType = userType;
+    }
+
+    public Integer getSpeed() {
+        return speed;
+    }
+
+    public void setSpeed(Integer speed) {
+        this.speed = speed;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+}
+

+ 23 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/CourseScheduleStudentPayment.java

@@ -63,6 +63,29 @@ public class CourseScheduleStudentPayment implements Serializable {
     @ApiModelProperty(value = "类型 practice陪练课 live直播课")
     private String courseType;
 
+    @TableField("play_midi_")
+    @ApiModelProperty(value = "网络教室节拍器参数")
+    private String playMidi;
+
+    @TableField("music_sheet_download_json_")
+    @ApiModelProperty(value = "网络教室当前课程曲目下载信息")
+    private String musicSheetDownloadJson;
+
+    public String getMusicSheetDownloadJson() {
+        return musicSheetDownloadJson;
+    }
+
+    public void setMusicSheetDownloadJson(String musicSheetDownloadJson) {
+        this.musicSheetDownloadJson = musicSheetDownloadJson;
+    }
+
+    public String getPlayMidi() {
+        return playMidi;
+    }
+
+    public void setPlayMidi(String playMidi) {
+        this.playMidi = playMidi;
+    }
 
     public Long getId() {
         return id;

+ 8 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/IMApiResultInfo.java

@@ -40,4 +40,12 @@ public class IMApiResultInfo {
     public void setInChrm(Boolean inChrm) {
         isInChrm = inChrm;
     }
+
+    @Override
+    public String toString() {
+        return "IMApiResultInfo{" +
+                "code=" + code +
+                ", errorMessage='" + errorMessage + '\'' +
+                '}';
+    }
 }

+ 108 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ImNetworkRoom.java

@@ -0,0 +1,108 @@
+package com.yonge.cooleshow.biz.dal.entity;
+
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import com.baomidou.mybatisplus.annotation.TableId;
+
+import java.io.Serializable;
+
+/**
+ * 网络教室房间(ImNetworkRoom)表实体类
+ *
+ * @author zx
+ * @since 2022-03-30 16:36:36
+ */
+@ApiModel(value = "im_network_room-网络教室房间")
+public class ImNetworkRoom implements Serializable {
+    @TableId(value = "id_", type = IdType.AUTO)
+    @ApiModelProperty(value = "主键;")
+    private Long id;
+
+    @TableField("room_id_")
+    @ApiModelProperty(value = "房间编号;")
+    private String roomId;
+
+    @TableField("course_schedule_id_")
+    @ApiModelProperty(value = "课程编号")
+    private Long courseScheduleId;
+
+    @TableField("display_")
+    @ApiModelProperty(value = "用于移动端房间渲染")
+    //type 1老师0助教
+    private String display = "";
+
+    @TableField("sound_volume_")
+    @ApiModelProperty(value = "伴奏音量")
+    private Integer soundVolume = 100;
+
+    @TableField("update_time_")
+    @ApiModelProperty(value = "修改时间")
+    private Date updateTime;
+
+    @TableField("create_time_")
+    @ApiModelProperty(value = "创建时间;")
+    private Date createTime;
+
+    public Integer getSoundVolume() {
+        return soundVolume;
+    }
+
+    public void setSoundVolume(Integer soundVolume) {
+        this.soundVolume = soundVolume;
+    }
+
+    public String getDisplay() {
+        return display;
+    }
+
+    public void setDisplay(String display) {
+        this.display = display;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getRoomId() {
+        return roomId;
+    }
+
+    public void setRoomId(String roomId) {
+        this.roomId = roomId;
+    }
+
+    public Long getCourseScheduleId() {
+        return courseScheduleId;
+    }
+
+    public void setCourseScheduleId(Long courseScheduleId) {
+        this.courseScheduleId = courseScheduleId;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+}
+

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

@@ -0,0 +1,166 @@
+package com.yonge.cooleshow.biz.dal.entity;
+
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import com.baomidou.mybatisplus.annotation.TableId;
+
+import java.io.Serializable;
+
+/**
+ * 网络教室成员(ImNetworkRoomMember)表实体类
+ *
+ * @author zx
+ * @since 2022-03-30 16:36:37
+ */
+@ApiModel(value = "im_network_room_member-网络教室成员")
+public class ImNetworkRoomMember implements Serializable {
+    @TableId(value = "id_", type = IdType.AUTO)
+    @ApiModelProperty(value = "主键;")
+    private Long id;
+
+    @TableField("course_schedule_id_")
+    @ApiModelProperty(value = "课程编号")
+    private Long courseScheduleId;
+
+    @TableField("room_id_")
+    @ApiModelProperty(value = "房间号")
+    private String roomId;
+
+    @TableField("user_id_")
+    @ApiModelProperty(value = "用户编号")
+    private Long userId;
+
+    @TableField("username_")
+    @ApiModelProperty(value = "用户名")
+    private String username;
+
+    @TableField("avatar_")
+    @ApiModelProperty(value = "用户头像")
+    private String avatar;
+
+    @TableField("join_time_")
+    @ApiModelProperty(value = "进入时间;")
+    private Date joinTime;
+
+    @TableField("role_")
+    @ApiModelProperty(value = "角色0学员1老师;")
+    private Integer role;
+
+    @TableField("camera_flag_")
+    @ApiModelProperty(value = "是否开启摄像头;")
+    private boolean cameraFlag;
+
+    @TableField("mic_flag_")
+    @ApiModelProperty(value = "是否开启麦克风")
+    private boolean micFlag;
+
+    @TableField("music_mode_flag_")
+    @ApiModelProperty(value = "是否开启音乐模式")
+    private boolean musicModeFlag;
+
+    @TableField("hand_flag_")
+    @ApiModelProperty(value = "是否举手")
+    private boolean handFlag;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getAvatar() {
+        return avatar;
+    }
+
+    public void setAvatar(String avatar) {
+        this.avatar = avatar;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getCourseScheduleId() {
+        return courseScheduleId;
+    }
+
+    public void setCourseScheduleId(Long courseScheduleId) {
+        this.courseScheduleId = courseScheduleId;
+    }
+
+    public String getRoomId() {
+        return roomId;
+    }
+
+    public void setRoomId(String roomId) {
+        this.roomId = roomId;
+    }
+
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    public Date getJoinTime() {
+        return joinTime;
+    }
+
+    public void setJoinTime(Date joinTime) {
+        this.joinTime = joinTime;
+    }
+
+    public Integer getRole() {
+        return role;
+    }
+
+    public void setRole(Integer role) {
+        this.role = role;
+    }
+
+    public boolean isCameraFlag() {
+        return cameraFlag;
+    }
+
+    public void setCameraFlag(boolean cameraFlag) {
+        this.cameraFlag = cameraFlag;
+    }
+
+    public boolean isMicFlag() {
+        return micFlag;
+    }
+
+    public void setMicFlag(boolean micFlag) {
+        this.micFlag = micFlag;
+    }
+
+    public boolean isMusicModeFlag() {
+        return musicModeFlag;
+    }
+
+    public void setMusicModeFlag(boolean musicModeFlag) {
+        this.musicModeFlag = musicModeFlag;
+    }
+
+    public boolean isHandFlag() {
+        return handFlag;
+    }
+
+    public void setHandFlag(boolean handFlag) {
+        this.handFlag = handFlag;
+    }
+}
+

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

@@ -46,6 +46,10 @@ public class MusicSheetAccompaniment extends BaseEntity {
     @ApiModelProperty(value = "排序号")
     private Integer sortNumber;  //排序号
 
+    @TableField("speed_")
+    @ApiModelProperty(value = "速度")
+    private Integer speed;  //速度
+
     @TableField("create_time_")
     @ApiModelProperty(value = "创建时间")
     private java.util.Date createTime;  //创建时间
@@ -60,6 +64,14 @@ public class MusicSheetAccompaniment extends BaseEntity {
 	    return this;
 	}
 
+	public Integer getSpeed() {
+		return speed;
+	}
+
+	public void setSpeed(Integer speed) {
+		this.speed = speed;
+	}
+
 	public String getMetronomeUrl() {
 		return metronomeUrl;
 	}

+ 24 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/ImNetworkActionEnum.java

@@ -0,0 +1,24 @@
+package com.yonge.cooleshow.biz.dal.enums;
+
+import com.yonge.toolset.base.enums.BaseEnum;
+
+public enum ImNetworkActionEnum implements BaseEnum<String,ImNetworkActionEnum> {
+    INVITE("邀请"),
+    REJECT("拒绝"),
+    APPROVE("同意");
+
+    private String msg;
+
+    ImNetworkActionEnum(String msg) {
+        this.msg = msg;
+    }
+
+    @Override
+    public String getCode() {
+        return this.name();
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+}

+ 28 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/ImNetworkDeviceTypeEnum.java

@@ -0,0 +1,28 @@
+package com.yonge.cooleshow.biz.dal.enums;
+
+import com.yonge.toolset.base.enums.BaseEnum;
+
+public enum ImNetworkDeviceTypeEnum implements BaseEnum<String,ImNetworkDeviceTypeEnum> {
+    MICROPHONE("麦克风"),
+    CAMERA("摄像头"),
+    MUSIC_MODE("音乐模式"),
+    HAND_UP("举手"),
+    EXAM_SONG("伴奏陪练"),
+    MUSIC_SHEET("原音"),
+    ACCOMPANIMENT("伴奏");
+
+    private String msg;
+
+    ImNetworkDeviceTypeEnum(String msg) {
+        this.msg = msg;
+    }
+
+    @Override
+    public String getCode() {
+        return this.name();
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+}

+ 33 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/ImNetworkDisplayEnum.java

@@ -0,0 +1,33 @@
+package com.yonge.cooleshow.biz.dal.enums;
+
+// Display 定义格式如下:
+// display://type=1?userId=xxx?uri=xxxxx
+// 0,1,3 时,userId 有效,对应此人的 id,uri 无效
+// 2 时,展示白板,必须携带白板 uri
+// 4 时,清空当前 room 的 display
+
+import com.yonge.toolset.base.enums.BaseEnum;
+
+public enum ImNetworkDisplayEnum implements BaseEnum<String, ImNetworkDisplayEnum> {
+    TEACHER("老师"),
+    WHITE_BOARD("白板"),
+    SCREEN("屏幕"),
+    //清空当前 room 的 display
+    NONE("清空"),
+    STUDENT("学员");
+
+    private String msg;
+
+    ImNetworkDisplayEnum(String msg) {
+        this.msg = msg;
+    }
+
+    @Override
+    public String getCode() {
+        return this.name();
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+}

+ 73 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/ImNetworkRoomErrorEnum.java

@@ -0,0 +1,73 @@
+package com.yonge.cooleshow.biz.dal.enums;
+
+
+import com.yonge.toolset.base.enums.BaseEnum;
+
+public enum ImNetworkRoomErrorEnum implements BaseEnum<Integer,ImNetworkRoomErrorEnum> {
+    ERR_SUCCESS(200, "OK"),
+    ERR_REQUEST_PARA_ERR(1, "Missing or invalid parameter"),
+    ERR_INVALID_AUTH(2, "Invalid or expired authorization"),
+    ERR_ACCESS_DENIED(3, "Access denied"),
+    ERR_BAD_REQUEST(4, "Bad request"),
+
+    //IM error
+    ERR_IM_TOKEN_ERROR(10, "IM token error"),
+    ERR_CREATE_ROOM_ERROR(11, "Create room error"),
+    ERR_JOIN_ROOM_ERROR(12, "Join room error"),
+    JOIN_ROOM_ERROR(35, "加入房间失败,请前往线下教室"),
+    ROOM_NOT_START(36, "网络教室暂未开启,请稍后重试"),
+    CLOUD_BALANCE_NOT_FEE(37, "云教室受限不可进入,请联系教务老师。"),
+    ERR_MESSAGE_ERROR(13, "IM Message send error"),
+
+
+    //room error
+    ERR_ROOM_NOT_EXIST(20, "Room not exist"),
+    ERR_USER_NOT_EXIST_IN_ROOM(21, "User not exist in room"),
+    ERR_EXIT_ROOM_ERROR(22, "Exit room error"),
+    ERR_TEACHER_NOT_EXIST_IN_ROOM(23, "Teacher not exist in room"),
+    ERR_ASSISTANT_NOT_EXIST_IN_ROOM(24, "Assistant not exist in room"),
+    ERR_CREATE_WHITE_BOARD(25, "Create whiteboard error"),
+    ERR_WHITE_BOARD_NOT_EXIST(26, "Whiteboard not exist"),
+    ERR_DELETE_WHITE_BOARD(27, "Delete whiteboard error"),
+    ERR_USER_EXIST_IN_ROOM(28, "User exist in room"),
+    ERR_CHANGE_SELF_ROLE(29, "Can not change self role"),
+    ERR_APPLY_TICKET_INVALID(30, "Apply ticket invalid"),
+    ERR_OVER_MAX_COUNT(31, "云教室人数已超上线"),
+    ERR_TEACHER_EXIST_IN_ROOM(32, "Teacher exist in room"),
+    ERR_DOWNGRADE_ROLE(33, "Can't downgrade role"),
+    ERR_CHANGE_ROLE(34, "Only change student to teacher");
+
+    private int code;
+
+    private ImNetworkRoomErrorEnum(int code, String remark) {
+        this.code = code;
+        this.remark = remark;
+    }
+
+    private String remark;
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public static ImNetworkRoomErrorEnum codeOf(int code) {
+        for (ImNetworkRoomErrorEnum errorEnum : ImNetworkRoomErrorEnum.values()) {
+            if (code == errorEnum.getCode()) {
+                return errorEnum;
+            }
+        }
+        return null;
+    }
+}

+ 41 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/ImNetworkRoomMemberChangedEnum.java

@@ -0,0 +1,41 @@
+package com.yonge.cooleshow.biz.dal.enums;
+
+
+import com.yonge.toolset.base.enums.BaseEnum;
+
+/**
+* @description: 用户动作枚举
+* @author zx
+* @date 2022/4/6 13:59
+*/
+public enum ImNetworkRoomMemberChangedEnum implements BaseEnum<Integer, ImNetworkRoomMemberChangedEnum> {
+
+    JOIN(0,"加入"),
+    LEAVE(1,"离开"),
+    KICK(2,"踢出");
+
+    private Integer code;
+    private String msg;
+
+    ImNetworkRoomMemberChangedEnum(Integer code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    @Override
+    public Integer getCode() {
+        return this.code;
+    }
+}

+ 22 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/UserRoleEnum.java

@@ -0,0 +1,22 @@
+package com.yonge.cooleshow.biz.dal.enums;
+
+import com.yonge.toolset.base.enums.BaseEnum;
+
+public enum UserRoleEnum implements BaseEnum<String, UserRoleEnum> {
+    STUDENT("学生"),TEACHER("老师");
+
+    private String msg;
+
+    UserRoleEnum(String msg) {
+        this.msg = msg;
+    }
+
+    @Override
+    public String getCode() {
+        return this.name();
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+}

+ 17 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/CourseScheduleStudentMusicSheetService.java

@@ -0,0 +1,17 @@
+package com.yonge.cooleshow.biz.dal.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.yonge.cooleshow.biz.dal.dao.CourseScheduleStudentMusicSheetDao;
+import com.yonge.cooleshow.biz.dal.entity.CourseScheduleStudentMusicSheet;
+
+/**
+ * (CourseScheduleStudentMusicSheet)表服务接口
+ *
+ * @author zx
+ * @since 2022-04-02 15:56:01
+ */
+public interface CourseScheduleStudentMusicSheetService extends IService<CourseScheduleStudentMusicSheet> {
+
+    CourseScheduleStudentMusicSheetDao getDao();
+}
+

+ 27 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/CourseScheduleStudentPaymentService.java

@@ -2,6 +2,8 @@ package com.yonge.cooleshow.biz.dal.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.yonge.cooleshow.biz.dal.dao.CourseScheduleStudentPaymentDao;
+import com.yonge.cooleshow.biz.dal.dto.ImNetworkCustomMessage;
+import com.yonge.cooleshow.biz.dal.dto.ImNetworkRoomMusicSheetDownloadData;
 import com.yonge.cooleshow.biz.dal.entity.CourseScheduleStudentPayment;
 import com.yonge.cooleshow.biz.dal.enums.OrderStatusEnum;
 import com.yonge.cooleshow.biz.dal.vo.LiveCourseInfoVo;
@@ -45,5 +47,30 @@ public interface CourseScheduleStudentPaymentService extends IService<CourseSche
      * @return
      */
     List<String> getOrderNoByGroupId( Long courseGroupId);
+
+    /**
+    * @description: 获取网络教室成员midi
+     * @param courseScheduleId
+     * @param userId
+    * @return com.yonge.cooleshow.biz.dal.dto.ImNetworkCustomMessage
+    * @author zx
+    * @date 2022/4/6 14:15
+    */
+    ImNetworkCustomMessage getMemberMidi(long courseScheduleId, Long userId);
+
+    //获取伴奏信息
+    ImNetworkRoomMusicSheetDownloadData getMemberExamSong(long courseScheduleId, Long userId);
+
+    /**
+    * @description:
+     * @param scheduleId    课程编号
+     * @param userId    学员编号
+     * @param content   节拍器参数
+     * @param musicSheetJson    伴奏参数
+    * @return void
+    * @author zx
+    * @date 2022/5/7 16:44
+    */
+    void adjustPlayMidiAndMusicSheet(Long scheduleId, Long userId, String content, String musicSheetJson);
 }
 

+ 26 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImNetworkRoomMemberService.java

@@ -0,0 +1,26 @@
+package com.yonge.cooleshow.biz.dal.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+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.UserRoleEnum;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 网络教室成员(ImNetworkRoomMember)表服务接口
+ *
+ * @author zx
+ * @since 2022-03-30 16:36:38
+ */
+public interface ImNetworkRoomMemberService extends IService<ImNetworkRoomMember> {
+
+    ImNetworkRoomMemberDao getDao();
+
+    ImNetworkRoomMember initRoomMember(String roomId, BasicUserInfo sysUser, UserRoleEnum userRole);
+
+}
+

+ 62 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImNetworkRoomService.java

@@ -0,0 +1,62 @@
+package com.yonge.cooleshow.biz.dal.service;
+
+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.UserRoleEnum;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+
+/**
+ * 网络教室房间(ImNetworkRoom)表服务接口
+ *
+ * @author zx
+ * @since 2022-03-30 16:36:36
+ */
+public interface ImNetworkRoomService extends IService<ImNetworkRoom> {
+
+    ImNetworkRoomDao getDao();
+
+    //加入网络教室
+    HttpResponseResult<ImNetworkRoomResult> joinRoom(Long courseScheduleId, UserRoleEnum userRole) throws Exception;
+
+    //加入网络教室成功
+    void joinRoomSuccess(String roomId,Long userId) throws Exception;
+
+    //加入网络教室失败
+    void joinRoomFailure(String roomId);
+
+    //退出房间
+    void leaveRoom(String roomId,UserRoleEnum userRole) throws Exception;
+
+    //退出房间成功
+    void leaveRoomSuccess(String roomId, Long userId) throws Exception;
+
+    //控制用户节拍器
+    void sendImPlayMidiMessage(ImNetworkCustomMessage customMessage) throws Exception;
+
+    //老师通知学员下载伴奏
+    void pushDownloadMusicSheetMsg(String roomId,Long accompanimentId) throws Exception;
+
+    //移动端用来渲染页面
+    void display(ImNetworkDisplayDataDto displayData) throws Exception;
+
+    //批量控制学员设备开关
+    void batchControlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception;
+
+    //控制学员设备开关
+    void controlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception;
+
+    //学员同意打开,麦克风、摄像头等权限请求
+    void approveControlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception;
+
+    //学员拒绝打开,麦克风、摄像头等权限请求
+    void rejectControlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception;
+
+    //学员伴奏下载状态回调
+    void musicSheetDownNotify(String roomId, Long accompanimentId, Integer status) throws Exception;
+
+    //学员设备状态同步
+    void deviceStatusSync(ImNetworkDeviceControlDto deviceStatusSync) throws Exception;
+}
+

+ 2 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/MusicSheetAccompanimentService.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.service;
 
+import com.yonge.cooleshow.biz.dal.dao.MusicSheetAccompanimentDao;
 import com.yonge.cooleshow.biz.dal.entity.MusicSheetAccompaniment;
 import com.baomidou.mybatisplus.extension.service.IService;
 
@@ -17,4 +18,5 @@ public interface MusicSheetAccompanimentService extends IService<MusicSheetAccom
      * @param musicSheetId
      */
     void delByMusicSheetId(Long musicSheetId);
+    MusicSheetAccompanimentDao getDao();
 }

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

@@ -0,0 +1,29 @@
+package com.yonge.cooleshow.biz.dal.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.yonge.cooleshow.biz.dal.dao.CourseScheduleStudentMusicSheetDao;
+import com.yonge.cooleshow.biz.dal.entity.CourseScheduleStudentMusicSheet;
+import com.yonge.cooleshow.biz.dal.service.CourseScheduleStudentMusicSheetService;
+import org.springframework.stereotype.Service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * (CourseScheduleStudentMusicSheet)表服务实现类
+ *
+ * @author zx
+ * @since 2022-04-02 15:56:01
+ */
+@Service("courseScheduleStudentMusicSheetService")
+public class CourseScheduleStudentMusicSheetServiceImpl extends ServiceImpl<CourseScheduleStudentMusicSheetDao, CourseScheduleStudentMusicSheet> implements CourseScheduleStudentMusicSheetService {
+
+    private final static Logger log = LoggerFactory.getLogger(CourseScheduleStudentMusicSheetServiceImpl.class);
+
+    @Override
+    public CourseScheduleStudentMusicSheetDao getDao() {
+        return this.baseMapper;
+    }
+
+}
+

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

@@ -1,14 +1,22 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.yonge.cooleshow.biz.dal.dao.CourseScheduleStudentPaymentDao;
+import com.yonge.cooleshow.biz.dal.dto.ImNetworkCustomMessage;
+import com.yonge.cooleshow.biz.dal.dto.ImNetworkRoomMusicSheetDownloadData;
 import com.yonge.cooleshow.biz.dal.entity.CourseScheduleStudentPayment;
 import com.yonge.cooleshow.biz.dal.enums.CourseScheduleEnum;
 import com.yonge.cooleshow.biz.dal.service.CourseScheduleStudentPaymentService;
 import com.yonge.cooleshow.biz.dal.vo.LiveCourseInfoVo;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 
 import java.util.List;
@@ -64,5 +72,29 @@ public class CourseScheduleStudentPaymentServiceImpl extends ServiceImpl<CourseS
 
     }
 
+    @Override
+    public ImNetworkCustomMessage getMemberMidi(long courseScheduleId, Long userId) {
+        String midi = baseMapper.getMidiByCourseIdAndUserId(courseScheduleId, userId);
+        if(StringUtils.isNotEmpty(midi)){
+            return JSONObject.parseObject(midi, ImNetworkCustomMessage.class);
+        }
+        return new ImNetworkCustomMessage();
+    }
+
+    @Override
+    public ImNetworkRoomMusicSheetDownloadData getMemberExamSong(long courseScheduleId, Long userId) {
+        String musicSheet = baseMapper.getMusicSheetByCourseIdAndUserId(courseScheduleId, userId);
+        if(StringUtils.isNotEmpty(musicSheet)){
+            return JSONObject.parseObject(musicSheet, ImNetworkRoomMusicSheetDownloadData.class);
+        }
+        return new ImNetworkRoomMusicSheetDownloadData();
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void adjustPlayMidiAndMusicSheet(Long scheduleId, Long userId, String content, String musicSheetJson) {
+        baseMapper.adjustPlayMidiAndMusicSheet(scheduleId,userId,content,musicSheetJson);
+    }
+
 }
 

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

@@ -0,0 +1,58 @@
+package com.yonge.cooleshow.biz.dal.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+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.UserRoleEnum;
+import com.yonge.cooleshow.biz.dal.service.ImNetworkRoomMemberService;
+import org.springframework.stereotype.Service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * 网络教室成员(ImNetworkRoomMember)表服务实现类
+ *
+ * @author zx
+ * @since 2022-03-30 16:36:38
+ */
+@Service("imNetworkRoomMemberService")
+public class ImNetworkRoomMemberServiceImpl extends ServiceImpl<ImNetworkRoomMemberDao, ImNetworkRoomMember> implements ImNetworkRoomMemberService {
+
+    private final static Logger log = LoggerFactory.getLogger(ImNetworkRoomMemberServiceImpl.class);
+
+    @Override
+    public ImNetworkRoomMemberDao getDao() {
+        return this.baseMapper;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public ImNetworkRoomMember initRoomMember(String roomId, BasicUserInfo sysUser, UserRoleEnum userRole) {
+        ImNetworkRoomMember roomMember = baseMapper.findByRidAndUid(roomId, sysUser.getUserId());
+        if(Objects.isNull(roomMember)){
+            roomMember = new ImNetworkRoomMember();
+            roomMember.setRoomId(roomId);
+            roomMember.setCameraFlag(true);
+            roomMember.setHandFlag(false);
+            roomMember.setMicFlag(true);
+            roomMember.setMusicModeFlag(false);
+            roomMember.setRole(userRole.ordinal());
+            roomMember.setUserId(sysUser.getUserId());
+//            roomMember.setUsername(userRole == UserRoleEnum.STUDENT?sysUser.getUsername():sysUser.getRealName());
+            roomMember.setUsername(sysUser.getUsername());
+            roomMember.setAvatar(sysUser.getAvatar());
+            roomMember.setCourseScheduleId(Long.parseLong(roomId));
+            baseMapper.insert(roomMember);
+        }
+        return roomMember;
+    }
+
+}
+

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

@@ -0,0 +1,601 @@
+package com.yonge.cooleshow.biz.dal.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.extension.exceptions.ApiException;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.dao.ImNetworkRoomDao;
+import com.yonge.cooleshow.biz.dal.dao.SysConfigDao;
+import com.yonge.cooleshow.biz.dal.dao.TeacherDao;
+import com.yonge.cooleshow.biz.dal.dto.*;
+import com.yonge.cooleshow.biz.dal.entity.*;
+import com.yonge.cooleshow.biz.dal.enums.*;
+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.toolset.base.exception.BizException;
+import com.yonge.toolset.utils.date.DateUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static org.bouncycastle.asn1.cms.CMSObjectIdentifiers.data;
+
+/**
+ * 网络教室房间(ImNetworkRoom)表服务实现类
+ *
+ * @author zx
+ * @since 2022-03-30 16:36:36
+ */
+@Service("imNetworkRoomService")
+public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNetworkRoom> implements ImNetworkRoomService {
+
+    private final static Logger log = LoggerFactory.getLogger(ImNetworkRoomServiceImpl.class);
+
+    @Resource
+    private SysUserFeignService sysUserFeignService;
+    @Resource
+    private TeacherDao teacherDao;
+    @Resource
+    private ImNetworkRoomMemberService imNetworkRoomMemberService;
+    @Resource
+    private CourseScheduleStudentPaymentService courseScheduleStudentPaymentService;
+    @Resource
+    private CourseScheduleStudentMusicSheetService courseScheduleStudentMusicSheetService;
+    @Resource
+    private CourseScheduleService courseScheduleService;
+    @Resource
+    private SysConfigDao sysConfigDao;
+    @Resource
+    private IMHelper imHelper;
+    @Resource
+    private MusicSheetAccompanimentService musicSheetAccompanimentService;
+    @Resource
+    private MusicSheetService musicSheetService;
+
+    @Override
+    public ImNetworkRoomDao getDao() {
+        return this.baseMapper;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public HttpResponseResult<ImNetworkRoomResult> joinRoom(Long courseScheduleId, UserRoleEnum userRole) throws Exception {
+        log.info("joinRoom params:courseScheduleId:{},userRole:{}",courseScheduleId,userRole);
+        SysUser user = Optional.ofNullable(sysUserFeignService.queryUserInfo()).
+                orElseThrow(()-> new BizException("请登录"));
+        CourseSchedule courseSchedule = Optional.ofNullable(courseScheduleService.getById(courseScheduleId)).
+                orElseThrow(()->new BizException("房间信息不存在"));
+        BasicUserInfo sysUser = Optional.ofNullable(teacherDao.getBasicUserInfo(user.getId())).
+                orElseThrow(()-> new BizException("用户信息不存在"));
+        Date now = new Date();
+        courseSchedule.setUpdatedTime(now);
+        //是否提前进入教室
+        if (roomNotStart(courseSchedule)) {
+            return HttpResponseResult.failed(ImNetworkRoomErrorEnum.ROOM_NOT_START.getRemark());
+        }
+        String roomId = courseScheduleId.toString();
+        ImNetworkRoomResult joinRoomResult = new ImNetworkRoomResult();
+        //初始化房间信息
+        ImNetworkRoom room = this.initRoom(roomId,courseScheduleId,userRole,sysUser.getUserId(),now);
+        BeanUtils.copyProperties(room,joinRoomResult);
+        //定时销毁房间
+        //初始化房间用户信息
+        ImNetworkRoomMember roomMember = imNetworkRoomMemberService.initRoomMember(roomId,sysUser,userRole);
+        joinRoomResult.setRoomMember(roomMember);
+        //获取房间所有成员
+        List<ImNetworkRoomMember> roomMemberList = imNetworkRoomMemberService.getDao().queryByRoomId(roomId);
+        joinRoomResult.setRoomMemberList(roomMemberList);
+        //如果是老师,重置节拍器数据
+        if(userRole == UserRoleEnum.TEACHER){
+            courseScheduleStudentPaymentService.getDao().cleanPlayMidi(courseScheduleId);
+        }else {
+            //获取节拍器信息
+            joinRoomResult.setMidiJson(courseScheduleStudentPaymentService.getMemberMidi(courseScheduleId,sysUser.getUserId()));
+        }
+        //获取用户已下载的伴奏列表
+        List<CourseScheduleStudentMusicSheetResult> musicSheetResults = courseScheduleStudentMusicSheetService.getDao().
+                queryBySheetIdAndCourseId(null,courseScheduleId,sysUser.getUserId(),null,null);
+        joinRoomResult.setMusicSheetResults(musicSheetResults);
+        //课程结束后关闭教室的时间
+        String autoCloseNetworkRoomTime = sysConfigDao.findConfigValue(SysConfigConstant.DESTROY_EXPIRED_PRACTICE_ROOM_MINUTE);
+        joinRoomResult.setAutoCloseNetworkRoomTime(autoCloseNetworkRoomTime);
+        //获取课程剩余时长
+        DateUtil.secondsBetween(now, courseSchedule.getEndTime());
+        //创建、加入群聊
+        IMApiResultInfo resultInfo = imHelper.joinGroup(new String[]{sysUser.getUserId().toString()}, roomId, roomId);
+        if(resultInfo.getCode() != 200){
+            log.error("加入群聊失败 resultInfo:{}",resultInfo);
+//            throw new BizException("加入网络教室失败,请联系管理员");
+        }
+        return HttpResponseResult.succeed(joinRoomResult);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void joinRoomSuccess(String roomId,Long userId) throws Exception {
+        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)){
+            userRole = UserRoleEnum.TEACHER;
+        }
+        Date now = new Date();
+        //获取房间信息
+        this.initRoom(roomId, Long.parseLong(roomId), userRole, userId, now);
+        //获取房间用户信息
+        ImNetworkRoomMember roomMember = imNetworkRoomMemberService.initRoomMember(roomId,sysUser,userRole);
+        //发送加入房间的消息
+        ImNetworkRoomMemberChangedMessage msg = new ImNetworkRoomMemberChangedMessage(roomMember,ImNetworkRoomMemberChangedEnum.JOIN);
+        //获取节拍器信息
+        ImNetworkCustomMessage imNetworkCustomMessage = courseScheduleStudentPaymentService.getMemberMidi(Long.parseLong(roomId), userId);
+        msg.setMetronomeSwitch(imNetworkCustomMessage.getEnable());
+        //获取伴奏信息
+        ImNetworkRoomMusicSheetDownloadData musicSheetDownloadData = courseScheduleStudentPaymentService.getMemberExamSong(Long.parseLong(roomId), userId);
+        msg.setExamSongSwitch(musicSheetDownloadData.getEnable());
+        imHelper.publishMessage(userId.toString(), roomId, msg);
+        //记录考勤
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void joinRoomFailure(String roomId) {
+        SysUser sysUser = Optional.ofNullable(sysUserFeignService.queryUserInfo()).
+                orElseThrow(()-> new BizException("请登录"));
+        Long userId = sysUser.getId();
+        log.info("joinRoomFailure: roomId={}, userId={}", roomId, userId);
+        imNetworkRoomMemberService.getDao().delByRidAndUid(roomId, userId);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void leaveRoom(String roomId,UserRoleEnum userRole) throws Exception {
+        SysUser sysUser = Optional.ofNullable(sysUserFeignService.queryUserInfo()).
+                orElseThrow(()-> new BizException("请登录"));
+        Long userId = sysUser.getId();
+        log.info("leaveRoom: roomId={}, userId={}", roomId, userId);
+        long courseScheduleId = Long.parseLong(roomId);
+        if (userRole == UserRoleEnum.TEACHER){
+            //如果老师退出房间,关闭伴奏
+            courseScheduleStudentMusicSheetService.getDao().closePlayStatus(courseScheduleId,null);
+            courseScheduleStudentPaymentService.getDao().adjustPlayMidi(courseScheduleId, null, null);
+            courseScheduleStudentPaymentService.getDao().adjustExamSong(courseScheduleId, null, null);
+        }
+        ImNetworkRoomMember roomMember = imNetworkRoomMemberService.getDao().findByRidAndUid(roomId, userId);
+        //删除用户信息
+        imNetworkRoomMemberService.getDao().delByRidAndUid(roomId,userId);
+        //发送退出房间的消息
+        ImNetworkRoomMemberChangedMessage msg = new ImNetworkRoomMemberChangedMessage(roomMember,ImNetworkRoomMemberChangedEnum.JOIN);
+        imHelper.publishMessage(userId.toString(), roomId, msg);
+        imHelper.quit(new String[]{userId.toString()}, roomId);
+        //记录考勤信息
+        //是否删除房间信息
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void leaveRoomSuccess(String roomId, Long userId) throws Exception {
+        log.info("leaveRoomSuccess: roomId={}, userId={}", roomId, userId);
+        CourseSchedule courseSchedule = courseScheduleService.getById(roomId);
+        if(Objects.isNull(courseSchedule)){
+            return;
+        }
+        UserRoleEnum roleEnum = UserRoleEnum.STUDENT;
+        if(Objects.equals(courseSchedule.getTeacherId(),userId)){
+            roleEnum = UserRoleEnum.TEACHER;
+        }
+        //记录考勤信息
+
+        ImNetworkRoom room = baseMapper.findByRoomId(roomId);
+        if (roleEnum == UserRoleEnum.TEACHER){
+            if (isUserDisplay(room.getDisplay(), userId)) {
+                room.setDisplay("");
+                this.updateDisplay(userId,room);
+            }
+            //老师退出房间,初始化节拍器和伴奏播放配置
+            courseScheduleStudentPaymentService.adjustPlayMidiAndMusicSheet(courseSchedule.getId(), null, null,"");
+        }
+        ImNetworkRoomMember roomMember = imNetworkRoomMemberService.getDao().findByRidAndUid(roomId, userId);
+        int memberNum = imNetworkRoomMemberService.getDao().countByRoomId(roomId);
+        if (memberNum <= 1) {
+            imHelper.dismiss(userId.toString(), 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);
+            log.info("leaveRoomSuccess quit group: roomId={},userId: {}", roomId, userId);
+        }
+        //删房间用户信息
+        imNetworkRoomMemberService.getDao().deleteById(roomMember.getId());
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void sendImPlayMidiMessage(ImNetworkCustomMessage customMessage) throws Exception {
+        SysUser sysUser = Optional.ofNullable(sysUserFeignService.queryUserInfo()).
+                orElseThrow(()-> new BizException("请登录"));
+        Long userId = sysUser.getId();
+        Long courseScheduleId = customMessage.getCourseScheduleId();
+        log.info("sendImPlayMidiMessage: roomId={}, userId={}", courseScheduleId, userId);
+        ImNetworkMetronomeMessage displayMessage = new ImNetworkMetronomeMessage(customMessage);
+        imHelper.publishMessage(userId.toString(), courseScheduleId.toString(), displayMessage, 0);
+        //记录节拍器信息
+        courseScheduleStudentPaymentService.getDao().adjustPlayMidi(courseScheduleId,userId,customMessage.toString());
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void pushDownloadMusicSheetMsg(String roomId,Long accompanimentId) throws Exception {
+        SysUser sysUser = Optional.ofNullable(sysUserFeignService.queryUserInfo()).
+                orElseThrow(()-> new BizException("请登录"));
+        Long courseScheduleId = Long.parseLong(roomId);
+        List<CourseScheduleStudentMusicSheetResult> scheduleStudentMusicSheetResults = courseScheduleStudentMusicSheetService.getDao().
+                queryBySheetIdAndCourseId(accompanimentId, courseScheduleId, null, null, 0);
+
+        MusicSheetAccompaniment accompaniment = musicSheetAccompanimentService.getById(accompanimentId);
+        if (scheduleStudentMusicSheetResults.size() == 0) {
+            //第一次下载,生成数据
+            List<CourseScheduleStudentPayment> courseScheduleStudentPayments = courseScheduleStudentPaymentService.getDao().queryByCourseId(courseScheduleId);
+            Set<Long> studentIds = courseScheduleStudentPayments.stream().map(e -> e.getUserId()).collect(Collectors.toSet());
+            studentIds.forEach(e -> {
+                CourseScheduleStudentMusicSheetResult musicSheet = new CourseScheduleStudentMusicSheetResult();
+                musicSheet.setMusicSheetAccompanimentId(accompanimentId);
+                musicSheet.setSpeed(accompaniment.getSpeed());
+                musicSheet.setCourseScheduleId(courseScheduleId);
+                musicSheet.setUserId(e);
+                scheduleStudentMusicSheetResults.add(musicSheet);
+            });
+            CourseScheduleStudentMusicSheetResult musicSheet = new CourseScheduleStudentMusicSheetResult();
+            musicSheet.setMusicSheetAccompanimentId(accompanimentId);
+            musicSheet.setSpeed(accompaniment.getSpeed());
+            musicSheet.setCourseScheduleId(courseScheduleId);
+            musicSheet.setUserId(sysUser.getId());
+            musicSheet.setUserType(1);
+            scheduleStudentMusicSheetResults.add(musicSheet);
+            courseScheduleStudentMusicSheetService.getDao().batchInsert(scheduleStudentMusicSheetResults);
+        }
+        ImNetworkMusicSheetDownloadMessage msg = new ImNetworkMusicSheetDownloadMessage(
+                JSON.parseObject(JSON.toJSONString(accompaniment), ImNetworkMusicSheetDownloadMessageContent.class));
+        imHelper.publishMessage(sysUser.getId().toString(), roomId, msg, 0);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void display(ImNetworkDisplayDataDto displayData) throws Exception {
+        log.info("display in data = {}", displayData);
+        SysUser sysUser = Optional.ofNullable(sysUserFeignService.queryUserInfo()).
+                orElseThrow(()-> new BizException("请登录"));
+
+        StringBuffer display = new StringBuffer("display://type=").append(displayData.getType().ordinal()).append("?userId=");
+        switch (displayData.getType()) {
+            case NONE:
+                //清空当前 room 的 display
+                display = new StringBuffer();
+                break;
+            case TEACHER:
+                CourseSchedule courseSchedule = courseScheduleService.getById(displayData.getRoomId());
+                display.append(courseSchedule.getTeacherId()).append("?uri=");
+                break;
+            case SCREEN:
+                display.append(sysUser.getId()).append("?uri=");
+                break;
+            case STUDENT:
+                display.append(displayData.getUserId()).append("?uri=").append(displayData.getUri());
+                break;
+            default:
+                display.append(sysUser.getId()).append("?uri=").append(displayData.getUri());
+                break;
+        }
+        ImNetworkRoom room = baseMapper.findByRoomId(displayData.getRoomId());
+        room.setDisplay(display.toString());
+        this.updateDisplay(sysUser.getId(),room);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void batchControlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception {
+        ImNetworkDeviceTypeEnum deviceType = deviceControl.getDeviceType();
+        if (deviceControl.getUserId() != null) {
+            controlDevice(deviceControl);
+        } else {
+            if (deviceType == ImNetworkDeviceTypeEnum.EXAM_SONG ||
+                    deviceType == ImNetworkDeviceTypeEnum.MUSIC_SHEET ||
+                    deviceType == ImNetworkDeviceTypeEnum.ACCOMPANIMENT) {
+                List<CourseScheduleStudentPayment> studentPayments = courseScheduleStudentPaymentService.getDao().queryByCourseId(Long.parseLong(deviceControl.getRoomId()));
+                for (CourseScheduleStudentPayment studentPayment : studentPayments) {
+                    deviceControl.setUserId(studentPayment.getUserId());
+                    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());
+                        controlDevice(deviceControl);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void controlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception {
+        log.info("controlDevice in deviceControl = {}", deviceControl);
+        SysUser sysUser = Optional.ofNullable(sysUserFeignService.queryUserInfo()).
+                orElseThrow(()-> new BizException("请登录"));
+        String roomId = deviceControl.getRoomId();
+        Long userId = deviceControl.getUserId();
+        if(deviceControl.getEnable()){
+            long scheduleId = Long.parseLong(roomId);
+            ImNetworkDeviceStateChangedMessage deviceResourceMessage = new ImNetworkDeviceStateChangedMessage(deviceControl.getDeviceType().ordinal(),deviceControl.getEnable());
+            deviceResourceMessage.setUserId(userId.toString());
+            switch (deviceControl.getDeviceType()) {
+                case EXAM_SONG:
+                    ImNetworkRoomMusicSheetDownloadData msg = courseScheduleStudentPaymentService.getMemberExamSong(scheduleId, userId);
+                    msg.setEnable(deviceControl.getEnable());
+                    courseScheduleStudentPaymentService.getDao().adjustExamSong(scheduleId,userId, JSON.toJSONString(msg));
+                    imHelper.publishMessage(userId.toString(), deviceControl.getRoomId(), deviceResourceMessage, 1);
+                    break;
+                case MUSIC_SHEET:
+                    //关闭所有曲目播放
+                    courseScheduleStudentMusicSheetService.getDao().closePlayStatus(scheduleId,userId);
+                    //打开原音
+                    courseScheduleStudentMusicSheetService.getDao().openPlayStatus(scheduleId,deviceControl.getMusicScoreAccompanimentId(),userId);
+                    deviceResourceMessage.setMusicScoreAccompanimentId(deviceControl.getMusicScoreAccompanimentId());
+                    deviceResourceMessage.setUserId(userId.toString());
+                    deviceResourceMessage.setSoundVolume(deviceControl.getSoundVolume());
+                    imHelper.publishMessage(sysUser.getId().toString(), roomId, deviceResourceMessage, 1);
+                    break;
+                case ACCOMPANIMENT:
+                    //关闭所有曲目播放
+                    courseScheduleStudentMusicSheetService.getDao().closePlayStatus(scheduleId,userId);
+                    //打开伴奏
+                    courseScheduleStudentMusicSheetService.getDao().openAccompanimentPlayStatus(scheduleId, deviceControl.getMusicScoreAccompanimentId(),userId);
+                    deviceResourceMessage.setMusicScoreAccompanimentId(deviceControl.getMusicScoreAccompanimentId());
+                    deviceResourceMessage.setUserId(userId.toString());
+                    deviceResourceMessage.setSoundVolume(deviceControl.getSoundVolume());
+                    imHelper.publishMessage(sysUser.getId().toString(), roomId, deviceResourceMessage, 1);
+                    break;
+                default:
+                    //邀请打开指定设备权限
+                    ImNetworkControlDeviceNotifyMessage message = new ImNetworkControlDeviceNotifyMessage(ImNetworkActionEnum.INVITE.ordinal());
+//                    msg.setTicket(ticket);
+                    message.setType(deviceControl.getDeviceType().ordinal());
+                    message.setOpUserId(sysUser.getId().toString());
+                    message.setOpUserName(sysUser.getUsername());
+                    imHelper.publishMessage(sysUser.getId().toString(), userId.toString(), roomId, message);
+                    break;
+            }
+        }else {
+            ImNetworkRoomMember roomMember = imNetworkRoomMemberService.getById(roomId);
+            long scheduleId = Long.parseLong(roomId);
+            switch (deviceControl.getDeviceType()) {
+                case CAMERA:
+                    roomMember.setCameraFlag(deviceControl.getEnable());
+                    break;
+                case MICROPHONE:
+                    roomMember.setMicFlag(deviceControl.getEnable());
+                    break;
+                case HAND_UP:
+                    roomMember.setHandFlag(deviceControl.getEnable());
+                    break;
+                case MUSIC_MODE:
+                    roomMember.setMusicModeFlag(deviceControl.getEnable());
+                    break;
+                case EXAM_SONG:
+                    ImNetworkRoomMusicSheetDownloadData msg = courseScheduleStudentPaymentService.getMemberExamSong(scheduleId, userId);
+                    msg.setEnable(deviceControl.getEnable());
+                    courseScheduleStudentPaymentService.getDao().adjustExamSong(scheduleId,userId, JSON.toJSONString(msg));
+                    break;
+                case MUSIC_SHEET:
+                case ACCOMPANIMENT:
+                    //关闭所有曲目播放
+                    courseScheduleStudentMusicSheetService.getDao().closePlayStatus(scheduleId,userId);
+                    break;
+            }
+            if(deviceControl.getDeviceType() != ImNetworkDeviceTypeEnum.MUSIC_SHEET &&
+                    deviceControl.getDeviceType() != ImNetworkDeviceTypeEnum.EXAM_SONG &&
+                    deviceControl.getDeviceType() != ImNetworkDeviceTypeEnum.ACCOMPANIMENT){
+                imNetworkRoomMemberService.getDao().updateById(roomMember);
+            }
+            ImNetworkDeviceStateChangedMessage deviceResourceMessage = new ImNetworkDeviceStateChangedMessage(deviceControl.getDeviceType().ordinal(),deviceControl.getEnable());
+            deviceResourceMessage.setUserId(userId.toString());
+            BasicUserInfo basicUserInfo = teacherDao.getBasicUserInfo(userId);
+            if (Objects.nonNull(basicUserInfo)) {
+                deviceResourceMessage.setUserName(basicUserInfo.getUsername());
+            }
+            imHelper.publishMessage(sysUser.getId().toString(), roomId, deviceResourceMessage, 1);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void approveControlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception {
+        log.info("approveControlDevice: deviceControl={}", deviceControl);
+        SysUser sysUser = Optional.ofNullable(sysUserFeignService.queryUserInfo()).
+                orElseThrow(()-> new BizException("请登录"));
+        ImNetworkRoomMember roomMember = imNetworkRoomMemberService.getById(deviceControl.getRoomId());
+        switch (deviceControl.getDeviceType()) {
+            case CAMERA:
+                roomMember.setCameraFlag(deviceControl.getEnable());
+                break;
+            case EXAM_SONG:
+                long scheduleId = Long.parseLong(deviceControl.getRoomId());
+                ImNetworkRoomMusicSheetDownloadData msg = courseScheduleStudentPaymentService.getMemberExamSong(scheduleId, sysUser.getId());
+                msg.setEnable(deviceControl.getEnable());
+                courseScheduleStudentPaymentService.getDao().adjustExamSong(scheduleId, sysUser.getId(), JSON.toJSONString(msg));
+                break;
+            case MICROPHONE:
+                roomMember.setMicFlag(deviceControl.getEnable());
+                break;
+        }
+        if(deviceControl.getDeviceType() == ImNetworkDeviceTypeEnum.CAMERA ||
+                deviceControl.getDeviceType() == ImNetworkDeviceTypeEnum.MICROPHONE){
+            imNetworkRoomMemberService.getDao().updateById(roomMember);
+        }
+        ImNetworkControlDeviceNotifyMessage msg = new ImNetworkControlDeviceNotifyMessage(ImNetworkActionEnum.APPROVE.ordinal());
+        msg.setType(deviceControl.getDeviceType().ordinal());
+        msg.setOpUserId(sysUser.getId().toString());
+        msg.setOpUserName(sysUser.getUsername());
+        imHelper.publishMessage(sysUser.getId().toString(),deviceControl.getUserId().toString(), deviceControl.getRoomId(), msg);
+
+        ImNetworkDeviceStateChangedMessage deviceResourceMessage = new ImNetworkDeviceStateChangedMessage(deviceControl.getDeviceType().ordinal(),deviceControl.getEnable());
+        deviceResourceMessage.setUserId(sysUser.getId().toString());
+        imHelper.publishMessage(sysUser.getId().toString(), deviceControl.getRoomId(), deviceResourceMessage, 1);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deviceStatusSync(ImNetworkDeviceControlDto deviceStatusSync) throws Exception {
+        log.info("deviceStatusSync: deviceStatusSync={}", deviceStatusSync);
+        SysUser sysUser = Optional.ofNullable(sysUserFeignService.queryUserInfo()).
+                orElseThrow(()-> new BizException("请登录"));
+        ImNetworkDeviceTypeEnum deviceType = deviceStatusSync.getDeviceType();
+        ImNetworkRoomMember roomMember = imNetworkRoomMemberService.getById(deviceStatusSync.getRoomId());
+        switch (deviceType) {
+            case CAMERA:
+                roomMember.setCameraFlag(deviceStatusSync.getEnable());
+                break;
+            case MICROPHONE:
+                roomMember.setMicFlag(deviceStatusSync.getEnable());
+                break;
+            case HAND_UP:
+                roomMember.setHandFlag(deviceStatusSync.getEnable());
+                break;
+            case MUSIC_MODE:
+                roomMember.setMusicModeFlag(deviceStatusSync.getEnable());
+                break;
+            case EXAM_SONG:
+                long scheduleId = Long.parseLong(deviceStatusSync.getRoomId());
+                ImNetworkRoomMusicSheetDownloadData msg = courseScheduleStudentPaymentService.getMemberExamSong(scheduleId, sysUser.getId());
+                msg.setEnable(deviceStatusSync.getEnable());
+                courseScheduleStudentPaymentService.getDao().adjustExamSong(scheduleId, sysUser.getId(), JSON.toJSONString(msg));
+                break;
+        }
+        if(deviceType == ImNetworkDeviceTypeEnum.CAMERA ||
+                deviceType == ImNetworkDeviceTypeEnum.MICROPHONE ||
+                deviceType == ImNetworkDeviceTypeEnum.HAND_UP ||
+                deviceType == ImNetworkDeviceTypeEnum.MUSIC_MODE){
+            imNetworkRoomMemberService.getDao().updateById(roomMember);
+        }
+        ImNetworkDeviceStateChangedMessage deviceResourceMessage = new ImNetworkDeviceStateChangedMessage(deviceType.ordinal(),deviceStatusSync.getEnable());
+        deviceResourceMessage.setUserId(sysUser.getId().toString());
+        ImNetworkRoom room = this.getById(deviceStatusSync.getRoomId());
+        deviceResourceMessage.setSoundVolume(room.getSoundVolume());
+        imHelper.publishMessage(sysUser.getId().toString(), deviceStatusSync.getRoomId(), deviceResourceMessage, 1);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void rejectControlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception {
+        log.info("rejectControlDevice: deviceControl={}", deviceControl);
+        SysUser sysUser = Optional.ofNullable(sysUserFeignService.queryUserInfo()).
+                orElseThrow(()-> new BizException("请登录"));
+        ImNetworkControlDeviceNotifyMessage msg = new ImNetworkControlDeviceNotifyMessage(ImNetworkActionEnum.REJECT.ordinal());
+        msg.setType(deviceControl.getDeviceType().ordinal());
+        msg.setOpUserId(sysUser.getId().toString());
+        msg.setOpUserName(sysUser.getUsername());
+        imHelper.publishMessage(sysUser.getId().toString(),deviceControl.getUserId().toString(), deviceControl.getRoomId(), msg);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void musicSheetDownNotify(String roomId, Long accompanimentId, Integer status) throws Exception {
+        log.info("musicSheetDownNotify: roomId={},accompanimentId={},status={}", roomId,accompanimentId,status);
+        SysUser sysUser = Optional.ofNullable(sysUserFeignService.queryUserInfo()).
+                orElseThrow(()-> new BizException("请登录"));
+        Long scheduleId = Long.parseLong(roomId);
+        List<CourseScheduleStudentMusicSheetResult> studentMusicSheetResults = courseScheduleStudentMusicSheetService.getDao().queryBySheetIdAndCourseId(accompanimentId, scheduleId, sysUser.getId(), null, null);
+        if(CollectionUtils.isEmpty(studentMusicSheetResults)){
+            return;
+        }
+        if (accompanimentId != null) {
+            Optional.ofNullable(musicSheetAccompanimentService.getById(accompanimentId)).
+                    orElseThrow(()-> new BizException("曲目信息不存在"));
+            //修改下载状态
+            CourseScheduleStudentMusicSheetResult musicSheetResult = studentMusicSheetResults.get(0);
+            musicSheetResult.setDownStatus(status);
+            courseScheduleStudentMusicSheetService.updateById(musicSheetResult);
+        }
+        //给老师发送学员曲目下载状态
+        CourseSchedule courseSchedule = courseScheduleService.getById(scheduleId);
+        ImNetworkMusicSheetDownloadStatusMessage statusMessage = new ImNetworkMusicSheetDownloadStatusMessage(status,studentMusicSheetResults);
+        imHelper.publishMessage(sysUser.getId().toString(), courseSchedule.getTeacherId().toString(), roomId, statusMessage);
+    }
+
+    //校验用户是否提前进入教室
+    private boolean roomNotStart(CourseSchedule courseSchedule){
+        //是否提前进入教室
+        String courseBeforeBufferTime = sysConfigDao.findConfigValue(SysConfigConstant.PRE_CREATE_PRACTICE_ROOM_MINUTE);
+        if (StringUtils.isEmpty(courseBeforeBufferTime)) {
+            courseBeforeBufferTime = "5";
+        }
+        Date addMinutes = DateUtil.addMinutes(courseSchedule.getUpdatedTime(), Integer.parseInt(courseBeforeBufferTime));
+        return courseSchedule.getStartTime().compareTo(addMinutes) > 0;
+    }
+
+    public ImNetworkRoom initRoom(String roomId,Long courseId,UserRoleEnum userRole,Long userId,Date now) throws Exception {
+        ImNetworkRoom room = baseMapper.findByRoomId(roomId);
+        String display = "";
+        if (userRole == UserRoleEnum.TEACHER) {
+            display = "display://type=1?userId=" + userId + "?uri=";
+        }
+        if(Objects.isNull(room)){
+            room = new ImNetworkRoom();
+            //创建房间
+            room.setCourseScheduleId(courseId);
+            room.setRoomId(roomId);
+            room.setCreateTime(now);
+            room.setUpdateTime(now);
+            room.setDisplay(display);
+            baseMapper.insert(room);
+            IMApiResultInfo resultInfo = imHelper.createGroup(new String[]{userId.toString()}, roomId, roomId);
+            if(resultInfo.getCode() != 200){
+                log.error("创建群聊失败 resultInfo:{}",resultInfo);
+                throw new BizException("加入网络教室失败,请联系管理员");
+            }
+        }else {
+            if(userRole == UserRoleEnum.TEACHER){
+                //修改节拍器
+                room.setDisplay(display);
+                this.updateDisplay(userId,room);
+            }
+        }
+        return room;
+    }
+
+    //修改节拍器
+    public void updateDisplay(Long userId,ImNetworkRoom room) throws Exception {
+        baseMapper.updateById(room);
+        //发送display改动通知
+        ImNetworkDisplayMessage displayMessage = new ImNetworkDisplayMessage(room.getDisplay());
+        imHelper.publishMessage(userId.toString(), room.getRoomId(), displayMessage, 0);
+    }
+
+    public boolean isUserDisplay(String display, Long userId) {
+        boolean result = false;
+        if (!display.isEmpty() && display.contains("userId=" + userId)) {
+            if (display.contains("type=0") || display.contains("type=1") || display.contains("type=3")) {
+                result = true;
+            }
+        }
+        return result;
+    }
+}

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

@@ -23,6 +23,7 @@ public class MusicSheetAccompanimentServiceImpl extends ServiceImpl<MusicSheetAc
     @Autowired
     private MusicSheetAccompanimentDao musicSheetAccompanimentDao;
 
+    @Override
     public MusicSheetAccompanimentDao getDao() {
         return musicSheetAccompanimentDao;
     }

+ 84 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/CourseScheduleStudentMusicSheetDao.xml

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.yonge.cooleshow.biz.dal.dao.CourseScheduleStudentMusicSheetDao">
+    <resultMap id="BaseResultMap" type="com.yonge.cooleshow.biz.dal.entity.CourseScheduleStudentMusicSheet">
+        <id column="id_" jdbcType="INTEGER" property="id"/>
+        <result column="course_schedule_id_" jdbcType="INTEGER" property="courseScheduleId"/>
+        <result column="user_id_" jdbcType="INTEGER" property="userId"/>
+        <result column="down_status_" jdbcType="INTEGER" property="downStatus"/>
+        <result column="music_sheet_accompaniment_id_" jdbcType="INTEGER" property="musicSheetAccompanimentId"/>
+        <result column="play_status_" jdbcType="INTEGER" property="playStatus"/>
+        <result column="accompaniment_play_status_" jdbcType="INTEGER" property="accompanimentPlayStatus"/>
+        <result column="user_type_" jdbcType="INTEGER" property="userType"/>
+        <result column="speed_" jdbcType="INTEGER" property="speed"/>
+        <result column="create_time_" jdbcType="TIMESTAMP" property="createTime"/>
+        <result column="update_time_" jdbcType="TIMESTAMP" property="updateTime"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id_
+        , course_schedule_id_, user_id_, down_status_, music_sheet_accompaniment_id_, play_status_,
+    accompaniment_play_status_, user_type_, speed_, create_time_, update_time_
+    </sql>
+    <insert id="batchInsert">
+        INSERT INTO course_schedule_student_music_score (course_schedule_id_,user_id_,user_type_,down_status_,
+        music_sheet_accompaniment_id_,play_status_,accompaniment_play_status_,
+                                                         speed_,create_time_,update_time_)
+        VALUE
+        <foreach collection="musicSheet" item="item" separator=",">
+            (#{item.courseScheduleId},#{item.userId},#{item.userType},#{item.downStatus},#{item.musicScoreAccompanimentId},
+            #{item.playStatus},#{item.accompanimentPlayStatus},#{item.speed},now(),now())
+        </foreach>
+    </insert>
+    <update id="closePlayStatus">
+        UPDATE course_schedule_student_music_sheet SET play_status_ = 0,accompaniment_play_status_ = 0,update_time_ = NOW()
+        WHERE course_schedule_id_ = #{courseId}
+        <if test="userId != null">
+            AND user_id_ = #{userId}
+        </if>
+    </update>
+    <update id="openPlayStatus">
+        UPDATE course_schedule_student_music_sheet SET play_status_ = 1,update_time_ = NOW()
+        WHERE course_schedule_id_ = #{scheduleId}
+        AND music_score_accompaniment_id_ = #{musicScoreAccompanimentId}
+        <if test="userId != null">
+            AND user_id_ = #{userId}
+        </if>
+    </update>
+    <update id="openAccompanimentPlayStatus">
+        UPDATE course_schedule_student_music_sheet SET accompaniment_play_status_ = 1,update_time_ = NOW()
+        WHERE course_schedule_id_ = #{scheduleId} AND music_score_accompaniment_id_ = #{musicScoreAccompanimentId}
+        <if test="userId != null">
+            AND user_id_ = #{userId}
+        </if>
+    </update>
+
+    <resultMap id="CourseScheduleStudentMusicSheetResult" type="com.yonge.cooleshow.biz.dal.dto.CourseScheduleStudentMusicSheetResult" extends="BaseResultMap">
+        <result property="audioFileUrl" column="audio_file_url_"/>
+        <result property="mp3Url" column="mp3_url_"/>
+        <result property="musicSheetName" column="music_sheet_name_"/>
+    </resultMap>
+    <select id="queryBySheetIdAndCourseId" resultMap="CourseScheduleStudentMusicSheetResult">
+        SELECT cssm.*,msa.audio_file_url_ mp3_url_,ms.audio_file_url_,ms.music_sheet_name_  FROM course_schedule_student_music_sheet cssm
+        LEFT JOIN music_sheet_accompaniment msa ON cssm.music_sheet_accompaniment_id_ = msa.id_
+        LEFT JOIN music_sheet ms ON ms.id_ = msa.music_sheet_id_
+        <where>
+            <if test="courseId != null">
+                AND cssm.course_schedule_id_ = #{courseId}
+            </if>
+            <if test="musicSheetAccompanimentId != null">
+                AND cssm.music_sheet_accompaniment_id_ = #{musicSheetAccompanimentId}
+            </if>
+            <if test="userType != null">
+                AND cssm.user_type_ = #{userType}
+            </if>
+            <if test="userId != null">
+                AND cssm.user_id_ = #{userId}
+            </if>
+            <if test="downStatus != null">
+                AND cssm.down_status_ = #{downStatus}
+            </if>
+        </where>
+    </select>
+
+</mapper>

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

@@ -17,7 +17,8 @@
 
     <sql id="Base_Column_List">
         id_
-        , user_id_, course_group_id_, course_id_, order_no_, original_price_, expect_price_, actual_price_, created_time_, updated_time_, course_type_
+        , user_id_, course_group_id_, course_id_, order_no_, original_price_, expect_price_,
+        actual_price_, created_time_, updated_time_, course_type_
     </sql>
 
     <insert id="insertBatch" keyColumn="id_" keyProperty="id" useGeneratedKeys="true"
@@ -32,6 +33,53 @@
         </foreach>
     </insert>
 
+    <update id="cleanPlayMidi">
+        UPDATE course_schedule_student_payment SET play_midi_ = NULL WHERE course_id_ = #{courseScheduleId}
+    </update>
+    <update id="adjustPlayMidi">
+        UPDATE course_schedule_student_payment cssp
+        <set>
+            <if test="content == null or content == ''">
+                cssp.play_midi_ = NULL,cssp.update_time_ = NOW()
+            </if>
+            <if test="content != null and content != ''">
+                cssp.play_midi_ = #{content},cssp.update_time_ = NOW()
+            </if>
+        </set>
+        <where>
+            cssp.course_id_ = #{courseScheduleId}
+            <if test="userId != null and userId != ''">
+                AND FIND_IN_SET(cssp.user_id_,#{userId})
+            </if>
+        </where>
+    </update>
+    <update id="adjustExamSong">
+        UPDATE course_schedule_student_payment SET music_sheet_download_json_ = #{examSongJson}
+        WHERE course_id_ = #{roomId}
+        <if test="userId != null">
+            AND user_id_ = #{userId}
+        </if>
+    </update>
+    <update id="adjustPlayMidiAndMusicSheet">
+        UPDATE course_schedule_student_payment cssp
+        <set>
+            <if test="content == null or content == ''">
+                cssp.open_play_midi_ = NULL,cssp.update_time_ = NOW()
+            </if>
+            <if test="content != null and content != ''">
+                cssp.open_play_midi_ = #{content},cssp.update_time_ = NOW()
+            </if>
+            <if test="examSongJson != null">
+                cssp.exam_song_download_json_ = #{examSongJson}
+            </if>
+        </set>
+        <where>
+            cssp.course_schedule_id_ = #{courseScheduleId}
+            <if test="userId != null and userId != ''">
+                AND FIND_IN_SET(cssp.user_id_,#{userId})
+            </if>
+        </where>
+    </update>
     <select id="queryStudentIds" resultType="java.lang.Long">
         SELECT DISTINCT user_id_ FROM course_schedule_student_payment
         <where>
@@ -43,6 +91,18 @@
             </if>
         </where>
     </select>
+    <select id="getMidiByCourseIdAndUserId" resultType="java.lang.String">
+        SELECT play_midi_ FROM course_schedule_student_payment
+        WHERE user_id_ = #{userId} AND course_id_ = #{courseScheduleId} LIMIT 1
+    </select>
+    <select id="getMusicSheetByCourseIdAndUserId" resultType="java.lang.String">
+        SELECT music_sheet_download_json_ FROM course_schedule_student_payment
+        WHERE user_id_ = #{userId} AND course_id_ = #{courseScheduleId} LIMIT 1
+    </select>
+    <select id="queryByCourseId" resultMap="BaseResultMap">
+        SELECT <include refid="Base_Column_List"/> FROM course_schedule_student_payment
+        WHERE course_id_ = #{courseScheduleId}
+    </select>
 
     <select id="queryStudentInfoByGroupId" parameterType="map" resultType="com.yonge.cooleshow.biz.dal.vo.LiveCourseInfoVo$CourseBuyStudentVo">
         select distinct a.user_id_      as studentId,

+ 22 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/ImNetworkRoomMapper.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.yonge.cooleshow.biz.dal.dao.ImNetworkRoomDao">
+    <resultMap id="BaseResultMap" type="com.yonge.cooleshow.biz.dal.entity.ImNetworkRoom">
+        <id column="id_" jdbcType="INTEGER" property="id"/>
+        <result column="room_id_" jdbcType="VARCHAR" property="roomId"/>
+        <result column="course_schedule_id_" jdbcType="INTEGER" property="courseScheduleId"/>
+        <result column="display_" jdbcType="VARCHAR" property="display"/>
+        <result column="sound_volume_" jdbcType="INTEGER" property="soundVolume"/>
+        <result column="update_time_" jdbcType="TIMESTAMP" property="updateTime"/>
+        <result column="create_time_" jdbcType="TIMESTAMP" property="createTime"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id_ , room_id_, course_schedule_id_,display_,sound_volume_, update_time_, create_time_
+    </sql>
+
+    <select id="findByRoomId" resultMap="BaseResultMap">
+        SELECT * FROM im_network_room WHERE room_id_ = #{roomId} LIMIT 1
+    </select>
+
+</mapper>

+ 62 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/ImNetworkRoomMemberMapper.xml

@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.yonge.cooleshow.biz.dal.dao.ImNetworkRoomMemberDao">
+    <resultMap id="BaseResultMap" type="com.yonge.cooleshow.biz.dal.entity.ImNetworkRoomMember">
+        <id column="id_" jdbcType="INTEGER" property="id"/>
+        <result column="course_schedule_id_" jdbcType="INTEGER" property="courseScheduleId"/>
+        <result column="room_id_" jdbcType="VARCHAR" property="roomId"/>
+        <result column="user_id_" jdbcType="INTEGER" property="userId"/>
+        <result column="username_" jdbcType="VARCHAR" property="username"/>
+        <result column="avatar_" jdbcType="VARCHAR" property="avatar"/>
+        <result column="join_time_" jdbcType="TIMESTAMP" property="joinTime"/>
+        <result column="role_" jdbcType="INTEGER" property="role"/>
+        <result column="camera_flag_" jdbcType="BOOLEAN" property="cameraFlag"/>
+        <result column="mic_flag_" jdbcType="BOOLEAN" property="micFlag"/>
+        <result column="music_mode_flag_" jdbcType="BOOLEAN" property="musicModeFlag"/>
+        <result column="hand_flag_" jdbcType="BOOLEAN" property="handFlag"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id_
+        , course_schedule_id_, room_id_, user_id_, join_time_, role_,
+        camera_flag_, mic_flag_, music_mode_flag_, hand_flag_,username_,avatar_
+    </sql>
+
+    <insert id="insertBatch" keyColumn="id_" keyProperty="id" useGeneratedKeys="true"
+            parameterType="com.yonge.cooleshow.biz.dal.entity.ImNetworkRoomMember">
+        insert into im_network_room_member(course_schedule_id_, room_id_, user_id_, join_time_, role_, camera_flag_,
+        mic_flag_, music_mode_flag_, hand_flag_,username_,avatar_)
+        values
+        <foreach collection="entities" item="entity" separator=",">
+            (#{entity.courseScheduleId}, #{entity.roomId}, #{entity.userId}, #{entity.joinTime}, #{entity.role},
+            #{entity.cameraFlag}, #{entity.micFlag}, #{entity.musicModeFlag}, #{entity.handFlag}, #{entity.username}, #{entity.avatar})
+        </foreach>
+    </insert>
+    <insert id="insert" keyColumn="id_" keyProperty="id" useGeneratedKeys="true"
+            parameterType="com.yonge.cooleshow.biz.dal.entity.ImNetworkRoomMember">
+        INSERT INTO im_network_room_member(course_schedule_id_, room_id_, user_id_, join_time_, role_, camera_flag_,
+                                           mic_flag_, music_mode_flag_, hand_flag_,username_,avatar_)
+        VALUES (#{entity.courseScheduleId}, #{entity.roomId}, #{entity.userId},NOW(), #{entity.role},
+                #{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_))
+    </insert>
+    <delete id="delByRidAndUid">
+        DELETE FROM im_network_room_member WHERE room_id_ = #{roomId} AND user_id_ = #{userId}
+    </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
+    </select>
+    <select id="queryByRoomId" resultMap="BaseResultMap">
+        SELECT <include refid="Base_Column_List"/> FROM im_network_room_member WHERE room_id_ = #{roomId}
+    </select>
+    <select id="countByRoomId" resultType="java.lang.Integer">
+        SELECT id_ FROM im_network_room_member WHERE room_id_ = #{roomId}
+    </select>
+    <select id="findByRoomAndRole" resultMap="BaseResultMap">
+        SELECT <include refid="Base_Column_List"/> FROM im_network_room_member WHERE room_id_ = #{roomId} AND role_ = #{role}
+    </select>
+
+</mapper>

+ 3 - 2
cooleshow-user/user-biz/src/main/resources/config/mybatis/MusicSheetAccompanimentMapper.xml

@@ -9,15 +9,16 @@
 		 <result column="music_subject_" jdbcType="VARCHAR" property="musicSubject" />
 		 <result column="audio_file_url_" jdbcType="VARCHAR" property="audioFileUrl" />
 		 <result column="sort_number_" jdbcType="TINYINT" property="sortNumber" />
+		 <result column="speed_" jdbcType="TINYINT" property="speed" />
 		 <result column="create_time_" jdbcType="TIMESTAMP" property="createTime" />
 		 <result column="create_by_" jdbcType="BIGINT" property="createBy" />
 	</resultMap>
 
 	<sql id="Base_Column_List">
-		id_, music_sheet_id_, music_subject_, audio_file_url_, sort_number_, create_time_, create_by_
+		id_, music_sheet_id_, music_subject_, audio_file_url_, sort_number_,speed_, create_time_, create_by_
 	</sql>
 
 	<delete id="delByMusicSheetId">
-		delete  from music_sheet_accompaniment where music_sheet_id_ = #{musicSheetId}
+		delete from music_sheet_accompaniment where music_sheet_id_ = #{musicSheetId}
     </delete>
 </mapper>

+ 80 - 0
cooleshow-user/user-classroom/pom.xml

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>cooleshow</artifactId>
+        <groupId>com.yonge.cooleshow</groupId>
+        <version>1.0</version>
+    </parent>
+    <groupId>com.yonge.cooleshow</groupId>
+    <artifactId>user-classroom</artifactId>
+    <version>1.0</version>
+    <name>user-classroom</name>
+    <url>http://maven.apache.org</url>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-security</artifactId>
+        </dependency>
+
+        <!-- swagger-spring-boot -->
+        <dependency>
+            <groupId>com.spring4all</groupId>
+            <artifactId>swagger-spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.yonge.toolset</groupId>
+            <artifactId>audit-log</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.yonge.toolset</groupId>
+            <artifactId>thirdparty-component</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.yonge.cooleshow</groupId>
+            <artifactId>user-biz</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.whvcse</groupId>
+            <artifactId>easy-captcha</artifactId>
+            <version>1.6.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.security.oauth</groupId>
+            <artifactId>spring-security-oauth2</artifactId>
+            <version>2.3.3.RELEASE</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 28 - 0
cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/ClassroomApplication.java

@@ -0,0 +1,28 @@
+package com.yonge.cooleshow.classroom;
+
+import com.spring4all.swagger.EnableSwagger2Doc;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+@SpringBootApplication
+@EnableDiscoveryClient
+@EnableFeignClients("com.yonge.cooleshow")
+@MapperScan(basePackages = {"com.yonge.cooleshow.biz.dal.dao", "com.yonge.toolset.payment.core.dao"})
+@ComponentScan(basePackages = {
+        "com.yonge.cooleshow.classroom", "com.yonge.cooleshow.auth", "com.yonge.cooleshow.biz",
+        "com.yonge.cooleshow.common", "com.yonge.cooleshow.common.security",
+        "com.yonge.toolset.log", "com.yonge.toolset.thirdparty", "com.yonge.toolset.payment"
+})
+@Configuration
+@EnableSwagger2Doc
+public class ClassroomApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(ClassroomApplication.class, args);
+    }
+
+}

+ 43 - 0
cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/config/ResourceServerConfig.java

@@ -0,0 +1,43 @@
+package com.yonge.cooleshow.classroom.config;
+
+import com.yonge.cooleshow.common.security.BaseAccessDeniedHandler;
+import com.yonge.cooleshow.common.security.BaseAuthenticationEntryPoint;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
+
+@Configuration
+@EnableResourceServer
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
+
+	@Autowired
+	private BaseAccessDeniedHandler baseAccessDeniedHandler;
+
+	@Autowired
+	private BaseAuthenticationEntryPoint baseAuthenticationEntryPoint;
+
+	@Override
+	public void configure(HttpSecurity http) throws Exception {
+		http.csrf()
+				.disable()
+				.exceptionHandling()
+				.accessDeniedHandler(baseAccessDeniedHandler)
+				.authenticationEntryPoint(baseAuthenticationEntryPoint)
+				.and()
+				.authorizeRequests()
+				.antMatchers("/task/**").hasIpAddress("0.0.0.0/0")
+				.antMatchers("/v2/api-docs")
+                .permitAll().anyRequest().authenticated().and().httpBasic();
+	}
+
+	@Override
+	public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
+		resources.authenticationEntryPoint(baseAuthenticationEntryPoint).accessDeniedHandler(baseAccessDeniedHandler);
+	}
+
+}

+ 56 - 0
cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/config/WebMvcConfig.java

@@ -0,0 +1,56 @@
+package com.yonge.cooleshow.classroom.config;
+
+import com.yonge.cooleshow.classroom.interceptor.MDCInterceptor;
+import com.yonge.cooleshow.classroom.interceptor.OperationLogInterceptor;
+import com.yonge.cooleshow.biz.dal.config.LocalFastJsonHttpMessageConverter;
+import com.yonge.cooleshow.common.config.EnumConverterFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.format.FormatterRegistry;
+import org.springframework.http.MediaType;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+
+	@Autowired
+	private MDCInterceptor mdcInterceptor;
+
+	@Autowired
+	private OperationLogInterceptor operationLogInterceptor;
+
+	@Override
+	public void addInterceptors(InterceptorRegistry registry) {
+		List<String> includePathPatterns = new ArrayList<String>();
+		includePathPatterns.add("/**");
+		List<String> excludePathPatterns = new ArrayList<String>();
+		excludePathPatterns.add("/login");
+		registry.addInterceptor(mdcInterceptor).addPathPatterns(includePathPatterns).excludePathPatterns(excludePathPatterns);
+
+		registry.addInterceptor(operationLogInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
+	}
+
+	/**
+	 * 枚举类的转换器 addConverterFactory
+	 */
+	@Override
+	public void addFormatters(FormatterRegistry registry) {
+		registry.addConverterFactory(new EnumConverterFactory());
+	}
+	
+	@Bean
+    public HttpMessageConverters fastJsonHttpMessageConverters(){
+		LocalFastJsonHttpMessageConverter converter = new LocalFastJsonHttpMessageConverter();
+        List<MediaType> fastMediaTypes =  new ArrayList<MediaType>();
+        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
+        converter.setSupportedMediaTypes(fastMediaTypes);
+        return new HttpMessageConverters(converter);
+    }
+
+}

+ 166 - 0
cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/controller/ImNetworkRoomController.java

@@ -0,0 +1,166 @@
+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.UserRoleEnum;
+import com.yonge.cooleshow.biz.dal.service.ImNetworkRoomService;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.toolset.base.exception.BizException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.MediaType;
+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 java.util.Optional;
+
+/**
+ * 网络教室房间(room)表控制层
+ *
+ * @author zx
+ * @since 2022-03-30 16:36:36
+ */
+@Api(tags = "网络教室房间")
+@RestController
+@RequestMapping("/room")
+public class ImNetworkRoomController extends BaseController {
+
+    private final static Logger log = LoggerFactory.getLogger(ImNetworkRoomController.class);
+    /**
+     * 服务对象
+     */
+    @Resource
+    private ImNetworkRoomService imNetworkRoomService;
+
+    @ApiOperation("加入网络教室")
+    @PostMapping(value = "/join", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    @ApiImplicitParam(name = "roomId", dataType = "Long", value = "课程编号")
+    public HttpResponseResult<ImNetworkRoomResult> joinRoom(Long roomId) throws Exception {
+        roomId = Optional.ofNullable(roomId)
+                .orElseThrow(()->new BizException("房间号不可为空"));
+        return imNetworkRoomService.joinRoom(roomId, UserRoleEnum.TEACHER);
+    }
+
+//    @ApiOperation("加入网络教室状态回调")
+//    @PostMapping(value = "joinRoomSuccess", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+//    public HttpResponseResult joinRoomSuccess(Long courseScheduleId) throws Exception {
+//        imNetworkRoomService.joinRoomSuccess(courseScheduleId.toString(),UserRoleEnum.TEACHER);
+//        return succeed();
+//    }
+
+    @ApiOperation("加入网络教室状态回调")
+    @PostMapping(value = "joinRoomFailure", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult joinRoomFailure(Long roomId){
+        imNetworkRoomService.joinRoomFailure(roomId.toString());
+        return succeed();
+    }
+
+    @RequestMapping(value = "/statusSync")
+    public void statusSync(@RequestBody String body) throws Exception {
+        ImChannelStateNotify notify = JSONObject.parseObject(body, ImChannelStateNotify.class);
+        log.info("statusSyncParam: {}",JSONObject.toJSON(notify));
+        switch (notify.getEvent()) {
+            case 11:
+                //成员加入
+                imNetworkRoomService.joinRoomSuccess(notify.getChannelId(),Long.parseLong(notify.getUserId()));
+                break;
+            case 12:
+                //成员退出
+                imNetworkRoomService.leaveRoomSuccess(notify.getChannelId(),Long.parseLong(notify.getUserId()));
+                break;
+        }
+    }
+
+    @ApiOperation("退出网络教室")
+    @ApiImplicitParam(name = "roomId", dataType = "Long", value = "课程编号")
+    @PostMapping(value = "/leave", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult leaveRoom(Long roomId) throws Exception {
+        imNetworkRoomService.leaveRoom(roomId.toString(),UserRoleEnum.TEACHER);
+        return succeed();
+    }
+
+    @ApiOperation("控制学员节拍器")
+    @PostMapping(value = "/sendImPlayMidiMessage", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult sendImPlayMidiMessage(@RequestBody ImNetworkCustomMessage customMessage) throws Exception {
+        imNetworkRoomService.sendImPlayMidiMessage(customMessage);
+        return succeed();
+    }
+
+    @ApiOperation("移动端用来渲染页面")
+    @PostMapping(value = "/display", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult display(@RequestBody ImNetworkDisplayDataDto displayData) throws Exception {
+        imNetworkRoomService.display(displayData);
+        return succeed();
+    }
+
+    @ApiOperation(value = "批量控制学员设备开关")
+    @PostMapping(value = "/device/batchControl", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public Object batchControlDevice(@RequestBody ImNetworkDeviceControlDto deviceControl)throws Exception {
+        imNetworkRoomService.batchControlDevice(deviceControl);
+        return succeed();
+    }
+
+    @ApiOperation(value = "控制学员设备开关")
+    @PostMapping(value = "/device/control", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult controlDevice(@RequestBody ImNetworkDeviceControlDto deviceControl)
+            throws Exception {
+        imNetworkRoomService.controlDevice(deviceControl);
+        return succeed();
+    }
+
+    @ApiOperation(value = "学员同意打开,麦克风、摄像头")
+    @PostMapping(value = "/device/approve", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult approveControlDevice(@RequestBody ImNetworkDeviceControlDto deviceControl) throws Exception {
+        imNetworkRoomService.approveControlDevice(deviceControl);
+        return succeed();
+    }
+
+    @ApiOperation(value = "学员拒绝打开,麦克风、摄像头")
+    @PostMapping(value = "/device/reject", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult rejectControlDevice(@RequestBody ImNetworkDeviceControlDto deviceControl)
+            throws Exception {
+        imNetworkRoomService.rejectControlDevice(deviceControl);
+        return succeed();
+    }
+
+    @ApiOperation(value = "学员设备状态同步")
+    @PostMapping(value = "/device/sync", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public Object deviceStatusSync(@RequestBody ImNetworkDeviceControlDto deviceControl)
+            throws Exception {
+        imNetworkRoomService.deviceStatusSync(deviceControl);
+        return succeed();
+    }
+
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "roomId", dataType = "String", value = "房间号",required = true),
+            @ApiImplicitParam(name = "accompanimentId", dataType = "Long", value = "伴奏编号",required = true)
+    })
+    @ApiOperation(value = "老师在网络教室选择完伴奏后、通知学员下载伴奏")
+    @PostMapping(value = "pushDownloadMusicSheetMsg", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult pushDownloadMusicSheetMsg(String roomId,Long accompanimentId) throws Exception {
+        imNetworkRoomService.pushDownloadMusicSheetMsg(roomId,accompanimentId);
+        return succeed();
+    }
+
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "roomId", dataType = "String", value = "房间号",required = true),
+            @ApiImplicitParam(name = "accompanimentId", dataType = "Long", value = "伴奏编号",required = false),
+            @ApiImplicitParam(name = "status", dataType = "Integer", value = "伴奏下载状态(1下载成功0下载中2下载失败)",required = true)
+    })
+    @ApiOperation(value = "学员伴奏下载状态回调")
+    @PostMapping(value = "musicSheetDownNotify", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult adjustMusicScore(String roomId,Long accompanimentId,Integer status) throws Exception {
+        imNetworkRoomService.musicSheetDownNotify(roomId,accompanimentId,status);
+        return succeed();
+    }
+}
+

+ 29 - 0
cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/controller/ImNetworkRoomMemberController.java

@@ -0,0 +1,29 @@
+package com.yonge.cooleshow.classroom.controller;
+
+
+import com.yonge.cooleshow.biz.dal.service.ImNetworkRoomMemberService;
+import com.yonge.cooleshow.common.controller.BaseController;
+import io.swagger.annotations.Api;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 网络教室成员(ImNetworkRoomMember)表控制层
+ *
+ * @author zx
+ * @since 2022-03-30 16:36:37
+ */
+@Api(tags = "网络教室成员")
+@RestController
+@RequestMapping("/imNetworkRoomMember")
+public class ImNetworkRoomMemberController extends BaseController {
+    /**
+     * 服务对象
+     */
+    @Resource
+    private ImNetworkRoomMemberService imNetworkRoomMemberService;
+
+}
+

+ 41 - 0
cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/interceptor/MDCInterceptor.java

@@ -0,0 +1,41 @@
+package com.yonge.cooleshow.classroom.interceptor;
+
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.toolset.utils.web.WebUtil;
+import org.slf4j.MDC;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@Component
+public class MDCInterceptor extends HandlerInterceptorAdapter {
+
+	private static final String IP = "ip";
+
+	private static final String USERNAME = "username";
+	
+	@Autowired
+	@Lazy
+	private SysUserFeignService sysUserFeignService;
+
+	@Override
+	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+		SysUser sysUser = sysUserFeignService.queryUserInfo();
+		if (sysUser != null && sysUser.getId() != null) {
+			// 存储userId以及IP
+			MDC.put(USERNAME, sysUser.getUsername() + "@" + sysUser.getId());
+		}
+		MDC.put(IP, WebUtil.getRemoteIp(request));
+
+		return true;
+	}
+
+	@Override
+	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+	}
+}

+ 31 - 0
cooleshow-user/user-classroom/src/main/java/com/yonge/cooleshow/classroom/interceptor/OperationLogInterceptor.java

@@ -0,0 +1,31 @@
+package com.yonge.cooleshow.classroom.interceptor;
+
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.toolset.log.interceptor.AuditLogInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+public class OperationLogInterceptor extends AuditLogInterceptor {
+
+	@Autowired
+	@Lazy
+	private SysUserFeignService sysUserFeignService;
+
+	@Override
+	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
+		SysUser sysUser = sysUserFeignService.queryUserInfo();
+		if (sysUser != null && sysUser.getId() != null) {
+			setUsername(sysUser.getRealName(),sysUser.getId());
+		}
+		return true;
+	}
+
+}

+ 12 - 0
cooleshow-user/user-classroom/src/main/resources/bootstrap-dev.yml

@@ -0,0 +1,12 @@
+spring:
+  cloud:
+    nacos:
+      config:
+        server-addr: 47.114.1.200:8848
+        namespace: 6f8374a9-598f-4889-bb17-476070ffb8de
+        group: DEFAULT_GROUP
+        prefix: classroom
+        file-extension: yaml
+        refresh:
+          enabled: true
+        enabled: true

+ 13 - 0
cooleshow-user/user-classroom/src/main/resources/bootstrap-prod.yml

@@ -0,0 +1,13 @@
+spring:
+  cloud:
+    nacos:
+      config:
+        server-addr: 47.114.1.200:8848
+        namespace: 6f8374a9-598f-4889-bb17-476070ffb8de
+
+        group: DEFAULT_GROUP
+        prefix: classroom
+        file-extension: yaml
+        refresh:
+          enabled: true
+        enabled: true

+ 61 - 0
cooleshow-user/user-classroom/src/main/resources/logback-spring.xml

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="10 seconds">
+
+	<property name="LOG_HOME" value="/mdata/logs/classroom-%d{yyyy-MM-dd_HH}-%i.log" />
+	<property name="CONSOLE_LOG_PATTERN"
+		value="[%X{username} %X{ip} %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}] : %msg%n" />
+
+	<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+		<encoder charset="UTF-8">
+			<pattern>${CONSOLE_LOG_PATTERN}</pattern>
+		</encoder>
+	</appender>
+
+	<appender name="file"
+		class="ch.qos.logback.core.rolling.RollingFileAppender">
+		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+			<FileNamePattern>${LOG_HOME}</FileNamePattern>
+			<MaxHistory>90</MaxHistory>
+			<TimeBasedFileNamingAndTriggeringPolicy
+				class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+				<MaxFileSize>20MB</MaxFileSize>
+			</TimeBasedFileNamingAndTriggeringPolicy>
+		</rollingPolicy>
+
+		<encoder>
+			<pattern>${CONSOLE_LOG_PATTERN}</pattern>
+		</encoder>
+	</appender>
+
+	<logger name="com.yonge.cooleshow" level="INFO" />
+	<!--本地环境:打印控制台 -->
+	<springProfile name="local">
+		<root level="INFO">
+			<appender-ref ref="stdout" />
+			<appender-ref ref="file" />
+		</root>
+	</springProfile>
+	<!--开发环境:打印控制台 -->
+	<springProfile name="dev">
+		<root level="INFO">
+			<appender-ref ref="stdout" />
+			<appender-ref ref="file" />
+		</root>
+	</springProfile>
+	
+	<springProfile name="test">
+		<root level="INFO">
+			<appender-ref ref="stdout" />
+			<appender-ref ref="file" />
+		</root>
+	</springProfile>
+
+	<!--生产环境:输出到文件 -->
+	<springProfile name="prod">
+		<root level="WARN">
+			<appender-ref ref="stdout" />
+			<appender-ref ref="file" />
+		</root>
+	</springProfile>
+
+</configuration>

+ 29 - 0
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/CourseScheduleStudentMusicSheetController.java

@@ -0,0 +1,29 @@
+package com.yonge.cooleshow.teacher.controller;
+
+
+import com.yonge.cooleshow.biz.dal.service.CourseScheduleStudentMusicSheetService;
+import com.yonge.cooleshow.common.controller.BaseController;
+import io.swagger.annotations.Api;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * (CourseScheduleStudentMusicSheet)表控制层
+ *
+ * @author zx
+ * @since 2022-04-02 15:56:00
+ */
+@Api(tags = "")
+@RestController
+@RequestMapping("/courseScheduleStudentMusicSheet")
+public class CourseScheduleStudentMusicSheetController extends BaseController {
+    /**
+     * 服务对象
+     */
+    @Resource
+    private CourseScheduleStudentMusicSheetService courseScheduleStudentMusicSheetService;
+
+}
+

+ 166 - 0
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/ImNetworkRoomController.java

@@ -0,0 +1,166 @@
+package com.yonge.cooleshow.teacher.controller;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.yonge.cooleshow.biz.dal.dto.*;
+import com.yonge.cooleshow.biz.dal.enums.UserRoleEnum;
+import com.yonge.cooleshow.biz.dal.service.ImNetworkRoomService;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.toolset.base.exception.BizException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.MediaType;
+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 java.util.Optional;
+
+/**
+ * 网络教室房间(ImNetworkRoom)表控制层
+ *
+ * @author zx
+ * @since 2022-03-30 16:36:36
+ */
+@Api(tags = "网络教室房间")
+@RestController
+@RequestMapping("/imNetworkRoom")
+public class ImNetworkRoomController extends BaseController {
+
+    private final static Logger log = LoggerFactory.getLogger(ImNetworkRoomController.class);
+    /**
+     * 服务对象
+     */
+    @Resource
+    private ImNetworkRoomService imNetworkRoomService;
+
+    @ApiOperation("加入网络教室")
+    @PostMapping(value = "/join", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    @ApiImplicitParam(name = "roomId", dataType = "Long", value = "课程编号")
+    public HttpResponseResult<ImNetworkRoomResult> joinRoom(Long roomId) throws Exception {
+        roomId = Optional.ofNullable(roomId)
+                .orElseThrow(()->new BizException("房间号不可为空"));
+        return imNetworkRoomService.joinRoom(roomId, UserRoleEnum.TEACHER);
+    }
+
+//    @ApiOperation("加入网络教室状态回调")
+//    @PostMapping(value = "joinRoomSuccess", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+//    public HttpResponseResult joinRoomSuccess(Long courseScheduleId) throws Exception {
+//        imNetworkRoomService.joinRoomSuccess(courseScheduleId.toString(),UserRoleEnum.TEACHER);
+//        return succeed();
+//    }
+
+    @ApiOperation("加入网络教室状态回调")
+    @PostMapping(value = "joinRoomFailure", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult joinRoomFailure(Long roomId){
+        imNetworkRoomService.joinRoomFailure(roomId.toString());
+        return succeed();
+    }
+
+    @RequestMapping(value = "/statusSync")
+    public void statusSync(@RequestBody String body) throws Exception {
+        ImChannelStateNotify notify = JSONObject.parseObject(body, ImChannelStateNotify.class);
+        log.info("statusSyncParam: {}",JSONObject.toJSON(notify));
+        switch (notify.getEvent()) {
+            case 11:
+                //成员加入
+                imNetworkRoomService.joinRoomSuccess(notify.getChannelId(),Long.parseLong(notify.getUserId()));
+                break;
+            case 12:
+                //成员退出
+                imNetworkRoomService.leaveRoomSuccess(notify.getChannelId(),Long.parseLong(notify.getUserId()));
+                break;
+        }
+    }
+
+    @ApiOperation("退出网络教室")
+    @ApiImplicitParam(name = "roomId", dataType = "Long", value = "课程编号")
+    @PostMapping(value = "/leave", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult leaveRoom(Long roomId) throws Exception {
+        imNetworkRoomService.leaveRoom(roomId.toString(),UserRoleEnum.TEACHER);
+        return succeed();
+    }
+
+    @ApiOperation("控制学员节拍器")
+    @PostMapping(value = "/sendImPlayMidiMessage", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult sendImPlayMidiMessage(@RequestBody ImNetworkCustomMessage customMessage) throws Exception {
+        imNetworkRoomService.sendImPlayMidiMessage(customMessage);
+        return succeed();
+    }
+
+    @ApiOperation("移动端用来渲染页面")
+    @PostMapping(value = "/display", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult display(@RequestBody ImNetworkDisplayDataDto displayData) throws Exception {
+        imNetworkRoomService.display(displayData);
+        return succeed();
+    }
+
+    @ApiOperation(value = "批量控制学员设备开关")
+    @PostMapping(value = "/device/batchControl", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public Object batchControlDevice(@RequestBody ImNetworkDeviceControlDto deviceControl)throws Exception {
+        imNetworkRoomService.batchControlDevice(deviceControl);
+        return succeed();
+    }
+
+    @ApiOperation(value = "控制学员设备开关")
+    @PostMapping(value = "/device/control", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult controlDevice(@RequestBody ImNetworkDeviceControlDto deviceControl)
+            throws Exception {
+        imNetworkRoomService.controlDevice(deviceControl);
+        return succeed();
+    }
+
+    @ApiOperation(value = "学员同意打开,麦克风、摄像头")
+    @PostMapping(value = "/device/approve", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult approveControlDevice(@RequestBody ImNetworkDeviceControlDto deviceControl) throws Exception {
+        imNetworkRoomService.approveControlDevice(deviceControl);
+        return succeed();
+    }
+
+    @ApiOperation(value = "学员拒绝打开,麦克风、摄像头")
+    @PostMapping(value = "/device/reject", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult rejectControlDevice(@RequestBody ImNetworkDeviceControlDto deviceControl)
+            throws Exception {
+        imNetworkRoomService.rejectControlDevice(deviceControl);
+        return succeed();
+    }
+
+    @ApiOperation(value = "学员设备状态同步")
+    @PostMapping(value = "/device/sync", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public Object deviceStatusSync(@RequestBody ImNetworkDeviceControlDto deviceControl)
+            throws Exception {
+        imNetworkRoomService.deviceStatusSync(deviceControl);
+        return succeed();
+    }
+
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "roomId", dataType = "String", value = "房间号",required = true),
+            @ApiImplicitParam(name = "accompanimentId", dataType = "Long", value = "伴奏编号",required = true)
+    })
+    @ApiOperation(value = "老师在网络教室选择完伴奏后、通知学员下载伴奏")
+    @PostMapping(value = "pushDownloadMusicSheetMsg", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult pushDownloadMusicSheetMsg(String roomId,Long accompanimentId) throws Exception {
+        imNetworkRoomService.pushDownloadMusicSheetMsg(roomId,accompanimentId);
+        return succeed();
+    }
+
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "roomId", dataType = "String", value = "房间号",required = true),
+            @ApiImplicitParam(name = "accompanimentId", dataType = "Long", value = "伴奏编号",required = false),
+            @ApiImplicitParam(name = "status", dataType = "Integer", value = "伴奏下载状态(1下载成功0下载中2下载失败)",required = true)
+    })
+    @ApiOperation(value = "学员伴奏下载状态回调")
+    @PostMapping(value = "musicSheetDownNotify", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public HttpResponseResult adjustMusicScore(String roomId,Long accompanimentId,Integer status) throws Exception {
+        imNetworkRoomService.musicSheetDownNotify(roomId,accompanimentId,status);
+        return succeed();
+    }
+}
+

+ 29 - 0
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/ImNetworkRoomMemberController.java

@@ -0,0 +1,29 @@
+package com.yonge.cooleshow.teacher.controller;
+
+
+import com.yonge.cooleshow.biz.dal.service.ImNetworkRoomMemberService;
+import com.yonge.cooleshow.common.controller.BaseController;
+import io.swagger.annotations.Api;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 网络教室成员(ImNetworkRoomMember)表控制层
+ *
+ * @author zx
+ * @since 2022-03-30 16:36:37
+ */
+@Api(tags = "网络教室成员")
+@RestController
+@RequestMapping("/imNetworkRoomMember")
+public class ImNetworkRoomMemberController extends BaseController {
+    /**
+     * 服务对象
+     */
+    @Resource
+    private ImNetworkRoomMemberService imNetworkRoomMemberService;
+
+}
+

+ 0 - 1
pom.xml

@@ -373,7 +373,6 @@
 		<module>cooleshow-gateway</module>
 		<module>cooleshow-user</module>
 		<module>toolset</module>
-		<module>cooleshow-im</module>
 	    <module>cooleshow-task</module>
 		<module>cooleshow-mall</module>
         <module>cooleshow-websocket</module>