Browse Source

Merge branch 'dev_20230222_live' into saas

# Conflicts:
#	mec-biz/src/main/java/com/ym/mec/biz/service/impl/MemberRankSettingServiceImpl.java
#	mec-web/pom.xml
Eric 2 years ago
parent
commit
81adc33605
100 changed files with 3158 additions and 191 deletions
  1. 8 0
      README.md
  2. 2 2
      audio-analysis/src/main/resources/bootstrap-test.properties
  3. 1 0
      cms/pom.xml
  4. 2 2
      cms/src/main/resources/bootstrap-test.properties
  5. 4 0
      mec-auth/mec-auth-api/src/main/java/com/ym/mec/auth/api/enums/SysUserType.java
  6. 1 0
      mec-auth/mec-auth-server/pom.xml
  7. 1 1
      mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/config/WebMvcConfig.java
  8. 9 3
      mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/config/WebSecurityConfig.java
  9. 1 1
      mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/core/filter/UsernameAuthenticationFilter.java
  10. 4 2
      mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/core/handler/BaseAuthenticationSuccessEventHandler.java
  11. 36 6
      mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/core/provider/PhoneAuthenticationProvider.java
  12. 8 1
      mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/core/service/CustomAuthenticationKeyGenerator.java
  13. 125 0
      mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/web/controller/UserController.java
  14. 67 0
      mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/web/controller/queryInfo/QRLoginDto.java
  15. 2 2
      mec-auth/mec-auth-server/src/main/resources/bootstrap-test.properties
  16. 13 0
      mec-biz/pom.xml
  17. 74 0
      mec-biz/src/main/java/com/mec/redisson/RedissonTopicListener.java
  18. 38 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/ImLiveBroadcastRoomMemberDao.java
  19. 23 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dto/ImLiveBroadcastRoomDto.java
  20. 38 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dto/LiveRoomStatus.java
  21. 19 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dto/RoomMemberNumDto.java
  22. 454 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dto/TencentData.java
  23. 40 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dto/TencentImCallbackResult.java
  24. 74 1
      mec-biz/src/main/java/com/ym/mec/biz/dal/entity/ImLiveBroadcastRoom.java
  25. 60 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/entity/ImLiveBroadcastRoomMember.java
  26. 43 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/enums/EAnchorStatus.java
  27. 72 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/enums/EGroupDefinedDataType.java
  28. 40 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/enums/EOnOffStatus.java
  29. 30 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/enums/ETencentGroupType.java
  30. 31 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/enums/ETencentImCallbackCommand.java
  31. 43 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/enums/LiveServiceProviderEnum.java
  32. 12 1
      mec-biz/src/main/java/com/ym/mec/biz/dal/vo/ImLiveBroadcastRoomDetailVo.java
  33. 33 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/vo/ImLiveBroadcastRoomMemberVo.java
  34. 117 1
      mec-biz/src/main/java/com/ym/mec/biz/dal/vo/ImLiveBroadcastRoomVo.java
  35. 22 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/vo/ImLiveRoomVideoVo.java
  36. 56 0
      mec-biz/src/main/java/com/ym/mec/biz/redisson/RedissonMessageService.java
  37. 1 0
      mec-biz/src/main/java/com/ym/mec/biz/service/ImLiveBroadcastRoomMemberService.java
  38. 61 1
      mec-biz/src/main/java/com/ym/mec/biz/service/ImLiveBroadcastRoomService.java
  39. 12 2
      mec-biz/src/main/java/com/ym/mec/biz/service/ImLiveRoomBlackService.java
  40. 8 0
      mec-biz/src/main/java/com/ym/mec/biz/service/ImLiveRoomVideoService.java
  41. 3 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/ChildrenDayReserveServiceImpl.java
  42. 5 4
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/ContractServiceImpl.java
  43. 667 65
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveBroadcastRoomServiceImpl.java
  44. 70 13
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveRoomBlackServiceImpl.java
  45. 2 5
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveRoomReservationServiceImpl.java
  46. 27 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveRoomVideoServiceImpl.java
  47. 0 3
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImSendGroupMessageServiceImpl.java
  48. 47 10
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/LiveGoodsMapperServiceImpl.java
  49. 5 1
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/MemberRankSettingServiceImpl.java
  50. 3 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/ReplacementInstrumentActivityServiceImpl.java
  51. 3 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/SporadicChargeInfoImpl.java
  52. 3 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/StudentInstrumentServiceImpl.java
  53. 33 1
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/StudentPaymentOrderServiceImpl.java
  54. 3 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/StudentRegistrationServiceImpl.java
  55. 3 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/StudentRepairServiceImpl.java
  56. 3 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/SubjectChangeServiceImpl.java
  57. 2 1
      mec-biz/src/main/resources/config/mybatis/ImLiveBroadcastRoomDataMapper.xml
  58. 24 1
      mec-biz/src/main/resources/config/mybatis/ImLiveBroadcastRoomMapper.xml
  59. 47 4
      mec-biz/src/main/resources/config/mybatis/ImLiveBroadcastRoomMemberMapper.xml
  60. 2 0
      mec-biz/src/main/resources/config/mybatis/ImLiveRoomReservationMapper.xml
  61. 6 0
      mec-client-api/src/main/java/com/ym/mec/task/TaskRemoteService.java
  62. 5 0
      mec-client-api/src/main/java/com/ym/mec/task/fallback/TaskRemoteServiceFallback.java
  63. 1 1
      mec-common/common-core/src/main/java/com/ym/mec/common/controller/BaseController.java
  64. 3 0
      mec-common/common-core/src/main/java/com/ym/mec/common/entity/ImRoomMessage.java
  65. 2 2
      mec-education/src/main/resources/bootstrap-test.properties
  66. 1 0
      mec-eureka/pom.xml
  67. 2 2
      mec-eureka/src/main/resources/bootstrap-test.properties
  68. 1 0
      mec-gateway/mec-gateway-admin/pom.xml
  69. 1 0
      mec-gateway/mec-gateway-web/pom.xml
  70. 2 2
      mec-gateway/mec-gateway-web/src/main/resources/bootstrap-test.properties
  71. 1 0
      mec-im/pom.xml
  72. 2 0
      mec-im/src/main/java/com/ym/SealClassApplication.java
  73. 21 2
      mec-im/src/main/java/com/ym/config/ResourceServerConfig.java
  74. 6 0
      mec-im/src/main/java/com/ym/controller/LiveRoomController.java
  75. 188 2
      mec-im/src/main/java/com/ym/controller/UserController.java
  76. 24 1
      mec-im/src/main/java/com/ym/service/Impl/LiveRoomServiceImpl.java
  77. 7 0
      mec-im/src/main/java/com/ym/service/LiveRoomService.java
  78. 2 2
      mec-im/src/main/resources/bootstrap-test.properties
  79. 9 2
      mec-im/src/main/resources/logback-spring.xml
  80. 2 2
      mec-mall/mall-admin/src/main/resources/bootstrap-test.properties
  81. 2 2
      mec-mall/mall-portal/src/main/resources/bootstrap-test.properties
  82. 1 0
      mec-monitor/pom.xml
  83. 2 2
      mec-monitor/src/main/resources/bootstrap-test.properties
  84. 1 0
      mec-student/pom.xml
  85. 1 1
      mec-student/src/main/java/com/ym/mec/student/StudentApplication.java
  86. 8 0
      mec-student/src/main/java/com/ym/mec/student/controller/ImLiveBroadcastRoomController.java
  87. 32 0
      mec-student/src/main/java/com/ym/mec/student/controller/StudentImLiveRoomVideoController.java
  88. 2 2
      mec-student/src/main/resources/bootstrap-test.properties
  89. 4 12
      mec-student/src/main/resources/logback-spring.xml
  90. 1 0
      mec-task/pom.xml
  91. 24 0
      mec-task/src/main/java/com/ym/mec/task/jobs/DestroyLiveRoomTask.java
  92. 2 2
      mec-task/src/main/resources/bootstrap-test.properties
  93. 5 0
      mec-teacher/pom.xml
  94. 1 1
      mec-teacher/src/main/java/com/ym/mec/teacher/TeacherApplication.java
  95. 68 6
      mec-teacher/src/main/java/com/ym/mec/teacher/controller/TeacherImLiveBroadcastRoomController.java
  96. 61 0
      mec-teacher/src/main/java/com/ym/mec/teacher/controller/TeacherImLiveBroadcastRoomMemberController.java
  97. 2 2
      mec-teacher/src/main/resources/bootstrap-test.properties
  98. 3 3
      mec-teacher/src/main/resources/logback-spring.xml
  99. 10 1
      mec-thirdparty/src/main/java/com/ym/mec/thirdparty/storage/StoragePluginContext.java
  100. 5 5
      mec-web/pom.xml

+ 8 - 0
README.md

@@ -0,0 +1,8 @@
+
+#### 直播回调配置
+
+> 1、IM回调配置
+> 2、直播录制回调配置
+> 3、录制模板创建
+> 4、添加IM管理员帐号 `mec_admin`
+> 5、群自定义数据

+ 2 - 2
audio-analysis/src/main/resources/bootstrap-test.properties

@@ -1,9 +1,9 @@
 #\u6307\u5b9a\u5f00\u53d1\u73af\u5883
 #spring.profiles.active=dev
 #\u670d\u52a1\u5668\u5730\u5740
-spring.cloud.nacos.config.server-addr=47.114.176.40:8848
+spring.cloud.nacos.config.server-addr=43.137.4.92:8848
 #\u9ed8\u8ba4\u4e3aPublic\u547d\u540d\u7a7a\u95f4,\u53ef\u4ee5\u7701\u7565\u4e0d\u5199
-spring.cloud.nacos.config.namespace=46f06363-b9d6-46f0-9cd7-7b33dcf26bb0
+spring.cloud.nacos.config.namespace=414816a2-0087-48ac-b50b-375d61cf1cd5
 #\u6307\u5b9a\u914d\u7f6e\u7fa4\u7ec4 --\u5982\u679c\u662fPublic\u547d\u540d\u7a7a\u95f4 \u5219\u53ef\u4ee5\u7701\u7565\u7fa4\u7ec4\u914d\u7f6e
 spring.cloud.nacos.config.group=DEFAULT_GROUP
 #\u6587\u4ef6\u540d -- \u5982\u679c\u6ca1\u6709\u914d\u7f6e\u5219\u9ed8\u8ba4\u4e3a ${spring.appliction.name}

+ 1 - 0
cms/pom.xml

@@ -89,6 +89,7 @@
 			<plugin>
 				<groupId>com.spotify</groupId>
 				<artifactId>docker-maven-plugin</artifactId>
+				<version>1.2.2</version>
 			</plugin>
 		</plugins>
 	</build>

+ 2 - 2
cms/src/main/resources/bootstrap-test.properties

@@ -1,9 +1,9 @@
 #\u6307\u5b9a\u5f00\u53d1\u73af\u5883
 #spring.profiles.active=dev
 #\u670d\u52a1\u5668\u5730\u5740
-spring.cloud.nacos.config.server-addr=47.114.176.40:8848
+spring.cloud.nacos.config.server-addr=43.137.4.92:8848
 #\u9ed8\u8ba4\u4e3aPublic\u547d\u540d\u7a7a\u95f4,\u53ef\u4ee5\u7701\u7565\u4e0d\u5199
-spring.cloud.nacos.config.namespace=46f06363-b9d6-46f0-9cd7-7b33dcf26bb0
+spring.cloud.nacos.config.namespace=414816a2-0087-48ac-b50b-375d61cf1cd5
 #\u6307\u5b9a\u914d\u7f6e\u7fa4\u7ec4 --\u5982\u679c\u662fPublic\u547d\u540d\u7a7a\u95f4 \u5219\u53ef\u4ee5\u7701\u7565\u7fa4\u7ec4\u914d\u7f6e
 spring.cloud.nacos.config.group=DEFAULT_GROUP
 #\u6587\u4ef6\u540d -- \u5982\u679c\u6ca1\u6709\u914d\u7f6e\u5219\u9ed8\u8ba4\u4e3a ${spring.appliction.name}

+ 4 - 0
mec-auth/mec-auth-api/src/main/java/com/ym/mec/auth/api/enums/SysUserType.java

@@ -1,5 +1,6 @@
 package com.ym.mec.auth.api.enums;
 
+import com.baomidou.mybatisplus.annotation.EnumValue;
 import org.apache.commons.lang3.StringUtils;
 
 import com.ym.mec.common.enums.BaseEnum;
@@ -10,6 +11,9 @@ public enum SysUserType implements BaseEnum<String, SysUserType> {
 
 	private String desc;
 
+	@EnumValue
+	private String code;
+
 	private SysUserType(String desc) {
 	}
 

+ 1 - 0
mec-auth/mec-auth-server/pom.xml

@@ -101,6 +101,7 @@
 			<plugin>
 				<groupId>com.spotify</groupId>
 				<artifactId>docker-maven-plugin</artifactId>
+				<version>1.2.2</version>
 			</plugin>
 		</plugins>
 	</build>

+ 1 - 1
mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/config/WebMvcConfig.java

@@ -38,7 +38,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
 	public void addInterceptors(InterceptorRegistry registry) {
 		registry.addInterceptor(tenantInterceptor).addPathPatterns("/**").
 				excludePathPatterns("/queryUserInfo","/user/updatePassword","/user/queryUserByPhone","/user/add",
-						"user/queryUserById/*","/role/queryRoleCodeListByUserId","/user/updateSysUser");
+						"user/queryUserById/*","/role/queryRoleCodeListByUserId","/user/updateSysUser","/user/open/*");
 		registry.addInterceptor(operationLogInterceptor).addPathPatterns("/userDevice/unbind").excludePathPatterns("/*");
 	}
 	

+ 9 - 3
mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/config/WebSecurityConfig.java

@@ -1,5 +1,6 @@
 package com.ym.mec.auth.config;
 
+import com.ym.mec.common.redis.service.RedisCache;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -47,7 +48,11 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 	
 	@Autowired
 	private SysUserDeviceService sysUserDeviceService;
-	
+
+
+	@Autowired
+	private RedisCache<String,Object> redisCache;
+
 	@Override
 	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
 		auth.authenticationProvider(daoAuthenticationProvider());
@@ -65,7 +70,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 			.addFilterBefore(getPhoneLoginAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
 				// 请求授权
 				.authorizeRequests()// 不需要权限认证的url
-				.antMatchers("/usernameLogin","/smsLogin", "/refreshToken", "/v2/api-docs").permitAll()// 任何请求
+				.antMatchers("/usernameLogin","/smsLogin", "/refreshToken", "/v2/api-docs","/user/open/*").permitAll()// 任何请求
 				.anyRequest()// 需要身份认证
 				.authenticated().and()// 关闭跨站请求防护
 				.csrf().disable();
@@ -74,7 +79,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	public void configure(WebSecurity web) throws Exception {
 		web.ignoring().antMatchers("/usernameLogin", "/smsLogin", "/refreshToken",
-				"/v2/api-docs","/loginIn","/user/updatePassword");
+				"/v2/api-docs","/loginIn","/user/updatePassword","/user/open/*");
 	}
 
 	@Bean
@@ -105,6 +110,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
     	PhoneAuthenticationProvider provider = new PhoneAuthenticationProvider();
         // 设置userDetailsService
         provider.setUserDetailsService(defaultUserDetailsService);
+		provider.setRedisCache(redisCache);
         provider.setSmsCodeService(smsCodeService);
         provider.setSysUserService(sysUserService);
         provider.setSysUserDeviceService(sysUserDeviceService);

+ 1 - 1
mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/core/filter/UsernameAuthenticationFilter.java

@@ -78,7 +78,7 @@ public class UsernameAuthenticationFilter extends AbstractAuthenticationProcessi
 				clientId = "SYSTEM";
 			}
 			if (!userInfo.getSysUser().getUserType().contains(clientId)) {
-				throw new LockedException("用户不存在,请联系教务老师");
+				throw new LockedException("用户不存在");
 			}
 		}
 		

+ 4 - 2
mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/core/handler/BaseAuthenticationSuccessEventHandler.java

@@ -118,7 +118,7 @@ public class BaseAuthenticationSuccessEventHandler extends SavedRequestAwareAuth
 		sysUserLoginLogService.insert(sysUserLoginLog);
 		
 		try {
-			String clientId = request.getParameter("clientId");
+			String clientId = request.getParameter("clientId").replace("QR_", "");
 			String clientSecret = request.getParameter("clientSecret");
 			if (clientId == null || clientSecret == null) {
 				throw new UnapprovedClientAuthenticationException("请求头中client信息为空");
@@ -129,7 +129,9 @@ public class BaseAuthenticationSuccessEventHandler extends SavedRequestAwareAuth
 			headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
 
 			ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
-			TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_MAP, clientId, clientDetails.getScope(), "password");
+			Map<String, String> requestParameters = new HashMap<>();
+			requestParameters.put("client_type", request.getParameter("clientType"));
+			TokenRequest tokenRequest = new TokenRequest(requestParameters, clientId, clientDetails.getScope(), "password");
 			OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
 
 			OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);

+ 36 - 6
mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/core/provider/PhoneAuthenticationProvider.java

@@ -2,7 +2,10 @@ package com.ym.mec.auth.core.provider;
 
 import java.util.Date;
 
+import com.ym.mec.auth.web.controller.queryInfo.QRLoginDto;
+import com.ym.mec.common.redis.service.RedisCache;
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.authentication.InternalAuthenticationServiceException;
 import org.springframework.security.authentication.LockedException;
@@ -30,7 +33,9 @@ public class PhoneAuthenticationProvider extends AbstractAuthenticationProvider
 	private SysUserService sysUserService;
 	
 	private SysUserDeviceService sysUserDeviceService;
-	
+
+	private RedisCache<String,Object> redisCache;
+
 	@Override
 	protected void additionalAuthenticationChecks(UserDetails userDetails, Authentication authentication) throws AuthenticationException {
 
@@ -48,19 +53,39 @@ public class PhoneAuthenticationProvider extends AbstractAuthenticationProvider
 		}
 		String smsCode = loginEntity.getSmsCode();
 		String phone = loginEntity.getPhone();
+		String clientId = loginEntity.getClientId();
 
 		// 验证码验证
-		if (!smsCodeService.verifyValidCode(phone, smsCode)) {
+		if (!clientId.startsWith("QR_") && !smsCodeService.verifyValidCode(phone, smsCode)) {
 			throw new BadCredentialsException("验证码校验失败");
 		}
 
-		String clientId = loginEntity.getClientId();
 
 		Boolean isRegister = loginEntity.getIsRegister();
 		
 		String deviceNum = loginEntity.getDeviceNum();
 
-		SysUserInfo userInfo = sysUserService.queryUserInfoByPhone(phone);
+
+
+		SysUserInfo userInfo;
+
+		if (clientId.startsWith("QR_")) {
+			Object data = redisCache.get(loginEntity.getPhone());
+			if (data == null) {
+				throw new LockedException("用户不存在");
+			} else {
+				redisCache.delete(loginEntity.getPhone());
+				QRLoginDto loginDto = (QRLoginDto) data;
+				if (loginDto.getPrivateKey().equals(loginEntity.getSmsCode())) {
+					userInfo = loginDto.getUserInfo();
+					username = username.replaceAll(loginDto.getCode(),userInfo.getSysUser().getPhone());
+				} else {
+					throw new LockedException("用户不存在");
+				}
+			}
+		} else {
+			userInfo = sysUserService.queryUserInfoByPhone(phone);
+		}
 
 		if (userInfo == null) {
 			if (isRegister == false || StringUtils.equals("SYSTEM", clientId)) {
@@ -85,8 +110,9 @@ public class PhoneAuthenticationProvider extends AbstractAuthenticationProvider
 			if (StringUtils.isNotBlank(deviceNum)) {
 				sysUserDeviceService.bindDevice(clientId, user.getId(), deviceNum, userInfo.getSysUser().getTenantId());
 			}
-			
-			if (!userInfo.getSysUser().getUserType().contains(clientId)) {
+
+			if (clientId.startsWith("QR_")) {
+			} else  if (!userInfo.getSysUser().getUserType().contains(clientId)) {
 				if (isRegister == false || StringUtils.equals("SYSTEM", clientId)) {
 					throw new LockedException("用户不存在");
 				} else {
@@ -137,6 +163,10 @@ public class PhoneAuthenticationProvider extends AbstractAuthenticationProvider
 		this.userDetailsService = userDetailsService;
 	}
 
+	public void setRedisCache(RedisCache<String, Object> redisCache) {
+		this.redisCache = redisCache;
+	}
+
 	public void setSysUserService(SysUserService sysUserService) {
 		this.sysUserService = sysUserService;
 	}

+ 8 - 1
mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/core/service/CustomAuthenticationKeyGenerator.java

@@ -13,6 +13,7 @@ import org.springframework.security.oauth2.provider.token.DefaultAuthenticationK
 public class CustomAuthenticationKeyGenerator extends DefaultAuthenticationKeyGenerator {
 	
 	private static final String CLIENT_ID = "client_id";
+	private static final String CLIENT_TYPE = "client_type";
 
 	private static final String SCOPE = "scope";
 
@@ -25,10 +26,16 @@ public class CustomAuthenticationKeyGenerator extends DefaultAuthenticationKeyGe
 		if (!authentication.isClientOnly()) {
 			values.put(USERNAME, StringUtils.substringAfter(authentication.getName(), ":"));
 		}
-		values.put(CLIENT_ID, authorizationRequest.getClientId());
+		String clientId = authorizationRequest.getClientId();
+		clientId = clientId.replace("QR_", "");
+		values.put(CLIENT_ID, clientId);
 		if (authorizationRequest.getScope() != null) {
 			values.put(SCOPE, OAuth2Utils.formatParameterList(new TreeSet<String>(authorizationRequest.getScope())));
 		}
+		String deviceId = authorizationRequest.getRequestParameters().get(CLIENT_TYPE);
+		if (StringUtils.isNotBlank(deviceId)) {
+			values.put(CLIENT_TYPE, deviceId);
+		}
 		return generateKey(values);
 	}
 

+ 125 - 0
mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/web/controller/UserController.java

@@ -1,17 +1,22 @@
 package com.ym.mec.auth.web.controller;
 
+import com.alibaba.fastjson.JSONObject;
+import com.huifu.adapay.core.util.StringUtil;
+import com.ym.mec.auth.api.dto.SysUserInfo;
 import com.ym.mec.auth.api.entity.SysUser;
 import com.ym.mec.auth.service.SysRoleService;
 import com.ym.mec.auth.service.SysUserRoleService;
 import com.ym.mec.auth.service.SysUserService;
 import com.ym.mec.auth.service.TenantInfoService;
 import com.ym.mec.auth.api.dto.SysUserQueryInfo;
+import com.ym.mec.auth.web.controller.queryInfo.QRLoginDto;
 import com.ym.mec.common.controller.BaseController;
 import com.ym.mec.common.entity.HttpResponseResult;
 import com.ym.mec.common.entity.ImResult;
 import com.ym.mec.common.entity.ImUserModel;
 import com.ym.mec.common.exception.BizException;
 import com.ym.mec.common.page.QueryInfo;
+import com.ym.mec.common.redis.service.RedisCache;
 import com.ym.mec.common.security.AuthUser;
 import com.ym.mec.common.security.SecurityConstants;
 import com.ym.mec.common.security.SecurityUtils;
@@ -24,16 +29,29 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
 import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.web.bind.annotation.*;
 
+import java.io.IOException;
+import java.util.Base64;
+import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
 
 @RestController()
 @RequestMapping("user")
@@ -52,6 +70,10 @@ public class UserController extends BaseController {
 	private IdGeneratorService smsCodeService;
 	@Autowired
 	private TenantInfoService tenantInfoService;
+
+	@Autowired
+	private RedisCache<String,Object> redisCache;
+
 	@Value("${message.debugMode}")
 	private boolean debugMode;
 	@Autowired
@@ -377,4 +399,107 @@ public class UserController extends BaseController {
 	public HttpResponseResult<List<SysUser>> page(@RequestBody SysUserQueryInfo queryInfo) {
 		return succeed(sysUserService.queryEmployeeList(queryInfo));
 	}
+
+
+
+	@GetMapping("/open/getQRLoginCode")
+	@ApiOperation(value = "获取二维码登录code(不需要鉴权)")
+	public HttpResponseResult<String> getQRLoginCode(String clientId) {
+
+		String uuid = UUID.randomUUID().toString();
+
+		QRLoginDto qrLoginDto = new QRLoginDto();
+		qrLoginDto.setCode(uuid);
+		qrLoginDto.setClientId(clientId);
+		redisCache.put(uuid,qrLoginDto,5*60);
+		return succeed(uuid);
+	}
+
+
+	@GetMapping("/open/pollingQRLoginCode")
+	@ApiOperation(value = "前端轮询登录(不需要鉴权)")
+	public HttpResponseResult<QRLoginDto> pollingQRLoginCode(@ApiParam(value = "二维码登录code", required = true) @RequestParam("code") String code) {
+		if (StringUtil.isEmpty(code)) {
+			throw new BizException("登录失败");
+		}
+
+		Object obj = redisCache.get(code);
+		if (null != obj) {
+			QRLoginDto dto = (QRLoginDto) obj;
+			dto.setUserInfo(null);
+			return succeed(dto);
+		} else {
+			QRLoginDto qrLoginDto = new QRLoginDto();
+			qrLoginDto.setExpireFlag(true);
+			return succeed(qrLoginDto);
+		}
+	}
+
+	@GetMapping(value = "/qrLogin")
+	@ApiOperation(value = "二维码登录-扫码")
+	public HttpResponseResult<QRLoginDto> qrLogin(
+		@ApiParam(value = "二维码登录code", required = true) @RequestParam("code") String code
+	) throws IOException {
+		AuthUser authUser = SecurityUtils.getUser();
+		if (authUser == null) {
+			throw new BizException("请先登录");
+		}
+		SysUser sysUser = sysUserService.get(authUser.getUserId());
+
+
+		Object data = redisCache.get(code);
+		if (null == data) {
+			QRLoginDto qrLoginDto = new QRLoginDto();
+			qrLoginDto.setExpireFlag(true);
+			return succeed(qrLoginDto);
+		}
+
+		QRLoginDto dto = (QRLoginDto) data;
+		if (!sysUser.getUserType().contains((dto).getClientId().replace("QR_", "").toUpperCase(Locale.ROOT))) {
+			throw new BizException("登录失败");
+		}
+		redisCache.put(code,data,5*60);
+		dto.setUserInfo(null);
+		return succeed(dto);
+	}
+
+	@GetMapping(value = "/doQrLogin")
+	@ApiOperation(value = "二维码登录-确认登录")
+	public HttpResponseResult<QRLoginDto> doQrLogin(
+		@ApiParam(value = "二维码登录code", required = true) @RequestParam("code") String code
+	) {
+		AuthUser authUser = SecurityUtils.getUser();
+		if (authUser == null) {
+			throw new BizException("请先登录");
+		}
+		SysUser sysUser = sysUserService.get(authUser.getUserId());
+
+		Object data = redisCache.get(code);
+		if (null == data) {
+			QRLoginDto qrLoginDto = new QRLoginDto();
+			qrLoginDto.setExpireFlag(true);
+			return succeed(qrLoginDto);
+		}
+
+
+		SysUserInfo userInfo = sysUserService.queryUserInfoByPhone(sysUser.getPhone());
+		QRLoginDto dto = (QRLoginDto) data;
+
+
+		if (!sysUser.getUserType().contains((dto).getClientId().replace("QR_", "").toUpperCase(Locale.ROOT))) {
+			throw new BizException("登录失败");
+		}
+
+		dto.setUserInfo(userInfo);
+
+
+		String uuid = UUID.randomUUID().toString();
+		dto.setPrivateKey(uuid);
+		redisCache.put(code,dto,5*60);
+
+		dto.setUserInfo(null);
+
+		return succeed(dto);
+	}
+
 }

+ 67 - 0
mec-auth/mec-auth-server/src/main/java/com/ym/mec/auth/web/controller/queryInfo/QRLoginDto.java

@@ -0,0 +1,67 @@
+package com.ym.mec.auth.web.controller.queryInfo;
+
+import com.ym.mec.auth.api.dto.SysUserInfo;
+
+import java.io.Serializable;
+
+/**
+ * Description
+ *
+ * @author liujunchi
+ * @date 2023-02-24
+ */
+public class QRLoginDto implements Serializable {
+
+    // 是否过期
+    private Boolean expireFlag;
+
+    // clientId
+    private String clientId;
+
+    // code
+    private String code;
+
+    private String privateKey;
+
+    private SysUserInfo userInfo;
+
+    public String getPrivateKey() {
+        return privateKey;
+    }
+
+    public void setPrivateKey(String privateKey) {
+        this.privateKey = privateKey;
+    }
+
+    public SysUserInfo getUserInfo() {
+        return userInfo;
+    }
+
+    public void setUserInfo(SysUserInfo userInfo) {
+        this.userInfo = userInfo;
+    }
+
+    public Boolean getExpireFlag() {
+        return expireFlag;
+    }
+
+    public void setExpireFlag(Boolean expireFlag) {
+        this.expireFlag = expireFlag;
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+}

+ 2 - 2
mec-auth/mec-auth-server/src/main/resources/bootstrap-test.properties

@@ -1,9 +1,9 @@
 #\u6307\u5b9a\u5f00\u53d1\u73af\u5883
 #spring.profiles.active=dev
 #\u670d\u52a1\u5668\u5730\u5740
-spring.cloud.nacos.config.server-addr=47.114.176.40:8848
+spring.cloud.nacos.config.server-addr=43.137.4.92:8848
 #\u9ed8\u8ba4\u4e3aPublic\u547d\u540d\u7a7a\u95f4,\u53ef\u4ee5\u7701\u7565\u4e0d\u5199
-spring.cloud.nacos.config.namespace=46f06363-b9d6-46f0-9cd7-7b33dcf26bb0
+spring.cloud.nacos.config.namespace=414816a2-0087-48ac-b50b-375d61cf1cd5
 #\u6307\u5b9a\u914d\u7f6e\u7fa4\u7ec4 --\u5982\u679c\u662fPublic\u547d\u540d\u7a7a\u95f4 \u5219\u53ef\u4ee5\u7701\u7565\u7fa4\u7ec4\u914d\u7f6e
 spring.cloud.nacos.config.group=DEFAULT_GROUP
 #\u6587\u4ef6\u540d -- \u5982\u679c\u6ca1\u6709\u914d\u7f6e\u5219\u9ed8\u8ba4\u4e3a ${spring.appliction.name}

+ 13 - 0
mec-biz/pom.xml

@@ -51,5 +51,18 @@
             <artifactId>thumbnailator</artifactId>
             <version>0.4.11</version>
         </dependency>
+
+		<dependency>
+			<groupId>com.microsvc.toolkit.middleware</groupId>
+			<artifactId>microsvc-middleware-live</artifactId>
+			<version>1.0.0</version>
+		</dependency>
+
+		<!--修复依赖冲突-->
+		<dependency>
+			<groupId>org.jetbrains.kotlin</groupId>
+			<artifactId>kotlin-stdlib</artifactId>
+		</dependency>
+
     </dependencies>
 </project>

+ 74 - 0
mec-biz/src/main/java/com/mec/redisson/RedissonTopicListener.java

@@ -0,0 +1,74 @@
+package com.mec.redisson;
+
+import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomVo;
+import com.ym.mec.biz.redisson.RedissonMessageService;
+import com.ym.mec.biz.service.ImLiveBroadcastRoomService;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RBucket;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.core.Ordered;
+import org.springframework.stereotype.Service;
+
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Redisson消息发布订阅服务监听
+ */
+@Slf4j
+@Service
+public class RedissonTopicListener implements ApplicationRunner, Ordered {
+ 
+    @Autowired
+    private RedissonMessageService redissonMessageService;
+    @Autowired
+    private RedissonClient redissonClient;
+
+    @Autowired
+    private ImLiveBroadcastRoomService imLiveBroadcastRoomService;
+ 
+    @Override
+    public void run(ApplicationArguments args) {
+
+        if (Objects.nonNull(redissonMessageService)) {
+
+            redissonMessageService.subscribe(RedissonMessageService.TOPIC_MESSAGE, (message) -> {
+                log.info("RedissonMessageService subscribe message={}", message);
+                try {
+                    TimeUnit.SECONDS.sleep(1);
+                } catch (InterruptedException e) {
+                    log.error("RedissonMessageService subscribe sleep error", e);
+                }
+
+                // 缓存JoinRoom用户信息到redis
+                RBucket<Object> bucket = redissonClient.getBucket(RedissonMessageService.LIVE_ROOM_MEMBER + message);
+                if (!bucket.isExists()) {
+                   return;
+                }
+                bucket.delete();
+
+                ImLiveBroadcastRoomVo imLiveBroadcastRoomVo = imLiveBroadcastRoomService.queryRoomInfo(message);
+                if (Objects.isNull(imLiveBroadcastRoomVo)) {
+                    return;
+                }
+                try {
+                    imLiveBroadcastRoomService.setGroupMemberDefinedData(imLiveBroadcastRoomVo,imLiveBroadcastRoomVo.getLookNum(),imLiveBroadcastRoomVo.getTotalLookNum());
+                } catch (Exception e) {
+                    log.error("RedissonMessageService subscribe setGroupMemberDefinedData error", e);
+                    bucket.set(message, 30, TimeUnit.MINUTES);
+                }
+                redissonMessageService.publish(RedissonMessageService.TOPIC_MESSAGE, message);
+
+            });
+            log.info("---> RedissonMessageService subscribe success");
+        }
+    }
+
+    @Override
+    public int getOrder() {
+        return 1;
+    }
+}

+ 38 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/ImLiveBroadcastRoomMemberDao.java

@@ -3,6 +3,7 @@ package com.ym.mec.biz.dal.dao;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ym.mec.biz.dal.dto.RoomMemberNumDto;
 import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomMember;
 import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomMemberVo;
 import org.apache.ibatis.annotations.Param;
@@ -22,5 +23,42 @@ public interface ImLiveBroadcastRoomMemberDao extends BaseMapper<ImLiveBroadcast
 
     IPage<ImLiveBroadcastRoomMemberVo> queryMemberPage(Page<ImLiveBroadcastRoomMemberVo> page, @Param("param") Map<String, Object> param);
 
+    /**
+     * 设置在线状态
+     *
+     * @param userIds      用户id
+     * @param groupId      房间编号
+     * @param onlineStatus 状态
+     */
+    void updateOnlineStatus(@Param("userIds") List<Long> userIds, @Param("groupId") String groupId, @Param(
+        "onlineStatus") Integer onlineStatus);
+    /**
+     * 设置直播状态
+     *
+     * @param userIds      用户id
+     * @param groupId      房间编号
+     * @param liveRoomStatus 状态
+     */
+    void updateLiveRoomStatus(@Param("userIds") List<Long> userIds, @Param("groupId") String groupId, @Param(
+        "liveRoomStatus") Integer liveRoomStatus);
+
+    List<ImLiveBroadcastRoomMember> queryMember(@Param("userIds") List<Long> userIds, @Param("groupId") String groupId);
+
+    /**
+     * 修改用户连麦状态
+     *
+     * @param roomUid          直播房间id
+     * @param userId           用户id
+     * @param whetherMicStatus 连麦状态
+     */
+    void userWhetherMic(@Param("roomUid") String roomUid, @Param("userId") Long userId, @Param(
+        "whetherMicStatus") Integer whetherMicStatus);
+
+    /**
+     * 查询房间人数
+     *
+     * @param roomUid 房间id
+     */
+    RoomMemberNumDto queryMemberNum(@Param("roomUid") String roomUid);
 }
 

+ 23 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/ImLiveBroadcastRoomDto.java

@@ -1,5 +1,6 @@
 package com.ym.mec.biz.dal.dto;
 
+import com.ym.mec.auth.api.enums.SysUserType;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
@@ -27,6 +28,9 @@ public class ImLiveBroadcastRoomDto implements Serializable {
     @ApiModelProperty(value = "主讲人id/老师id")
     private Integer speakerId;
 
+    @ApiModelProperty("用户类型 TEACHER 老师 EDUCATION 教务端")
+    private SysUserType clientType;
+
     @Size(max = 12, message = "房间标题最多12个字!")
     @NotBlank(message = "房间标题不能为空")
     @ApiModelProperty(value = "房间标题/最多12个字")
@@ -55,6 +59,9 @@ public class ImLiveBroadcastRoomDto implements Serializable {
     @ApiModelProperty(value = "播出端-  pc网页端 移动端mobile")
     private String os = "pc";
 
+    @ApiModelProperty(value = "服务提供方 rongCloud tencentCloud")
+    private String serviceProvider;
+
     @ApiModel(value = "房间配置")
     public static class RoomConfig implements Serializable {
 
@@ -114,6 +121,14 @@ public class ImLiveBroadcastRoomDto implements Serializable {
         }
     }
 
+    public SysUserType getClientType() {
+        return clientType;
+    }
+
+    public void setClientType(SysUserType clientType) {
+        this.clientType = clientType;
+    }
+
     public Integer getId() {
         return id;
     }
@@ -193,5 +208,13 @@ public class ImLiveBroadcastRoomDto implements Serializable {
     public void setOs(String os) {
         this.os = os;
     }
+
+    public String getServiceProvider() {
+        return serviceProvider;
+    }
+
+    public void setServiceProvider(String serviceProvider) {
+        this.serviceProvider = serviceProvider;
+    }
 }
 

+ 38 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/LiveRoomStatus.java

@@ -0,0 +1,38 @@
+package com.ym.mec.biz.dal.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * Description
+ *
+ * @author liujunchi
+ * @date 2023-03-09
+ */
+@Data
+@ApiModel(value = "更新直播间状态")
+public class LiveRoomStatus {
+
+    @ApiModelProperty(value = "房间uid",required = true)
+    @NotBlank(message = "房间号不能为空")
+    private String roomUid;
+
+    @ApiModelProperty(value = "主播状态: 0离开;1在播")
+    private Integer speakerStatus;
+
+    @ApiModelProperty(value = "推流状态: 0 暂停; 1在播")
+    private Integer pushStatus;
+
+    @ApiModelProperty(value = "禁言状态: 0 取消;1禁言")
+    private Integer banStatus;
+
+    @ApiModelProperty(value = "主播摄像头状态 1:开启 0:关闭")
+    private Integer cameraStatus;
+
+    @ApiModelProperty(value = "直播时长")
+    private Integer liveTotalTime;
+
+}

+ 19 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/RoomMemberNumDto.java

@@ -0,0 +1,19 @@
+package com.ym.mec.biz.dal.dto;
+
+import lombok.Data;
+
+/**
+ * Description
+ *
+ * @author liujunchi
+ * @date 2023-03-29
+ */
+@Data
+public class RoomMemberNumDto {
+
+    private String roomUid;
+
+    private Integer onlineNum;
+
+    private Integer totalNum;
+}

+ 454 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/TencentData.java

@@ -0,0 +1,454 @@
+package com.ym.mec.biz.dal.dto;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.annotation.JSONField;
+import com.ym.mec.biz.dal.enums.ETencentGroupType;
+import com.ym.mec.biz.dal.enums.ETencentImCallbackCommand;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Description
+ *
+ * @author liujunchi
+ * @date 2023-03-06
+ */
+public class TencentData {
+
+    // 群成员离开之后回调对象
+    @NoArgsConstructor
+    @Data
+    public static class CallbackAfterMemberExit {
+
+
+        private String clientIP;
+
+        private String optPlatform;
+
+        // 回调命令
+        private ETencentImCallbackCommand callbackCommand;
+        // 群组 ID
+        private String groupId;
+        // 群组类型
+        private ETencentGroupType type;
+        // 成员离开方式:Kicked-被踢;Quit-主动退群
+        private String exitType;
+        // 操作者
+        private String operatorAccount;
+        // 离开群的成员列表
+        private List<MemberListDTO> exitMemberList;
+        //毫秒级别,事件触发时间戳
+        private LocalDateTime eventTime;
+
+        public static CallbackAfterMemberExit toObject(String jsonString) {
+
+            CallbackAfterMemberExit res = new CallbackAfterMemberExit();
+
+            JSONObject jsonObject = JSON.parseObject(jsonString);
+            res.setCallbackCommand(ETencentImCallbackCommand.valueOf(jsonObject.getString("CallbackCommand").replace(".","_").toUpperCase(
+                Locale.ROOT)));
+            res.setGroupId(jsonObject.getString("GroupId"));
+            res.setType(jsonObject.getObject("Type",ETencentGroupType.class));
+            res.setExitType(jsonObject.getString("ExitType"));
+            res.setOperatorAccount(jsonObject.getString("Operator_Account"));
+
+            JSONArray exitMemberList = jsonObject.getJSONArray("ExitMemberList");
+            if (!exitMemberList.isEmpty()) {
+                List<MemberListDTO> memberListDTOS = new ArrayList<>();
+                for (int i = 0; i < exitMemberList.size(); i++) {
+                    MemberListDTO memberListDTO = new MemberListDTO();
+                    JSONObject exitMemberListJSONObject = exitMemberList.getJSONObject(i);
+                    String member_account = exitMemberListJSONObject.getString("Member_Account");
+                    memberListDTO.setMemberAccount(member_account);
+                    memberListDTOS.add(memberListDTO);
+                }
+                res.setExitMemberList(memberListDTOS);
+            }
+
+
+            res.setEventTime(jsonObject.getTimestamp("EventTime").toLocalDateTime());
+
+            return res;
+        }
+    }
+
+    @NoArgsConstructor
+    @Data
+    public static class MemberListDTO {
+        private String memberAccount;
+    }
+
+    // 直播群成员在线状态回调
+    @NoArgsConstructor
+    @Data
+    public static class CallbackOnMemberStateChange {
+
+        // 客户端平台,对应不同的平台类型,可能的取值有:
+        // RESTAPI(使用 REST API 发送请求)、Web(使用 Web SDK 发送请求)、
+        // Android、iOS、Windows、Mac、iPad、Unknown(使用未知类型的设备发送请求)
+        private String clientIP;
+
+        private String optPlatform;
+        // 回调命令
+        private ETencentImCallbackCommand callbackCommand;
+        // 群组 ID
+        private String groupId;
+        // 事件类型:Offline - 掉线、Online - 重新上线
+        private String eventType;
+        // 离开群的成员列表
+        private List<MemberListDTO> memberList;
+
+        public static CallbackOnMemberStateChange toObject(String jsonString) {
+
+            CallbackOnMemberStateChange res = new CallbackOnMemberStateChange();
+
+            JSONObject jsonObject = JSON.parseObject(jsonString);
+            res.setCallbackCommand(ETencentImCallbackCommand.valueOf(jsonObject.getString("CallbackCommand").replace(".","_").toUpperCase(
+                Locale.ROOT)));
+            res.setGroupId(jsonObject.getString("GroupId"));
+
+            JSONArray exitMemberList = jsonObject.getJSONArray("MemberList");
+            if (!exitMemberList.isEmpty()) {
+                List<MemberListDTO> memberListDTOS = new ArrayList<>();
+                for (int i = 0; i < exitMemberList.size(); i++) {
+                    MemberListDTO memberListDTO = new MemberListDTO();
+                    JSONObject exitMemberListJSONObject = exitMemberList.getJSONObject(i);
+                    String member_account = exitMemberListJSONObject.getString("Member_Account");
+                    memberListDTO.setMemberAccount(member_account);
+                    memberListDTOS.add(memberListDTO);
+                }
+                res.setMemberList(memberListDTOS);
+            }
+
+            res.setEventType(jsonObject.getString("EventType"));
+
+            return res;
+        }
+    }
+
+    @NoArgsConstructor
+    @Data
+    public static class CallbackAfterNewMemberJoin {
+
+        private String clientIP;
+
+        private String optPlatform;
+        // 回调命令
+        private ETencentImCallbackCommand callbackCommand;
+        // 群组 ID
+        private String groupId;
+        // 群组类型
+        private ETencentGroupType type;
+        // 入群方式:Apply(申请入群);Invited(邀请入群)
+        private String joinType;
+        // 操作者成员
+        private String operatorAccount;
+        // 新入群成员列表
+        private List<MemberListDTO> newMemberList;
+        //毫秒级别,事件触发时间戳
+        private LocalDateTime eventTime;
+
+        public static CallbackAfterNewMemberJoin toObject(String jsonString) {
+
+            CallbackAfterNewMemberJoin res = new CallbackAfterNewMemberJoin();
+
+            JSONObject jsonObject = JSON.parseObject(jsonString);
+            res.setCallbackCommand(ETencentImCallbackCommand.valueOf(jsonObject.getString("CallbackCommand").replace(".","_").toUpperCase(
+                Locale.ROOT)));
+            res.setGroupId(jsonObject.getString("GroupId"));
+            res.setType(jsonObject.getObject("Type",ETencentGroupType.class));
+            res.setJoinType(jsonObject.getString("JoinType"));
+            res.setOperatorAccount(jsonObject.getString("Operator_Account"));
+
+            JSONArray exitMemberList = jsonObject.getJSONArray("NewMemberList");
+            if (!exitMemberList.isEmpty()) {
+                List<MemberListDTO> memberListDTOS = new ArrayList<>();
+                for (int i = 0; i < exitMemberList.size(); i++) {
+                    MemberListDTO memberListDTO = new MemberListDTO();
+                    JSONObject exitMemberListJSONObject = exitMemberList.getJSONObject(i);
+                    String member_account = exitMemberListJSONObject.getString("Member_Account");
+                    memberListDTO.setMemberAccount(member_account);
+                    memberListDTOS.add(memberListDTO);
+                }
+                res.setNewMemberList(memberListDTOS);
+            }
+
+
+            res.setEventTime(jsonObject.getTimestamp("EventTime").toLocalDateTime());
+
+            return res;
+        }
+    }
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel("推断流事件回调通知")
+    public static class CallbackStreamStateEvent implements Serializable {
+
+
+        @ApiModelProperty("推流域名")
+        @JSONField(name = "app")
+        private String app;
+
+        @ApiModelProperty("用户 APPID")
+        @JSONField(name = "appid")
+        private Integer appid;
+
+        @ApiModelProperty("推流路径")
+        @JSONField(name = "appname")
+        private String appname;
+
+        @ApiModelProperty("同直播流名称")
+        @JSONField(name = "channel_id")
+        private String channelId;
+
+        @ApiModelProperty("断流事件通知推流时长,单位毫秒")
+        @JSONField(name = "push_duration")
+        private String pushDuration;
+
+        @ApiModelProperty("推断流错误码")
+        @JSONField(name = "errcode")
+        private Integer errcode;
+
+        @ApiModelProperty("推断流错误描述")
+        @JSONField(name = "errmsg")
+        private String errmsg;
+
+        @ApiModelProperty("事件消息产生的 UNIX 时间戳")
+        @JSONField(name = "event_time")
+        private Integer eventTime;
+
+        @ApiModelProperty("事件类型: 推流:1;断流:0")
+        @JSONField(name = "event_type")
+        private Integer eventType;
+
+        @ApiModelProperty("判断是否为国内外推流。1-6为国内,7-200为国外")
+        @JSONField(name = "set_id")
+        private Integer setId;
+
+        @ApiModelProperty("直播接入点的 IP")
+        @JSONField(name = "node")
+        private String node;
+
+        @ApiModelProperty("消息序列号,标识一次推流活动,一次推流活动会产生相同序列号的推流和断流消息")
+        @JSONField(name = "sequence")
+        private String sequence;
+
+        @ApiModelProperty("直播流名称")
+        @JSONField(name = "stream_id")
+        private String streamId;
+
+        @ApiModelProperty("用户推流 URL 所带参数")
+        @JSONField(name = "stream_param")
+        private String streamParam;
+
+        @ApiModelProperty("用户推流 IP")
+        @JSONField(name = "user_ip")
+        private String userIp;
+
+        @ApiModelProperty("视频宽度,最开始推流回调的时候若视频头部信息缺失,可能为0")
+        @JSONField(name = "width")
+        private Integer width;
+
+        @ApiModelProperty("视频高度,最开始推流回调的时候若视频头部信息缺失,可能为0")
+        @JSONField(name = "height")
+        private Integer height;
+
+        @ApiModelProperty("事件通知安全签名 sign = MD5(key + t)")
+        @JSONField(name = "sign")
+        private String sign;
+
+        @ApiModelProperty("过期时间,事件通知签名过期 UNIX 时间戳")
+        @JSONField(name = "t")
+        private Integer t;
+
+        public static CallbackStreamStateEvent from(String jsonString) {
+            return JSON.parseObject(jsonString, CallbackStreamStateEvent.class);
+        }
+    }
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel("流录制事件回调通知")
+    public static class CallbackSteamRecordEvent implements Serializable {
+
+        @ApiModelProperty("事件类型:直播录制: 100")
+        @JSONField(name = "event_type")
+        private Integer eventType;
+
+        @ApiModelProperty("用户 APPID")
+        @JSONField(name = "appid")
+        private Integer appid;
+
+        @ApiModelProperty("推流域名")
+        @JSONField(name = "app")
+        private String app;
+
+        @ApiModelProperty("json对象字符串,用户自定义数据")
+        @JSONField(name = "callback_ext")
+        private String callbackExt;
+
+        @ApiModelProperty("推流路径")
+        @JSONField(name = "appname")
+        private String appname;
+
+        @ApiModelProperty("直播流名称")
+        @JSONField(name = "stream_id")
+        private String streamId;
+
+        @ApiModelProperty("同直播流名称")
+        @JSONField(name = "channel_id")
+        private String channelId;
+
+        @ApiModelProperty("点播 file ID,在 云点播平台 可以唯一定位一个点播视频文件")
+        @JSONField(name = "file_id")
+        private String fileId;
+
+        @ApiModelProperty("点播文件ID")
+        @JSONField(name = "record_file_id")
+        private String recordFileId;
+
+        @ApiModelProperty("文件格式: FLV,HLS,MP4,AAC")
+        @JSONField(name = "file_format")
+        private String fileFormat;
+
+        @ApiModelProperty("录制任务 ID")
+        @JSONField(name = "task_id")
+        private String taskId;
+
+        @ApiModelProperty("录制任务开始写文件的时间;不能以该值作为录制内容的开始时间,录制内容的开始时间 = end_time – duration")
+        @JSONField(name = "start_time")
+        private Integer startTime;
+
+        @ApiModelProperty("录制任务结束写文件的时间")
+        @JSONField(name = "end_time")
+        private Integer endTime;
+
+        @ApiModelProperty("录制任务开始写文件的时间,微秒部分")
+        @JSONField(name = "start_time_usec")
+        private Integer startTimeUsec;
+
+        @ApiModelProperty("录制任务结束写文件的时间,微秒部分")
+        @JSONField(name = "end_time_usec")
+        private Integer endTimeUsec;
+
+        @ApiModelProperty("录制文件时长,单位秒")
+        @JSONField(name = "duration")
+        private Integer duration;
+
+        @ApiModelProperty("录制文件大小,单位字节")
+        @JSONField(name = "file_size")
+        private Integer fileSize;
+
+        @ApiModelProperty("用户推流 URL 所带参数(自定义)")
+        @JSONField(name = "stream_param")
+        private String streamParam;
+
+        @ApiModelProperty("录制文件下载 URL")
+        @JSONField(name = "video_url")
+        private String videoUrl;
+
+        @ApiModelProperty("录制开始拉流收到的首帧 pts ")
+        @JSONField(name = "media_start_time")
+        private Integer mediaStartTime;
+
+        @ApiModelProperty("录制从转码拉流录制对应的码率(单位 kbps)")
+        @JSONField(name = "record_bps")
+        private Integer recordBps;
+
+        @ApiModelProperty("事件通知安全签名 sign = MD5(key + t)")
+        @JSONField(name = "sign")
+        private String sign;
+
+        @ApiModelProperty("过期时间,事件通知签名过期 UNIX 时间戳")
+        @JSONField(name = "t")
+        private Integer t;
+
+
+        public static CallbackSteamRecordEvent from(String json) {
+            return JSON.parseObject(json, CallbackSteamRecordEvent.class);
+        }
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel("流异常事件回调通知")
+    public static class CallbackStreamExceptionEvent implements Serializable {
+
+        @ApiModelProperty("用户 APPID")
+        @JSONField(name = "appid")
+        private Integer appid;
+
+        @ApiModelProperty("推流事件回调时间(单位ms)")
+        @JSONField(name = "data_time")
+        private Long dataTime;
+
+        @ApiModelProperty("推流域名")
+        @JSONField(name = "domain")
+        private String domain;
+
+        @ApiModelProperty("事件类型:推流异常:321")
+        @JSONField(name = "event_type")
+        private Integer eventType;
+
+        @JSONField(name = "interface")
+        private String interfaceX;
+        @JSONField(name = "path")
+        private String path;
+
+        @ApiModelProperty("有异常事件时,上报间隔(单位ms)")
+        @JSONField(name = "report_interval")
+        private Integer reportInterval;
+
+        @JSONField(name = "sequence")
+        private String sequence;
+
+        @ApiModelProperty("直播流名称")
+        @JSONField(name = "stream_id")
+        private String streamId;
+
+        @ApiModelProperty("用户推流 URL 所带参数")
+        @JSONField(name = "stream_param")
+        private String streamParam;
+
+        @JSONField(name = "timeout")
+        private Integer timeout;
+
+        @ApiModelProperty("详细异常事件事件组")
+        @JSONField(name = "abnormal_event")
+        private String abnormalEvent;
+
+        public static CallbackStreamExceptionEvent from(String json) {
+            return JSON.parseObject(json, CallbackStreamExceptionEvent.class);
+        }
+    }
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel("流事件回调结果")
+    public static class StreamEventCallbackResult implements Serializable {
+
+        @ApiModelProperty("事件响应状态")
+        private Integer code;
+    }
+
+}

+ 40 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/TencentImCallbackResult.java

@@ -0,0 +1,40 @@
+package com.ym.mec.biz.dal.dto;
+
+/**
+ * Description
+ *
+ * @author liujunchi
+ * @date 2023-03-02
+ */
+public class TencentImCallbackResult {
+
+    private String ActionStatus = "OK";
+
+    private String ErrorInfo;
+
+    private int ErrorCode = 0;
+
+    public String getActionStatus() {
+        return ActionStatus;
+    }
+
+    public void setActionStatus(String actionStatus) {
+        ActionStatus = actionStatus;
+    }
+
+    public String getErrorInfo() {
+        return ErrorInfo;
+    }
+
+    public void setErrorInfo(String errorInfo) {
+        ErrorInfo = errorInfo;
+    }
+
+    public int getErrorCode() {
+        return ErrorCode;
+    }
+
+    public void setErrorCode(int errorCode) {
+        ErrorCode = errorCode;
+    }
+}

+ 74 - 1
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/ImLiveBroadcastRoom.java

@@ -4,6 +4,7 @@ import java.util.Date;
 
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
+import com.ym.mec.auth.api.enums.SysUserType;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import com.baomidou.mybatisplus.annotation.TableId;
@@ -34,6 +35,11 @@ public class ImLiveBroadcastRoom implements Serializable {
     @ApiModelProperty(value = "主讲人id/老师id")
     private Integer speakerId;
 
+
+    @TableField("client_type_")
+    @ApiModelProperty("用户类型 TEACHER 老师 EDUCATION 教务端")
+    private SysUserType clientType;
+
     @TableField("room_uid_")
     @ApiModelProperty(value = "房间编号")
     private String roomUid;
@@ -66,6 +72,10 @@ public class ImLiveBroadcastRoom implements Serializable {
     @ApiModelProperty(value = "直播状态 0未开始 1开始 2已结束")
     private Integer liveState;
 
+    @TableField("live_total_time_")
+    @ApiModelProperty(value = "直播时长")
+    private Integer liveTotalTime;
+
     @TableField("room_state_")
     @ApiModelProperty(value = "房间状态 0正常 1已删除 2销毁")
     private Integer roomState;
@@ -80,7 +90,23 @@ public class ImLiveBroadcastRoom implements Serializable {
 
     @TableField("os_")
     @ApiModelProperty(value = "播出端-  pc网页端 移动端mobile")
-    private String os = "pc";
+    private String os;
+
+    @TableField("service_provider_")
+    @ApiModelProperty(value = "服务提供方 rongCloud tencentCloud")
+    private String serviceProvider;
+
+    @TableField("speaker_status_")
+    @ApiModelProperty(value = "主播状态: 0离开;1在播")
+    private Integer speakerStatus;
+
+    @TableField("push_status_")
+    @ApiModelProperty(value = "推流状态: 0 暂停; 1在播")
+    private Integer pushStatus;
+
+    @TableField("ban_status_")
+    @ApiModelProperty(value = "禁言状态: 0 取消;1禁言")
+    private Integer banStatus;
 
     @TableField("created_by_")
     @ApiModelProperty(value = "创建人")
@@ -100,6 +126,22 @@ public class ImLiveBroadcastRoom implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
+    public SysUserType getClientType() {
+        return clientType;
+    }
+
+    public void setClientType(SysUserType clientType) {
+        this.clientType = clientType;
+    }
+
+    public String getServiceProvider() {
+        return serviceProvider;
+    }
+
+    public void setServiceProvider(String serviceProvider) {
+        this.serviceProvider = serviceProvider;
+    }
+
     public Integer getId() {
         return id;
     }
@@ -270,5 +312,36 @@ public class ImLiveBroadcastRoom implements Serializable {
         this.popularizeType = popularizeType;
     }
 
+    public Integer getSpeakerStatus() {
+        return speakerStatus;
+    }
+
+    public void setSpeakerStatus(Integer speakerStatus) {
+        this.speakerStatus = speakerStatus;
+    }
+
+    public Integer getPushStatus() {
+        return pushStatus;
+    }
+
+    public void setPushStatus(Integer pushStatus) {
+        this.pushStatus = pushStatus;
+    }
+
+    public Integer getBanStatus() {
+        return banStatus;
+    }
+
+    public void setBanStatus(Integer banStatus) {
+        this.banStatus = banStatus;
+    }
+
+    public Integer getLiveTotalTime() {
+        return liveTotalTime;
+    }
+
+    public void setLiveTotalTime(Integer liveTotalTime) {
+        this.liveTotalTime = liveTotalTime;
+    }
 }
 

+ 60 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/ImLiveBroadcastRoomMember.java

@@ -43,8 +43,37 @@ public class ImLiveBroadcastRoomMember implements Serializable {
     @ApiModelProperty(value = "累计观看时间/以分钟为单位")
     private Integer totalTime;
 
+    @TableField("online_status_")
+    @ApiModelProperty(value = "在线状态;0离线;1在线")
+    private Integer onlineStatus;
+
+    @TableField("ban_status_")
+    @ApiModelProperty(value = "禁言状态:0取消;1禁言")
+    private Integer banStatus;
+
+    @TableField("live_room_status_")
+    @ApiModelProperty(value = "直播状态: 0离开;1观看")
+    private Integer liveRoomStatus;
+
+
+    @TableField("whether_mic_status_")
+    @ApiModelProperty(value = "连麦状态 0:未申请1:申请连麦中2:连麦中")
+    private Integer whetherMicStatus;
+
+    @TableField("create_time_")
+    @ApiModelProperty(value = "创建时间")
+    private Date createTime;
+
     private static final long serialVersionUID = 1L;
 
+    public Integer getWhetherMicStatus() {
+        return whetherMicStatus;
+    }
+
+    public void setWhetherMicStatus(Integer whetherMicStatus) {
+        this.whetherMicStatus = whetherMicStatus;
+    }
+
     public Integer getId() {
         return id;
     }
@@ -93,5 +122,36 @@ public class ImLiveBroadcastRoomMember implements Serializable {
         this.totalTime = totalTime;
     }
 
+    public Integer getOnlineStatus() {
+        return onlineStatus;
+    }
+
+    public void setOnlineStatus(Integer onlineStatus) {
+        this.onlineStatus = onlineStatus;
+    }
+
+    public Integer getBanStatus() {
+        return banStatus;
+    }
+
+    public void setBanStatus(Integer banStatus) {
+        this.banStatus = banStatus;
+    }
+
+    public Integer getLiveRoomStatus() {
+        return liveRoomStatus;
+    }
+
+    public void setLiveRoomStatus(Integer liveRoomStatus) {
+        this.liveRoomStatus = liveRoomStatus;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
 }
 

+ 43 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/enums/EAnchorStatus.java

@@ -0,0 +1,43 @@
+package com.ym.mec.biz.dal.enums;
+
+/**
+ * Description
+ *
+ * @author liujunchi
+ * @date 2023-03-20
+ */
+public enum EAnchorStatus {
+
+    /**
+     * 主讲人状态
+     */
+    ONLINE("在线"),
+    OFFLINE("离线"),
+
+
+    ;
+    private String code;
+
+    private String msg;
+
+    EAnchorStatus(String msg) {
+        this.msg = msg;
+        this.code = this.name();
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+}

+ 72 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/enums/EGroupDefinedDataType.java

@@ -0,0 +1,72 @@
+package com.ym.mec.biz.dal.enums;
+
+/**
+ * Description
+ *
+ * @author liujunchi
+ * @date 2023-03-20
+ */
+public enum EGroupDefinedDataType {
+
+    /**
+     * 主讲人状态
+     */
+    ANCHOR_STATUS("主讲人状态"), // "ONLINE":"OFFLINE"
+
+    /**
+     * 全局禁言
+     */
+    GLOBAL_BAN("全局禁言"), // 开启禁言"ON" 关闭禁言 "OFF"
+
+    /**
+     * 点赞数
+     */
+    LIKES("点赞数"), // 点赞数
+
+    /**
+     * 在线人数
+     */
+    MEMBER_ONLINE("在线人数"), // 在线人数
+
+
+    /**
+     * 累计观看人数
+     */
+    MEMBER_TOTAL("累计观看人数"), // 累计观看人数
+
+    /**
+     * 当前房间推流状态
+     */
+    LIVE_STATUS("当前房间推流状态"), //开播 "ON" 暂停直播 "OFF"
+
+    /**
+     * 主播摄像头状态
+     */
+    ANCHOR_CAMERA("主播摄像头状态"), // 开启摄像头 "ON" 关闭摄像头 "OFF"
+
+    ;
+    private String code;
+
+    private String msg;
+
+    EGroupDefinedDataType(String msg) {
+        this.msg = msg;
+        this.code = this.name();
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+}

+ 40 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/enums/EOnOffStatus.java

@@ -0,0 +1,40 @@
+package com.ym.mec.biz.dal.enums;
+
+/**
+ * Description
+ *
+ * @author liujunchi
+ * @date 2023-03-20
+ */
+public enum EOnOffStatus {
+
+
+    ON("是"),
+    OFF("否"),
+
+    ;
+    private String code;
+
+    private String msg;
+
+    EOnOffStatus(String msg) {
+        this.msg = msg;
+        this.code = this.name();
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+}

+ 30 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/enums/ETencentGroupType.java

@@ -0,0 +1,30 @@
+package com.ym.mec.biz.dal.enums;
+
+/**
+ * Description
+ *
+ * @author liujunchi
+ * @date 2023-03-06
+ */
+public enum ETencentGroupType {
+
+    Public("陌生人社交群"),
+    Work("好友工作群"),
+    AVChatRoom("直播群"),
+    Meeting("临时会议群"),
+    Community("社群"),
+
+    ;
+
+    private String code;
+
+    private String msg;
+
+
+    ETencentGroupType(String msg) {
+        this.code = this.name();
+        this.msg = msg;
+    }
+
+
+}

+ 31 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/enums/ETencentImCallbackCommand.java

@@ -0,0 +1,31 @@
+package com.ym.mec.biz.dal.enums;
+
+import lombok.Getter;
+
+/**
+ * Description
+ *
+ * @author liujunchi
+ * @date 2023-03-02
+ */
+@Getter
+public enum ETencentImCallbackCommand {
+
+    // STATE_STATECHANGE("State.StateChange", "用户状态变更"),
+    GROUP_CALLBACKAFTERMEMBEREXIT("Group.CallbackAfterMemberExit", "群成员离开之后回调"),
+    GROUP_CALLBACKAFTERNEWMEMBERJOIN("Group.CallbackAfterNewMemberJoin", "新成员入群之后回调"),
+    GROUP_CALLBACKONMEMBERSTATECHANGE("Group.CallbackOnMemberStateChange", "直播群成员在线状态回调"),
+    ;
+
+    private final String command;
+    private final String desc;
+
+    private final String code;
+
+    ETencentImCallbackCommand(String command, String desc) {
+        this.command = command;
+        this.desc = desc;
+
+        this.code = this.name();
+    }
+}

+ 43 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/enums/LiveServiceProviderEnum.java

@@ -0,0 +1,43 @@
+package com.ym.mec.biz.dal.enums;
+
+import com.ym.mec.common.enums.BaseEnum;
+
+/**
+ * Description
+ *
+ * @author liujunchi
+ * @date 2023-02-28
+ */
+public enum LiveServiceProviderEnum  implements BaseEnum<String, LevelEnum> {
+    RONG_CLOUD("融云"),
+    TENCENT_CLOUD("腾讯云"),
+    ;
+
+    private String code;
+    private String msg;
+
+    LiveServiceProviderEnum(String msg) {
+        this.code = this.name();
+        this.msg = msg;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    @Override
+    public String getCode() {
+        return this.code;
+    }
+
+
+    public static LiveServiceProviderEnum getByName(String name) {
+        for (LiveServiceProviderEnum level : LiveServiceProviderEnum.values()) {
+            if (level.getMsg().equals(name)) {
+                return level;
+            }
+        }
+        return null;
+    }
+
+}

+ 12 - 1
mec-biz/src/main/java/com/ym/mec/biz/dal/vo/ImLiveBroadcastRoomDetailVo.java

@@ -30,9 +30,12 @@ public class ImLiveBroadcastRoomDetailVo implements Serializable {
     @ApiModelProperty(value = "点赞数")
     private Integer totalLikeNum;
 
-    @ApiModelProperty(value = "直播时长")
+    @ApiModelProperty(value = "直播时长 分钟 平台统计")
     private Integer totalLiveTime;
 
+    @ApiModelProperty("推流时长 毫秒 三方统计")
+    private Integer liveTotalTime;
+
     @ApiModelProperty(value = "直播开始时间")
     private Date liveStartTime;
 
@@ -44,6 +47,14 @@ public class ImLiveBroadcastRoomDetailVo implements Serializable {
 
     private List<ImLiveRoomVideoVo> videoList;
 
+    public Integer getLiveTotalTime() {
+        return liveTotalTime;
+    }
+
+    public void setLiveTotalTime(Integer liveTotalTime) {
+        this.liveTotalTime = liveTotalTime;
+    }
+
     public Date getLiveStartTime() {
         return liveStartTime;
     }

+ 33 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/vo/ImLiveBroadcastRoomMemberVo.java

@@ -26,6 +26,9 @@ public class ImLiveBroadcastRoomMemberVo implements java.io.Serializable {
     @ApiModelProperty(value = "学生姓名")
     private String studentName;
 
+    @ApiModelProperty(value = "学生头像")
+    private String avatar;
+
     @ApiModelProperty(value = "手机号")
     private String phone;
 
@@ -45,6 +48,36 @@ public class ImLiveBroadcastRoomMemberVo implements java.io.Serializable {
     @ApiModelProperty(value = "累计观看时长")
     private Integer totalViewTime;
 
+    @ApiModelProperty(value = "连麦状态 0:未申请1:申请连麦中2:连麦中")
+    private Integer whetherMicStatus;
+
+    @ApiModelProperty(value = "是否黑名单")
+    private boolean blackFlag;
+
+    public boolean isBlackFlag() {
+        return blackFlag;
+    }
+
+    public void setBlackFlag(boolean blackFlag) {
+        this.blackFlag = blackFlag;
+    }
+
+    public String getAvatar() {
+        return avatar;
+    }
+
+    public void setAvatar(String avatar) {
+        this.avatar = avatar;
+    }
+
+    public Integer getWhetherMicStatus() {
+        return whetherMicStatus;
+    }
+
+    public void setWhetherMicStatus(Integer whetherMicStatus) {
+        this.whetherMicStatus = whetherMicStatus;
+    }
+
     public Integer getStudentId() {
         return studentId;
     }

+ 117 - 1
mec-biz/src/main/java/com/ym/mec/biz/dal/vo/ImLiveBroadcastRoomVo.java

@@ -1,6 +1,9 @@
 package com.ym.mec.biz.dal.vo;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.microsvc.toolkit.middleware.live.message.LiveRoomConfig;
+import com.ym.mec.auth.api.enums.SysUserType;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
@@ -39,6 +42,9 @@ public class ImLiveBroadcastRoomVo implements Serializable {
     @ApiModelProperty(value = "主讲人id/老师id")
     private Integer speakerId;
 
+    @ApiModelProperty("用户类型 TEACHER 老师 EDUCATION 教务端")
+    private SysUserType clientType;
+
     @ApiModelProperty(value = "主讲人名称")
     private String speakerName;
 
@@ -52,6 +58,9 @@ public class ImLiveBroadcastRoomVo implements Serializable {
     @ApiModelProperty(value = "直播状态 0未开始 1开始 2结束")
     private Integer liveState;
 
+    @ApiModelProperty(value = "直播时长")
+    private Integer liveTotalTime;
+
     @ApiModelProperty(value = "房间状态 0正常 1已删除")
     private Integer roomState;
 
@@ -68,7 +77,7 @@ public class ImLiveBroadcastRoomVo implements Serializable {
     private String imToken;
 
     @ApiModelProperty(value = "播出端-  pc网页端 移动端mobile")
-    private String os = "pc";
+    private String os;
 
     @ApiModelProperty(value = "是否在首页推广 0否 1是 - 每个机构只能有一个直播间在首页推广")
     private Integer popularize;
@@ -92,6 +101,55 @@ public class ImLiveBroadcastRoomVo implements Serializable {
     @ApiModelProperty("预约人数")
     private Integer roomReservationNum;
 
+    @ApiModelProperty("直播间用户签名")
+    private String userSig;
+
+
+    @ApiModelProperty(value = "服务提供方 RONG_CLOUD TENCENT_CLOUD")
+    private String serviceProvider;
+
+    @ApiModelProperty("直播配置")
+    private LiveRoomConfig liveRoomConfig;
+
+    @TableField("speaker_status_")
+    @ApiModelProperty(value = "主播状态: 0离开;1在播")
+    private Integer speakerStatus;
+
+    @TableField("push_status_")
+    @ApiModelProperty(value = "推流状态: 0 暂停; 1在播")
+    private Integer pushStatus;
+
+    @TableField("ban_status_")
+    @ApiModelProperty(value = "禁言状态: 0 取消;1禁言")
+    private Integer banStatus;
+
+    @ApiModelProperty("视频数量")
+    private Integer videoNum;
+
+    public Integer getVideoNum() {
+        return videoNum;
+    }
+
+    public void setVideoNum(Integer videoNum) {
+        this.videoNum = videoNum;
+    }
+
+    public SysUserType getClientType() {
+        return clientType;
+    }
+
+    public void setClientType(SysUserType clientType) {
+        this.clientType = clientType;
+    }
+
+    public String getServiceProvider() {
+        return serviceProvider;
+    }
+
+    public void setServiceProvider(String serviceProvider) {
+        this.serviceProvider = serviceProvider;
+    }
+
     public Integer getId() {
         return id;
     }
@@ -305,5 +363,63 @@ public class ImLiveBroadcastRoomVo implements Serializable {
     public void setPopularizeType(String popularizeType) {
         this.popularizeType = popularizeType;
     }
+
+    public String getUserSig() {
+        return userSig;
+    }
+
+    public void setUserSig(String userSig) {
+        this.userSig = userSig;
+    }
+
+    public LiveRoomConfig getLiveRoomConfig() {
+        return liveRoomConfig;
+    }
+
+    public void setLiveRoomConfig(LiveRoomConfig liveRoomConfig) {
+        this.liveRoomConfig = liveRoomConfig;
+    }
+
+    public ImLiveBroadcastRoomVo userSig(String userSig) {
+        this.userSig = userSig;
+        return this;
+    }
+
+    public ImLiveBroadcastRoomVo liveRoomConfig(LiveRoomConfig liveRoomConfig) {
+        this.liveRoomConfig = liveRoomConfig;
+        return this;
+    }
+
+    public Integer getSpeakerStatus() {
+        return speakerStatus;
+    }
+
+    public void setSpeakerStatus(Integer speakerStatus) {
+        this.speakerStatus = speakerStatus;
+    }
+
+    public Integer getPushStatus() {
+        return pushStatus;
+    }
+
+    public void setPushStatus(Integer pushStatus) {
+        this.pushStatus = pushStatus;
+    }
+
+    public Integer getBanStatus() {
+        return banStatus;
+    }
+
+    public void setBanStatus(Integer banStatus) {
+        this.banStatus = banStatus;
+    }
+
+    public Integer getLiveTotalTime() {
+        return liveTotalTime;
+    }
+
+    public void setLiveTotalTime(Integer liveTotalTime) {
+        this.liveTotalTime = liveTotalTime;
+    }
 }
 

+ 22 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/vo/ImLiveRoomVideoVo.java

@@ -3,6 +3,7 @@ package com.ym.mec.biz.dal.vo;
 import com.ym.mec.biz.dal.entity.ImLiveRoomVideo;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.StringUtils;
 
 import java.io.Serializable;
 
@@ -12,6 +13,9 @@ public class ImLiveRoomVideoVo extends ImLiveRoomVideo implements Serializable {
     @ApiModelProperty(value = "播出端-  pc网页端 移动端mobile")
     private String os;
 
+    @ApiModelProperty("视频类型")
+    private String videoType;
+
     public String getOs() {
         return os;
     }
@@ -19,4 +23,22 @@ public class ImLiveRoomVideoVo extends ImLiveRoomVideo implements Serializable {
     public void setOs(String os) {
         this.os = os;
     }
+
+    public String getVideoType() {
+
+        if (StringUtils.isNotEmpty(getUrl())) {
+
+            String fileName = getUrl();
+            int indexOf = fileName.lastIndexOf("?");
+            if (indexOf > -1) {
+                fileName = getUrl().substring(0, indexOf);
+            }
+            return fileName.substring(fileName.lastIndexOf(".") + 1);
+        }
+        return videoType;
+    }
+
+    public void setVideoType(String videoType) {
+        this.videoType = videoType;
+    }
 }

+ 56 - 0
mec-biz/src/main/java/com/ym/mec/biz/redisson/RedissonMessageService.java

@@ -0,0 +1,56 @@
+package com.ym.mec.biz.redisson;
+
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RTopic;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * Redisson消息发布订阅服务
+ */
+@Slf4j
+@Service
+public class RedissonMessageService {
+
+    // 订阅消息通知
+    public static final String TOPIC_MESSAGE = "topic:message";
+    // 直播在线人数
+    public static final String LIVE_ROOM_MEMBER = "delayQueue:liveRoomMember:";
+
+    private final RedissonClient redissonClient;
+
+    @Autowired
+    public RedissonMessageService(RedissonClient redissonClient) {
+
+        this.redissonClient = redissonClient;
+    }
+
+    /**
+     * 订阅消息
+     * @param topic 消息主题
+     * @param listener MessageListener
+     */
+    public void subscribe(String topic, MessageListener listener) {
+        RTopic messageTopic = redissonClient.getTopic(topic);
+        messageTopic.addListener(String.class, (channel, msg) -> listener.onMessage(msg));
+    }
+
+    /**
+     * 发布消息
+     * @param topic 消息主题
+     * @param message 消息内容
+     */
+    public void publish(String topic, String message) {
+        RTopic messageTopic = redissonClient.getTopic(topic);
+        messageTopic.publish(message);
+    }
+
+    /**
+     * 消息监听
+     */
+    public interface MessageListener {
+        void onMessage(String message);
+    }
+
+}

+ 1 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/ImLiveBroadcastRoomMemberService.java

@@ -2,6 +2,7 @@ package com.ym.mec.biz.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ym.mec.biz.dal.dao.ImLiveBroadcastRoomMemberDao;
+import com.ym.mec.biz.dal.dto.LiveRoomStatus;
 import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomMember;
 import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomDetailVo;
 import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomMemberVo;

+ 61 - 1
mec-biz/src/main/java/com/ym/mec/biz/service/ImLiveBroadcastRoomService.java

@@ -2,7 +2,9 @@ package com.ym.mec.biz.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ym.mec.biz.dal.dto.ImLiveBroadcastRoomDto;
+import com.ym.mec.biz.dal.dto.LiveRoomStatus;
 import com.ym.mec.biz.dal.dto.RoomReservationUserSearch;
+import com.ym.mec.biz.dal.dto.TencentData;
 import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoom;
 import com.ym.mec.biz.dal.page.LiveRoomGoodsOrderQueryInfo;
 import com.ym.mec.biz.dal.vo.BaseRoomUserVo;
@@ -70,15 +72,23 @@ public interface ImLiveBroadcastRoomService extends IService<ImLiveBroadcastRoom
 
     ImLiveBroadcastRoomVo speakerJoinRoom(String roomUid, String os);
 
+    void setGroupMemberDefinedData(ImLiveBroadcastRoomVo roomVo, Integer onlineUser, Integer totalUser);
+
     void joinRoom(String roomUid, Integer userId);
 
     void startLive(String roomUid, Integer userId,String videoResolution);
 
+    void startLive(String roomUid, Integer userId, String videoResolution, String sequence);
+
     void closeLive(String roomUid, Integer userId);
 
+    void closeLive(String roomUid, Integer userId, String sequence);
+
     void createLiveRoom();
 
-    Map<String, Object> test(String roomUid,String userFlag);
+    void createLiveRoom(ImLiveBroadcastRoom room);
+
+    Map<String, Object> test(String roomUid, String userFlag);
 
     /**
      * @param roomUid 直播间uid
@@ -126,5 +136,55 @@ public interface ImLiveBroadcastRoomService extends IService<ImLiveBroadcastRoom
      * @param whetherMic 是否连麦 0: 是 1:否
      */
     void whetherMic(String roomUid, Integer whetherMic);
+
+    /**
+     * 更新主播直播间状态
+     *
+     * @param status 直播间状态
+     * @return
+     */
+    Boolean updateRoomStatus(LiveRoomStatus status);
+
+    /**
+     * 直播群成员在线状态回调处理
+     *
+     */
+    void callbackOnMemberStateChange(TencentData.CallbackOnMemberStateChange callbackOnMemberStateChange);
+    /**
+     * 群成员离开之后回调
+     */
+    void callbackAfterMemberExit(TencentData.CallbackAfterMemberExit callbackAfterMemberExit);
+
+    /**
+     * 新成员入群之后回调
+     */
+    void callbackAfterNewMemberJoin(TencentData.CallbackAfterNewMemberJoin callbackAfterNewMemberJoin);
+
+    /**
+     * 直播间销毁定时任务
+     */
+    void destroyLiveRoom();
+
+    /**
+     * 更新直播推流时间
+     * @param event TencentData.CallbackStreamStateEvent
+     */
+    void updateLiveRoomPushStreamTime(TencentData.CallbackStreamStateEvent event);
+
+    /**
+     * 修改用户连麦状态
+     *
+     * @param roomUid 直播房间id
+     * @param userId 用户id
+     * @param whetherMicStatus 连麦状态
+     */
+    void userWhetherMic(String roomUid, Long userId, Integer whetherMicStatus);
+
+    /**
+     * 同步直播间点赞数
+     *
+     * @param roomUid 直播间uid
+     */
+    int syncLikeCount(String roomUid);
 }
 

+ 12 - 2
mec-biz/src/main/java/com/ym/mec/biz/service/ImLiveRoomBlackService.java

@@ -3,6 +3,7 @@ package com.ym.mec.biz.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ym.mec.auth.api.entity.SysUser;
 import com.ym.mec.biz.dal.entity.ImLiveRoomBlack;
+import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomVo;
 import com.ym.mec.biz.dal.vo.ImLiveRoomBlackVo;
 import com.ym.mec.common.page.PageInfo;
 
@@ -34,6 +35,8 @@ public interface ImLiveRoomBlackService extends IService<ImLiveRoomBlack> {
      */
     void add(Map<String, Object> param);
 
+    void setBlack(Integer userId, ImLiveBroadcastRoomVo roomVo);
+
     /**
      * 删除该用户从房间黑名单中移除
      *
@@ -53,10 +56,17 @@ public interface ImLiveRoomBlackService extends IService<ImLiveRoomBlack> {
     /**
      * 发送黑名单消息到直播房间
      *
-     * @param roomUid    房间uid
+     * @param roomVo    房间
      * @param fromUserId 发送人id
      * @param userId     用户id
      */
-    void sendBlackMsg(String roomUid, Integer fromUserId, Integer userId, String type);
+    void sendBlackMsg(ImLiveBroadcastRoomVo roomVo, Integer fromUserId, Integer userId, String type);
+
+    /**
+     * 检查用户是否在房间黑名单中
+     * @param userId 用户id
+     * @param roomUid 房间uid
+     */
+    Boolean checkBlackUser(Integer userId, String roomUid);
 }
 

+ 8 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/ImLiveRoomVideoService.java

@@ -6,6 +6,7 @@ import com.ym.mec.biz.dal.entity.ImLiveRoomVideo;
 import com.ym.mec.biz.dal.vo.ImLiveRoomVideoVo;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 直播视频记录(ImLiveRoomVideo)表服务接口
@@ -18,5 +19,12 @@ public interface ImLiveRoomVideoService extends IService<ImLiveRoomVideo> {
     ImLiveRoomVideoDao getDao();
 
     List<ImLiveRoomVideoVo> queryList(String roomUid);
+
+    /**
+     * 直播间的视频数
+     *
+     * @param roomIdList 直播间id
+     */
+    Map<String,Integer> queryRoomUidCountMap(List<String> roomIdList);
 }
 

+ 3 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/ChildrenDayReserveServiceImpl.java

@@ -21,6 +21,7 @@ import com.ym.mec.util.http.HttpUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -55,6 +56,8 @@ public class ChildrenDayReserveServiceImpl extends BaseServiceImpl<Integer, Chil
     private PayService payService;
     @Autowired
     private SysUserCashAccountDetailService sysUserCashAccountDetailService;
+
+    @Lazy
     @Autowired
     private ContractService contractService;
     @Autowired

+ 5 - 4
mec-biz/src/main/java/com/ym/mec/biz/service/impl/ContractServiceImpl.java

@@ -20,7 +20,6 @@ import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Lazy;
@@ -88,8 +87,10 @@ import com.ym.mec.util.freemarker.FreemarkerTemplateEngine;
 import com.ym.mec.util.money.MoneyUtil;
 import com.ym.mec.util.pdf.PDFUtil;
 
+import javax.annotation.PostConstruct;
+
 @Service
-public class ContractServiceImpl implements ContractService, InitializingBean {
+public class ContractServiceImpl implements ContractService {
 
     @Autowired
     private SysUserTsignService sysUserTsignService;
@@ -175,8 +176,8 @@ public class ContractServiceImpl implements ContractService, InitializingBean {
 
     private final Logger logger = LoggerFactory.getLogger(ContractService.class);
 
-    @Override
-    public void afterPropertiesSet() throws Exception {
+    @PostConstruct
+    public void afterPropertiesSet() {
         // 注册企业账户
         Map<String, String> organList = new HashMap<String, String>();
         organList.put("91420106333619290A", "2,武汉长乐长风乐器销售有限公司");

File diff suppressed because it is too large
+ 667 - 65
mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveBroadcastRoomServiceImpl.java


+ 70 - 13
mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveRoomBlackServiceImpl.java

@@ -5,11 +5,16 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.microsvc.toolkit.middleware.live.LivePluginContext;
+import com.microsvc.toolkit.middleware.live.LivePluginService;
+import com.microsvc.toolkit.middleware.live.message.LiveRoomMessage;
 import com.ym.mec.auth.api.client.SysUserFeignService;
 import com.ym.mec.auth.api.entity.SysUser;
 import com.ym.mec.biz.dal.dao.ImLiveRoomBlackDao;
 import com.ym.mec.biz.dal.entity.ImLiveRoomBlack;
+import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomVo;
 import com.ym.mec.biz.dal.vo.ImLiveRoomBlackVo;
+import com.ym.mec.biz.service.ImLiveBroadcastRoomService;
 import com.ym.mec.biz.service.ImLiveRoomBlackService;
 import com.ym.mec.common.entity.ImRoomMessage;
 import com.ym.mec.common.exception.BizException;
@@ -17,7 +22,6 @@ import com.ym.mec.common.page.PageInfo;
 import com.ym.mec.common.page.PageUtil;
 import com.ym.mec.common.page.WrapperUtil;
 import com.ym.mec.common.tenant.TenantContextHolder;
-import com.ym.mec.im.ImFeignService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -40,7 +44,9 @@ public class ImLiveRoomBlackServiceImpl extends ServiceImpl<ImLiveRoomBlackDao,
     @Autowired
     private SysUserFeignService sysUserFeignService;
     @Autowired
-    private ImFeignService imFeignService;
+    private LivePluginContext livePluginContext;
+    @Autowired
+    private ImLiveBroadcastRoomService imLiveBroadcastRoomService;
 
     /**
      * 查询当前机构学生 -下拉框
@@ -73,6 +79,7 @@ public class ImLiveRoomBlackServiceImpl extends ServiceImpl<ImLiveRoomBlackDao,
     public void add(Map<String, Object> param) {
         String roomUid = WrapperUtil.toStr(param, "roomUid");
         List<String> userIdList = WrapperUtil.toList(WrapperUtil.toStr(param, "userIdList", "用户id不能为空"));
+
         userIdList.forEach(userIdStr -> {
             Integer userId = Integer.parseInt(userIdStr);
             int count = this.count(Wrappers.<ImLiveRoomBlack>lambdaQuery()
@@ -88,13 +95,41 @@ public class ImLiveRoomBlackServiceImpl extends ServiceImpl<ImLiveRoomBlackDao,
             imLiveRoomBlack.setCreateBy(getSysUser().getId());
             imLiveRoomBlack.setCreateTime(new Date());
             this.save(imLiveRoomBlack);
-            //发送消息到直播房间
-            this.sendBlackMsg(roomUid, userId, userId, ImRoomMessage.BLOCK_BLACK_USER);
-            //调用融云方法加入禁言
-            imFeignService.addUserUnableSpeak(roomUid, userIdStr);
+            ImLiveBroadcastRoomVo roomVo = imLiveBroadcastRoomService.queryRoomInfo(roomUid);
+            if (roomVo == null) {
+                throw new BizException("直播房间不存在");
+            }
+            if (roomVo.getLiveState() != 1) {
+                log.info("直播房间未开播,不需要发送消息");
+                return;
+            }
+            setBlack( userId, roomVo);
         });
     }
 
+    @Override
+    public void setBlack(Integer userId, ImLiveBroadcastRoomVo roomVo) {
+        //发送消息到直播房间
+        this.sendBlackMsg(roomVo, userId, userId, ImRoomMessage.BLOCK_BLACK_USER);
+        //调用融云方法加入禁言
+        LivePluginService pluginService = livePluginContext.getPluginService(roomVo.getServiceProvider());
+        try {
+
+            SysUser sysUser = sysUserFeignService.queryUserById(userId);
+            if (sysUser == null) {
+                log.error("用户不存在");
+                return;
+            }
+
+            // 注册主播用户信息到三方平台
+            pluginService.register(sysUser.getId().toString(), sysUser.getUsername(), sysUser.getAvatar());
+
+            pluginService.chatRoomUserGagCreate(userId.toString(), roomVo.getRoomUid(),-1L);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     /**
      * 删除该用户从房间黑名单中移除
      *
@@ -107,15 +142,21 @@ public class ImLiveRoomBlackServiceImpl extends ServiceImpl<ImLiveRoomBlackDao,
     public void delete(Map<String, Object> param) {
         String roomUid = WrapperUtil.toStr(param, "roomUid");
         List<String> userIdList = WrapperUtil.toList(WrapperUtil.toStr(param, "userIdList", "用户id不能为空"));
+        ImLiveBroadcastRoomVo roomVo = imLiveBroadcastRoomService.queryRoomInfo(roomUid);
         userIdList.forEach(userIdStr -> {
             Integer userId = Integer.parseInt(userIdStr);
             this.remove(Wrappers.<ImLiveRoomBlack>lambdaQuery()
                     .eq(ImLiveRoomBlack::getRoomUid, roomUid)
                     .eq(ImLiveRoomBlack::getUserId, userId));
             //发送消息到直播房间
-            this.sendBlackMsg(roomUid, userId, userId, ImRoomMessage.UNBLOCK_BLACK_USER);
+            this.sendBlackMsg(roomVo, userId, userId, ImRoomMessage.UNBLOCK_BLACK_USER);
             //调用融云方法加入禁言
-            imFeignService.removeUserUnableSpeak(roomUid, userIdStr);
+            LivePluginService pluginService = livePluginContext.getPluginService(roomVo.getServiceProvider());
+            try {
+                pluginService.chatRoomuserGagRemove(userIdStr,roomUid);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
         });
     }
 
@@ -136,27 +177,29 @@ public class ImLiveRoomBlackServiceImpl extends ServiceImpl<ImLiveRoomBlackDao,
     /**
      * 发送黑名单消息到直播房间
      *
-     * @param roomUid    房间uid
+     * @param roomVo    房间uid
      * @param fromUserId 发送人id
      * @param userId     用户id
      */
-    public void sendBlackMsg(String roomUid, Integer fromUserId, Integer userId, String type) {
+    public void sendBlackMsg(ImLiveBroadcastRoomVo roomVo, Integer fromUserId, Integer userId, String type) {
+        String roomUid = roomVo.getRoomUid();
         //校验传入参数,房间uid和发送人id不能为空
         if (!WrapperUtil.checkObj(roomUid, fromUserId, userId, type)) {
             log.info(" sendBlackMsg>>>> param is null   roomUid: {}  fromUserId:{}  type:{}", roomUid, fromUserId, type);
             return;
         }
-        ImRoomMessage message = new ImRoomMessage();
+        LiveRoomMessage message = new LiveRoomMessage();
         message.setIsIncludeSender(1);
         message.setObjectName(type);
-        message.setToChatroomId(roomUid);
+        message.setToChatRoomId(roomUid);
         HashMap<String, Integer> sendMap = new HashMap<>();
         sendMap.put("userId", userId);
         message.setFromUserId(fromUserId.toString());
         message.setContent(sendMap);
         //发送消息
         try {
-            imFeignService.publishRoomMsg(message);
+            LivePluginService pluginService = livePluginContext.getPluginService(roomVo.getServiceProvider());
+            pluginService.sendChatRoomMessage(message);
             log.info("sendBlackMsg>>>> message: {}", JSONObject.toJSONString(message));
         } catch (Exception e) {
             log.error("sendBlackMsg>>>> error {}", e.getMessage());
@@ -164,6 +207,20 @@ public class ImLiveRoomBlackServiceImpl extends ServiceImpl<ImLiveRoomBlackDao,
         }
     }
 
+    /**
+     * 检查用户是否在房间黑名单中
+     *
+     * @param userId  用户id
+     * @param roomUid 房间uid
+     */
+    @Override
+    public Boolean checkBlackUser(Integer userId, String roomUid) {
+        ImLiveRoomBlack imLiveRoomBlack = this.getOne(Wrappers.<ImLiveRoomBlack>lambdaQuery()
+                .eq(ImLiveRoomBlack::getRoomUid, roomUid)
+                .eq(ImLiveRoomBlack::getUserId, userId));
+        return imLiveRoomBlack != null;
+    }
+
     private SysUser getSysUser() {
         //修改机构基础信息
         return Optional.ofNullable(sysUserFeignService.queryUserInfo())

+ 2 - 5
mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveRoomReservationServiceImpl.java

@@ -1,7 +1,7 @@
 package com.ym.mec.biz.service.impl;
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
-import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -10,11 +10,9 @@ import com.ym.mec.auth.api.entity.SysUser;
 import com.ym.mec.biz.dal.dao.ImLiveRoomReservationDao;
 import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoom;
 import com.ym.mec.biz.dal.entity.ImLiveRoomReservation;
-import com.ym.mec.biz.dal.entity.Student;
 import com.ym.mec.biz.dal.enums.MessageTypeEnum;
 import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomVo;
 import com.ym.mec.biz.service.ImLiveRoomReservationService;
-import com.ym.mec.biz.service.StudentService;
 import com.ym.mec.biz.service.SysMessageService;
 import com.ym.mec.common.exception.BizException;
 import com.ym.mec.common.page.PageInfo;
@@ -46,8 +44,6 @@ public class ImLiveRoomReservationServiceImpl extends ServiceImpl<ImLiveRoomRese
     @Autowired
     private SysUserFeignService sysUserFeignService;
     @Autowired
-    private StudentService studentService;
-    @Autowired
     private SysMessageService sysMessageService;
 
     /**
@@ -108,6 +104,7 @@ public class ImLiveRoomReservationServiceImpl extends ServiceImpl<ImLiveRoomRese
         for (ImLiveRoomReservation obj : list) {
             pushStudentList.put(obj.getUserId(), obj.getUserId().toString());
         }
+        log.debug("ImLiveRoomReservation push >>> RECEIVES: {}", JSON.toJSONString(pushStudentList));
         //推送状态
         AtomicInteger pushState = new AtomicInteger(0);
         try {

+ 27 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveRoomVideoServiceImpl.java

@@ -1,6 +1,7 @@
 package com.ym.mec.biz.service.impl;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.common.collect.Maps;
 import com.ym.mec.biz.dal.dao.ImLiveRoomVideoDao;
 import com.ym.mec.biz.dal.entity.ImLiveRoomVideo;
 import com.ym.mec.biz.dal.vo.ImLiveRoomVideoVo;
@@ -11,6 +12,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 直播视频记录(ImLiveRoomVideo)表服务实现类
@@ -32,5 +34,30 @@ public class ImLiveRoomVideoServiceImpl extends ServiceImpl<ImLiveRoomVideoDao,
         return baseMapper.queryVideoList(roomUid);
     }
 
+    /**
+     * 直播间的视频数
+     *
+     * @param roomIdList 直播间id
+     */
+    @Override
+    public Map<String, Integer> queryRoomUidCountMap(List<String> roomIdList) {
+        if (roomIdList == null || roomIdList.isEmpty()) {
+            return Maps.newHashMap();
+        }
+        List<ImLiveRoomVideo> list = this.lambdaQuery().in(ImLiveRoomVideo::getRoomUid, roomIdList).list();
+        Map<String, Integer> map = Maps.newHashMap();
+        for (ImLiveRoomVideo imLiveRoomVideo : list) {
+            String roomUid = imLiveRoomVideo.getRoomUid();
+            Integer count = map.get(roomUid);
+            if (count == null) {
+                count = 0;
+            }
+            map.put(roomUid, count + 1);
+        }
+        return map;
+
+
+    }
+
 }
 

+ 0 - 3
mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImSendGroupMessageServiceImpl.java

@@ -3,7 +3,6 @@ package com.ym.mec.biz.service.impl;
 import com.ym.mec.auth.api.client.SysUserFeignService;
 import com.ym.mec.auth.api.entity.SysUser;
 import com.ym.mec.biz.dal.dao.ImSendGroupMessageDao;
-import com.ym.mec.biz.dal.dao.SysConfigDao;
 import com.ym.mec.biz.dal.entity.ImSendGroupMessage;
 import com.ym.mec.biz.dal.enums.ImSendTypeEnum;
 import com.ym.mec.biz.service.ImSendGroupMessageService;
@@ -28,8 +27,6 @@ public class ImSendGroupMessageServiceImpl extends BaseServiceImpl<Long, ImSendG
 	private SysMessageService sysMessageService;
 	@Autowired
 	private SysUserFeignService sysUserFeignService;
-	@Autowired
-	private SysConfigDao sysConfigDao;
 
 	@Override
 	public BaseDAO<Long, ImSendGroupMessage> getDAO() {

+ 47 - 10
mec-biz/src/main/java/com/ym/mec/biz/service/impl/LiveGoodsMapperServiceImpl.java

@@ -1,6 +1,11 @@
 package com.ym.mec.biz.service.impl;
 
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.microsvc.toolkit.middleware.live.LivePluginContext;
+import com.microsvc.toolkit.middleware.live.message.LiveRoomMessage;
+import com.ym.mec.auth.api.client.SysUserFeignService;
+import com.ym.mec.auth.api.entity.SysUser;
 import com.ym.mec.biz.dal.dao.LiveGoodsMapperDao;
 import com.ym.mec.biz.dal.dto.LiveGoodsMapperDto;
 import com.ym.mec.biz.dal.dto.RedisKeyConstant;
@@ -15,8 +20,8 @@ import com.ym.mec.common.entity.ImRoomMessage;
 import com.ym.mec.common.exception.BizException;
 import com.ym.mec.common.page.PageInfo;
 import com.ym.mec.common.service.impl.BaseServiceImpl;
-import com.ym.mec.im.ImFeignService;
 import com.ym.mec.util.collection.MapUtil;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;
 import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -24,9 +29,9 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.*;
-import java.util.stream.Collectors;
 
 @Service
+@Slf4j
 public class LiveGoodsMapperServiceImpl extends BaseServiceImpl<Integer, LiveGoodsMapper>  implements LiveGoodsMapperService {
 	
 	@Autowired
@@ -34,12 +39,14 @@ public class LiveGoodsMapperServiceImpl extends BaseServiceImpl<Integer, LiveGoo
 	@Autowired
 	private LiveGoodsMapperDao liveGoodsMapperDao;
 	@Autowired
-	private ImFeignService imFeignService;
+	private LivePluginContext livePluginContext;
 	@Autowired
 	private ImLiveBroadcastRoomService imLiveBroadcastRoomService;
 	@Autowired
 	private RedissonClient redissonClient;
 
+	@Autowired
+	private SysUserFeignService sysUserFeignService;
 
 	@Override
 	public BaseDAO<Integer, LiveGoodsMapper> getDAO() {
@@ -104,13 +111,43 @@ public class LiveGoodsMapperServiceImpl extends BaseServiceImpl<Integer, LiveGoo
 	}
 
 	private void publishRoomMsg(ImLiveBroadcastRoom imLiveBroadcastRoom) {
-		ImRoomMessage message = new ImRoomMessage();
-		message.setIsIncludeSender(1);
-		message.setObjectName(ImRoomMessage.LIVE_GOODS_CHANGE);
-		message.setToChatroomId(imLiveBroadcastRoom.getRoomUid());
-		message.setFromUserId(imLiveBroadcastRoom.getSpeakerId().toString());
-		message.setContent(liveGoodsMapperDao.getLiveGoodsList(imLiveBroadcastRoom.getRoomUid(),null,true));
-		imFeignService.publishRoomMsg(message);
+
+
+		// 消息发送用户
+		LiveRoomMessage.MessageUser messageUser = null;
+		SysUser sysUser = sysUserFeignService.queryUserById(imLiveBroadcastRoom.getSpeakerId());
+		if (Objects.nonNull(sysUser)) {
+			// 发送用户信息
+			messageUser = LiveRoomMessage.MessageUser
+				.builder()
+				.sendUserId(sysUser.getId().toString())
+				.sendUserName(sysUser.getUsername())
+				.avatarUrl(sysUser.getAvatar())
+				.build();
+		}
+
+		LiveRoomMessage.MessageContent messageContent = LiveRoomMessage.MessageContent
+			.builder()
+			.sendUserInfo(messageUser)
+			.goodsContent(liveGoodsMapperDao.getLiveGoodsList(imLiveBroadcastRoom.getRoomUid(),null,true))
+			.build();
+
+		LiveRoomMessage message = LiveRoomMessage.builder()
+												 .isIncludeSender(1)
+												 .objectName(LiveRoomMessage.LIVE_GOODS_CHANGE)
+												 .fromUserId(sysUser.getId().toString())
+												 .toChatRoomId(imLiveBroadcastRoom.getRoomUid())
+												 .content(messageContent)
+												 .build();
+
+		//发送消息
+		try {
+			livePluginContext.getPluginService(imLiveBroadcastRoom.getServiceProvider()).sendChatRoomMessage(message);
+			log.info("LIVE_GOODS_CHANGE>>>> message: {}", JSONObject.toJSONString(message));
+		} catch (Exception e) {
+			log.error("LIVE_GOODS_CHANGE>>>> error {}", e.getMessage());
+			log.error("LIVE_GOODS_CHANGE>>>> sendMessage {} :", JSONObject.toJSONString(message));
+		}
 	}
 
 	@Override

+ 5 - 1
mec-biz/src/main/java/com/ym/mec/biz/service/impl/MemberRankSettingServiceImpl.java

@@ -14,6 +14,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.function.BiPredicate;
 import java.util.stream.Collectors;
 
+import com.alibaba.fastjson.JSON;
 import com.ym.mec.biz.service.*;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -23,6 +24,7 @@ import org.redisson.api.RedissonClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.http.HttpStatus;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Isolation;
@@ -31,7 +33,6 @@ import org.springframework.transaction.annotation.Transactional;
 import com.alibaba.fastjson.JSONArray;
 import com.ym.mec.auth.api.client.SysUserFeignService;
 import com.ym.mec.auth.api.entity.SysUser;
-import com.ym.mec.biz.dal.dao.ActivityUserMapperDao;
 import com.ym.mec.biz.dal.dao.MemberRankPrivilegesDao;
 import com.ym.mec.biz.dal.dao.MemberRankSettingDao;
 import com.ym.mec.biz.dal.dao.StudentPaymentOrderDetailDao;
@@ -92,6 +93,8 @@ public class MemberRankSettingServiceImpl extends BaseServiceImpl<Integer, Membe
     private SysUserCashAccountService sysUserCashAccountService;
     @Autowired
     private SysUserCashAccountDetailService sysUserCashAccountDetailService;
+
+    @Lazy
     @Autowired
     private ContractService contractService;
     @Autowired
@@ -381,6 +384,7 @@ public class MemberRankSettingServiceImpl extends BaseServiceImpl<Integer, Membe
                 filter(e -> Arrays.stream(e.getOrganId().split(",")).collect(Collectors.toList()).contains(sysUser.getOrganId().toString())).collect(Collectors.toList());
         if(CollectionUtils.isEmpty(activityDtos)){
             succeed.setMsg("当前分部暂未开通活动");
+            succeed.setData(2);
             return succeed;
         }
         if(memberPayParamDto.getLiveGoodsId() == 1 || memberPayParamDto.getLiveGoodsId() == 5){

+ 3 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/ReplacementInstrumentActivityServiceImpl.java

@@ -12,6 +12,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -100,6 +101,8 @@ public class ReplacementInstrumentActivityServiceImpl extends BaseServiceImpl<In
     private SysConfigDao sysConfigDao;
     @Autowired
     private PayService payService;
+
+    @Lazy
     @Autowired
     private ContractService contractService;
     @Autowired

+ 3 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/SporadicChargeInfoImpl.java

@@ -17,6 +17,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
@@ -48,6 +49,8 @@ public class SporadicChargeInfoImpl extends BaseServiceImpl<Integer, SporadicCha
     private SysUserCashAccountDetailService sysUserCashAccountDetailService;
     @Autowired
     private DegreeRegistrationService degreeRegistrationService;
+
+    @Lazy
     @Autowired
     private ContractService contractService;
     @Autowired

+ 3 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/StudentInstrumentServiceImpl.java

@@ -12,6 +12,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -74,6 +75,8 @@ public class StudentInstrumentServiceImpl extends BaseServiceImpl<Long, StudentI
     private StudentPaymentRouteOrderService studentPaymentRouteOrderService;
     @Autowired
     private StudentPaymentOrderService studentPaymentOrderService;
+
+    @Lazy
     @Autowired
     private ContractService contractService;
     @Autowired

+ 33 - 1
mec-biz/src/main/java/com/ym/mec/biz/service/impl/StudentPaymentOrderServiceImpl.java

@@ -119,6 +119,8 @@ public class StudentPaymentOrderServiceImpl extends BaseServiceImpl<Long, Studen
     private TenantConfigService tenantConfigService;
     @Autowired
     private GoodsProcurementDao goodsProcurementDao;
+
+    @Lazy
     @Autowired
     private ContractService contractService;
     @Autowired
@@ -182,6 +184,7 @@ public class StudentPaymentOrderServiceImpl extends BaseServiceImpl<Long, Studen
 
         String baseApiUrl = sysConfigDao.findConfigValue("base_api_url");
 
+        //logger.info("XXX-createOrder ---> cashAmount:{}, balance:{}", cashAmount, cashAmount.compareTo(BigDecimal.ZERO));
         if (cashAmount.compareTo(BigDecimal.ZERO) == 0) {
 
             studentPaymentRouteOrderService.addRouteOrder(studentPaymentOrder.getOrderNo(), studentPaymentOrder.getOrganId(), balance);
@@ -394,9 +397,12 @@ public class StudentPaymentOrderServiceImpl extends BaseServiceImpl<Long, Studen
 
     @Transactional(rollbackFor = Exception.class)
     public void updateOrder(Map<String, String> rpMap) throws Exception {
+
+        //logger.info("XXX-createOrder ---> updateOrder:{}", rpMap);
+
         DealStatusEnum status = rpMap.get("tradeState").equals("1") ? DealStatusEnum.SUCCESS : DealStatusEnum.FAILED;
         StudentPaymentOrder order = findOrderByOrderNo(rpMap.get("merOrderNo"));
-        order = studentPaymentOrderDao.lockOrder(order.getId());
+        //order = studentPaymentOrderDao.lockOrder(order.getId());
         //关闭或失败的订单查询订单成功,订单改成成功,钱退到余额
         if (order != null && (order.getStatus().equals(DealStatusEnum.CLOSE) || order.getStatus().equals(DealStatusEnum.FAILED)) && status.equals(DealStatusEnum.SUCCESS)) {
             String memo = order.getStatus().equals(DealStatusEnum.CLOSE) ? "关闭订单" : "失败订单";
@@ -431,6 +437,7 @@ public class StudentPaymentOrderServiceImpl extends BaseServiceImpl<Long, Studen
         } else {
             order.setMemo(rpMap.get("remarks"));
         }
+        // 设置订单状态
         order.setStatus(status);
         if (StringUtils.isBlank(order.getTransNo())) {
             order.setTransNo(rpMap.get("orderNo"));
@@ -438,7 +445,9 @@ public class StudentPaymentOrderServiceImpl extends BaseServiceImpl<Long, Studen
 
         order.setPaymentBusinessChannel(rpMap.get("channelType"));
         order.setTenantId(this.get(order.getId()).getTenantId());
+
         TenantContextHolder.setTenantId(order.getTenantId());
+
         callOrderCallBack(order);
 
         if (status.equals(DealStatusEnum.SUCCESS)
@@ -448,6 +457,28 @@ public class StudentPaymentOrderServiceImpl extends BaseServiceImpl<Long, Studen
             confirmOrder(order);
         }
         TenantContextHolder.clearTenantId();
+
+        /*StudentPaymentOrder finalOrder = order;
+        Executors.newCachedThreadPool().submit(() -> {
+
+            try {
+                TenantContextHolder.setTenantId(finalOrder.getTenantId());
+
+                callOrderCallBack(finalOrder);
+
+                if (status.equals(DealStatusEnum.SUCCESS)
+                        && StringUtils.isNotBlank(finalOrder.getPaymentChannel())
+                        && finalOrder.getPaymentChannel().equals("ADAPAY")
+                        && !rpMap.containsKey("simulation")) {
+                    confirmOrder(finalOrder);
+                }
+                TenantContextHolder.clearTenantId();
+            } catch (Exception e) {
+                logger.error("updateOrder 订单回调流程, order={}", JSON.toJSONString(finalOrder), e);
+            }
+
+        });*/
+
     }
 
     private Boolean confirmOrder(StudentPaymentOrder order) {
@@ -536,6 +567,7 @@ public class StudentPaymentOrderServiceImpl extends BaseServiceImpl<Long, Studen
 
     //调用相应业务回调接口
     public void callOrderCallBack(StudentPaymentOrder order) throws Exception {
+        //logger.info("XXX-createOrder ---> callOrderCallBack:{}", JSON.toJSONString(order));
         if(order.getGroupType() == GroupType.ACTIVITY){
             vipGroupActivityService.orderCallback(order);
         }else {

+ 3 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/StudentRegistrationServiceImpl.java

@@ -29,6 +29,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.http.HttpStatus;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.stereotype.Service;
@@ -202,6 +203,8 @@ public class StudentRegistrationServiceImpl extends BaseServiceImpl<Long, Studen
     private SysUserCashAccountDao sysUserCashAccountDao;
     @Autowired
     private StudentDao studentDao;
+
+    @Lazy
     @Autowired
     private ContractService contractService;
     @Autowired

+ 3 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/StudentRepairServiceImpl.java

@@ -19,6 +19,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Isolation;
 import org.springframework.transaction.annotation.Propagation;
@@ -97,6 +98,8 @@ public class StudentRepairServiceImpl extends BaseServiceImpl<Integer, StudentRe
     private StudentGoodsSellDao studentGoodsSellDao;
     @Autowired
     private GoodsProcurementDao goodsProcurementDao;
+
+    @Lazy
     @Autowired
     private ContractService contractService;
     @Autowired

+ 3 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/SubjectChangeServiceImpl.java

@@ -20,6 +20,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Isolation;
 import org.springframework.transaction.annotation.Transactional;
@@ -128,6 +129,8 @@ public class SubjectChangeServiceImpl extends BaseServiceImpl<Integer, SubjectCh
     private SysMessageService sysMessageService;
     @Autowired
     private StudentRegistrationService studentRegistrationService;
+
+    @Lazy
     @Autowired
     private ContractService contractService;
     @Autowired

+ 2 - 1
mec-biz/src/main/resources/config/mybatis/ImLiveBroadcastRoomDataMapper.xml

@@ -35,7 +35,8 @@
                r.live_remark_              AS liveRemark,
                ifnull(a.total_user_num_, 0) AS totalLookNum,
                ifnull(a.like_num_, 0)      as totalLikeNum,
-               ifnull(a.live_time_, 0)     as totalLiveTime,
+               ifnull(a.live_time_, 0)/60/1000     as totalLiveTime,
+               ifnull(r.live_total_time_, 0)     as liveTotalTime,
                r.live_start_time_      as liveStartTime,
                r.live_end_time_      as liveEndTime,
                r.live_state_      as liveState

+ 24 - 1
mec-biz/src/main/resources/config/mybatis/ImLiveBroadcastRoomMapper.xml

@@ -47,17 +47,24 @@
         a.room_title_ AS roomTitle,
         a.live_remark_ AS liveRemark,
         a.speaker_id_ AS speakerId,
+        a.client_type_ as clientType,
         b.real_name_ AS speakerName,
         b.im_token_ as imToken,
         b.avatar_ AS speakerPic,
         a.live_start_time_ AS liveStartTime,
         a.live_state_ AS liveState,
+        a.live_total_time_ AS liveTotalTime,
         a.room_state_ AS roomState,
         c.real_name_ AS createdByName,
         a.pre_template_ AS preTemplate,
         a.room_config_ AS roomConfig,
         a.popularize_ AS popularize,
-        a.popularize_type_ AS popularizeType
+        a.popularize_type_ AS popularizeType,
+        a.speaker_status_ AS speakerStatus,
+        a.push_status_ AS pushStatus,
+        a.ban_status_ AS banStatus,
+        a.created_time_ AS createdTime,
+        a.service_provider_ as serviceProvider
         from im_live_broadcast_room as a
         left join tenant_info AS t on a.tenant_id_ = t.id_
         left join sys_user AS b on a.speaker_id_ = b.id_
@@ -68,6 +75,7 @@
                 AND (
                 a.`id_` LIKE CONCAT('%', #{param.search},'%')
                 OR a.`room_title_` LIKE CONCAT('%', #{param.search},'%')
+                OR a.`live_remark_` LIKE CONCAT('%', #{param.search},'%')
                 )
             </if>
             <if test="param.tenantId != null ">
@@ -91,7 +99,22 @@
             <if test="param.speakerId != null">
                 and  a.speaker_id_ = #{param.speakerId}
             </if>
+            <if test="param.serviceProvider != null and param.serviceProvider != ''">
+                and  a.service_provider_ = #{param.serviceProvider}
+            </if>
+            <if test="param.clientType != null and param.clientType != ''">
+                and  a.client_type_ = #{param.clientType}
+            </if>
         </where>
+        order by
+        <choose>
+            <when test="param.sort == null or param.sort == ''">
+                a.created_time_ desc
+            </when>
+            <when test="param.sort == 1">
+                field(a.live_state_, 1, 0, 2) asc, a.live_start_time_ desc
+            </when>
+        </choose>
     </select>
 
     <select id="queryBaseUserInfo" resultType="com.ym.mec.biz.dal.vo.BaseRoomUserVo">

+ 47 - 4
mec-biz/src/main/resources/config/mybatis/ImLiveBroadcastRoomMemberMapper.xml

@@ -17,11 +17,11 @@
 
     <insert id="insertBatch" keyColumn="id_" keyProperty="id" useGeneratedKeys="true"
             parameterType="com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomMember">
-        insert into im_live_broadcast_room_member(tenant_id_, room_uid_, user_id_, join_time_, total_time_)
-        values
+        insert into im_live_broadcast_room_member(tenant_id_, room_uid_, user_id_, join_time_, total_time_) values
         <foreach collection="entities" item="entity" separator=",">
             (#{entity.tenantId}, #{entity.roomUid}, #{entity.userId}, #{entity.joinTime}, #{entity.totalTime})
         </foreach>
+        ON DUPLICATE KEY UPDATE join_time_ = VALUES(join_time_), total_time_ = VALUES(total_time_)
     </insert>
 
     <select id="queryMemberPage" resultType="com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomMemberVo">
@@ -29,13 +29,16 @@
         i.room_title_ as roomTitle,
         tu.real_name_ speakerName,
         a.user_id_ as studentId,
+        a.whether_mic_status_ as whetherMicStatus,
         su.username_ as studentName,
+        su.avatar_ as avatar,
         su.phone_ as phone,
         b.name_ as subName,
         o.name_ organName,
         GROUP_CONCAT(distinct mg.name_) musicGroupName,
         a.join_time_ as joinTime,
-        a.total_time_ as totalViewTime
+        a.total_time_ as totalViewTime,
+        if(ib.user_id_ is null, 0, 1) as blackFlag
         from im_live_broadcast_room_member as a
         left join im_live_broadcast_room as i on a.room_uid_ = i.room_uid_
         left join sys_user as su on su.id_ = a.user_id_
@@ -44,7 +47,8 @@
 		LEFT JOIN music_group mg ON  mg.id_ = sr.music_group_id_
         left join subject as b on st.subject_id_list_ = b.id_
 		left join `sys_user` tu on tu.`id_` = i.`speaker_id_` 
-		LEFT JOIN `organization` o on o.`id_` = su.`organ_id_` 
+		LEFT JOIN `organization` o on o.`id_` = su.`organ_id_`
+        left join im_live_room_black ib on ib.room_uid_ = a.room_uid_ and ib.user_id_ = a.user_id_
         where a.room_uid_ = #{param.roomUid}
         <if test="param.search != null ">
             AND (
@@ -52,7 +56,46 @@
             OR su.username_ LIKE CONCAT('%', #{param.search},'%')
             )
         </if>
+        <if test="param.onlineStatus != null">
+            AND (a.online_status_ = #{param.onlineStatus} and a.live_room_status_ = 1)
+        </if>
+        <if test="param.whetherMicStatus != null">
+            and a.whether_mic_status_ = #{param.whetherMicStatus}
+        </if>
         group by a.user_id_
     </select>
 
+    <update id="updateOnlineStatus">
+        update im_live_broadcast_room_member
+        set online_status_ = #{onlineStatus}
+        where room_uid_ = #{groupId} and user_id_ in <foreach collection="userIds" item="userId" open="(" separator="," close=")">#{userId}</foreach>
+    </update>
+
+    <update id="updateLiveRoomStatus">
+        update im_live_broadcast_room_member
+        set live_room_status_ = #{liveRoomStatus}
+        where room_uid_ = #{groupId} and user_id_ in <foreach collection="userIds" item="userId" open="(" separator="," close=")">#{userId}</foreach>
+
+    </update>
+
+    <select id="queryMember" resultType="com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomMember">
+        select * from im_live_broadcast_room_member
+        where room_uid_ = #{groupId} and user_id_ in <foreach collection="userIds" item="userId" open="(" separator="," close=")">#{userId}</foreach>
+
+    </select>
+
+    <update id="userWhetherMic">
+        update im_live_broadcast_room_member
+        set whether_mic_status_ = #{whetherMicStatus}
+        where room_uid_ = #{roomUid} and user_id_ = #{userId}
+    </update>
+
+    <select id="queryMemberNum" resultType="com.ym.mec.biz.dal.dto.RoomMemberNumDto">
+        select room_uid_ as roomUid,
+        count(1) as totalNum ,
+        sum(if(online_status_ = 1 and live_room_status_ = 1,1,0)) as onlineNum
+        from im_live_broadcast_room_member
+        where room_uid_ = #{roomUid}
+        group by room_uid_
+    </select>
 </mapper>

+ 2 - 0
mec-biz/src/main/resources/config/mybatis/ImLiveRoomReservationMapper.xml

@@ -43,6 +43,8 @@
         a.pre_template_ AS preTemplate,
         a.room_config_ AS roomConfig,
         a.popularize_ AS popularize,
+        a.created_time_ AS createdTime,
+        a.service_provider_ as serviceProvider,
         a.popularize_type_ AS popularizeType,
         IF(d.user_id_ is null, 0, 1) as reserve
         from (

+ 6 - 0
mec-client-api/src/main/java/com/ym/mec/task/TaskRemoteService.java

@@ -264,6 +264,12 @@ public interface TaskRemoteService {
     void destroyExpiredLiveRoom();
 
     /**
+     * 每日凌晨执行定时任务
+     */
+    @GetMapping("task/destroyLiveRoom")
+    void destroyLiveRoom();
+
+    /**
      * 学员小课统计
      */
     @GetMapping("task/studentSmallClassStatistics")

+ 5 - 0
mec-client-api/src/main/java/com/ym/mec/task/fallback/TaskRemoteServiceFallback.java

@@ -306,6 +306,11 @@ public class TaskRemoteServiceFallback implements TaskRemoteService {
     }
 
     @Override
+    public void destroyLiveRoom() {
+        logger.error("销毁直播间失败");
+    }
+
+    @Override
     public void studentSmallClassStatistics() {
         logger.error("学员小课统计失败");
     }

+ 1 - 1
mec-common/common-core/src/main/java/com/ym/mec/common/controller/BaseController.java

@@ -88,7 +88,7 @@ public class BaseController {
 		if (e == null) {
 			e = ex;
 		}
-		logger.error("System Error", ex);
+		logger.error("System Error", e);
 		// return failed(e.getMessage());
 		if (e instanceof BizException || e instanceof ThirdpartyException) {
 			if(e.getMessage().equals("205")){

+ 3 - 0
mec-common/common-core/src/main/java/com/ym/mec/common/entity/ImRoomMessage.java

@@ -24,6 +24,9 @@ public class ImRoomMessage extends BaseMessage {
     //objectName 类型-在黑名单中解除该用户
     public static final String UNBLOCK_BLACK_USER = "RC:UNBLOCK_BLACK_USER";
 
+    //objectName 类型-用户点赞数同步
+    public static final String LIKES_COUNT = "RC:Chatroom:LikeCount";
+
     /**
      * <p>必传
      * 消息类型

+ 2 - 2
mec-education/src/main/resources/bootstrap-test.properties

@@ -1,9 +1,9 @@
 #\u6307\u5b9a\u5f00\u53d1\u73af\u5883
 #spring.profiles.active=dev
 #\u670d\u52a1\u5668\u5730\u5740
-spring.cloud.nacos.config.server-addr=47.96.85.100:8848
+spring.cloud.nacos.config.server-addr=43.137.4.92:8848
 #\u9ed8\u8ba4\u4e3aPublic\u547d\u540d\u7a7a\u95f4,\u53ef\u4ee5\u7701\u7565\u4e0d\u5199
-spring.cloud.nacos.config.namespace=02105743-16b8-46ab-87df-2aca0f3dbca3
+spring.cloud.nacos.config.namespace=414816a2-0087-48ac-b50b-375d61cf1cd5
 #\u6307\u5b9a\u914d\u7f6e\u7fa4\u7ec4 --\u5982\u679c\u662fPublic\u547d\u540d\u7a7a\u95f4 \u5219\u53ef\u4ee5\u7701\u7565\u7fa4\u7ec4\u914d\u7f6e
 spring.cloud.nacos.config.group=DEFAULT_GROUP
 #\u6587\u4ef6\u540d -- \u5982\u679c\u6ca1\u6709\u914d\u7f6e\u5219\u9ed8\u8ba4\u4e3a ${spring.appliction.name}

+ 1 - 0
mec-eureka/pom.xml

@@ -42,6 +42,7 @@
 			<plugin>
 				<groupId>com.spotify</groupId>
 				<artifactId>docker-maven-plugin</artifactId>
+				<version>1.2.2</version>
 			</plugin>
 		</plugins>
 	</build>

+ 2 - 2
mec-eureka/src/main/resources/bootstrap-test.properties

@@ -1,9 +1,9 @@
 #\u6307\u5b9a\u5f00\u53d1\u73af\u5883
 #spring.profiles.active=dev
 #\u670d\u52a1\u5668\u5730\u5740
-spring.cloud.nacos.config.server-addr=47.114.176.40:8848
+spring.cloud.nacos.config.server-addr=43.137.4.92:8848
 #\u9ed8\u8ba4\u4e3aPublic\u547d\u540d\u7a7a\u95f4,\u53ef\u4ee5\u7701\u7565\u4e0d\u5199
-spring.cloud.nacos.config.namespace=46f06363-b9d6-46f0-9cd7-7b33dcf26bb0
+spring.cloud.nacos.config.namespace=414816a2-0087-48ac-b50b-375d61cf1cd5
 #\u6307\u5b9a\u914d\u7f6e\u7fa4\u7ec4 --\u5982\u679c\u662fPublic\u547d\u540d\u7a7a\u95f4 \u5219\u53ef\u4ee5\u7701\u7565\u7fa4\u7ec4\u914d\u7f6e
 spring.cloud.nacos.config.group=DEFAULT_GROUP
 #\u6587\u4ef6\u540d -- \u5982\u679c\u6ca1\u6709\u914d\u7f6e\u5219\u9ed8\u8ba4\u4e3a ${spring.appliction.name}

+ 1 - 0
mec-gateway/mec-gateway-admin/pom.xml

@@ -33,6 +33,7 @@
 			<plugin>
 				<groupId>com.spotify</groupId>
 				<artifactId>docker-maven-plugin</artifactId>
+				<version>1.2.2</version>
 			</plugin>
 		</plugins>
 	</build>

+ 1 - 0
mec-gateway/mec-gateway-web/pom.xml

@@ -71,6 +71,7 @@
 			<plugin>
 				<groupId>com.spotify</groupId>
 				<artifactId>docker-maven-plugin</artifactId>
+				<version>1.2.2</version>
 			</plugin>
 		</plugins>
 	</build>

+ 2 - 2
mec-gateway/mec-gateway-web/src/main/resources/bootstrap-test.properties

@@ -1,9 +1,9 @@
 #\u6307\u5b9a\u5f00\u53d1\u73af\u5883
 #spring.profiles.active=dev
 #\u670d\u52a1\u5668\u5730\u5740
-spring.cloud.nacos.config.server-addr=47.114.176.40:8848
+spring.cloud.nacos.config.server-addr=43.137.4.92:8848
 #\u9ed8\u8ba4\u4e3aPublic\u547d\u540d\u7a7a\u95f4,\u53ef\u4ee5\u7701\u7565\u4e0d\u5199
-spring.cloud.nacos.config.namespace=46f06363-b9d6-46f0-9cd7-7b33dcf26bb0
+spring.cloud.nacos.config.namespace=414816a2-0087-48ac-b50b-375d61cf1cd5
 #\u6307\u5b9a\u914d\u7f6e\u7fa4\u7ec4 --\u5982\u679c\u662fPublic\u547d\u540d\u7a7a\u95f4 \u5219\u53ef\u4ee5\u7701\u7565\u7fa4\u7ec4\u914d\u7f6e
 spring.cloud.nacos.config.group=DEFAULT_GROUP
 #\u6587\u4ef6\u540d -- \u5982\u679c\u6ca1\u6709\u914d\u7f6e\u5219\u9ed8\u8ba4\u4e3a ${spring.appliction.name}

+ 1 - 0
mec-im/pom.xml

@@ -123,6 +123,7 @@
             <plugin>
                 <groupId>com.spotify</groupId>
                 <artifactId>docker-maven-plugin</artifactId>
+                <version>1.2.2</version>
             </plugin>
         </plugins>
     </build>

+ 2 - 0
mec-im/src/main/java/com/ym/SealClassApplication.java

@@ -8,6 +8,7 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 import org.springframework.cloud.client.loadbalancer.LoadBalanced;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.EnableAspectJAutoProxy;
 import org.springframework.scheduling.annotation.EnableAsync;
@@ -19,6 +20,7 @@ import org.springframework.web.client.RestTemplate;
 @SpringBootApplication
 @EnableFeignClients("com.ym.mec")
 @MapperScan("com.ym.mec.biz.dal.dao")
+@ComponentScan(basePackages = {"com.ym", "com.mec.redisson"})
 @EnableScheduling
 @EnableDiscoveryClient
 @Configuration

+ 21 - 2
mec-im/src/main/java/com/ym/config/ResourceServerConfig.java

@@ -1,22 +1,41 @@
 package com.ym.config;
 
+import com.ym.mec.common.security.BaseAccessDeniedHandler;
+import com.ym.mec.common.security.BaseAuthenticationEntryPoint;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Configuration;
 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
 public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
+
+    @Autowired
+    private BaseAccessDeniedHandler baseAccessDeniedHandler;
+
+    @Autowired
+    private BaseAuthenticationEntryPoint baseAuthenticationEntryPoint;
+
     @Override
     public void configure(HttpSecurity http) throws Exception {
         http.authorizeRequests().antMatchers("/v2/api-docs", "/user/register",
                         "/group/join", "/group/create", "/group/quit", "/room/leave", "/room/statusSync",
-                        "/room/statusImMsg", "/group/batchDismiss", "/private/send", "/group/send",
+                        "/room/statusImMsg", "/group/batchDismiss", "/private/send", "/group/send", "/user/tencentImCallback",
                         "/group/dismiss", "/room/statusImMsg", "/history/get", "/user/statusImUser", "/liveRoom/recordSync",
                         "/liveRoom/publishRoomMsg", "/liveRoom/destroy", "/liveRoom/create", "/liveRoom/startRecord",
                         "/liveRoom/stopRecord", "/liveRoom/userExistInRoom","/liveRoom/checkOnline",
-                        "/liveRoom/addUserUnableSpeak","/liveRoom/removeUserUnableSpeak","/liveRoom/syncChatRoomStatus")
+                        "/user/tencentStreamEventCallback", "/user/tencentStreamRecordCallback", "/user/tencentStreamExceptionCallback",
+                        "/liveRoom/addUserUnableSpeak","/liveRoom/removeUserUnableSpeak","/liveRoom/syncChatRoomStatus","/liveRoom/tencentImCallback")
                 .permitAll().anyRequest().authenticated().and().csrf().disable();
     }
+
+
+    @Override
+    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
+        resources.authenticationEntryPoint(baseAuthenticationEntryPoint).accessDeniedHandler(baseAccessDeniedHandler);
+    }
+
 }

+ 6 - 0
mec-im/src/main/java/com/ym/controller/LiveRoomController.java

@@ -1,9 +1,13 @@
 package com.ym.controller;
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.ym.mec.biz.dal.enums.ETencentImCallbackCommand;
 import com.ym.mec.common.entity.ImRoomMessage;
 import com.ym.pojo.IMApiResultInfo;
 import com.ym.pojo.RecordNotify;
+import com.ym.mec.biz.dal.dto.TencentData;
+import com.ym.mec.biz.dal.dto.TencentImCallbackResult;
 import com.ym.service.LiveRoomService;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
@@ -13,6 +17,8 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.servlet.http.HttpServletRequest;
+
 /**
  * @author hgw
  * Created by 2022-02-21

+ 188 - 2
mec-im/src/main/java/com/ym/controller/UserController.java

@@ -1,18 +1,37 @@
 package com.ym.controller;
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.microsvc.toolkit.middleware.live.LivePluginContext;
+import com.microsvc.toolkit.middleware.live.LivePluginService;
+import com.microsvc.toolkit.middleware.live.impl.TencentCloudLivePlugin;
 import com.ym.common.BaseResponse;
+import com.ym.mec.biz.dal.dto.TencentData;
+import com.ym.mec.biz.dal.dto.TencentImCallbackResult;
+import com.ym.mec.biz.dal.enums.ETencentImCallbackCommand;
 import com.ym.mec.biz.service.ImLiveBroadcastRoomService;
 import com.ym.mec.common.entity.ImUserState;
+import com.ym.service.LiveRoomService;
 import com.ym.service.UserService;
 import io.rong.models.user.UserModel;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
+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.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
 
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
+import static com.ym.mec.common.controller.BaseController.succeed;
+
 @RestController
 @RequestMapping("/user")
 public class UserController {
@@ -21,6 +40,10 @@ public class UserController {
     private UserService userService;
     @Autowired
     private ImLiveBroadcastRoomService imLiveBroadcastRoomService;
+    @Autowired
+    private LiveRoomService liveRoomService;
+  @Autowired
+  private LivePluginContext livePluginContext;
 
     @RequestMapping(value = "/register", method = RequestMethod.POST)
     public Object register(@RequestBody UserModel userModel) throws Exception {
@@ -35,7 +58,7 @@ public class UserController {
     /**
      * 监听融云用户状态变更
      *
-     * @param userState
+     * @param userState List<ImUserState>
      */
     @PostMapping(value = "/statusImUser")
     public BaseResponse statusImUser(@RequestBody List<ImUserState> userState) {
@@ -43,4 +66,167 @@ public class UserController {
         imLiveBroadcastRoomService.opsRoom(userState);
         return new BaseResponse<>();
     }
+
+
+
+    /**
+     * 监听融云用户状态变更
+     *
+     * @param userState List<ImUserState>
+     */
+    @PostMapping(value = "/update/statusImUser")
+    public Object updateStatusImUser(@RequestBody List<ImUserState> userState) {
+        log.info("statusImUser >>>>> : {}", JSONObject.toJSONString(userState));
+        imLiveBroadcastRoomService.opsRoom(userState);
+        return succeed();
+    }
+
+
+
+    @PostMapping(value = "/syncLikeCount")
+    public Object syncLikeCount(String roomUid) {
+        log.info("statusImUser >>>>> : {}", JSONObject.toJSONString(roomUid));
+        imLiveBroadcastRoomService.syncLikeCount(roomUid);
+        return succeed();
+    }
+
+    @ApiOperation("腾讯im 回调接口")
+    @PostMapping(value = "/tencentImCallback")
+    public TencentImCallbackResult tencentImCallback(@RequestBody String body, HttpServletRequest request) {
+        log.info("tencentImCallback body:{}", body);
+
+      LivePluginService pluginService = livePluginContext.getPluginService(TencentCloudLivePlugin.PLUGIN_NAME);
+      String appKey = pluginService.getLiveRoomConfig().getAppKey();
+
+      log.info("tencentImCallback request param:{}", JSON.toJSONString(request.getParameterMap()));
+
+      List<String> sdkList = Arrays.asList(request.getParameterValues("SdkAppid"));
+      if (sdkList == null || sdkList.size() == 0) {
+        log.error("tencentImCallback sdkAppid is null");
+        return new TencentImCallbackResult();
+      }
+      if (!sdkList.contains(appKey)) {
+        log.error("tencentImCallback sdkAppid is not match");
+        return new TencentImCallbackResult();
+      }
+
+      String clientIP = request.getParameter("ClientIP");
+        String optPlatform = request.getParameter("OptPlatform");
+
+
+        if(request.getParameter("CallbackCommand").equals(ETencentImCallbackCommand.GROUP_CALLBACKONMEMBERSTATECHANGE.getCommand())) {
+            TencentData.CallbackOnMemberStateChange callbackOnMemberStateChange = TencentData.CallbackOnMemberStateChange.toObject(
+                body);
+
+            log.debug("callbackOnMemberStateChange: {}", callbackOnMemberStateChange);
+            callbackOnMemberStateChange.setClientIP(clientIP);
+            callbackOnMemberStateChange.setOptPlatform(optPlatform);
+            if (callbackOnMemberStateChange.getGroupId().startsWith("LIVE")) {
+                imLiveBroadcastRoomService.callbackOnMemberStateChange(callbackOnMemberStateChange);
+            }
+
+
+        } else if(request.getParameter("CallbackCommand").equals(ETencentImCallbackCommand.GROUP_CALLBACKAFTERMEMBEREXIT.getCommand())) {
+            TencentData.CallbackAfterMemberExit callbackAfterMemberExit = TencentData.CallbackAfterMemberExit.toObject(
+                body);
+
+            log.debug("callbackAfterMemberExit: {}", callbackAfterMemberExit);
+            callbackAfterMemberExit.setClientIP(clientIP);
+            callbackAfterMemberExit.setOptPlatform(optPlatform);
+
+            if (callbackAfterMemberExit.getGroupId().startsWith("LIVE")) {
+                imLiveBroadcastRoomService.callbackAfterMemberExit(callbackAfterMemberExit);
+            }
+        }  else if(request.getParameter("CallbackCommand").equals(ETencentImCallbackCommand.GROUP_CALLBACKAFTERNEWMEMBERJOIN.getCommand())) {
+            TencentData.CallbackAfterNewMemberJoin callbackAfterNewMemberJoin = TencentData.CallbackAfterNewMemberJoin.toObject(
+                body);
+
+            log.debug("CallbackAfterNewMemberJoin: {}", callbackAfterNewMemberJoin);
+            callbackAfterNewMemberJoin.setClientIP(clientIP);
+            callbackAfterNewMemberJoin.setOptPlatform(optPlatform);
+
+            if (callbackAfterNewMemberJoin.getGroupId().startsWith("LIVE")) {
+                imLiveBroadcastRoomService.callbackAfterNewMemberJoin(callbackAfterNewMemberJoin);
+            }
+        }
+
+
+        return new TencentImCallbackResult();
+    }
+
+
+    @ApiOperation("腾讯云直播-推流 回调接口")
+    @PostMapping(value = "/tencentStreamEventCallback")
+    public TencentData.StreamEventCallbackResult tencentStreamEventCallback(@RequestBody String body) {
+
+        log.info("tencentStreamEventCallback body:{}", body);
+
+        TencentData.CallbackStreamStateEvent event = TencentData.CallbackStreamStateEvent.from(body);
+
+        List<ImUserState> userState = new ArrayList<>();
+        ImUserState imUserState = new ImUserState();
+        userState.add(imUserState);
+        imUserState.setUserid(getSpeakerId(event.getStreamId()).toString());
+        // 断流事件通知
+        if (event.getEventType() == 0) {
+
+            // 更新推流时长
+            if (StringUtils.isNotBlank(event.getPushDuration()) && event.getPushDuration().matches("\\d+")) {
+                // 更新直播推流时长
+                imLiveBroadcastRoomService.updateLiveRoomPushStreamTime(event);
+            }
+            imUserState.setStatus("3");
+
+            // 自动关闭录制
+            imLiveBroadcastRoomService.closeLive(getRoomUid(event.getStreamId()), getSpeakerId(event.getStreamId()),event.getSequence());
+
+            // 同步点赞数
+            imLiveBroadcastRoomService.syncLikeCount(getRoomUid(event.getStreamId()));
+        }
+
+        // 推流事件通知
+        if (event.getEventType() == 1) {
+            // 自动开启录制
+            imLiveBroadcastRoomService.startLive(getRoomUid(event.getStreamId()), getSpeakerId(event.getStreamId()), null,event.getSequence());
+
+            imUserState.setStatus("0");
+        }
+
+        // imLiveBroadcastRoomService.opsRoom(userState);
+        return TencentData.StreamEventCallbackResult.builder().code(0).build();
+    }
+
+    private Integer getSpeakerId(String streamId) {
+        return Integer.parseInt(streamId.split("_")[1]);
+    }
+
+    private String getRoomUid(String streamId) {
+        return streamId.split("_")[0];
+    }
+
+    @ApiOperation("腾讯云直播-录制 回调接口")
+    @PostMapping(value = "/tencentStreamRecordCallback")
+    public TencentData.StreamEventCallbackResult tencentStreamRecordCallback(@RequestBody String body) {
+
+        log.info("tencentStreamRecordCallback body:{}", body);
+
+        TencentData.CallbackSteamRecordEvent event = TencentData.CallbackSteamRecordEvent.from(body);
+
+        log.info("taskId={}, url={}", event.getTaskId(), event.getVideoUrl());
+
+        // 生成直播录制信息
+        liveRoomService.createLiveRoomVideoRecord(event);
+
+        return TencentData.StreamEventCallbackResult.builder().code(0).build();
+    }
+
+    @ApiOperation("腾讯云直播-推流异常 回调接口")
+    @PostMapping(value = "/tencentStreamExceptionCallback")
+    public TencentData.StreamEventCallbackResult tencentStreamExceptionCallback(@RequestBody String body) {
+
+        log.info("tencentStreamExceptionCallback body:{}", body);
+
+        return TencentData.StreamEventCallbackResult.builder().code(0).build();
+    }
+
 }

+ 24 - 1
mec-im/src/main/java/com/ym/service/Impl/LiveRoomServiceImpl.java

@@ -3,13 +3,13 @@ package com.ym.service.Impl;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.ym.http.HttpHelper;
+import com.ym.mec.biz.dal.dto.TencentData;
 import com.ym.mec.biz.dal.entity.ImLiveRoomVideo;
 import com.ym.mec.biz.service.ImLiveRoomVideoService;
 import com.ym.mec.common.entity.ImRoomMessage;
 import com.ym.mec.common.exception.BizException;
 import com.ym.mec.im.IMHelper;
 import com.ym.mec.thirdparty.storage.StoragePluginContext;
-import com.ym.mec.thirdparty.storage.provider.KS3StoragePlugin;
 import com.ym.pojo.IMApiResultInfo;
 import com.ym.pojo.IMUserOnlineInfo;
 import com.ym.pojo.RecordConfig;
@@ -17,6 +17,7 @@ import com.ym.pojo.RecordNotify;
 import com.ym.service.LiveRoomService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.StringUtils;
+import org.joda.time.DateTime;
 import org.redisson.api.RBucket;
 import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -319,4 +320,26 @@ public class LiveRoomServiceImpl implements LiveRoomService {
         return sessionId;
     }
 
+    /**
+     * 生成直播录制信息
+     *
+     * @param event TencentData.CallbackSteamRecordEvent
+     */
+    @Override
+    public void createLiveRoomVideoRecord(TencentData.CallbackSteamRecordEvent event) {
+
+        // 直播间ROOM_UID
+        String roomId = event.getStreamId().split("_")[0];
+
+        // 录制开始时间
+        long startTime =  (event.getEndTime() - event.getDuration()) * 1000L;
+        //保存切片
+        ImLiveRoomVideo imLiveRoomVideo = initImLiveRoomVideo(roomId, event.getTaskId(), DateTime.now().toDate());
+        imLiveRoomVideo.setStartTime(new DateTime(startTime).toDate());
+        imLiveRoomVideo.setEndTime(new DateTime(event.getEndTime() * 1000L).toDate());
+        imLiveRoomVideo.setUrl(event.getVideoUrl());
+        imLiveRoomVideo.setType(2);
+
+        imLiveRoomVideoService.save(imLiveRoomVideo);
+    }
 }

+ 7 - 0
mec-im/src/main/java/com/ym/service/LiveRoomService.java

@@ -1,5 +1,6 @@
 package com.ym.service;
 
+import com.ym.mec.biz.dal.dto.TencentData;
 import com.ym.mec.common.entity.ImRoomMessage;
 import com.ym.pojo.IMApiResultInfo;
 import com.ym.pojo.RecordNotify;
@@ -62,4 +63,10 @@ public interface LiveRoomService {
      * @param userId  用户id
      */
     boolean removeUserUnableSpeak(String roomUid, String userId);
+
+    /**
+     * 生成直播录制信息
+     * @param event TencentData.CallbackSteamRecordEvent
+     */
+    void createLiveRoomVideoRecord(TencentData.CallbackSteamRecordEvent event);
 }

+ 2 - 2
mec-im/src/main/resources/bootstrap-test.properties

@@ -1,9 +1,9 @@
 #\u6307\u5b9a\u5f00\u53d1\u73af\u5883
 #spring.profiles.active=dev
 #\u670d\u52a1\u5668\u5730\u5740
-spring.cloud.nacos.config.server-addr=47.114.176.40:8848
+spring.cloud.nacos.config.server-addr=43.137.4.92:8848
 #\u9ed8\u8ba4\u4e3aPublic\u547d\u540d\u7a7a\u95f4,\u53ef\u4ee5\u7701\u7565\u4e0d\u5199
-spring.cloud.nacos.config.namespace=46f06363-b9d6-46f0-9cd7-7b33dcf26bb0
+spring.cloud.nacos.config.namespace=414816a2-0087-48ac-b50b-375d61cf1cd5
 #\u6307\u5b9a\u914d\u7f6e\u7fa4\u7ec4 --\u5982\u679c\u662fPublic\u547d\u540d\u7a7a\u95f4 \u5219\u53ef\u4ee5\u7701\u7565\u7fa4\u7ec4\u914d\u7f6e
 spring.cloud.nacos.config.group=DEFAULT_GROUP
 #\u6587\u4ef6\u540d -- \u5982\u679c\u6ca1\u6709\u914d\u7f6e\u5219\u9ed8\u8ba4\u4e3a ${spring.appliction.name}

+ 9 - 2
mec-im/src/main/resources/logback-spring.xml

@@ -29,16 +29,23 @@
 
     <logger name="com.ym.mec" level="INFO" />
 
+    <!--本地环境:打印控制台 -->
+    <springProfile name="local">
+        <root level="DEBUG">
+            <appender-ref ref="stdout" />
+            <appender-ref ref="file" />
+        </root>
+    </springProfile>
     <!--开发环境:打印控制台 -->
     <springProfile name="dev">
-        <root level="INFO">
+        <root level="DEBUG">
             <appender-ref ref="stdout" />
             <appender-ref ref="file" />
         </root>
     </springProfile>
 
     <springProfile name="test">
-        <root level="INFO">
+        <root level="DEBUG">
             <appender-ref ref="stdout" />
             <appender-ref ref="file" />
         </root>

+ 2 - 2
mec-mall/mall-admin/src/main/resources/bootstrap-test.properties

@@ -1,9 +1,9 @@
 #\u6307\u5b9a\u5f00\u53d1\u73af\u5883
 #spring.profiles.active=dev
 #\u670d\u52a1\u5668\u5730\u5740
-spring.cloud.nacos.config.server-addr=47.114.176.40:8848
+spring.cloud.nacos.config.server-addr=43.137.4.92:8848
 #\u9ed8\u8ba4\u4e3aPublic\u547d\u540d\u7a7a\u95f4,\u53ef\u4ee5\u7701\u7565\u4e0d\u5199
-spring.cloud.nacos.config.namespace=46f06363-b9d6-46f0-9cd7-7b33dcf26bb0
+spring.cloud.nacos.config.namespace=414816a2-0087-48ac-b50b-375d61cf1cd5
 #\u6307\u5b9a\u914d\u7f6e\u7fa4\u7ec4 --\u5982\u679c\u662fPublic\u547d\u540d\u7a7a\u95f4 \u5219\u53ef\u4ee5\u7701\u7565\u7fa4\u7ec4\u914d\u7f6e
 spring.cloud.nacos.config.group=DEFAULT_GROUP
 #\u6587\u4ef6\u540d -- \u5982\u679c\u6ca1\u6709\u914d\u7f6e\u5219\u9ed8\u8ba4\u4e3a ${spring.appliction.name}

+ 2 - 2
mec-mall/mall-portal/src/main/resources/bootstrap-test.properties

@@ -1,9 +1,9 @@
 #\u6307\u5b9a\u5f00\u53d1\u73af\u5883
 #spring.profiles.active=dev
 #\u670d\u52a1\u5668\u5730\u5740
-spring.cloud.nacos.config.server-addr=47.114.176.40:8848
+spring.cloud.nacos.config.server-addr=43.137.4.92:8848
 #\u9ed8\u8ba4\u4e3aPublic\u547d\u540d\u7a7a\u95f4,\u53ef\u4ee5\u7701\u7565\u4e0d\u5199
-spring.cloud.nacos.config.namespace=46f06363-b9d6-46f0-9cd7-7b33dcf26bb0
+spring.cloud.nacos.config.namespace=414816a2-0087-48ac-b50b-375d61cf1cd5
 #\u6307\u5b9a\u914d\u7f6e\u7fa4\u7ec4 --\u5982\u679c\u662fPublic\u547d\u540d\u7a7a\u95f4 \u5219\u53ef\u4ee5\u7701\u7565\u7fa4\u7ec4\u914d\u7f6e
 spring.cloud.nacos.config.group=DEFAULT_GROUP
 #\u6587\u4ef6\u540d -- \u5982\u679c\u6ca1\u6709\u914d\u7f6e\u5219\u9ed8\u8ba4\u4e3a ${spring.appliction.name}

+ 1 - 0
mec-monitor/pom.xml

@@ -40,6 +40,7 @@
 			<plugin>
 				<groupId>com.spotify</groupId>
 				<artifactId>docker-maven-plugin</artifactId>
+				<version>1.2.2</version>
 			</plugin>
 		</plugins>
 	</build>

+ 2 - 2
mec-monitor/src/main/resources/bootstrap-test.properties

@@ -1,9 +1,9 @@
 #\u6307\u5b9a\u5f00\u53d1\u73af\u5883
 #spring.profiles.active=dev
 #\u670d\u52a1\u5668\u5730\u5740
-spring.cloud.nacos.config.server-addr=47.114.176.40:8848
+spring.cloud.nacos.config.server-addr=43.137.4.92:8848
 #\u9ed8\u8ba4\u4e3aPublic\u547d\u540d\u7a7a\u95f4,\u53ef\u4ee5\u7701\u7565\u4e0d\u5199
-spring.cloud.nacos.config.namespace=02105743-16b8-46ab-87df-2aca0f3dbca3
+spring.cloud.nacos.config.namespace=414816a2-0087-48ac-b50b-375d61cf1cd5
 #\u6307\u5b9a\u914d\u7f6e\u7fa4\u7ec4 --\u5982\u679c\u662fPublic\u547d\u540d\u7a7a\u95f4 \u5219\u53ef\u4ee5\u7701\u7565\u7fa4\u7ec4\u914d\u7f6e
 spring.cloud.nacos.config.group=DEFAULT_GROUP
 #\u6587\u4ef6\u540d -- \u5982\u679c\u6ca1\u6709\u914d\u7f6e\u5219\u9ed8\u8ba4\u4e3a ${spring.appliction.name}

+ 1 - 0
mec-student/pom.xml

@@ -77,6 +77,7 @@
 			<plugin>
 				<groupId>com.spotify</groupId>
 				<artifactId>docker-maven-plugin</artifactId>
+				<version>1.2.2</version>
 			</plugin>
 		</plugins>
 	</build>

+ 1 - 1
mec-student/src/main/java/com/ym/mec/student/StudentApplication.java

@@ -22,7 +22,7 @@ import com.ym.mec.common.filters.EmojiEncodingFilter;
 @EnableDiscoveryClient
 @EnableFeignClients("com.ym.mec")
 @MapperScan(basePackages = {"com.ym.mec.biz.**.dao", "com.yonge.datasource.dao"})
-@ComponentScan(basePackages = {"com.ym.mec", "com.yonge.log", "com.yonge.datasource"})
+@ComponentScan(basePackages = {"com.ym.mec", "com.yonge.log", "com.mec.redisson", "com.yonge.datasource"})
 @Configuration
 @EnableSwagger2Doc
 @EnableAsync

+ 8 - 0
mec-student/src/main/java/com/ym/mec/student/controller/ImLiveBroadcastRoomController.java

@@ -61,5 +61,13 @@ public class ImLiveBroadcastRoomController extends BaseController {
         return succeed();
     }
 
+    @ApiOperation("设置连麦状态")
+    @PutMapping("/userWhetherMic")
+    public HttpResponseResult<Object> userWhetherMic(@ApiParam(value = "房间uid", required = true) String roomUid,
+                                                     @ApiParam(value = "用户id", required = true) Long userId,
+                                                     @ApiParam(value = "连麦状态 0:未申请1:申请连麦中2:连麦中", required = true) Integer whetherMicStatus) {
+        imLiveBroadcastRoomService.userWhetherMic(roomUid,userId,whetherMicStatus);
+        return succeed();
+    }
 }
 

+ 32 - 0
mec-student/src/main/java/com/ym/mec/student/controller/StudentImLiveRoomVideoController.java

@@ -0,0 +1,32 @@
+package com.ym.mec.student.controller;
+
+import com.ym.mec.biz.dal.vo.ImLiveRoomVideoVo;
+import com.ym.mec.biz.service.ImLiveRoomVideoService;
+import com.ym.mec.common.controller.BaseController;
+import com.ym.mec.common.entity.HttpResponseResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Api(tags = "直播回放录像记录表")
+@RestController
+@RequestMapping("/imLiveRoomVideo")
+public class StudentImLiveRoomVideoController extends BaseController {
+
+    /**
+     * 服务对象
+     */
+    @Resource
+    private ImLiveRoomVideoService imLiveRoomVideoService;
+
+    @ApiOperation("查询该机构目前推广的直播间")
+    @GetMapping(value = "/queryList")
+    public HttpResponseResult<List<ImLiveRoomVideoVo>> queryList(String roomUid) {
+        return succeed(imLiveRoomVideoService.queryList(roomUid));
+    }
+}

+ 2 - 2
mec-student/src/main/resources/bootstrap-test.properties

@@ -1,9 +1,9 @@
 #\u6307\u5b9a\u5f00\u53d1\u73af\u5883
 #spring.profiles.active=dev
 #\u670d\u52a1\u5668\u5730\u5740
-spring.cloud.nacos.config.server-addr=47.114.176.40:8848
+spring.cloud.nacos.config.server-addr=43.137.4.92:8848
 #\u9ed8\u8ba4\u4e3aPublic\u547d\u540d\u7a7a\u95f4,\u53ef\u4ee5\u7701\u7565\u4e0d\u5199
-spring.cloud.nacos.config.namespace=46f06363-b9d6-46f0-9cd7-7b33dcf26bb0
+spring.cloud.nacos.config.namespace=414816a2-0087-48ac-b50b-375d61cf1cd5
 #\u6307\u5b9a\u914d\u7f6e\u7fa4\u7ec4 --\u5982\u679c\u662fPublic\u547d\u540d\u7a7a\u95f4 \u5219\u53ef\u4ee5\u7701\u7565\u7fa4\u7ec4\u914d\u7f6e
 spring.cloud.nacos.config.group=DEFAULT_GROUP
 #\u6587\u4ef6\u540d -- \u5982\u679c\u6ca1\u6709\u914d\u7f6e\u5219\u9ed8\u8ba4\u4e3a ${spring.appliction.name}

+ 4 - 12
mec-student/src/main/resources/logback-spring.xml

@@ -52,15 +52,7 @@
 
 	<!--本地环境:打印控制台 -->
 	<springProfile name="local">
-		<root level="INFO">
-			<appender-ref ref="stdout" />
-			<appender-ref ref="file" />
-		</root>
-	</springProfile>
-
-	<!--本地环境:打印控制台 -->
-	<springProfile name="local">
-		<root level="INFO">
+		<root level="DEBUG">
 			<appender-ref ref="stdout" />
 			<appender-ref ref="file" />
 		</root>
@@ -68,21 +60,21 @@
 
 	<!--开发环境:打印控制台 -->
 	<springProfile name="dev">
-		<root level="INFO">
+		<root level="DEBUG">
 			<appender-ref ref="stdout" />
 			<appender-ref ref="file" />
 		</root>
 	</springProfile>
 
 	<springProfile name="test">
-		<root level="INFO">
+		<root level="DEBUG">
 			<appender-ref ref="stdout" />
 			<appender-ref ref="file" />
 		</root>
 	</springProfile>
 
 	<springProfile name="dev_server">
-		<root level="INFO">
+		<root level="DEBUG">
 			<appender-ref ref="stdout" />
 			<appender-ref ref="file" />
 		</root>

+ 1 - 0
mec-task/pom.xml

@@ -81,6 +81,7 @@
 			<plugin>
 				<groupId>com.spotify</groupId>
 				<artifactId>docker-maven-plugin</artifactId>
+				<version>1.2.2</version>
 			</plugin>
 		</plugins>
 	</build>

+ 24 - 0
mec-task/src/main/java/com/ym/mec/task/jobs/DestroyLiveRoomTask.java

@@ -0,0 +1,24 @@
+package com.ym.mec.task.jobs;
+
+import com.ym.mec.task.TaskRemoteService;
+import com.ym.mec.task.core.BaseTask;
+import com.ym.mec.task.core.TaskException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author hgw
+ * Created by 2022-03-04
+ */
+@Service
+public class DestroyLiveRoomTask extends BaseTask {
+
+    @Autowired
+    private TaskRemoteService taskRemoteService;
+
+    @Override
+    public void execute() throws TaskException {
+        taskRemoteService.destroyLiveRoom();
+    }
+
+}

+ 2 - 2
mec-task/src/main/resources/bootstrap-test.properties

@@ -1,9 +1,9 @@
 #\u6307\u5b9a\u5f00\u53d1\u73af\u5883
 #spring.profiles.active=dev
 #\u670d\u52a1\u5668\u5730\u5740
-spring.cloud.nacos.config.server-addr=47.114.176.40:8848
+spring.cloud.nacos.config.server-addr=43.137.4.92:8848
 #\u9ed8\u8ba4\u4e3aPublic\u547d\u540d\u7a7a\u95f4,\u53ef\u4ee5\u7701\u7565\u4e0d\u5199
-spring.cloud.nacos.config.namespace=46f06363-b9d6-46f0-9cd7-7b33dcf26bb0
+spring.cloud.nacos.config.namespace=414816a2-0087-48ac-b50b-375d61cf1cd5
 #\u6307\u5b9a\u914d\u7f6e\u7fa4\u7ec4 --\u5982\u679c\u662fPublic\u547d\u540d\u7a7a\u95f4 \u5219\u53ef\u4ee5\u7701\u7565\u7fa4\u7ec4\u914d\u7f6e
 spring.cloud.nacos.config.group=DEFAULT_GROUP
 #\u6587\u4ef6\u540d -- \u5982\u679c\u6ca1\u6709\u914d\u7f6e\u5219\u9ed8\u8ba4\u4e3a ${spring.appliction.name}

+ 5 - 0
mec-teacher/pom.xml

@@ -65,6 +65,10 @@
 			<artifactId>easy-captcha</artifactId>
 			<version>1.6.2</version>
 		</dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
     </dependencies>
 	<build>
 		<plugins>
@@ -75,6 +79,7 @@
 			<plugin>
 				<groupId>com.spotify</groupId>
 				<artifactId>docker-maven-plugin</artifactId>
+				<version>1.2.2</version>
 			</plugin>
 		</plugins>
 	</build>

+ 1 - 1
mec-teacher/src/main/java/com/ym/mec/teacher/TeacherApplication.java

@@ -22,7 +22,7 @@ import com.ym.mec.common.filters.EmojiEncodingFilter;
 @EnableDiscoveryClient
 @EnableFeignClients("com.ym.mec")
 @MapperScan(basePackages = {"com.ym.mec.biz.**.dao", "com.yonge.datasource.dao"})
-@ComponentScan(basePackages = { "com.ym.mec", "org.snaker.engine", "com.yonge.log", "com.yonge.datasource"})
+@ComponentScan(basePackages = { "com.ym.mec", "org.snaker.engine", "com.yonge.log", "com.mec.redisson", "com.yonge.datasource"})
 @Configuration
 @EnableSwagger2Doc
 @EnableAsync

+ 68 - 6
mec-teacher/src/main/java/com/ym/mec/teacher/controller/TeacherImLiveBroadcastRoomController.java

@@ -1,18 +1,32 @@
 package com.ym.mec.teacher.controller;
 
+import com.ym.mec.biz.dal.dto.LiveRoomStatus;
 import com.ym.mec.biz.dal.dto.RoomReservationUserSearch;
 import com.ym.mec.biz.dal.page.LiveRoomGoodsOrderQueryInfo;
 import com.ym.mec.biz.dal.vo.BaseRoomUserVo;
+import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomMemberVo;
 import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomVo;
 import com.ym.mec.biz.dal.vo.LiveRoomGoodsOrderVo;
 import com.ym.mec.biz.dal.vo.RoomReservationUserVo;
+import com.ym.mec.biz.service.ImLiveBroadcastRoomMemberService;
 import com.ym.mec.biz.service.ImLiveBroadcastRoomService;
 import com.ym.mec.common.controller.BaseController;
 import com.ym.mec.common.entity.HttpResponseResult;
-import com.ym.mec.common.entity.ImUserState;
 import com.ym.mec.common.page.PageInfo;
-import io.swagger.annotations.*;
-import org.springframework.web.bind.annotation.*;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
@@ -35,6 +49,8 @@ public class TeacherImLiveBroadcastRoomController extends BaseController {
      */
     @Resource
     private ImLiveBroadcastRoomService imLiveBroadcastRoomService;
+    @Autowired
+    private ImLiveBroadcastRoomMemberService imLiveBroadcastRoomMemberService;
 
     @ApiImplicitParams({
             @ApiImplicitParam(name = "search", dataType = "String", value = "模糊查询关键字"),
@@ -43,6 +59,8 @@ public class TeacherImLiveBroadcastRoomController extends BaseController {
             @ApiImplicitParam(name = "endTime", dataType = "String", value = "结束时间"),
             @ApiImplicitParam(name = "popularize", dataType = "Integer", value = "是否在首页推广 0否 1是"),
             @ApiImplicitParam(name = "speakerId", dataType = "Integer", value = "老师ID"),
+            @ApiImplicitParam(name = "clientType", dataType = "String", value = "用户类型 TEACHER 老师 EDUCATION 教务端"),
+            @ApiImplicitParam(name = "sort", dataType = "String", value = "不传是默认web端排序  1:直播中--未开始--已结束(状态相同时,根据直播时间倒序)"),
             @ApiImplicitParam(name = "page", dataType = "Integer", value = "页数"),
             @ApiImplicitParam(name = "rows", dataType = "Integer", value = "每页数量"),
     })
@@ -67,10 +85,23 @@ public class TeacherImLiveBroadcastRoomController extends BaseController {
     }
 
     @ApiOperation("查询房间信息并校验房间是否合规")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "roomUid", dataType = "String", value = "房间uid", required = true),
+            @ApiImplicitParam(name = "userId", dataType = "Integer", value = "用户id", required = true),
+            @ApiImplicitParam(name = "liveAssistant", dataType = "Boolean", value = "直播助手"),
+    })
     @GetMapping("/queryRoom")
     public HttpResponseResult<ImLiveBroadcastRoomVo> queryRoomAndCheck(@ApiParam(value = "房间uid", required = true) String roomUid,
-                                                                       @ApiParam(value = "用户id", required = true) Integer userId) {
-        return succeed(imLiveBroadcastRoomService.queryRoomAndCheck(roomUid, userId, 2));
+                                                                       @ApiParam(value = "用户id", required = true) Integer userId,
+                                                                       @RequestParam(defaultValue = "false") Boolean liveAssistant) {
+
+        // 请求来源业源
+        int osType = 2; // 老师端
+        if (Optional.ofNullable(liveAssistant).orElse(false)) {
+            osType = 3; // 直播助手
+        }
+
+        return succeed(imLiveBroadcastRoomService.queryRoomAndCheck(roomUid, userId, osType));
     }
 
     @ApiOperation("关闭直播间")
@@ -88,7 +119,7 @@ public class TeacherImLiveBroadcastRoomController extends BaseController {
         return succeed();
     }
 
-    @ApiOperation("开启/关闭直播的录像")
+    @ApiOperation("开启/关闭直播的录像-融云使用")
     @GetMapping("/opsLiveVideo")
     public HttpResponseResult<Object> opsLiveVideo(@ApiParam(value = "房间uid", required = true) String roomUid,
                                                    @ApiParam(value = "用户id", required = true) Integer userId,
@@ -132,10 +163,41 @@ public class TeacherImLiveBroadcastRoomController extends BaseController {
         return succeed();
     }
 
+
+    @ApiOperation("设置连麦状态")
+    @PutMapping("/userWhetherMic")
+    public HttpResponseResult<Object> userWhetherMic(@ApiParam(value = "房间uid", required = true) String roomUid,
+                                                 @ApiParam(value = "用户id", required = true) Long userId,
+                                                 @ApiParam(value = "连麦状态 0:未申请1:申请连麦中2:连麦中", required = true) Integer whetherMicStatus) {
+        imLiveBroadcastRoomService.userWhetherMic(roomUid,userId,whetherMicStatus);
+        return succeed();
+    }
+
     @ApiOperation("查询直播间商品订单列表")
     @GetMapping("/queryLiveRoomGoodsOrderList")
     public HttpResponseResult<PageInfo<LiveRoomGoodsOrderVo>> queryLiveRoomGoodsOrderList(LiveRoomGoodsOrderQueryInfo queryInfo) {
         return succeed(imLiveBroadcastRoomService.queryLiveRoomGoodsOrderList(queryInfo));
     }
+
+    @ApiOperation("分页查询直播间人员列表")
+    @ApiImplicitParams({
+      @ApiImplicitParam(name = "search", dataType = "String", value = "模糊搜索 学员编号姓名"),
+      @ApiImplicitParam(name = "roomUid", dataType = "String", value = "房间uid"),
+      @ApiImplicitParam(name = "onlineStatus", dataType = "String ", value = "0:离线 1:在线  不传是全部"),
+      @ApiImplicitParam(name = "whetherMicStatus", dataType = "String", value = "连麦状态 0:未申请1:申请连麦中2:连麦中"),
+      @ApiImplicitParam(name = "page", dataType = "Integer", value = "页数"),
+      @ApiImplicitParam(name = "rows", dataType = "Integer", value = "每页数量"),
+    })
+    @PostMapping("/queryRoomMember")
+    public HttpResponseResult<PageInfo<ImLiveBroadcastRoomMemberVo>> queryRoomMember(@RequestBody Map<String, Object> param) {
+        return succeed(imLiveBroadcastRoomMemberService.queryRoomMember(param));
+    }
+
+
+    @ApiOperation("更新直播间状态")
+    @PostMapping("/updateRoomStatus")
+    public HttpResponseResult<Boolean> updateRoomStatus(@RequestBody @Valid LiveRoomStatus status ) {
+        return succeed(imLiveBroadcastRoomService.updateRoomStatus(status));
+    }
 }
 

+ 61 - 0
mec-teacher/src/main/java/com/ym/mec/teacher/controller/TeacherImLiveBroadcastRoomMemberController.java

@@ -0,0 +1,61 @@
+package com.ym.mec.teacher.controller;
+
+import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomDetailVo;
+import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomMemberVo;
+import com.ym.mec.biz.service.ImLiveBroadcastRoomMemberService;
+import com.ym.mec.common.controller.BaseController;
+import com.ym.mec.common.entity.HttpResponseResult;
+import com.ym.mec.common.page.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+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.Map;
+
+/**
+ * 直播间人员关系表(ImLiveBroadcastRoomMember)表控制层
+ *
+ * @author hgw
+ * @since 2022-02-21 14:26:58
+ */
+@Api(tags = "直播间人员关系表")
+@RestController
+@RequestMapping("/imLiveBroadcastRoomMember")
+public class TeacherImLiveBroadcastRoomMemberController extends BaseController {
+    /**
+     * 服务对象
+     */
+    @Resource
+    private ImLiveBroadcastRoomMemberService imLiveBroadcastRoomMemberService;
+
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "roomUid", dataType = "String", value = "房间uid")
+    })
+    @ApiOperation("直播间详情")
+    @PostMapping("/queryRoomDetail")
+    public HttpResponseResult<ImLiveBroadcastRoomDetailVo> queryRoomDetail(@RequestBody Map<String, Object> param) {
+        return succeed(imLiveBroadcastRoomMemberService.queryRoomDetail(param));
+    }
+
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "search", dataType = "String", value = "模糊搜索 学员编号姓名"),
+            @ApiImplicitParam(name = "roomUid", dataType = "String", value = "房间uid"),
+            @ApiImplicitParam(name = "onlineStatus", dataType = "String ", value = "0:离线 1:在线  不传是全部"),
+            @ApiImplicitParam(name = "whetherMicStatus", dataType = "String", value = "连麦状态 0:未申请1:申请连麦中2:连麦中"),
+            @ApiImplicitParam(name = "page", dataType = "Integer", value = "页数"),
+            @ApiImplicitParam(name = "rows", dataType = "Integer", value = "每页数量"),
+    })
+    @ApiOperation("分页查询直播间人员列表")
+    @PostMapping("/queryRoomMember")
+    public HttpResponseResult<PageInfo<ImLiveBroadcastRoomMemberVo>> queryRoomMember(@RequestBody Map<String, Object> param) {
+        return succeed(imLiveBroadcastRoomMemberService.queryRoomMember(param));
+    }
+
+}
+

+ 2 - 2
mec-teacher/src/main/resources/bootstrap-test.properties

@@ -1,9 +1,9 @@
 #\u6307\u5b9a\u5f00\u53d1\u73af\u5883
 #spring.profiles.active=dev
 #\u670d\u52a1\u5668\u5730\u5740
-spring.cloud.nacos.config.server-addr=47.114.176.40:8848
+spring.cloud.nacos.config.server-addr=43.137.4.92:8848
 #\u9ed8\u8ba4\u4e3aPublic\u547d\u540d\u7a7a\u95f4,\u53ef\u4ee5\u7701\u7565\u4e0d\u5199
-spring.cloud.nacos.config.namespace=46f06363-b9d6-46f0-9cd7-7b33dcf26bb0
+spring.cloud.nacos.config.namespace=414816a2-0087-48ac-b50b-375d61cf1cd5
 #\u6307\u5b9a\u914d\u7f6e\u7fa4\u7ec4 --\u5982\u679c\u662fPublic\u547d\u540d\u7a7a\u95f4 \u5219\u53ef\u4ee5\u7701\u7565\u7fa4\u7ec4\u914d\u7f6e
 spring.cloud.nacos.config.group=DEFAULT_GROUP
 #\u6587\u4ef6\u540d -- \u5982\u679c\u6ca1\u6709\u914d\u7f6e\u5219\u9ed8\u8ba4\u4e3a ${spring.appliction.name}

+ 3 - 3
mec-teacher/src/main/resources/logback-spring.xml

@@ -60,21 +60,21 @@
 
 	<!--开发环境:打印控制台 -->
 	<springProfile name="dev">
-		<root level="INFO">
+		<root level="DEBUG">
 			<appender-ref ref="stdout" />
 			<appender-ref ref="file" />
 		</root>
 	</springProfile>
 
 	<springProfile name="test">
-		<root level="INFO">
+		<root level="DEBUG">
 			<appender-ref ref="stdout" />
 			<appender-ref ref="file" />
 		</root>
 	</springProfile>
 
 	<springProfile name="dev_server">
-		<root level="INFO">
+		<root level="DEBUG">
 			<appender-ref ref="stdout" />
 			<appender-ref ref="file" />
 		</root>

+ 10 - 1
mec-thirdparty/src/main/java/com/ym/mec/thirdparty/storage/StoragePluginContext.java

@@ -45,7 +45,16 @@ public class StoragePluginContext {
 
 	public String getPublicUrl(String fileName,String bucketName){
 		try {
-			String substring = fileName.substring(0, fileName.lastIndexOf("?"));
+
+			// 文件地址
+			String substring = fileName;
+
+			// 访问后缀参数
+			int indexOf = fileName.lastIndexOf("?");
+			if (indexOf > -1) {
+				substring = fileName.substring(0, fileName.lastIndexOf("?"));
+			}
+
 			String substring1 = substring.substring(substring.lastIndexOf("/") + 1);
 			this.setFileAcl(KS3StoragePlugin.PLUGIN_NAME,substring1,true,bucketName);
 			return substring;

+ 5 - 5
mec-web/pom.xml

@@ -70,11 +70,10 @@
 			<groupId>com.yonge.datasource</groupId>
 			<artifactId>dynamic-datasource</artifactId>
 		</dependency>
-
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-        </dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-api</artifactId>
+		</dependency>
 	</dependencies>
 	<build>
 		<plugins>
@@ -85,6 +84,7 @@
 			<plugin>
 				<groupId>com.spotify</groupId>
 				<artifactId>docker-maven-plugin</artifactId>
+				<version>1.2.2</version>
 			</plugin>
 		</plugins>
 	</build>

Some files were not shown because too many files changed in this diff