浏览代码

Merge remote-tracking branch 'origin/online' into online

zouxuan 2 年之前
父节点
当前提交
c982a380ff
共有 99 个文件被更改,包括 2964 次插入321 次删除
  1. 1 1
      audio-analysis/src/main/java/com/yonge/audio/AudioAnalysisServerApplication.java
  2. 9 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/AdminFeignService.java
  3. 27 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/dto/UserFriendInfoVO.java
  4. 12 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/fallback/AdminFeignServiceFallback.java
  5. 1 1
      cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/dto/UserSetReq.java
  6. 26 0
      cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/config/CustomerServiceConfig.java
  7. 1 1
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/AuthServerApplication.java
  8. 6 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/provider/PhoneAuthenticationProvider.java
  9. 6 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/SysUserService.java
  10. 81 21
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/impl/SysUserServiceImpl.java
  11. 14 3
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/web/controller/UserController.java
  12. 2 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/CacheNameEnum.java
  13. 1 0
      cooleshow-mall/mall-portal/src/main/java/com/yonge/cooleshow/portal/service/impl/OmsPortalOrderServiceImpl.java
  14. 1 2
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/AdminApplication.java
  15. 21 9
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/AdminClient.java
  16. 69 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/ImUserFriendController.java
  17. 52 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/io/request/im/IMNotifyMessageVO.java
  18. 32 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/io/request/im/UserFriendInfoVO.java
  19. 15 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/task/TaskController.java
  20. 6 0
      cooleshow-user/user-biz/pom.xml
  21. 9 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/ActivityEvaluationDao.java
  22. 37 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/ActivityPlanDao.java
  23. 4 3
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/MusicAlbumDao.java
  24. 4 4
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/MusicSheetDao.java
  25. 10 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/UserFirstTimeDao.java
  26. 79 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/req/TeacherMusicSheetAuditReq.java
  27. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/ActivityRegistrationSearch.java
  28. 23 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/MusicAlbumDetailSearch.java
  29. 10 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/StudentMusicSheetSearch.java
  30. 43 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/UserFirstTimeSearch.java
  31. 24 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ActivityEvaluationRecord.java
  32. 25 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ActivityPlan.java
  33. 13 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/AlbumFavorite.java
  34. 13 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/MusicFavorite.java
  35. 56 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/MusicSheet.java
  36. 19 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/ClientEnum.java
  37. 63 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/EQueryOp.java
  38. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/MK.java
  39. 34 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/activity/ActivityRankingMethodEnum.java
  40. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/activity/ActivityRankingRuleEnum.java
  41. 8 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/CouponIssueMapper.java
  42. 3 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/queryInfo/CouponInfoQuery.java
  43. 5 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/AlbumFavoriteService.java
  44. 17 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImUserFriendService.java
  45. 9 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/LiveRoomService.java
  46. 9 4
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/MusicAlbumService.java
  47. 3 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/MusicFavoriteService.java
  48. 9 6
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/MusicSheetService.java
  49. 199 19
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ActivityEvaluationRecordServiceImpl.java
  50. 77 10
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ActivityEvaluationServiceImpl.java
  51. 93 28
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ActivityPlanEvaluationServiceImpl.java
  52. 268 45
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ActivityPlanServiceImpl.java
  53. 76 14
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ActivityPlanStandardServiceImpl.java
  54. 59 11
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ActivityRegistrationServiceImpl.java
  55. 5 3
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ActivityRewardServiceImpl.java
  56. 9 5
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/AlbumFavoriteServiceImpl.java
  57. 18 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CouponIssueServiceImp.java
  58. 1 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseScheduleServiceImpl.java
  59. 196 5
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImUserFriendServiceImpl.java
  60. 41 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/LiveRoomServiceImpl.java
  61. 11 9
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/MusicAlbumServiceImpl.java
  62. 3 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/MusicFavoriteServiceImpl.java
  63. 31 11
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/MusicSheetServiceImpl.java
  64. 5 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TeacherServiceImpl.java
  65. 4 4
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserFirstTimeServiceImpl.java
  66. 17 10
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserOrderServiceImpl.java
  67. 3 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserWithdrawalServiceImpl.java
  68. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/ActivityEvaluationVo.java
  69. 70 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/ActivityMusicVo.java
  70. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/ActivityPlanVo.java
  71. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/ActivityRankingVo.java
  72. 38 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/ActivityRegistrationVo.java
  73. 15 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/CourseStudent.java
  74. 79 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/MusicActivityVo.java
  75. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/StatGroupWrapper.java
  76. 39 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/im/CustomerService.java
  77. 77 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/liveroom/LiveRoomWrapper.java
  78. 29 11
      cooleshow-user/user-biz/src/main/resources/config/mybatis/ActivityEvaluationMapper.xml
  79. 77 4
      cooleshow-user/user-biz/src/main/resources/config/mybatis/ActivityPlanMapper.xml
  80. 3 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/ActivityRegistrationMapper.xml
  81. 15 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/CouponIssueMapper.xml
  82. 6 2
      cooleshow-user/user-biz/src/main/resources/config/mybatis/CourseScheduleMapper.xml
  83. 4 1
      cooleshow-user/user-biz/src/main/resources/config/mybatis/MusicAlbumMapper.xml
  84. 10 3
      cooleshow-user/user-biz/src/main/resources/config/mybatis/MusicSheetMapper.xml
  85. 35 1
      cooleshow-user/user-biz/src/main/resources/config/mybatis/UserFirstTimeMapper.xml
  86. 12 6
      cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/MusicAlbumController.java
  87. 12 5
      cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/MusicSheetController.java
  88. 26 0
      cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/open/OpenClient.java
  89. 90 0
      cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/io/request/LiveRoomVO.java
  90. 16 8
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/MusicAlbumController.java
  91. 52 3
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/MusicSheetController.java
  92. 9 12
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/SubjectController.java
  93. 5 0
      cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/TeacherController.java
  94. 16 4
      cooleshow-user/user-website/src/main/java/com/yonge/cooleshow/website/controller/MusicAlbumController.java
  95. 27 6
      cooleshow-user/user-website/src/main/java/com/yonge/cooleshow/website/controller/MusicSheetController.java
  96. 19 6
      cooleshow-user/user-website/src/main/java/com/yonge/cooleshow/website/controller/open/OpenMusicAlbumController.java
  97. 22 5
      cooleshow-user/user-website/src/main/java/com/yonge/cooleshow/website/controller/open/OpenMusicSheetController.java
  98. 13 0
      cooleshow-websocket/src/main/resources/bootstrap-dev.yml
  99. 69 0
      cooleshow-websocket/src/main/resources/logback-spring.xml

+ 1 - 1
audio-analysis/src/main/java/com/yonge/audio/AudioAnalysisServerApplication.java

@@ -24,7 +24,7 @@ import com.yonge.audio.config.LocalFastJsonHttpMessageConverter;
 @SpringBootApplication
 @EnableDiscoveryClient
 @EnableFeignClients("com.yonge.cooleshow")
-@MapperScan(basePackages = {"com.yonge.cooleshow.biz.dal.dao", "com.yonge.toolset.payment.core.dao"})
+@MapperScan(basePackages = {"com.yonge.cooleshow.biz.dal.dao", "com.yonge.cooleshow.biz.dal.mapper", "com.yonge.toolset.payment.core.dao"})
 @ComponentScan(basePackages = {
         "com.yonge.netty", "com.yonge.cooleshow", "com.yonge.toolset"
 })

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

@@ -4,6 +4,7 @@ import com.yonge.cooleshow.api.feign.dto.CouponInfoApi;
 import com.yonge.cooleshow.api.feign.dto.EmployeeApi;
 import com.yonge.cooleshow.api.feign.dto.StudentApi;
 import com.yonge.cooleshow.api.feign.dto.TeacherApi;
+import com.yonge.cooleshow.api.feign.dto.UserFriendInfoVO;
 import com.yonge.cooleshow.api.feign.fallback.AdminFeignServiceFallback;
 import com.yonge.cooleshow.common.constant.AppConstant;
 import com.yonge.cooleshow.common.entity.ContractDto;
@@ -128,4 +129,12 @@ public interface AdminFeignService {
                                                                @RequestParam("issueIds") String issueIds,
                                                                @RequestParam("orderAmount") BigDecimal orderAmount,
                                                                @RequestParam("client") String client);
+
+    /**
+     * 新用户添加客服好友
+     * @param info UserFriendInfoVO
+     * @return HttpResponseResult<Boolean>
+     */
+    @PostMapping(value = "/open/im/customerService")
+    HttpResponseResult<Boolean> customerService(@RequestBody UserFriendInfoVO info);
 }

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

@@ -0,0 +1,27 @@
+package com.yonge.cooleshow.api.feign.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 用户IM好友信息
+ * Created by Eric.Shang on 2022/9/20.
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserFriendInfoVO implements Serializable {
+
+    // 新用户ID
+    private Long userId;
+
+    // 好友ID
+    private List<Long> friendIds;
+
+}

+ 12 - 0
cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/fallback/AdminFeignServiceFallback.java

@@ -5,6 +5,7 @@ import com.yonge.cooleshow.api.feign.dto.CouponInfoApi;
 import com.yonge.cooleshow.api.feign.dto.EmployeeApi;
 import com.yonge.cooleshow.api.feign.dto.StudentApi;
 import com.yonge.cooleshow.api.feign.dto.TeacherApi;
+import com.yonge.cooleshow.api.feign.dto.UserFriendInfoVO;
 import com.yonge.cooleshow.common.entity.ContractDto;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.entity.MallOrderItemDto;
@@ -106,4 +107,15 @@ public class AdminFeignServiceFallback implements AdminFeignService {
     public HttpResponseResult<CouponInfoApi> queryCouponOrderPageInfo(Long userId, String issueIds, BigDecimal orderAmount, String client) {
         return null;
     }
+
+    /**
+     * 新用户添加客服好友
+     *
+     * @param info UserFriendInfoVO
+     * @return HttpResponseResult<Boolean>
+     */
+    @Override
+    public HttpResponseResult<Boolean> customerService(UserFriendInfoVO info) {
+        return null;
+    }
 }

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

@@ -20,7 +20,7 @@ public class UserSetReq {
     @ApiModelProperty("头像地址")
     private String avatar;
     @ApiModelProperty("昵称")
-    @Size(max = 7, message = "昵称长度不能超过7个字")
+    @Size(max = 12, message = "昵称长度不能超过12个字")
     private String username;
     @ApiModelProperty(value = "性别 0女 1男")
     private Integer gender;

+ 26 - 0
cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/config/CustomerServiceConfig.java

@@ -0,0 +1,26 @@
+package com.yonge.cooleshow.auth.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.stereotype.Component;
+
+import java.io.Serializable;
+
+/**
+ * 系统客服配置
+ * Created by Eric.Shang on 2022/9/21.
+ */
+@Data
+@RefreshScope
+@Component
+public class CustomerServiceConfig implements Serializable {
+
+    @Value("${app.customer.service:17740683946}")
+    private String customerService;
+    @Value("${app.customer.message:}")
+    private String customerMessage;
+    @Value("${app.customer.title:}")
+    private String customerTitle;
+
+}

+ 1 - 1
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/AuthServerApplication.java

@@ -19,7 +19,7 @@ import com.spring4all.swagger.EnableSwagger2Doc;
 @EnableDiscoveryClient
 @EnableFeignClients("com.yonge.cooleshow")
 @MapperScan("com.yonge.cooleshow.auth.dal.dao")
-@ComponentScan(basePackages = {"com.yonge.cooleshow", "com.yonge.toolset"})
+@ComponentScan(basePackages = {"com.yonge.cooleshow", "com.yonge.toolset", "com.yonge.cooleshow.auth.config"})
 @Configuration
 @EnableSwagger2Doc
 @EnableAsync

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

@@ -1,6 +1,7 @@
 package com.yonge.cooleshow.auth.core.provider;
 
 import java.util.Date;
+import java.util.Objects;
 
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.security.authentication.BadCredentialsException;
@@ -77,6 +78,11 @@ public class PhoneAuthenticationProvider extends AbstractAuthenticationProvider
 
             userInfo = sysUserService.registerUser(loginEntity.getPhone(), clientId, loginUserType);
 
+            if (Objects.nonNull(userInfo.getSysUser())) {
+                // 自动添加系统默认IM帐号为好友,并自动发送通知消息
+                sysUserService.sendSysCustomerServiceFriendMessage(userInfo.getSysUser());
+            }
+
             if (StringUtils.isNotBlank(deviceNum)) {
                 sysUserDeviceService.bindDevice(clientId, userInfo.getSysUser().getId(), deviceNum);
             }

+ 6 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/SysUserService.java

@@ -121,6 +121,12 @@ public interface SysUserService extends BaseService<Long, SysUser> {
     SysUserInfo registerUser(String phone, String clientId, String loginUserType);
 
     /**
+     * 添加系统客服好友消息
+     * @param sysUser SysUser
+     */
+    void sendSysCustomerServiceFriendMessage(SysUser sysUser);
+
+    /**
      * 刷新token
      *
      * @param sysUser

+ 81 - 21
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/impl/SysUserServiceImpl.java

@@ -1,38 +1,54 @@
 package com.yonge.cooleshow.auth.service.impl;
 
-import java.util.List;
-
+import com.alibaba.fastjson.JSON;
+import com.google.common.collect.Lists;
 import com.yonge.cooleshow.api.feign.AdminFeignService;
-import com.yonge.cooleshow.auth.api.dto.*;
+import com.yonge.cooleshow.api.feign.dto.UserFriendInfoVO;
+import com.yonge.cooleshow.auth.api.dto.QRLoginDto;
+import com.yonge.cooleshow.auth.api.dto.RealnameAuthReq;
+import com.yonge.cooleshow.auth.api.dto.SysUserInfo;
+import com.yonge.cooleshow.auth.api.dto.SysUserQueryInfo;
+import com.yonge.cooleshow.auth.api.dto.UserSetReq;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.auth.api.vo.UserSetVo;
+import com.yonge.cooleshow.auth.config.CustomerServiceConfig;
 import com.yonge.cooleshow.auth.config.RongCloudConfig;
+import com.yonge.cooleshow.auth.dal.dao.SysUserDao;
+import com.yonge.cooleshow.auth.service.SysConfigService;
+import com.yonge.cooleshow.auth.service.SysRoleMenuService;
+import com.yonge.cooleshow.auth.service.SysUserRoleService;
+import com.yonge.cooleshow.auth.service.SysUserService;
+import com.yonge.cooleshow.common.constant.SysConfigConstant;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.cooleshow.common.entity.ImUserModel;
 import com.yonge.cooleshow.common.enums.CacheNameEnum;
 import com.yonge.cooleshow.common.enums.SysUserType;
 import com.yonge.cooleshow.common.enums.UserFirstTimeTypeEnum;
-import com.yonge.cooleshow.common.enums.UserLockFlag;
+import com.yonge.toolset.base.exception.BizException;
+import com.yonge.toolset.base.util.ThreadPool;
+import com.yonge.toolset.mybatis.dal.BaseDAO;
 import com.yonge.toolset.mybatis.service.impl.BaseServiceImpl;
 import io.rong.models.user.UserModel;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
-
-import com.yonge.cooleshow.auth.api.entity.SysUser;
-import com.yonge.cooleshow.auth.api.vo.UserSetVo;
-import com.yonge.cooleshow.auth.dal.dao.SysUserDao;
-import com.yonge.cooleshow.auth.service.SysConfigService;
-import com.yonge.cooleshow.auth.service.SysRoleMenuService;
-import com.yonge.cooleshow.auth.service.SysUserRoleService;
-import com.yonge.cooleshow.auth.service.SysUserService;
-import com.yonge.cooleshow.common.constant.SysConfigConstant;
-import com.yonge.toolset.mybatis.dal.BaseDAO;
-import com.yonge.cooleshow.common.entity.ImUserModel;
-import com.yonge.toolset.base.exception.BizException;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Random;
+import java.util.stream.Collectors;
 
+@Slf4j
 @Service
+@RefreshScope
 public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implements SysUserService {
 
     @Autowired
@@ -47,6 +63,8 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
     private RedissonClient redissonClient;
     @Resource
     private AdminFeignService adminFeignService;
+    @Autowired
+    private CustomerServiceConfig customerServiceConfig;
 
     @Override
     public BaseDAO<Long, SysUser> getDAO() {
@@ -135,16 +153,19 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
     @Override
     @Transactional(rollbackFor = Exception.class)
     public SysUserInfo registerUser(String phone, String clientId, String loginUserType) {
+
+        SysUserInfo userInfo = null;
         if (StringUtils.equalsIgnoreCase(loginUserType, "TEACHER")) {
-            return registerTeacher(phone);
+            userInfo = registerTeacher(phone);
         } else if (StringUtils.equalsIgnoreCase(loginUserType, "STUDENT")) {
-            return registerStudent(phone);
+            userInfo = registerStudent(phone);
         } else if (StringUtils.equalsIgnoreCase(clientId, "TEACHER")) {
-            return registerTeacher(phone);
+            userInfo = registerTeacher(phone);
         } else if (StringUtils.equalsIgnoreCase(clientId, "STUDENT")) {
-            return registerStudent(phone);
+            userInfo = registerStudent(phone);
         }
-        return null;
+
+        return userInfo;
     }
 
     private SysUserInfo registerTeacher(String phone) {
@@ -160,6 +181,7 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
         //用户默认昵称
         sysUser.setUsername("游客" + sysUser.getId());
         sysUserDao.update(sysUser);
+
         return queryUserInfoByPhone(phone);
     }
 
@@ -176,9 +198,47 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
         //用户默认昵称
         sysUser.setUsername("游客" + sysUser.getId());
         sysUserDao.update(sysUser);
+
         return queryUserInfoByPhone(phone);
     }
 
+    /**
+     * 添加系统客服好友消息
+     * @param sysUser SysUser
+     */
+    public void sendSysCustomerServiceFriendMessage(SysUser sysUser) {
+
+        try {
+
+            ThreadPool.getExecutor().submit(() -> {
+
+                String customerService = customerServiceConfig.getCustomerService();
+                if (StringUtils.isNotEmpty(customerService)) {
+
+                    List<String> collect = Arrays.stream(customerService.split(",")).collect(Collectors.toList());
+
+                    Random rand = new Random();
+                    String mobile = collect.get(rand.nextInt(collect.size()));
+
+                    // 系统客服好友
+                    SysUser friend = sysUserDao.queryByPhone(mobile);
+
+                    // 发送添加系统客服好友消息
+                    HttpResponseResult<Boolean> result = adminFeignService.customerService(UserFriendInfoVO.builder()
+                            .userId(sysUser.getId())
+                            .friendIds(Lists.newArrayList(friend.getId()))
+                            .build());
+                    log.info("sendSysCustomerServiceFriendMessage mobile={}, ret={}", mobile, JSON.toJSONString(result));
+                }
+
+            });
+
+        } catch (Exception e) {
+            log.error("sendSysCustomerServiceFriendMessage userId={}", sysUser.getId(), e);
+        }
+
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void refreshImToken(SysUser sysUser) {

+ 14 - 3
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/web/controller/UserController.java

@@ -7,6 +7,7 @@ import io.swagger.annotations.ApiOperation;
 
 import java.util.Date;
 import java.util.List;
+import java.util.Objects;
 
 import javax.validation.Valid;
 
@@ -170,9 +171,12 @@ public class UserController extends BaseController {
 
     @ApiOperation(value = "设置用户名密码")
     @PostMapping(value = "/setUsernameAndPassword", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
-    @ApiImplicitParams({@ApiImplicitParam(name = "password", value = "密码", required = true, dataType = "String"),
-            @ApiImplicitParam(name = "username", value = "用户名", dataType = "String")})
-    public Object setPassword(String password, String username) {
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "password", value = "密码", required = true, dataType = "String"),
+            @ApiImplicitParam(name = "username", value = "用户名", dataType = "String"),
+            @ApiImplicitParam(name = "gender", value = "性别0女1男", dataType = "Integer")
+    })
+    public Object setPassword(String password, String username, Integer gender) {
         if (StringUtils.isEmpty(password)) {
             return failed("参数校验失败");
         }
@@ -184,6 +188,13 @@ public class UserController extends BaseController {
         if (sysUser == null) {
             return failed("用户不存在");
         }
+
+        // 设置用户性别
+        if (Objects.nonNull(gender)) {
+            sysUser.setGender(gender);
+        }
+
+        // 设置用户名称、昵称
         if (!StringUtil.isEmpty(username)) {
             if (sysUser.getUserType().contains("SYSTEM")) {
                 sysUser.setRealName(username);

+ 2 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/CacheNameEnum.java

@@ -29,6 +29,8 @@ public enum CacheNameEnum implements BaseEnum<String, CacheNameEnum> {
     LOCK_REWARD_STOCK("锁奖品库存变更"),
     LOCK_ACTIVITY_REWARD_STOCK("锁活动奖品变更"),
     LOCK_ACTIVITY_STOCK("锁活动变更"),
+    LOCK_STANDARD_GIFT_CRON("达标活动定时任务锁"),
+    LOCK_EVALUATION_CRON("评测活动定时任务锁"),
     ;
     /***
      * 缓存描述

+ 1 - 0
cooleshow-mall/mall-portal/src/main/java/com/yonge/cooleshow/portal/service/impl/OmsPortalOrderServiceImpl.java

@@ -176,6 +176,7 @@ public class OmsPortalOrderServiceImpl implements OmsPortalOrderService {
             orderItem.setGiftIntegration(cartPromotionItem.getIntegration());
             orderItem.setGiftGrowth(cartPromotionItem.getGrowth());
             orderItem.setPromoterId(cartPromotionItem.getPromoterId());
+            orderItem.setPrecisionAmount(BigDecimal.ZERO);
             orderItemList.add(orderItem);
         }
         //判断购物车中商品是否都有库存

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

@@ -3,7 +3,6 @@ package com.yonge.cooleshow.admin;
 import com.yonge.cooleshow.common.constant.AppConstant;
 import com.yonge.toolset.base.BaseApplication;
 import org.mybatis.spring.annotation.MapperScan;
-import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 import org.springframework.cloud.openfeign.EnableFeignClients;
@@ -17,7 +16,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
 @EnableDiscoveryClient
 @EnableFeignClients("com.yonge.cooleshow")
 @MapperScan(basePackages = {"com.yonge.cooleshow.biz.dal.dao", "com.yonge.cooleshow.biz.dal.mapper", "com.yonge.toolset.payment.core.dao"})
-@ComponentScan(basePackages = {"com.yonge.cooleshow", "com.yonge.toolset"})
+@ComponentScan(basePackages = {"com.yonge.cooleshow", "com.yonge.toolset", "com.yonge.cooleshow.auth.config"})
 @Configuration
 @EnableSwagger2Doc
 @EnableScheduling

+ 21 - 9
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/AdminClient.java

@@ -1,6 +1,5 @@
 package com.yonge.cooleshow.admin.controller.open;
 
-import com.alibaba.fastjson.JSON;
 import com.yonge.cooleshow.admin.io.request.coupon.CouponOrderVO;
 import com.yonge.cooleshow.api.feign.dto.CouponInfoApi;
 import com.yonge.cooleshow.api.feign.dto.EmployeeApi;
@@ -10,23 +9,30 @@ import com.yonge.cooleshow.biz.dal.entity.Employee;
 import com.yonge.cooleshow.biz.dal.entity.Student;
 import com.yonge.cooleshow.biz.dal.entity.Teacher;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
-import com.yonge.cooleshow.biz.dal.enums.GoodTypeEnum;
 import com.yonge.cooleshow.biz.dal.enums.coupon.CouponCategoryEnum;
 import com.yonge.cooleshow.biz.dal.enums.coupon.CouponUseStateEnum;
 import com.yonge.cooleshow.biz.dal.queryInfo.CouponInfoQuery;
-import com.yonge.cooleshow.biz.dal.service.*;
+import com.yonge.cooleshow.biz.dal.service.CouponInfoService;
+import com.yonge.cooleshow.biz.dal.service.EmployeeService;
+import com.yonge.cooleshow.biz.dal.service.StudentService;
+import com.yonge.cooleshow.biz.dal.service.TeacherService;
+import com.yonge.cooleshow.biz.dal.service.UserFirstTimeService;
 import com.yonge.cooleshow.biz.dal.wrapper.coupon.CouponOrderWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
-import com.yonge.cooleshow.common.entity.ContractDto;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.enums.UserFirstTimeTypeEnum;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections.CollectionUtils;
 import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 
 import java.math.BigDecimal;
 import java.util.Arrays;
@@ -111,11 +117,17 @@ public class AdminClient extends BaseController {
         request.setTimestamp(DateTime.now().getMillis());
         request.setAmount(orderAmount.doubleValue());
 
-        // 订单优惠券信息
-        CouponOrderWrapper wrapper = couponInfoService.queryUserOrderCouponInfo(request.getUserId(),
-                                                                                CouponInfoQuery.CouponOrderQuery.from(request.jsonString()));
         CouponInfoApi couponInfoApi = new CouponInfoApi();
-        couponInfoApi.setDiscountedPrices(BigDecimal.valueOf(wrapper.getDiscountedPrices()));
+        couponInfoApi.setDiscountedPrices(BigDecimal.ZERO);
+
+        if (CollectionUtils.isNotEmpty(collect)) {
+
+            // 订单优惠券信息
+            CouponOrderWrapper wrapper = couponInfoService.queryUserOrderCouponInfo(request.getUserId(),
+                    CouponInfoQuery.CouponOrderQuery.from(request.jsonString()));
+
+            couponInfoApi.setDiscountedPrices(BigDecimal.valueOf(wrapper.getDiscountedPrices()));
+        }
 
         return succeed(couponInfoApi);
     }

+ 69 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/ImUserFriendController.java

@@ -0,0 +1,69 @@
+package com.yonge.cooleshow.admin.controller.open;
+
+import com.yonge.cooleshow.admin.io.request.im.IMNotifyMessageVO;
+import com.yonge.cooleshow.admin.io.request.im.UserFriendInfoVO;
+import com.yonge.cooleshow.biz.dal.service.ImUserFriendService;
+import com.yonge.cooleshow.biz.dal.wrapper.im.CustomerService;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Value;
+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;
+
+/**
+ * 用户通讯录表(ImUserFriend)表控制层
+ *
+ * @author zx
+ * @since 2022-03-22 10:45:59
+ */
+@Api(tags = "用户通讯录表")
+@RestController
+@RequestMapping("/open/im")
+public class ImUserFriendController extends BaseController {
+
+    /**
+     * 服务对象
+     */
+    @Resource
+    private ImUserFriendService imUserFriendService;
+
+    @ApiOperation("新用户添加客服")
+    @PostMapping(value = "/customerService")
+    public HttpResponseResult<Boolean> customerService(@RequestBody UserFriendInfoVO info) {
+
+        if (info.invalidRequestParam()) {
+            return failed("无效的请求参数");
+        }
+
+        // 新用户自动绑定系统客服
+        int ret = imUserFriendService.registerUserBindCustomerService(info.getUserId(), info.getFriendIds());
+
+        return succeed(ret > 0);
+    }
+
+    /**
+     * 发送系统客服消息
+     * @param info IMNotifyMessageVO
+     * @return HttpResponseResult<Boolean>
+     */
+    @PostMapping(value = "/message")
+    public HttpResponseResult<Boolean> sendSysCustomerServiceMessage(@RequestBody IMNotifyMessageVO info) {
+
+        if (info.invalidRequestParam()) {
+            return failed("无效的请求参数");
+        }
+
+        // 发送客服通知消息
+        imUserFriendService.sendCustomerServiceNotifyMessage(info.getSender(),
+                CustomerService.NotifyMessage.from(info.jsonString()));
+
+        return succeed();
+    }
+}
+

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

@@ -0,0 +1,52 @@
+package com.yonge.cooleshow.admin.io.request.im;
+
+import com.alibaba.fastjson.JSON;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 系统IM通知信息
+ * Created by Eric.Shang on 2022/9/20.
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class IMNotifyMessageVO implements Serializable {
+
+    @ApiModelProperty(value = "发送者ID")
+    private String sender;
+
+    @ApiModelProperty(value = "接收ID")
+    private List<String> receives;
+
+    @ApiModelProperty(value = "通知标题")
+    private String title;
+
+    @ApiModelProperty(value = "文件通知消息")
+    private String txtMessage;
+
+    @ApiModelProperty(value = "图片通知消息")
+    private String imgMessage;
+
+    @ApiModelProperty(value = "图片文件地址")
+    private String imgUrl;
+
+    public String jsonString() {
+
+        return JSON.toJSONString(this);
+    }
+
+    public boolean invalidRequestParam() {
+
+        return StringUtils.isEmpty(getSender())
+                || StringUtils.isAllBlank(getTxtMessage(), getImgMessage());
+    }
+}

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

@@ -0,0 +1,32 @@
+package com.yonge.cooleshow.admin.io.request.im;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.collections.CollectionUtils;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 用户IM好友信息
+ * Created by Eric.Shang on 2022/9/20.
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserFriendInfoVO implements Serializable {
+
+    @ApiModelProperty(value = "新用户ID")
+    private Long userId;
+
+    @ApiModelProperty(value = "好友ID")
+    private List<Long> friendIds;
+
+    public boolean invalidRequestParam() {
+
+        return Optional.ofNullable(getUserId()).orElse(0L) <= 0 || CollectionUtils.isEmpty(getFriendIds());
+    }
+}

+ 15 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/task/TaskController.java

@@ -12,6 +12,7 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 import springfox.documentation.annotations.ApiIgnore;
 
@@ -39,6 +40,8 @@ public class TaskController extends BaseController {
     private PlatformCashAccountRecordService platformCashAccountRecordService;
     @Autowired
     private ActivityPlanService activityPlanService;
+    @Autowired
+    private ActivityPlanEvaluationService activityPlanEvaluationService;
 
     @Value("${app.blacklist:}")
     private String blacklistFilePath;
@@ -111,4 +114,16 @@ public class TaskController extends BaseController {
         activityPlanService.activityIng();
         return HttpResponseResult.succeed();
     }
+
+    /**
+     * 活动测试
+     * @param activityId 活动ID
+     * @return HttpResponseResult<Object>
+     */
+    @GetMapping("/test")
+    public HttpResponseResult<Object> test(@RequestParam("activityId") Long activityId) {
+
+        activityPlanEvaluationService.successActivity(activityId);
+        return HttpResponseResult.succeed();
+    }
 }

+ 6 - 0
cooleshow-user/user-biz/pom.xml

@@ -43,6 +43,12 @@
             <version>${rongcloud.im.version}</version>
         </dependency>
 
+        <dependency>
+            <groupId>net.coobird</groupId>
+            <artifactId>thumbnailator</artifactId>
+            <version>0.4.11</version>
+        </dependency>
+
         <!-- redisson -->
         <dependency>
             <groupId>org.redisson</groupId>

+ 9 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/ActivityEvaluationDao.java

@@ -9,6 +9,7 @@ import com.yonge.cooleshow.biz.dal.dto.search.MusicSheetSearch;
 import com.yonge.cooleshow.biz.dal.vo.ActivityMusicVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicSheetVo;
 import com.yonge.cooleshow.biz.dal.vo.activity.ActivityTeacherWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper;
 import org.apache.ibatis.annotations.Param;
 import com.yonge.cooleshow.biz.dal.entity.ActivityEvaluation;
 import com.yonge.cooleshow.biz.dal.vo.ActivityEvaluationVo;
@@ -85,4 +86,12 @@ public interface ActivityEvaluationDao extends BaseMapper<ActivityEvaluation> {
 	 * @return List<ActivityTeacherWrapper>
 	 */
 	List<ActivityTeacherWrapper> selectActivityTeacherByTimePageInfo(@Param("page") IPage<ActivityTeacherWrapper> page, @Param("record") ActivityTeacherQuery query);
+
+	/**
+	 * 评测活动声部曲目最高分
+	 * @param activityId 活动ID
+	 * @param userId 用户ID
+	 * @return List<StatGroupWrapper>
+	 */
+    List<StatGroupWrapper> selectSubjectMusicHighestScoreStat(@Param("activityId") Long activityId, @Param("userId") Long userId);
 }

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

@@ -4,8 +4,9 @@ import java.util.List;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.yonge.cooleshow.biz.dal.entity.ActivityUserReward;
-import com.yonge.cooleshow.biz.dal.vo.MusicActivityVo;
+import com.yonge.cooleshow.biz.dal.entity.ActivityEvaluationRecord;
+import com.yonge.cooleshow.biz.dal.vo.ActivityRankingVo;
+import com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper;
 import org.apache.ibatis.annotations.Param;
 import com.yonge.cooleshow.biz.dal.entity.ActivityPlan;
 import com.yonge.cooleshow.biz.dal.vo.ActivityPlanVo;
@@ -69,4 +70,38 @@ public interface ActivityPlanDao extends BaseMapper<ActivityPlan> {
 	 * @return
 	 */
 	ActivityPlanVo selectActivityShare(@Param("type") String type, @Param("userId") Long userId);
+
+	/**
+	 * 活动参与人数统计
+	 * @param activityIds 活动ID
+	 * @return List<StatGroupWrapper>
+	 */
+    List<StatGroupWrapper> selectActivityParticipateStatInfo(@Param("activityIds") List<Long> activityIds);
+
+	/**
+	 * 活动获奖用户统计
+	 * @param activityIds 活动ID
+	 * @return List<StatGroupWrapper>
+	 */
+	List<StatGroupWrapper> selectActivityWinnerStatInfo(@Param("activityIds") List<Long> activityIds);
+
+	/**
+	 * 活动总分用户排名
+	 * @param activityId 活动ID
+	 * @param subjectId 声部ID
+	 * @return List<ActivityRankingVo>
+	 */
+    List<ActivityRankingVo> selectActivityHighestScoreRankingInfo(@Param("activityId") Long activityId, @Param("subjectId") Long subjectId,
+																  @Param("rankingScore") Double rankingScore, @Param("limit") Integer limit);
+
+	/**
+	 * 总分用户排名信息
+	 * @param activityPlanId 活动ID
+	 * @param subjectId 声部ID
+	 * @param rankingScore 分数
+	 * @param userId 用户ID
+	 * @return ActivityRankingVo
+	 */
+	ActivityRankingVo selectActivityHighestScoreUserRanking(@Param("activityId") Long activityPlanId, @Param("subjectId") Long subjectId,
+															@Param("rankingScore") Double rankingScore, @Param("userId") Long userId);
 }

+ 4 - 3
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/MusicAlbumDao.java

@@ -5,6 +5,7 @@ import com.yonge.cooleshow.biz.dal.dto.search.MusicAlbumSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentMusicAlbumSearch;
 import com.yonge.cooleshow.biz.dal.entity.MusicAlbum;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.vo.MusicAlbumVo;
 import org.apache.ibatis.annotations.Param;
 
@@ -35,8 +36,7 @@ public interface MusicAlbumDao extends BaseMapper<MusicAlbum> {
      * @param search 查询条件
      * @return
      */
-    List<MusicAlbumVo> selectFavoritePage(@Param("page") IPage<MusicAlbumVo> page, @Param(
-            "query") StudentMusicAlbumSearch search);
+    List<MusicAlbumVo> selectFavoritePage(@Param("page") IPage<MusicAlbumVo> page, @Param("query") StudentMusicAlbumSearch search, @Param("clientType") ClientEnum clientType);
 
     /**
      * 查询收藏专辑的收藏数和曲谱数
@@ -60,7 +60,8 @@ public interface MusicAlbumDao extends BaseMapper<MusicAlbum> {
      *
      * @param page  分页信息
      * @param query 查询条件
+     * @param clientType ClientEnum
      * @return page
      */
-    List<MusicAlbumVo> selectStudentPage(@Param("page") IPage<MusicAlbumVo> page, @Param("query") MusicAlbumSearch query);
+    List<MusicAlbumVo> selectStudentPage(@Param("page") IPage<MusicAlbumVo> page, @Param("query") MusicAlbumSearch query, @Param("clientType") ClientEnum clientType);
 }

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

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.yonge.cooleshow.biz.dal.dto.search.*;
 import com.yonge.cooleshow.biz.dal.entity.MusicSheet;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.vo.*;
 import org.apache.ibatis.annotations.Param;
 
@@ -44,8 +45,7 @@ public interface MusicSheetDao extends BaseMapper<MusicSheet> {
     /**
      * 分页查询
      */
-    List<MusicSheetVo> selectStudentMusicPage(@Param("page") IPage<MusicSheetVo> page, @Param(
-            "param") StudentMusicSheetSearch query);
+    List<MusicSheetVo> selectStudentMusicPage(@Param("page") IPage<MusicSheetVo> page, @Param("param") StudentMusicSheetSearch query, @Param("clientType") ClientEnum clientType);
 
     /**
      * 我的单曲
@@ -62,10 +62,10 @@ public interface MusicSheetDao extends BaseMapper<MusicSheet> {
      *
      * @param page  分页信息
      * @param query 查询条件
+     * @param clientType ClientEnum
      * @return list
      */
-    List<MusicSheetVo> selectFavoriteMusicPage(@Param("page") IPage<MusicSheetVo> page, @Param(
-            "param") StudentMusicSheetSearch query);
+    List<MusicSheetVo> selectFavoriteMusicPage(@Param("page") IPage<MusicSheetVo> page, @Param("param") StudentMusicSheetSearch query, @Param("clientType") ClientEnum clientType);
 
     /**
      * 最近练习曲目

+ 10 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/UserFirstTimeDao.java

@@ -1,6 +1,7 @@
 package com.yonge.cooleshow.biz.dal.dao;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.yonge.cooleshow.biz.dal.dto.search.UserFirstTimeSearch;
 import com.yonge.cooleshow.biz.dal.entity.UserFirstTime;
 import org.apache.ibatis.annotations.Param;
@@ -9,10 +10,19 @@ import java.util.List;
 
 
 public interface UserFirstTimeDao extends BaseMapper<UserFirstTime>{
+
     /**
      * 查询集合
      * @param param
      * @return
      */
     List<UserFirstTime> selectAllList(@Param("param") UserFirstTimeSearch param);
+
+    /**
+     * 达标活动参与用户信息
+     * @param page IPage<UserFirstTime>
+     * @param search UserFirstTimeSearch
+     * @return IPage<UserFirstTime>
+     */
+    List<UserFirstTime> selectActivityParticipateUserPage(@Param("page") IPage<UserFirstTime> page, @Param("record") UserFirstTimeSearch search);
 }

+ 79 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/req/TeacherMusicSheetAuditReq.java

@@ -1,7 +1,9 @@
 package com.yonge.cooleshow.biz.dal.dto.req;
 
 
+import com.yonge.cooleshow.biz.dal.enums.AudioTypeEnum;
 import com.yonge.cooleshow.biz.dal.enums.AuthStatusEnum;
+import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
@@ -32,6 +34,27 @@ public class TeacherMusicSheetAuditReq {
     @NotBlank(message = "审核理由不能为空 ")
     private String remark;
 
+    @ApiModelProperty("是否可以转简谱(0:否,1:是)")
+    private YesOrNoEnum notation;
+
+    @ApiModelProperty(value = "是否可以评测(0:否;1:是)")
+    private YesOrNoEnum canEvaluate;  //是否可以评测(0:否;1:是)
+
+    @ApiModelProperty(value = "是否展示指法(0:否;1:是)")
+    private YesOrNoEnum showFingering;  //是否展示指法(0:否;1:是)
+
+    @ApiModelProperty(value = "是否自带节拍器(0:否;1:是)")
+    private YesOrNoEnum hasBeat;  //是否自带节拍器(0:否;1:是)
+
+    @ApiModelProperty(value = "mp3类型 MP3:mp3, MP3_METRONOME:MP3_METRONOME,")
+    private AudioTypeEnum mp3Type;
+
+    @ApiModelProperty(value = "曲目音频类型 MP3:mp3, MIDI:midi,")
+    private AudioTypeEnum audioType;
+
+    @ApiModelProperty(value = "音频文件存储路径")
+    private String audioFileUrl;  //音频文件存储路径
+
     public String getMusicImg() {
         return musicImg;
     }
@@ -63,4 +86,60 @@ public class TeacherMusicSheetAuditReq {
     public void setRemark(String remark) {
         this.remark = remark;
     }
+
+    public YesOrNoEnum getNotation() {
+        return notation;
+    }
+
+    public void setNotation(YesOrNoEnum notation) {
+        this.notation = notation;
+    }
+
+    public YesOrNoEnum getCanEvaluate() {
+        return canEvaluate;
+    }
+
+    public void setCanEvaluate(YesOrNoEnum canEvaluate) {
+        this.canEvaluate = canEvaluate;
+    }
+
+    public YesOrNoEnum getShowFingering() {
+        return showFingering;
+    }
+
+    public void setShowFingering(YesOrNoEnum showFingering) {
+        this.showFingering = showFingering;
+    }
+
+    public YesOrNoEnum getHasBeat() {
+        return hasBeat;
+    }
+
+    public void setHasBeat(YesOrNoEnum hasBeat) {
+        this.hasBeat = hasBeat;
+    }
+
+    public AudioTypeEnum getMp3Type() {
+        return mp3Type;
+    }
+
+    public void setMp3Type(AudioTypeEnum mp3Type) {
+        this.mp3Type = mp3Type;
+    }
+
+    public AudioTypeEnum getAudioType() {
+        return audioType;
+    }
+
+    public void setAudioType(AudioTypeEnum audioType) {
+        this.audioType = audioType;
+    }
+
+    public String getAudioFileUrl() {
+        return audioFileUrl;
+    }
+
+    public void setAudioFileUrl(String audioFileUrl) {
+        this.audioFileUrl = audioFileUrl;
+    }
 }

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

@@ -34,6 +34,9 @@ public class ActivityRegistrationSearch extends QueryInfo {
     @ApiModelProperty(value = "是否获奖 0 否 1 是")
     private YesOrNoEnum rewardFlag;
 
+    @ApiModelProperty(value = "声部ID集合")
+    private List<Long> subjectIds;
+
     public ActivityTypeEnum getActivityType() {
         return activityType;
     }
@@ -65,4 +68,12 @@ public class ActivityRegistrationSearch extends QueryInfo {
     public void setRewardFlag(YesOrNoEnum rewardFlag) {
         this.rewardFlag = rewardFlag;
     }
+
+    public List<Long> getSubjectIds() {
+        return subjectIds;
+    }
+
+    public void setSubjectIds(List<Long> subjectIds) {
+        this.subjectIds = subjectIds;
+    }
 }

+ 23 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/MusicAlbumDetailSearch.java

@@ -1,9 +1,11 @@
 package com.yonge.cooleshow.biz.dal.dto.search;
 
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
 import javax.validation.constraints.NotNull;
+import java.util.Optional;
 
 /**
  * Description 专辑详情下的曲目查询
@@ -30,6 +32,11 @@ public class MusicAlbumDetailSearch extends MusicSheetSearch {
     @ApiModelProperty("相关专辑数,默认4")
     private Integer relatedNum = 4;
 
+    @ApiModelProperty("客户端类型")
+    private ClientEnum clientType;
+
+    @ApiModelProperty(value = "艺术家")
+    private String composer;  //音乐家
 
     public Integer getRelatedNum() {
         return relatedNum;
@@ -55,6 +62,22 @@ public class MusicAlbumDetailSearch extends MusicSheetSearch {
         this.type = type;
     }
 
+    public ClientEnum getClientType() {
+        return Optional.ofNullable(clientType).orElse(ClientEnum.STUDENT);
+    }
+
+    public void setClientType(ClientEnum clientType) {
+        this.clientType = clientType;
+    }
+
+    public String getComposer() {
+        return composer;
+    }
+
+    public void setComposer(String composer) {
+        this.composer = composer;
+    }
+
     @Override
     public Boolean getDelFlag() {
         return delFlag;

+ 10 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/StudentMusicSheetSearch.java

@@ -1,7 +1,6 @@
 package com.yonge.cooleshow.biz.dal.dto.search;
 
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
-import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import io.swagger.annotations.ApiModelProperty;
 
 /**
@@ -33,6 +32,8 @@ public class StudentMusicSheetSearch  extends MusicSheetSearch{
     @ApiModelProperty(value = "平台")
     private String platform;
 
+    // 客户端类型
+    private ClientEnum clientType;
 
 
     public ClientEnum getUserType() {
@@ -83,4 +84,12 @@ public class StudentMusicSheetSearch  extends MusicSheetSearch{
     public void setStudentId(Long studentId) {
         this.studentId = studentId;
     }
+
+    public ClientEnum getClientType() {
+        return clientType;
+    }
+
+    public void setClientType(ClientEnum clientType) {
+        this.clientType = clientType;
+    }
 }

+ 43 - 2
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/UserFirstTimeSearch.java

@@ -1,14 +1,14 @@
 package com.yonge.cooleshow.biz.dal.dto.search;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
-import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
-import com.yonge.cooleshow.common.enums.UserFirstTimeTypeEnum;
+import com.yonge.cooleshow.common.enums.ConditionMethodEnum;
 import com.yonge.toolset.base.page.QueryInfo;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import org.springframework.format.annotation.DateTimeFormat;
 
 import java.util.Date;
+import java.util.List;
 
 /**
  * @Author: liweifan
@@ -33,6 +33,13 @@ public class UserFirstTimeSearch extends QueryInfo{
 	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
 	private Date endTime;
 
+	// 活动ID
+	private Long activityId;
+	// 活动参与用户ID
+	private List<Long> userIds;
+	// 达标活动计算方式
+	private ConditionMethodEnum calculationMethod;
+
 	public Long getUserId() {
 		return userId;
 	}
@@ -72,4 +79,38 @@ public class UserFirstTimeSearch extends QueryInfo{
 	public void setEndTime(Date endTime) {
 		this.endTime = endTime;
 	}
+
+	public Long getActivityId() {
+		return activityId;
+	}
+
+	public void setActivityId(Long activityId) {
+		this.activityId = activityId;
+	}
+
+	public List<Long> getUserIds() {
+		return userIds;
+	}
+
+	public void setUserIds(List<Long> userIds) {
+		this.userIds = userIds;
+	}
+
+	public ConditionMethodEnum getCalculationMethod() {
+		return calculationMethod;
+	}
+
+	public void setCalculationMethod(ConditionMethodEnum calculationMethod) {
+		this.calculationMethod = calculationMethod;
+	}
+
+	public UserFirstTimeSearch activityId(Long activityId) {
+		this.activityId = activityId;
+		return this;
+	}
+
+	public UserFirstTimeSearch userIds(List<Long> userIds) {
+		this.userIds = userIds;
+		return this;
+	}
 }

+ 24 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ActivityEvaluationRecord.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.yonge.cooleshow.biz.dal.enums.activity.ActivityRankingMethodEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
@@ -43,6 +44,14 @@ public class ActivityEvaluationRecord implements Serializable {
     @ApiModelProperty("次数")
     @TableField(value = "times_")
     private int times;
+
+    @ApiModelProperty("评份方式")
+    @TableField(value = "ranking_method_")
+    private ActivityRankingMethodEnum rankingMethod;
+
+    @ApiModelProperty("活动报名时间 ")
+    @TableField(value = "registration_time_")
+    private Long registrationTime;
     
     @ApiModelProperty("创建时间 ")
     @TableField(value = "create_time_")
@@ -114,4 +123,19 @@ public class ActivityEvaluationRecord implements Serializable {
         this.createTime = createTime;
     }
 
+    public ActivityRankingMethodEnum getRankingMethod() {
+        return rankingMethod;
+    }
+
+    public void setRankingMethod(ActivityRankingMethodEnum rankingMethod) {
+        this.rankingMethod = rankingMethod;
+    }
+
+    public Long getRegistrationTime() {
+        return registrationTime;
+    }
+
+    public void setRegistrationTime(Long registrationTime) {
+        this.registrationTime = registrationTime;
+    }
 }

+ 25 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ActivityPlan.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.activity.ActivityRankingMethodEnum;
 import com.yonge.cooleshow.biz.dal.enums.activity.ActivityRankingRuleEnum;
 import com.yonge.cooleshow.common.enums.ActivityTypeEnum;
 import com.yonge.cooleshow.common.enums.RegistrationMethodEnum;
@@ -118,6 +119,14 @@ public class ActivityPlan implements Serializable {
     @TableField(value = "ranking_rule_")
     private ActivityRankingRuleEnum rankingRule;
 
+    @ApiModelProperty("活动形式: MUSIC_RANKING(单曲排名) TOTAL_SCORE(总分排名) ")
+    @TableField(value = "ranking_method_")
+    private ActivityRankingMethodEnum rankingMethod;
+
+    @ApiModelProperty("获奖分数 ")
+    @TableField(value = "ranking_score_")
+    private Double rankingScore;
+
     public Long getId() {
         return id;
     }
@@ -317,4 +326,20 @@ public class ActivityPlan implements Serializable {
     public void setRankingRule(ActivityRankingRuleEnum rankingRule) {
         this.rankingRule = rankingRule;
     }
+
+    public ActivityRankingMethodEnum getRankingMethod() {
+        return rankingMethod;
+    }
+
+    public void setRankingMethod(ActivityRankingMethodEnum rankingMethod) {
+        this.rankingMethod = rankingMethod;
+    }
+
+    public Double getRankingScore() {
+        return rankingScore;
+    }
+
+    public void setRankingScore(Double rankingScore) {
+        this.rankingScore = rankingScore;
+    }
 }

+ 13 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/AlbumFavorite.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.entity;
 
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.common.entity.BaseEntity;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
@@ -22,6 +23,10 @@ public class AlbumFavorite extends BaseEntity {
     @ApiModelProperty(value = "主键id")
     private Long id;  //主键ID
 
+	@TableField("client_type_")
+	@ApiModelProperty(value = "客户端类型")
+	private ClientEnum clientType;
+
     @TableField("user_id_")
     @ApiModelProperty(value = "用户ID(目前只是学生ID)")
     private Long userId;  //用户ID(目前只是学生ID)
@@ -84,8 +89,15 @@ public class AlbumFavorite extends BaseEntity {
 	    return this.favoriteFlag;
 	}
 
+	public ClientEnum getClientType() {
+		return clientType;
+	}
+
+	public void setClientType(ClientEnum clientType) {
+		this.clientType = clientType;
+	}
 
-    @Override
+	@Override
     public String toString() {
         return ToStringBuilder.reflectionToString(this);
     }

+ 13 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/MusicFavorite.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.entity;
 
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.common.entity.BaseEntity;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
@@ -22,6 +23,10 @@ public class MusicFavorite extends BaseEntity {
     @ApiModelProperty(value = "主键id")
     private Long id;  //主键ID
 
+	@TableField("client_type_")
+	@ApiModelProperty(value = "客户端类型")
+	private ClientEnum clientType;
+
     @TableField("user_id_")
     @ApiModelProperty(value = "用户ID(目前只是学生ID)")
     private Long userId;  //用户ID(目前只是学生ID)
@@ -84,8 +89,15 @@ public class MusicFavorite extends BaseEntity {
 	    return this.favoriteFlag;
 	}
 
+	public ClientEnum getClientType() {
+		return clientType;
+	}
+
+	public void setClientType(ClientEnum clientType) {
+		this.clientType = clientType;
+	}
 
-    @Override
+	@Override
     public String toString() {
         return ToStringBuilder.reflectionToString(this);
     }

+ 56 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/MusicSheet.java

@@ -6,6 +6,8 @@ import io.swagger.annotations.ApiModelProperty;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.util.Date;
+import java.util.Objects;
+import java.util.Optional;
 
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
@@ -20,6 +22,7 @@ import com.yonge.cooleshow.biz.dal.enums.AuthStatusEnum;
 import com.yonge.cooleshow.biz.dal.enums.ChargeTypeEnum;
 import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
+import org.apache.commons.lang3.StringUtils;
 
 /**
  * 曲谱表
@@ -104,11 +107,16 @@ public class MusicSheet implements Serializable {
     @ApiModelProperty(value = "是否展示指法(0:否;1:是)")
     private YesOrNoEnum showFingering;  //是否展示指法(0:否;1:是)
 
-    @NotNull(message = "收费类型不能为空!")
+    // @NotNull(message = "收费类型不能为空!")
     @TableField("charge_type_")
     @ApiModelProperty(value = "收费类型(FREE:免费;VIP:会员;CHARGE:单曲收费)")
     private ChargeTypeEnum chargeType;  //收费类型(0:免费;1:会员;2:单曲收费)
 
+	@NotNull(message = "收费类型不能为空!")
+	@TableField("payment_type_")
+	@ApiModelProperty(value = "收费类型(FREE:免费;VIP:会员;CHARGE:单曲收费)")
+	private String paymentType;
+
 
 	@TableField("state_")
 	@ApiModelProperty(value = "曲目状态(0:停用,1:启用)")
@@ -361,6 +369,10 @@ public class MusicSheet implements Serializable {
 	}
 
 	public ChargeTypeEnum getChargeType() {
+		if (Objects.isNull(this.chargeType) && StringUtils.isNotEmpty(getPaymentType())) {
+
+			return ChargeTypeEnum.valueOf(getPaymentType().split(",")[0]);
+		}
 		return chargeType;
 	}
 
@@ -527,4 +539,47 @@ public class MusicSheet implements Serializable {
 	public void setAuditVersion(YesOrNoEnum auditVersion) {
 		this.auditVersion = auditVersion;
 	}
+
+	public String getPaymentType() {
+		return paymentType;
+	}
+
+	public void setPaymentType(String paymentType) {
+		this.paymentType = paymentType;
+	}
+
+	public MusicSheet notation(YesOrNoEnum notation) {
+		this.notation = notation;
+		return this;
+	}
+
+	public MusicSheet canEvaluate(YesOrNoEnum canEvaluate) {
+		this.canEvaluate = canEvaluate;
+		return this;
+	}
+
+	public MusicSheet showFingering(YesOrNoEnum showFingering) {
+		this.showFingering = showFingering;
+		return this;
+	}
+
+	public MusicSheet hasBeat(YesOrNoEnum hasBeat) {
+		this.hasBeat = hasBeat;
+		return this;
+	}
+
+	public MusicSheet mp3Type(AudioTypeEnum mp3Type) {
+		this.mp3Type = mp3Type;
+		return this;
+	}
+
+	public MusicSheet audioType(AudioTypeEnum audioType) {
+		this.audioType = audioType;
+		return this;
+	}
+
+	public MusicSheet audioFileUrl(String audioFileUrl) {
+		this.audioFileUrl = audioFileUrl;
+		return this;
+	}
 }

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

@@ -32,4 +32,23 @@ public enum ClientEnum implements BaseEnum<String, ClientEnum> {
     public String getMsg() {
         return msg;
     }
+
+    /**
+     * 校验客户端类型合法性
+     * @param clientType 客户端类型
+     * @return boolean
+     */
+    public static boolean invalid(String clientType) {
+
+        ClientEnum[] values = ClientEnum.values();
+
+        for (ClientEnum item : values) {
+
+            if (item.getCode().equals(clientType)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
 }

+ 63 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/EQueryOp.java

@@ -0,0 +1,63 @@
+package com.yonge.cooleshow.biz.dal.enums;
+
+/**
+ * Created by Eric.Shang on 30/5/17.
+ */
+public enum EQueryOp {
+    FUNCTION_1(1),
+    FUNCTION_2(2),
+    FUNCTION_3(3),
+    FUNCTION_4(4),
+    FUNCTION_5(5),
+    FUNCTION_6(6),
+    FUNCTION_7(7),
+    FUNCTION_8(8),
+    FUNCTION_9(9),
+    FUNCTION_10(10),
+    FUNCTION_11(11),
+    FUNCTION_12(12),
+    FUNCTION_13(13),
+    FUNCTION_14(14),
+    FUNCTION_15(15),
+    FUNCTION_16(16),
+    FUNCTION_17(17),
+    FUNCTION_18(18),
+    FUNCTION_19(19),
+    FUNCTION_20(20),
+    FUNCTION_21(21),
+    UNKNOWN(-1);
+
+    private final int value;
+
+    public int getValue() {
+        return value;
+    }
+
+    EQueryOp(int value) {
+        this.value = value;
+    }
+
+    /**
+     * 校验枚举合法性
+     * @param value 枚举值
+     * @return boolean
+     */
+    public boolean valid(int value) {
+        return (this.getValue() == value);
+    }
+
+    /**
+     * 枚举对象
+     * @param value 枚举值
+     * @return EQueryOp
+     */
+    public static EQueryOp getOp(int value) {
+        EQueryOp[] values = EQueryOp.values();
+        for (EQueryOp item : values) {
+            if (item.getValue() == value) {
+                return item;
+            }
+        }
+        return UNKNOWN;
+    }
+}

+ 5 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/MK.java

@@ -16,4 +16,9 @@ public interface MK {
     String TIME_ZONE = "GMT+8";
     // 时间戳
     String YYYYMMDD = "yyyyMMdd";
+
+    // 客服消息
+    String IM_SYS_FRIEND = "你好!我是你的专属客服~有任何问题都可以与我联系哦!";
+    // 推送消息标题
+    String IM_SYS_TITLE = "客服消息";
 }

+ 34 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/activity/ActivityRankingMethodEnum.java

@@ -0,0 +1,34 @@
+package com.yonge.cooleshow.biz.dal.enums.activity;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+
+/**
+ * 活动获奖排名方式
+ *
+ * @Author: Eric
+ * @Data: 2022/3/16 10:19
+ */
+public enum ActivityRankingMethodEnum implements BaseEnum<String, ActivityRankingMethodEnum> {
+
+    MUSIC_RANKING("单曲排名"),
+    TOTAL_SCORE("总分排名"),
+    ;
+    @EnumValue
+    private String code;
+    private String name;
+
+    ActivityRankingMethodEnum(String name) {
+        this.code = this.name();
+        this.name = name;
+    }
+
+    @Override
+    public String getCode() {
+        return this.code;
+    }
+
+    public String getName() {
+        return name;
+    }
+}

+ 1 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/activity/ActivityRankingRuleEnum.java

@@ -13,6 +13,7 @@ public enum ActivityRankingRuleEnum implements BaseEnum<String, ActivityRankingR
 
     EVALUATIONS_NUMBER("评测次数"),
     EVALUATIONS_TIME("评测时间"),
+    TOTAL_SCORE("评测总分"),
     ;
     @EnumValue
     private String code;

+ 8 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/CouponIssueMapper.java

@@ -33,4 +33,12 @@ public interface CouponIssueMapper extends BaseMapper<CouponIssue> {
      * @return List<StatGroupWrapper>
      */
     List<StatGroupWrapper> selectCouponStateStatInfo(@Param("userId") Long id, @Param("record") CouponInfoQuery.CouponStateStatQuery query);
+
+    /**
+     * 用户发送优惠券统计
+     * @param couponId 优惠券ID
+     * @param statQuery CouponInfoQuery.IssueStatQuery
+     * @return List<StatGroupWrapper>
+     */
+    List<StatGroupWrapper> selectCouponIssueStatInfo(@Param("couponId") Long couponId, @Param("record") CouponInfoQuery.IssueStatQuery statQuery);
 }

+ 3 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/queryInfo/CouponInfoQuery.java

@@ -68,6 +68,9 @@ public class CouponInfoQuery implements Serializable {
 
         // 状态排除
         private List<CouponUseStateEnum> excludeUseState;
+
+        // 发送用户
+        private List<Long> userIds;
     }
 
     /**

+ 5 - 2
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/AlbumFavoriteService.java

@@ -2,6 +2,7 @@ package com.yonge.cooleshow.biz.dal.service;
 
 import com.yonge.cooleshow.biz.dal.entity.AlbumFavorite;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 
 import java.util.List;
 
@@ -18,16 +19,18 @@ public interface AlbumFavoriteService extends IService<AlbumFavorite> {
      *
      * @param studentId 学生id
      * @param albumId 专辑id
+     * @param clientType ClientEnum
      * @return list
      */
-    List<AlbumFavorite> getFavorite(Long studentId, Long albumId);
+    List<AlbumFavorite> getFavorite(Long studentId, Long albumId, ClientEnum clientType);
 
     /**
      * 获取收藏信息
      *
      * @param userId 用户id
      * @param albumIds 专辑id
+     * @param clientType ClientEnum
      * @return
      */
-    List<Long> selectFavorite(Long userId, List<Long> albumIds);
+    List<Long> selectFavorite(Long userId, List<Long> albumIds, ClientEnum clientType);
 }

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

@@ -3,7 +3,9 @@ package com.yonge.cooleshow.biz.dal.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.yonge.cooleshow.biz.dal.dao.ImUserFriendDao;
 import com.yonge.cooleshow.biz.dal.entity.ImUserFriend;
+import com.yonge.cooleshow.biz.dal.wrapper.im.CustomerService;
 
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -34,5 +36,20 @@ public interface ImUserFriendService extends IService<ImUserFriend> {
     * @date 2022/3/24 12:03
     */
     ImUserFriend getDetail(Long userId);
+
+    /**
+     * 新用户自动添加客服
+     * @param userId 新用户ID
+     * @param friendIds 好友ID
+     * @return Integer
+     */
+    Integer registerUserBindCustomerService(Long userId, List<Long> friendIds);
+
+    /**
+     * 发送系统客服消息
+     * @param sender 发送者
+     * @param info CustomerService.NotifyMessage
+     */
+    void sendCustomerServiceNotifyMessage(String sender, CustomerService.NotifyMessage info);
 }
 

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

@@ -10,6 +10,7 @@ import com.yonge.cooleshow.biz.dal.entity.ImUserStateSync;
 import com.yonge.cooleshow.biz.dal.entity.LiveRoom;
 import com.yonge.cooleshow.biz.dal.entity.RoomInfoCache;
 import com.yonge.cooleshow.biz.dal.vo.TeacherLivingInfoVo;
+import com.yonge.cooleshow.biz.dal.wrapper.liveroom.LiveRoomWrapper;
 import com.yonge.toolset.base.page.PageInfo;
 
 /**
@@ -136,5 +137,13 @@ public interface LiveRoomService extends IService<LiveRoom> {
      * @param whetherMic 是否连麦 0: 是 1:否
      */
     void whetherMic(String roomUid, Integer whetherMic);
+
+    /**
+     * 直播间详情信息
+     * @param liveRoomId 直播间编号
+     * @param userId 分享用户ID
+     * @return LiveRoomWrapper
+     */
+    LiveRoomWrapper findLiveRoomDetailInfoByRoomId(String liveRoomId, Long userId);
 }
 

+ 9 - 4
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/MusicAlbumService.java

@@ -8,6 +8,7 @@ import com.yonge.cooleshow.biz.dal.dto.search.MusicAlbumDetailSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.MusicAlbumSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentMusicAlbumSearch;
 import com.yonge.cooleshow.biz.dal.entity.MusicAlbum;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.vo.AlbumDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicAlbumVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicSheetVo;
@@ -87,27 +88,30 @@ public interface MusicAlbumService extends IService<MusicAlbum> {
      *
      * @param studentId 学生id
      * @param albumId 专辑id
+     * @param clientType ClientEnum
      * @return YesOrNoEnum
      */
-    YesOrNoEnum checkFavorite(Long studentId, Long albumId);
+    YesOrNoEnum checkFavorite(Long studentId, Long albumId, ClientEnum clientType);
 
     /**
      * 设置学生收藏/取消收藏 专辑
      *
      * @param studentId 学生id
      * @param albumId 专辑id
+     * @param clientType ClientEnum
      * @return boolean
      */
-    Boolean setFavorite(Long studentId, Long albumId);
+    Boolean setFavorite(Long studentId, Long albumId, ClientEnum clientType);
 
     /**
      * 收藏专辑列表
      *
      * @param page 分页
      * @param search 查询条件
+     * @param clientType ClientEnum
      * @return list
      */
-    IPage<MusicAlbumVo> favoriteAlbum(IPage<MusicAlbumVo> page, StudentMusicAlbumSearch search);
+    IPage<MusicAlbumVo> favoriteAlbum(IPage<MusicAlbumVo> page, StudentMusicAlbumSearch search, ClientEnum clientType);
 
     /**
      * 删除专辑
@@ -122,9 +126,10 @@ public interface MusicAlbumService extends IService<MusicAlbum> {
      *
      * @param page 分页
      * @param query 查询条件
+     * @param clientType ClientEnum
      * @return
      */
-    IPage<MusicAlbumVo> selectStudentPage(IPage<MusicAlbumVo> page, MusicAlbumSearch query);
+    IPage<MusicAlbumVo> selectStudentPage(IPage<MusicAlbumVo> page, MusicAlbumSearch query, ClientEnum clientType);
 
     /**
      * 修改专辑中 曲目的排序值

+ 3 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/MusicFavoriteService.java

@@ -2,6 +2,7 @@ package com.yonge.cooleshow.biz.dal.service;
 
 import com.yonge.cooleshow.biz.dal.entity.MusicFavorite;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 
 import java.util.List;
 
@@ -18,9 +19,10 @@ public interface MusicFavoriteService extends IService<MusicFavorite> {
      *
      * @param userId 学生id
      * @param musicSheetId 专辑id
+     * @param clientType 客户端类型
      * @return list
      */
-    List<MusicFavorite> getFavorite(Long userId, Long musicSheetId);
+    List<MusicFavorite> getFavorite(Long userId, Long musicSheetId, ClientEnum clientType);
 
     /**
      * 获取曲目收藏数量

+ 9 - 6
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/MusicSheetService.java

@@ -18,7 +18,6 @@ import com.yonge.cooleshow.biz.dal.dto.search.TeacherMusicSheetAuditSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.TeacherMusicSheetSearch;
 import com.yonge.cooleshow.biz.dal.entity.MusicSheet;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
-import com.yonge.cooleshow.biz.dal.enums.MusicSheetType;
 import com.yonge.cooleshow.biz.dal.vo.HomeMusicSheetVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicSheetDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicSheetShareVo;
@@ -96,18 +95,20 @@ public interface MusicSheetService extends IService<MusicSheet> {
      *
      * @param page 分页
      * @param query 查询条件
+     * @param clientType ClientEnum
      * @return iPage 分页信息
      */
-    IPage<MusicSheetVo> selectStudentPage(IPage<MusicSheetVo> page, StudentMusicSheetSearch query);
+    IPage<MusicSheetVo> selectStudentPage(IPage<MusicSheetVo> page, StudentMusicSheetSearch query, ClientEnum clientType);
 
     /**
      * 收藏/取消收藏 曲目
      *
      * @param userId 用户id , 学生id
      * @param musicSheetId 曲目id
+     * @param clientType 客户端类型
      * @return boolean
      */
-    boolean setFavorite(Long userId, Long musicSheetId);
+    boolean setFavorite(Long userId, Long musicSheetId, ClientEnum clientType);
 
     /**
      * 我的单曲
@@ -124,9 +125,10 @@ public interface MusicSheetService extends IService<MusicSheet> {
      *
      * @param page 分页信息
      * @param query 查询条件
+     * @param clientType ClientEnum
      * @return
      */
-    IPage<MusicSheetVo> favoriteMusic(IPage<MusicSheetVo> page, StudentMusicSheetSearch query);
+    IPage<MusicSheetVo> favoriteMusic(IPage<MusicSheetVo> page, StudentMusicSheetSearch query, ClientEnum clientType);
 
     /**
      * 最近练习曲目
@@ -261,10 +263,11 @@ public interface MusicSheetService extends IService<MusicSheet> {
      * 官网曲目详情
      *
      * @param musicSheetId 曲目id
-     * @param sysUser
+     * @param sysUser SysUser
+     * @param clientType 客户端类型
      * @return
      */
-    MusicSheetWebsiteDetailVo websiteDetail(Long musicSheetId, SysUser sysUser);
+    MusicSheetWebsiteDetailVo websiteDetail(Long musicSheetId, SysUser sysUser, ClientEnum clientType);
 
     /**
      * 查询老师曲目审核数量

+ 199 - 19
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ActivityEvaluationRecordServiceImpl.java

@@ -1,43 +1,63 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
-import java.math.BigDecimal;
-import java.util.Date;
-import java.util.List;
-import java.util.Optional;
-
-import com.google.common.collect.Lists;
-import com.yonge.cooleshow.biz.dal.entity.ActivityPlan;
-import com.yonge.cooleshow.biz.dal.enums.activity.ActivityRankingRuleEnum;
-import com.yonge.cooleshow.biz.dal.service.ActivityPlanService;
-import org.apache.commons.collections.CollectionUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.common.collect.Lists;
 import com.yonge.cooleshow.biz.dal.dao.ActivityEvaluationRecordDao;
+import com.yonge.cooleshow.biz.dal.dao.ActivityPlanDao;
+import com.yonge.cooleshow.biz.dal.dao.StudentDao;
 import com.yonge.cooleshow.biz.dal.dto.search.ActivityEvaluationRecordSearch;
 import com.yonge.cooleshow.biz.dal.entity.ActivityEvaluation;
 import com.yonge.cooleshow.biz.dal.entity.ActivityEvaluationRecord;
+import com.yonge.cooleshow.biz.dal.entity.ActivityPlan;
+import com.yonge.cooleshow.biz.dal.entity.MusicSheet;
+import com.yonge.cooleshow.biz.dal.entity.Student;
+import com.yonge.cooleshow.biz.dal.entity.Subject;
+import com.yonge.cooleshow.biz.dal.enums.activity.ActivityRankingMethodEnum;
 import com.yonge.cooleshow.biz.dal.service.ActivityEvaluationRecordService;
 import com.yonge.cooleshow.biz.dal.service.ActivityEvaluationService;
+import com.yonge.cooleshow.biz.dal.service.ActivityPlanService;
+import com.yonge.cooleshow.biz.dal.service.MusicSheetService;
+import com.yonge.cooleshow.biz.dal.service.SubjectService;
 import com.yonge.cooleshow.biz.dal.vo.ActivityEvaluationRecordVo;
 import com.yonge.cooleshow.biz.dal.vo.ActivityRankingVo;
 import com.yonge.cooleshow.common.enums.ActivityResourceEnum;
 import com.yonge.toolset.base.exception.BizException;
+import com.yonge.toolset.base.util.ThreadPool;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.joda.time.DateTime;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
+@Slf4j
 @Service
 public class ActivityEvaluationRecordServiceImpl extends ServiceImpl<ActivityEvaluationRecordDao, ActivityEvaluationRecord> implements ActivityEvaluationRecordService {
-    private final static Logger log = LoggerFactory.getLogger(ActivityEvaluationRecordServiceImpl.class);
 
     @Autowired
     private ActivityEvaluationService activityEvaluationService;
-
+    @Autowired
+    private ActivityEvaluationRecordService activityEvaluationRecordService;
     @Autowired
     private ActivityPlanService activityPlanService;
+    @Autowired
+    private MusicSheetService musicSheetService;
+    @Autowired
+    private ActivityPlanDao activityPlanMapper;
+    @Autowired
+    private StudentDao studentMapper;
+    @Autowired
+    private SubjectService subjectService;
 
 	@Override
     public ActivityEvaluationRecordVo detail(Long id) {
@@ -63,10 +83,13 @@ public class ActivityEvaluationRecordServiceImpl extends ServiceImpl<ActivityEva
         if (activityEvaluation == null) {
             throw new BizException("未找到评测项目");
         }
+
+        // 记录曲目评测试分数
         ActivityEvaluationRecord activityEvaluationRecord = new ActivityEvaluationRecord();
         activityEvaluationRecord.setActivityId(activityEvaluation.getActivityId());
         activityEvaluationRecord.setUserId(userId);
         activityEvaluationRecord.setEvaluationId(evaluationId);
+        activityEvaluationRecord.setResourceId(activityEvaluation.getMusicSheetId());
         activityEvaluationRecord.setCreateTime(new Date());
         activityEvaluationRecord.setScore(score == null ? 0:score.doubleValue());
         
@@ -77,6 +100,99 @@ public class ActivityEvaluationRecordServiceImpl extends ServiceImpl<ActivityEva
         	activityEvaluationRecord.setTimes(lastestRecord.getTimes() + 1);
         }
         save(activityEvaluationRecord);
+
+        // 活动信息
+        ActivityPlan activity = activityPlanService.getById(activityEvaluation.getActivityId());
+        if (ActivityRankingMethodEnum.TOTAL_SCORE == activity.getRankingMethod()) {
+
+            // 若为总分评测,计算声部分数
+            ThreadPool.getExecutor().submit(() -> {
+
+                List<ActivityEvaluationRecord> records = activityEvaluationRecordService.list(Wrappers.<ActivityEvaluationRecord>lambdaQuery()
+                        .eq(ActivityEvaluationRecord::getActivityId, activityEvaluation.getActivityId())
+                        .eq(ActivityEvaluationRecord::getUserId, userId));
+
+                // 用户当前声部所有评测数据,获取单曲最高进行加和计算为声部最高分
+                Map<Long, Double> highestScoreMap = records.stream()
+                        .filter(x -> Optional.ofNullable(x.getScore()).orElse(0D) > 0)
+                        .filter(x -> Optional.ofNullable(x.getEvaluationId()).orElse(0L) > 0)
+                        .collect(Collectors.groupingBy(ActivityEvaluationRecord::getEvaluationId,
+                                Collectors.mapping(ActivityEvaluationRecord::getScore, Collectors.toSet())))
+                        .entrySet().stream()
+                        .collect(Collectors.toMap(Map.Entry::getKey,
+                                x -> x.getValue().stream().mapToDouble(Double::doubleValue).max().orElse(0D), (o, n) -> n));
+
+                // 最高分
+                double sumScore = highestScoreMap.values().stream().mapToDouble(Double::doubleValue).sum();
+
+                // 获取最高分的时间为每个单曲最高分的记录时间
+                Map<Long, Long> highestScoreTimeMap = records.stream()
+                        .filter(x -> Optional.ofNullable(x.getScore()).orElse(0D) > 0)
+                        .filter(x -> Optional.ofNullable(x.getEvaluationId()).orElse(0L) > 0)
+                        .filter(x -> highestScoreMap.getOrDefault(x.getEvaluationId(), -1D).doubleValue() == x.getScore())
+                        .collect(Collectors.groupingBy(ActivityEvaluationRecord::getEvaluationId, Collectors.mapping(x -> x.getCreateTime().getTime(), Collectors.toSet())))
+                        .entrySet().stream()
+                        .collect(Collectors.toMap(Map.Entry::getKey,
+                                x -> x.getValue().stream().mapToLong(Long::longValue).max().orElse(0L), (o, n) -> n));
+
+                // 最高分时间
+                long highScoreTime = highestScoreTimeMap.values().stream().mapToLong(Long::longValue).max().orElse(DateTime.now().getMillis());
+
+                // 若分总相同,最高分时间相同,则根据用户活动报名时间进行排序
+                Date registrationTime = records.stream()
+                        .filter(x -> Objects.isNull(x.getScore()))
+                        .min(Comparator.comparing(ActivityEvaluationRecord::getId))
+                        .map(ActivityEvaluationRecord::getCreateTime).orElse(DateTime.now().toDate());
+
+                // 查询用户声部评分记录
+                ActivityEvaluationRecord evaluationRecord = activityEvaluationRecordService.getOne(Wrappers.<ActivityEvaluationRecord>lambdaQuery()
+                        .eq(ActivityEvaluationRecord::getActivityId, activity.getId())
+                        .eq(ActivityEvaluationRecord::getUserId, userId)
+                        .eq(ActivityEvaluationRecord::getRankingMethod, activity.getRankingMethod())
+                );
+
+                if (Objects.isNull(evaluationRecord)) {
+
+                    MusicSheet musicSheet = musicSheetService.getById(activityEvaluation.getMusicSheetId());
+
+                    long subjectId = 0;
+                    if (Objects.nonNull(musicSheet)) {
+                        subjectId = Long.parseLong(musicSheet.getMusicSubject().split(",")[0]);
+                    }
+                    // 添加用户声部总分记录
+                    ActivityEvaluationRecord record = new ActivityEvaluationRecord();
+
+                    record.setActivityId(activityEvaluation.getActivityId());
+                    record.setUserId(userId);
+                    record.setEvaluationId(0L);
+                    // 声部ID
+                    record.setResourceId(subjectId);
+                    record.setRegistrationTime(registrationTime.getTime());
+                    record.setRankingMethod(activity.getRankingMethod());
+                    record.setTimes(0);
+                    // 最高分时间
+                    record.setCreateTime(new DateTime(highScoreTime).toDate());
+                    record.setScore(sumScore);
+
+                    save(record);
+                }
+
+                // 更新最高分记录
+                if (Objects.nonNull(evaluationRecord)
+                        && evaluationRecord.getScore() < sumScore) {
+
+                    ActivityEvaluationRecord record = new ActivityEvaluationRecord();
+
+                    record.setId(evaluationRecord.getId());
+                    record.setScore(sumScore);
+                    record.setCreateTime(new DateTime(highScoreTime).toDate());
+
+                    updateById(record);
+                }
+
+            });
+        }
+
     }
 
 
@@ -105,7 +221,41 @@ public class ActivityEvaluationRecordServiceImpl extends ServiceImpl<ActivityEva
         if (activityPlan == null) {
             throw new BizException("活动已结束");
         }
-		return baseMapper.queryRankingList(activityPlanId, activityEvaluationId, limit,activityPlan.getRankingRule());
+
+        List<ActivityRankingVo> activityRankings;
+        // 活动排名
+        if (ActivityRankingMethodEnum.TOTAL_SCORE == activityPlan.getRankingMethod()) {
+
+            // 总分排名, 根据声部ID进行查询
+            activityRankings = activityPlanMapper.selectActivityHighestScoreRankingInfo(activityPlanId, activityEvaluationId,
+                    1D, limit);
+
+            List<Long> userIds = activityRankings.stream()
+                    .map(ActivityRankingVo::getUserId).distinct().collect(Collectors.toList());
+
+            if (CollectionUtils.isNotEmpty(userIds)) {
+
+                Map<Long, Long> userSubjectMap = studentMapper.selectList(Wrappers.<Student>lambdaQuery().in(Student::getUserId, userIds)).stream()
+                        .filter(x -> Objects.nonNull(x.getSubjectId()))
+                        .collect(Collectors.toMap(Student::getUserId, x -> Long.parseLong(Optional.ofNullable(x.getSubjectId()).orElse("0").split(",")[0]), (o, n) -> n));
+
+
+                Map<Long, String> subjectNameMap = subjectService.findBySubjectByIdList(Lists.newArrayList(userSubjectMap.values())).stream()
+                        .collect(Collectors.toMap(Subject::getId, Subject::getName, (o, n) -> n));
+
+                for (ActivityRankingVo item : activityRankings) {
+
+                    item.setUserSubject(subjectNameMap.getOrDefault(userSubjectMap.get(item.getUserId()), ""));
+                }
+            }
+
+        } else {
+
+            // 单曲排名
+            activityRankings = baseMapper.queryRankingList(activityPlanId, activityEvaluationId, limit, activityPlan.getRankingRule());
+        }
+
+        return activityRankings;
 	}
 
 	@Override
@@ -114,7 +264,37 @@ public class ActivityEvaluationRecordServiceImpl extends ServiceImpl<ActivityEva
         if (activityPlan == null) {
             throw new BizException("活动已结束");
         }
-        return baseMapper.queryUserRanking(activityPlanId, activityEvaluationId, userId,activityPlan.getRankingRule());
+
+        // 用户排名信息
+        ActivityRankingVo userRanking;
+
+        if (ActivityRankingMethodEnum.TOTAL_SCORE == activityPlan.getRankingMethod()) {
+
+            // 总分排名
+            userRanking = activityPlanMapper.selectActivityHighestScoreUserRanking(activityPlanId, activityEvaluationId,
+                    1D, userId);
+
+            // 学生声部信息
+            Student student = studentMapper.selectOne(Wrappers.<Student>lambdaQuery().eq(Student::getUserId, userId));
+
+            long subjectId = 0;
+            if (Objects.nonNull(student.getSubjectId())) {
+                subjectId = Long.parseLong(student.getSubjectId().split(",")[0]);
+            }
+            Subject subject = subjectService.get(subjectId);
+
+            if (Objects.nonNull(userRanking)) {
+
+                userRanking.setUserSubject(Optional.ofNullable(subject).map(Subject::getName).orElse(""));
+            }
+
+        } else {
+
+            // 单曲排名
+            userRanking = baseMapper.queryUserRanking(activityPlanId, activityEvaluationId, userId, activityPlan.getRankingRule());
+        }
+
+        return userRanking;
 	}
 
     /**

+ 77 - 10
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ActivityEvaluationServiceImpl.java

@@ -15,6 +15,7 @@ import com.yonge.cooleshow.biz.dal.entity.ActivityEvaluation;
 import com.yonge.cooleshow.biz.dal.entity.ActivityPlan;
 import com.yonge.cooleshow.biz.dal.entity.ActivityPlanReward;
 import com.yonge.cooleshow.biz.dal.entity.Subject;
+import com.yonge.cooleshow.biz.dal.enums.activity.ActivityRankingMethodEnum;
 import com.yonge.cooleshow.biz.dal.service.ActivityEvaluationRecordService;
 import com.yonge.cooleshow.biz.dal.service.ActivityEvaluationService;
 import com.yonge.cooleshow.biz.dal.service.ActivityPlanRewardService;
@@ -26,9 +27,11 @@ import com.yonge.cooleshow.biz.dal.vo.ActivityMusicVo;
 import com.yonge.cooleshow.biz.dal.vo.ActivityRankingVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicSheetVo;
 import com.yonge.cooleshow.biz.dal.vo.activity.ActivityTeacherWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper;
 import com.yonge.cooleshow.common.enums.ActivityResourceEnum;
 import com.yonge.cooleshow.common.enums.ActivityTypeEnum;
 import com.yonge.cooleshow.common.enums.EStatus;
+import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import com.yonge.toolset.base.exception.BizException;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -68,7 +71,28 @@ public class ActivityEvaluationServiceImpl extends ServiceImpl<ActivityEvaluatio
 
     @Override
     public IPage<ActivityEvaluationVo> selectPage(IPage<ActivityEvaluationVo> page, ActivityEvaluationSearch query) {
-        return page.setRecords(baseMapper.selectPage(page, query));
+
+        ActivityPlan activity = activityPlanService.getById(query.getActivityId());
+        if (Objects.isNull(activity)) {
+            throw new BizException("无效的活动ID");
+        }
+
+        List<ActivityEvaluationVo> evaluationInfos = baseMapper.selectPage(page, query);
+        // 排序方式
+        if (ActivityTypeEnum.EVALUATION == activity.getActivityType()
+                && ActivityRankingMethodEnum.TOTAL_SCORE == activity.getRankingMethod()) {
+
+            // 按声部聚合数据返回
+            evaluationInfos = evaluationInfos.stream()
+                    .collect(Collectors.groupingBy(x -> Long.parseLong(x.getSubjectId().split(",")[0])))
+                    .entrySet().stream()
+                    .sorted(Map.Entry.comparingByKey())
+                    .flatMap(x -> x.getValue().stream())
+                    .collect(Collectors.toList());
+
+        }
+
+        return page.setRecords(evaluationInfos);
     }
 
     @Override
@@ -146,8 +170,9 @@ public class ActivityEvaluationServiceImpl extends ServiceImpl<ActivityEvaluatio
         activityContentIds.removeAll(oldMusicSheetIds);
 
         if ((oldMusicSheetIds.size() + activityContentIds.size()) > 10
+                && activity.getRankingMethod() == ActivityRankingMethodEnum.MUSIC_RANKING
                 && activityType == ActivityTypeEnum.EVALUATION) {
-
+            // 评测活动、曲目排名需要限制曲目数量
             throw new BizException("添加的曲目不能多余10首");
         }
         if (CollectionUtils.isNotEmpty(activityContentIds)) {
@@ -179,17 +204,59 @@ public class ActivityEvaluationServiceImpl extends ServiceImpl<ActivityEvaluatio
 
     @Override
     public List<ActivityMusicVo> getActivityMusic(Long activityPlanId, Long userId) {
+
+        // 活动曲目信息
         List<ActivityMusicVo> result = baseMapper.selectActivityMusic(activityPlanId, userId);
-        for (ActivityMusicVo activityMusicVo : result) {
-        	List<ActivityRankingVo> rankingList =  activityEvaluationRecordService.queryRankingList(activityPlanId, activityMusicVo.getEvaluationId(), 1);
-            if (rankingList != null && rankingList.size() > 0) {
-                activityMusicVo.setUserSubject(rankingList.get(0).getUserSubject());
-                activityMusicVo.setScore(rankingList.get(0).getScore());
-                activityMusicVo.setUserAvatar(rankingList.get(0).getUserAvatar());
-                activityMusicVo.setUsername(rankingList.get(0).getUsername());
-                activityMusicVo.setUserId(rankingList.get(0).getUserId());
+
+        // 活动信息
+        ActivityPlan activity = activityPlanService.getById(activityPlanId);
+        if (Objects.isNull(activity)) {
+            throw new BizException("无效的活动ID");
+        }
+
+        // 评测活动
+        if (ActivityTypeEnum.EVALUATION == activity.getActivityType()) {
+
+
+            // 单曲排名,计算每一个曲目的最高分
+            if (ActivityRankingMethodEnum.MUSIC_RANKING == activity.getRankingMethod()) {
+
+                result.parallelStream().forEach(item -> {
+
+                    List<ActivityRankingVo> rankingList =  activityEvaluationRecordService.queryRankingList(activityPlanId, item.getEvaluationId(), 1);
+                    if (rankingList != null && rankingList.size() > 0) {
+                        item.setUserSubject(rankingList.get(0).getUserSubject());
+                        item.setScore(rankingList.get(0).getScore());
+                        item.setUserAvatar(rankingList.get(0).getUserAvatar());
+                        item.setUsername(rankingList.get(0).getUsername());
+                        item.setUserId(rankingList.get(0).getUserId());
+                    }
+
+                });
+
+            }
+
+            // 总分排名
+            if (ActivityRankingMethodEnum.TOTAL_SCORE == activity.getRankingMethod()) {
+
+                Map<Long, Double> collect = Maps.newHashMap();
+                if (result.stream().anyMatch(x -> x.getJoin() == YesOrNoEnum.YES
+                        && Objects.nonNull(userId))) {
+
+                    collect = getBaseMapper().selectSubjectMusicHighestScoreStat(activity.getId(), userId).stream()
+                            .collect(Collectors.toMap(StatGroupWrapper::getId, StatGroupWrapper::getNumber, (o, n) -> n));
+                }
+
+                for (ActivityMusicVo item : result) {
+
+                    item.setScore(collect.getOrDefault(item.getEvaluationId(), 0D));
+                }
+
+
             }
+
         }
+
         return result;
     }
 

+ 93 - 28
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ActivityPlanEvaluationServiceImpl.java

@@ -1,6 +1,7 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.yonge.cooleshow.biz.dal.dao.ActivityPlanDao;
 import com.yonge.cooleshow.biz.dal.dto.ActivityPlanDto;
 import com.yonge.cooleshow.biz.dal.dto.ActivityPlanRewardDto;
 import com.yonge.cooleshow.biz.dal.dto.req.OrderPayReq;
@@ -10,6 +11,7 @@ import com.yonge.cooleshow.biz.dal.entity.ActivityPlanReward;
 import com.yonge.cooleshow.biz.dal.entity.ActivityUserReward;
 import com.yonge.cooleshow.biz.dal.enums.GoodTypeEnum;
 import com.yonge.cooleshow.biz.dal.enums.OrderTypeEnum;
+import com.yonge.cooleshow.biz.dal.enums.activity.ActivityRankingMethodEnum;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.vo.ActivityPlanVo;
 import com.yonge.cooleshow.biz.dal.vo.ActivityRankingVo;
@@ -52,6 +54,8 @@ public class ActivityPlanEvaluationServiceImpl extends ServiceImpl<ActivityPlanE
 
     @Autowired
     private ActivityEvaluationService activityEvaluationService;
+    @Autowired
+    private ActivityPlanDao activityPlanMapper;
 
     @Override
     public boolean createOrUpdate(ActivityPlanDto activityPlan) {
@@ -86,7 +90,7 @@ public class ActivityPlanEvaluationServiceImpl extends ServiceImpl<ActivityPlanE
     }
 
     @Override
-    @Transactional(rollbackFor = Exception.class)
+    //@Transactional(rollbackFor = Exception.class)
     public void successActivity(Long activityId) {
         //关闭未付款订单
         closeActivity(activityId);
@@ -110,53 +114,114 @@ public class ActivityPlanEvaluationServiceImpl extends ServiceImpl<ActivityPlanE
         } catch (ParseException e) {
             e.printStackTrace();
         }
-        for (ActivityEvaluation activityEvaluation : activityEvaluationList) {
+        // 总分排名发奖流程
+        if (ActivityRankingMethodEnum.TOTAL_SCORE == detail.getRankingMethod()) {
 
-            List<ActivityRankingVo> activityRankingVos = activityEvaluationRecordService.queryRankingList(activityId,
-                                                              activityEvaluation.getId(),detail.getRanking());
-            for (int i = 0; i < activityRankingVos.size(); i++) {
+            // 查询活动获奖用户信息
+            List<ActivityRankingVo> rankingInfos = activityPlanMapper.selectActivityHighestScoreRankingInfo(detail.getId(), null,
+                    detail.getRankingScore(), 9999);
 
-                ActivityRankingVo activityRankingVo = activityRankingVos.get(i);
+            if (CollectionUtils.isEmpty(detail.getActivityRewardList())) {
+                // 活动未关联奖品,忽略后续流程
+                return;
+            }
 
-                List<ActivityPlanRewardDto> activityPlanRewardDtos = rewardMap.get(i + 1 + "");
-                if (CollectionUtils.isEmpty(activityPlanRewardDtos)) {
-                    continue;
-                }
+            // 活动关联奖品ID
+            List<Long> activityRewardIds = detail.getActivityRewardList().stream()
+                    .map(ActivityPlanReward::getId).collect(Collectors.toList());
 
-                // 活动关联奖品ID
-                List<Long> activityRewardIds = activityPlanRewardDtos.stream()
-                                   .map(ActivityPlanReward::getId).collect(Collectors.toList());
+            int ranking = 0;
+            for (ActivityRankingVo rankingInfo : rankingInfos) {
 
-                //给用户发放奖品 传入用户id和活动id
-                List<Long> collect = activityRewardService.sendReward(activityRankingVo.getUserId(), activityId, activityRewardIds, date);
+                // 推送发奖消息给用户
+                List<Long> collect = activityRewardService.sendReward(rankingInfo.getUserId(), activityId, activityRewardIds, date);
 
-                // 保存奖品发放记录
-                for (ActivityPlanRewardDto item : activityPlanRewardDtos) {
+                // 活动奖品信息
+                for (ActivityPlanRewardDto reward : detail.getActivityRewardList()) {
 
                     ActivityUserReward activityUserReward = new ActivityUserReward();
                     activityUserReward.setActivityId(activityId);
-                    activityUserReward.setBizId(activityEvaluation.getId());
-                    activityUserReward.setUserId(activityRankingVo.getUserId());
+                    activityUserReward.setBizId(rankingInfo.getResourceId());
+                    activityUserReward.setUserId(rankingInfo.getUserId());
                     activityUserReward.setRankingRule(detail.getRankingRule());
-                    activityUserReward.setRanking(i+1);
-                    activityUserReward.setGrantFlag(0);
-                    activityUserReward.setWinningTime(activityRankingVo.getJoinDate());
+                    activityUserReward.setRanking(ranking++);
+                    // 奖品发送状态
+                    activityUserReward.setGrantFlag(collect.contains(reward.getId()) ? 1 : 0);
+                    // 获取最高分时间
+                    activityUserReward.setWinningTime(rankingInfo.getJoinDate());
                     activityUserReward.setCreateTime(date);
                     activityUserReward.setUpdateTime(date);
-                    activityUserReward.setRewardId(item.getRewardId());
+                    activityUserReward.setRewardId(reward.getRewardId());
 
-                    // 奖品发送状态
-                    if (collect.contains(item.getId())) {
-                        activityUserReward.setGrantFlag(1);
-                    }
+                    // 添加发放记录
                     activityUserRewardList.add(activityUserReward);
                 }
 
+                // 若奖品数量超过1000,提交数据刷新缓存
+                if (activityUserRewardList.size() > 1000) {
+
+                    // 提交奖品发放记录
+                    activityUserRewardService.saveBatch(activityUserRewardList);
+
+                    // 清除缓存数据
+                    activityUserRewardList.clear();
+                }
+            }
+
+        } else {
+
+            // 曲目排名发奖流程
+            for (ActivityEvaluation activityEvaluation : activityEvaluationList) {
+
+                List<ActivityRankingVo> activityRankingVos = activityEvaluationRecordService.queryRankingList(activityId,
+                        activityEvaluation.getId(),detail.getRanking());
+                for (int i = 0; i < activityRankingVos.size(); i++) {
+
+                    ActivityRankingVo activityRankingVo = activityRankingVos.get(i);
+
+                    List<ActivityPlanRewardDto> activityPlanRewardDtos = rewardMap.get(i + 1 + "");
+                    if (CollectionUtils.isEmpty(activityPlanRewardDtos)) {
+                        continue;
+                    }
+
+                    // 活动关联奖品ID
+                    List<Long> activityRewardIds = activityPlanRewardDtos.stream()
+                            .map(ActivityPlanReward::getId).collect(Collectors.toList());
+
+                    //给用户发放奖品 传入用户id和活动id
+                    List<Long> collect = activityRewardService.sendReward(activityRankingVo.getUserId(), activityId, activityRewardIds, date);
+
+                    // 保存奖品发放记录
+                    for (ActivityPlanRewardDto item : activityPlanRewardDtos) {
+
+                        ActivityUserReward activityUserReward = new ActivityUserReward();
+                        activityUserReward.setActivityId(activityId);
+                        activityUserReward.setBizId(activityEvaluation.getId());
+                        activityUserReward.setUserId(activityRankingVo.getUserId());
+                        activityUserReward.setRankingRule(detail.getRankingRule());
+                        activityUserReward.setRanking(i+1);
+                        activityUserReward.setGrantFlag(0);
+                        activityUserReward.setWinningTime(activityRankingVo.getJoinDate());
+                        activityUserReward.setCreateTime(date);
+                        activityUserReward.setUpdateTime(date);
+                        activityUserReward.setRewardId(item.getRewardId());
+
+                        // 奖品发送状态
+                        if (collect.contains(item.getId())) {
+                            activityUserReward.setGrantFlag(1);
+                        }
+                        activityUserRewardList.add(activityUserReward);
+                    }
+
+                }
             }
+
         }
-        if (!CollectionUtils.isEmpty(activityUserRewardList)) {
+
+        if (CollectionUtils.isNotEmpty(activityUserRewardList)) {
             activityUserRewardService.saveBatch(activityUserRewardList);
         }
+
         //发完奖后将库存归还
         // activityPlanRewardService.recoveryReward(activityId);
     }

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

@@ -6,9 +6,12 @@ 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.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dao.ActivityPlanDao;
+import com.yonge.cooleshow.biz.dal.dao.StudentDao;
+import com.yonge.cooleshow.biz.dal.dao.SubjectDao;
 import com.yonge.cooleshow.biz.dal.dto.ActivityPlanDto;
 import com.yonge.cooleshow.biz.dal.dto.ActivityPlanPayDto;
 import com.yonge.cooleshow.biz.dal.dto.ActivityPlanRewardDto;
@@ -22,8 +25,13 @@ import com.yonge.cooleshow.biz.dal.entity.ActivityPlan;
 import com.yonge.cooleshow.biz.dal.entity.ActivityPlanReward;
 import com.yonge.cooleshow.biz.dal.entity.ActivityRegistration;
 import com.yonge.cooleshow.biz.dal.entity.ActivityReward;
+import com.yonge.cooleshow.biz.dal.entity.Student;
+import com.yonge.cooleshow.biz.dal.entity.Subject;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.EQueryOp;
+import com.yonge.cooleshow.biz.dal.enums.MK;
 import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
+import com.yonge.cooleshow.biz.dal.enums.activity.ActivityRankingMethodEnum;
 import com.yonge.cooleshow.biz.dal.service.ActivityEvaluationRecordService;
 import com.yonge.cooleshow.biz.dal.service.ActivityEvaluationService;
 import com.yonge.cooleshow.biz.dal.service.ActivityPlanEvaluationService;
@@ -32,21 +40,33 @@ import com.yonge.cooleshow.biz.dal.service.ActivityPlanService;
 import com.yonge.cooleshow.biz.dal.service.ActivityPlanStandardService;
 import com.yonge.cooleshow.biz.dal.service.ActivityRegistrationService;
 import com.yonge.cooleshow.biz.dal.service.ActivityRewardService;
+import com.yonge.cooleshow.biz.dal.service.SubjectService;
 import com.yonge.cooleshow.biz.dal.service.SysMessageService;
 import com.yonge.cooleshow.biz.dal.vo.ActivityMusicVo;
 import com.yonge.cooleshow.biz.dal.vo.ActivityPlanVo;
+import com.yonge.cooleshow.biz.dal.vo.ActivityRankingVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicActivityVo;
 import com.yonge.cooleshow.biz.dal.vo.UserOrderDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.activity.ActivityTeacherWrapper;
 import com.yonge.cooleshow.biz.dal.vo.res.OrderCreateRes;
+import com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
-import com.yonge.cooleshow.common.enums.*;
+import com.yonge.cooleshow.common.enums.ActivityResourceEnum;
+import com.yonge.cooleshow.common.enums.ActivityShareEnum;
+import com.yonge.cooleshow.common.enums.ActivityTypeEnum;
+import com.yonge.cooleshow.common.enums.CacheNameEnum;
+import com.yonge.cooleshow.common.enums.EStatus;
+import com.yonge.cooleshow.common.enums.RegistrationMethodEnum;
+import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import com.yonge.toolset.base.exception.BizException;
 import com.yonge.toolset.base.util.StringUtil;
+import com.yonge.toolset.base.util.ThreadPool;
 import com.yonge.toolset.payment.util.DistributedLock;
 import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -104,6 +124,10 @@ public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, Activi
 
     @Autowired
     private RedissonClient redissonClient;
+    @Autowired
+    private StudentDao studentMapper;
+    @Autowired
+    private SubjectService subjectService;
 
     //保存/更新拓展字段
     private static final Map<ActivityTypeEnum, Consumer<ActivityPlanDto>> saveOrUpdateExpand = new HashMap<>();
@@ -169,9 +193,50 @@ public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, Activi
 
         List<ActivityPlanVo> wrappers = baseMapper.selectPage(page, query);
 
+        if (CollectionUtils.isEmpty(wrappers)) {
+            return page.setRecords(wrappers);
+        }
+
+        List<Long> activityIds = wrappers.stream()
+                .map(ActivityPlan::getId).distinct().collect(Collectors.toList());
+
+        // 参与人数
+        Map<Long, Integer> participantNumMap = Maps.newConcurrentMap();
+        // 获奖人数
+        Map<Long, Integer> winnerNumMap = Maps.newConcurrentMap();
+        Lists.partition(activityIds, 30).parallelStream().forEach(item ->
+
+            Lists.newArrayList(EQueryOp.values()).parallelStream().forEach(dataType -> {
+
+                switch (dataType) {
+                    case FUNCTION_1:
+                        // 参与人数
+                        Map<Long, Integer> participantMap = getBaseMapper().selectActivityParticipateStatInfo(activityIds).stream()
+                                .collect(Collectors.toMap(StatGroupWrapper::getId, StatGroupWrapper::getTotal, (o, n) -> n));
+
+                        participantNumMap.putAll(participantMap);
+                        break;
+                    case FUNCTION_2:
+                        // 获奖人数
+                        Map<Long, Integer> winnerMap = getBaseMapper().selectActivityWinnerStatInfo(activityIds).stream()
+                                .collect(Collectors.toMap(StatGroupWrapper::getId, StatGroupWrapper::getTotal, (o, n) -> n));
+
+                        winnerNumMap.putAll(winnerMap);
+                        break;
+                    default:
+                        break;
+                }
+
+            })
+        );
+
         // 分享活动-参与人数获奖人数相等
         for (ActivityPlanVo item : wrappers) {
 
+            // 参与人数、获奖人数
+            item.registrationNum(participantNumMap.getOrDefault(item.getId(), 0))
+                    .rewardNum(winnerNumMap.getOrDefault(item.getId(), 0));
+
             // 重置分享活动获奖与参与人数
             if (ActivityTypeEnum.SHARE == item.getActivityType()) {
                 item.setRegistrationNum(item.getRewardNum());
@@ -434,6 +499,11 @@ public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, Activi
     @Override
     public MusicActivityVo getActivityInfo(Long activityPlanId, SysUser user) {
         ActivityPlan activityPlan = this.getById(activityPlanId);
+
+        if (Objects.isNull(activityPlan)) {
+            throw new BizException("无效的活动ID");
+        }
+
         if (activityPlan.getActivityState() != 1) {
             activityPlan.setActivityState(0);
         }
@@ -447,9 +517,115 @@ public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, Activi
         }
 
 
-        // 活动曲目
-        List<ActivityMusicVo> activityMusicVoList = activityEvaluationService.getActivityMusic(activityPlanId, userId);
-        activityVo.setActivityMusicVoList(activityMusicVoList);
+        // 评测活动曲目信息
+        if (ActivityTypeEnum.EVALUATION == activityPlan.getActivityType()) {
+
+            // 活动曲目
+            List<ActivityMusicVo> activityMusicVoList = activityEvaluationService.getActivityMusic(activityPlanId, userId);
+            activityVo.setActivityMusicVoList(activityMusicVoList);
+
+            // 评测难度
+            String evaluationDifficulty = baseMapper.selectActivityPlanEvaluation(activityPlanId);
+            activityVo.setEvaluationDifficulty(evaluationDifficulty);
+
+            // 计算评测活动声部最高分
+            if (ActivityRankingMethodEnum.TOTAL_SCORE == activityPlan.getRankingMethod()) {
+
+                Map<String, List<ActivityMusicVo>> collect = activityMusicVoList.stream()
+                        .collect(Collectors.groupingBy(x -> x.getSubjectId().split(",")[0]));
+
+                // 曲目难度
+                Map<Integer, String> difficultyMap = Maps.newHashMap();
+                difficultyMap.put(0, "BEGINNER");
+                difficultyMap.put(1, "ADVANCED");
+                difficultyMap.put(2, "PERFORMER");
+                // FIXME:临时增加声部曲目难度字段
+                for (Map.Entry<String, List<ActivityMusicVo>> entry : collect.entrySet()) {
+
+                    int index = 0;
+                    for (ActivityMusicVo item : entry.getValue()) {
+
+                        if (StringUtils.isEmpty(item.getEvaluationDifficulty())) {
+
+                            item.setEvaluationDifficulty(difficultyMap.getOrDefault(index, "PERFORMER"));
+                        }
+
+                        index += 1;
+                    }
+                }
+
+                // 计算声部评测最高分
+                Map<String, ActivityRankingVo> highestScoreMap = Maps.newConcurrentMap();
+                collect.entrySet().parallelStream().forEach(item -> {
+
+                    // 单声部计算用户总分排名用户信息
+                    List<ActivityRankingVo> records = getBaseMapper().selectActivityHighestScoreRankingInfo(activityPlanId, Long.parseLong(item.getKey()),
+                            1D, 1);
+
+                    if (CollectionUtils.isNotEmpty(records)) {
+
+                        highestScoreMap.put(item.getKey(), records.get(0));
+                    }
+                });
+
+                // 用户学生身份声部信息
+                List<Long> userIds = highestScoreMap.values().stream()
+                        .map(ActivityRankingVo::getUserId).distinct().collect(Collectors.toList());
+
+                Map<Long, Long> userSubjectMap = Maps.newHashMap();
+                Map<Long, String> subjectNameMap = Maps.newHashMap();
+                if (CollectionUtils.isNotEmpty(userIds)) {
+
+                    userSubjectMap = studentMapper.selectList(Wrappers.<Student>lambdaQuery().in(Student::getUserId, userIds)).stream()
+                            .filter(x -> Objects.nonNull(x.getSubjectId()))
+                            .collect(Collectors.toMap(Student::getUserId, x -> Long.parseLong(Optional.ofNullable(x.getSubjectId()).orElse("0").split(",")[0]), (o, n) -> n));
+
+
+                    subjectNameMap = subjectService.findBySubjectByIdList(Lists.newArrayList(userSubjectMap.values())).stream()
+                            .collect(Collectors.toMap(Subject::getId, Subject::getName, (o, n) -> n));
+                }
+
+
+                List<MusicActivityVo.SubjectInfo> subjectInfos = Lists.newArrayList();
+                ActivityMusicVo musicVo;
+                ActivityRankingVo ranking;
+                for (Map.Entry<String, List<ActivityMusicVo>> entry : collect.entrySet()) {
+
+                    if (CollectionUtils.isEmpty(entry.getValue())) {
+                        continue;
+                    }
+
+                    musicVo = entry.getValue().get(0);
+
+                    MusicActivityVo.SubjectInfo subjectInfo = MusicActivityVo.SubjectInfo.builder()
+                            .subjectId(musicVo.getSubjectId().split(",")[0])
+                            .subjectName(musicVo.getMusicSubject())
+                            .join(entry.getValue().stream().anyMatch(x -> x.getJoin() == YesOrNoEnum.YES) ? 1 : 0)
+                            .userId(0L)
+                            .username("")
+                            .userAvatar("")
+                            .userSubject("")
+                            .score(0D)
+                            .musicNums(entry.getValue().size())
+                            .build();
+                    subjectInfos.add(subjectInfo);
+
+                    // 最高分记录
+                    if (highestScoreMap.containsKey(entry.getKey())) {
+
+                        ranking = highestScoreMap.get(entry.getKey());
+
+                        subjectInfo.userId(ranking.getUserId())
+                                .username(ranking.getUsername())
+                                .userAvatar(ranking.getUserAvatar())
+                                .userSubject(subjectNameMap.getOrDefault(userSubjectMap.get(ranking.getUserId()), ""))
+                                .score(ranking.getScore());
+                    }
+                }
+
+                activityVo.setSubjectInfos(subjectInfos);
+            }
+        }
 
         // 报名状态
         activityVo.setJoin(activityRegistrationService.getRegistration(userId, activityPlanId));
@@ -458,10 +634,6 @@ public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, Activi
         List<ActivityReward> activityRewardList = activityRewardService.getActivityReward(activityPlanId);
         activityVo.setActivityRewardList(activityRewardList);
 
-        // 评测难度
-        String evaluationDifficulty = baseMapper.selectActivityPlanEvaluation(activityPlanId);
-
-        activityVo.setEvaluationDifficulty(evaluationDifficulty);
         return activityVo;
     }
 
@@ -576,43 +748,94 @@ public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, Activi
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void activityState() {
-        List<ActivityPlan> list = baseMapper.activityState();
-        for (ActivityPlan plan : list) {
-            DistributedLock.of(redissonClient)
-                    .runIfLockToFunction(CacheNameEnum.LOCK_ACTIVITY_STOCK.getRedisKey(plan.getId())
-                            , (id) -> {
-                                ActivityPlan activityPlan = getById(id);
-                                if (activityPlan.getActivityState() == 0) {
-                                    activityPlan.setActivityState(1);
-                                    baseMapper.updateById(activityPlan);
-
-                                    //开始活动
-                                    Consumer<Long> afterFunction = startActivity.get(activityPlan.getActivityType());
-                                    if (!Objects.isNull(afterFunction)) {
-                                        afterFunction.accept(activityPlan.getId());
-                                    }
-                                } else {
-                                    activityPlan.setActivityState(0);
-                                    activityPlan.setRewardFlag(1);
-                                    baseMapper.updateById(activityPlan);
-
-                                    //完成活动
-                                    Consumer<Long> afterFunction = successActivity.get(activityPlan.getActivityType());
-                                    if (!Objects.isNull(afterFunction)) {
-                                        afterFunction.accept(activityPlan.getId());
-                                    }
-                                }
-                                return true;
-                            }, plan.getId(), 10l);
-        }
+
+        // 方法调整为异常执行,预防HTTP接口调用返回超时响应
+        ThreadPool.getExecutor().submit(() -> {
+
+            RLock lock = redissonClient.getLock(CacheNameEnum.LOCK_EVALUATION_CRON.getCode());
+            try {
+                if (lock.isLocked()) {
+                    log.warn("activityState {}, lockName={}", DateTime.now().toString(MK.TIME_PATTERN), lock.getName());
+                    return;
+                }
+
+                // 增加达标活动计算同步标识,前一个请求未执行完时忽略后续执行请求
+                lock.lock();
+
+                List<ActivityPlan> list = baseMapper.activityState();
+                for (ActivityPlan plan : list) {
+                    DistributedLock.of(redissonClient)
+                            .runIfLockToFunction(CacheNameEnum.LOCK_ACTIVITY_STOCK.getRedisKey(plan.getId())
+                                    , (id) -> {
+                                        ActivityPlan activityPlan = getById(id);
+                                        if (activityPlan.getActivityState() == 0) {
+                                            activityPlan.setActivityState(1);
+                                            baseMapper.updateById(activityPlan);
+
+                                            //开始活动
+                                            Consumer<Long> afterFunction = startActivity.get(activityPlan.getActivityType());
+                                            if (!Objects.isNull(afterFunction)) {
+                                                afterFunction.accept(activityPlan.getId());
+                                            }
+                                        } else {
+                                            activityPlan.setActivityState(0);
+                                            activityPlan.setRewardFlag(1);
+                                            baseMapper.updateById(activityPlan);
+
+                                            //完成活动
+                                            Consumer<Long> afterFunction = successActivity.get(activityPlan.getActivityType());
+                                            if (!Objects.isNull(afterFunction)) {
+                                                afterFunction.accept(activityPlan.getId());
+                                            }
+                                        }
+                                        return true;
+                                    }, plan.getId(), 10l);
+                }
+
+            } catch (Exception e) {
+                log.error("activityState time={}", DateTime.now().toString(MK.TIME_PATTERN), e);
+            } finally {
+                // 释放锁
+                if (lock.isLocked() && lock.isHeldByCurrentThread()) {
+                    lock.unlock(); // 删除同步标识
+                }
+            }
+
+        });
+
     }
 
-    @Override
     @Transactional(rollbackFor = Exception.class)
+    @Override
     public void activityIng() {
-        for (ActivityTypeEnum activityTypeEnum : activityIng.keySet()) {
-            activityIng.get(activityTypeEnum).accept(null);
-        }
+
+        // 当前处理任务调整为异步执行
+        ThreadPool.getExecutor().submit(() -> {
+
+            RLock lock = redissonClient.getLock(CacheNameEnum.LOCK_STANDARD_GIFT_CRON.getCode());
+            try {
+                if (lock.isLocked()) {
+                    log.warn("activityIng {}, lockName={}", DateTime.now().toString(MK.TIME_PATTERN), lock.getName());
+                    return;
+                }
+
+                // 增加达标活动计算同步标识,前一个请求未执行完时忽略后续执行请求
+                lock.lock();
+
+                for (ActivityTypeEnum activityTypeEnum : activityIng.keySet()) {
+                    activityIng.get(activityTypeEnum).accept(null);
+                }
+
+            } catch (Exception e) {
+                log.error("activityIng time={}", DateTime.now().toString(MK.TIME_PATTERN), e);
+            } finally {
+                // 释放锁
+                if (lock.isLocked() && lock.isHeldByCurrentThread()) {
+                    lock.unlock(); // 删除同步标识
+                }
+            }
+        });
+
     }
 
     @Override
@@ -635,10 +858,10 @@ public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, Activi
         List<Long> collect = saveOrUpdateRewardDto.getUpdateRewardDtoList().stream()
                 .map(ActivityPlanReward::getRewardId).distinct().collect(Collectors.toList());
 
-        long validRewardNums = activityRewardService.listByIds(collect).stream()
-                .filter(x -> x.getRewardClient().equals(activityPlan.getActivityClient().getCode()))
-                .count();
-        if (saveOrUpdateRewardDto.getUpdateRewardDtoList().size() != validRewardNums) {
+        String clientType = activityPlan.getActivityClient().getCode();
+        boolean invalidRewardNums = activityRewardService.listByIds(collect).stream()
+                .anyMatch(x -> !Lists.newArrayList(x.getRewardClient().split(",")).contains(clientType));
+        if (invalidRewardNums) {
             throw new BizException("添加奖品与活动客户端不匹配");
         }
 

+ 76 - 14
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ActivityPlanStandardServiceImpl.java

@@ -1,8 +1,13 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
+import com.alibaba.fastjson.JSON;
+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.google.common.collect.Lists;
 import com.yonge.cooleshow.biz.dal.dao.ActivityPlanStandardDao;
+import com.yonge.cooleshow.biz.dal.dao.UserFirstTimeDao;
 import com.yonge.cooleshow.biz.dal.dto.ActivityPlanDto;
 import com.yonge.cooleshow.biz.dal.dto.ActivityPlanRewardDto;
 import com.yonge.cooleshow.biz.dal.dto.search.UserFirstTimeSearch;
@@ -25,6 +30,7 @@ import com.yonge.cooleshow.common.enums.CacheNameEnum;
 import com.yonge.cooleshow.common.enums.ConditionMethodEnum;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import com.yonge.toolset.payment.util.DistributedLock;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.MapUtils;
 import org.joda.time.DateTime;
 import org.redisson.api.RedissonClient;
@@ -38,7 +44,6 @@ import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.stream.Collectors;
 
 
@@ -60,6 +65,8 @@ public class ActivityPlanStandardServiceImpl extends ServiceImpl<ActivityPlanSta
     private ActivityRegistrationService activityRegistrationService;
     @Autowired
     private RedissonClient redissonClient;
+    @Autowired
+    private UserFirstTimeDao userFirstTimeMapper;
 
     @Override
     public boolean createOrUpdate(ActivityPlanDto activityPlan) {
@@ -82,10 +89,12 @@ public class ActivityPlanStandardServiceImpl extends ServiceImpl<ActivityPlanSta
 
     @Override
     public void activityIng(Object param) {
+
         //查询当前进行的活动
         List<ActivityPlan> activityIds = activityPlanService.list(Wrappers.<ActivityPlan>lambdaQuery()
                 .eq(ActivityPlan::getActivityType, ActivityTypeEnum.STANDARD_GIFT)
                 .eq(ActivityPlan::getActivityState, 1)
+                //.ge(ActivityPlan::getActivityEnd, DateTime.now().toDate())
                 .select(ActivityPlan::getId));
 
         for (ActivityPlan activityPlan : activityIds) {
@@ -96,6 +105,7 @@ public class ActivityPlanStandardServiceImpl extends ServiceImpl<ActivityPlanSta
     }
 
     private Boolean dealActivityIng(Long activityId) {
+
         ActivityPlanVo detail = activityPlanService.detail(activityId);
         if (null == detail) {
             return true;
@@ -110,51 +120,103 @@ public class ActivityPlanStandardServiceImpl extends ServiceImpl<ActivityPlanSta
         search.setStartTime(detail.getActivityStart());
         search.setEndTime(detail.getActivityEnd());
         search.setUserType(detail.getActivityClient().getCode());
-
-        String timeType = planStandard.getCondition();
-        search.setTimeType(timeType);
+        search.setCalculationMethod(planStandard.getCalculationMethod());
+        search.setTimeType(planStandard.getCondition());
 
         // 达标活动匹配条件数
         int conditionNum = planStandard.getCondition().split(",").length;
 
+        // 分页查询达标活动匹配用户信息;在根据用户ID查询对应激活时间记录信息
+        IPage<UserFirstTime> page = new Page<>(1, 10);
+        userFirstTimeMapper.selectActivityParticipateUserPage(page, search.activityId(activityId));
+
+        // 当前匹配条件用户数
+        int limit = 30; // 分页行数
+        long maxPage = (page.getTotal() - 1) / limit + 1;
+
+        // 分页查询匹配用户信息
+        UserFirstTimeSearch query;
+        List<Long> userIds;
+        for (long pageNum = 1; pageNum <= maxPage; pageNum++) {
+
+            // 匹配用户ID
+            userIds = userFirstTimeMapper.selectActivityParticipateUserPage(new Page<>(pageNum, limit),
+                            search.activityId(activityId)).stream()
+                    .map(UserFirstTime::getUserId).distinct().collect(Collectors.toList());
+
+            if (CollectionUtils.isEmpty(userIds)) {
+                continue;
+            }
+
+            // 匹配用户查询条件
+            query = JSON.parseObject(JSON.toJSONString(search.userIds(userIds)), UserFirstTimeSearch.class);
+            //log.info("dealActivityIng query={}", JSON.toJSONString(query));
+
+            // 用户达标活动获奖发送记录
+            activityUserSendRewardRecordInfo(userIds, activityId, detail, planStandard, query, conditionNum);
+        }
+
+        return true;
+    }
+
+    /**
+     * 活动用户发奖记录信息
+     * @param userIds 发奖用户顺序
+     * @param activityId 活动ID
+     * @param detail ActivityPlanVo
+     * @param planStandard ActivityPlanStandard
+     * @param search UserFirstTimeSearch
+     * @param conditionNum 达标活动匹配条件
+     */
+    private void activityUserSendRewardRecordInfo(List<Long> userIds,
+                                                  Long activityId,
+                                                  ActivityPlanVo detail,
+                                                  ActivityPlanStandard planStandard,
+                                                  UserFirstTimeSearch search,
+                                                  int conditionNum) {
         // 用户激活时间
         Map<Long, List<Long>> userActiveTimeMap = userFirstTimeService.selectAllList(search).stream()
                 .collect(Collectors.groupingBy(UserFirstTime::getUserId,
                         Collectors.mapping(x -> new DateTime(x.getTime()).getMillis(), Collectors.toList())));
 
         if (MapUtils.isEmpty(userActiveTimeMap)) {
-            return true;
+            return;
         }
 
         List<ActivityPlanRewardDto> activityPlanRewardDtos = activityPlanRewardService.queryActivityPlanReward(activityId);
 
-        // 用户信息
-        for (Map.Entry<Long, List<Long>> entry : userActiveTimeMap.entrySet()) {
+        // 获然用户顺序信息
+        List<Long> collect;
+        for (Long userId : userIds) {
+
+            collect = userActiveTimeMap.getOrDefault(userId, Lists.newArrayList());
+            if (CollectionUtils.isEmpty(collect)) {
+                // 没有匹配用户信息
+                continue;
+            }
 
             if (ConditionMethodEnum.OR.equals(planStandard.getCalculationMethod())) {
 
                 // 满足其一
-                long timestamp = entry.getValue().stream().mapToLong(Long::longValue).min().orElse(0L);
+                long timestamp = collect.stream().mapToLong(Long::longValue).min().orElse(0L);
 
                 if (timestamp > 0) {
                     //给用户发奖
-                    sendUserReward(entry.getKey(), detail.getId(), new Date(timestamp), activityPlanRewardDtos);
+                    sendUserReward(userId, detail.getId(), new Date(timestamp), activityPlanRewardDtos);
                 }
 
             } else {
 
                 // 全部满足
-                long timestamp = entry.getValue().stream().mapToLong(Long::longValue).max().orElse(0L);
+                long timestamp = collect.stream().mapToLong(Long::longValue).max().orElse(0L);
 
-                if (timestamp > 0 && entry.getValue().size() == conditionNum) {
+                if (timestamp > 0 && collect.size() == conditionNum) {
                     //给用户发奖
-                    sendUserReward(entry.getKey(), detail.getId(), new Date(timestamp), activityPlanRewardDtos);
+                    sendUserReward(userId, detail.getId(), new Date(timestamp), activityPlanRewardDtos);
                 }
             }
-
         }
 
-        return true;
     }
 
     private void sendUserReward(Long userId, Long activityId, Date winningTime, List<ActivityPlanRewardDto> activityPlanRewardDtos) {

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

@@ -1,13 +1,20 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.yonge.cooleshow.biz.dal.dao.ActivityRegistrationDao;
+import com.yonge.cooleshow.biz.dal.dao.SubjectDao;
 import com.yonge.cooleshow.biz.dal.dto.search.ActivityRegistrationSearch;
 import com.yonge.cooleshow.biz.dal.entity.ActivityEvaluationRecord;
+import com.yonge.cooleshow.biz.dal.entity.ActivityPlan;
 import com.yonge.cooleshow.biz.dal.entity.ActivityRegistration;
+import com.yonge.cooleshow.biz.dal.entity.Subject;
+import com.yonge.cooleshow.biz.dal.enums.activity.ActivityRankingMethodEnum;
 import com.yonge.cooleshow.biz.dal.service.ActivityEvaluationRecordService;
+import com.yonge.cooleshow.biz.dal.service.ActivityPlanService;
 import com.yonge.cooleshow.biz.dal.service.ActivityRegistrationService;
+import com.yonge.cooleshow.biz.dal.service.SubjectService;
 import com.yonge.cooleshow.biz.dal.vo.ActivityRegistrationVo;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import lombok.extern.slf4j.Slf4j;
@@ -17,6 +24,7 @@ import org.springframework.stereotype.Service;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -26,6 +34,10 @@ public class ActivityRegistrationServiceImpl extends ServiceImpl<ActivityRegistr
 
     @Autowired
     private ActivityEvaluationRecordService activityEvaluationRecordService;
+    @Autowired
+    private ActivityPlanService activityPlanService;
+    @Autowired
+    private SubjectService subjectService;
 	@Override
     public ActivityRegistrationVo detail(Long id) {
         return baseMapper.detail(id);
@@ -40,22 +52,58 @@ public class ActivityRegistrationServiceImpl extends ServiceImpl<ActivityRegistr
         List<Long> userIds = activityUserInfos.stream()
                 .map(ActivityRegistration::getUserId).distinct().collect(Collectors.toList());
 
+        ActivityPlan activity = activityPlanService.getById(query.getActivityId());
         // 查询用户活动评测获排名最高记录
-        if (CollectionUtils.isNotEmpty(userIds)) {
+        if (CollectionUtils.isNotEmpty(userIds) && Objects.nonNull(activity)) {
+
+            if (ActivityRankingMethodEnum.TOTAL_SCORE == activity.getRankingMethod()) {
+
+                // 总分排名
+                Map<Long, ActivityEvaluationRecord> collect = activityEvaluationRecordService.list(Wrappers.<ActivityEvaluationRecord>lambdaQuery()
+                        .eq(ActivityEvaluationRecord::getActivityId, activity.getId())
+                        .in(ActivityEvaluationRecord::getUserId, userIds)
+                        .eq(ActivityEvaluationRecord::getRankingMethod, activity.getRankingMethod().getCode())).stream()
+                        .collect(Collectors.toMap(ActivityEvaluationRecord::getUserId, Function.identity(), (o, n) -> n));
+
+                // 声部信息
+                List<Long> subjectIds = collect.values().stream()
+                        .map(ActivityEvaluationRecord::getResourceId)
+                        .filter(Objects::nonNull).distinct().collect(Collectors.toList());
+
+                Map<Long, String> subjectNameMap = subjectService.findBySubjectByIdList(subjectIds).stream()
+                        .collect(Collectors.toMap(Subject::getId, Subject::getName, (o, n) -> n));
+
+                ActivityEvaluationRecord record;
+                for (ActivityRegistrationVo item : activityUserInfos) {
+
+                    if (collect.containsKey(item.getUserId())) {
+
+                        record = collect.get(item.getUserId());
+                        // 重置当前时间为用户最高排名时间
+                        item.score(record.getScore())
+                                .subjectName(subjectNameMap.getOrDefault(record.getResourceId(), ""))
+                                .scoreTime(record.getCreateTime());
+
+                    }
+                }
+
+            } else {
 
-            Map<Long, ActivityEvaluationRecord> collect = activityEvaluationRecordService.queryActivityUserHighestRankingInfo(query.getActivityId(), userIds).stream()
-                    .collect(Collectors.toMap(ActivityEvaluationRecord::getUserId, Function.identity(), (o, n) -> n));
+                // 单曲排名
+                Map<Long, ActivityEvaluationRecord> collect = activityEvaluationRecordService.queryActivityUserHighestRankingInfo(query.getActivityId(), userIds).stream()
+                        .collect(Collectors.toMap(ActivityEvaluationRecord::getUserId, Function.identity(), (o, n) -> n));
 
-            ActivityEvaluationRecord record;
-            for (ActivityRegistrationVo item : activityUserInfos) {
+                ActivityEvaluationRecord record;
+                for (ActivityRegistrationVo item : activityUserInfos) {
 
-                if (collect.containsKey(item.getUserId())) {
+                    if (collect.containsKey(item.getUserId())) {
 
-                    record = collect.get(item.getUserId());
-                    // 重置当前时间为用户最高排名时间
-                    item.score(record.getScore())
-                            .times(record.getTimes())
-                            .setCreateTime(record.getCreateTime());
+                        record = collect.get(item.getUserId());
+                        // 重置当前时间为用户最高排名时间
+                        item.score(record.getScore())
+                                .times(record.getTimes())
+                                .setCreateTime(record.getCreateTime());
+                    }
                 }
             }
         }

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

@@ -19,6 +19,7 @@ import com.yonge.cooleshow.biz.dal.entity.ActivityRewardChangeStock;
 import com.yonge.cooleshow.biz.dal.entity.CouponInfo;
 import com.yonge.cooleshow.biz.dal.entity.PianoRoomChangeRecord;
 import com.yonge.cooleshow.biz.dal.enums.*;
+import com.yonge.cooleshow.biz.dal.enums.activity.ActivityRankingMethodEnum;
 import com.yonge.cooleshow.biz.dal.mapper.CouponInfoMapper;
 import com.yonge.cooleshow.biz.dal.service.ActivityPlanRewardService;
 import com.yonge.cooleshow.biz.dal.service.ActivityPlanService;
@@ -39,8 +40,6 @@ import com.yonge.toolset.payment.util.DistributedLock;
 import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.MapUtils;
-import org.redisson.RedissonMultiLock;
-import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -281,7 +280,10 @@ public class ActivityRewardServiceImpl extends ServiceImpl<ActivityRewardDao, Ac
 
             // 扣减奖品库存
             int update = activityPlanRewardService.reduceStock(activityId, item.getId());
-            if (update == 0) {
+
+            // 排除总分排名用户库存限制
+            if (ActivityRankingMethodEnum.TOTAL_SCORE != activityPlan.getRankingMethod()
+                    && update == 0) {
                 continue;
             }
 

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

@@ -2,6 +2,7 @@ package com.yonge.cooleshow.biz.dal.service.impl;
 
 import com.yonge.cooleshow.biz.dal.entity.AlbumFavorite;
 import com.yonge.cooleshow.biz.dal.dao.AlbumFavoriteDao;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.AlbumFavoriteService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -33,20 +34,23 @@ public class AlbumFavoriteServiceImpl extends ServiceImpl<AlbumFavoriteDao,Album
     }
 
     @Override
-    public List<AlbumFavorite> getFavorite(Long studentId, Long albumId) {
+    public List<AlbumFavorite> getFavorite(Long studentId, Long albumId, ClientEnum clientType) {
 
         return this.lambdaQuery()
                     .eq(AlbumFavorite::getAlbumId, albumId)
                     .eq(AlbumFavorite::getUserId, studentId)
+                    .eq(AlbumFavorite::getClientType, clientType)
                     .list();
     }
 
     @Override
-    public List<Long> selectFavorite(Long userId, List<Long> albumIds) {
+    public List<Long> selectFavorite(Long userId, List<Long> albumIds, ClientEnum clientType) {
+
         List<AlbumFavorite> list = this.lambdaQuery()
-                                       .in(AlbumFavorite::getAlbumId, albumIds)
-                                       .eq(AlbumFavorite::getUserId, userId)
-                                       .list();
+                .in(AlbumFavorite::getAlbumId, albumIds)
+                .eq(AlbumFavorite::getUserId, userId)
+                .eq(AlbumFavorite::getClientType, clientType)
+                .list();
 
         if (CollectionUtils.isEmpty(list)) {
             return new ArrayList<>();

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

@@ -26,6 +26,7 @@ import com.yonge.cooleshow.biz.dal.vo.coupon.CouponIssueWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper;
 import com.yonge.cooleshow.common.enums.EStatus;
 import com.yonge.toolset.base.exception.BizException;
+import com.yonge.toolset.base.string.MessageFormatter;
 import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -36,6 +37,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.text.MessageFormat;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
@@ -167,6 +169,22 @@ public class CouponIssueServiceImp extends ServiceImpl<CouponIssueMapper, Coupon
             if (!throwE) return false;
             throw new BizException("优惠券已被禁用");
         }
+
+        List<Long> userIds = userParam.stream()
+                .map(UserParam::getUserId).distinct().collect(Collectors.toList());
+        // 判断用户领取数据限制
+        if (Optional.ofNullable(couponInfo.getQuantityLimit()).orElse(0) > 0
+                && CollectionUtils.isNotEmpty(userIds)) {
+
+            CouponInfoQuery.IssueStatQuery statQuery = CouponInfoQuery.IssueStatQuery.builder().userIds(userIds).build();
+            // 统计用户领取优惠券数量
+            List<StatGroupWrapper> groupWrappers = getBaseMapper().selectCouponIssueStatInfo(couponId, statQuery);
+
+            if (groupWrappers.stream().anyMatch(x -> x.getTotal() >= couponInfo.getQuantityLimit())) {
+                throw new BizException(MessageFormat.format("优惠券已领取,每人仅限{0}张", couponInfo.getQuantityLimit()));
+            }
+        }
+
         // 判断优惠券类型 设置优惠券时间
         Long startTime = null;
         Long endTime = null;

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

@@ -1314,7 +1314,7 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
         if (teacherId == null) {
         	Student student = studentService.getById(studentId);
         	Long subjectId = null;
-            if (student != null) {
+            if (student != null && student.getSubjectId() != null) {
             	subjectId = Long.parseLong(student.getSubjectId());
             }
             

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

@@ -1,21 +1,52 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.auth.config.CustomerServiceConfig;
+import com.yonge.cooleshow.biz.dal.config.RongCloudConfig;
 import com.yonge.cooleshow.biz.dal.dao.ImUserFriendDao;
 import com.yonge.cooleshow.biz.dal.dao.TeacherDao;
 import com.yonge.cooleshow.biz.dal.dto.BasicUserInfo;
 import com.yonge.cooleshow.biz.dal.entity.ImUserFriend;
+import com.yonge.cooleshow.biz.dal.enums.MK;
+import com.yonge.cooleshow.biz.dal.mapper.SysUserMapper;
 import com.yonge.cooleshow.biz.dal.service.ImUserFriendService;
+import com.yonge.cooleshow.biz.dal.wrapper.im.CustomerService;
+import com.yonge.toolset.base.exception.BizException;
+import io.rong.messages.BaseMessage;
+import io.rong.messages.FileMessage;
+import io.rong.messages.ImgMessage;
+import io.rong.messages.ImgTextMessage;
+import io.rong.messages.TxtMessage;
+import io.rong.models.message.PrivateMessage;
+import io.rong.models.message.PushExt;
+import io.rong.models.response.ResponseResult;
+import lombok.extern.slf4j.Slf4j;
+import net.coobird.thumbnailator.Thumbnails;
+import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.collections.CollectionUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
-import java.util.*;
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -24,15 +55,19 @@ import java.util.stream.Collectors;
  * @author zx
  * @since 2022-03-22 10:46:00
  */
+@Slf4j
 @Service("imUserFriendService")
 public class ImUserFriendServiceImpl extends ServiceImpl<ImUserFriendDao, ImUserFriend> implements ImUserFriendService {
 
-    private final static Logger log = LoggerFactory.getLogger(ImUserFriendServiceImpl.class);
-
     @Resource
     private TeacherDao teacherDao;
     @Resource
     private SysUserFeignService sysUserFeignService;
+    @Autowired
+    private CustomerServiceConfig customerServiceConfig;
+    @Autowired
+    private SysUserMapper sysUserMapper;
+
     @Override
     public ImUserFriendDao getDao() {
         return this.baseMapper;
@@ -99,5 +134,161 @@ public class ImUserFriendServiceImpl extends ServiceImpl<ImUserFriendDao, ImUser
         return imUserFriend;
     }
 
+    /**
+     * 新用户自动添加客服
+     *
+     * @param userId    新用户ID
+     * @param friendIds 好友ID
+     * @return Integer
+     */
+    @Override
+    public Integer registerUserBindCustomerService(Long userId, List<Long> friendIds) {
+
+        // 添加新用户好友
+        saveUserFriend(userId, Sets.newHashSet(friendIds));
+
+        try {
+
+            // 设置默认值
+            String customerMessage = customerServiceConfig.getCustomerMessage();
+            if (StringUtils.isEmpty(customerMessage)) {
+                customerMessage = MK.IM_SYS_FRIEND;
+            }
+
+            String customerTitle = customerServiceConfig.getCustomerTitle();
+            if (StringUtils.isEmpty(customerTitle)) {
+                customerTitle = MK.IM_SYS_TITLE;
+            }
+
+            // 发送消息
+            TxtMessage txtMessage = new TxtMessage(customerMessage, "");
+
+            // 拓展消息
+            PushExt pushExt = PushExt.build(customerTitle, 1,
+                    new PushExt.HW("channelId", "NORMAL"), new PushExt.VIVO("1"),
+                    new PushExt.APNs("", ""),
+                    new PushExt.OPPO(""));
+
+            // 发送用户IM通知消息
+            PrivateMessage privateMessage = new PrivateMessage()
+                    .setSenderId(String.valueOf(friendIds.get(0)))
+                    .setTargetId(new String[]{String.valueOf(userId)})
+                    .setObjectName(txtMessage.getType())
+                    .setContent(txtMessage)
+                    .setPushExt(pushExt)
+                    .setIsIncludeSender(1);
+
+            ResponseResult privateResult = RongCloudConfig.rongCloud.message.msgPrivate.send(privateMessage);
+            log.info("registerUserBindCustomerService userId={}, ret={}", userId, privateResult.getCode());
+        } catch (Exception e) {
+            log.error("registerUserBindCustomerService userId={}", userId, e);
+        }
+
+        return CollectionUtils.size(friendIds);
+    }
+
+    /**
+     * 发送系统客服消息
+     *
+     * @param sender 发送者
+     * @param info   CustomerService.NotifyMessage
+     */
+    @Override
+    public void sendCustomerServiceNotifyMessage(String sender, CustomerService.NotifyMessage info) {
+
+        // 发送者信息
+        com.yonge.cooleshow.biz.dal.entity.SysUser senderUser = sysUserMapper.selectOne(Wrappers.<com.yonge.cooleshow.biz.dal.entity.SysUser>lambdaQuery()
+                .eq(com.yonge.cooleshow.biz.dal.entity.SysUser::getPhone, sender));
+
+        if (Objects.isNull(senderUser)) {
+            throw new BizException("无效的客服联系方式");
+        }
+
+        LambdaQueryWrapper<com.yonge.cooleshow.biz.dal.entity.SysUser> wrapper = Wrappers.<com.yonge.cooleshow.biz.dal.entity.SysUser>lambdaQuery()
+                .select(com.yonge.cooleshow.biz.dal.entity.SysUser::getId,
+                        com.yonge.cooleshow.biz.dal.entity.SysUser::getUsername)
+                .in(com.yonge.cooleshow.biz.dal.entity.SysUser::getPhone, info.getReceives());
+
+        wrapper.last("LIMIT 1000");
+        // 接收者信息
+        List<com.yonge.cooleshow.biz.dal.entity.SysUser> sysUsers = sysUserMapper.selectList(wrapper);
+
+        // 发送图片消息
+        ImgMessage imgMessage = new ImgMessage(imageToBase64(info.getImgMessage(), "png"), "", info.getImgUrl());
+
+        // 发送文本消息
+        TxtMessage txtMessage = new TxtMessage(info.getTxtMessage(), "");
+
+        List<BaseMessage> messages = Lists.newArrayList(imgMessage, txtMessage);
+
+        // 拓展消息
+        PushExt pushExt = PushExt.build(info.getTitle(), 1,
+                new PushExt.HW("channelId", "NORMAL"), new PushExt.VIVO("1"),
+                new PushExt.APNs("", ""),
+                new PushExt.OPPO(""));
+
+        // 分批次发送用户消息
+        List<String> receiveUserIds = sysUsers.stream()
+                .map(com.yonge.cooleshow.biz.dal.entity.SysUser::getId)
+                .map(String::valueOf)
+                .collect(Collectors.toList());
+
+        String senderId = String.valueOf(senderUser.getId());
+        PrivateMessage privateMessage;
+        ResponseResult privateResult;
+        for (List<String> item : Lists.partition(receiveUserIds, 100)) {
+
+            try {
+
+                for (BaseMessage message : messages) {
+
+                    // 发送用户IM通知消息
+                    privateMessage = new PrivateMessage()
+                            .setSenderId(senderId)
+                            .setTargetId(item.toArray(new String[0]))
+                            .setObjectName(message.getType())
+                            .setContent(message)
+                            .setPushExt(pushExt)
+                            .setIsIncludeSender(0);
+
+                    privateResult = RongCloudConfig.rongCloud.message.msgPrivate.send(privateMessage);
+                    log.info("sendCustomerServiceNotifyMessage senderId={}, ret={}", senderId, privateResult.getCode());
+                }
+
+            } catch (Exception e) {
+                log.error("sendCustomerServiceNotifyMessage senderId={}", senderId, e);
+            }
+
+        }
+
+    }
+
+    public static String imageToBase64(String imgMessage, String suffix) {
+
+        Base64 encoder = new Base64();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+            URL url = new URL(imgMessage);
+            BufferedImage bufferedImage = Thumbnails.of(url).scale(0.1f).outputQuality(0.25f).asBufferedImage();
+            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+            ImageIO.write(bufferedImage, suffix, outputStream);
+
+            byte[] bytes = outputStream.toByteArray();
+            outputStream.close();
+            int length = bytes.length;
+            //文件大小不能超过393216 Bytes
+            if (length > 393216) {
+                throw new BizException("文件过大请调整 像素 或 文件大小");
+            }
+
+            ImageIO.write(bufferedImage, suffix, baos);
+        } catch (IOException e) {
+            log.error("imageToBase64", e);
+        }
+        return new String(encoder.encode((baos.toByteArray())));
+    }
+
+
+
 }
 

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

@@ -30,6 +30,9 @@ import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
+import com.alibaba.fastjson.JSON;
+import com.yonge.cooleshow.biz.dal.mapper.SysUserMapper;
+import com.yonge.cooleshow.biz.dal.wrapper.liveroom.LiveRoomWrapper;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.redisson.api.RBucket;
@@ -126,6 +129,8 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
 
     @Autowired
     private LiveBroadcastRoomMemberService liveBroadcastRoomMemberService;
+    @Autowired
+    private SysUserMapper sysUserMapper;
     /**
      * 生成房间UID
      *
@@ -1140,5 +1145,41 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
         roomInfo.setWhether_mic(whetherMic);
         roomInfoCache.set(roomInfo);
     }
+
+    /**
+     * 直播间详情信息
+     *
+     * @param liveRoomId 直播间编号
+     * @param userId 分享用户ID
+     * @return LiveRoomWrapper
+     */
+    @Override
+    public LiveRoomWrapper findLiveRoomDetailInfoByRoomId(String liveRoomId, Long userId) {
+
+        // 直播间信息
+        LiveRoom liveRoom = getBaseMapper().selectOne(Wrappers.<LiveRoom>lambdaQuery()
+                .eq(LiveRoom::getRoomUid, liveRoomId));
+        if (Objects.isNull(liveRoom)) {
+            return null;
+        }
+
+        LiveRoomWrapper roomWrapper = LiveRoomWrapper.from(JSON.toJSONString(liveRoom));
+
+        // 直播老师信息
+        com.yonge.cooleshow.biz.dal.entity.SysUser teacher = sysUserMapper.selectById(roomWrapper.getSpeakerId());
+        if (Objects.nonNull(teacher)) {
+
+            roomWrapper.setTeacher(JSON.parseObject(JSON.toJSONString(teacher), LiveRoomWrapper.UserInfo.class));
+        }
+
+        // 分享同学信息
+        if (Optional.ofNullable(userId).orElse(0L) > 0) {
+
+            com.yonge.cooleshow.biz.dal.entity.SysUser student = sysUserMapper.selectById(userId);
+            roomWrapper.setStudent(JSON.parseObject(JSON.toJSONString(student), LiveRoomWrapper.UserInfo.class));
+        }
+
+        return roomWrapper;
+    }
 }
 

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

@@ -4,6 +4,7 @@ import java.util.Date;
 import java.util.List;
 import java.util.stream.Collectors;
 
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -160,19 +161,20 @@ public class MusicAlbumServiceImpl extends ServiceImpl<MusicAlbumDao,MusicAlbum>
     }
 
     @Override
-    public YesOrNoEnum checkFavorite(Long studentId, Long albumId) {
-        List<AlbumFavorite> albumFavorites = albumFavoriteService.getFavorite(studentId,albumId);
+    public YesOrNoEnum checkFavorite(Long studentId, Long albumId, ClientEnum clientType) {
+        List<AlbumFavorite> albumFavorites = albumFavoriteService.getFavorite(studentId,albumId, clientType);
 
         return CollectionUtils.isEmpty(albumFavorites)?YesOrNoEnum.NO:YesOrNoEnum.YES;
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public Boolean setFavorite(Long studentId, Long albumId) {
-        List<AlbumFavorite> albumFavorites = albumFavoriteService.getFavorite(studentId,albumId);
+    public Boolean setFavorite(Long studentId, Long albumId, ClientEnum clientType) {
+        List<AlbumFavorite> albumFavorites = albumFavoriteService.getFavorite(studentId,albumId, clientType);
         if (CollectionUtils.isEmpty(albumFavorites)) {
             AlbumFavorite albumFavorite = new AlbumFavorite();
             albumFavorite.setAlbumId(albumId);
+            albumFavorite.setClientType(clientType);
             albumFavorite.setUserId(studentId);
             albumFavorite.setFavoriteTime(new Date());
             return albumFavoriteService.save(albumFavorite);
@@ -183,9 +185,9 @@ public class MusicAlbumServiceImpl extends ServiceImpl<MusicAlbumDao,MusicAlbum>
     }
 
     @Override
-    public IPage<MusicAlbumVo> favoriteAlbum(IPage<MusicAlbumVo> page, StudentMusicAlbumSearch search) {
+    public IPage<MusicAlbumVo> favoriteAlbum(IPage<MusicAlbumVo> page, StudentMusicAlbumSearch search, ClientEnum clientType) {
 
-        IPage<MusicAlbumVo> iPage = page.setRecords(baseMapper.selectFavoritePage(page, search));
+        IPage<MusicAlbumVo> iPage = page.setRecords(baseMapper.selectFavoritePage(page, search, clientType));
         List<MusicAlbumVo> records = iPage.getRecords();
         if (CollectionUtils.isEmpty(records)) {
             return iPage;
@@ -209,8 +211,8 @@ public class MusicAlbumServiceImpl extends ServiceImpl<MusicAlbumDao,MusicAlbum>
     }
 
     @Override
-    public IPage<MusicAlbumVo> selectStudentPage(IPage<MusicAlbumVo> page, MusicAlbumSearch query) {
-    	List<MusicAlbumVo> records = baseMapper.selectStudentPage(page, query);
+    public IPage<MusicAlbumVo> selectStudentPage(IPage<MusicAlbumVo> page, MusicAlbumSearch query, ClientEnum clientType) {
+    	List<MusicAlbumVo> records = baseMapper.selectStudentPage(page, query, clientType);
     	/*if(records == null || records.size() == 0){
     		query.setSubjectIdList(null);
     		records = baseMapper.selectStudentPage(page, query);
@@ -221,7 +223,7 @@ public class MusicAlbumServiceImpl extends ServiceImpl<MusicAlbumDao,MusicAlbum>
         if (query.getUserId() == null || CollectionUtils.isEmpty(albumIds)) {
             return iPage;
         }
-        albumIds = albumFavoriteService.selectFavorite(query.getUserId(),albumIds);
+        albumIds = albumFavoriteService.selectFavorite(query.getUserId(), albumIds, clientType);
         for (MusicAlbumVo record : records) {
             if(albumIds.contains(record.getId())) {
                 record.setFavorite(YesOrNoEnum.YES);

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

@@ -3,6 +3,7 @@ package com.yonge.cooleshow.biz.dal.service.impl;
 import com.yonge.cooleshow.biz.dal.entity.AlbumFavorite;
 import com.yonge.cooleshow.biz.dal.entity.MusicFavorite;
 import com.yonge.cooleshow.biz.dal.dao.MusicFavoriteDao;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.MusicFavoriteService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -31,10 +32,11 @@ public class MusicFavoriteServiceImpl extends ServiceImpl<MusicFavoriteDao,Music
     }
 
     @Override
-    public List<MusicFavorite> getFavorite(Long userId, Long musicSheetId) {
+    public List<MusicFavorite> getFavorite(Long userId, Long musicSheetId, ClientEnum clientType) {
         return this.lambdaQuery()
                    .eq(MusicFavorite::getMusicSheetId, musicSheetId)
                    .eq(MusicFavorite::getUserId, userId)
+                   .eq(MusicFavorite::getClientType, clientType)
                    .list();
 
     }

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

@@ -316,8 +316,8 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
     }
 
     @Override
-    public IPage<MusicSheetVo> selectStudentPage(IPage<MusicSheetVo> page, StudentMusicSheetSearch query) {
-    	List<MusicSheetVo> records = baseMapper.selectStudentMusicPage(page, query);
+    public IPage<MusicSheetVo> selectStudentPage(IPage<MusicSheetVo> page, StudentMusicSheetSearch query, ClientEnum clientType) {
+    	List<MusicSheetVo> records = baseMapper.selectStudentMusicPage(page, query, clientType);
     	
     	/*if(query.getMyself() != null && query.getMyself() == false){//首页
         	if(records == null || records.size() == 0){
@@ -345,11 +345,12 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public boolean setFavorite(Long userId, Long musicSheetId) {
-        List<MusicFavorite> musicFavorites = musicFavoriteService.getFavorite(userId, musicSheetId);
+    public boolean setFavorite(Long userId, Long musicSheetId, ClientEnum clientType) {
+        List<MusicFavorite> musicFavorites = musicFavoriteService.getFavorite(userId, musicSheetId, clientType);
         if (CollectionUtils.isEmpty(musicFavorites)) {
             MusicFavorite musicFavorite = new MusicFavorite();
             musicFavorite.setMusicSheetId(musicSheetId);
+            musicFavorite.setClientType(clientType);
             musicFavorite.setUserId(userId);
             musicFavorite.setFavoriteTime(new Date());
             return musicFavoriteService.save(musicFavorite);
@@ -366,8 +367,8 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
     }
 
     @Override
-    public IPage<MusicSheetVo> favoriteMusic(IPage<MusicSheetVo> page, StudentMusicSheetSearch query) {
-        return page.setRecords(baseMapper.selectFavoriteMusicPage(page, query));
+    public IPage<MusicSheetVo> favoriteMusic(IPage<MusicSheetVo> page, StudentMusicSheetSearch query, ClientEnum clientType) {
+        return page.setRecords(baseMapper.selectFavoriteMusicPage(page, query, clientType));
     }
 
     @Override
@@ -380,6 +381,9 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
             page.setRecords(new ArrayList<>());
             return page;
         }
+
+        // 设置学生端收藏联系
+        query.setClientType(ClientEnum.STUDENT);
         // 构建分页信息
         page.setRecords(baseMapper.selectPracticeMusicPage(query, practiceMusicIdList));
         page.setPages(practiceMusicIdPage.getPages());
@@ -427,7 +431,17 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
         musicSheet.setUpdateBy(userId);
         musicSheet.setUpdateTime(new Date());
         if (AuthStatusEnum.PASS.getCode().equals(param.getAuthStatus().getCode())) {
-            musicSheet.setState(YesOrNoEnum.YES);
+
+            // 更新曲谱评测,指法、简谱、节拍器状态
+            musicSheet
+                    .notation(param.getNotation())
+                    .canEvaluate(param.getCanEvaluate())
+                    .showFingering(param.getShowFingering())
+                    //.hasBeat(param.getHasBeat())
+                    .mp3Type(param.getMp3Type())
+                    //.audioType(param.getAudioType())
+                    //.audioFileUrl(param.getAudioFileUrl())
+                    .setState(YesOrNoEnum.YES);
             // 替换曲目id
             replaceMusicSheet(param, musicSheet, originalMusicSheetId);
 
@@ -453,7 +467,6 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
 
     private void replaceMusicSheet(TeacherMusicSheetAuditReq param, MusicSheet musicSheet, Long originalMusicSheetId) {
         if (!musicSheet.getId().equals(originalMusicSheetId)) {
-            musicSheet.setId(originalMusicSheetId);
             MusicSheet originalMusicSheet = getById(originalMusicSheetId);
             originalMusicSheet.setId(param.getMusicSheetId());
             this.saveOrUpdate(originalMusicSheet);
@@ -474,6 +487,7 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
                 return;
             }
             musicSheetAccompanimentService.saveOrUpdateBatch(musicSheetAccompanimentList);
+            musicSheet.setId(originalMusicSheetId);
         }
     }
 
@@ -547,10 +561,16 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
         if (musicSheetDto.getAuditVersion() == null) {
             musicSheetDto.setAuditVersion(YesOrNoEnum.NO);
         }
-        if (musicSheetDto.getChargeType().equals(ChargeTypeEnum.VIP) || musicSheetDto.getChargeType().equals(ChargeTypeEnum.FREE)) {
+        List<String> collect = Arrays.stream(musicSheetDto.getPaymentType().split(",")).collect(Collectors.toList());
+        // 非付费方式,默认曲目价格为0
+        if (!collect.contains(ChargeTypeEnum.CHARGE.getCode())) {
             musicSheetDto.setMusicPrice(BigDecimal.ZERO);
         }
 
+        /*if (musicSheetDto.getChargeType().equals(ChargeTypeEnum.VIP) || musicSheetDto.getChargeType().equals(ChargeTypeEnum.FREE)) {
+            musicSheetDto.setMusicPrice(BigDecimal.ZERO);
+        }*/
+
         // 删除曲目专辑关联
         if (oldMusicSheet != null && !oldMusicSheet.getMusicSubject().equals(musicSheetDto.getMusicSubject())) {
             delAlbumSheetRef(musicSheetDto.getId(), musicSheetDto.getMusicSubject());
@@ -943,7 +963,7 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
     }
 
     @Override
-    public MusicSheetWebsiteDetailVo websiteDetail(Long musicSheetId, SysUser sysUser) {
+    public MusicSheetWebsiteDetailVo websiteDetail(Long musicSheetId, SysUser sysUser, ClientEnum clientType) {
         MusicSheetDetailVo detail = detail(musicSheetId, null, null);
         MusicSheetWebsiteDetailVo musicSheetWebsiteDetailVo = new MusicSheetWebsiteDetailVo();
         BeanUtils.copyProperties(detail, musicSheetWebsiteDetailVo);
@@ -976,7 +996,7 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
             }
 
             // 曲目收藏
-            List<MusicFavorite> favorite = musicFavoriteService.getFavorite(sysUser.getId(), detail.getId());
+            List<MusicFavorite> favorite = musicFavoriteService.getFavorite(sysUser.getId(), detail.getId(), clientType);
             if (!CollectionUtils.isEmpty(favorite)) {
                 musicSheetWebsiteDetailVo.setFavorite(YesOrNoEnum.YES);
             }

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

@@ -636,8 +636,12 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
     	}
     	
     	Student student = studentService.getById(userId);
+        Long subjectId = null;
+        if (student.getSubjectId()!= null) {
+            subjectId = Long.parseLong(student.getSubjectId());
+        }
     	
-    	List<HotTeacherVo> hotTeacherList = baseMapper.queryHotTeacherList(Long.parseLong(student.getSubjectId()));
+    	List<HotTeacherVo> hotTeacherList = baseMapper.queryHotTeacherList(subjectId);
     	for(HotTeacherVo vo : hotTeacherList){
     		if(watchTeacherIdList.contains(vo.getUserId())){
     			vo.setWatch(true);

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

@@ -2,15 +2,15 @@ package com.yonge.cooleshow.biz.dal.service.impl;
 
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.yonge.cooleshow.biz.dal.dao.UserFirstTimeDao;
 import com.yonge.cooleshow.biz.dal.dto.search.UserFirstTimeSearch;
+import com.yonge.cooleshow.biz.dal.entity.UserFirstTime;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.service.UserFirstTimeService;
 import com.yonge.cooleshow.common.enums.UserFirstTimeTypeEnum;
-import org.springframework.stereotype.Service;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import com.yonge.cooleshow.biz.dal.entity.UserFirstTime;
-import com.yonge.cooleshow.biz.dal.dao.UserFirstTimeDao;
-import com.yonge.cooleshow.biz.dal.service.UserFirstTimeService;
+import org.springframework.stereotype.Service;
 
 import java.util.Date;
 import java.util.List;

+ 17 - 10
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserOrderServiceImpl.java

@@ -66,6 +66,7 @@ import com.yonge.toolset.payment.core.service.PaymentClient;
 import com.yonge.toolset.payment.util.DistributedLock;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.joda.time.DateTime;
 import org.redisson.api.RedissonClient;
 import org.springframework.beans.BeanUtils;
@@ -337,7 +338,10 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
         //验证参数,必须验证参数
         BigDecimal actualPrice = BigDecimal.ZERO;
         // 订单优惠券信息
-        CouponOrderWrapper couponOrderWrapper = CouponOrderWrapper.builder().couponInfos(Lists.newArrayList()).build();
+        CouponOrderWrapper couponOrderWrapper = CouponOrderWrapper.builder()
+                .discountedPrices(0D)
+                .couponInfos(Lists.newArrayList())
+                .build();
 
         for (OrderReq.OrderReqInfo info : orderReq.getOrderInfos()) {
             Function<OrderReq.OrderReqInfo, HttpResponseResult<OrderCreateRes>> createFunction = orderCreate.get(info.getGoodType());
@@ -364,15 +368,18 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
             }
 
             // 计算优惠券金额
-            couponOrderWrapper = couponInfoService.queryUserOrderCouponInfo(orderReq.getUserId(),
-                    CouponInfoQuery.CouponOrderQuery.builder()
-                            .clientType(orderReq.getOrderClient())
-                            .couponTypes(CouponCategoryEnum.getCategory(orderReq.getOrderType().getCode()))
-                            .useState(CouponUseStateEnum.USABLE)
-                            .timestamp(DateTime.now().getMillis())
-                            .amount(createRes.getExpectPrice().doubleValue())
-                            .build()
-                            .issueIds(orderReq.getCouponId()));
+            if (StringUtils.isNotEmpty(orderReq.getCouponId())) {
+
+                couponOrderWrapper = couponInfoService.queryUserOrderCouponInfo(orderReq.getUserId(),
+                        CouponInfoQuery.CouponOrderQuery.builder()
+                                .clientType(orderReq.getOrderClient())
+                                .couponTypes(CouponCategoryEnum.getCategory(orderReq.getOrderType().getCode()))
+                                .useState(CouponUseStateEnum.USABLE)
+                                .timestamp(DateTime.now().getMillis())
+                                .amount(createRes.getExpectPrice().doubleValue())
+                                .build()
+                                .issueIds(orderReq.getCouponId()));
+            }
 
             //log.info("executeOrder couponId={}, wrapper={}", orderReq.getCouponId(), couponOrderWrapper.jsonString());
 

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

@@ -280,6 +280,9 @@ public class UserWithdrawalServiceImpl extends ServiceImpl<UserWithdrawalDao, Us
 
                 UserAccountRecordVo detail = accountRecordService.detail(null, AccountBizTypeEnum.WITHDRAWAL, Long.parseLong(authOperaReq.getId()));
                 userAccountService.accountChange(detail, PostStatusEnum.CANCEL);
+
+                // 结算失崺,重置为DOING;否则审核流程异常
+                build.setAuthStatus(AuthStatusEnum.DOING);
             }
         } else {
             //审核不通过,账户解冻

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

@@ -26,6 +26,9 @@ public class ActivityEvaluationVo extends ActivityEvaluation{
 	@ApiModelProperty(value = "销售价格")
 	private BigDecimal musicPrice;
 
+	@ApiModelProperty(value = "曲目声部ID")
+	private String subjectId;
+
 	public String getMusicSheetName() {
 		return musicSheetName;
 	}
@@ -65,4 +68,12 @@ public class ActivityEvaluationVo extends ActivityEvaluation{
 	public void setMusicPrice(BigDecimal musicPrice) {
 		this.musicPrice = musicPrice;
 	}
+
+	public String getSubjectId() {
+		return subjectId;
+	}
+
+	public void setSubjectId(String subjectId) {
+		this.subjectId = subjectId;
+	}
 }

+ 70 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/ActivityMusicVo.java

@@ -47,6 +47,18 @@ public class ActivityMusicVo {
     @ApiModelProperty("最高分用户声部")
     private String userSubject;
 
+    @ApiModelProperty("声部ID")
+    private String subjectId;
+
+    @ApiModelProperty("作曲人")
+    private String composer;
+
+    @ApiModelProperty("曲目图片")
+    private String musicImage;
+
+    @ApiModelProperty("评测难度 BEGINNER 入门级 ADVANCED 进阶级 PERFORMER 大师级")
+    private String  evaluationDifficulty;
+
     public Long getUserId() {
         return userId;
     }
@@ -126,4 +138,62 @@ public class ActivityMusicVo {
     public void setUserSubject(String userSubject) {
         this.userSubject = userSubject;
     }
+
+    public String getSubjectId() {
+        return subjectId;
+    }
+
+    public void setSubjectId(String subjectId) {
+        this.subjectId = subjectId;
+    }
+
+    public String getComposer() {
+        return composer;
+    }
+
+    public void setComposer(String composer) {
+        this.composer = composer;
+    }
+
+    public String getEvaluationDifficulty() {
+        return evaluationDifficulty;
+    }
+
+    public void setEvaluationDifficulty(String evaluationDifficulty) {
+        this.evaluationDifficulty = evaluationDifficulty;
+    }
+
+    public String getMusicImage() {
+        return musicImage;
+    }
+
+    public void setMusicImage(String musicImage) {
+        this.musicImage = musicImage;
+    }
+
+
+    public ActivityMusicVo score(double score) {
+        this.score = score;
+        return this;
+    }
+
+    public ActivityMusicVo userId(Long userId) {
+        this.userId = userId;
+        return this;
+    }
+
+    public ActivityMusicVo userAvatar(String userAvatar) {
+        this.userAvatar = userAvatar;
+        return this;
+    }
+
+    public ActivityMusicVo username(String username) {
+        this.username = username;
+        return this;
+    }
+
+    public ActivityMusicVo userSubject(String userSubject) {
+        this.userSubject = userSubject;
+        return this;
+    }
 }

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

@@ -83,4 +83,15 @@ public class ActivityPlanVo extends ActivityPlan{
 	public void setUpdateByName(String updateByName) {
 		this.updateByName = updateByName;
 	}
+
+
+	public ActivityPlanVo registrationNum(Integer registrationNum) {
+		this.registrationNum = registrationNum;
+		return this;
+	}
+
+	public ActivityPlanVo rewardNum(Integer rewardNum) {
+		this.rewardNum = rewardNum;
+		return this;
+	}
 }

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

@@ -27,6 +27,9 @@ public class ActivityRankingVo {
     @ApiModelProperty("次数")
     private int times;
 
+	@ApiModelProperty("资源ID")
+	private Long resourceId;
+
 	public double getScore() {
 		return score;
 	}
@@ -82,4 +85,12 @@ public class ActivityRankingVo {
 	public void setTimes(int times) {
 		this.times = times;
 	}
+
+	public Long getResourceId() {
+		return resourceId;
+	}
+
+	public void setResourceId(Long resourceId) {
+		this.resourceId = resourceId;
+	}
 }

+ 38 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/ActivityRegistrationVo.java

@@ -1,9 +1,13 @@
 package com.yonge.cooleshow.biz.dal.vo;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
 import com.yonge.cooleshow.biz.dal.entity.ActivityRegistration;
+import com.yonge.cooleshow.biz.dal.enums.MK;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
+import java.util.Date;
+
 /**
  * @Author: liweifan
  * @Data: 2022-08-04 10:19:49
@@ -39,9 +43,17 @@ public class ActivityRegistrationVo extends ActivityRegistration{
 	// 用户高最排名信息
 	@ApiModelProperty("最高排名分数")
 	private Double score;
+	
 	@ApiModelProperty("最高排名次数")
 	private Integer times;
 
+	@ApiModelProperty("曲子声部")
+	private String subjectName;
+
+	@ApiModelProperty("最高分时间")
+	@JsonFormat(pattern = MK.TIME_PATTERN, timezone = MK.TIME_ZONE)
+	private Date scoreTime;
+
 	public String getRealName() {
 		return realName;
 	}
@@ -122,6 +134,22 @@ public class ActivityRegistrationVo extends ActivityRegistration{
 		this.times = times;
 	}
 
+	public String getSubjectName() {
+		return subjectName;
+	}
+
+	public void setSubjectName(String subjectName) {
+		this.subjectName = subjectName;
+	}
+
+	public Date getScoreTime() {
+		return scoreTime;
+	}
+
+	public void setScoreTime(Date scoreTime) {
+		this.scoreTime = scoreTime;
+	}
+
 	public ActivityRegistrationVo score(Double score) {
 		this.score = score;
 		return this;
@@ -131,4 +159,14 @@ public class ActivityRegistrationVo extends ActivityRegistration{
 		this.times = times;
 		return this;
 	}
+
+	public ActivityRegistrationVo subjectName(String subjectName) {
+		this.subjectName = subjectName;
+		return this;
+	}
+
+	public ActivityRegistrationVo scoreTime(Date scoreTime) {
+		this.scoreTime = scoreTime;
+		return this;
+	}
 }

+ 15 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/CourseStudent.java

@@ -5,6 +5,8 @@ import io.swagger.annotations.ApiModelProperty;
 
 import java.io.Serializable;
 import java.util.Date;
+import java.util.Objects;
+import java.util.Optional;
 
 /**
  * @Author: cy
@@ -65,6 +67,9 @@ public class CourseStudent implements Serializable {
     @ApiModelProperty(value = "老师评价 0:未评价 1:已评价")
     private Integer teacherReplied;
 
+    @ApiModelProperty(value = "课程名称")
+    private String courseName;
+
     public Integer getStudentReplied() {
         return studentReplied;
     }
@@ -154,7 +159,8 @@ public class CourseStudent implements Serializable {
     }
 
     public String getName() {
-        return name;
+
+        return Optional.ofNullable(name).orElse(getCourseName());
     }
 
     public void setName(String name) {
@@ -208,5 +214,13 @@ public class CourseStudent implements Serializable {
     public void setImGroupId(String imGroupId) {
         this.imGroupId = imGroupId;
     }
+
+    public String getCourseName() {
+        return courseName;
+    }
+
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
 }
 

+ 79 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/MusicActivityVo.java

@@ -5,7 +5,12 @@ import com.yonge.cooleshow.biz.dal.entity.ActivityReward;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 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.util.List;
 
 /**
@@ -29,6 +34,9 @@ public class MusicActivityVo extends ActivityPlan {
     @ApiModelProperty("是否已经报名参与 0 :否 1:是")
     private YesOrNoEnum join;
 
+    @ApiModelProperty("活动声部信息")
+    private List<SubjectInfo> subjectInfos;
+
     public YesOrNoEnum getJoin() {
         return join;
     }
@@ -60,4 +68,75 @@ public class MusicActivityVo extends ActivityPlan {
     public void setEvaluationDifficulty(String evaluationDifficulty) {
         this.evaluationDifficulty = evaluationDifficulty;
     }
+
+    public List<SubjectInfo> getSubjectInfos() {
+        return subjectInfos;
+    }
+
+    public void setSubjectInfos(List<SubjectInfo> subjectInfos) {
+        this.subjectInfos = subjectInfos;
+    }
+
+    /**
+     * 活动曲目声部信息
+     */
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class SubjectInfo implements Serializable {
+
+        @ApiModelProperty("声部ID")
+        private String subjectId;
+
+        @ApiModelProperty("声部名称")
+        private String subjectName;
+
+        @ApiModelProperty("是否已经报名参与 ")
+        private Integer join;
+
+        @ApiModelProperty("最高分")
+        private double score;
+
+        @ApiModelProperty("最高分的用户id")
+        private Long userId;
+
+        @ApiModelProperty("最高分用户头像")
+        private String userAvatar;
+
+        @ApiModelProperty("最高分用户声部")
+        private String userSubject;
+
+        @ApiModelProperty("最高分用户名")
+        private String username;
+
+        @ApiModelProperty("声部曲目数")
+        private Integer musicNums;
+
+
+        public SubjectInfo score(double score) {
+            this.score = score;
+            return this;
+        }
+
+        public SubjectInfo userId(Long userId) {
+            this.userId = userId;
+            return this;
+        }
+
+        public SubjectInfo userAvatar(String userAvatar) {
+            this.userAvatar = userAvatar;
+            return this;
+        }
+
+        public SubjectInfo username(String username) {
+            this.username = username;
+            return this;
+        }
+
+        public SubjectInfo userSubject(String userSubject) {
+            this.userSubject = userSubject;
+            return this;
+        }
+    }
 }

+ 1 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/StatGroupWrapper.java

@@ -20,5 +20,6 @@ public class StatGroupWrapper implements Serializable {
     private Long id;
     private Integer total;
     private String gid; // 字符串分组ID
+    private Double number;
 
 }

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

@@ -0,0 +1,39 @@
+package com.yonge.cooleshow.biz.dal.wrapper.im;
+
+import com.alibaba.fastjson.JSON;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 客服消息
+ * Created by Eric.Shang on 2022/9/30.
+ */
+public class CustomerService {
+
+    /**
+     * 客服通知消息
+     */
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class NotifyMessage implements Serializable {
+
+        private List<String> receives;
+
+        private String title;
+        private String txtMessage;
+        private String imgMessage;
+        private String imgUrl;
+
+        public static NotifyMessage from(String recv) {
+
+            return JSON.parseObject(recv, NotifyMessage.class);
+        }
+    }
+}

+ 77 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/liveroom/LiveRoomWrapper.java

@@ -0,0 +1,77 @@
+package com.yonge.cooleshow.biz.dal.wrapper.liveroom;
+
+import com.alibaba.fastjson.JSON;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 直播间详情信息
+ * Created by Eric.Shang on 2022/9/22.
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class LiveRoomWrapper implements Serializable {
+
+    // 课程组id
+    private Long courseGroupId;
+    // 课程id
+    private Long courseId;
+    // 主讲人id/老师id
+    private Long speakerId;
+    // 房间编号
+    private String roomUid;
+    private String roomTitle;
+    private Date liveStartTime;
+    private Date liveEndTime;
+    private String liveRemark;
+    private Integer liveState;
+    private Integer roomState;
+    private String type;
+    private String coverPic;
+
+    // 直播老师信息
+    private UserInfo teacher;
+
+    // 分享同学信息
+    private UserInfo student;
+
+    public static LiveRoomWrapper from(String jsonString) {
+        return JSON.parseObject(jsonString, LiveRoomWrapper.class);
+    }
+
+    public String jsonString() {
+        return JSON.toJSONString(this);
+    }
+
+    public LiveRoomWrapper teacher(UserInfo teacher) {
+        this.teacher = teacher;
+        return this;
+    }
+
+    public LiveRoomWrapper student(UserInfo student) {
+        this.student = student;
+        return this;
+    }
+
+
+    /**
+     * 直播间老师信息
+     */
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class UserInfo implements Serializable {
+
+        private String username;
+        private String phone;
+        private String avatar;
+        private String realName;
+    }
+}

+ 29 - 11
cooleshow-user/user-biz/src/main/resources/config/mybatis/ActivityEvaluationMapper.xml

@@ -30,14 +30,13 @@
 
     <sql id="selectSql">
         SELECT
-            <include refid="baseColumns" />,
-            ms.music_sheet_name_ as musicSheetName,
-            (select group_concat(mt.name_) from music_tag mt
-                where find_in_set(mt.id_,ms.music_tag_) and mt.del_flag_ = 0  and mt.state_ = 1) as musicTagNames,
-            (select group_concat(s.name_) from subject s
-                where find_in_set(s.id_,ms.music_subject_) and s.del_flag_ = 0 ) as subjectNames,
-            ms.source_type_ as sourceType,
-            ms.music_price_ as musicPrice
+            <include refid="baseColumns" />
+            , ms.music_sheet_name_ as musicSheetName
+            , ms.music_subject_ AS subjectId
+            , (select group_concat(mt.name_) from music_tag mt where find_in_set(mt.id_,ms.music_tag_) and mt.del_flag_ = 0  and mt.state_ = 1) as musicTagNames
+            , (select group_concat(s.name_) from subject s where find_in_set(s.id_,ms.music_subject_) and s.del_flag_ = 0 ) as subjectNames
+            , ms.source_type_ as sourceType
+            , ms.music_price_ as musicPrice
         FROM activity_evaluation t
         left join music_sheet ms on t.music_sheet_id_ = ms.id_
         <where>
@@ -67,11 +66,13 @@
 
         select ms.id_ as musicSheetId
         ,ms.music_sheet_name_ as musicSheetName
+        , ms.music_subject_ AS subjectId
+        , ms.title_img_ AS musicImage
         ,s.name_ as musicSubject
+        , ms.composer_ AS composer
         ,ae.id_ as evaluationId
-        ,(select if(count(1)>0,1,0) as `join` from activity_evaluation_record aer
-            where aer.evaluation_id_ = ae.id_ and aer.user_id_ = #{userId}
-        ) as `join`
+        , ae.evaluation_difficulty_ AS evaluationDifficulty
+        ,(select if(count(1)>0,1,0) as `join` from activity_evaluation_record aer where aer.evaluation_id_ = ae.id_ and aer.user_id_ = #{userId}) as `join`
         from activity_evaluation ae
         left join music_sheet ms on ms.id_ = ae.music_sheet_id_
         left join subject s on s.id_ = ms.music_subject_
@@ -241,4 +242,21 @@
         </where>
     </select>
     <!--时间匹配活动老师信息-->
+
+    <!--评测活动声部曲目最多分-->
+    <select id="selectSubjectMusicHighestScoreStat"
+            resultType="com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper">
+        SELECT t1.evaluation_id_ AS id, MAX(t1.score_) AS number FROM activity_evaluation_record t1
+        <where>
+            t1.score_ IS NOT NULL
+            <if test="activityId != null">
+                AND t1.activity_id_ = #{activityId}
+            </if>
+            <if test="userId != null">
+                AND t1.user_id_ = #{userId}
+            </if>
+        </where>
+        GROUP BY t1.evaluation_id_
+    </select>
+    <!--评测活动声部曲目最多分-->
 </mapper>

+ 77 - 4
cooleshow-user/user-biz/src/main/resources/config/mybatis/ActivityPlanMapper.xml

@@ -17,6 +17,11 @@
 	        <result column="registration_method_" property="registrationMethod" />
 	        <result column="registration_price_" property="registrationPrice" />
             <result column="share_rate_" property="shareRate" />
+            <result column="share_type_" property="shareType" />
+            <result column="ranking_" property="ranking" />
+            <result column="ranking_rule_" property="rankingRule" />
+            <result column="ranking_method_" property="rankingMethod" />
+            <result column="ranking_score_" property="rankingScore" />
 	        <result column="draft_flag_" property="draftFlag" />
 	        <result column="activity_state_" property="activityState" />
 	        <result column="create_time_" property="createTime" />
@@ -45,6 +50,8 @@
         , t.share_type_ as shareType
         , t.ranking_ as ranking
         , t.ranking_rule_ as rankingRule
+        , t.ranking_method_ as rankingMethod
+        , t.ranking_score_ as rankingScore
         , t.draft_flag_ as draftFlag
         , if(t.activity_state_ = 1, 1, 0) as activityState
         , t.create_time_ as createTime
@@ -62,10 +69,10 @@
     
     <select id="selectPage" resultType="com.yonge.cooleshow.biz.dal.vo.ActivityPlanVo">
 		SELECT         
-        	<include refid="baseColumns" />,
-		        u.username_ as updateByName,
-		        (select count(1) from activity_registration r where t.id_ = r.activity_id_) as registrationNum,
-                (select count(distinct r.user_id_) from activity_user_reward r where t.id_ = r.activity_id_) as rewardNum
+        	<include refid="baseColumns" />
+		    ,   u.username_ as updateByName
+		    /*,   (select count(1) from activity_registration r where t.id_ = r.activity_id_) as registrationNum*/
+		    /*,   (select count(distinct r.user_id_) from activity_user_reward r where t.id_ = r.activity_id_) as rewardNum*/
 		FROM activity_plan t
         LEFT JOIN  sys_user u on t.update_by_ = u.id_
         <where>
@@ -133,4 +140,70 @@
             </if>
         </where>
     </select>
+
+    <!--活动参与人数、获奖人数统计-->
+    <select id="selectActivityParticipateStatInfo"
+            resultType="com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper">
+        SELECT t1.activity_id_ AS id, COUNT(DISTINCT t1.id_) AS total FROM activity_registration t1
+        <where>
+            <if test="activityIds != null">
+                AND t1.activity_id_ IN (<foreach collection="activityIds" separator="," item="item">#{item}</foreach>)
+            </if>
+        </where>
+        GROUP BY t1.activity_id_
+    </select>
+
+    <select id="selectActivityWinnerStatInfo"
+            resultType="com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper">
+        SELECT t1.activity_id_ AS id, COUNT(DISTINCT t1.user_id_) AS total FROM activity_user_reward t1
+        <where>
+            <if test="activityIds != null">
+                AND t1.activity_id_ IN (<foreach collection="activityIds" separator="," item="item">#{item}</foreach>)
+            </if>
+        </where>
+        GROUP BY t1.activity_id_
+    </select>
+    <!--活动参与人数、获奖人数统计-->
+
+    <!--活动总分用户排名-->
+    <select id="selectActivityHighestScoreRankingInfo"
+            resultType="com.yonge.cooleshow.biz.dal.vo.ActivityRankingVo">
+        SELECT
+            t1.score_, t1.user_id_, t1.resource_id_, t1.create_time_ AS joinDate, t1.times_, t2.avatar_ AS userAvatar, t2.username_ AS username
+        FROM
+            activity_evaluation_record t1 LEFT JOIN sys_user t2 ON t1.user_id_ = t2.id_
+        WHERE
+            t1.activity_id_ = #{activityId} AND t1.ranking_method_ = 'TOTAL_SCORE' AND t1.score_ >= #{rankingScore}
+            <if test="subjectId != null">
+                AND t1.resource_id_ = #{subjectId}
+            </if>
+            <if test="subjectId == null">
+                AND t1.user_id_ NOT IN (SELECT t3.user_id_ FROM activity_user_reward t3 WHERE t3.activity_id_ = #{activityId})
+            </if>
+        ORDER BY
+            t1.score_ DESC,
+            t1.registration_time_ ASC
+        LIMIT #{limit}
+    </select>
+
+    <select id="selectActivityHighestScoreUserRanking"
+            resultType="com.yonge.cooleshow.biz.dal.vo.ActivityRankingVo">
+        SELECT
+            t1.score_, t1.user_id_, t1.resource_id_, t1.create_time_ AS joinDate, t1.times_, t2.avatar_ AS userAvatar, t2.username_ AS username
+        FROM
+            activity_evaluation_record t1 LEFT JOIN sys_user t2 ON t1.user_id_ = t2.id_
+        WHERE
+            t1.activity_id_ = #{activityId} AND t1.ranking_method_ = 'TOTAL_SCORE' AND t1.score_ >= #{rankingScore}
+            <if test="subjectId != null">
+                AND t1.resource_id_ = #{subjectId}
+            </if>
+            <if test="userId != null">
+                AND t1.user_id_ = #{userId}
+            </if>
+        ORDER BY
+            t1.score_ DESC,
+            t1.registration_time_ ASC
+        LIMIT 1
+    </select>
+    <!--活动总分用户排名-->
 </mapper>

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

@@ -63,6 +63,9 @@
                     <if test="param.activityId != null">
                         and aer.activity_id_ = #{param.activityId}
                     </if>
+		            <if test="param.subjectIds != null and param.subjectIds.size() > 0">
+                        AND aer.resource_id_ IN (<foreach collection="param.subjectIds" separator="," item="item">#{item}</foreach>)
+                    </if>
 		            <if test="param.musicSheetIds != null and param.musicSheetIds.size()>0">
                         and ae.music_sheet_id_ IN
                         <foreach collection="param.musicSheetIds" item="item" separator="," open="(" close=")">

+ 15 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/CouponIssueMapper.xml

@@ -159,4 +159,19 @@
         <if test="record.groupByState != null">GROUP BY t1.use_state_</if>
     </select>
     <!--用户优惠券状态统计-->
+
+    <!--用户发送优惠券统计-->
+    <select id="selectCouponIssueStatInfo" resultType="com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper">
+        SELECT t1.user_id_ AS id, COUNT(DISTINCT t1.id_) AS total FROM coupon_issue t1
+        <where>
+            <if test="couponId != null">
+                AND t1.coupon_id_ = #{couponId}
+            </if>
+            <if test="record.userIds != null">
+                AND t1.user_id_ IN (<foreach collection="record.userIds" separator="," item="item">#{item}</foreach>)
+            </if>
+        </where>
+        GROUP BY t1.user_id_
+    </select>
+    <!--用户发送优惠券统计-->
 </mapper>

+ 6 - 2
cooleshow-user/user-biz/src/main/resources/config/mybatis/CourseScheduleMapper.xml

@@ -330,8 +330,9 @@
             cs.end_time_ AS endTime,
             cs.status_ AS `status`,
             cs.type_ AS courseType,
+            CONCAT(g.name_,'-第',cs.class_num_,'课') AS courseName,
             NULL AS userId,
-            CONCAT(g.name_,'-第',cs.class_num_,'课') AS name,
+            NULL AS name,
             NULL AS realName,
             p.payCount AS payCount,
             g.background_pic_ AS cover,
@@ -370,6 +371,7 @@
             cs.end_time_ AS endTime,
             cs.status_ AS `status`,
             cs.type_ AS courseType,
+            NULL AS courseName,
             u.id_ AS userId,
             u.username_ AS name,
             u.real_name_ AS realName,
@@ -466,6 +468,7 @@
             s.end_time_ AS endTime,
             s.type_ AS courseType,
             s.status_ AS `status`,
+            NULL AS courseName,
             u.id_ AS userId,
             u.username_ AS name,
             u.real_name_ AS realName,
@@ -496,8 +499,9 @@
             s.end_time_ AS endTime,
             s.type_ AS courseType,
             s.status_ AS `status`,
+            CONCAT(g.name_,'-第',s.class_num_,'课') AS courseName,
             NULL AS userId,
-            CONCAT(g.name_,'-第',s.class_num_,'课') AS name,
+            NULL AS name,
             NULL AS realName,
             g.background_pic_ AS cover,
             g.subject_id_ AS subjectId,

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

@@ -108,6 +108,9 @@
             <if test="query.studentId != null">
                 and af2.user_id_ = #{query.studentId}
             </if>
+            <if test="clientType != null">
+                AND af2.client_type_ = #{clientType}
+            </if>
             <if test="query.idAndName != null and query.idAndName != ''">
                 and (t.id_ like concat('%',#{query.idAndName},'%') or
                 t.album_name_ like concat('%',#{query.idAndName},'%'))
@@ -204,7 +207,7 @@
         ,if(t2.num >0,t2.num,0) as albumFavoriteCount
         from music_album t
         left join (select count(1) as num,af.album_id_ from album_favorite af
-            left join sys_user su on af.user_id_ = su.id_
+            left join sys_user su on (af.user_id_ = su.id_ <if test="clientType != null"> AND af.client_type_ = #{clientType} </if>)
             where su.del_flag_ = 0 group by af.album_id_
         ) t2 on t2.album_id_ = t.id_
         <where>

+ 10 - 3
cooleshow-user/user-biz/src/main/resources/config/mybatis/MusicSheetMapper.xml

@@ -46,6 +46,7 @@
         t.can_evaluate_ as canEvaluate,
         t.show_fingering_ as showFingering,
         t.charge_type_ as chargeType,
+        t.payment_type_ as paymentType,
         t.state_ as state,
         t.audit_status_ as auditStatus,
         t.sort_number_ as sortNumber,
@@ -133,7 +134,7 @@
             and t.source_type_ = #{param.sourceType}
         </if>
         <if test="param.chargeType != null">
-            and t.charge_type_ = #{param.chargeType}
+            and (t.charge_type_ = #{param.chargeType} OR FIND_IN_SET(#{param.chargeType}, t.payment_type_))
         </if>
         <if test="param.topFlag != null">
             and t.top_flag_ = #{param.topFlag}
@@ -162,6 +163,9 @@
         left join album_music_relate amr on t.id_ = amr.music_sheet_id_
         left join sys_user su on t.create_by_ = su.id_
         <where>
+            <if test="param.composer != null">
+                AND t.composer_ LIKE '%${param.composer}%'
+            </if>
             <if test="param.idAndName != null and param.idAndName != ''">
                 and (t.id_ like concat('%',#{param.idAndName},'%') or
                 t.music_sheet_name_ like concat('%',#{param.idAndName},'%'))
@@ -319,7 +323,7 @@
 <!--                on mspr.music_sheet_id_ = t.id_-->
 <!--                and mspr.student_id_ = #{param.studentId}-->
 <!--                and order_status_ = 'PAID'-->
-            left join music_favorite mf on t.id_ = mf.music_sheet_id_ and mf.user_id_ = #{param.studentId}
+            left join music_favorite mf on (t.id_ = mf.music_sheet_id_ and mf.user_id_ = #{param.studentId} <if test="clientType != null"> AND mf.client_type_ = #{clientType}</if> )
         </if>
         <where>
             su.del_flag_ = 0
@@ -376,6 +380,9 @@
         <where>
             su.del_flag_ = 0
             <include refid="QueryInfo"/>
+            <if test="clientType != null">
+                AND mf.client_type_ = #{clientType}
+            </if>
             <if test="param.studentId != null">
                 and mf.user_id_ = #{param.studentId}
             </if>
@@ -394,7 +401,7 @@
         from music_sheet_practice_record mspr
         left join music_sheet t on mspr.music_sheet_id_ = t.id_
         left join sys_user su on t.create_by_ = su.id_
-        left join music_favorite mf on t.id_ = mf.music_sheet_id_ and mspr.user_id_ = mf.user_id_
+        left join music_favorite mf on (t.id_ = mf.music_sheet_id_ and mspr.user_id_ = mf.user_id_ <if test="param.clientType != null"> AND mf.client_type_ = #{param.clientType}</if> )
         <where>
             su.del_flag_ = 0
             <include refid="QueryInfo"/>

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

@@ -28,10 +28,13 @@
             <if test="param.userId != null">
                 and t.user_id_ = #{param.userId}
             </if>
+            <if test="param.userIds != null">
+                AND t.user_id_ IN (<foreach collection="param.userIds" separator="," item="item">#{item}</foreach>)
+            </if>
             <if test="param.userType != null and param.userType != ''">
                 and find_in_set(t.user_type_ , #{param.userType})
             </if>
-            <if test="param.timeType != null and param.userType != ''">
+            <if test="param.timeType != null and param.timeType != ''">
                 and find_in_set(t.time_type_ , #{param.timeType})
             </if>
             <if test="param.startTime != null">
@@ -43,4 +46,35 @@
         </where>
         order by t.time_
     </select>
+
+    <!--达标活动参与用户-->
+    <select id="selectActivityParticipateUserPage"
+            resultType="com.yonge.cooleshow.biz.dal.entity.UserFirstTime">
+        SELECT t.user_id_ AS userId FROM (
+            SELECT t1.user_id_, t1.user_type_, <choose><when test="record.calculationMethod.code == 'AND'">MAX(t1.time_)</when><otherwise>MIN(t1.time_)</otherwise></choose>  AS time_ FROM user_first_time t1
+            <where>
+                <if test="record.userType != null and record.userType != ''">
+                    and find_in_set(t1.user_type_ , #{record.userType})
+                </if>
+                <if test="record.timeType != null and record.timeType != ''">
+                    and find_in_set(t1.time_type_ , #{record.timeType})
+                </if>
+                <if test="record.startTime != null">
+                    and t1.time_ &gt;= #{record.startTime}
+                </if>
+                <if test="record.endTime != null">
+                    and t1.time_ &lt;= #{record.endTime}
+                </if>
+            </where>
+            GROUP BY t1.user_id_ ORDER BY t1.time_ ASC
+        ) t
+        <where>
+            <if test="record.activityId != null">
+                AND t.user_id_ NOT IN (SELECT t2.user_id_ FROM activity_user_reward t2 WHERE t2.activity_id_ = #{record.activityId})
+            </if>
+        </where>
+        ORDER BY t.time_ ASC
+    </select>
+    <!--达标活动参与用户-->
+
 </mapper>

+ 12 - 6
cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/MusicAlbumController.java

@@ -11,6 +11,7 @@ import com.yonge.cooleshow.biz.dal.dto.search.MusicAlbumDetailSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.MusicAlbumSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentMusicAlbumSearch;
 import com.yonge.cooleshow.biz.dal.entity.Student;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.AppVersionInfoService;
 import com.yonge.cooleshow.biz.dal.service.MusicAlbumService;
 import com.yonge.cooleshow.biz.dal.service.StudentService;
@@ -83,7 +84,7 @@ public class MusicAlbumController extends BaseController {
         // query.setSubjectIds(student.getSubjectId());
         query.setAlbumStatus(YesOrNoEnum.YES);
         query.setSortBy(1);
-        IPage<MusicAlbumVo> iPage = musicAlbumService.selectStudentPage(PageUtil.getPage(query),query);
+        IPage<MusicAlbumVo> iPage = musicAlbumService.selectStudentPage(PageUtil.getPage(query),query, ClientEnum.STUDENT);
         return succeed(PageUtil.pageInfo(iPage));
     }
 
@@ -100,7 +101,7 @@ public class MusicAlbumController extends BaseController {
         }
         query.setType(2);
         query.setState(YesOrNoEnum.YES);
-        YesOrNoEnum yesOrNoEnum = musicAlbumService.checkFavorite(sysUser.getId(),query.getId() );
+        YesOrNoEnum yesOrNoEnum = musicAlbumService.checkFavorite(sysUser.getId(),query.getId(), ClientEnum.STUDENT);
         AlbumDetailVo albumDetailVo = musicAlbumService.detail(PageUtil.getPage(query), query);
         albumDetailVo.setFavorite(yesOrNoEnum);
 
@@ -112,7 +113,7 @@ public class MusicAlbumController extends BaseController {
         musicAlbumSearch.setPage(1);
         musicAlbumSearch.setRows(query.getRelatedNum() +1);
         musicAlbumSearch.setAlbumTagIds(albumDetailVo.getAlbumTag());
-        IPage<MusicAlbumVo> relatedMusicAlbum = musicAlbumService.selectStudentPage(PageUtil.getPage(musicAlbumSearch),musicAlbumSearch);
+        IPage<MusicAlbumVo> relatedMusicAlbum = musicAlbumService.selectStudentPage(PageUtil.getPage(musicAlbumSearch),musicAlbumSearch, ClientEnum.STUDENT);
         List<MusicAlbumVo> musicAlbumVos1 = relatedMusicAlbum.getRecords()
                                                       .stream()
                                                       .filter(musicAlbumVo -> !musicAlbumVo.getId()
@@ -130,13 +131,18 @@ public class MusicAlbumController extends BaseController {
      */
     @PostMapping("/favorite/{id}")
     @ApiOperation(value = "专辑收藏/取消收藏")
-    public HttpResponseResult<Boolean> favorite(@ApiParam(value = "专辑编号", required = true) @PathVariable("id") Long id) {
+    public HttpResponseResult<Boolean> favorite(@ApiParam(value = "专辑编号", required = true) @PathVariable("id") Long id,
+                                                @ApiParam(value = "客户端类型") @RequestParam(value = "clientType", required = false, defaultValue = "STUDENT") String clientType) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (sysUser == null  || sysUser.getId() == null) {
             return failed("用户信息获取失败");
         }
 
-        return succeed(musicAlbumService.setFavorite(sysUser.getId(),id));
+        if (ClientEnum.invalid(clientType)) {
+            return failed("无效的客户端类型");
+        }
+
+        return succeed(musicAlbumService.setFavorite(sysUser.getId(), id, ClientEnum.valueOf(clientType)));
     }
 
 
@@ -153,7 +159,7 @@ public class MusicAlbumController extends BaseController {
         StudentMusicAlbumSearch search = new StudentMusicAlbumSearch();
         search.setStudentId(sysUser.getId());
         search.setAlbumStatus(YesOrNoEnum.YES);
-        IPage<MusicAlbumVo> albumVoIPage = musicAlbumService.favoriteAlbum(PageUtil.getPage(query), search);
+        IPage<MusicAlbumVo> albumVoIPage = musicAlbumService.favoriteAlbum(PageUtil.getPage(query), search, ClientEnum.STUDENT);
         return succeed(PageUtil.pageInfo(albumVoIPage));
     }
 }

+ 12 - 5
cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/MusicSheetController.java

@@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -119,7 +120,7 @@ public class MusicSheetController extends BaseController {
             query.setMyself(false);
         }
 
-        IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.selectStudentPage(PageUtil.getPage(query), query);
+        IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.selectStudentPage(PageUtil.getPage(query), query, ClientEnum.STUDENT);
         return succeed(PageUtil.pageInfo(musicSheetVoIPage));
     }
 
@@ -146,7 +147,7 @@ public class MusicSheetController extends BaseController {
 
         // query.setSubjectIds(student.getSubjectId());
         query.setRows(query.getSheetRow());
-        IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.selectStudentPage(PageUtil.getPage(query), query);
+        IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.selectStudentPage(PageUtil.getPage(query), query, ClientEnum.STUDENT);
 
         MusicAlbumSearch musicAlbumSearch = new MusicAlbumSearch();
         musicAlbumSearch.setAlbumStatus(YesOrNoEnum.YES);
@@ -170,12 +171,18 @@ public class MusicSheetController extends BaseController {
      */
     @PostMapping("/favorite/{id}")
     @ApiOperation(value = "曲目收藏/取消收藏")
-    public HttpResponseResult<Boolean> favorite(@ApiParam(value = "曲目编号", required = true) @PathVariable("id") Long id) {
+    public HttpResponseResult<Boolean> favorite(@ApiParam(value = "曲目编号", required = true) @PathVariable("id") Long id,
+                                                @ApiParam(value = "客户端类型") @RequestParam(value = "clientType", required = false, defaultValue = "STUDENT") String clientType) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (sysUser == null  || sysUser.getId() == null) {
             return failed("用户信息获取失败");
         }
-        return succeed(musicSheetService.setFavorite(sysUser.getId(),id));
+
+        if (ClientEnum.invalid(clientType)) {
+            return failed("无效的客户端类型");
+        }
+
+        return succeed(musicSheetService.setFavorite(sysUser.getId(),id, ClientEnum.valueOf(clientType)));
     }
 
 
@@ -214,7 +221,7 @@ public class MusicSheetController extends BaseController {
         search.setStudentId(sysUser.getId());
         search.setState(YesOrNoEnum.YES);
         search.setAuditStatus(AuthStatusEnum.PASS);
-        IPage<MusicSheetVo> sheetVoIPage = musicSheetService.favoriteMusic(PageUtil.getPage(query),search);
+        IPage<MusicSheetVo> sheetVoIPage = musicSheetService.favoriteMusic(PageUtil.getPage(query),search, ClientEnum.STUDENT);
         return succeed(PageUtil.pageInfo(sheetVoIPage));
     }
 

+ 26 - 0
cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/open/OpenClient.java

@@ -5,7 +5,9 @@ import com.yonge.cooleshow.biz.dal.entity.SysConfig;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.vo.CheckVo;
 import com.yonge.cooleshow.biz.dal.vo.MemberPriceVo;
+import com.yonge.cooleshow.biz.dal.wrapper.liveroom.LiveRoomWrapper;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
+import com.yonge.cooleshow.student.io.request.LiveRoomVO;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
@@ -15,9 +17,11 @@ import io.swagger.annotations.ApiParam;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 import javax.validation.Valid;
 
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -63,6 +67,8 @@ public class OpenClient extends BaseController {
 
     @Autowired
     private ActivityPlanService activityPlanService;
+    @Autowired
+    private LiveRoomService liveRoomService;
 
     @ApiOperation(value = "查询老师头像昵称信息")
     @GetMapping("/getTeacher")
@@ -165,4 +171,24 @@ public class OpenClient extends BaseController {
         List<SysConfig> configs = sysConfigService.findAll(params);
         return succeed(configs);
     }
+
+    @ApiOperation(value = "直播间详情信息", notes = "直播间ID")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "userId", value = "分享用户ID", dataType = "Long")
+    })
+    @GetMapping("/liveRoom/detail/{ID}")
+    public HttpResponseResult<LiveRoomVO> liveRoomDetailInfo(@PathVariable("ID") String liveRoomId,
+                                                             @RequestParam(value = "userId", required = false) Long userId) {
+
+        if (StringUtils.isEmpty(liveRoomId)) {
+            return failed("无效的直播间编号");
+        }
+
+        LiveRoomWrapper roomWrapper = liveRoomService.findLiveRoomDetailInfoByRoomId(liveRoomId, userId);
+        if (Objects.isNull(roomWrapper)) {
+            return failed("无效的直播间编号");
+        }
+
+        return succeed(LiveRoomVO.from(roomWrapper.jsonString()));
+    }
 }

+ 90 - 0
cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/io/request/LiveRoomVO.java

@@ -0,0 +1,90 @@
+package com.yonge.cooleshow.student.io.request;
+
+import com.alibaba.fastjson.JSON;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.yonge.cooleshow.biz.dal.enums.MK;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * Created by Eric.Shang on 2022/9/22.
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class LiveRoomVO implements Serializable {
+
+    @ApiModelProperty(value = "课程组id")
+    private Long courseGroupId;
+
+    @ApiModelProperty(value = "课程id")
+    private Long courseId;
+
+    @ApiModelProperty(value = "主讲人id/老师id")
+    private Long speakerId;
+
+    @ApiModelProperty(value = "房间编号")
+    private String roomUid;
+
+    @ApiModelProperty(value = "房间标题/最多12个字")
+    private String roomTitle;
+
+    @ApiModelProperty(value = "直播开始时间")
+    @JsonFormat(pattern = MK.TIME_PATTERN, timezone = MK.TIME_ZONE)
+    private Date liveStartTime;
+
+    @ApiModelProperty(value = "直播结束时间")
+    @JsonFormat(pattern = MK.TIME_PATTERN, timezone = MK.TIME_ZONE)
+    private Date liveEndTime;
+
+    @ApiModelProperty(value = "直播内容/最多200个字")
+    private String liveRemark;
+
+    @ApiModelProperty(value = "直播状态 0未开始 1已开始 2已结束")
+    private Integer liveState;
+
+    @ApiModelProperty(value = "房间状态 0正常 1已删除 2已销毁")
+    private Integer roomState;
+
+    @ApiModelProperty(value = "房间类型 live直播课  temp临时直播间")
+    private String type;
+
+    @ApiModelProperty(value = "封面图片")
+    private String coverPic;
+
+    @ApiModelProperty(value = "直播老师信息")
+    private UserInfo teacher;
+
+    @ApiModelProperty(value = "分享同学信息")
+    private UserInfo student;
+
+    public static LiveRoomVO from(String jsonString) {
+        return JSON.parseObject(jsonString, LiveRoomVO.class);
+    }
+
+    /**
+     * 直播间老师信息
+     */
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class UserInfo implements Serializable {
+
+        @ApiModelProperty("用户名")
+        private String username;
+
+        @ApiModelProperty("手机号")
+        private String phone;
+
+        @ApiModelProperty("头像")
+        private String avatar;
+
+        @ApiModelProperty("真实姓名")
+        private String realName;
+    }
+}

+ 16 - 8
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/MusicAlbumController.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.teacher.controller;
 
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
@@ -12,10 +13,12 @@ import javax.validation.Valid;
 
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -88,7 +91,7 @@ public class MusicAlbumController extends BaseController {
 
         query.setAlbumStatus(YesOrNoEnum.YES);
         query.setSortBy(1);
-        IPage<MusicAlbumVo> iPage = musicAlbumService.selectStudentPage(PageUtil.getPage(query),query);
+        IPage<MusicAlbumVo> iPage = musicAlbumService.selectStudentPage(PageUtil.getPage(query),query, ClientEnum.TEACHER);
         return succeed(PageUtil.pageInfo(iPage));
     }
 
@@ -105,7 +108,7 @@ public class MusicAlbumController extends BaseController {
         }
         query.setType(2);
         query.setState(YesOrNoEnum.YES);
-        YesOrNoEnum yesOrNoEnum = musicAlbumService.checkFavorite(sysUser.getId(),query.getId() );
+        YesOrNoEnum yesOrNoEnum = musicAlbumService.checkFavorite(sysUser.getId(),query.getId(), ClientEnum.TEACHER);
         AlbumDetailVo albumDetailVo = musicAlbumService.detail(PageUtil.getPage(query), query);
         albumDetailVo.setFavorite(yesOrNoEnum);
 
@@ -117,7 +120,7 @@ public class MusicAlbumController extends BaseController {
         musicAlbumSearch.setPage(1);
         musicAlbumSearch.setRows(query.getRelatedNum() +1);
         musicAlbumSearch.setAlbumTagIds(albumDetailVo.getAlbumTag());
-        IPage<MusicAlbumVo> relatedMusicAlbum = musicAlbumService.selectStudentPage(PageUtil.getPage(musicAlbumSearch),musicAlbumSearch);
+        IPage<MusicAlbumVo> relatedMusicAlbum = musicAlbumService.selectStudentPage(PageUtil.getPage(musicAlbumSearch),musicAlbumSearch, ClientEnum.TEACHER);
         List<MusicAlbumVo> musicAlbumVos1 = relatedMusicAlbum.getRecords()
                                                       .stream()
                                                       .filter(musicAlbumVo -> !musicAlbumVo.getId()
@@ -133,22 +136,27 @@ public class MusicAlbumController extends BaseController {
     /**
      * 专辑收藏
      */
-    // @PostMapping("/favorite/{id}")
+     @PostMapping("/favorite/{id}")
     @ApiOperation(value = "专辑收藏/取消收藏")
-    public HttpResponseResult<Boolean> favorite(@ApiParam(value = "专辑编号", required = true) @PathVariable("id") Long id) {
+    public HttpResponseResult<Boolean> favorite(@ApiParam(value = "专辑编号", required = true) @PathVariable("id") Long id,
+                                                @ApiParam(value = "客户端类型") @RequestParam(value = "clientType", required = false, defaultValue = "TEACHER") String clientType) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (sysUser == null  || sysUser.getId() == null) {
             return failed("用户信息获取失败");
         }
 
-        return succeed(musicAlbumService.setFavorite(sysUser.getId(),id));
+         if (ClientEnum.invalid(clientType)) {
+             return failed("无效的客户端类型");
+         }
+
+        return succeed(musicAlbumService.setFavorite(sysUser.getId(), id, ClientEnum.valueOf(clientType)));
     }
 
 
     /**
      * 专辑收藏
      */
-    // @GetMapping("/favorite")
+    @GetMapping("/favorite")
     @ApiOperation(value = "收藏专辑列表")
     public HttpResponseResult<PageInfo<MusicAlbumVo>> favoriteAlbum(QueryInfo query) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
@@ -158,7 +166,7 @@ public class MusicAlbumController extends BaseController {
         StudentMusicAlbumSearch search = new StudentMusicAlbumSearch();
         search.setStudentId(sysUser.getId());
         search.setAlbumStatus(YesOrNoEnum.YES);
-        IPage<MusicAlbumVo> albumVoIPage = musicAlbumService.favoriteAlbum(PageUtil.getPage(query), search);
+        IPage<MusicAlbumVo> albumVoIPage = musicAlbumService.favoriteAlbum(PageUtil.getPage(query), search, ClientEnum.TEACHER);
         return succeed(PageUtil.pageInfo(albumVoIPage));
     }
 }

+ 52 - 3
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/MusicSheetController.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.teacher.controller;
 
+import com.yonge.toolset.base.page.QueryInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
@@ -15,6 +16,7 @@ import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -74,7 +76,17 @@ public class MusicSheetController extends BaseController {
         if (sysUser == null  || sysUser.getId() == null) {
             return failed("用户信息获取失败");
         }
-        return succeed(musicSheetService.detail(id, sysUser, ClientEnum.TEACHER));
+
+        MusicSheetDetailVo detail = musicSheetService.detail(id, sysUser, ClientEnum.TEACHER);
+
+        // 设置返回默认值
+        if (StringUtil.isEmpty(detail.getAudioFileUrl())) {
+            detail.setAudioFileUrl("");
+        }
+        if (StringUtils.isEmpty(detail.getMusicImg())) {
+            detail.setMusicImg("");
+        }
+        return succeed(detail);
     }
 
 	@ApiOperation(value = "新增", httpMethod="POST", consumes="application/json", produces="application/json")
@@ -172,7 +184,7 @@ public class MusicSheetController extends BaseController {
             query.setMyself(false);
         }
 
-        IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.selectStudentPage(PageUtil.getPage(query), query);
+        IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.selectStudentPage(PageUtil.getPage(query), query, ClientEnum.TEACHER);
         return succeed(PageUtil.pageInfo(musicSheetVoIPage));
     }
 
@@ -197,7 +209,26 @@ public class MusicSheetController extends BaseController {
     }
 
     /**
-     * 我的单曲,收藏单曲
+     * 曲目收藏
+     */
+    @PostMapping("/favorite/{id}")
+    @ApiOperation(value = "曲目收藏/取消收藏")
+    public HttpResponseResult<Boolean> favorite(@ApiParam(value = "曲目编号", required = true) @PathVariable("id") Long id,
+                                                @ApiParam(value = "客户端类型") @RequestParam(value = "clientType", required = false, defaultValue = "TEACHER") String clientType) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        if (sysUser == null  || sysUser.getId() == null) {
+            return failed("用户信息获取失败");
+        }
+
+        if (ClientEnum.invalid(clientType)) {
+            return failed("无效的客户端类型");
+        }
+
+        return succeed(musicSheetService.setFavorite(sysUser.getId(),id, ClientEnum.valueOf(clientType)));
+    }
+
+    /**
+     * 我的单曲
      */
     @PostMapping("/my")
     @ApiOperation(value = "我的单曲")
@@ -214,6 +245,24 @@ public class MusicSheetController extends BaseController {
         return succeed(PageUtil.pageInfo(sheetVoIPage));
     }
 
+    /**
+     * 收藏单曲
+     */
+    @GetMapping("/favorite")
+    @ApiOperation(value = "收藏单曲")
+    public HttpResponseResult<PageInfo<MusicSheetVo>> favoriteMusic(QueryInfo query) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        if (sysUser == null  || sysUser.getId() == null) {
+            return failed("用户信息获取失败");
+        }
+        StudentMusicSheetSearch search = new StudentMusicSheetSearch();
+        search.setStudentId(sysUser.getId());
+        search.setState(YesOrNoEnum.YES);
+        search.setAuditStatus(AuthStatusEnum.PASS);
+        IPage<MusicSheetVo> sheetVoIPage = musicSheetService.favoriteMusic(PageUtil.getPage(query),search, ClientEnum.TEACHER);
+        return succeed(PageUtil.pageInfo(sheetVoIPage));
+    }
+
     @ApiOperation(value = "乐谱分享")
     @GetMapping(value="/share")
     public HttpResponseResult<MusicSheetShareVo> shareMusicSheet() {

+ 9 - 12
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/SubjectController.java

@@ -1,26 +1,23 @@
 package com.yonge.cooleshow.teacher.controller;
 
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.entity.Subject;
+import com.yonge.cooleshow.biz.dal.entity.Teacher;
+import com.yonge.cooleshow.biz.dal.service.SubjectService;
+import com.yonge.cooleshow.biz.dal.service.TeacherService;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
-
-import java.util.List;
-
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
-import com.yonge.cooleshow.auth.api.entity.SysUser;
-import com.yonge.cooleshow.biz.dal.entity.Student;
-import com.yonge.cooleshow.biz.dal.entity.Subject;
-import com.yonge.cooleshow.biz.dal.entity.Teacher;
-import com.yonge.cooleshow.biz.dal.service.SubjectService;
-import com.yonge.cooleshow.biz.dal.service.TeacherService;
-import com.yonge.cooleshow.common.controller.BaseController;
-import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import java.util.List;
 
 @RequestMapping("subject")
 @Api(tags = "声部服务")

+ 5 - 0
cooleshow-user/user-teacher/src/main/java/com/yonge/cooleshow/teacher/controller/TeacherController.java

@@ -76,6 +76,11 @@ public class TeacherController extends BaseController {
         if (StringUtil.isEmpty(subjectIds)) {
             return failed("参数不能为空");
         }
+
+        if (subjectIds.split(",").length > 5) {
+            return failed("最多选择5个乐器");
+        }
+
         SysUser user = sysUserFeignService.queryUserInfo();
         if (user == null || null == user.getId()) {
             return failed(HttpStatus.FORBIDDEN, "请登录");

+ 16 - 4
cooleshow-user/user-website/src/main/java/com/yonge/cooleshow/website/controller/MusicAlbumController.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentMusicAlbumSearch;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.MusicAlbumService;
 import com.yonge.cooleshow.biz.dal.vo.MusicAlbumVo;
 import com.yonge.cooleshow.common.controller.BaseController;
@@ -40,13 +41,18 @@ public class MusicAlbumController extends BaseController {
      */
     @PostMapping("/favorite/{id}")
     @ApiOperation(value = "专辑收藏/取消收藏")
-    public HttpResponseResult<Boolean> favorite(@ApiParam(value = "专辑编号", required = true) @PathVariable("id") Long id) {
+    public HttpResponseResult<Boolean> favorite(@ApiParam(value = "专辑编号", required = true) @PathVariable("id") Long id,
+                                                @ApiParam(value = "客户端类型") @RequestParam(value = "clientType", required = false, defaultValue = "STUDENT") String clientType) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (sysUser == null  || sysUser.getId() == null) {
             return failed("用户信息获取失败");
         }
 
-        return succeed(musicAlbumService.setFavorite(sysUser.getId(),id));
+        if (ClientEnum.invalid(clientType)) {
+            return failed("无效的客户端类型");
+        }
+
+        return succeed(musicAlbumService.setFavorite(sysUser.getId(), id, ClientEnum.valueOf(clientType)));
     }
 
 
@@ -55,15 +61,21 @@ public class MusicAlbumController extends BaseController {
      */
     @GetMapping("/favorite")
     @ApiOperation(value = "学生-收藏专辑列表")
-    public HttpResponseResult<PageInfo<MusicAlbumVo>> favoriteAlbum(QueryInfo query) {
+    public HttpResponseResult<PageInfo<MusicAlbumVo>> favoriteAlbum(@ApiParam(value = "客户端类型") @RequestParam(value = "clientType", required = false, defaultValue = "STUDENT") String clientType,
+                                                                    QueryInfo query) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (sysUser == null  || sysUser.getId() == null) {
             return failed("用户信息获取失败");
         }
+
+        if (ClientEnum.invalid(clientType)) {
+            return failed("无效的客户端类型");
+        }
+
         StudentMusicAlbumSearch search = new StudentMusicAlbumSearch();
         search.setStudentId(sysUser.getId());
         search.setAlbumStatus(YesOrNoEnum.YES);
-        IPage<MusicAlbumVo> albumVoIPage = musicAlbumService.favoriteAlbum(PageUtil.getPage(query), search);
+        IPage<MusicAlbumVo> albumVoIPage = musicAlbumService.favoriteAlbum(PageUtil.getPage(query), search, ClientEnum.valueOf(clientType));
         return succeed(PageUtil.pageInfo(albumVoIPage));
     }
 }

+ 27 - 6
cooleshow-user/user-website/src/main/java/com/yonge/cooleshow/website/controller/MusicSheetController.java

@@ -4,16 +4,19 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 
+import java.io.File;
 import java.util.Date;
 
 import javax.validation.Valid;
 
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -64,12 +67,18 @@ public class MusicSheetController extends BaseController {
      */
     @PostMapping("/favorite/{id}")
     @ApiOperation(value = "曲目收藏/取消收藏")
-    public HttpResponseResult<Boolean> favorite(@ApiParam(value = "曲目编号", required = true) @PathVariable("id") Long id) {
+    public HttpResponseResult<Boolean> favorite(@ApiParam(value = "曲目编号", required = true) @PathVariable("id") Long id,
+                                                @ApiParam(value = "客户端类型") @RequestParam(value = "clientType", required = false, defaultValue = "STUDENT") String clientType) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (sysUser == null  || sysUser.getId() == null) {
             return failed("用户信息获取失败");
         }
-        return succeed(musicSheetService.setFavorite(sysUser.getId(),id));
+
+        if (ClientEnum.invalid(clientType)) {
+            return failed("无效的客户端类型");
+        }
+
+        return succeed(musicSheetService.setFavorite(sysUser.getId(), id, ClientEnum.valueOf(clientType)));
     }
 
 
@@ -79,15 +88,21 @@ public class MusicSheetController extends BaseController {
      */
     @GetMapping("/my")
     @ApiOperation(value = "学生-我的单曲")
-    public HttpResponseResult<PageInfo<MusicSheetVo>> myMusic(QueryInfo query) {
+    public HttpResponseResult<PageInfo<MusicSheetVo>> myMusic(@ApiParam(value = "客户端类型") @RequestParam(value = "clientType", required = false, defaultValue = "STUDENT") String clientType,
+                                                              QueryInfo query) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (sysUser == null  || sysUser.getId() == null) {
             return failed("用户信息获取失败");
         }
+
+        if (ClientEnum.invalid(clientType)) {
+            return failed("无效的客户端类型");
+        }
+
         StudentMusicSheetSearch search = new StudentMusicSheetSearch();
         search.setStudentId(sysUser.getId());
         search.setAuditStatus(AuthStatusEnum.PASS);
-        search.setUserType(ClientEnum.STUDENT);
+        search.setUserType(ClientEnum.valueOf(clientType));
         IPage<MusicSheetVo> sheetVoIPage = musicSheetService.myMusic(PageUtil.getPage(query),search);
         return succeed(PageUtil.pageInfo(sheetVoIPage));
     }
@@ -98,16 +113,22 @@ public class MusicSheetController extends BaseController {
      */
     @GetMapping("/favorite")
     @ApiOperation(value = "学生-收藏单曲")
-    public HttpResponseResult<PageInfo<MusicSheetVo>> favoriteMusic(QueryInfo query) {
+    public HttpResponseResult<PageInfo<MusicSheetVo>> favoriteMusic(@ApiParam(value = "客户端类型") @RequestParam(value = "clientType", required = false, defaultValue = "STUDENT") String clientType,
+                                                                    QueryInfo query) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (sysUser == null  || sysUser.getId() == null) {
             return failed("用户信息获取失败");
         }
+
+        if (ClientEnum.invalid(clientType)) {
+            return failed("无效的客户端类型");
+        }
+
         StudentMusicSheetSearch search = new StudentMusicSheetSearch();
         search.setStudentId(sysUser.getId());
         search.setState(YesOrNoEnum.YES);
         search.setAuditStatus(AuthStatusEnum.PASS);
-        IPage<MusicSheetVo> sheetVoIPage = musicSheetService.favoriteMusic(PageUtil.getPage(query),search);
+        IPage<MusicSheetVo> sheetVoIPage = musicSheetService.favoriteMusic(PageUtil.getPage(query),search, ClientEnum.valueOf(clientType));
         return succeed(PageUtil.pageInfo(sheetVoIPage));
     }
 

+ 19 - 6
cooleshow-user/user-website/src/main/java/com/yonge/cooleshow/website/controller/open/OpenMusicAlbumController.java

@@ -22,11 +22,13 @@ import com.yonge.toolset.base.page.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 
+import io.swagger.annotations.ApiParam;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
@@ -59,7 +61,8 @@ public class OpenMusicAlbumController extends BaseController {
 
     @ApiOperation(value = "热门专辑", httpMethod="POST", consumes="application/json", produces="application/json")
     @PostMapping(value="/list", consumes="application/json", produces="application/json")
-    public HttpResponseResult<PageInfo<MusicAlbumVo>> list(@RequestBody MusicAlbumSearch query) {
+    public HttpResponseResult<PageInfo<MusicAlbumVo>> list(@ApiParam(value = "客户端类型") @RequestParam(value = "clientType", required = false, defaultValue = "STUDENT") String clientType,
+                                                           @RequestBody MusicAlbumSearch query) {
 
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (sysUser != null && sysUser.getId() != null) {
@@ -80,11 +83,15 @@ public class OpenMusicAlbumController extends BaseController {
             }
         }
 
+        if (ClientEnum.invalid(clientType)) {
+            return failed("无效的客户端类型");
+        }
+
         // 检查app版本
         query.setAuditVersion(YesOrNoEnum.NO);
         query.setAlbumStatus(YesOrNoEnum.YES);
         query.setSortBy(1);
-        IPage<MusicAlbumVo> iPage = musicAlbumService.selectStudentPage(PageUtil.getPage(query),query);
+        IPage<MusicAlbumVo> iPage = musicAlbumService.selectStudentPage(PageUtil.getPage(query),query, ClientEnum.valueOf(clientType));
         return succeed(PageUtil.pageInfo(iPage));
     }
 
@@ -94,11 +101,17 @@ public class OpenMusicAlbumController extends BaseController {
      */
     @PostMapping(value = "/detail",  consumes="application/json", produces="application/json")
     @ApiOperation(value = "专辑详情",httpMethod="POST", consumes="application/json", produces="application/json")
-    public HttpResponseResult<AlbumDetailVo> detail(@Valid @RequestBody MusicAlbumDetailSearch query) {
+    public HttpResponseResult<AlbumDetailVo> detail(@ApiParam(value = "客户端类型") @RequestParam(value = "clientType", required = false, defaultValue = "STUDENT") String clientType,
+                                                    @Valid @RequestBody MusicAlbumDetailSearch query) {
+
+        if (ClientEnum.invalid(clientType)) {
+            return failed("无效的客户端类型");
+        }
+
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         YesOrNoEnum favorite = YesOrNoEnum.NO;
         if (sysUser != null && sysUser.getId() != null) {
-            favorite = musicAlbumService.checkFavorite(sysUser.getId(),query.getId() );
+            favorite = musicAlbumService.checkFavorite(sysUser.getId(),query.getId(), query.getClientType());
         }
         query.setType(2);
         query.setState(YesOrNoEnum.YES);
@@ -112,7 +125,7 @@ public class OpenMusicAlbumController extends BaseController {
         musicAlbumSearch.setSortBy(1);
         musicAlbumSearch.setPage(1);
         musicAlbumSearch.setRows(query.getRelatedNum() + 1);
-        IPage<MusicAlbumVo> hotMusicAlbum = musicAlbumService.selectStudentPage(PageUtil.getPage(musicAlbumSearch),musicAlbumSearch);
+        IPage<MusicAlbumVo> hotMusicAlbum = musicAlbumService.selectStudentPage(PageUtil.getPage(musicAlbumSearch),musicAlbumSearch, ClientEnum.valueOf(clientType));
         List<MusicAlbumVo> musicAlbumVos = hotMusicAlbum.getRecords()
                                                   .stream()
                                                   .filter(musicAlbumVo -> !musicAlbumVo.getId()
@@ -125,7 +138,7 @@ public class OpenMusicAlbumController extends BaseController {
 
         // 相关专辑
         musicAlbumSearch.setAlbumTagIds(albumDetailVo.getAlbumTag());
-        IPage<MusicAlbumVo> relatedMusicAlbum = musicAlbumService.selectStudentPage(PageUtil.getPage(musicAlbumSearch),musicAlbumSearch);
+        IPage<MusicAlbumVo> relatedMusicAlbum = musicAlbumService.selectStudentPage(PageUtil.getPage(musicAlbumSearch),musicAlbumSearch, ClientEnum.valueOf(clientType));
         List<MusicAlbumVo> musicAlbumVos1 = relatedMusicAlbum.getRecords()
                                                       .stream()
                                                       .filter(musicAlbumVo -> !musicAlbumVo.getId()

+ 22 - 5
cooleshow-user/user-website/src/main/java/com/yonge/cooleshow/website/controller/open/OpenMusicSheetController.java

@@ -8,6 +8,7 @@ import com.yonge.cooleshow.biz.dal.dto.search.HotSearchSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.MusicAlbumSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentMusicSheetSearch;
 import com.yonge.cooleshow.biz.dal.enums.AuthStatusEnum;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.HotSearchEnum;
 import com.yonge.cooleshow.biz.dal.service.HotSearchService;
 import com.yonge.cooleshow.biz.dal.service.MusicAlbumService;
@@ -21,6 +22,7 @@ import com.yonge.toolset.base.page.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
@@ -54,15 +56,25 @@ public class OpenMusicSheetController extends BaseController {
      */
     @GetMapping("/detail/{id}")
     @ApiOperation(value = "曲目详情", notes = "传入musicTag")
-    public HttpResponseResult<MusicSheetWebsiteDetailVo> detail(@ApiParam(value = "曲谱编号", required = true) @PathVariable("id") Long id) {
+    public HttpResponseResult<MusicSheetWebsiteDetailVo> detail(@ApiParam(value = "曲谱编号", required = true) @PathVariable("id") Long id,
+                                                                @ApiParam(value = "客户端类型") @RequestParam(value = "clientType", required = false) String clientType) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
-        MusicSheetWebsiteDetailVo detail = musicSheetService.websiteDetail(id,sysUser);
+
+        if (StringUtils.isEmpty(clientType)) {
+            clientType = ClientEnum.STUDENT.getCode();
+        }
+        if (ClientEnum.invalid(clientType)) {
+            return failed("无效的客户端类型");
+        }
+
+        MusicSheetWebsiteDetailVo detail = musicSheetService.websiteDetail(id, sysUser, ClientEnum.valueOf(clientType));
         return succeed(detail);
     }
 
     @ApiOperation(value = "首页曲目分页查询", httpMethod="POST", consumes="application/json", produces="application/json")
     @PostMapping(value="/list", consumes="application/json", produces="application/json")
-    public HttpResponseResult<PageInfo<MusicSheetVo>> list(@RequestBody StudentMusicSheetSearch query) {
+    public HttpResponseResult<PageInfo<MusicSheetVo>> list(@ApiParam(value = "客户端类型") @RequestParam(value = "clientType", required = false, defaultValue = "STUDENT") String clientType,
+                                                           @RequestBody StudentMusicSheetSearch query) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
 
         // 检查app版本
@@ -75,7 +87,12 @@ public class OpenMusicSheetController extends BaseController {
         if (sysUser != null) {
             query.setStudentId(sysUser.getId());
         }
-        IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.selectStudentPage(PageUtil.getPage(query), query);
+
+        if (ClientEnum.invalid(clientType)) {
+            return failed("无效的客户端类型");
+        }
+
+        IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.selectStudentPage(PageUtil.getPage(query), query, ClientEnum.valueOf(clientType));
         return succeed(PageUtil.pageInfo(musicSheetVoIPage));
     }
 
@@ -93,7 +110,7 @@ public class OpenMusicSheetController extends BaseController {
             query.setStudentId(sysUser.getId());
         }
         query.setRows(query.getSheetRow());
-        IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.selectStudentPage(PageUtil.getPage(query), query);
+        IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.selectStudentPage(PageUtil.getPage(query), query, ClientEnum.STUDENT);
 
         MusicAlbumSearch musicAlbumSearch = new MusicAlbumSearch();
         musicAlbumSearch.setAlbumStatus(YesOrNoEnum.YES);

+ 13 - 0
cooleshow-websocket/src/main/resources/bootstrap-dev.yml

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

+ 69 - 0
cooleshow-websocket/src/main/resources/logback-spring.xml

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