liujc 10 kuukautta sitten
vanhempi
commit
105415e6fb
100 muutettua tiedostoa jossa 2926 lisäystä ja 708 poistoa
  1. 1 1
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/ImGroupController.java
  2. 6 1
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/MemberPriceSettingsController.java
  3. 13 12
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/StudentController.java
  4. 28 15
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TeacherController.java
  5. 56 6
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/VipCardRecordController.java
  6. 12 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/TeacherBindingUserVo.java
  7. 3 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/teacher/TeacherVO.java
  8. 2 2
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/ImGroupController.java
  9. 2 2
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/ImUserFriendController.java
  10. 38 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/MemberPriceSettingsController.java
  11. 40 2
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/MusicSheetController.java
  12. 9 4
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/UserOrderController.java
  13. 3 3
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/ImGroupController.java
  14. 4 2
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/ImUserFriendController.java
  15. 17 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/MemberPriceSettingsController.java
  16. 22 1
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/MusicSheetController.java
  17. 25 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/StudentController.java
  18. 28 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/TeacherController.java
  19. 2 2
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/TeacherCourseScheduleController.java
  20. 33 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/UserOrderController.java
  21. 1 1
      cooleshow-app/src/main/java/com/yonge/cooleshow/website/controller/MusicSheetController.java
  22. 3 2
      cooleshow-app/src/main/java/com/yonge/cooleshow/website/controller/WebCourseScheduleController.java
  23. 2 2
      cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/config/CustomerServiceConfig.java
  24. 3 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/dao/SysUserDao.java
  25. 5 13
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/impl/SysUserServiceImpl.java
  26. 17 0
      cooleshow-auth/auth-server/src/main/resources/config/mybatis/SysUserMapper.xml
  27. 16 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/constant/SysConfigConstant.java
  28. 1 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/RewardTypeEnum.java
  29. 1 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/UnitEnum.java
  30. 1 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EPaymentType.java
  31. 13 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/CourseScheduleStudentPaymentDao.java
  32. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/ImUserFriendDao.java
  33. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/MusicSheetDao.java
  34. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/StudentDao.java
  35. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/TeacherDao.java
  36. 4 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/VipCardRecordDao.java
  37. 8 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/BasicUserInfo.java
  38. 44 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/req/OrderReq.java
  39. 3 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/req/TeacherSubmitReq.java
  40. 7 13
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/MemberPriceSettingsSearch.java
  41. 22 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/MusicSheetRelatedQueryInfo.java
  42. 23 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/MusicSheetSearch.java
  43. 1 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/OrderSearch.java
  44. 13 9
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/StudentSearch.java
  45. 9 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/TeacherSearch.java
  46. 23 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/VipRecordSearch.java
  47. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/CourseScheduleStudentPayment.java
  48. 12 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/ImGroup.java
  49. 12 58
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/MemberPriceSettings.java
  50. 16 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/StudentTime.java
  51. 4 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/Teacher.java
  52. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/UserOrderDetail.java
  53. 27 130
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/VipCardRecord.java
  54. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/AccountBizTypeEnum.java
  55. 33 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/EUserVipType.java
  56. 37 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/EVipRecordStatus.java
  57. 46 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/EVipType.java
  58. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/GoodTypeEnum.java
  59. 24 8
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/MessageTypeEnum.java
  60. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/OrderTypeEnum.java
  61. 4 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/PeriodEnum.java
  62. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/SourceTypeEnum.java
  63. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/coupon/CouponCategoryEnum.java
  64. 21 4
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/CourseScheduleService.java
  65. 7 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImGroupMemberService.java
  66. 9 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImGroupService.java
  67. 4 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImUserFriendService.java
  68. 1 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/MemberPriceSettingsService.java
  69. 4 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/MusicSheetService.java
  70. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/StudentService.java
  71. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/TeacherService.java
  72. 41 5
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/VipCardRecordService.java
  73. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/im/ImGroupCoreService.java
  74. 12 10
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/im/impl/ImGroupCoreServiceImpl.java
  75. 1 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ActivityRewardServiceImpl.java
  76. 8 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseGroupServiceImpl.java
  77. 32 17
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseScheduleServiceImpl.java
  78. 9 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CustomerServiceBatchSendingServiceImpl.java
  79. 4 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/HomeServiceImpl.java
  80. 113 44
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImGroupMemberAuditServiceImpl.java
  81. 14 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImGroupMemberServiceImpl.java
  82. 112 34
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImGroupServiceImpl.java
  83. 133 39
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImUserFriendServiceImpl.java
  84. 244 57
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/MemberPriceSettingsServiceImpl.java
  85. 48 8
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/MusicSheetServiceImpl.java
  86. 12 3
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/PaymentDivMemberRecordServiceImpl.java
  87. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/PlatformCashAccountRecordServiceImpl.java
  88. 60 17
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/StudentServiceImpl.java
  89. 8 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/StudentTimeServiceImpl.java
  90. 310 30
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TeacherServiceImpl.java
  91. 11 7
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantApplyRecordServiceImpl.java
  92. 21 4
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantGroupServiceImpl.java
  93. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserAccountRecordServiceImpl.java
  94. 19 6
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserBindingTeacherServiceImpl.java
  95. 11 2
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserMusicServiceImpl.java
  96. 37 7
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserOrderServiceImpl.java
  97. 6 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserPaymentCoreServiceImpl.java
  98. 43 43
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserTenantAlbumRecordServiceImpl.java
  99. 750 67
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/VipCardRecordServiceImpl.java
  100. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/MusicSheetDetailVo.java

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

@@ -65,7 +65,7 @@ public class ImGroupController extends BaseController {
     @PostMapping(value = "/getDetail/{groupId}")
     @PreAuthorize("@pcs.hasPermissions('imGroup/detail')")
     public HttpResponseResult<ImGroup> getDetail(@ApiParam(value = "群编号", required = true) @PathVariable("groupId") String groupId) throws Exception {
-        ImGroup group = imGroupService.getById(groupId);
+        ImGroup group = imGroupService.getGroupById(groupId);
         if (group == null) {
             return failed(HttpStatus.NO_CONTENT, "群组不存在");
         }

+ 6 - 1
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/MemberPriceSettingsController.java

@@ -1,5 +1,7 @@
 package com.yonge.cooleshow.admin.controller;
 
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
@@ -69,6 +71,9 @@ public class MemberPriceSettingsController extends BaseController {
 		}
 		memberPriceSettings.setUpdateBy(user.getId());
 		memberPriceSettings.setUpdateTime(new Date());
-		return status(memberPriceSettingsService.updateById(memberPriceSettings));
+		boolean update = memberPriceSettingsService.update(memberPriceSettings, new UpdateWrapper<MemberPriceSettings>().lambda()
+				.set(MemberPriceSettings::getDesc, memberPriceSettings.getDesc())
+				.eq(MemberPriceSettings::getId, memberPriceSettings.getId()));
+		return status(update);
 	}
 }

+ 13 - 12
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/StudentController.java

@@ -251,9 +251,9 @@ public class StudentController extends BaseController {
         OutputStream outputStream = response.getOutputStream();
         try {
             HSSFWorkbook workbook = POIUtil.exportExcel(new String[]{"学生编号", "学生姓名", "真实姓名", "性别", "出生日期",
-                    "年龄", "专业", "手机号码", "是否是会员", "注册时间", "用户状态", "学生来源","小组"}, new String[]{
+                    "年龄", "专业", "手机号码", "会员类型", "会员结束时间", "注册时间", "用户状态", "学生来源","小组"}, new String[]{
                     "userId", "username", "realName", "gender.msg", "birthdate", "age", "subjectName", "phone",
-                    "isVip.msg", "createTime", "userStatus.msg", "tenantName", "tenantGroupName"}, rows);
+                    "vipType.name", "membershipEndTimeStr", "createTime", "userStatus.msg", "tenantName", "tenantGroupName"}, rows);
             response.setContentType("application/octet-stream");
             response.setHeader("Content-Disposition", "attac:wq" +
                     "hment;filename=学生列表-" + DateUtil.getDate(new Date()) + ".xls");
@@ -274,16 +274,16 @@ public class StudentController extends BaseController {
         }
     }
 
-    @PostMapping("/addVip")
-    @ApiOperation(value = "添加会员")
-    @PreAuthorize("@pcs.hasPermissions('student/addVip')")
-    public HttpResponseResult<Boolean> addVip(@Valid @RequestBody VipSubmitReq vipSubmitReq) {
-        SysUser sysUser = sysUserFeignService.queryUserInfo();
-        if (sysUser == null || sysUser.getId() == null) {
-            return failed("用户信息获取失败");
-        }
-        return succeed(memberPriceSettingsService.addVip(vipSubmitReq, ClientEnum.STUDENT, sysUser));
-    }
+//    @PostMapping("/addVip")
+//    @ApiOperation(value = "添加会员")
+//    @PreAuthorize("@pcs.hasPermissions('student/addVip')")
+//    public HttpResponseResult<Boolean> addVip(@Valid @RequestBody VipSubmitReq vipSubmitReq) {
+//        SysUser sysUser = sysUserFeignService.queryUserInfo();
+//        if (sysUser == null || sysUser.getId() == null) {
+//            return failed("用户信息获取失败");
+//        }
+//        return succeed(memberPriceSettingsService.addVip(vipSubmitReq, ClientEnum.STUDENT, sysUser));
+//    }
 
 
     @PostMapping("/vipRecord")
@@ -291,6 +291,7 @@ public class StudentController extends BaseController {
     @PreAuthorize("@pcs.hasPermissions('student/vipRecord')")
     public HttpResponseResult<PageInfo<VipRecordVo>> vipRecord(@Valid @RequestBody VipRecordSearch recordSearch) {
 
+        recordSearch.setDisplayFlag(true);
         recordSearch.setClient(ClientEnum.STUDENT);
         return succeed(vipCardRecordService.vipRecord(recordSearch));
     }

+ 28 - 15
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TeacherController.java

@@ -218,9 +218,9 @@ public class TeacherController extends BaseController {
         OutputStream outputStream = response.getOutputStream();
         try {
             HSSFWorkbook workbook = POIUtil.exportExcel(new String[]{"老师编号", "昵称", "姓名", "手机号", "老师类型",
-                    "注册时间", "认证时间", "状态", "是否是会员", "徽章", "机构", "小组"}, new String[]{
+                    "注册时间", "认证时间", "状态", "会员类型", "会员结束时间", "徽章", "机构", "小组"}, new String[]{
                     "userId", "username", "realName", "phone", "entryFlag.code == 1 ? '达人' : '游客'", "createTime",
-                    "entryAuthDate","userStatus.msg", "isVip.code == 1 ? '是' : '否'", "tag", "tenantName",
+                    "entryAuthDate","userStatus.msg", "vipType.name", "membershipEndTimeStr", "tag", "tenantName",
                     "tenantGroupName"}, rows);
             response.setContentType("application/octet-stream");
             response.setHeader("Content-Disposition", "attac:wq" +
@@ -242,25 +242,25 @@ public class TeacherController extends BaseController {
         }
     }
 
-    @PostMapping("/addVip")
-    @ApiOperation(value = "添加会员")
-    @PreAuthorize("@pcs.hasPermissions('teacher/addVip')")
-    public HttpResponseResult<Boolean> addVip(@Valid @RequestBody VipSubmitReq vipSubmitReq) {
-
-
-        SysUser sysUser = sysUserFeignService.queryUserInfo();
-        if (sysUser == null  || sysUser.getId() == null) {
-            return failed("用户信息获取失败");
-        }
-        return succeed(memberPriceSettingsService.addVip(vipSubmitReq, ClientEnum.TEACHER,sysUser));
-    }
+//    @PostMapping("/addVip")
+//    @ApiOperation(value = "添加会员")
+//    @PreAuthorize("@pcs.hasPermissions('teacher/addVip')")
+//    public HttpResponseResult<Boolean> addVip(@Valid @RequestBody VipSubmitReq vipSubmitReq) {
+//
+//
+//        SysUser sysUser = sysUserFeignService.queryUserInfo();
+//        if (sysUser == null  || sysUser.getId() == null) {
+//            return failed("用户信息获取失败");
+//        }
+//        return succeed(memberPriceSettingsService.addVip(vipSubmitReq, ClientEnum.TEACHER,sysUser));
+//    }
 
 
     @PostMapping("/vipRecord")
     @ApiOperation(value = "会员记录")
     @PreAuthorize("@pcs.hasPermissions('teacher/vipRecord')")
     public HttpResponseResult<PageInfo<VipRecordVo>> vipRecord(@Valid @RequestBody VipRecordSearch recordSearch) {
-
+        recordSearch.setDisplayFlag(true);
         recordSearch.setClient(ClientEnum.TEACHER);
         return succeed(vipCardRecordService.vipRecord(recordSearch));
     }
@@ -355,4 +355,17 @@ public class TeacherController extends BaseController {
         imGroupService.setTeacherFansGroup();
         return succeed();
     }
+
+    /**
+     * 老师账号冻结/解冻
+     */
+    @PostMapping("/updateLock/{teacherId}")
+    @ApiOperation(value = "老师账号冻结/解冻")
+    @PreAuthorize("@pcs.hasPermissions('teacher/updateLock')")
+    public HttpResponseResult updateLock(@PathVariable("teacherId") Long teacherId) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        teacherService.updateLock(sysUser, teacherId);
+        return succeed();
+    }
+
 }

+ 56 - 6
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/VipCardRecordController.java

@@ -1,16 +1,30 @@
 package com.yonge.cooleshow.admin.controller;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.google.common.collect.Lists;
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.dao.UserOrderDao;
+import com.yonge.cooleshow.biz.dal.dto.search.OrderSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.VipCardRecordSearch;
+import com.yonge.cooleshow.biz.dal.enums.EVipRecordStatus;
+import com.yonge.cooleshow.biz.dal.enums.GoodTypeEnum;
+import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
 import com.yonge.cooleshow.biz.dal.service.VipCardRecordService;
+import com.yonge.cooleshow.biz.dal.vo.UserOrderVo;
 import com.yonge.cooleshow.biz.dal.vo.VipCardRecordVo;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.toolset.base.exception.BizException;
 import com.yonge.toolset.base.page.PageInfo;
 import com.yonge.toolset.mybatis.support.PageUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.checkerframework.checker.units.qual.A;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -18,6 +32,9 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
+import java.util.stream.Collectors;
+
 @RestController
 @RequestMapping("${app-config.url.admin:}/vipCardRecord")
 @Api(value = "购买会员卡记录表", tags = "购买会员卡记录表")
@@ -26,22 +43,55 @@ public class VipCardRecordController extends BaseController {
     @Autowired
     private VipCardRecordService vipCardRecordService;
 
-	/**
+    @Resource
+    private SysUserFeignService sysUserFeignService;
+
+    @Autowired
+    private UserOrderDao userOrderDao;
+
+    /**
      * 查询单条
      */
     @GetMapping("/detail/{orderDetilId}")
     @ApiOperation(value = "详情", notes = "传入订单详情id")
     public HttpResponseResult<VipCardRecordVo> detail(@PathVariable("orderDetilId") Long orderDetilId) {
-    	return succeed(vipCardRecordService.detail(orderDetilId));
-	}
-    
+        return succeed(vipCardRecordService.detail(orderDetilId));
+    }
+
     /**
      * 查询分页
      */
     @PostMapping("/page")
     @ApiOperation(value = "查询分页", notes = "传入vipCardRecordSearch")
     public HttpResponseResult<PageInfo<VipCardRecordVo>> page(@RequestBody VipCardRecordSearch query) {
-		IPage<VipCardRecordVo> pages = vipCardRecordService.selectPage(PageUtil.getPage(query), query);
+        IPage<VipCardRecordVo> pages = vipCardRecordService.selectPage(PageUtil.getPage(query), query);
         return succeed(PageUtil.pageInfo(pages));
-	}
+    }
+
+
+    @ApiOperation("添加/扣减会员")
+    @PostMapping("/add")
+    @PreAuthorize("@pcs.hasPermissions('vipCardRecord/add')")
+    public HttpResponseResult<Void> add(@RequestBody @Validated VipCardRecordWrapper.AddVipCardRecord addVipCardRecord) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        addVipCardRecord.setCreateBy(sysUser.getId());
+        if (addVipCardRecord.getStatus().equals(EVipRecordStatus.ADD)) {
+            addVipCardRecord.setSourceType(SourceTypeEnum.PLATFORM);
+        } else if (addVipCardRecord.getStatus().equals(EVipRecordStatus.DEDUCTION)) {
+            addVipCardRecord.setSourceType(SourceTypeEnum.PLATFORM_DEDUCT);
+        }
+
+        // 判断是否有待支付订单 如果有返回不可下单
+        OrderSearch search = new OrderSearch();
+        search.setOrderClient(addVipCardRecord.getClientType().name());
+        search.setGoodType(Lists.newArrayList(GoodTypeEnum.VIP, GoodTypeEnum.SVIP).stream().map(GoodTypeEnum::name).collect(Collectors.joining(",")));
+        search.setUserId(addVipCardRecord.getUserId());
+
+        UserOrderVo userOrderVo = userOrderDao.getPendingOrder(search);
+        if (null != userOrderVo) {
+            throw new BizException(997, "当前用户存在未支付订单,不可操作添加/扣减会员");
+        }
+        vipCardRecordService.add(addVipCardRecord);
+        return succeed();
+    }
 }

+ 12 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/TeacherBindingUserVo.java

@@ -1,6 +1,7 @@
 package com.yonge.cooleshow.admin.io.request;
 
 import com.alibaba.fastjson.JSON;
+import com.yonge.cooleshow.biz.dal.enums.EUserVipType;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import com.yonge.toolset.base.page.QueryInfo;
 import io.swagger.annotations.ApiModel;
@@ -100,6 +101,9 @@ public class TeacherBindingUserVo {
         @ApiModelProperty(value = "是否会员 0否 1是")
         private YesOrNoEnum isVip;
 
+        @ApiModelProperty("用户会员类型")
+        private EUserVipType vipType;
+
 
         @ApiModelProperty("课程数")
         private Long courseNum;
@@ -204,6 +208,14 @@ public class TeacherBindingUserVo {
         public void setBindingTime(Date bindingTime) {
             this.bindingTime = bindingTime;
         }
+
+        public EUserVipType getVipType() {
+            return vipType;
+        }
+
+        public void setVipType(EUserVipType vipType) {
+            this.vipType = vipType;
+        }
     }
 
     @ApiModel("BindingStudentCourseQuery-绑定学生课程列表查询")

+ 3 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/teacher/TeacherVO.java

@@ -2,6 +2,7 @@ package com.yonge.cooleshow.admin.io.request.teacher;
 
 import com.alibaba.fastjson.JSON;
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.yonge.cooleshow.biz.dal.enums.EUserVipType;
 import com.yonge.cooleshow.biz.dal.enums.GenderEnum;
 import com.yonge.cooleshow.biz.dal.enums.MK;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
@@ -138,5 +139,7 @@ public class TeacherVO {
 
         @ApiModelProperty("出生日期")
         private Integer age;
+
+        private EUserVipType vipType;
     }
 }

+ 2 - 2
cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/ImGroupController.java

@@ -136,7 +136,7 @@ public class ImGroupController extends BaseController {
             return failed("无效的用户ID");
         }
 
-        ImUserFriend userFriend = imUserFriendService.getDetail(userId, ClientEnum.TEACHER);
+        ImUserFriendVO.ImUserFriend userFriend = imUserFriendService.getDetail(userId, ClientEnum.TEACHER);
         if (Objects.isNull(userFriend)) {
             return failed("当前好友不存在");
         }
@@ -145,7 +145,7 @@ public class ImGroupController extends BaseController {
             userFriend.setFriendType(ClientEnum.STUDENT);
         }
 
-        return succeed(ImUserFriendVO.ImUserFriend.from(JSON.toJSONString(userFriend)));
+        return succeed(userFriend);
     }
 }
 

+ 2 - 2
cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/ImUserFriendController.java

@@ -91,7 +91,7 @@ public class ImUserFriendController extends BaseController {
             return failed("无效的用户ID");
         }
 
-        ImUserFriend userFriend = imUserFriendService.getDetail(userId, ClientEnum.STUDENT);
+        ImUserFriendVO.ImUserFriend userFriend = imUserFriendService.getDetail(userId, ClientEnum.STUDENT);
         if (Objects.isNull(userFriend)) {
             return failed("当前好友不存在");
         }
@@ -100,7 +100,7 @@ public class ImUserFriendController extends BaseController {
             userFriend.setFriendType(ClientEnum.TEACHER);
         }
 
-        return succeed(ImUserFriendVO.ImUserFriend.from(JSON.toJSONString(userFriend)));
+        return succeed(userFriend);
     }
 }
 

+ 38 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/MemberPriceSettingsController.java

@@ -6,11 +6,13 @@ import com.yonge.cooleshow.biz.dal.service.MemberPriceSettingsService;
 import com.yonge.cooleshow.biz.dal.service.SysConfigService;
 import com.yonge.cooleshow.biz.dal.vo.MemberPriceSettingsVo;
 import com.yonge.cooleshow.biz.dal.vo.MemberPriceVo;
+import com.yonge.cooleshow.biz.dal.wrapper.MemberPriceSettingsWrapper;
 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.Autowired;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -43,10 +45,46 @@ public class MemberPriceSettingsController extends BaseController {
 	@PostMapping("/list")
 	@ApiOperation(value = "查询列表")
 	public HttpResponseResult<MemberPriceVo> list(@RequestBody MemberPriceSettingsSearch query) {
+		query.setStatus(true);
 		MemberPriceVo memberPriceVo = memberPriceSettingsService.getVipShare(query);
 		return succeed(memberPriceVo);
 	}
 
+
+
+    /**
+     * 查询单条
+     */
+    @GetMapping("/check/{id}")
+    @ApiOperation(value = "检查会员是否有效", notes = "传入id")
+    public HttpResponseResult<Boolean> check(@PathVariable("id") Long id) {
+        MemberPriceSettingsVo detail = memberPriceSettingsService.detail(id);
+        if (detail == null) {
+            return succeed(false);
+        }else if (Boolean.FALSE.equals(detail.getStatus())) {
+            return succeed(false);
+        }
+        return succeed(true);
+    }
+
+
+    /**
+     * 查询单条
+     */
+    @PostMapping("/checkChange")
+    @ApiOperation(value = "检查会员是否有效", notes = "传入id")
+    public HttpResponseResult<Boolean> checkChange(@RequestBody @Validated MemberPriceSettingsWrapper.MemberChange memberChange) {
+        MemberPriceSettingsVo detail = memberPriceSettingsService.detail(memberChange.getId());
+        if (detail == null) {
+            return succeed(false);
+        }else if (Boolean.FALSE.equals(detail.getStatus())) {
+            return succeed(false);
+        } else if (memberChange.getSalePrice() != null && memberChange.getSalePrice().compareTo(detail.getSalePrice()) !=0) {
+            return succeed(false);
+        }
+        return succeed(true);
+    }
+
 	@PostMapping("/vipPermissions")
 	@ApiOperation(value = "查询vip权限")
 	public HttpResponseResult<List<SysConfig>> vipPermissions() {

+ 40 - 2
cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/MusicSheetController.java

@@ -25,6 +25,7 @@ import com.yonge.cooleshow.biz.dal.vo.CheckVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicAlbumVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicSheetDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicSheetVo;
+import com.yonge.cooleshow.biz.dal.wrapper.MusicSheetWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.music.MusicCompareWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
@@ -96,6 +97,27 @@ public class MusicSheetController extends BaseController {
         return succeed(musicSheetService.detail(id, sysUser, ClientEnum.STUDENT,tenantAlbumId));
     }
 
+
+
+    @GetMapping("/detailUse/{id}")
+    @ApiOperation(value = "是否可使用")
+    public HttpResponseResult<MusicSheetWrapper.MusicUse> detailUse(@ApiParam(value = "曲谱编号", required = true) @PathVariable("id") String id,
+                                                        @RequestParam(required = false) String tenantAlbumId) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        if (sysUser == null  || sysUser.getId() == null) {
+            sysUser = null;
+        }
+        MusicSheetDetailVo detail = musicSheetService.detail(id, sysUser, ClientEnum.STUDENT, tenantAlbumId);
+        if (detail == null) {
+            return failed("曲目不存在");
+        }
+
+        MusicSheetWrapper.MusicUse musicUse = new MusicSheetWrapper.MusicUse();
+        musicUse.setBuyed(detail.getBuyed());
+        musicUse.setPlay(detail.getPlay());
+        return succeed(musicUse);
+    }
+
     @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) {
@@ -329,8 +351,24 @@ public class MusicSheetController extends BaseController {
     @ApiOperation(value = "关联的曲目列表")
     @GetMapping(value="/queryRelatedList")
     public HttpResponseResult<PageInfo<MusicSheetVo>> queryRelatedList(MusicSheetRelatedQueryInfo queryInfo) {
-    	
-    	IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.queryRelatedList(PageUtil.getPage(queryInfo),queryInfo.getAlbumId(), queryInfo.getMusicSheetId());
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        if (sysUser == null  || sysUser.getId() == null) {
+            return failed("用户信息获取失败");
+        }
+
+        Student student = studentService.getById(sysUser.getId());
+        if (student == null) {
+            return failed("用户信息获取失败");
+        }
+        // 如果是机构学生
+        IPage<MusicSheetVo> musicSheetVoIPage;
+        if (student.getTenantId() !=null && student.getTenantId()>0) {
+            queryInfo.setSubjectId(Long.parseLong(student.getSubjectId()));
+            musicSheetVoIPage =musicSheetService.queryTenantRelatedList(PageUtil.getPage(queryInfo),queryInfo);
+        } else {
+
+            musicSheetVoIPage = musicSheetService.queryRelatedList(PageUtil.getPage(queryInfo), queryInfo);
+        }
         return succeed(PageUtil.pageInfo(musicSheetVoIPage));
     }
 

+ 9 - 4
cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/UserOrderController.java

@@ -103,9 +103,10 @@ public class UserOrderController extends BaseController {
                 return HttpResponseResult.failed("下单失败");
             }
         } catch (BizException e) {
-            return HttpResponseResult.failed(e.getMessage());
+            log.error("下单失败", e);
+            throw e;
         } catch (Exception e) {
-            e.printStackTrace();
+            log.error("下单失败", e);
             return HttpResponseResult.failed("下单失败");
         }
     }
@@ -134,7 +135,8 @@ public class UserOrderController extends BaseController {
                 return HttpResponseResult.failed("付款失败");
             }
         } catch (BizException e) {
-            return HttpResponseResult.failed(e.getMessage());
+            log.error("下单失败", e);
+            throw e;
         } catch (Exception e) {
             e.printStackTrace();
             return HttpResponseResult.failed("付款失败");
@@ -157,7 +159,9 @@ public class UserOrderController extends BaseController {
     })
     public HttpResponseResult<UserOrderVo> getPendingOrder(@ApiIgnore @RequestBody OrderSearch query) {
         if (null == query.getGoodType()
-                || (!GoodTypeEnum.VIP.getCode().equals(query.getGoodType()) && null == query.getBizId())) {
+                || (!GoodTypeEnum.VIP.getCode().equals(query.getGoodType())
+            && !GoodTypeEnum.SVIP.getCode().equals(query.getGoodType())
+            && null == query.getBizId())) {
             return HttpResponseResult.failed("参数异常");
         }
         SysUser user = sysUserFeignService.queryUserInfo();
@@ -165,6 +169,7 @@ public class UserOrderController extends BaseController {
             return failed(HttpStatus.FORBIDDEN, "请登录");
         }
         query.setUserId(user.getId());
+        query.setOrderClient(ClientEnum.STUDENT.name());
         return userOrderService.getPendingOrder(query);
     }
 

+ 3 - 3
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/ImGroupController.java

@@ -145,7 +145,7 @@ public class ImGroupController extends BaseController {
     @ApiOperation("获取群详情")
     @PostMapping(value = "/getDetail/{groupId}")
     public HttpResponseResult<ImGroup> getDetail(@ApiParam(value = "群编号", required = true) @PathVariable("groupId") String groupId) throws Exception {
-        ImGroup group = imGroupService.getById(groupId);
+        ImGroup group = imGroupService.getGroupById(groupId);
         if (group == null) {
             return failed(HttpStatus.NO_CONTENT, "群组不存在");
         }
@@ -195,7 +195,7 @@ public class ImGroupController extends BaseController {
             return failed("无效的用户ID");
         }
 
-        ImUserFriend userFriend = imUserFriendService.getDetail(userId, ClientEnum.TEACHER);
+        ImUserFriendVO.ImUserFriend userFriend = imUserFriendService.getDetail(userId, ClientEnum.TEACHER);
         if (Objects.isNull(userFriend)) {
             return failed("当前好友不存在");
         }
@@ -204,7 +204,7 @@ public class ImGroupController extends BaseController {
             userFriend.setFriendType(ClientEnum.STUDENT);
         }
 
-        return succeed(ImUserFriendVO.ImUserFriend.from(JSON.toJSONString(userFriend)));
+        return succeed(userFriend);
     }
 
     @ApiOperation(value = "转让群主", notes = "转让群主- 传入 ImGroupVo.ImGroupOwner")

+ 4 - 2
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/ImUserFriendController.java

@@ -9,6 +9,7 @@ import com.yonge.cooleshow.biz.dal.service.ImGroupService;
 import com.yonge.cooleshow.biz.dal.service.ImUserFriendService;
 import com.yonge.cooleshow.biz.dal.service.SysUserService;
 import com.yonge.cooleshow.biz.dal.vo.im.ImUserFriendVO;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.im.ImUserWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
@@ -90,7 +91,7 @@ public class ImUserFriendController extends BaseController {
             return failed("无效的用户ID");
         }
 
-        ImUserFriend userFriend = imUserFriendService.getDetail(userId, ClientEnum.TEACHER);
+        ImUserFriendVO.ImUserFriend userFriend = imUserFriendService.getDetail(userId, ClientEnum.TEACHER);
         if (Objects.isNull(userFriend)) {
             return failed("当前好友不存在");
         }
@@ -99,7 +100,8 @@ public class ImUserFriendController extends BaseController {
             userFriend.setFriendType(ClientEnum.STUDENT);
         }
 
-        return succeed(ImUserFriendVO.ImUserFriend.from(JSON.toJSONString(userFriend)));
+
+        return succeed(userFriend);
     }
 
 }

+ 17 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/MemberPriceSettingsController.java

@@ -40,9 +40,26 @@ public class MemberPriceSettingsController extends BaseController {
 		return succeed(memberPriceSettingsService.detail(id)); 
 	}
 
+
+    /**
+     * 查询单条
+     */
+    @GetMapping("/check/{id}")
+    @ApiOperation(value = "检查会员是否有效", notes = "传入id")
+    public HttpResponseResult<Boolean> check(@PathVariable("id") Long id) {
+        MemberPriceSettingsVo detail = memberPriceSettingsService.detail(id);
+        if (detail == null) {
+            return succeed(false);
+        }else if (Boolean.FALSE.equals(detail.getStatus())) {
+            return succeed(false);
+        }
+        return succeed(true);
+    }
+
 	@PostMapping("/list")
 	@ApiOperation(value = "查询列表")
 	public HttpResponseResult<MemberPriceVo> list(@RequestBody MemberPriceSettingsSearch query) {
+		query.setStatus(true);
 		MemberPriceVo memberPriceVo = memberPriceSettingsService.getVipShare(query);
 		return succeed(memberPriceVo);
 	}

+ 22 - 1
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/MusicSheetController.java

@@ -23,6 +23,7 @@ import com.yonge.cooleshow.biz.dal.service.cbs.CbsMusicScoreService;
 import com.yonge.cooleshow.biz.dal.vo.MusicSheetDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicSheetShareVo;
 import com.yonge.cooleshow.biz.dal.vo.MusicSheetVo;
+import com.yonge.cooleshow.biz.dal.wrapper.MusicSheetWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.enums.EStatus;
@@ -89,6 +90,26 @@ public class MusicSheetController extends BaseController {
         return succeed(detail);
     }
 
+
+    @GetMapping("/detailUse/{id}")
+    @ApiOperation(value = "是否可使用")
+    public HttpResponseResult<MusicSheetWrapper.MusicUse> detailUse(@ApiParam(value = "曲谱编号", required = true) @PathVariable("id") String id,
+                                                                    @RequestParam(required = false) String tenantAlbumId) {
+        SysUser sysUser = sysUserService.getUser();
+        if (sysUser == null  || sysUser.getId() == null) {
+            sysUser = null;
+        }
+        MusicSheetDetailVo detail = musicSheetService.detail(id, sysUser, ClientEnum.TEACHER, tenantAlbumId);
+        if (detail == null) {
+            return failed("曲目不存在");
+        }
+
+        MusicSheetWrapper.MusicUse musicUse = new MusicSheetWrapper.MusicUse();
+        musicUse.setBuyed(detail.getBuyed());
+        musicUse.setPlay(detail.getPlay());
+        return succeed(musicUse);
+    }
+
     @ApiOperation(value = "修改", httpMethod="POST", consumes="application/json", produces="application/json")
     @PostMapping(value="/updateRenderFile", consumes="application/json", produces="application/json")
     public HttpResponseResult<Object> updateRenderFile(@Valid @RequestBody MusicSheetRenderDto musicSheetRenderDto) {
@@ -238,7 +259,7 @@ public class MusicSheetController extends BaseController {
     @GetMapping(value="/queryRelatedList")
     public HttpResponseResult<PageInfo<MusicSheetVo>> queryRelatedList(MusicSheetRelatedQueryInfo queryInfo) {
     	
-    	IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.queryRelatedList(PageUtil.getPage(queryInfo),queryInfo.getAlbumId(), queryInfo.getMusicSheetId());
+    	IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.queryRelatedList(PageUtil.getPage(queryInfo),queryInfo);
         return succeed(PageUtil.pageInfo(musicSheetVoIPage));
     }
 

+ 25 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/StudentController.java

@@ -5,10 +5,12 @@ import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentSearch;
 import com.yonge.cooleshow.biz.dal.entity.Student;
+import com.yonge.cooleshow.biz.dal.entity.Teacher;
 import com.yonge.cooleshow.biz.dal.entity.TenantGroup;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.ImGroupService;
 import com.yonge.cooleshow.biz.dal.service.StudentService;
+import com.yonge.cooleshow.biz.dal.service.TeacherService;
 import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
 import com.yonge.cooleshow.biz.dal.vo.StudentVo;
 import com.yonge.cooleshow.common.controller.BaseController;
@@ -16,15 +18,20 @@ import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.enums.UserLockFlag;
 import com.yonge.cooleshow.common.enums.UserStatusEnum;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
+import com.yonge.toolset.base.exception.BizException;
 import com.yonge.toolset.base.page.PageInfo;
 import com.yonge.toolset.base.util.StringUtil;
 import com.yonge.toolset.mybatis.support.PageUtil;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
+import org.springframework.security.access.prepost.PreAuthorize;
 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;
@@ -53,6 +60,9 @@ public class StudentController extends BaseController {
     @Autowired
     private TenantGroupService tenantGroupService;
 
+    @Autowired
+    private TeacherService teacherService;
+
 
     @ApiOperation(value = "查询指定学员信息-融云token")
     @GetMapping("/queryUserById")
@@ -75,6 +85,21 @@ public class StudentController extends BaseController {
         return succeed(studentService.detail(userId));
     }
 
+    @GetMapping("/detail/{id}")
+    public HttpResponseResult<StudentVo> detail(@PathVariable("id") Long id) {
+        SysUser user = sysUserFeignService.queryUserInfo();
+        Teacher teacher = teacherService.getById(user.getId());
+        if (Boolean.FALSE.equals(teacher.getCustomerService())) {
+            throw new BizException("权限不足");
+        }
+        StudentVo detail = studentService.detail(id);
+        if (detail != null && detail.getTenantGroupId() != null) {
+            TenantGroup group = tenantGroupService.getById(detail.getTenantGroupId());
+            detail.setTenantGroupName(group == null ? "" : group.getName());
+        }
+        return succeed(detail);
+    }
+
     /**
      * 查询老师所属机构下所有的学生
      *

+ 28 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/TeacherController.java

@@ -7,8 +7,10 @@ import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.TeacherDto;
 import com.yonge.cooleshow.biz.dal.entity.Subject;
 import com.yonge.cooleshow.biz.dal.entity.Teacher;
+import com.yonge.cooleshow.biz.dal.entity.TeacherStyleVideo;
 import com.yonge.cooleshow.biz.dal.entity.TenantInfo;
 import com.yonge.cooleshow.biz.dal.entity.TenantUnbindRecord;
+import com.yonge.cooleshow.biz.dal.enums.AuthStatusEnum;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.SmsCodeService;
 import com.yonge.cooleshow.biz.dal.service.SubjectService;
@@ -30,13 +32,18 @@ import com.yonge.toolset.base.util.StringUtil;
 import com.yonge.toolset.mybatis.support.PageUtil;
 import com.yonge.toolset.utils.idcard.IdcardInfoExtractor;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.util.CollectionUtils;
 import org.springframework.validation.annotation.Validated;
 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;
@@ -83,6 +90,27 @@ public class TeacherController extends BaseController {
         return teacherService.queryUserInfo(user.getId());
     }
 
+
+    /**
+     * 查询单条
+     */
+    @GetMapping("/detail/{id}")
+    public HttpResponseResult<TeacherVo> detail(@PathVariable("id") Long userId) {
+        SysUser user = sysUserFeignService.queryUserInfo();
+        Teacher teacher = teacherService.getById(user.getId());
+        if (Boolean.FALSE.equals(teacher.getCustomerService())) {
+            throw new BizException("权限不足");
+        }
+
+        TeacherVo detail = teacherService.findTeacherDetailInfo(userId);
+        if (null != detail && !CollectionUtils.isEmpty(detail.getStyleVideo())) {
+            List<TeacherStyleVideo> styleVideo = detail.getStyleVideo();
+            List<TeacherStyleVideo> collect = styleVideo.stream().filter(o -> AuthStatusEnum.PASS.equals(o.getAuthStatus())).collect(Collectors.toList());
+            detail.setStyleVideo(collect);
+        }
+        return succeed(detail);
+    }
+
     @ApiOperation(value = "开通直播")
     @GetMapping("/openLive")
     public HttpResponseResult<Boolean> openLive() {

+ 2 - 2
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/TeacherCourseScheduleController.java

@@ -215,8 +215,8 @@ public class TeacherCourseScheduleController extends BaseController {
         if (user == null || null == user.getId()) {
             return failed(HttpStatus.FORBIDDEN, "请登录");
         }
-        courseScheduleService.arrangeCourse(arrangeCourseVo, user.getId());
-        return succeed();
+        String message = courseScheduleService.arrangeCourse(arrangeCourseVo, user.getId());
+        return succeed(message);
     }
 
     @ApiOperation("根据月份查询消耗时长")

+ 33 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/UserOrderController.java

@@ -12,6 +12,7 @@ import com.yonge.cooleshow.biz.dal.dto.req.OrderReq;
 import com.yonge.cooleshow.biz.dal.dto.search.OrderSearch;
 import com.yonge.cooleshow.biz.dal.entity.UserOrder;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.GoodTypeEnum;
 import com.yonge.cooleshow.biz.dal.service.TenantStaffService;
 import com.yonge.cooleshow.biz.dal.service.UserOrderService;
 import com.yonge.cooleshow.biz.dal.service.UserPaymentCoreService;
@@ -137,6 +138,38 @@ public class UserOrderController extends BaseController {
         }
     }
 
+
+    @ApiOperation(value = "通过业务id查询用户正在交易中的订单")
+    @PostMapping("/getPendingOrder")
+    @ApiImplicitParams({
+        @ApiImplicitParam(
+            name = "goodType",
+            value = "订单类型:  PRACTICE、陪练课购买  LIVE、直播课购买 VIDEO、视频课购买 MUSIC、单曲点播 ACTI_REGIST、活动报名",
+            paramType = "query", dataType = "String", required = true
+        ),
+        @ApiImplicitParam(
+            name = "bizId",
+            value = "业务id 直播课、陪练课购买为课程组id;陪练课为老师id;单曲点播传曲子id",
+            paramType = "query", dataType = "Long"
+        )
+    })
+    public HttpResponseResult<UserOrderVo> getPendingOrder(@ApiIgnore @RequestBody OrderSearch query) {
+        if (null == query.getGoodType()
+            || (!GoodTypeEnum.VIP.getCode().equals(query.getGoodType())
+            && !GoodTypeEnum.SVIP.getCode().equals(query.getGoodType())
+            && null == query.getBizId())) {
+            return HttpResponseResult.failed("参数异常");
+        }
+        SysUser user = sysUserFeignService.queryUserInfo();
+        if (user == null || null == user.getId()) {
+            return failed(HttpStatus.FORBIDDEN, "请登录");
+        }
+        query.setUserId(user.getId());
+        query.setOrderClient(ClientEnum.TEACHER.name());
+        return userOrderService.getPendingOrder(query);
+    }
+
+
     @ApiOperation(value = "取消订单")
     @PostMapping("/orderCancel")
     @ApiImplicitParams({

+ 1 - 1
cooleshow-app/src/main/java/com/yonge/cooleshow/website/controller/MusicSheetController.java

@@ -177,7 +177,7 @@ public class MusicSheetController extends BaseController {
     @GetMapping(value="/queryRelatedList")
     public HttpResponseResult<PageInfo<MusicSheetVo>> queryRelatedList(MusicSheetRelatedQueryInfo queryInfo) {
     	
-    	IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.queryRelatedList(PageUtil.getPage(queryInfo),queryInfo.getAlbumId(), queryInfo.getMusicSheetId());
+    	IPage<MusicSheetVo> musicSheetVoIPage = musicSheetService.queryRelatedList(PageUtil.getPage(queryInfo), queryInfo);
         return succeed(PageUtil.pageInfo(musicSheetVoIPage));
     }
 }

+ 3 - 2
cooleshow-app/src/main/java/com/yonge/cooleshow/website/controller/WebCourseScheduleController.java

@@ -23,6 +23,7 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.validation.annotation.Validated;
@@ -211,8 +212,8 @@ public class WebCourseScheduleController extends BaseController {
         if (user == null || null == user.getId()) {
             return failed(HttpStatus.FORBIDDEN, "请登录");
         }
-        courseScheduleService.arrangeCourse(arrangeCourseVo, user.getId());
-        return succeed();
+        String message = courseScheduleService.arrangeCourse(arrangeCourseVo, user.getId());
+        return succeed(message);
     }
 
     @ApiOperation("根据月份查询消耗时长")

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

@@ -16,8 +16,8 @@ import java.io.Serializable;
 @Component
 public class CustomerServiceConfig implements Serializable {
 
-    @Value("${app.customer.service:17740683946}")
-    private String customerService;
+//    @Value("${app.customer.service:17740683946}")
+//    private String customerService;
     @Value("${app.customer.message:}")
     private String customerMessage;
     @Value("${app.customer.title:}")

+ 3 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/dao/SysUserDao.java

@@ -185,4 +185,7 @@ public interface SysUserDao extends BaseDAO<Long, SysUser> {
     void updateStudentHideFlag(@Param("userId") Long userId, @Param("hideFlag") int hideFlag);
 
     void updateAvatar(@Param("clientId") String clientId, @Param("avatar") String avatar,@Param("id") Long id);
+
+    SysUser getCustomerServiceByFriendLeast();
+
 }

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

@@ -3,6 +3,7 @@ package com.yonge.cooleshow.auth.service.impl;
 import com.alibaba.fastjson.JSON;
 import com.google.common.collect.Lists;
 import com.yonge.cooleshow.api.feign.AdminFeignService;
+import com.yonge.cooleshow.api.feign.TeacherFeignService;
 import com.yonge.cooleshow.api.feign.dto.UserFriendInfoVO;
 import com.yonge.cooleshow.auth.api.dto.QRLoginDto;
 import com.yonge.cooleshow.auth.api.dto.RealnameAuthReq;
@@ -218,24 +219,15 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
 
             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);
-
+                SysUser customerService = sysUserDao.getCustomerServiceByFriendLeast();
+                if (customerService != null) {
                     // 发送添加系统客服好友消息
                     HttpResponseResult<Boolean> result = adminFeignService.customerService(UserFriendInfoVO.builder()
                             .userId(sysUser.getId())
                             .clientType(clientType)
-                            .friendIds(Lists.newArrayList(friend.getId()))
+                            .friendIds(Lists.newArrayList(customerService.getId()))
                             .build());
-                    log.info("sendSysCustomerServiceFriendMessage mobile={}, ret={}", mobile, JSON.toJSONString(result));
+                    log.info("sendSysCustomerServiceFriendMessage mobile={}, ret={}", customerService.getPhone(), JSON.toJSONString(result));
                 }
 
             });

+ 17 - 0
cooleshow-auth/auth-server/src/main/resources/config/mybatis/SysUserMapper.xml

@@ -382,4 +382,21 @@
             update sys_user set avatar_ = #{avatar} where id_ = #{id}
         </if>
     </update>
+
+    <select id="getCustomerServiceByFriendLeast" resultMap="SysUser">
+        select m.*
+        from (SELECT te.user_id_,
+                     count(distinct iuf.friend_id_) friends
+              from teacher te
+                       left join sys_user su on te.user_id_ = su.id_
+                       left join im_user_friend iuf on te.user_id_ = iuf.user_id_
+              where te.lock_flag_ = 0
+                and te.customer_service_ = 1
+                and su.del_flag_ = 0
+                and su.lock_flag_ = 0
+              group by te.user_id_
+              order by friends
+              limit 1) t
+                 left join sys_user m on m.id_ = t.user_id_
+    </select>
 </mapper>

+ 16 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/constant/SysConfigConstant.java

@@ -110,6 +110,7 @@ public interface SysConfigConstant {
      * @updateTime 2022/4/20 11:43
      */
     String GOOD_LOGO_VIP = "good_logo_vip";
+    String GOOD_LOGO_SVIP = "good_logo_svip";
     /***
      * 商品视频课图片
      * @author liweifan
@@ -429,4 +430,19 @@ public interface SysConfigConstant {
      * 草稿保存时长
      */
     String USER_MUSIC_DRAFT_TIME = "user_music_draft_time";
+
+    /**
+     * 添加客服好友时,客服发送消息
+     */
+    String CUSTOMER_SERVICE_ADD_MSG = "customer_service_add_msg";
+
+    /**
+     * 添加客服好友时,客服发送消息标题
+     */
+    String CUSTOMER_SERVICE_ADD_MSG_TITLE = "customer_service_add_msg_title";
+
+    /**
+     * 群成员人数限制
+     */
+    String GROUP_MEMBER_LIMIT = "group_member_limit";
 }

+ 1 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/RewardTypeEnum.java

@@ -13,6 +13,7 @@ public enum RewardTypeEnum implements BaseEnum<String, RewardTypeEnum> {
 
     ACTUAL("实物"),
     VIP("小酷AI会员"),
+    SVIP("小酷AISVIP会员"),
     PIANO_ROOM("琴房时长"),
     COUPON("优惠券"),
     ;

+ 1 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/UnitEnum.java

@@ -22,6 +22,7 @@ public enum UnitEnum implements BaseEnum<String, UnitEnum> {
 //    YEAR("年"),
     QUARTERLY("季度"),
     YEAR_HALF("半年"),
+    PERPETUAL("永久"),
     ;
 
     @EnumValue

+ 1 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EPaymentType.java

@@ -10,6 +10,7 @@ import lombok.Getter;
 public enum EPaymentType {
 
     VIP("开通会员"),
+    SVIP("开通会员 SVIP"),
     PRACTICE("陪练课购买"),
     LIVE("直播课购买"),
     VIDEO("视频课购买"),

+ 13 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/CourseScheduleStudentPaymentDao.java

@@ -30,7 +30,7 @@ public interface CourseScheduleStudentPaymentDao extends BaseMapper<CourseSchedu
      * @author zx
      * @date 2022/3/23 16:18
      */
-    Set<Long> queryStudentIds(@Param("courseGroupId") Long courseGroupId,
+    List<Long> queryStudentIds(@Param("courseGroupId") Long courseGroupId,
                               @Param("courseGroupType") String courseGroupType);
 
     /**
@@ -87,5 +87,17 @@ public interface CourseScheduleStudentPaymentDao extends BaseMapper<CourseSchedu
     List<CourseScheduleStudentVo> selectUser();
 
     List<BasicUserInfoDto> queryNoJoinStu(@Param("scheduleId") String scheduleId, @Param("studentIds") List<String> studentIds);
+
+    /**
+     * 更新用户入群状态
+     * @param courseGroupId 课程组id
+     * @param courseGroupType 课程组类型
+     * @param groupJoin 入群状态
+     * @param studentIds 学员id
+     */
+    void updateGroupJoinStatus(@Param("courseGroupId") Long courseGroupId,
+                               @Param("courseGroupType") String courseGroupType,
+                               @Param("groupJoin") Boolean groupJoin,
+                               @Param("studentIds") List<Long> studentIds);
 }
 

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

@@ -23,5 +23,7 @@ public interface ImUserFriendDao extends BaseMapper<ImUserFriend> {
 
     void delStudentFriendByTenantId(@Param("tenantId") Long tenantId,@Param("userId") Long userId ,
                                     @Param("clientType") String clientType);
+
+    List<ImUserFriend> queryExistCustomerServiceFriend(@Param("userIds") String userIds, @Param("clientType") String clientType);
 }
 

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

@@ -213,4 +213,6 @@ public interface MusicSheetDao extends BaseMapper<MusicSheet> {
     MusicSheet get(Long id);
 
     IPage<MusicSheet> selectSyncPage(Page<Object> objectPage);
+
+    IPage<MusicSheetVo> queryTenantRelatedList(@Param("page") IPage<Object> page, @Param("queryInfo") MusicSheetRelatedQueryInfo queryInfo);
 }

+ 1 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/StudentDao.java

@@ -82,4 +82,5 @@ public interface StudentDao extends BaseMapper<Student> {
     Integer queryStudentCounts(@Param("id") Long id);
 
     List<StudentWrapper.UserCount> countStudentByTenantGroupIds(@Param("tenantId") Long tenantId, @Param("groupIdList") List<Long> groupIdList);
+
 }

+ 5 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/TeacherDao.java

@@ -16,6 +16,7 @@ import com.yonge.cooleshow.biz.dal.vo.TeacherVo;
 
 import com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantInfoWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.teacher.TeacherWrapper;
 import org.apache.ibatis.annotations.Param;
 
 public interface TeacherDao extends BaseMapper<Teacher> {
@@ -115,4 +116,8 @@ public interface TeacherDao extends BaseMapper<Teacher> {
     List<TenantInfoWrapper.UserCount> countTeacherByTenantIds(@Param("tenantIdList") List<Long> tenantIdList);
 
     Integer queryTeacherCounts(@Param("id") Long id);
+
+    Teacher getCustomerServiceByFriendLeast();
+
+    List<TeacherWrapper.TeacherFriend> getCustomerServiceFriendNums();
 }

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

@@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.yonge.cooleshow.biz.dal.dto.search.VipRecordSearch;
 import com.yonge.cooleshow.biz.dal.entity.MemberPriceSettings;
 import com.yonge.cooleshow.biz.dal.vo.VipRecordVo;
+import com.yonge.cooleshow.biz.dal.wrapper.StudentWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import org.apache.ibatis.annotations.Param;
 import com.yonge.cooleshow.biz.dal.entity.VipCardRecord;
 import com.yonge.cooleshow.biz.dal.vo.VipCardRecordVo;
@@ -58,4 +60,6 @@ public interface VipCardRecordDao extends BaseMapper<VipCardRecord> {
      * @return
      */
     IPage<VipRecordVo> selectVipRecord(@Param("page") IPage<VipRecordVo> page, @Param("param") VipRecordSearch param);
+
+    List<VipCardRecordWrapper.UserVipInfo> queryUserVipInfo(@Param("userIdList") List<Long> userIdList ,@Param("clientType") String clientType);
 }

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

@@ -3,6 +3,8 @@ package com.yonge.cooleshow.biz.dal.dto;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import java.util.Date;
+
 /**
 * @description: 用户基本信息
 * @author zx
@@ -27,4 +29,10 @@ public class BasicUserInfo {
 
     @ApiModelProperty("手机号")
     private String phone;
+
+    @ApiModelProperty("性别")
+    private Integer gender;
+
+    @ApiModelProperty("生日")
+    private Date birthdate;
 }

+ 44 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/req/OrderReq.java

@@ -32,7 +32,7 @@ public class OrderReq {
     @ApiModelProperty(value = "订单名称 ", required = true)
     private String orderName;
     @NotNull(message = "订单类型不能为空")
-    @ApiModelProperty(value = "订单类型: 学生端( VIP、开通会员  PRACTICE、陪练课购买  LIVE、直播课购买 VIDEO、视频课购买 MUSIC、单曲点播 ACTI_REGIST、活动报名 ) 老师端(VIP、开通会员 PIANO_ROOM、琴房时长 ACTI_REGIST 活动报名)", required = true)
+    @ApiModelProperty(value = "订单类型: 学生端( VIP、开通会员  SVIP:SVIP PRACTICE、陪练课购买  LIVE、直播课购买 VIDEO、视频课购买 MUSIC、单曲点播 ACTI_REGIST、活动报名 ) 老师端(VIP、开通会员 PIANO_ROOM、琴房时长 ACTI_REGIST 活动报名)", required = true)
     private OrderTypeEnum orderType;
     @ApiModelProperty(value = "订单描述信息 ")
     private String orderDesc;
@@ -71,10 +71,21 @@ public class OrderReq {
         private GoodTypeEnum goodType;
         @ApiModelProperty("商品名称 ")
         private String goodName;
+
+        @ApiModelProperty(value = "下单客户端 ",hidden = true)
+        private ClientEnum orderClient;
+        @ApiModelProperty(value = "vip剩余天数")
+        private Integer vipEndDays;
+
+        @ApiModelProperty(value = "商品数量")
+        private Integer goodsNum = 1;
+
         @ApiModelProperty(value = "优惠券id")
         private Long couponId;
         @ApiModelProperty(value = "业务内容")
         private Object bizContent;
+        @ApiModelProperty(value = "业务价格")
+        private BigDecimal bizPrice;
         @ApiModelProperty(value = "调用业务创建方法返回", hidden = true)
         private OrderCreateRes createRes;
         @ApiModelProperty(value = "订单金额", required = true)
@@ -85,6 +96,38 @@ public class OrderReq {
         // 透传订单类型
         private OrderTypeEnum orderType;
 
+        public BigDecimal getBizPrice() {
+            return bizPrice;
+        }
+
+        public void setBizPrice(BigDecimal bizPrice) {
+            this.bizPrice = bizPrice;
+        }
+
+        public Integer getGoodsNum() {
+            return goodsNum;
+        }
+
+        public void setGoodsNum(Integer goodsNum) {
+            this.goodsNum = goodsNum;
+        }
+
+        public ClientEnum getOrderClient() {
+            return orderClient;
+        }
+
+        public void setOrderClient(ClientEnum orderClient) {
+            this.orderClient = orderClient;
+        }
+
+        public Integer getVipEndDays() {
+            return vipEndDays;
+        }
+
+        public void setVipEndDays(Integer vipEndDays) {
+            this.vipEndDays = vipEndDays;
+        }
+
         public BigDecimal getActualPrice() {
             return actualPrice;
         }

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

@@ -65,6 +65,9 @@ public class TeacherSubmitReq implements Serializable {
     @ApiModelProperty(value = "后台修改人",hidden = true)
     private Long updateBy;
 
+    @ApiModelProperty("是否客服")
+    private Boolean customerService;
+
     public Long getUserId() {
         return userId;
     }

+ 7 - 13
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/MemberPriceSettingsSearch.java

@@ -1,13 +1,16 @@
 package com.yonge.cooleshow.biz.dal.dto.search;
 
+import com.yonge.cooleshow.biz.dal.enums.EVipType;
 import com.yonge.toolset.base.page.QueryInfo;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
 
 /**
  * @Author: liweifan
  * @Data: 2022-04-25 14:34:49
  */
+@Data
 @ApiModel(value = "MemberPriceSettingsSearch对象", description = "查询对象")
 public class MemberPriceSettingsSearch extends QueryInfo{
 	private static final long serialVersionUID = 1L;
@@ -18,19 +21,10 @@ public class MemberPriceSettingsSearch extends QueryInfo{
 	@ApiModelProperty("活动id")
 	private Long  activityId;
 
-	public Long getActivityId() {
-		return activityId;
-	}
+	@ApiModelProperty("true:启用,false:停用")
+	private Boolean status;
 
-	public void setActivityId(Long activityId) {
-		this.activityId = activityId;
-	}
+	@ApiModelProperty("VIP,SVIP")
+	private EVipType vipType;
 
-	public Long getUserId() {
-		return userId;
-	}
-
-	public void setUserId(Long userId) {
-		this.userId = userId;
-	}
 }

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

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.dto.search;
 
+import com.yonge.cooleshow.biz.dal.enums.MusicSheetTypeEnum;
 import com.yonge.toolset.base.page.QueryInfo;
 
 public class MusicSheetRelatedQueryInfo extends QueryInfo {
@@ -8,7 +9,27 @@ public class MusicSheetRelatedQueryInfo extends QueryInfo {
 	
 	private Long musicSheetId;
 
-	public Long getAlbumId() {
+    private Long subjectId;
+
+    private MusicSheetTypeEnum musicSheetType;
+
+    public MusicSheetTypeEnum getMusicSheetType() {
+        return musicSheetType;
+    }
+
+    public void setMusicSheetType(MusicSheetTypeEnum musicSheetType) {
+        this.musicSheetType = musicSheetType;
+    }
+
+    public Long getSubjectId() {
+        return subjectId;
+    }
+
+    public void setSubjectId(Long subjectId) {
+        this.subjectId = subjectId;
+    }
+
+    public Long getAlbumId() {
 		return albumId;
 	}
 

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

@@ -106,6 +106,29 @@ public class MusicSheetSearch  extends QueryInfo{
     @ApiModelProperty("指定关联专辑的曲目排在最后")
     private Long sortByAlbumIdDesc;
 
+
+    @ApiModelProperty(value = "不包含曲目ID",hidden = true)
+    private List<Long> excludeMusicIds;
+
+    @ApiModelProperty(value = "必须要匹配声部ID")
+    private List<Long> mustMatchSubjectIds;
+
+    public List<Long> getExcludeMusicIds() {
+        return excludeMusicIds;
+    }
+
+    public void setExcludeMusicIds(List<Long> excludeMusicIds) {
+        this.excludeMusicIds = excludeMusicIds;
+    }
+
+    public List<Long> getMustMatchSubjectIds() {
+        return mustMatchSubjectIds;
+    }
+
+    public void setMustMatchSubjectIds(List<Long> mustMatchSubjectIds) {
+        this.mustMatchSubjectIds = mustMatchSubjectIds;
+    }
+
     public SourceTypeEnum getProviderType() {
         return providerType;
     }

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

@@ -22,7 +22,7 @@ public class OrderSearch extends QueryInfo{
 	@ApiModelProperty("下单应用:STUDENT 学生端 TEACHER 老师端")
 	private String orderClient;
 
-	@ApiModelProperty("交易类型:  VIP、开通会员  PRACTICE、陪练课购买  LIVE、直播课购买 VIDEO、视频课购买 MUSIC、单曲点播 ACTI_REGIST、活动报名(多选用,分割)")
+	@ApiModelProperty("交易类型:  VIP、开通会员  SVIP、开通会员 PRACTICE、陪练课购买  LIVE、直播课购买 VIDEO、视频课购买 MUSIC、单曲点播 ACTI_REGIST、活动报名(多选用,分割)")
 	private String orderType;
 
 	@ApiModelProperty("订单状态 WAIT_PAY 待支付 PAYING 支付中  PAID 已付款 CLOSE 已关闭 FAIL 支付失败 (多选用,分割)")

+ 13 - 9
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/StudentSearch.java

@@ -1,6 +1,7 @@
 package com.yonge.cooleshow.biz.dal.dto.search;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.yonge.cooleshow.biz.dal.enums.EUserVipType;
 import com.yonge.cooleshow.biz.dal.enums.GenderEnum;
 import com.yonge.cooleshow.common.enums.UserLockFlag;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
@@ -31,8 +32,8 @@ public class StudentSearch extends QueryInfo{
     @ApiModelProperty(value = "0-正常, 1-锁定")
     private UserLockFlag lockFlag;
     private YesOrNoEnum delFlag;
-    @ApiModelProperty(value = "是否会员 0否 1是")
-    private YesOrNoEnum isVip;
+//    @ApiModelProperty(value = "是否会员 0否 1是")
+//    private YesOrNoEnum isVip;
 
     @ApiModelProperty(value = "是否练习 0否 1是")
     private YesOrNoEnum trainFlag;
@@ -80,6 +81,9 @@ public class StudentSearch extends QueryInfo{
     @ApiModelProperty("机构购买专辑的购买记录ID")
     private Long tenantAlbumPurchaseId;
 
+    @ApiModelProperty("用户会员类型")
+    private EUserVipType vipType;
+
     @ApiModelProperty(value = "手机号码列表", hidden = true)
     private List<String> phoneList = new ArrayList<>();
 
@@ -138,13 +142,13 @@ public class StudentSearch extends QueryInfo{
         this.lockFlag = lockFlag;
     }
 
-    public YesOrNoEnum getIsVip() {
-        return isVip;
-    }
-
-    public void setIsVip(Integer isVip) {
-        this.isVip = YesOrNoEnum.valueOf(isVip);
-    }
+//    public YesOrNoEnum getIsVip() {
+//        return isVip;
+//    }
+//
+//    public void setIsVip(Integer isVip) {
+//        this.isVip = YesOrNoEnum.valueOf(isVip);
+//    }
 
     public Date getStartTime() {
         return startTime;

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

@@ -1,6 +1,7 @@
 package com.yonge.cooleshow.biz.dal.dto.search;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.yonge.cooleshow.biz.dal.enums.EUserVipType;
 import com.yonge.cooleshow.common.enums.ESettlementFrom;
 import com.yonge.cooleshow.common.enums.UserLockFlag;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
@@ -32,8 +33,8 @@ public class TeacherSearch extends QueryInfo{
     
     private YesOrNoEnum delFlag;
     
-    @ApiModelProperty(value = "是否会员(0-否 1-是)")
-    private Integer isVip;
+//    @ApiModelProperty(value = "是否会员(0-否 1-是)")
+//    private Integer isVip;
     
     @ApiModelProperty("用户状态")
     private String userStatus;
@@ -78,6 +79,12 @@ public class TeacherSearch extends QueryInfo{
 	@ApiModelProperty("老师ID")
 	private Long userId;
 
+	@ApiModelProperty("用户会员类型")
+	private EUserVipType vipType;
+
+	@ApiModelProperty("是否客服")
+	private Boolean customerService;
+
 	@ApiModelProperty(value = "排序方式, 默认 create_time_ desc", hidden = true)
 	private String orderBy;
 	public YesOrNoEnum getTrainFlag() {

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

@@ -3,6 +3,7 @@ package com.yonge.cooleshow.biz.dal.dto.search;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.EVipType;
 import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
 import com.yonge.toolset.base.page.QueryInfo;
 import io.swagger.annotations.ApiModel;
@@ -45,6 +46,12 @@ public class VipRecordSearch extends QueryInfo {
     @ApiModelProperty("来源类型 : ACTIVITY :活动 ,ORDER:订单 PLATFORM:平台")
     private SourceTypeEnum sourceType;
 
+    @ApiModelProperty(value = "是否展示1:展示,0:隐藏",hidden = true)
+    private Boolean displayFlag;
+
+    @ApiModelProperty("会员类型")
+    private EVipType vipType;
+
     public SourceTypeEnum getSourceType() {
         return sourceType;
     }
@@ -94,4 +101,20 @@ public class VipRecordSearch extends QueryInfo {
     public void setSearch(String search) {
         this.search = search;
     }
+
+    public Boolean getDisplayFlag() {
+        return displayFlag;
+    }
+
+    public void setDisplayFlag(Boolean displayFlag) {
+        this.displayFlag = displayFlag;
+    }
+
+    public EVipType getVipType() {
+        return vipType;
+    }
+
+    public void setVipType(EVipType vipType) {
+        this.vipType = vipType;
+    }
 }

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

@@ -65,5 +65,10 @@ public class CourseScheduleStudentPayment implements Serializable {
     @ApiModelProperty(value = "类型 practice陪练课 live直播课")
     private String courseType;
 
+    @TableField(value = "group_join_")
+    @ApiModelProperty("入群标记")
+    private Boolean groupJoin;
+
+
 }
 

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

@@ -75,6 +75,10 @@ public class ImGroup implements Serializable {
     @ApiModelProperty(value = "群聊配置")
     private String configJson;
 
+    @TableField(exist = false) // 不映射数据库字段,返回群成员人数限制
+    @ApiModelProperty("群成员人数限制")
+    private Integer groupMemberLimit;
+
     public Long getCourseGroupId() {
         return courseGroupId;
     }
@@ -178,5 +182,13 @@ public class ImGroup implements Serializable {
     public void setConfigJson(String configJson) {
         this.configJson = configJson;
     }
+
+    public Integer getGroupMemberLimit() {
+        return groupMemberLimit;
+    }
+
+    public void setGroupMemberLimit(Integer groupMemberLimit) {
+        this.groupMemberLimit = groupMemberLimit;
+    }
 }
 

+ 12 - 58
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/MemberPriceSettings.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.EVipType;
 import com.yonge.cooleshow.biz.dal.enums.PeriodEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -11,11 +12,13 @@ import io.swagger.annotations.ApiModelProperty;
 import java.io.Serializable;
 import java.util.Date;
 import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
 import javax.validation.constraints.PositiveOrZero;
 import java.math.BigDecimal;
 
+@Data
 @TableName("member_price_settings")
 @ApiModel(value = "MemberPriceSettings对象", description = "")
 public class MemberPriceSettings implements Serializable {
@@ -50,68 +53,19 @@ public class MemberPriceSettings implements Serializable {
 	@TableField(value = "update_by_")
 	private Long updateBy;
 
-	public Long getId() {
-		return id;
-	}
 
-	public void setId(Long id) {
-		this.id = id;
-	}
+    @ApiModelProperty("状态 1:启用 0:停用 ")
+    @TableField(value = "status_")
+    private Boolean status;
 
-	public PeriodEnum getPeriod() {
-		return period;
-	}
 
-	public void setPeriod(PeriodEnum period) {
-		this.period = period;
-	}
+    @ApiModelProperty("描述文案")
+    @TableField(value = "desc_")
+    private String desc;
 
-	public BigDecimal getSalePrice() {
-		return salePrice;
-	}
 
-	public void setSalePrice(BigDecimal salePrice) {
-		this.salePrice = salePrice;
-	}
-
-	public BigDecimal getOriginalPrice() {
-		return originalPrice;
-	}
-
-	public void setOriginalPrice(BigDecimal originalPrice) {
-		this.originalPrice = originalPrice;
-	}
-
-	public Date getCreateTime() {
-		return createTime;
-	}
-
-	public void setCreateTime(Date createTime) {
-		this.createTime = createTime;
-	}
-
-	public Date getUpdateTime() {
-		return updateTime;
-	}
-
-	public void setUpdateTime(Date updateTime) {
-		this.updateTime = updateTime;
-	}
-
-	public Long getCreateBy() {
-		return createBy;
-	}
-
-	public void setCreateBy(Long createBy) {
-		this.createBy = createBy;
-	}
-
-	public Long getUpdateBy() {
-		return updateBy;
-	}
-
-	public void setUpdateBy(Long updateBy) {
-		this.updateBy = updateBy;
-	}
 
+    @ApiModelProperty("会员类型")
+    @TableField(value = "vip_type_")
+    private EVipType vipType;
 }

+ 16 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/StudentTime.java

@@ -25,6 +25,13 @@ public class StudentTime implements Serializable {
     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
     private Date firstVipTime;
+
+
+    @ApiModelProperty("第一次购买svip时间 ")
+    @TableField(value = "first_svip_time_")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
+    private Date firstSvipTime;
     @ApiModelProperty("第一次购买陪练课时间 ")
     @TableField(value = "first_practice_time_")
     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@@ -65,6 +72,15 @@ public class StudentTime implements Serializable {
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
     private Date firstActivityTime;
 
+
+    public Date getFirstSvipTime() {
+        return firstSvipTime;
+    }
+
+    public void setFirstSvipTime(Date firstSvipTime) {
+        this.firstSvipTime = firstSvipTime;
+    }
+
     public Date getFirstActivityTime() {
         return firstActivityTime;
     }

+ 4 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/Teacher.java

@@ -251,6 +251,10 @@ public class Teacher implements Serializable {
     @TableField(value = "im_device_id_")
     private String imDeviceId;
 
+    @ApiModelProperty("是否是客服")
+    @TableField(value = "customer_service_")
+    private Boolean customerService;
+
     public ESettlementFrom getSettlementFrom() {
         return settlementFrom;
     }

+ 5 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/UserOrderDetail.java

@@ -95,4 +95,9 @@ public class UserOrderDetail implements Serializable {
     @TableField(value = "tenant_group_album_id_")
     private Long tenantGroupAlbumId;
 
+
+    @ApiModelProperty("业务数据")
+    @TableField(value = "biz_json_")
+    private String bizJson;
+
 }

+ 27 - 130
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/VipCardRecord.java

@@ -4,20 +4,20 @@ 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.ClientEnum;
-import com.yonge.cooleshow.biz.dal.enums.PeriodEnum;
-import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
+import com.yonge.cooleshow.biz.dal.enums.*;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
 import java.io.Serializable;
 import java.util.Date;
 import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
 /**
  * 购买会员卡记录表
  */
+@Data
 @TableName("vip_card_record")
 @ApiModel(value = "VipCardRecord对象", description = "购买会员卡记录表")
 public class VipCardRecord implements Serializable {
@@ -90,131 +90,28 @@ public class VipCardRecord implements Serializable {
     @TableField(value = "reason_")
     private String reason;
 
-    public Long getCreateBy() {
-        return createBy;
-    }
-
-    public void setCreateBy(Long createBy) {
-        this.createBy = createBy;
-    }
-
-    public String getReason() {
-        return reason;
-    }
-
-    public void setReason(String reason) {
-        this.reason = reason;
-    }
-
-    public Integer getTimes() {
-        return times;
-    }
-
-    public void setTimes(Integer times) {
-        this.times = times;
-    }
-
-    public PeriodEnum getType() {
-        return type;
-    }
-
-    public void setType(PeriodEnum type) {
-        this.type = type;
-    }
-
-    public SourceTypeEnum getSourceType() {
-        return sourceType;
-    }
-
-    public void setSourceType(SourceTypeEnum sourceType) {
-        this.sourceType = sourceType;
-    }
-
-    public ClientEnum getClientType() {
-        return clientType;
-    }
-
-    public void setClientType(ClientEnum clientType) {
-        this.clientType = clientType;
-    }
-
-    public Long getId() {
-        return id;
-    }
-
-    public void setId(Long id) {
-        this.id = id;
-    }
-    
-	public Long getUserId() {
-        return userId;
-    }
-
-    public void setUserId(Long userId) {
-        this.userId = userId;
-    }
-
-    public String getOrderNo() {
-        return orderNo;
-    }
-
-    public void setOrderNo(String orderNo) {
-        this.orderNo = orderNo;
-    }
-
-    public String getSubOrderNo() {
-        return subOrderNo;
-    }
-
-    public void setSubOrderNo(String subOrderNo) {
-        this.subOrderNo = subOrderNo;
-    }
-
-    public Long getVipCardId() {
-        return vipCardId;
-    }
-
-    public void setVipCardId(Long vipCardId) {
-        this.vipCardId = vipCardId;
-    }
-
-    public Date getStartTime() {
-        return startTime;
-    }
-
-    public void setStartTime(Date startTime) {
-        this.startTime = startTime;
-    }
-    
-	public Date getCreateTime() {
-        return createTime;
-    }
-
-    public void setCreateTime(Date createTime) {
-        this.createTime = createTime;
-    }
-    
-	public Date getUpdateTime() {
-        return updateTime;
-    }
-
-    public void setUpdateTime(Date updateTime) {
-        this.updateTime = updateTime;
-    }
-    
-	public Date getEndTime() {
-        return endTime;
-    }
-
-    public void setEndTime(Date endTime) {
-        this.endTime = endTime;
-    }
-
-    public Integer getMsgStatus() {
-        return msgStatus;
-    }
-
-    public void setMsgStatus(Integer msgStatus) {
-        this.msgStatus = msgStatus;
-    }
+    @ApiModelProperty("会员类型 VIP,SVIP")
+    @TableField(value = "vip_type_")
+    private EVipType vipType;
+
+    @ApiModelProperty("状态 ADD:新增,DEDUCTION:扣减,UPDATE:变更")
+    @TableField(value = "status_")
+    private EVipRecordStatus status;
+
+    @ApiModelProperty("是否展示1:展示,0:隐藏")
+    @TableField(value = "display_flag_")
+    private Boolean displayFlag;
+
+    @ApiModelProperty("是否有效 1:有效,0:失效")
+    @TableField(value = "efficient_flag_")
+    private Boolean efficientFlag;
+
+    @ApiModelProperty("关联ID")
+    @TableField(value = "ref_id_")
+    private Long refId;
+
+    @ApiModelProperty("是否发送消息")
+    @TableField(value = "send_msg_")
+    private Boolean sendMsg;
+
 }

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

@@ -16,6 +16,7 @@ public enum AccountBizTypeEnum implements BaseEnum<String, AccountBizTypeEnum> {
     VIDEO("视频课"),
     MUSIC("乐谱购买"),
     VIP("会员充值"),
+    SVIP("SVIP会员充值"),
     MALL("商品购买"),
     PIANO_ROOM("琴房充值"),
     ACTI_REGIST("活动报名"),

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

@@ -0,0 +1,33 @@
+package com.yonge.cooleshow.biz.dal.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+
+/**
+ * 用户会员类型
+ */
+public enum EUserVipType implements BaseEnum<String, EUserVipType> {
+
+    NORMAL("普通用户"),
+    VIP("VIP会员"),
+    SVIP("SVIP会员"),
+
+    ;
+    @EnumValue
+    private String code;
+    private String name;
+
+    EUserVipType(String name) {
+        this.code = this.name();
+        this.name = name;
+    }
+
+    @Override
+    public String getCode() {
+        return this.code;
+    }
+
+    public String getName() {
+        return name;
+    }
+}

+ 37 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/EVipRecordStatus.java

@@ -0,0 +1,37 @@
+package com.yonge.cooleshow.biz.dal.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+
+/**
+ * 认证审核类型 ADD 新增 MODIFY 修改
+ *
+ * @Author: liweifan
+ * @Data: 2022/3/16 10:19
+ */
+public enum EVipRecordStatus implements BaseEnum<String, EVipRecordStatus> {
+
+    //状态 ADD:新增,DEDUCTION:扣减,UPDATE:变更
+    ADD("新增"),
+    DEDUCTION("扣减"),
+    UPDATE("变更"),
+
+    ;
+    @EnumValue
+    private String code;
+    private String name;
+
+    EVipRecordStatus(String name) {
+        this.code = this.name();
+        this.name = name;
+    }
+
+    @Override
+    public String getCode() {
+        return this.code;
+    }
+
+    public String getName() {
+        return name;
+    }
+}

+ 46 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/EVipType.java

@@ -0,0 +1,46 @@
+package com.yonge.cooleshow.biz.dal.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+
+/**
+ * 认证审核类型 ADD 新增 MODIFY 修改
+ *
+ * @Author: liweifan
+ * @Data: 2022/3/16 10:19
+ */
+public enum EVipType implements BaseEnum<String, EVipType> {
+
+    // 字段 说明 VIP:会员 SVIP:SVIP,PERMANENT_SVIP:永久SVIP,NOT_VIP:不是vip
+
+    VIP("VIP"),
+    SVIP("SVIP"),
+
+
+    // 业务用字段
+    // 永久SVIP
+    PERMANENT_SVIP("永久SVIP"),
+
+    // 不是vip
+    NOT_VIP("不是vip"),
+    ALL_VIP("所有VIP"),
+
+    ;
+    @EnumValue
+    private String code;
+    private String name;
+
+    EVipType(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/GoodTypeEnum.java

@@ -11,6 +11,7 @@ import com.yonge.toolset.base.enums.BaseEnum;
  */
 public enum GoodTypeEnum implements BaseEnum<String, GoodTypeEnum> {
     VIP("开通会员"),
+    SVIP("开通会员 SVIP"),
     PRACTICE("陪练课购买"),
     LIVE("直播课购买"),
     VIDEO("视频课购买"),

+ 24 - 8
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/MessageTypeEnum.java

@@ -62,14 +62,22 @@ public enum MessageTypeEnum implements BaseEnum<String, MessageTypeEnum> {
     STUDENT_JOIN_FANSGROUP("学员申请加入粉丝群"),
     STUDENT_AUTOJOIN_FANSGROUP("学员自动加入粉丝群"),
 
-    VIP_BUY_SUCCESS("会员购买成功"),
-    SMS_VIP_BUY_SUCCESS("会员购买成功(短信)"),
-
-    VIP_EXPIRE_THIRTY_DAY("会员到期前30天"),
-    SMS_VIP_EXPIRE_THIRTY_DAY("会员到期前30天(短信)"),
-
-    VIP_EXPIRE("会员到期"),
-    SMS_VIP_EXPIRE("会员到期(短信)"),
+//    VIP_BUY_SUCCESS("会员购买成功"),
+    NEW_VIP_BUY_SUCCESS("会员购买成功"),
+    NEW_TEACHER_VIP_BUY_SUCCESS("会员购买成功"),
+//    SMS_VIP_BUY_SUCCESS("会员购买成功(短信)"),
+    SMS_NEW_VIP_BUY_SUCCESS("会员购买成功(短信)"),
+    SMS_TEACHER_NEW_VIP_BUY_SUCCESS("会员购买成功(短信)"),
+
+    VIP_EXPIRE_THIRTY_DAY("VIP会员到期前30天"),
+    SVIP_EXPIRE_THIRTY_DAY("SVIP会员到期前30天"),
+    SMS_VIP_EXPIRE_THIRTY_DAY("VIP会员到期前30天(短信)"),
+    SMS_SVIP_EXPIRE_THIRTY_DAY("SVIP会员到期前30天(短信)"),
+
+    VIP_EXPIRE("VIP会员到期"),
+    SVIP_EXPIRE("SVIP会员到期"),
+    SMS_VIP_EXPIRE("VIP会员到期(短信)"),
+    SMS_SVIP_EXPIRE("SVIP会员到期(短信)"),
 
     PRACTICE_BUY("陪练课购买"),
     SMS_PRACTICE_BUY("陪练课购买(短信)"),
@@ -110,6 +118,14 @@ public enum MessageTypeEnum implements BaseEnum<String, MessageTypeEnum> {
     PRACTICE_ADJUST("陪练课调整"),
     ACTIVITY_WIN("获奖消息"),
     PLATFORM_ADD_VIP("会员赠送"),
+    PLATFORM_ADD_SVIP("会员赠送"),
+
+    PLATFORM_ADD_PER_SVIP("会员永久赠送"),
+
+    PLATFORM_ADD_DUDECT_VIP("会员扣减"),
+    PLATFORM_ADD_DUDECT_SVIP("会员扣减"),
+    PLATFORM_ADD_DUDECT_PER_SVIP("会员永久扣减"),
+
     SMS_STUDENT_LIVE_COMPLETION_FAIL("直播课成课失败"),
     STUDENT_LIVE_COMPLETION_FAIL("直播课成课失败"),
     COUPON_ISSUE("优惠券发放"),

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

@@ -11,6 +11,7 @@ import com.yonge.toolset.base.enums.BaseEnum;
  */
 public enum OrderTypeEnum implements BaseEnum<String, OrderTypeEnum> {
     VIP("开通会员"),
+    SVIP("开通会员 SVIP"),
     PRACTICE("陪练课购买"),
     LIVE("直播课购买"),
     VIDEO("视频课购买"),

+ 4 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/PeriodEnum.java

@@ -12,7 +12,10 @@ public enum PeriodEnum implements BaseEnum<String, PeriodEnum> {
 	MONTH("月"),
 	QUARTERLY("季度"),
 	YEAR_HALF("半年"),
-	YEAR("年");
+	YEAR("年"),
+	PERPETUAL("永久"),
+
+    ;
 
 	@EnumValue
 	private String code;

+ 2 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/SourceTypeEnum.java

@@ -16,9 +16,11 @@ public enum SourceTypeEnum implements BaseEnum<String, AuditStatusEnum> {
     // 机构,机构自己上传曲目 , 暂时没有
     TENANT("机构"),
     PLATFORM("平台"),
+    PLATFORM_DEDUCT("后台扣减"),
     ACTIVITY("活动"),
     ORDER("订单"),
     BACKEND_GIVE("后台赠送"),
+    FREE_UPGRADE("免费升级"),
 
 
     ;

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

@@ -16,6 +16,7 @@ public enum CouponCategoryEnum implements BaseEnum<String, CouponCategoryEnum> {
 
     UNIVERSAL("全场通用", "UNIVERSAL"),
     VIP("小酷Ai", "VIP"),
+    SVIP("小酷Ai SVIP ", "SVIP"),
     PIANO("云酷琴房", "PIANO_ROOM"),
     MALL("商场购物券", "MALL"),
     MUSIC("单曲点播券", "MUSIC"),

+ 21 - 4
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/CourseScheduleService.java

@@ -10,11 +10,21 @@ import com.yonge.cooleshow.biz.dal.dto.search.PracticeTeacherSearch;
 import com.yonge.cooleshow.biz.dal.entity.CourseCalendarEntity;
 import com.yonge.cooleshow.biz.dal.entity.CourseSchedule;
 import com.yonge.cooleshow.biz.dal.entity.TeacherSubjectPrice;
-import com.yonge.cooleshow.biz.dal.entity.UserOrderDetail;
-import com.yonge.cooleshow.biz.dal.vo.*;
+import com.yonge.cooleshow.biz.dal.vo.ArrangeCourseVo;
+import com.yonge.cooleshow.biz.dal.vo.CourseAdjustVo;
+import com.yonge.cooleshow.biz.dal.vo.CourseScheduleRecordVo;
+import com.yonge.cooleshow.biz.dal.vo.CourseStudent;
+import com.yonge.cooleshow.biz.dal.vo.CourseStudentVo;
+import com.yonge.cooleshow.biz.dal.vo.MyCourseVo;
+import com.yonge.cooleshow.biz.dal.vo.PianoClassVo;
+import com.yonge.cooleshow.biz.dal.vo.PianoRoomTimeVo;
+import com.yonge.cooleshow.biz.dal.vo.PracticeTeacherVo;
+import com.yonge.cooleshow.biz.dal.vo.StudentHomePage;
+import com.yonge.cooleshow.biz.dal.vo.TeacherLiveCourseInfoVo;
+import com.yonge.cooleshow.biz.dal.vo.UserOrderDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.res.OrderCreateRes;
-import com.yonge.cooleshow.biz.dal.wrapper.course.CourseScheduleWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.UserPaymentOrderWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.course.CourseScheduleWrapper;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import com.yonge.toolset.base.page.PageInfo;
@@ -247,7 +257,14 @@ public interface CourseScheduleService extends IService<CourseSchedule> {
 
     PageInfo<CourseStudentVo> selectStudent(Map<String, Object> param);
 
-    void arrangeCourse(ArrangeCourseVo arrangeCourseVo, Long teacherId);
+    String arrangeCourse(ArrangeCourseVo arrangeCourseVo, Long teacherId);
+
+    /**
+     * 校验排课
+     * @param arrangeCourseVo 排课参数
+     * @param teacherId 老师id
+     */
+    String checkArrangeCourse(ArrangeCourseVo arrangeCourseVo, Long teacherId);
 
     Map<String, Object> selectConsumeTime(String month, Long teacherId);
 

+ 7 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImGroupMemberService.java

@@ -92,5 +92,12 @@ public interface ImGroupMemberService extends IService<ImGroupMember> {
     List<ImGroupMember> findChatGroupAllMemberInfo(Map<String, Object> params);
 
     IPage<ImGroupMemberWrapper.ImGroupMember> selectPage(@Param("page") IPage<ImGroupMemberWrapper.ImGroupMember> page,@Param("query") ImGroupMemberWrapper.ImGroupMemberQuery query);
+
+    /**
+     * 获取群成员数量
+     * @param groupId 群ID
+     * @return int
+     */
+    int countGroupMember(String groupId);
 }
 

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

@@ -85,10 +85,11 @@ public interface ImGroupService extends IService<ImGroup> {
     * @description: 成课后自动创建群聊,建议放在最后执行
      * @param courseGroupId 课程组编号
      * @param courseGroupType 课程组类型
+     * @param noGroupJoinUserIds 未加入群聊的用户编号
     * @author zx
     * @date 2022/3/22 11:17
     */
-    String autoCreate(Long courseGroupId,String courseGroupType) throws Exception;
+    String autoCreate(Long courseGroupId,String courseGroupType, List<Long> noGroupJoinUserIds) throws Exception;
 
     List<GroupMemberWrapper.ImGroupMember> getImGroupMembers(List<ImGroupMember> groupMemberList);
 
@@ -144,6 +145,13 @@ public interface ImGroupService extends IService<ImGroup> {
      */
     ImGroup findGroupInfoById(String groupId, Long userId);
 
+    /**
+     * 获取群信息
+     * @param groupId 群ID
+     * @return ImGroup
+     */
+    ImGroup getGroupById(String groupId);
+
     void getAndSaveImHistoryMessage(String date) throws Exception;
 
     /**

+ 4 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImUserFriendService.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.yonge.cooleshow.biz.dal.dao.ImUserFriendDao;
 import com.yonge.cooleshow.biz.dal.entity.ImUserFriend;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.vo.im.ImUserFriendVO;
 import com.yonge.cooleshow.biz.dal.wrapper.im.CustomerService;
 import com.yonge.cooleshow.biz.dal.wrapper.im.ImUserWrapper;
 import org.springframework.transaction.annotation.Transactional;
@@ -41,7 +42,7 @@ public interface ImUserFriendService extends IService<ImUserFriend> {
     * @author zx
     * @date 2022/3/24 12:03
     */
-    ImUserFriend getDetail(String userId, ClientEnum clientType);
+    ImUserFriendVO.ImUserFriend getDetail(String userId, ClientEnum clientType);
 
     /**
      * 新用户自动添加客服
@@ -52,6 +53,8 @@ public interface ImUserFriendService extends IService<ImUserFriend> {
      */
     Integer registerUserBindCustomerService(Long userId, List<Long> friendIds, ClientEnum clientType);
 
+    void sendCustomerServiceAddFriendMessage(Long customerServiceId, String sendTitle, String sendMessage, List<Long> friendIds, ClientEnum friendType);
+
     /**
      * 发送系统客服消息
      * @param sender 发送者

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

@@ -87,7 +87,7 @@ public interface MemberPriceSettingsService extends IService<MemberPriceSettings
      * @param sysUser
      * @return
      */
-    Boolean addVip(VipSubmitReq vipSubmitReq, ClientEnum client, SysUser sysUser);
+//    Boolean addVip(VipSubmitReq vipSubmitReq, ClientEnum client, SysUser sysUser);
 
     /**
      * 会员信息

+ 4 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/MusicSheetService.java

@@ -10,6 +10,7 @@ import com.yonge.cooleshow.biz.dal.dto.ReasonDto;
 import com.yonge.cooleshow.biz.dal.dto.req.OrderReq;
 import com.yonge.cooleshow.biz.dal.dto.search.*;
 import com.yonge.cooleshow.biz.dal.entity.MusicSheet;
+import com.yonge.cooleshow.biz.dal.entity.MusicSheetAccompaniment;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.OrderTypeEnum;
 import com.yonge.cooleshow.biz.dal.vo.*;
@@ -46,7 +47,7 @@ public interface MusicSheetService extends IService<MusicSheet> {
 
     IPage<MusicSheetVoResult> selectCbsPage(IPage<MusicSheetVo> page, MusicSheetSearch query);
     
-    IPage<MusicSheetVo> queryRelatedList(IPage<MusicSheetVo> page, Long albumId, Long musicSheetId);
+    IPage<MusicSheetVo> queryRelatedList(IPage<MusicSheetVo> page, MusicSheetRelatedQueryInfo queryInfo);
 
     /**
      * 曲目状态修改 启用、停用
@@ -415,4 +416,6 @@ public interface MusicSheetService extends IService<MusicSheet> {
     PageInfo<CbsMusicSheetWrapper.MusicSheetAccApplication> queryCbsMusicSheetSoundApplication(CbsMusicSheetWrapper.MusicSheetApplicationQuery query);
 
     List<CbsMusicSheetWrapper.MusicSheetApplication> queryCbsMusicSheetApplication(CbsMusicSheetWrapper.MusicSheetApplicationQuery query);
+
+    IPage<MusicSheetVo> queryTenantRelatedList(IPage<Object> page, MusicSheetRelatedQueryInfo queryInfo);
 }

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

@@ -133,4 +133,5 @@ public interface StudentService extends IService<Student> {
     void sendStudentTenantChange(Student student, Long toTenantId);
 
     Map<Long,Student> getMapByIds(List<Long> userIds);
+
 }

+ 5 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/TeacherService.java

@@ -2,6 +2,7 @@ package com.yonge.cooleshow.biz.dal.service;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dao.TeacherDao;
 import com.yonge.cooleshow.biz.dal.dto.TeacherDto;
 import com.yonge.cooleshow.biz.dal.dto.req.TeacherSubmitReq;
@@ -186,4 +187,8 @@ public interface TeacherService extends IService<Teacher> {
     UserPaymentOrderWrapper.AccountTenantTo teacherSettlementFrom(Long teacherId,Long recomUserId);
 
     Map<Long, Teacher> getMapByIds(List<Long> teacherIds);
+
+    List<Teacher> getCustomerService();
+
+    void updateLock(SysUser sysUser, Long teacherId);
 }

+ 41 - 5
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/VipCardRecordService.java

@@ -2,22 +2,22 @@ package com.yonge.cooleshow.biz.dal.service;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.yonge.cooleshow.biz.dal.dto.VipSubmitReq;
-import com.yonge.cooleshow.biz.dal.dto.req.OrderReq;
 import com.yonge.cooleshow.biz.dal.dto.search.VipRecordSearch;
 import com.yonge.cooleshow.biz.dal.entity.ActivityReward;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.EVipType;
 import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
 import com.yonge.cooleshow.biz.dal.vo.UserOrderDetailVo;
 import com.yonge.cooleshow.biz.dal.vo.VipRecordVo;
-import com.yonge.cooleshow.biz.dal.vo.res.OrderCreateRes;
-import com.yonge.cooleshow.biz.dal.vo.UserOrderVo;
 import com.yonge.cooleshow.biz.dal.vo.VipCardRecordVo;
 import com.yonge.cooleshow.biz.dal.dto.search.VipCardRecordSearch;
 import com.yonge.cooleshow.biz.dal.entity.VipCardRecord;
-import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.toolset.base.page.PageInfo;
 
+import java.util.List;
+import java.util.Map;
+
 /**
  * 购买会员卡记录表 服务类
  *
@@ -83,4 +83,40 @@ public interface VipCardRecordService extends IService<VipCardRecord> {
      * @return
      */
     PageInfo<VipRecordVo> vipRecord(VipRecordSearch recordSearch);
+
+    /**
+     * 获取生效中的会员记录
+     *
+     * @param userId
+     * @param clientEnum
+     * @return
+     */
+    List<VipCardRecord> getEfficientVipRecord(List<Long> userId, ClientEnum clientEnum);
+
+    VipCardRecordWrapper.UserVip UserVipInfo(Long userId, ClientEnum clientEnum);
+
+    /**
+     * 用户会员信息
+     *
+     * @param userId
+     * @param clientEnum
+     * @return
+     */
+    VipCardRecordWrapper.UserVip userVipInfo(Long userId, ClientEnum clientEnum);
+
+    void add(VipCardRecordWrapper.AddVipCardRecord addVipCardRecord);
+
+    /**
+     * 获取用户会员类型
+     *
+     * @param studentIds
+     * @param client
+     * @return
+     */
+    Map<Long, EVipType> getVipTypeMapByUserIds(List<Long> studentIds, ClientEnum client);
+
+    // 会员添加
+    VipCardRecord addVip(VipCardRecordWrapper.AddVipCardRecord addVipCardRecord);
+
+    List<VipCardRecordWrapper.UserVipInfo> queryUserVipInfo(List<Long> userIdList , String clientType);
 }

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

@@ -48,6 +48,8 @@ public interface ImGroupCoreService {
     String analysisImUserId(String imUserId);
 
 
+    String analysisImUser(String imUserId);
+
     /**
      * 检测imUserid
      *

+ 12 - 10
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/im/impl/ImGroupCoreServiceImpl.java

@@ -7,7 +7,6 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.dayaedu.cbs.common.enums.EClientType;
 import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 import com.microsvc.toolkit.common.tools.ThreadPool;
 import com.microsvc.toolkit.middleware.im.ImPluginContext;
 import com.microsvc.toolkit.middleware.im.ImPluginService;
@@ -19,7 +18,6 @@ import com.yonge.cooleshow.biz.dal.entity.ImGroupMemberAudit;
 import com.yonge.cooleshow.biz.dal.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.enums.AuditStatusEnum;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
-import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
 import com.yonge.cooleshow.biz.dal.enums.RoleEnum;
 import com.yonge.cooleshow.biz.dal.enums.im.EImGroupMemberRoleType;
 import com.yonge.cooleshow.biz.dal.service.ImGroupMemberAuditService;
@@ -27,14 +25,12 @@ import com.yonge.cooleshow.biz.dal.service.ImGroupMemberService;
 import com.yonge.cooleshow.biz.dal.service.ImGroupService;
 import com.yonge.cooleshow.biz.dal.service.SysUserService;
 import com.yonge.cooleshow.biz.dal.service.im.ImGroupCoreService;
-import com.yonge.cooleshow.biz.dal.wrapper.TenantActivationCodeWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.im.ImGroupMemberAuditWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.im.ImGroupMemberWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.im.ImGroupWrapper;
 import com.yonge.toolset.base.exception.BizException;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -120,7 +116,7 @@ public class ImGroupCoreServiceImpl implements ImGroupCoreService {
             clientType = "TEACHER";
         }
         if (StringUtils.isNotBlank(imConfig.getAppPrefix()) && !imUserId.startsWith(imConfig.getAppPrefix())) {
-            imUserId = MessageFormat.format("{0}_{1}_{2}", imConfig.getAppPrefix(), userId, clientType);
+            imUserId = MessageFormat.format("{0}_{1}_{2}", imConfig.getAppPrefix(), userId.toString(), clientType);
         }
         return imUserId;
     }
@@ -133,7 +129,7 @@ public class ImGroupCoreServiceImpl implements ImGroupCoreService {
             clientType = "TEACHER";
         }
         if (StringUtils.isNotBlank(imConfig.getAppPrefix()) && !imUserId.startsWith(imConfig.getAppPrefix())) {
-            imUserId = MessageFormat.format("{0}_{1}_{2}", imConfig.getAppPrefix(), userId, clientType);
+            imUserId = MessageFormat.format("{0}_{1}_{2}", imConfig.getAppPrefix(), userId.toString(), clientType);
         }
         return imUserId;
     }
@@ -152,6 +148,13 @@ public class ImGroupCoreServiceImpl implements ImGroupCoreService {
         }
         return imUserId;
     }
+    @Override
+    public String analysisImUser(String imUserId) {
+        if (StringUtils.isNotBlank(imConfig.getAppPrefix()) && imUserId.startsWith(imConfig.getAppPrefix())) {
+            return imUserId.replace(imConfig.getAppPrefix() + "_", "");
+        }
+        return imUserId;
+    }
 
 
     /**
@@ -738,7 +741,6 @@ public class ImGroupCoreServiceImpl implements ImGroupCoreService {
      */
     @Override
     public void changeGroupOwner(String groupId, String newOwner, String oldOwner) throws Exception {
-
         try {
             if (newOwner.equals(oldOwner)) {
                 throw new BizException("不能转让给自己");
@@ -746,7 +748,7 @@ public class ImGroupCoreServiceImpl implements ImGroupCoreService {
 
             {
                 // 判断旧群主
-                String[] values = analysisImUserId(oldOwner).split(IM_USER_ID_SPLIT);
+                String[] values = analysisImUser(oldOwner).split(IM_USER_ID_SPLIT);
 
                 // 新群主ID和身份
                 long userId = Long.parseLong(values[0]);
@@ -765,7 +767,7 @@ public class ImGroupCoreServiceImpl implements ImGroupCoreService {
 
             {
                 // 判定新群主是否为禁言状态,需要先解除禁言
-                String[] values = analysisImUserId(newOwner).split(IM_USER_ID_SPLIT);
+                String[] values = analysisImUser(newOwner).split(IM_USER_ID_SPLIT);
 
                 // 新群主ID和身份
                 long userId = Long.parseLong(values[0]);
@@ -1016,7 +1018,7 @@ public class ImGroupCoreServiceImpl implements ImGroupCoreService {
      * @param isAdmin 群主标记
      */
     private void updateGroupOwner(String groupId, String groupMember, Boolean isAdmin) {
-        String[] values = analysisImUserId(groupMember).split(IM_USER_ID_SPLIT);
+        String[] values = analysisImUser(groupMember).split(IM_USER_ID_SPLIT);
 
         // 新群主ID和身份
         long userId = Long.parseLong(values[0]);

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

@@ -317,7 +317,7 @@ public class ActivityRewardServiceImpl extends ServiceImpl<ActivityRewardDao, Ac
             pianoRoomChangeRecord.setCreateTime(new Date());
             pianoRoomChangeRecord.setReason(activityPlan.getActivityName());
             pianoRoomChangeRecordService.add(pianoRoomChangeRecord);
-        } else if (activityReward.getRewardType().equals(RewardTypeEnum.VIP)) {
+        } else if (activityReward.getRewardType().equals(RewardTypeEnum.VIP) || activityReward.getRewardType().equals(RewardTypeEnum.SVIP)) {
             // VIP
             memberPriceSettingsService.activityReward(userId, activityPlan.getActivityClient(), activityReward,
                                                       activityPlan.getId(), activityPlan.getActivityName());

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

@@ -5,7 +5,7 @@ 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.beust.jcommander.internal.Lists;
+import com.google.common.collect.Lists;
 import com.microsvc.toolkit.config.jwt.utils.JwtUserInfo;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
@@ -1250,9 +1250,15 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
                 if (courseGroup.getPreStudentNum() >= courseGroup.getMixStudentNum() &&courseGroup.getStatus().equals(CourseGroupEnum.APPLY.getCode())) {
                     //人数达标则修改课程组为进行中状态
                     courseGroup.setStatus(CourseGroupEnum.ING.getCode());
+                    List<Long> noGroupJoinUserIds = Lists.newArrayList();
                     //创建群聊 并添加人员到群中
-                    String imGroupId = imGroupService.autoCreate(courseGroup.getId(), courseGroup.getType());
+                    String imGroupId = imGroupService.autoCreate(courseGroup.getId(), courseGroup.getType(), noGroupJoinUserIds);
 
+                    // 排除未进群的学生
+                    if (CollectionUtils.isNotEmpty(noGroupJoinUserIds)) {
+                        noGroupJoinUserIds.forEach(userIds::remove);
+                    }
+                    // 更新已进群用户身份
                     imGroupMemberService.initGroupMembers(imGroupId, userIds, ImGroupMemberRoleType.STUDENT);
                     //添加老师进群
                     imGroupMemberService.initGroupMembers(imGroupId, Collections.singleton(courseGroup.getTeacherId()), ImGroupMemberRoleType.TEACHER);

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

@@ -10,9 +10,11 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fasterxml.jackson.databind.ObjectMapper;
 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.biz.dal.dao.*;
+import com.yonge.cooleshow.biz.dal.dto.BasicUserInfo;
 import com.yonge.cooleshow.biz.dal.dto.PracticeScheduleDto;
 import com.yonge.cooleshow.biz.dal.dto.UserAccountRecordDto;
 import com.yonge.cooleshow.biz.dal.dto.req.OrderReq;
@@ -54,7 +56,6 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
-import java.text.MessageFormat;
 import java.text.SimpleDateFormat;
 import java.time.Instant;
 import java.time.LocalDate;
@@ -1954,16 +1955,23 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
      * @Author: cy
      * @Date: 2022/5/27
      */
-    public void arrangeCourse(ArrangeCourseVo arrangeCourseVo, Long teacherId) {
-        DistributedLock.of(redissonClient)
-                .runIfLockCanGet(CacheNameEnum.LOCK_EXECUTE_ORDER.getRedisKey("teacherId:" + teacherId)
-                        , () -> this.checkArrangeCourse(arrangeCourseVo, teacherId), 60L, TimeUnit.SECONDS);
+    public String arrangeCourse(ArrangeCourseVo arrangeCourseVo, Long teacherId) {
+
+        // 返回未加入群用户消息
+        return DistributedLock.of(redissonClient)
+            .runIfLockCanGet(CacheNameEnum.LOCK_EXECUTE_ORDER.getRedisKey("teacherId:" + teacherId)
+                , () -> this.checkArrangeCourse(arrangeCourseVo, teacherId), 60L, TimeUnit.SECONDS);
     }
 
+    /**
+     * 校验排课
+     * @param arrangeCourseVo 排课参数
+     * @param teacherId 老师id
+     */
     @Transactional(rollbackFor = Exception.class)
-    public void checkArrangeCourse(ArrangeCourseVo arrangeCourseVo, Long teacherId) {
+    public String checkArrangeCourse(ArrangeCourseVo arrangeCourseVo, Long teacherId) {
         Integer classNum = arrangeCourseVo.getClassNum();//课时数
-        Integer singleClssTime = arrangeCourseVo.getSingleClssTime();//单课时长
+        Integer singleClassTime = arrangeCourseVo.getSingleClssTime();//单课时长
         List<Long> studentIds = arrangeCourseVo.getStudentIds();//学员id集合
 
         String formula = sysConfigService.findConfigValue(SysConfigConstant.PIANO_ROOM_TIME_FORMULA);
@@ -1971,13 +1979,13 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
         if (n == null) {
             throw new BizException("公式转换失败");
         }
-        Integer consumTime = classNum * singleClssTime * n;//消耗时长 课程数*单课时长*人数
+        Integer consumTime = classNum * singleClassTime * n;//消耗时长 课程数*单课时长*人数
 
         List<CourseTimeEntity> timeList = arrangeCourseVo.getTimeList();//选课时间
         Integer consumeTime = arrangeCourseVo.getConsumeTime();
 
         log.info("classNum:" + classNum);
-        log.info("singleClssTime:" + singleClssTime);
+        log.info("singleClssTime:" + singleClassTime);
         log.info("n:" + n);
         log.info("消耗时长:" + consumTime);
         log.info("传入时长:" + consumeTime);
@@ -2002,7 +2010,7 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
             if (timeList.get(i).getStartTime().before(new Date())) {
                 throw new BizException("上课时间必须大于当前时间");
             }
-            if (!DateUtil.offsetMinute(timeList.get(i).getStartTime(), singleClssTime).equals(timeList.get(i).getEndTime())) {
+            if (!DateUtil.offsetMinute(timeList.get(i).getStartTime(), singleClassTime).equals(timeList.get(i).getEndTime())) {
                 throw new BizException("第{}节课结束时间计算错误", i + 1);
             }
         }
@@ -2059,7 +2067,7 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
         courseGroup.setTeacherId(teacherId);
         courseGroup.setName(arrangeCourseVo.getCourseName());
         courseGroup.setSubjectId(arrangeCourseVo.getSubjectId());
-        courseGroup.setSingleCourseMinutes(singleClssTime);
+        courseGroup.setSingleCourseMinutes(singleClassTime);
         courseGroup.setCourseNum(classNum);
         courseGroup.setStatus(CourseGroupEnum.ING.getCode());
         courseGroup.setCreatedBy(teacherId);
@@ -2079,7 +2087,7 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
             schedule.setLock(0);
             schedule.setStatus(CourseScheduleEnum.NOT_START.getCode());
             schedule.setCreatedBy(teacherId);
-            schedule.setSingleCourseTime(singleClssTime);
+            schedule.setSingleCourseTime(singleClassTime);
             baseMapper.insert(schedule);
 
             //添加payment
@@ -2113,14 +2121,14 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
                             roomTimeLock.setFrozenTime(frozenTimeLock + consumTime);
                             pianoRoomTimeDao.update(roomTimeLock, Wrappers.<PianoRoomTime>lambdaQuery().eq(PianoRoomTime::getTeacherId, teacherId));
                             return null;
-                        }, null, 10l);
+                        }, null, 10L);
 
+        List<Long> noGroupJoinUserIds = Lists.newArrayList();
         //创建群聊
         try {
-            imGroupService.autoCreate(courseGroup.getId(), CourseScheduleEnum.PIANO_ROOM_CLASS.getCode());
+            imGroupService.autoCreate(courseGroup.getId(), CourseScheduleEnum.PIANO_ROOM_CLASS.getCode(), noGroupJoinUserIds);
         } catch (Exception e) {
-            log.error("琴房课程组id:{},创建群聊失败:{}", courseGroup.getId(), e);
-            e.printStackTrace();
+            log.error("琴房课程组id:{},创建群聊失败", courseGroup.getId(), e);
         }
 
         for (Long studentId : studentIds) {
@@ -2131,6 +2139,13 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
         }
         //清除老师缓存
         redissonClient.getBucket(CacheNameEnum.TEACHER_TOTAL.getRedisKey(teacherId)).delete();
+
+        String message = "";
+        if (CollectionUtils.isNotEmpty(noGroupJoinUserIds)) {
+            // 返回未加入群用户消息
+            message = "群成员人数达到上限,有" + noGroupJoinUserIds.size() + "位学生未进入课程群";
+        }
+        return message;
     }
 
     /**
@@ -2450,7 +2465,7 @@ public class CourseScheduleServiceImpl extends ServiceImpl<CourseScheduleDao, Co
                                     .set(PianoRoomTime::getRemainTime, remainTime - diffTime)
                                     .set(PianoRoomTime::getFrozenTime, frozenTime + diffTime));
                             return null;
-                        }, null, 10l);
+                        }, null, 10L);
 
         //删除原学员
         paymentDao.delete(Wrappers.<CourseScheduleStudentPayment>lambdaQuery().eq(CourseScheduleStudentPayment::getCourseId, courseId));

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

@@ -1,6 +1,7 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
 import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -211,7 +212,14 @@ public class CustomerServiceBatchSendingServiceImpl extends ServiceImpl<Customer
         // 发送客服ID
         String customerService = info.getMobile();
         if (StringUtils.isBlank(customerService)) {
-            customerService = customerServiceConfig.getCustomerService();
+            List<Long> teacherIds = teacherService.getCustomerService().stream().map(Teacher::getUserId).collect(Collectors.toList());
+            if (!teacherIds.isEmpty()) {
+                customerService = sysUserMapper.selectList(new QueryWrapper<SysUser>().lambda()
+                                .in(SysUser::getId, teacherIds))
+                        .stream()
+                        .map(SysUser::getPhone)
+                        .collect(Collectors.joining(","));
+            }
         }
         if (StringUtils.isNotEmpty(customerService)) {
 

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

@@ -141,6 +141,7 @@ public class HomeServiceImpl implements HomeService {
         List<HomeTotalStudent> totalList = baserMapper.totalStudent(query.getTimeType().getCode(), query);
         Integer registerNum = 0;
         Integer vipNum = 0;
+        Integer svipNum = 0;
         Integer practiceNum = 0;
         Integer videoNum = 0;
         Integer liveNum = 0;
@@ -151,6 +152,7 @@ public class HomeServiceImpl implements HomeService {
         for (HomeTotalStudent totalStudent : totalList) {
             totalStudent.setRegisterNum(null == totalStudent.getRegisterNum() ? 0 : totalStudent.getRegisterNum());
             totalStudent.setVipNum(null == totalStudent.getVipNum() ? 0 : totalStudent.getVipNum());
+            totalStudent.setSvipNum(null == totalStudent.getSvipNum() ? 0 : totalStudent.getSvipNum());
             totalStudent.setPracticeNum(null == totalStudent.getPracticeNum() ? 0 : totalStudent.getPracticeNum());
             totalStudent.setVideoNum(null == totalStudent.getVideoNum() ? 0 : totalStudent.getVideoNum());
             totalStudent.setLiveNum(null == totalStudent.getLiveNum() ? 0 : totalStudent.getLiveNum());
@@ -160,6 +162,7 @@ public class HomeServiceImpl implements HomeService {
 
             registerNum += totalStudent.getRegisterNum();
             vipNum += totalStudent.getVipNum();
+            svipNum += totalStudent.getSvipNum();
             practiceNum += totalStudent.getPracticeNum();
             videoNum += totalStudent.getVideoNum();
             liveNum += totalStudent.getLiveNum();
@@ -170,6 +173,7 @@ public class HomeServiceImpl implements HomeService {
         HomeTotalStudent total = new HomeTotalStudent();
         total.setRegisterNum(registerNum);
         total.setVipNum(vipNum);
+        total.setSvipNum(svipNum);
         total.setPracticeNum(practiceNum);
         total.setVideoNum(videoNum);
         total.setLiveNum(liveNum);

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

@@ -6,6 +6,7 @@ import com.yonge.cooleshow.biz.dal.dao.ImGroupMemberAuditDao;
 import com.yonge.cooleshow.biz.dal.entity.ImGroup;
 import com.yonge.cooleshow.biz.dal.entity.ImGroupMember;
 import com.yonge.cooleshow.biz.dal.entity.ImGroupMemberAudit;
+import com.yonge.cooleshow.biz.dal.entity.SysConfig;
 import com.yonge.cooleshow.biz.dal.enums.AuditStatusEnum;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
@@ -14,19 +15,28 @@ import com.yonge.cooleshow.biz.dal.queryInfo.ImGroupMemberAuditQueryInfo;
 import com.yonge.cooleshow.biz.dal.service.ImGroupMemberAuditService;
 import com.yonge.cooleshow.biz.dal.service.ImGroupMemberService;
 import com.yonge.cooleshow.biz.dal.service.ImGroupService;
+import com.yonge.cooleshow.biz.dal.service.SysConfigService;
 import com.yonge.cooleshow.biz.dal.service.SysUserService;
 import com.yonge.cooleshow.biz.dal.vo.AuditUserInfo;
+import com.yonge.cooleshow.common.constant.SysConfigConstant;
 import com.yonge.toolset.base.exception.BizException;
+import com.yonge.toolset.payment.util.DistributedLock;
 import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
-import io.rong.models.group.GroupMember;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
-import java.util.*;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -35,11 +45,10 @@ import java.util.stream.Collectors;
  * @author zx
  * @since 2022-03-22 17:18:51
  */
+@Slf4j
 @Service("imGroupMemberAuditService")
 public class ImGroupMemberAuditServiceImpl extends ServiceImpl<ImGroupMemberAuditDao, ImGroupMemberAudit> implements ImGroupMemberAuditService {
 
-    private final static Logger log = LoggerFactory.getLogger(ImGroupMemberAuditServiceImpl.class);
-
     @Resource
     private ImGroupService imGroupService;
     @Resource
@@ -49,6 +58,12 @@ public class ImGroupMemberAuditServiceImpl extends ServiceImpl<ImGroupMemberAudi
     @Resource
     private SysMessageServiceImpl sysMessageService;
 
+    @Autowired
+    private RedissonClient redissonClient;
+
+    @Autowired
+    private SysConfigService sysConfigService;
+
     @Override
     public ImGroupMemberAuditDao getDao() {
         return this.baseMapper;
@@ -79,36 +94,55 @@ public class ImGroupMemberAuditServiceImpl extends ServiceImpl<ImGroupMemberAudi
         if(Objects.nonNull(baseMapper.findOne(auditParams))){
             throw new BizException("您有待审核的申请,请勿重复提交");
         }
-        Date date = new Date();
-        //是否自动通过审核
-        imGroupMemberAudit.setAuditStatus(imGroup.getAutoPassFlag() && autoJoin?AuditStatusEnum.OPEN:AuditStatusEnum.AUDITING);
-        imGroupMemberAudit.setUpdateTime(date);
-        imGroupMemberAudit.setCreateTime(date);
-        baseMapper.insert(imGroupMemberAudit);
-        if(imGroup.getAutoPassFlag() && Optional.ofNullable(autoJoin).orElse(false)){
-            //处理本地群成员
-            List<ImGroupMember> groupMembers = imGroupMemberService.initGroupMember(imGroup.getId(),
-                    imGroupMemberAudit.getUserId(), false,
-                    imGroupMemberAudit.getRoleType());
-            //同步群成员数量
-            imGroupService.getDao().updateMemberNum(imGroup.getId());
-            //加入融云群
-            imGroupMemberService.join(groupMembers,groupId);
-        } else {
-            Map<Long,String> receivers = new HashMap<>(1);
-            // 群创建人
-            SysUser user = sysUserService.findUserById(imGroup.getCreateBy());
-            // 申请人
-            SysUser auditUser = sysUserService.findUserById(imGroupMemberAudit.getUserId());
-
-            receivers.put(user.getId(), user.getPhone());
+
+        // 增加群成员校验锁,当群成员人数达到限制时,不允许再次加入
+        String lockName = "klx:group_member_apply_lock:" + groupId;
+        DistributedLock.of(redissonClient).runIfLockToFunction(lockName, (x)-> {
+
+            // 统计群成员数量,大于等于群组最大人数时,不允许加入
+            if (!verifyGroupMemberJoinLimit(groupId, 1)) {
+                SysConfig config = sysConfigService.findByParamName(SysConfigConstant.GROUP_MEMBER_LIMIT);
+                throw new BizException("群成员人数上限为:" + config.getParamValue() + "人");
+            }
+
             try {
-                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.STUDENT_JOIN_FANSGROUP,
-                           receivers, null, 0, null, ClientEnum.TEACHER.getCode(), auditUser.getUsername(),imGroup.getName());
+                Date date = new Date();
+                //是否自动通过审核
+                imGroupMemberAudit.setAuditStatus(imGroup.getAutoPassFlag() && autoJoin?AuditStatusEnum.OPEN:AuditStatusEnum.AUDITING);
+                imGroupMemberAudit.setUpdateTime(date);
+                imGroupMemberAudit.setCreateTime(date);
+                baseMapper.insert(imGroupMemberAudit);
+                if(imGroup.getAutoPassFlag() && Optional.ofNullable(autoJoin).orElse(false)){
+                    //处理本地群成员
+                    List<ImGroupMember> groupMembers = imGroupMemberService.initGroupMember(imGroup.getId(),
+                        imGroupMemberAudit.getUserId(), false,
+                        imGroupMemberAudit.getRoleType());
+                    //同步群成员数量
+                    imGroupService.getDao().updateMemberNum(imGroup.getId());
+                    //加入融云群
+                    imGroupMemberService.join(groupMembers,groupId);
+                } else {
+                    Map<Long,String> receivers = new HashMap<>(1);
+                    // 群创建人
+                    SysUser user = sysUserService.findUserById(imGroup.getCreateBy());
+                    // 申请人
+                    SysUser auditUser = sysUserService.findUserById(imGroupMemberAudit.getUserId());
+
+                    receivers.put(user.getId(), user.getPhone());
+                    try {
+                        sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.STUDENT_JOIN_FANSGROUP,
+                            receivers, null, 0, null, ClientEnum.TEACHER.getCode(), auditUser.getUsername(),imGroup.getName());
+                    } catch (Exception e) {
+                        log.warn("学生入群消息发送失败,{}",e.getMessage());
+                    }
+                }
             } catch (Exception e) {
-                log.warn("学生入群消息发送失败,{}",e.getMessage());
+                log.error("加入群组申请失败,{}", e.getMessage(), e);
+                throw new BizException("加入群组申请失败");
             }
-        }
+            return true;
+        }, null, 10L);
+
     }
 
     @Override
@@ -117,18 +151,53 @@ public class ImGroupMemberAuditServiceImpl extends ServiceImpl<ImGroupMemberAudi
         Optional.of(auditStatus).filter(e->e != AuditStatusEnum.AUDITING).orElseThrow(()->new BizException("操作失败:审核状态异常"));
         ImGroup imGroup = Optional.ofNullable(imGroupService.getById(groupId)).orElseThrow(() ->new BizException("群组信息不存在"));
         Optional.of(sysUserService.getUserId()).filter(imGroup.getCreateBy()::equals).orElseThrow(()->new BizException("操作失败:您没有审核权限"));
-        //修改审核状态
-        baseMapper.batchUpdateAuditStatus(auditIds,auditStatus.getCode());
-        if(auditStatus == AuditStatusEnum.OPEN){
-            List<ImGroupMemberAudit> imGroupMemberAudit = baseMapper.findByIds(auditIds);
-            Set<Long> userIds = imGroupMemberAudit.stream().map(ImGroupMemberAudit::getUserId).collect(Collectors.toSet());
-            List<ImGroupMember> groupMembers = imGroupMemberService.initGroupMembers(groupId,userIds, ImGroupMemberRoleType.STUDENT);
-            //同步群成员数量
-            imGroupService.getDao().updateMemberNum(imGroup.getId());
-            //加入融云群
-            imGroupMemberService.join(groupMembers,imGroup.getId());
-            sendMessage(auditIds);
+
+        // 增加群成员校验锁,当群成员人数达到限制时,不允许再次加入
+        String lockName = "klx:group_member_audit_lock:" + groupId;
+        DistributedLock.of(redissonClient).runIfLockToFunction(lockName, (x)-> {
+
+            // 校验群成员加入限制
+            String[] split = auditIds.split(",");
+            if (AuditStatusEnum.OPEN.equals(auditStatus) && !verifyGroupMemberJoinLimit(groupId, split.length)) {
+                SysConfig config = sysConfigService.findByParamName(SysConfigConstant.GROUP_MEMBER_LIMIT);
+                throw new BizException("群成员人数上限为:" + config.getParamValue() + "人");
+            }
+            try {
+                //修改审核状态
+                baseMapper.batchUpdateAuditStatus(auditIds,auditStatus.getCode());
+                if(auditStatus == AuditStatusEnum.OPEN){
+                    List<ImGroupMemberAudit> imGroupMemberAudit = baseMapper.findByIds(auditIds);
+                    Set<Long> userIds = imGroupMemberAudit.stream().map(ImGroupMemberAudit::getUserId).collect(Collectors.toSet());
+                    List<ImGroupMember> groupMembers = imGroupMemberService.initGroupMembers(groupId,userIds, ImGroupMemberRoleType.STUDENT);
+                    //同步群成员数量
+                    imGroupService.getDao().updateMemberNum(imGroup.getId());
+                    //加入融云群
+                    imGroupMemberService.join(groupMembers,imGroup.getId());
+                    sendMessage(auditIds);
+                }
+            } catch (Exception e) {
+                log.error("加入群组审核失败,{}", e.getMessage(), e);
+                throw new BizException("加入群组审核失败");
+            }
+            return true;
+        }, null, 10L);
+
+    }
+
+    /**
+     * 校验群成员加入限制
+     * @param groupId 群组ID
+     */
+    private Boolean verifyGroupMemberJoinLimit(String groupId, int addNum) {
+        // 统计群成员数量,大于等于群组最大人数时,不允许加入
+        int memberCount = imGroupMemberService.countGroupMember(groupId);
+        // 查询群成员人数限制
+        SysConfig config = sysConfigService.findByParamName(SysConfigConstant.GROUP_MEMBER_LIMIT);
+        if (Objects.nonNull(config) && Integer.parseInt(config.getParamValue()) > 0
+            && (memberCount + addNum) > Integer.parseInt(config.getParamValue())) {
+            return false;
         }
+        return true;
     }
 
     /**

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

@@ -266,5 +266,19 @@ public class ImGroupMemberServiceImpl extends ServiceImpl<ImGroupMemberDao, ImGr
     public IPage<ImGroupMemberWrapper.ImGroupMember> selectPage(IPage<ImGroupMemberWrapper.ImGroupMember> page, ImGroupMemberWrapper.ImGroupMemberQuery query) {
         return page.setRecords(imGroupMemberDao.selectPage(page, query));
     }
+
+    /**
+     * 获取群成员数量
+     *
+     * @param groupId 群ID
+     * @return int
+     */
+    @Override
+    public int countGroupMember(String groupId) {
+        if (org.apache.commons.lang3.StringUtils.isEmpty(groupId)) {
+            return 0;
+        }
+        return lambdaQuery().eq(ImGroupMember::getGroupId, groupId).count();
+    }
 }
 

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

@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 import com.microsvc.toolkit.middleware.common.http.ImageUtil;
 import com.microsvc.toolkit.middleware.im.ImPluginContext;
 import com.microsvc.toolkit.middleware.im.message.GroupMemberWrapper;
@@ -33,6 +34,7 @@ import com.yonge.cooleshow.biz.dal.dto.search.StudentSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.TeacherSearch;
 import com.yonge.cooleshow.biz.dal.entity.*;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.CourseScheduleEnum;
 import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
 import com.yonge.cooleshow.biz.dal.enums.ImGroupType;
 import com.yonge.cooleshow.biz.dal.enums.RoleEnum;
@@ -64,6 +66,7 @@ import com.yonge.cooleshow.common.constant.SysConfigConstant;
 import com.yonge.cooleshow.common.entity.UploadReturnBean;
 import com.yonge.toolset.base.exception.BizException;
 import com.yonge.toolset.base.util.ThreadPool;
+import com.yonge.toolset.payment.util.DistributedLock;
 import com.yonge.toolset.utils.date.DateUtil;
 import io.rong.RongCloud;
 import io.rong.methods.message.history.History;
@@ -304,6 +307,12 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
     @Override
     @Transactional(rollbackFor = Exception.class)
     public String create(ImGroupWrapper.ImGroup imGroup) throws Exception {
+        // 群成员数量限制校验
+        SysConfig config = sysConfigService.findByParamName(SysConfigConstant.GROUP_MEMBER_LIMIT);
+        if (config != null && Integer.parseInt(config.getParamValue()) < (imGroup.getStudentIdList().size() + 1)) {
+            throw new BizException("群成员人数上限为:" + config.getParamValue() + "人");
+        }
+
         Date now = new Date();
         if (imGroup.getType() == null) {
             imGroup.setType(ImGroupType.FAN.getCode());
@@ -359,31 +368,52 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
             throw new BizException("添加的群成员不能为空");
 
         }
-        List<ImGroupMember> groupMemberList = imGroupMemberService.initGroupMembers(groupId,
-                studentIdList, ImGroupMemberRoleType.STUDENT);
-        imGroupMemberService.join(groupMemberList, groupId);
-
-        // 如果是机构群,学生自动添加老师好友
-        if (ImGroupType.ORG.equals(imGroup.getType())) {
-            List<ImGroupMember> teacherList = imGroupMemberService.lambdaQuery()
-                    .eq(ImGroupMember::getGroupId, groupId)
-                    .eq(ImGroupMember::getRoleType, ImGroupMemberRoleType.TEACHER)
-                    .list();
-            teacherList.forEach(teacher -> imUserFriendService.saveUserFriend(teacher.getUserId(), studentIdList));
-        }
+        // 增加群成员校验锁,当群成员人数达到限制时,不允许再次加入
+        String lockName = "klx:group_member_add_lock:" + groupId;
+        DistributedLock.of(redissonClient).runIfLockToFunction(lockName, (x)-> {
+            // 群成员数量限制校验
+            int memberCount = imGroupMemberService.countGroupMember(groupId);
+            // 查询群成员人数限制
+            SysConfig config = sysConfigService.findByParamName(SysConfigConstant.GROUP_MEMBER_LIMIT);
+            if (Objects.nonNull(config) && Integer.parseInt(config.getParamValue()) > 0
+                && (memberCount + studentIdList.size()) > Integer.parseInt(config.getParamValue())) {
+                throw new BizException("群成员人数上限为:" + config.getParamValue() + "人");
+            }
+
+            try {
+                List<ImGroupMember> groupMemberList = imGroupMemberService.initGroupMembers(groupId,
+                    studentIdList, ImGroupMemberRoleType.STUDENT);
+                imGroupMemberService.join(groupMemberList, groupId);
+
+                // 如果是机构群,学生自动添加老师好友
+                if (ImGroupType.ORG.equals(imGroup.getType())) {
+                    List<ImGroupMember> teacherList = imGroupMemberService.lambdaQuery()
+                        .eq(ImGroupMember::getGroupId, groupId)
+                        .eq(ImGroupMember::getRoleType, ImGroupMemberRoleType.TEACHER)
+                        .list();
+                    teacherList.forEach(teacher -> imUserFriendService.saveUserFriend(teacher.getUserId(), studentIdList));
+                }
+            } catch (Exception e) {
+                log.error("加入群组失败,{}", e.getMessage(), e);
+                throw new BizException(e.getMessage());
+            }
+            return true;
+        }, null, 10L);
+
     }
 
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public String autoCreate(Long courseGroupId, String courseGroupType) throws Exception {
+    public String autoCreate(Long courseGroupId, String courseGroupType, List<Long> noGroupJoinUserIds) throws Exception {
         //获取课程组
         CourseGroup courseGroup = courseGroupService.getById(courseGroupId);
         if (courseGroup.getTeacherId() == null) {
             return null;
         }
-        //获取学员列表
-        Set<Long> studentIds = courseScheduleStudentPaymentDao.queryStudentIds(courseGroupId, courseGroupType);
+        //获取学员列表,按购买时间顺序升序排列返回
+        List<Long> studentIds = courseScheduleStudentPaymentDao.queryStudentIds(courseGroupId, courseGroupType);
+        // studentIds集合中所有null元素移除
         studentIds.removeAll(Collections.singleton(null));
         if (CollectionUtils.isEmpty(studentIds)) {
             return null;
@@ -391,7 +421,7 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
         Date now = new Date();
         Long teacherId = courseGroup.getTeacherId();
         //保存老师学员关联的通讯录xz
-        imUserFriendService.saveUserFriend(teacherId, studentIds);
+        imUserFriendService.saveUserFriend(teacherId, Sets.newHashSet(studentIds));
 
         //创建群聊
         ImGroup imGroup = new ImGroup();
@@ -408,25 +438,48 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
         imGroup.setCourseGroupId(courseGroupId);
 //        this.baseMapper.insert(imGroup);
 
-
         String groupId = createImGroup(imGroup);
-//        // 添加学生
-        List<ImGroupMember> groupMembers = imGroupMemberService.initGroupMembers(groupId, studentIds,
-                ImGroupMemberRoleType.STUDENT);
-        List<com.yonge.cooleshow.biz.dal.wrapper.im.ImGroupMemberWrapper.ImGroupMember> groupMemberList = Lists.newArrayList();
-        for (ImGroupMember groupMember : groupMembers) {
-            groupMemberList.add(com.yonge.cooleshow.biz.dal.wrapper.im.ImGroupMemberWrapper.ImGroupMember.builder()
-                    .groupId(groupMember.getGroupId())
-                    .userId(groupMember.getUserId())
-                    .clientType(groupMember.getRoleType().getCode())
-                    .avatar(groupMember.getAvatar())
-                    .nickname(groupMember.getNickname())
-                    .isAdmin(groupMember.getIsAdmin())
-                    .imUserId(getImUserId(groupMember.getUserId().toString(), groupMember.getRoleType().getCode()))
-                    .roleType(groupMember.getRoleType().getCode())
-                    .build());
+
+        // 直播课、琴房课校验群成员人数限制
+        if (CourseScheduleEnum.PIANO_ROOM_CLASS.getCode().equals(courseGroupType)
+            || CourseScheduleEnum.LIVE.getCode().equals(courseGroupType)) {
+
+            // 增加群成员人数限制,若超过限制则不添加到群组
+            SysConfig config = sysConfigService.findByParamName(SysConfigConstant.GROUP_MEMBER_LIMIT);
+            if (Objects.nonNull(config) && Integer.parseInt(config.getParamValue()) > 0) {
+                int groupMemberLimit = Integer.parseInt(config.getParamValue());
+                if ((CollectionUtils.size(studentIds) + 1) > groupMemberLimit) {
+
+                    // 已加入群组用户标记
+                    List<Long> userIds = Lists.newArrayList(studentIds);
+                    studentIds = userIds.subList(0, groupMemberLimit - 1);
+                    // 未加入群组用户标记
+                    noGroupJoinUserIds.addAll(userIds.subList(groupMemberLimit - 1, userIds.size()));
+                    // 重置用户入群加入标记
+                    courseScheduleStudentPaymentDao.updateGroupJoinStatus(courseGroupId, courseGroupType, false,
+                        noGroupJoinUserIds);
+                }
+            }
+        }
+
+        if (!studentIds.isEmpty()) {
+            // 添加学生
+            List<ImGroupMember> groupMembers = imGroupMemberService.initGroupMembers(groupId, Sets.newHashSet(studentIds), ImGroupMemberRoleType.STUDENT);
+            List<com.yonge.cooleshow.biz.dal.wrapper.im.ImGroupMemberWrapper.ImGroupMember> groupMemberList = Lists.newArrayList();
+            for (ImGroupMember groupMember : groupMembers) {
+                groupMemberList.add(com.yonge.cooleshow.biz.dal.wrapper.im.ImGroupMemberWrapper.ImGroupMember.builder()
+                        .groupId(groupMember.getGroupId())
+                        .userId(groupMember.getUserId())
+                        .clientType(groupMember.getRoleType().getCode())
+                        .avatar(groupMember.getAvatar())
+                        .nickname(groupMember.getNickname())
+                        .isAdmin(groupMember.getIsAdmin())
+                        .imUserId(getImUserId(groupMember.getUserId().toString(), groupMember.getRoleType().getCode()))
+                        .roleType(groupMember.getRoleType().getCode())
+                        .build());
+            }
+            imGroupCoreService.saveImGroupMemberList(groupId, groupMemberList);
         }
-        imGroupCoreService.saveImGroupMemberList(groupId, groupMemberList);
         //处理本地群成员列表
         // 添加老师
 //        List<ImGroupMember> groupMembers = imGroupMemberService.initGroupMember(imGroupId, imGroup.getCreateBy(),
@@ -436,7 +489,7 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
 //        this.rtcCreate(courseGroup.getTeacherId(), imGroupId, imGroup.getName(),imGroup.getImg());
 //        //加入融云群
 //        imGroupMemberService.join(groupMembers, imGroupId);
-        return groupId.toString();
+        return groupId;
     }
 
 
@@ -612,6 +665,13 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
     public ImGroup findGroupInfoById(String groupId, Long userId) {
 
         ImGroup group = imGroupService.getById(groupId);
+        if (Objects.nonNull(group)) {
+            // 查询群成员人数限制
+            SysConfig byParamName = sysConfigService.findByParamName(SysConfigConstant.GROUP_MEMBER_LIMIT);
+            if (Objects.nonNull(byParamName)) {
+                group.setGroupMemberLimit(Integer.parseInt(byParamName.getParamValue()));
+            }
+        }
 
         // 异步执行自动加入群组功能
         ThreadPool.getExecutor().submit(() -> {
@@ -664,6 +724,24 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
         return group;
     }
 
+    /**
+     * 获取群信息
+     *
+     * @param groupId 群ID
+     * @return ImGroup
+     */
+    @Override
+    public ImGroup getGroupById(String groupId) {
+        ImGroup group = imGroupService.getById(groupId);
+        if (Objects.nonNull(group)) {
+            // 查询群成员人数限制
+            SysConfig byParamName = sysConfigService.findByParamName(SysConfigConstant.GROUP_MEMBER_LIMIT);
+            if (Objects.nonNull(byParamName)) {
+                group.setGroupMemberLimit(Integer.parseInt(byParamName.getParamValue()));
+            }
+        }
+        return group;
+    }
 
 
     /**

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

@@ -15,24 +15,32 @@ 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.dao.ImUserFriendDao;
+import com.yonge.cooleshow.biz.dal.dao.StudentDao;
 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.entity.Subject;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.MK;
 import com.yonge.cooleshow.biz.dal.mapper.SysUserMapper;
 import com.yonge.cooleshow.biz.dal.service.ImGroupService;
 import com.yonge.cooleshow.biz.dal.service.ImUserFriendService;
+import com.yonge.cooleshow.biz.dal.service.SubjectService;
+import com.yonge.cooleshow.biz.dal.service.SysConfigService;
+import com.yonge.cooleshow.biz.dal.service.VipCardRecordService;
+import com.yonge.cooleshow.biz.dal.vo.StudentVo;
+import com.yonge.cooleshow.biz.dal.vo.TeacherVo;
+import com.yonge.cooleshow.biz.dal.vo.im.ImUserFriendVO;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.im.CustomerService;
 import com.yonge.cooleshow.biz.dal.wrapper.im.ImUserWrapper;
+import com.yonge.cooleshow.common.constant.SysConfigConstant;
 import com.yonge.toolset.base.exception.BizException;
 import com.yonge.toolset.base.util.ImUtil;
 import io.rong.messages.BaseMessage;
 import io.rong.messages.ImgMessage;
 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 org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -41,13 +49,12 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
-import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -78,6 +85,14 @@ public class ImUserFriendServiceImpl extends ServiceImpl<ImUserFriendDao, ImUser
 
     @Autowired
     private ImPluginContext imPluginContext;
+    @Autowired
+    private StudentDao studentDao;
+    @Autowired
+    private SubjectService subjectService;
+    @Autowired
+    private VipCardRecordService vipCardRecordService;
+    @Autowired
+    private SysConfigService sysConfigService;
     @Override
     public ImUserFriendDao getDao() {
         return this.baseMapper;
@@ -183,49 +198,71 @@ public class ImUserFriendServiceImpl extends ServiceImpl<ImUserFriendDao, ImUser
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public ImUserFriend getDetail(String imUserId, ClientEnum clientType) {
+    public ImUserFriendVO.ImUserFriend getDetail(String imUserId, ClientEnum clientType) {
 
         // 用户ID
         long userId = Long.parseLong(imGroupService.analysisImUserId(imUserId));
 
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         BasicUserInfo basicUserInfo = teacherDao.getBasicUserInfo(userId);
-        if (sysUser != null && sysUser.getId() != null) {
-
-            ImUserFriend imUserFriend = lambdaQuery()
-                    .eq(ImUserFriend::getUserId, sysUser.getId())
-                    .eq(ImUserFriend::getClientType, clientType)
-                    .eq(ImUserFriend::getFriendId, userId)
-                    .one();
-            if (Objects.nonNull(imUserFriend)) {
-                //更新当前用户关联的该用户的详情信息
-                imUserFriend.setFriendAvatar(basicUserInfo.getAvatar());
-                imUserFriend.setFriendNickname(basicUserInfo.getUsername());
-                imUserFriend.setUpdateTime(new Date());
-                baseMapper.updateById(imUserFriend);
-
-                // 设置融云IM好友ID
-                imUserFriend.setImFriendId(imUserId);
-
-                return imUserFriend;
+        if (basicUserInfo == null) {
+            throw new BizException("无效的用户");
+        }
+
+        String friendClientType = imGroupService.analysisImUserClient(imUserId);
+        ImUserFriend imUserFriend = lambdaQuery()
+                .eq(ImUserFriend::getUserId, sysUser.getId())
+                .eq(ImUserFriend::getClientType, clientType)
+                .eq(ImUserFriend::getFriendId, userId)
+                .eq(ImUserFriend::getFriendType, ClientEnum.valueOf(friendClientType))
+                .one();
+        if (Objects.nonNull(imUserFriend)) {
+            //更新当前用户关联的该用户的详情信息
+            imUserFriend.setFriendAvatar(basicUserInfo.getAvatar());
+            imUserFriend.setFriendNickname(basicUserInfo.getUsername());
+            imUserFriend.setUpdateTime(new Date());
+            baseMapper.updateById(imUserFriend);
+
+            // 设置融云IM好友ID
+            imUserFriend.setImFriendId(imUserId);
+        } else {
+            // 好友身份类型
+            ClientEnum friendType = ClientEnum.TEACHER;
+            if (ClientEnum.STUDENT.match(imGroupService.analysisImUserClient(imUserId))) {
+                friendType = ClientEnum.STUDENT;
             }
+            // 返回当前登录用户信息
+            imUserFriend = new ImUserFriend();
+            imUserFriend.setFriendAvatar(basicUserInfo.getAvatar());
+            imUserFriend.setFriendNickname(basicUserInfo.getUsername());
+            imUserFriend.setFriendId(userId);
+            imUserFriend.setFriendType(friendType);
+            // 设置融云IM好友ID
+            imUserFriend.setImFriendId(imUserId);
         }
 
-        // 好友身份类型
-        ClientEnum friendType = ClientEnum.TEACHER;
-        if (ClientEnum.STUDENT.match(imGroupService.analysisImUserClient(imUserId))) {
-            friendType = ClientEnum.STUDENT;
+        ImUserFriendVO.ImUserFriend result = JSON.parseObject(JSON.toJSONString(imUserFriend), ImUserFriendVO.ImUserFriend.class);
+        result.setFriendGender(basicUserInfo.getGender());
+
+        if (ClientEnum.STUDENT.getCode().equals(friendClientType)) {
+            StudentVo detail = studentDao.detail(userId);
+            if (detail != null && StringUtils.isNotEmpty(detail.getSubjectId())) {
+                List<Subject> subject = subjectService.findBySubjectByIdList(detail.getSubjectId());
+                String subjectName = subject.stream().map(Subject::getName).collect(Collectors.joining("、"));
+                result.setFriendSubjectName(subjectName);
+            }
+        } else if (ClientEnum.TEACHER.getCode().equals(friendClientType)) {
+            TeacherVo detail = teacherDao.detail(userId);
+            if (detail != null && StringUtils.isNotEmpty(detail.getSubjectId())) {
+                List<Subject> subject = subjectService.findBySubjectByIdList(detail.getSubjectId());
+                String subjectName = subject.stream().map(Subject::getName).collect(Collectors.joining("、"));
+                result.setFriendSubjectName(subjectName);
+            }
         }
-        // 返回当前登录用户信息
-        ImUserFriend imUserFriend = new ImUserFriend();
-        imUserFriend.setFriendAvatar(basicUserInfo.getAvatar());
-        imUserFriend.setFriendNickname(basicUserInfo.getUsername());
-        imUserFriend.setFriendId(userId);
-        imUserFriend.setFriendType(friendType);
-        // 设置融云IM好友ID
-        imUserFriend.setImFriendId(imUserId);
-
-        return imUserFriend;
+        VipCardRecordWrapper.UserVip userVip = vipCardRecordService.UserVipInfo(userId, ClientEnum.valueOf(friendClientType));
+        result.setUserVip(userVip);
+        result.setFriendBirthdate(basicUserInfo.getBirthdate());
+        return result;
     }
 
     /**
@@ -280,12 +317,12 @@ public class ImUserFriendServiceImpl extends ServiceImpl<ImUserFriendDao, ImUser
         try {
 
             // 设置默认值
-            String customerMessage = customerServiceConfig.getCustomerMessage();
+            String customerMessage = sysConfigService.findConfigValue(SysConfigConstant.CUSTOMER_SERVICE_ADD_MSG);
             if (StringUtils.isEmpty(customerMessage)) {
                 customerMessage = MK.IM_SYS_FRIEND;
             }
 
-            String customerTitle = customerServiceConfig.getCustomerTitle();
+            String customerTitle = sysConfigService.findConfigValue(SysConfigConstant.CUSTOMER_SERVICE_ADD_MSG_TITLE);
             if (StringUtils.isEmpty(customerTitle)) {
                 customerTitle = MK.IM_SYS_TITLE;
             }
@@ -332,6 +369,63 @@ public class ImUserFriendServiceImpl extends ServiceImpl<ImUserFriendDao, ImUser
     }
 
     /**
+     * 与客服建立好友关系时,客服给好友发送消息
+     */
+    @Override
+    public void sendCustomerServiceAddFriendMessage(Long customerServiceId, String sendTitle, String sendMessage, List<Long> friendIds, ClientEnum friendType) {
+
+        if (customerServiceId == null || CollectionUtils.isEmpty(friendIds)) {
+            return;
+        }
+
+        try {
+            if (StringUtils.isEmpty(sendMessage)) {
+                sendMessage = MK.IM_SYS_FRIEND;
+            }
+
+            if (StringUtils.isEmpty(sendTitle)) {
+                sendTitle = MK.IM_SYS_TITLE;
+            }
+
+            // 拓展消息
+            PushExt pushExt = PushExt.build(sendTitle, 1,
+                    new PushExt.HW("channelId", "NORMAL"), new PushExt.VIVO("1"),
+                    new PushExt.APNs("", ""),
+                    new PushExt.OPPO(""));
+
+
+            List<String> targetIds = friendIds.stream().map(n -> imGroupService.getImUserId(n, friendType)).collect(Collectors.toList());
+            MessageWrapper.PrivateMessage build = MessageWrapper.PrivateMessage.builder()
+                    .senderId(imGroupService.getImUserId(customerServiceId.toString(), ClientEnum.TEACHER.getCode()))
+                    .targetIds(targetIds)
+                    //.objectName(txtMessage.getType())
+                    //.rongCloueMessage(txtMessage)
+                    .pushExt(JSON.toJSONString(pushExt))
+                    .includeSender(0)
+                    .build();
+
+
+            if (TencentCloudImPlugin.PLUGIN_NAME.equals(imPluginContext.defaultService())) {
+                // 腾讯IM消息
+                TencentRequest.MessageBody message = TencentRequest.MessageBody.builder()
+                        .msgType(ETencentMessage.TIMTextElem.name())
+                        .msgContent(TencentRequest.TextMessageBody.builder().text(sendMessage).build())
+                        .build();
+
+                Boolean ret = imPluginContext.getPluginService().sendPrivateMessage(build.objectName(message.getMsgType()).tencentMessage(message));
+                log.info("registerUserBindCustomerService GROUP tencentCloud senderId={}, ret={}", build.getSenderId(), ret);
+            } else {
+                // 融云IM消息
+                TxtMessage message = new TxtMessage(sendMessage, "");
+                Boolean ret = imPluginContext.getPluginService().sendPrivateMessage(build.objectName(message.getType()).rongCloueMessage(message));
+                log.info("registerUserBindCustomerService GROUP rongCloud senderId={}, ret={}", build.getSenderId(), ret);
+            }
+        } catch (Exception e) {
+            log.error("registerUserBindCustomerService userId={}", customerServiceId, e);
+        }
+    }
+
+    /**
      * 发送系统客服消息
      *
      * @param sender 发送者

+ 244 - 57
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/MemberPriceSettingsServiceImpl.java

@@ -3,11 +3,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.extension.service.impl.ServiceImpl;
+import com.google.common.collect.Lists;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.dao.UserOrderDao;
 import com.yonge.cooleshow.biz.dal.dto.ActivityPlanRewardDto;
-import com.yonge.cooleshow.biz.dal.dto.VipSubmitReq;
 import com.yonge.cooleshow.biz.dal.dto.req.OrderReq;
+import com.yonge.cooleshow.biz.dal.dto.search.OrderSearch;
 import com.yonge.cooleshow.biz.dal.entity.*;
 import com.yonge.cooleshow.biz.dal.enums.*;
 import com.yonge.cooleshow.biz.dal.entity.VipCardRecord;
@@ -21,15 +23,14 @@ import com.yonge.cooleshow.biz.dal.vo.*;
 
 import com.yonge.cooleshow.biz.dal.vo.res.OrderCreateRes;
 import com.yonge.cooleshow.biz.dal.wrapper.UserPaymentOrderWrapper;
-import com.yonge.cooleshow.common.constant.SysConfigConstant;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.enums.ActivityShareEnum;
-import com.yonge.cooleshow.common.enums.RewardTypeEnum;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import com.yonge.toolset.base.exception.BizException;
-import com.yonge.toolset.base.string.MessageFormatter;
 import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
 import com.yonge.toolset.utils.date.DateUtil;
+import org.joda.time.DateTime;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -37,9 +38,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import com.yonge.cooleshow.biz.dal.dto.search.MemberPriceSettingsSearch;
 import com.yonge.cooleshow.biz.dal.dao.MemberPriceSettingsDao;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.util.*;
+import java.util.stream.Collectors;
 
 
 @Service
@@ -66,6 +69,9 @@ public class MemberPriceSettingsServiceImpl extends ServiceImpl<MemberPriceSetti
     private UserOrderService userOrderService;
 
     @Autowired
+    private UserOrderDao userOrderDao;
+
+    @Autowired
     private RedisCacheService redisCacheService;
 
     @Override
@@ -88,16 +94,32 @@ public class MemberPriceSettingsServiceImpl extends ServiceImpl<MemberPriceSetti
     public HttpResponseResult<OrderCreateRes> orderCreate(OrderReq.OrderReqInfo orderReqInfo) {
         MemberPriceSettingsVo detail = detail(Long.parseLong(orderReqInfo.getBizContent().toString()));
         if (null == detail) {
-            return HttpResponseResult.failed("未找到会员卡信息");
+            return HttpResponseResult.failed("产品信息已更新,请重新选择");
+        }
+
+        if (!orderReqInfo.getOrderType().name().equals(detail.getVipType().name())) {
+            return HttpResponseResult.failed("产品信息已更新,请重新选择");
         }
 
+        if (Boolean.FALSE.equals(detail.getStatus())) {
+            return HttpResponseResult.failed("产品信息已更新,请重新选择");
+        }
+
+
+        // 判断是否有待支付订单 如果有返回不可下单
+        checkOrder(orderReqInfo.getOrderClient(), orderReqInfo.getOrderType().name(), orderReqInfo.getUserId());
+
+
+        checkVip(detail, orderReqInfo.getVipEndDays(), orderReqInfo.getUserId(), orderReqInfo.getOrderClient(), orderReqInfo.getGoodsNum(),orderReqInfo.getBizPrice());
+
         OrderCreateRes orderCreateRes = new OrderCreateRes();
         BigDecimal couponAmount = BigDecimal.ZERO;
         ActivityPlanVo activityPlanVo = activityPlanService.detail(orderReqInfo.getActivityId());
 
         if (activityPlanVo != null && activityPlanVo.getActivityState() == 1) {
             for (ActivityPlanRewardDto activityPlanRewardDto : activityPlanVo.getActivityRewardList()) {
-                if (activityPlanRewardDto.getActivityReward().getUnit().getCode().equals(detail.getPeriod().getCode())) {
+                if (activityPlanRewardDto.getActivityReward().getRewardType().getCode().equals(detail.getVipType().getCode())
+                && activityPlanRewardDto.getActivityReward().getUnit().getCode().equals(detail.getPeriod().getCode())) {
                     couponAmount = activityPlanRewardDto.getActivityReward().getDiscountPrice();
                     orderCreateRes.setActivityId(activityPlanVo.getId());
                     orderCreateRes.setRewardId(activityPlanRewardDto.getActivityReward().getId());
@@ -110,14 +132,70 @@ public class MemberPriceSettingsServiceImpl extends ServiceImpl<MemberPriceSetti
         orderCreateRes.setMerchId(0l);
         orderCreateRes.setBizId(detail.getId());
         orderCreateRes.setBizContent("会员卡购买-" + detail.getPeriod().getMsg());
-        orderCreateRes.setGoodNum(1);
-        orderCreateRes.setOriginalPrice(detail.getOriginalPrice());
-        orderCreateRes.setCouponAmount(couponAmount);
-        orderCreateRes.setExpectPrice(detail.getSalePrice());
+        orderCreateRes.setGoodNum(orderReqInfo.getGoodsNum());
+        orderCreateRes.setOriginalPrice(detail.getOriginalPrice().multiply(new BigDecimal(orderReqInfo.getGoodsNum())));
+        orderCreateRes.setCouponAmount(couponAmount.multiply(new BigDecimal(orderReqInfo.getGoodsNum())));
+        orderCreateRes.setExpectPrice(detail.getSalePrice().multiply(new BigDecimal(orderReqInfo.getGoodsNum())));
         orderCreateRes.setSourceType(SourceTypeEnum.PLATFORM);
+        UserPaymentOrderWrapper.VipDays vipDays = new UserPaymentOrderWrapper.VipDays();
+        vipDays.setVipEndDays(orderReqInfo.getVipEndDays());
+        orderCreateRes.setBizJson(JSON.toJSONString(vipDays));
         return HttpResponseResult.succeed(orderCreateRes);
     }
 
+    private void checkVip(MemberPriceSettingsVo detail, Integer vipDays, Long userId, ClientEnum client, Integer num, BigDecimal bizPrice) {
+        // 判断会员剩余天数是否改变
+        if (detail.getVipType() == EVipType.SVIP && vipDays != null && vipDays > 0) {
+            VipCardRecordWrapper.UserVip userVip = vipCardRecordService.userVipInfo(userId, client);
+            if (!userVip.getVipEndDays().equals(vipDays)) {
+                throw new BizException(998, "您当前VIP天数更新,请刷新后尝试");
+            }
+            // 判断能不能升级
+            // 按时间区分 个数
+            int days = getSvipDays(detail, num, userVip);
+            if (days < userVip.getVipEndDays()) {
+                throw new BizException(998, "您当前VIP天数更新,请刷新后尝试");
+            }
+        }
+        if (bizPrice !=null && detail.getSalePrice().compareTo(bizPrice) !=0) {
+            throw new BizException(999, "产品信息已更新,请重新选择");
+
+        }
+    }
+
+    private int getSvipDays(MemberPriceSettingsVo detail, Integer num, VipCardRecordWrapper.UserVip userVip) {
+        Integer timeNum = num;
+
+        // 判断当前时间 加 一段时间后,和当前天数比较
+        Date svipStartDate = new Date();
+        if (userVip.getSvipEndDate() != null) {
+            svipStartDate = userVip.getSvipEndDate();
+        }
+
+        DateTime dateTime = DateTime.parse(DateUtil.format(svipStartDate, "yyyy-MM-dd"))
+            .withHourOfDay(23)
+            .withMinuteOfHour(59)
+            .withSecondOfMinute(59)
+            .withMillisOfSecond(0);
+        if (PeriodEnum.DAY.equals(detail.getPeriod())) {
+            dateTime=dateTime.plusDays(timeNum);
+        } else if (PeriodEnum.MONTH.equals(detail.getPeriod())) {
+            dateTime=dateTime.plusMonths(timeNum);
+        } else if (PeriodEnum.QUARTERLY.equals(detail.getPeriod())) {
+            dateTime=dateTime.plusMonths(3 * timeNum);
+        } else if (PeriodEnum.YEAR_HALF.equals(detail.getPeriod())) {
+            dateTime=dateTime.plusMonths(6 * timeNum);
+        } else if (PeriodEnum.YEAR.equals(detail.getPeriod())) {
+            dateTime=dateTime.plusYears(timeNum);
+        } else if (PeriodEnum.PERPETUAL.equals(detail.getPeriod())) {
+            dateTime=dateTime.plusYears(100);
+        }
+        Date date = dateTime.toDate();
+        // 比较两个时间 天数差
+        int days = DateUtil.daysBetween(svipStartDate, date);
+        return days;
+    }
+
     @Override
     public void orderSuccess(UserOrderDetailVo orderDetailVo) {
         orderSuccess(orderDetailVo,true);
@@ -126,25 +204,101 @@ public class MemberPriceSettingsServiceImpl extends ServiceImpl<MemberPriceSetti
     @Override
     public void orderSuccess(UserOrderDetailVo orderDetailVo,boolean messageFlag) {
 
-        VipCardRecord vipCardRecord = vipCardRecordService.buildVipCardRecordByOrderDetail(orderDetailVo);
+        if (null == orderDetailVo) {
+            return;
+        }
+        MemberPriceSettingsVo detail = detail(orderDetailVo.getBizId());
+
+
+        VipCardRecordWrapper.AddVipCardRecord addVipCardRecord = new VipCardRecordWrapper.AddVipCardRecord();
+
+        addVipCardRecord.setUserId(orderDetailVo.getUserId());
+        addVipCardRecord.setClientType(orderDetailVo.getOrderClient());
+        addVipCardRecord.setStatus(EVipRecordStatus.ADD);
+        addVipCardRecord.setVipType(detail.getVipType());
+        addVipCardRecord.setType(detail.getPeriod());
+        addVipCardRecord.setTimes(orderDetailVo.getGoodNum());
+        addVipCardRecord.setSendMsg(false);
+        addVipCardRecord.setSourceType(SourceTypeEnum.ORDER);
+        addVipCardRecord.setCreateBy(orderDetailVo.getUserId());
+        addVipCardRecord.setOrderNo(orderDetailVo.getOrderNo());
+        addVipCardRecord.setSubOrderNo(orderDetailVo.getSubOrderNo());
+        addVipCardRecord.setVipCardId(orderDetailVo.getBizId());
+        addVipCardRecord.setOrderFlag(true);
+
+        // 判断转换天数
+
+        VipCardRecordWrapper.UserVip userVip = vipCardRecordService.userVipInfo(orderDetailVo.getUserId(), orderDetailVo.getOrderClient());
+        int svipDays = getSvipDays(detail, orderDetailVo.getGoodNum(), userVip);
+        if (detail.getVipType() == EVipType.SVIP &&userVip.getVipEndDays() !=null && svipDays >=userVip.getVipEndDays()) {
+            addVipCardRecord.setVipDays(userVip.getVipEndDays());
+            if (userVip.getVipType() == EVipType.VIP) {
+                addVipCardRecord.setVipDays(Math.max(userVip.getVipEndDays()-1,0));
+            }
+        }
+
+        addVipCardRecord.setReason("会员购买");
+        vipCardRecordService.add(addVipCardRecord);
 
-        UserVipInfoVo userVipInfoVo = getUserVipInfoVo(vipCardRecord);
         //会员购买消息推送
         if (messageFlag) {
-            authSend(userVipInfoVo.getUserId(), userVipInfoVo.getPhone(), DateUtil.format(vipCardRecord.getEndTime(), DateUtil.DEFAULT_PATTERN), orderDetailVo.getOrderClient());
+
+            SysUser sysUser = sysUserFeignService.queryUserById(orderDetailVo.getUserId());
+            if (sysUser == null) {
+                return;
+            }
+
+            // 按时间区分 个数
+            Integer timeNum = 0;
+            PeriodEnum periodType  = null;
+            if (PeriodEnum.DAY.equals(detail.getPeriod())) {
+                timeNum = 1;
+                periodType = PeriodEnum.DAY;
+            } else if (PeriodEnum.MONTH.equals(detail.getPeriod())) {
+                timeNum = 1;
+                periodType = PeriodEnum.MONTH;
+            } else if (PeriodEnum.QUARTERLY.equals(detail.getPeriod())) {
+                timeNum = 3;
+                periodType = PeriodEnum.MONTH;
+            } else if (PeriodEnum.YEAR_HALF.equals(detail.getPeriod())) {
+                timeNum = 6;
+                periodType = PeriodEnum.MONTH;
+            } else if (PeriodEnum.YEAR.equals(detail.getPeriod())) {
+                timeNum = 1;
+                periodType = PeriodEnum.YEAR;
+            } else if (PeriodEnum.PERPETUAL.equals(detail.getPeriod())) {
+                timeNum = 1;
+                periodType = PeriodEnum.PERPETUAL;
+            }
+            if (periodType == null) {
+                return;
+            }
+            String s = timeNum + periodType.getMsg() + addVipCardRecord.getVipType().getName();
+            if (PeriodEnum.PERPETUAL.equals(detail.getPeriod())) {
+                s =addVipCardRecord.getVipType().getName();
+            }
+            authSend(sysUser.getId(), sysUser.getPhone(), s, orderDetailVo.getOrderClient());
         }
     }
 
 
     @Override
+    @Transactional
     public void activityReward(Long userId, ClientEnum client, ActivityReward activityReward, Long activityId,String activityName) {
 
-        VipCardRecord vipCardRecord = vipCardRecordService.buildVipCardRecordByOrderDetail(userId,client,activityReward,activityId,activityName);
-        if (vipCardRecord == null) {
-            return;
-        }
+        VipCardRecordWrapper.AddVipCardRecord addVipCardRecord = new VipCardRecordWrapper.AddVipCardRecord();
+
+        addVipCardRecord.setUserId(userId);
+        addVipCardRecord.setClientType(client);
+        addVipCardRecord.setStatus(EVipRecordStatus.ADD);
+        addVipCardRecord.setVipType(EVipType.valueOf(activityReward.getRewardType().name()));
+        addVipCardRecord.setType(PeriodEnum.valueOf(activityReward.getUnit().name()));
+        addVipCardRecord.setTimes(activityReward.getNum());
+        addVipCardRecord.setSendMsg(false);
+        addVipCardRecord.setCreateBy(userId);
+        addVipCardRecord.setSourceType(SourceTypeEnum.ACTIVITY);
+        vipCardRecordService.add(addVipCardRecord);
 
-        getUserVipInfoVo(vipCardRecord);
     }
 
     private UserVipInfoVo getUserVipInfoVo(VipCardRecord vipCardRecord) {
@@ -212,19 +366,20 @@ public class MemberPriceSettingsServiceImpl extends ServiceImpl<MemberPriceSetti
         return result;
     }
 
-    @Override
-    public Boolean addVip(VipSubmitReq vipSubmitReq, ClientEnum client, SysUser sysUser) {
-
-        VipCardRecord vipCardRecord = vipCardRecordService.getVipCardRecord(vipSubmitReq.getUserId(), client, null, null, vipSubmitReq.getType().toString(),
-                            null, vipSubmitReq.getTimes(),SourceTypeEnum.PLATFORM, sysUser.getId(), vipSubmitReq.getReason());
-
-        getUserVipInfoVo(vipCardRecord);
-
-        // 发消息
-        sendAddVipMessage(vipSubmitReq.getUserId(),sysUser.getPhone(),client,vipSubmitReq.getTimes(),vipSubmitReq.getType(),vipSubmitReq.getReason());
-
-        return true;
-    }
+//    @Deprecated
+//    @Override
+//    public Boolean addVip(VipSubmitReq vipSubmitReq, ClientEnum client, SysUser sysUser) {
+//
+//        VipCardRecord vipCardRecord = vipCardRecordService.getVipCardRecord(vipSubmitReq.getUserId(), client, null, null, vipSubmitReq.getType().toString(),
+//                            null, vipSubmitReq.getTimes(),SourceTypeEnum.PLATFORM, sysUser.getId(), vipSubmitReq.getReason());
+//
+//        getUserVipInfoVo(vipCardRecord);
+//
+//        // 发消息
+//        sendAddVipMessage(vipSubmitReq.getUserId(),sysUser.getPhone(),client,vipSubmitReq.getTimes(),vipSubmitReq.getType(),vipSubmitReq.getReason());
+//
+//        return true;
+//    }
 
     @Override
     public MemberPriceVo getVipShare(MemberPriceSettingsSearch query) {
@@ -248,7 +403,8 @@ public class MemberPriceSettingsServiceImpl extends ServiceImpl<MemberPriceSetti
 
         for (ActivityPlanRewardDto activityPlanRewardDto : activityPlan.getActivityRewardList()) {
             for (MemberPriceSettingsVo memberPriceSettingsVo : memberPriceSettingsVos) {
-                if (memberPriceSettingsVo.getPeriod().getCode().equals( activityPlanRewardDto.getActivityReward().getUnit().getCode())) {
+                if (activityPlanRewardDto.getActivityReward().getRewardType().getCode().equals(memberPriceSettingsVo.getVipType().getCode())
+                    && activityPlanRewardDto.getActivityReward().getUnit().getCode().equals(memberPriceSettingsVo.getPeriod().getCode())) {
                     memberPriceSettingsVo.setDiscount(YesOrNoEnum.YES);
                     memberPriceSettingsVo.setDiscountPrice(activityPlanRewardDto.getActivityReward().getDiscountPrice());
                 }
@@ -261,14 +417,29 @@ public class MemberPriceSettingsServiceImpl extends ServiceImpl<MemberPriceSetti
     public void orderCreate(UserPaymentOrderWrapper.OrderGoodsInfo orderGoodsInfo) {
         MemberPriceSettingsVo detail = detail(Long.parseLong(orderGoodsInfo.getBizContent().toString()));
         if (null == detail) {
-            throw new BizException("未找到会员卡信息");
+            throw new BizException(999,"产品信息已更新,请重新选择");
+        }
+
+        if (!orderGoodsInfo.getGoodType().name().equals(detail.getVipType().name())) {
+            throw new BizException(999,"产品信息已更新,请重新选择");
+        }
+        if (Boolean.FALSE.equals(detail.getStatus())) {
+            throw new BizException(999,"产品信息已更新,请重新选择");
         }
+
+
+        checkOrder(orderGoodsInfo.getPaymentClient(), detail.getVipType().name(), orderGoodsInfo.getUserId());
+
+        // 判断会员剩余天数是否改变
+        checkVip(detail, orderGoodsInfo.getVipEndDays(), orderGoodsInfo.getUserId(), orderGoodsInfo.getPaymentClient(), orderGoodsInfo.getGoodNum(), orderGoodsInfo.getBizPrice());
+
         BigDecimal couponAmount = BigDecimal.ZERO;
         ActivityPlanVo activityPlanVo = activityPlanService.detail(orderGoodsInfo.getActivityId());
 
         if (activityPlanVo != null && activityPlanVo.getActivityState() == 1) {
             for (ActivityPlanRewardDto activityPlanRewardDto : activityPlanVo.getActivityRewardList()) {
-                if (activityPlanRewardDto.getActivityReward().getUnit().getCode().equals(detail.getPeriod().getCode())) {
+                if (activityPlanRewardDto.getActivityReward().getRewardType().getCode().equals(detail.getVipType().getCode())
+                    && activityPlanRewardDto.getActivityReward().getUnit().getCode().equals(detail.getPeriod().getCode())) {
                     couponAmount = activityPlanRewardDto.getActivityReward().getDiscountPrice();
                     break;
                 }
@@ -281,13 +452,16 @@ public class MemberPriceSettingsServiceImpl extends ServiceImpl<MemberPriceSetti
         userOrderDetail.setMerchId(0l);
         userOrderDetail.setBizId(detail.getId());
         userOrderDetail.setBizContent("会员卡购买-" + detail.getPeriod().getMsg());
-        userOrderDetail.setGoodNum(1);
-        userOrderDetail.setOriginalPrice(detail.getOriginalPrice());
-        userOrderDetail.setCouponAmount(couponAmount);
-        userOrderDetail.setExpectPrice(detail.getSalePrice());
+        userOrderDetail.setGoodNum(orderGoodsInfo.getGoodNum());
+        userOrderDetail.setOriginalPrice(detail.getOriginalPrice().multiply(new BigDecimal(orderGoodsInfo.getGoodNum())));
+        userOrderDetail.setCouponAmount(couponAmount.multiply(new BigDecimal(orderGoodsInfo.getGoodNum())));
+        userOrderDetail.setExpectPrice(detail.getSalePrice().multiply(new BigDecimal(orderGoodsInfo.getGoodNum())));
         userOrderDetail.setActualPrice(userOrderDetail.getExpectPrice().subtract(couponAmount));
         orderGoodsInfo.setUserOrderDetail(userOrderDetail);
 
+        UserPaymentOrderWrapper.VipDays vipDays = new UserPaymentOrderWrapper.VipDays();
+        vipDays.setVipEndDays(orderGoodsInfo.getVipEndDays());
+        userOrderDetail.setBizJson(JSON.toJSONString(vipDays));
         userOrderDetail.setAccountConfig( teacherService.teacherSettlementFrom(null,orderGoodsInfo.getRecomUserId()).jsonString());
 
         // 设置金额入账去向
@@ -296,6 +470,19 @@ public class MemberPriceSettingsServiceImpl extends ServiceImpl<MemberPriceSetti
 
     }
 
+    private void checkOrder(ClientEnum orderGoodsInfo, String orderType, Long userId) {
+        // 判断是否有待支付订单 如果有返回不可下单
+        OrderSearch search = new OrderSearch();
+        search.setOrderClient(orderGoodsInfo.name());
+        search.setGoodType(Lists.newArrayList(GoodTypeEnum.VIP, GoodTypeEnum.SVIP).stream().map(GoodTypeEnum::name).collect(Collectors.joining(",")));
+        search.setUserId(userId);
+
+        UserOrderVo userOrderVo = userOrderDao.getPendingOrder(search);
+        if (null != userOrderVo) {
+            throw new BizException(997, "您有未支付订单,请先支付");
+        }
+    }
+
     private void sendAddVipMessage(Long userId,String phone, ClientEnum client, Integer times, PeriodEnum type, String reason) {
         try {
             Map<Long, String> receivers = new HashMap<>();
@@ -348,28 +535,28 @@ public class MemberPriceSettingsServiceImpl extends ServiceImpl<MemberPriceSetti
         receivers.put(userId, phone);
 
         // 判断是否是机构学生 机构学生推送走另一个
-        Student student = studentService.getById(userId);
-        if (clientEnum.equals(ClientEnum.STUDENT) && student != null && student.getTenantId() != null && student.getTenantId() >0) {
-            try {
-                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.TENANT_VIP_BUY,
-                        receivers, null, 0, null, ClientEnum.TENANT_STUDENT.getCode(),param1);
-            } catch (Exception e) {
-                log.error("会员购买极光消息推送异常,userId={}", userId);
-            }
-        } else {
-            try {
-                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.VIP_BUY_SUCCESS,
-                        receivers, null, 0, null, clientEnum.getCode(), param1);
-            } catch (Exception e) {
-                log.error("会员购买极光消息推送异常,userId={}", userId);
+
+        try {
+            MessageTypeEnum messageTypeEnum = MessageTypeEnum.NEW_VIP_BUY_SUCCESS;
+            if (clientEnum == ClientEnum.TEACHER) {
+                messageTypeEnum= MessageTypeEnum.NEW_TEACHER_VIP_BUY_SUCCESS;
             }
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, messageTypeEnum,
+                    receivers, null, 0, null, clientEnum.getCode(), param1);
+        } catch (Exception e) {
+            log.error("会员购买极光消息推送异常,userId={}", userId);
+        }
 
-            try {
-                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS, MessageTypeEnum.SMS_VIP_BUY_SUCCESS,
-                        receivers, null, 0, null, clientEnum.getCode(), param1);
-            } catch (Exception e) {
-                log.error("会员购买短信消息推送异常,userId={}", userId);
+        try {
+
+            MessageTypeEnum messageTypeEnum = MessageTypeEnum.SMS_NEW_VIP_BUY_SUCCESS;
+            if (clientEnum == ClientEnum.TEACHER) {
+                messageTypeEnum= MessageTypeEnum.SMS_TEACHER_NEW_VIP_BUY_SUCCESS;
             }
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS, messageTypeEnum,
+                    receivers, null, 0, null, clientEnum.getCode(), param1);
+        } catch (Exception e) {
+            log.error("会员购买短信消息推送异常,userId={}", userId);
         }
 
     }

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

@@ -254,24 +254,46 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
     }
 
     @Override
-    public IPage<MusicSheetVo> queryRelatedList(IPage<MusicSheetVo> page, Long albumId, Long musicSheetId) {
+    public IPage<MusicSheetVo> queryRelatedList(IPage<MusicSheetVo> page, MusicSheetRelatedQueryInfo queryInfo) {
 
-        if (albumId == null) {
+
+        MusicSheet musicSheet = baseMapper.selectById(queryInfo.getMusicSheetId());
+        if (queryInfo.getAlbumId() == null) {
             // 查询专辑下的所有曲目
 
-            MusicSheet musicSheet = baseMapper.selectById(musicSheetId);
 
             if (musicSheet != null) {
                 MusicAlbumDetailSearch query = new MusicAlbumDetailSearch();
                 query.setMusicTagIds(musicSheet.getMusicTag());
                 query.setAuditVersion(musicSheet.getAuditVersion());
+                query.setMusicSheetType(musicSheet.getMusicSheetType());
+                if (queryInfo.getSubjectId() !=null) {
+                    query.setSubjectIdList(Lists.newArrayList(queryInfo.getSubjectId()));
+                }
+                query.setState(YesOrNoEnum.YES);
+                query.setProviderType(SourceTypeEnum.PLATFORM);
+                query.setExcludeMusicIds(Lists.newArrayList(queryInfo.getMusicSheetId()));
+                if (StringUtils.isNotBlank(musicSheet.getMusicSubject())) {
+                    List<Long> subjectIds = Arrays.stream(musicSheet.getMusicSubject().split(",")).filter(StringUtils::isNotBlank).map(Long::parseLong).collect(Collectors.toList());
+                    query.setMustMatchSubjectIds(subjectIds);
+                }
                 return page.setRecords(baseMapper.selectPage(page, query));
             }
         } else {
             // 查询带有当前曲目标签的所有曲目
             MusicAlbumDetailSearch query = new MusicAlbumDetailSearch();
-            query.setId(albumId);
+            query.setId(queryInfo.getAlbumId());
+            query.setState(YesOrNoEnum.YES);
             query.setType(2);
+            if (queryInfo.getSubjectId() !=null) {
+                query.setSubjectIdList(Lists.newArrayList(queryInfo.getSubjectId()));
+            }
+            query.setExcludeMusicIds(Lists.newArrayList(queryInfo.getMusicSheetId()));
+            if (StringUtils.isNotBlank(musicSheet.getMusicSubject())) {
+                List<Long> subjectIds = Arrays.stream(musicSheet.getMusicSubject().split(",")).filter(StringUtils::isNotBlank).map(Long::parseLong).collect(Collectors.toList());
+                query.setMustMatchSubjectIds(subjectIds);
+            }
+            query.setExcludeMusicIds(Lists.newArrayList(queryInfo.getMusicSheetId()));
             return page.setRecords(baseMapper.selectAlbumDetailPage(page, query));
         }
         return null;
@@ -670,6 +692,7 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
                     List<Long> musicSheetIds = tenantAlbumMusicService.getMusicIdsByIds(collect);
                     if (CollectionUtils.isNotEmpty(musicSheetIds) && musicSheetIds.contains(detail.getId())) {
                         detail.setPlay(YesOrNoEnum.YES);
+                        detail.setBuyed(true);
                     }
                 }
             } else if (ClientEnum.TEACHER == userType) {
@@ -679,6 +702,7 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
                     List<Long> musicSheetIds = tenantAlbumMusicService.getMusicIdsByTenantIds(teacher.getTenantId());
                     if (musicSheetIds.contains(detail.getId())) {
                         detail.setPlay(YesOrNoEnum.YES);
+                        detail.setBuyed(true);
                     }
                 }
             }
@@ -707,6 +731,7 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
                 detail.setOrderNo(musicSheetPurchaseRecord.getOrderNo());
                 if (OrderStatusEnum.PAID.getCode().equals(musicSheetPurchaseRecord.getOrderStatus().getCode())) {
                     detail.setPlay(YesOrNoEnum.YES);
+                    detail.setBuyed(true);
                     return;
                 }
             }
@@ -721,12 +746,12 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
             // 会员 判断是否为会员, 会员可播放
             if (userType.equals(ClientEnum.STUDENT)) {
                 StudentVo studentVo = studentService.detail(studentId);
-                if (studentVo != null && YesOrNoEnum.YES.getCode().equals(studentVo.getIsVip().getCode())) {
+                if (studentVo != null && studentVo.getUserVip().getVipType() !=EVipType.NOT_VIP) {
                     detail.setPlay(YesOrNoEnum.YES);
                 }
             } else if (userType.equals(ClientEnum.TEACHER)) {
                 TeacherVo teacher = teacherService.detail(studentId);
-                if (teacher != null && YesOrNoEnum.YES.getCode().equals(teacher.getIsVip().getCode())) {
+                if (teacher != null && teacher.getUserVip().getVipType() !=EVipType.NOT_VIP) {
                     detail.setPlay(YesOrNoEnum.YES);
                 }
             }
@@ -760,6 +785,7 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
                     .count();
             if (count > 0) {
                 detail.setPlay(YesOrNoEnum.YES);
+                detail.setBuyed(true);
                 return;
             }
         }
@@ -773,7 +799,7 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
                 List<Long> musicSheetIds = tenantAlbumMusicService.getMusicIdsByIds(tenantAlbumIds);
                 if (musicSheetIds.contains(detail.getId())) {
                     detail.setPlay(YesOrNoEnum.YES);
-                    return;
+                    detail.setBuyed(true);
                 }
             }
         } else if (ClientEnum.TEACHER == userType) {
@@ -783,7 +809,7 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
                 List<Long> musicSheetIds = tenantAlbumMusicService.getMusicIdsByTenantIds(teacher.getTenantId());
                 if (musicSheetIds.contains(detail.getId())) {
                     detail.setPlay(YesOrNoEnum.YES);
-                    return;
+                    detail.setBuyed(true);
                 }
             }
         }
@@ -2370,6 +2396,20 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
         return new ArrayList<>();
     }
 
+    @Override
+    public IPage<MusicSheetVo> queryTenantRelatedList(IPage<Object> page, MusicSheetRelatedQueryInfo queryInfo) {
+
+        MusicSheet musicSheet = musicSheetDao.get(queryInfo.getMusicSheetId());
+        if (musicSheet == null) {
+            throw new BizException("曲目不存在");
+        }
+        queryInfo.setMusicSheetType(musicSheet.getMusicSheetType());
+        if (musicSheet.getMusicSheetType() == MusicSheetTypeEnum.CONCERT) {
+            queryInfo.setSubjectId(null);
+        }
+        return musicSheetDao.queryTenantRelatedList(page,queryInfo);
+    }
+
 
     private void syncMusicSheet(MusicSheet record, Date date) {
         List<MusicSheetAccompaniment> list = musicSheetAccompanimentService.lambdaQuery().eq(MusicSheetAccompaniment::getMusicSheetId, record.getId()).list();

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

@@ -956,7 +956,12 @@ public class PaymentDivMemberRecordServiceImpl extends ServiceImpl<PaymentDivMem
     private void teacherShare(UserOrderDetailVo userPaymentOrder, BigDecimal shareFee) {
         //获取账期时间
         Date accountPeriodTime = userOrderService.getAccountPeriodTime(userPaymentOrder);
-        AccountBizTypeEnum bizTypeEnum = AccountBizTypeEnum.valueOf(userPaymentOrder.getGoodType().getCode() + "_SHARE");
+        AccountBizTypeEnum bizTypeEnum;
+        if (userPaymentOrder.getGoodType() == GoodTypeEnum.SVIP) {
+            bizTypeEnum = AccountBizTypeEnum.VIP_SHARE;
+        } else {
+            bizTypeEnum = AccountBizTypeEnum.valueOf(userPaymentOrder.getGoodType().getCode() + "_SHARE");
+        }
         if (null != bizTypeEnum) {
             //插入分润老师账户变更记录-分润老师预收
             HttpResponseResult<UserAccountRecord> recomRecordRes = userAccountService.accountRecord(
@@ -1031,8 +1036,12 @@ public class PaymentDivMemberRecordServiceImpl extends ServiceImpl<PaymentDivMem
                 continue;
             }
             String type = userPaymentOrder.getGoodType().getCode();
-            if (share) {
-                type = type + "_SHARE";
+            if (share ) {
+                if (type.equals(GoodTypeEnum.SVIP.name())) {
+                    type = AccountBizTypeEnum.VIP_SHARE.name();
+                } else {
+                    type = type + "_SHARE";
+                }
             }
 
             AccountBizTypeEnum bizTypeEnum = AccountBizTypeEnum.valueOf(type);

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

@@ -75,6 +75,7 @@ public class PlatformCashAccountRecordServiceImpl extends ServiceImpl<PlatformCa
         paramNames.add(AccountBizTypeEnum.ALBUM.getCode());
         paramNames.add(AccountBizTypeEnum.ALBUM_SHARE.getCode());
         paramNames.add(AccountBizTypeEnum.VIP.getCode());
+        paramNames.add(AccountBizTypeEnum.SVIP.getCode());
         paramNames.add(AccountBizTypeEnum.VIP_SHARE.getCode());
         paramNames.add(AccountBizTypeEnum.ACTI_REGIST.getCode());
         paramNames.add(AccountBizTypeEnum.ACTI_REGIST_SHARE.getCode());

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

@@ -17,10 +17,7 @@ import com.yonge.cooleshow.biz.dal.dao.*;
 import com.yonge.cooleshow.biz.dal.dto.search.QueryMyFollowSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentSearch;
 import com.yonge.cooleshow.biz.dal.entity.*;
-import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
-import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
-import com.yonge.cooleshow.biz.dal.enums.ImGroupType;
-import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
+import com.yonge.cooleshow.biz.dal.enums.*;
 import com.yonge.cooleshow.biz.dal.mapper.SysUserMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumRefMapper;
@@ -34,6 +31,7 @@ import com.yonge.cooleshow.biz.dal.vo.StudentHomeVo;
 import com.yonge.cooleshow.biz.dal.vo.StudentVo;
 import com.yonge.cooleshow.biz.dal.vo.TeacherVo;
 import com.yonge.cooleshow.biz.dal.wrapper.StudentWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.im.ImGroupWrapper;
 import com.yonge.cooleshow.common.constant.SysConfigConstant;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
@@ -116,6 +114,9 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
     @Autowired
     private SysMessageService sysMessageService;
 
+    @Autowired
+    private VipCardRecordService vipCardRecordService;
+
     @Override
     public StudentDao getDao() {
         return baseMapper;
@@ -134,7 +135,16 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
     private TenantGroupAlbumMapper tenantGroupAlbumMapper;
     @Override
     public StudentVo detail(Long userId) {
-        return baseMapper.detail(userId);
+        StudentVo detail = baseMapper.detail(userId);
+        VipCardRecordWrapper.UserVip userVip = vipCardRecordService.userVipInfo(userId, ClientEnum.STUDENT);
+        detail.setUserVip(userVip);
+        detail.setVipType(EUserVipType.NORMAL);
+        List<VipCardRecordWrapper.UserVipInfo> userVipInfos = vipCardRecordService.queryUserVipInfo(Collections.singletonList(userId), ClientEnum.STUDENT.getCode());
+        Map<Long, VipCardRecordWrapper.UserVipInfo> curVipMap = userVipInfos.stream().collect(Collectors.toMap(VipCardRecordWrapper.UserVipInfo::getUserId, Function.identity()));
+        VipCardRecordWrapper.UserVipInfo vipType = curVipMap.getOrDefault(userId, new VipCardRecordWrapper.UserVipInfo());
+        detail.setMembershipEndTime(vipType.getCurrentVipSvipEndTime());
+        detail.setVipType(vipType.getCurrentVipType());
+        return detail;
     }
 
     @Override
@@ -144,7 +154,26 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
 
     @Override
     public IPage<StudentVo> selectPage(IPage<StudentVo> page, StudentSearch studentSearch) {
-        return page.setRecords(baseMapper.selectPage(page, studentSearch));
+        List<StudentVo> records = baseMapper.selectPage(page, studentSearch);
+        for (StudentVo record : records) {
+            EUserVipType vipType = record.getVipType();
+            if (EUserVipType.NORMAL.equals(vipType)) {
+                record.setMembershipEndTime(Optional.ofNullable(record.getVipEndTime()).orElse(record.getSvipEndTime()));
+            }
+            if (EUserVipType.SVIP.equals(vipType)) {
+                Date perSvipEndTime = record.getPerSvipEndTime();
+                if (perSvipEndTime != null) {
+                    // 永久会员
+                    record.setMembershipEndTime(null);
+                } else {
+                    record.setMembershipEndTime(record.getSvipEndTime());
+                }
+            }
+            if (EUserVipType.VIP.equals(vipType)) {
+                record.setMembershipEndTime(record.getVipEndTime());
+            }
+        }
+        return page.setRecords(records);
     }
 
     @Override
@@ -190,6 +219,12 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
         studentHomeVo.setMusicAlbumNum(null == total.getMusicAlbumNum() ? 0 : total.getMusicAlbumNum());
         studentHomeVo.setMusicSheetNum(null == total.getMusicSheetNum() ? 0 : total.getMusicSheetNum());
 
+        // 设置会员信息
+
+
+        studentHomeVo.setUserVip(vipCardRecordService.userVipInfo(user.getId(), ClientEnum.STUDENT));
+
+
         // IM聊天用户ID
         studentHomeVo.setImUserId(imGroupService.getImUserId(String.valueOf(detail.getUserId()), ClientEnum.STUDENT.name()));
 
@@ -284,6 +319,20 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
     @Override
     public IPage<MyFollow> queryMyFollow(IPage<MyFollow> page, QueryMyFollowSearch query) {
         List<MyFollow> teacherVos = baseMapper.queryMyFollow(page, query);
+        if (CollectionUtils.isEmpty(teacherVos)) {
+            return page.setRecords(teacherVos);
+        }
+
+        // 老师ID集合
+        List<Long> teacherIds = teacherVos.stream().filter(o -> o.getTeacher() != null).map(o -> o.getTeacher().getUserId()).collect(Collectors.toList());
+        Map<Long, EVipType> vipTypeMapByUserIds = vipCardRecordService.getVipTypeMapByUserIds(teacherIds, ClientEnum.TEACHER);
+        for (MyFollow teacherVo : teacherVos) {
+            teacherVo.setVipType(EVipType.NOT_VIP);
+            if (teacherVo.getTeacher() != null) {
+                teacherVo.setVipType(vipTypeMapByUserIds.getOrDefault(teacherVo.getTeacher().getUserId(),EVipType.NOT_VIP));
+            }
+        }
+
         return page.setRecords(teacherVos);
     }
 
@@ -853,17 +902,11 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
             addBindUnBindRecord(student.getUserId(), student.getTenantId(), true);
         }
 
-        //  与随机一个客服建立好友
-        String customerService = customerServiceConfig.getCustomerService();
-        if (StringUtils.isNotBlank(customerService)) {
-            List<String> phones = Arrays.stream(customerService.split(",")).collect(Collectors.toList());
-            Random rand = new Random();
-            String mobile = phones.get(rand.nextInt(phones.size()));
-            SysUser friend = sysUserMapper.findUserByPhone(mobile);
-            if (friend != null) {
-                imUserFriendService.registerUserBindCustomerService(student.getUserId(),
-                        Collections.singletonList(friend.getId()), ClientEnum.STUDENT);
-            }
+        //  与好友数量最少的客服建立好友关系
+        Teacher customerService = teacherDao.getCustomerServiceByFriendLeast();
+        if (customerService != null) {
+            imUserFriendService.registerUserBindCustomerService(student.getUserId(),
+                    Collections.singletonList(customerService.getUserId()), ClientEnum.STUDENT);
         }
 
         // 加入机构小组群

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

@@ -78,6 +78,10 @@ public class StudentTimeServiceImpl extends ServiceImpl<StudentTimeDao, StudentT
                 if (null == studentTime.getFirstVipTime() && GoodTypeEnum.VIP.equals(detailVo.getGoodType())) {
                     studentTime.setFirstVipTime(now);
                 }
+
+                if (null == studentTime.getFirstVipTime() && GoodTypeEnum.SVIP.equals(detailVo.getGoodType())) {
+                    studentTime.setFirstSvipTime(now);
+                }
                 if (null == studentTime.getFirstPracticeTime() && GoodTypeEnum.PRACTICE.equals(detailVo.getGoodType())) {
                     studentTime.setFirstPracticeTime(now);
                 }
@@ -158,6 +162,10 @@ public class StudentTimeServiceImpl extends ServiceImpl<StudentTimeDao, StudentT
         if (GoodTypeEnum.VIP.equals(goodType) && null == studentTime.getFirstVipTime()) {
             studentTime.setFirstVipTime(new Date());
         }
+
+        if (GoodTypeEnum.SVIP.equals(goodType) && null == studentTime.getFirstVipTime()) {
+            studentTime.setFirstSvipTime(new Date());
+        }
         if (GoodTypeEnum.PRACTICE.equals(goodType) && null == studentTime.getFirstPracticeTime()) {
             studentTime.setFirstPracticeTime(new Date());
         }

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

@@ -7,7 +7,6 @@ import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.google.common.collect.Lists;
-import com.microsvc.toolkit.middleware.rtc.enums.EDeviceMessageType;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.dto.RealnameAuthReq;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
@@ -21,11 +20,13 @@ import com.yonge.cooleshow.biz.dal.dto.search.TeacherSearch;
 import com.yonge.cooleshow.biz.dal.entity.*;
 import com.yonge.cooleshow.biz.dal.enums.AuthStatusEnum;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.EUserVipType;
 import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
 import com.yonge.cooleshow.biz.dal.enums.ImGroupType;
 import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
 import com.yonge.cooleshow.biz.dal.enums.TeacherTagEnum;
 import com.yonge.cooleshow.biz.dal.enums.TeacherTypeEnum;
+import com.yonge.cooleshow.biz.dal.enums.im.EImGroupMemberRoleType;
 import com.yonge.cooleshow.biz.dal.mapper.TenantGroupMapper;
 import com.yonge.cooleshow.biz.dal.mapper.UserTenantBindRecordMapper;
 import com.yonge.cooleshow.biz.dal.queryInfo.TeacherQueryInfo;
@@ -48,10 +49,8 @@ import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumRefMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantUnbindHistoryMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantUnbindRecordMapper;
-import com.yonge.cooleshow.biz.dal.queryInfo.TeacherQueryInfo;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.vo.HotTeacherVo;
-import com.yonge.cooleshow.biz.dal.vo.MusicSheetUploadCountVo;
 import com.yonge.cooleshow.biz.dal.vo.MyFens;
 import com.yonge.cooleshow.biz.dal.vo.TeacherAuthEntryRecordVo;
 import com.yonge.cooleshow.biz.dal.vo.TeacherHomeVo;
@@ -59,16 +58,16 @@ import com.yonge.cooleshow.biz.dal.vo.TeacherVo;
 import com.yonge.cooleshow.biz.dal.wordfilter.WordFilter;
 import com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.UserPaymentOrderWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.im.ImGroupWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.teacher.TeacherWrapper;
-import com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper;
-import com.yonge.cooleshow.biz.dal.wrapper.teacher.TeacherWrapper;
 import com.yonge.cooleshow.common.constant.SysConfigConstant;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.enums.CacheNameEnum;
 import com.yonge.cooleshow.common.enums.ESettlementFrom;
 import com.yonge.cooleshow.common.enums.ETenantUnBindAuditStatus;
 import com.yonge.cooleshow.common.enums.UserFirstTimeTypeEnum;
+import com.yonge.cooleshow.common.enums.UserLockFlag;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import com.yonge.toolset.base.exception.BizException;
 import com.yonge.toolset.base.util.StringUtil;
@@ -90,21 +89,12 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.annotation.Resource;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import static com.yonge.cooleshow.biz.dal.constant.LiveRoomConstant.TEACHER_TEMP_LIVE_ROOM;
 import org.apache.commons.lang3.StringUtils;
-import org.redisson.api.RMap;
-import org.redisson.api.RedissonClient;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
 
-import javax.annotation.Resource;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
@@ -112,11 +102,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-import static com.yonge.cooleshow.biz.dal.constant.LiveRoomConstant.TEACHER_TEMP_LIVE_ROOM;
 
 @Service
 public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> implements TeacherService {
@@ -208,6 +193,8 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
     @Autowired
     private UserTenantBindRecordMapper userTenantBindRecordMapper;
 
+    @Autowired
+    private VipCardRecordService vipCardRecordService;
 
     @Override
     public TeacherDao getDao() {
@@ -243,6 +230,14 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
                 detail.setTenantName(tenantInfo == null ? "" : tenantInfo.getName());
             }
         }
+
+        // 会员信息
+        detail.setUserVip(vipCardRecordService.userVipInfo(detail.getUserId(), ClientEnum.TEACHER));
+        List<VipCardRecordWrapper.UserVipInfo> userVipInfos = vipCardRecordService.queryUserVipInfo(Collections.singletonList(userId), ClientEnum.TEACHER.getCode());
+        Map<Long, VipCardRecordWrapper.UserVipInfo> curVipMap = userVipInfos.stream().collect(Collectors.toMap(VipCardRecordWrapper.UserVipInfo::getUserId, Function.identity()));
+        VipCardRecordWrapper.UserVipInfo vipType = curVipMap.getOrDefault(userId, new VipCardRecordWrapper.UserVipInfo());
+        detail.setMembershipEndTime(vipType.getCurrentVipSvipEndTime());
+        detail.setVipType(vipType.getCurrentVipType());
         return detail;
     }
 
@@ -250,6 +245,25 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
     public IPage<TeacherVo> selectPage(IPage<TeacherVo> page, TeacherSearch search) {
         List<TeacherVo> teacherVos = baseMapper.selectPage(page, search);
 
+        for (TeacherVo record : teacherVos) {
+            EUserVipType vipType = record.getVipType();
+            if (EUserVipType.NORMAL.equals(vipType)) {
+                record.setMembershipEndTime(Optional.ofNullable(record.getVipEndTime()).orElse(record.getSvipEndTime()));
+            }
+            if (EUserVipType.SVIP.equals(vipType)) {
+                Date perSvipEndTime = record.getPerSvipEndTime();
+                if (perSvipEndTime != null) {
+                    // 永久会员
+                    record.setMembershipEndTime(null);
+                } else {
+                    record.setMembershipEndTime(record.getSvipEndTime());
+                }
+            }
+            if (EUserVipType.VIP.equals(vipType)) {
+                record.setMembershipEndTime(record.getVipEndTime());
+            }
+        }
+
         if (CollectionUtils.isEmpty(teacherVos)) {
             return page.setRecords(teacherVos);
         }
@@ -304,12 +318,18 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
             }).filter(Objects::nonNull).collect(Collectors.joining(","));
             teacherVo.setSubjectName(subjectNames);
         }
+
+
+
+
         return page.setRecords(teacherVos);
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
     public HttpResponseResult<Boolean> submit(TeacherSubmitReq teacherSubmitReq) throws BizException {
+        // todo 暂时不上客服相关
+        teacherSubmitReq.setCustomerService(null);
         if (null == teacherSubmitReq.getUserId()) {
 
             if (StringUtils.isNoneBlank(teacherSubmitReq.getPhone(), teacherSubmitReq.getCode())) {
@@ -351,6 +371,7 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
 
         teacherHomeVo.setDegreeDate(teacher.getDegreeDate());
         teacherHomeVo.setTeacherDate(teacher.getTeacherDate());
+        teacherHomeVo.setCustomerService(teacher.getCustomerService());
         //身份证号、手机号脱敏
         teacherHomeVo.setIdCardNo(ValueUtil.fuzzyIdCard(teacherHomeVo.getIdCardNo()));
 //        teacherHomeVo.setPhone(ValueUtil.fuzzyMobile(teacherHomeVo.getPhone()));
@@ -376,6 +397,11 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
             }
         }
 
+        // 会员信息
+
+        teacherHomeVo.setUserVip(vipCardRecordService.userVipInfo(teacherHomeVo.getUserId(), ClientEnum.TEACHER));
+
+
         if (YesOrNoEnum.YES.equals(teacher.getMusicianFlag())) {
             teacherHomeVo.setMusicianAuthStatus(AuthStatusEnum.PASS);
         } else {
@@ -599,18 +625,20 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
             sendBindUnBindSMS(teacher.getUserId(), teacherSubmitReq.getPhone(), MessageTypeEnum.TEACHER_BIND_TENANT, teacher.getTenantId());
 
             //  与客服建立好友
-            String customerService = customerServiceConfig.getCustomerService();
-            if (StringUtils.isNotBlank(customerService)) {
-                List<String> phones = Arrays.stream(customerService.split(",")).collect(Collectors.toList());
-                Random rand = new Random();
-                String mobile = phones.get(rand.nextInt(phones.size()));
-                SysUser friend = sysUserMapper.findUserByPhone(mobile);
-                if (friend != null) {
+            if (!Boolean.TRUE.equals(teacher.getCustomerService())) {
+                Teacher customerServiceTeacher = getCustomerServiceByFriendLeast();
+                if (customerServiceTeacher != null) {
                     imUserFriendService.registerUserBindCustomerService(teacher.getUserId(),
-                            Collections.singletonList(friend.getId()), ClientEnum.TEACHER);
+                            Collections.singletonList(customerServiceTeacher.getUserId()), ClientEnum.TEACHER);
                 }
             }
         } else {
+            // 客服状态变更,移交好友信息
+            Boolean customerService = teacher.getCustomerService();
+            List<TeacherWrapper.CustomerServiceSendMsg2User> customerServiceSendMsg2User = new ArrayList<>();
+            if (Boolean.TRUE.equals(customerService) && Boolean.FALSE.equals(teacherSubmitReq.getCustomerService())) {
+                customerServiceSendMsg2User.addAll(transferFriend(teacher.getUserId(), true));
+            }
             // 如果机构解绑,更新机构ID为-1
             if (Boolean.TRUE.equals(teacherSubmitReq.getBindTenant())) {
                 teacherSubmitReq.setTenantId(-1L);
@@ -643,11 +671,200 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
             // 老师头像
             teacher.setAvatar(Optional.ofNullable(teacherSubmitReq.getAvatar()).orElse(teacher.getAvatar()));
             baseMapper.updateById(teacher);
+
+
+            // 交接后的客服发送消息
+            if (Boolean.TRUE.equals(customerService) && Boolean.FALSE.equals(teacherSubmitReq.getCustomerService())) {
+                String customerMessage = sysConfigService.findConfigValue(SysConfigConstant.CUSTOMER_SERVICE_ADD_MSG);
+                String customerTitle = sysConfigService.findConfigValue(SysConfigConstant.CUSTOMER_SERVICE_ADD_MSG_TITLE);
+                for (TeacherWrapper.CustomerServiceSendMsg2User serviceSendMsg2User : customerServiceSendMsg2User) {
+                    imUserFriendService.sendCustomerServiceAddFriendMessage(serviceSendMsg2User.getCustomerId(), customerTitle, customerMessage, serviceSendMsg2User.getTeacherIds(),
+                            ClientEnum.TEACHER);
+                    imUserFriendService.sendCustomerServiceAddFriendMessage(serviceSendMsg2User.getCustomerId(), customerTitle, customerMessage, serviceSendMsg2User.getStudentIds(),
+                            ClientEnum.STUDENT);
+                }
+            }
+
         }
 
         return teacher;
     }
 
+    // 客服好友移交给其他客服
+    private List<TeacherWrapper.CustomerServiceSendMsg2User> transferFriend(Long userId, boolean saveGroupFriend) {
+        List<TeacherWrapper.CustomerServiceSendMsg2User> result = new ArrayList<>();
+        // 所有的好友
+        List<ImUserFriend> userFriendList = imUserFriendService.lambdaQuery()
+                .eq(ImUserFriend::getUserId, userId)
+                .eq(ImUserFriend::getClientType, ClientEnum.TEACHER)
+                .list();
+
+        // 其他客服
+        List<TeacherWrapper.TeacherFriend> customerServiceFriendNums = this.getBaseMapper().getCustomerServiceFriendNums();
+        customerServiceFriendNums.removeIf(n -> n.getTeacherId().equals(userId));
+        List<Long> customerIds = customerServiceFriendNums.stream().map(TeacherWrapper.TeacherFriend::getTeacherId).collect(Collectors.toList());
+        userFriendList.removeIf(n -> customerIds.contains(n.getFriendId()) && ClientEnum.TEACHER.equals(n.getFriendType()));
+        if (userFriendList.isEmpty()) { // 没有好友
+            return result;
+        }
+
+        List<ImUserFriend> removeFriendList = userFriendList;
+        if (saveGroupFriend) {
+            // 群里的好友保留
+            List<String> groupIdList = imGroupMemberService.lambdaQuery()
+                    .eq(ImGroupMember::getUserId, userId)
+                    .eq(ImGroupMember::getIsAdmin, true)
+                    .eq(ImGroupMember::getGroupRoleType, EImGroupMemberRoleType.Owner)
+                    .list()
+                    .stream()
+                    .map(ImGroupMember::getGroupId).collect(Collectors.toList());
+
+            List<Long> savedTeacherIdList = new ArrayList<>();
+            List<Long> savedStudentIdList = new ArrayList<>();
+
+            if (!groupIdList.isEmpty()) {
+                List<ImGroupMember> savedMemberList = imGroupMemberService.lambdaQuery()
+                        .in(ImGroupMember::getGroupId, groupIdList)
+                        .eq(ImGroupMember::getIsAdmin, false)
+                        .ne(ImGroupMember::getGroupRoleType, EImGroupMemberRoleType.Owner)
+                        .list();
+
+                savedTeacherIdList.addAll(savedMemberList.stream()
+                        .filter(n -> ImGroupMemberRoleType.TEACHER.equals(n.getRoleType()))
+                        .map(ImGroupMember::getUserId)
+                        .collect(Collectors.toList()));
+
+                savedStudentIdList.addAll(savedMemberList.stream()
+                        .filter(n -> ImGroupMemberRoleType.STUDENT.equals(n.getRoleType()))
+                        .map(ImGroupMember::getUserId)
+                        .collect(Collectors.toList()));
+            }
+
+            // 机构好友保留
+            Teacher teacher = this.getById(userId);
+            List<Long> tenantTeacherIds = new ArrayList<>();
+            List<Long> tenantStudentIds = new ArrayList<>();
+            if (teacher.getTenantId() > 0) {
+                List<Long> teacherIdList = userFriendList.stream().filter(n -> ClientEnum.TEACHER.equals(n.getFriendType())).map(ImUserFriend::getFriendId).collect(Collectors.toList());
+                List<Long> studentIdList = userFriendList.stream().filter(n -> ClientEnum.STUDENT.equals(n.getFriendType())).map(ImUserFriend::getFriendId).collect(Collectors.toList());
+                if (!teacherIdList.isEmpty()) {
+                    List<Long> tenantTeacherIdsTemp = this.lambdaQuery().in(Teacher::getUserId, teacherIdList)
+                            .eq(Teacher::getTenantId, teacher.getTenantId())
+                            .list()
+                            .stream().filter(n -> n.getTenantId() > 0).map(Teacher::getUserId).collect(Collectors.toList());
+                    tenantTeacherIds.addAll(tenantTeacherIdsTemp);
+                }
+                if (!studentIdList.isEmpty()) {
+                    List<Long> tenantStudentIdsTemp = studentService.lambdaQuery().in(Student::getUserId, studentIdList)
+                            .eq(Student::getTenantId, teacher.getTenantId())
+                            .list()
+                            .stream().filter(n -> n.getTenantId() > 0).map(Student::getUserId).collect(Collectors.toList());
+                    tenantStudentIds.addAll(tenantStudentIdsTemp);
+                }
+            }
+
+            // 删除的好友
+            removeFriendList = userFriendList.stream().filter(n -> {
+                if (ClientEnum.STUDENT.equals(n.getFriendType())) {
+                    if (tenantStudentIds.contains(n.getFriendId())) {
+                        return false;
+                    }
+                    return !savedStudentIdList.contains(n.getFriendId());
+                }
+                if (ClientEnum.TEACHER.equals(n.getFriendType())) {
+                    if (tenantTeacherIds.contains(n.getFriendId())) {
+                        return false;
+                    }
+                    return !savedTeacherIdList.contains(n.getFriendId());
+                }
+                return false;
+            }).collect(Collectors.toList());
+        }
+
+        // 删除好友
+        removeFriendList.stream().collect(Collectors.groupingBy(ImUserFriend::getFriendType)).forEach((client, friends) -> {
+            List<Long> friendIds = friends.stream().map(ImUserFriend::getFriendId).collect(Collectors.toList());
+            imUserFriendService.lambdaUpdate()
+                    .eq(ImUserFriend::getUserId, userId)
+                    .eq(ImUserFriend::getClientType, ClientEnum.TEACHER)
+                    .in(ImUserFriend::getFriendId, friendIds)
+                    .eq(ImUserFriend::getFriendType, client)
+                    .remove();
+
+            imUserFriendService.lambdaUpdate()
+                    .eq(ImUserFriend::getFriendId, userId)
+                    .eq(ImUserFriend::getFriendType, ClientEnum.TEACHER)
+                    .in(ImUserFriend::getUserId, friendIds)
+                    .eq(ImUserFriend::getClientType, client)
+                    .remove();
+        });
+
+        if (customerIds.isEmpty()) {
+            return result;
+        }
+        // 去除好友里面存在其他客服关系的好友,只有没有客服好友的好友,才需要与客服建立好友关系
+        List<ImUserFriend> teacherFriends = userFriendList.stream().filter(n -> ClientEnum.TEACHER.equals(n.getFriendType())).collect(Collectors.toList());
+        if (!teacherFriends.isEmpty()) {
+            String teacherFriendIds = teacherFriends.stream().map(n -> n.getFriendId().toString()).distinct().collect(Collectors.joining(","));
+            List<Long> existFriendIds = imUserFriendService.getDao().queryExistCustomerServiceFriend(teacherFriendIds, ClientEnum.TEACHER.getCode())
+                    .stream()
+                    .map(ImUserFriend::getUserId)
+                    .collect(Collectors.toList());
+            userFriendList.removeIf(n -> ClientEnum.TEACHER.equals(n.getFriendType()) && existFriendIds.contains(n.getFriendId()));
+        }
+
+        List<ImUserFriend> studentFriends = userFriendList.stream().filter(n -> ClientEnum.STUDENT.equals(n.getFriendType())).collect(Collectors.toList());
+        if (!studentFriends.isEmpty()) {
+            String studentFriendIds = studentFriends.stream().map(n -> n.getFriendId().toString()).distinct().collect(Collectors.joining(","));
+            List<Long> existFriendIds = imUserFriendService.getDao().queryExistCustomerServiceFriend(studentFriendIds, ClientEnum.STUDENT.getCode())
+                    .stream()
+                    .map(ImUserFriend::getUserId)
+                    .collect(Collectors.toList());
+            userFriendList.removeIf(n -> ClientEnum.STUDENT.equals(n.getFriendType()) && existFriendIds.contains(n.getFriendId()));
+        }
+
+        if (userFriendList.isEmpty()) {
+            return result;
+        }
+
+        // 好友交接
+        Map<Long, Set<Long>> teacherFriendMap = new LinkedHashMap<>();
+        Map<Long, Set<Long>> studentFriendMap = new LinkedHashMap<>();
+        for (ImUserFriend imUserFriend : userFriendList) {
+            TeacherWrapper.TeacherFriend teacherFriend = customerServiceFriendNums.get(0);
+            if (ClientEnum.TEACHER.equals(imUserFriend.getFriendType())) {
+                Set<Long> set = teacherFriendMap.getOrDefault(teacherFriend.getTeacherId(), new HashSet<>());
+                set.add(imUserFriend.getFriendId());
+                teacherFriendMap.put(teacherFriend.getTeacherId(), set);
+            } else if (ClientEnum.STUDENT.equals(imUserFriend.getFriendType())) {
+                Set<Long> set = studentFriendMap.getOrDefault(teacherFriend.getTeacherId(), new HashSet<>());
+                set.add(imUserFriend.getFriendId());
+                studentFriendMap.put(teacherFriend.getTeacherId(), set);
+            }
+            teacherFriend.setFriendNums(teacherFriend.getFriendNums() + 1);
+            Collections.sort(customerServiceFriendNums);
+        }
+
+        teacherFriendMap.forEach((teacherId, teacherIds) -> {
+            imUserFriendService.saveUserTeacherFriend(teacherId, teacherIds);
+            // 发送消息
+            TeacherWrapper.CustomerServiceSendMsg2User customerServiceSendMsg2User = new TeacherWrapper.CustomerServiceSendMsg2User();
+            customerServiceSendMsg2User.setCustomerId(teacherId);
+            customerServiceSendMsg2User.getTeacherIds().addAll(teacherIds);
+            result.add(customerServiceSendMsg2User);
+//            imUserFriendService.sendCustomerServiceAddFriendMessage(teacherId, customerTitle, customerMessage, new ArrayList<>(teacherIds), ClientEnum.TEACHER);
+        });
+        studentFriendMap.forEach((teacherId, studentIds) -> {
+            imUserFriendService.saveUserFriend(teacherId, studentIds);
+            TeacherWrapper.CustomerServiceSendMsg2User customerServiceSendMsg2User = new TeacherWrapper.CustomerServiceSendMsg2User();
+            customerServiceSendMsg2User.setCustomerId(teacherId);
+            customerServiceSendMsg2User.getTeacherIds().addAll(studentIds);
+            result.add(customerServiceSendMsg2User);
+//            imUserFriendService.sendCustomerServiceAddFriendMessage(teacherId, customerTitle, customerMessage, new ArrayList<>(studentIds), ClientEnum.STUDENT);
+        });
+        return result;
+    }
+
     /***
      * 封装用户信息
      * @author liweifan
@@ -700,6 +917,7 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
         teacher.setSettlementFrom(teacherSubmitReq.getSettlementFrom());
         teacher.setTenantId(teacherSubmitReq.getTenantId() == null ? -1L : teacherSubmitReq.getTenantId());
         teacher.setAvatar(Optional.ofNullable(teacherSubmitReq.getAvatar()).orElse(teacher.getAvatar()));
+        teacher.setCustomerService(teacherSubmitReq.getCustomerService());
         if (StringUtil.isEmpty(teacherSubmitReq.getTeacherType())) {
             return teacher;
         }
@@ -912,6 +1130,7 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
     public IPage<MyFens> queryMyFans(IPage<MyFens> page, Long teacherId) {
         List<MyFens> teacherVos = baseMapper.queryMyFans(page,
                 TeacherQueryInfo.FansQuery.builder().teacherId(teacherId).build());
+        setVip(teacherVos);
         return page.setRecords(teacherVos);
     }
 
@@ -926,6 +1145,7 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
     public IPage<MyFens> queryMyFans(IPage<MyFens> page, TeacherQueryInfo.FansQuery query) {
 
         List<MyFens> teacherVos = baseMapper.queryMyFans(page, query);
+        setVip(teacherVos);
         return page.setRecords(teacherVos);
     }
 
@@ -1033,7 +1253,6 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
 
             teacherInfo.setStudentNums(studentNumsMap.getOrDefault(teacherId, 0));
         }
-
         return teacherInfo;
     }
 
@@ -1117,7 +1336,10 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
                 });
             }
             // 删除好友关系
-            imUserFriendService.delStudentFriendByTenantId(teacher.getTenantId(), teacher.getUserId(), ClientEnum.TEACHER.getCode());
+            Boolean customerService = teacher.getCustomerService();
+            if (Boolean.FALSE.equals(customerService)) {
+                imUserFriendService.delStudentFriendByTenantId(teacher.getTenantId(), teacher.getUserId(), ClientEnum.TEACHER.getCode());
+            }
             addBindUnBindRecord(teacher.getUserId(), teacher.getTenantId(), false);
             SysUser sysUser = sysUserMapper.getByUserId(teacher.getUserId());
             sendBindUnBindSMS(teacher.getUserId(), sysUser.getPhone(), MessageTypeEnum.TEACHER_UNBIND_TENANT, teacher.getTenantId());
@@ -1250,4 +1472,62 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
         sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS, messageType,
                 receivers, null, 0, null, ClientEnum.SYSTEM.getCode(), tenantInfo.getName());
     }
+
+    private void setVip(List<MyFens> teacherVos) {
+        if (CollectionUtils.isEmpty(teacherVos)) {
+            return;
+        }
+        List<Long> studentIds = teacherVos.stream().map(n -> Long.valueOf(n.getUserId())).collect(Collectors.toList());
+        Map<Long, EUserVipType> vipMap = vipCardRecordService.queryUserVipInfo(studentIds, ClientEnum.STUDENT.getCode()).stream()
+                .collect(Collectors.toMap(VipCardRecordWrapper.UserVipInfo::getUserId, VipCardRecordWrapper.UserVipInfo::getCurrentVipType));
+
+        for (MyFens teacherVo : teacherVos) {
+            EUserVipType vipType = vipMap.getOrDefault(Long.valueOf(teacherVo.getUserId()), EUserVipType.NORMAL);
+            teacherVo.setIsVip(EUserVipType.NORMAL.equals(vipType) ? YesOrNoEnum.NO : YesOrNoEnum.YES);
+            teacherVo.setVipType(vipType);
+        }
+    }
+
+    /**
+     * 获取学生好友最少的一个客服
+     * @return 客服
+     */
+    private Teacher getCustomerServiceByFriendLeast() {
+        return this.getBaseMapper().getCustomerServiceByFriendLeast();
+    }
+
+    @Override
+    public List<Teacher> getCustomerService() {
+        return this.lambdaQuery()
+                .eq(Teacher::getCustomerService, true)
+                .eq(Teacher::getLockFlag, false)
+                .list();
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void updateLock(SysUser sysUser, Long teacherId) {
+        Teacher teacher = this.getById(teacherId);
+        if (teacher == null) {
+            throw new BizException("无效的老师账号");
+        }
+
+        // todo 暂时不上,逻辑调整
+        // 冻结客服,移交好友给其他客服
+//        Boolean customerService = teacher.getCustomerService();
+        Boolean customerService = null;
+        if (UserLockFlag.NORMAL.equals(teacher.getLockFlag()) && Boolean.TRUE.equals(customerService)) {
+            List<TeacherWrapper.CustomerServiceSendMsg2User> customerServiceSendMsg2User = transferFriend(teacherId, false);
+            String customerMessage = sysConfigService.findConfigValue(SysConfigConstant.CUSTOMER_SERVICE_ADD_MSG);
+            String customerTitle = sysConfigService.findConfigValue(SysConfigConstant.CUSTOMER_SERVICE_ADD_MSG_TITLE);
+            for (TeacherWrapper.CustomerServiceSendMsg2User serviceSendMsg2User : customerServiceSendMsg2User) {
+                imUserFriendService.sendCustomerServiceAddFriendMessage(serviceSendMsg2User.getCustomerId(), customerTitle, customerMessage, serviceSendMsg2User.getTeacherIds(),
+                        ClientEnum.TEACHER);
+                imUserFriendService.sendCustomerServiceAddFriendMessage(serviceSendMsg2User.getCustomerId(), customerTitle, customerMessage, serviceSendMsg2User.getStudentIds(),
+                        ClientEnum.STUDENT);
+            }
+        }
+        teacher.setLockFlag(UserLockFlag.NORMAL.equals(teacher.getLockFlag()) ? UserLockFlag.LOCKED : UserLockFlag.NORMAL);
+        this.updateById(teacher);
+    }
 }

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

@@ -296,11 +296,9 @@ public class TenantApplyRecordServiceImpl extends ServiceImpl<TenantApplyRecordM
         tenantApplyRecord.setVerifyUserId(verifyUserId);
         tenantApplyRecord.setReason(entry.getReason());
         tenantApplyRecord.setBriefIntroduction(applyRecord.getBriefIntroduction());
-
-        applyRecord.setStatus(Boolean.TRUE.equals(ifPass) ? AuthStatusEnum.PASS : AuthStatusEnum.UNPASS);
-        applyRecord.setVerifyUserId(verifyUserId);
-        applyRecord.setReason(entry.getReason());
         if (ifPass == true){
+            tenantApplyRecord.setStatus(AuthStatusEnum.PASS);
+
 
             //机构账户新增逻辑
             TenantInfo tenantInfo = new TenantInfo();
@@ -315,13 +313,19 @@ public class TenantApplyRecordServiceImpl extends ServiceImpl<TenantApplyRecordM
             tenantInfo.setBriefIntroduction(applyRecord.getBriefIntroduction());
             if (tenantInfoService.add(tenantInfo)) {
                 applyRecord.setUserId(tenantInfo.getUserId());
+                tenantApplyRecordMapper.updateById(applyRecord);
             }
+            //更改当前记录的审核状态
+            tenantApplyRecordMapper.updateStatusById(id);
+        } else {
+            tenantApplyRecord.setStatus(AuthStatusEnum.UNPASS);
+            tenantApplyRecordMapper.updateUnpassStatusById(id);
         }
-        tenantApplyRecordMapper.updateById(applyRecord);
-
 
+        String name = tenantEntryRecordMapper.selectName(verifyUserId);
+        tenantApplyRecord.setVerifyUserName(name);
 
-        TenantEntryRecord tenantEntryRecord = JSON.parseObject(JSON.toJSONString(applyRecord), TenantEntryRecord.class);
+        TenantEntryRecord tenantEntryRecord = JSON.parseObject(JSON.toJSONString(tenantApplyRecord), TenantEntryRecord.class);
          tenantEntryRecordMapper.insert(tenantEntryRecord);
 
 

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

@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.dayaedu.cbs.common.enums.EClientType;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dao.StudentDao;
 import com.yonge.cooleshow.biz.dal.dao.SubjectDao;
@@ -17,6 +18,7 @@ import com.yonge.cooleshow.biz.dal.entity.ImGroup;
 import com.yonge.cooleshow.biz.dal.entity.ImGroupMember;
 import com.yonge.cooleshow.biz.dal.entity.Student;
 import com.yonge.cooleshow.biz.dal.entity.Subject;
+import com.yonge.cooleshow.biz.dal.entity.SysConfig;
 import com.yonge.cooleshow.biz.dal.entity.Teacher;
 import com.yonge.cooleshow.biz.dal.entity.TenantGroup;
 import com.yonge.cooleshow.biz.dal.entity.TenantGroupAlbum;
@@ -28,6 +30,7 @@ import com.yonge.cooleshow.biz.dal.mapper.TenantGroupAlbumMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantGroupMapper;
 import com.yonge.cooleshow.biz.dal.service.ImGroupMemberService;
 import com.yonge.cooleshow.biz.dal.service.ImGroupService;
+import com.yonge.cooleshow.biz.dal.service.SysConfigService;
 import com.yonge.cooleshow.biz.dal.service.SysUserService;
 import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
 import com.yonge.cooleshow.biz.dal.service.im.ImGroupCoreService;
@@ -36,6 +39,7 @@ import com.yonge.cooleshow.biz.dal.wrapper.StudentWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupAlbumWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.im.ImGroupWrapper;
+import com.yonge.cooleshow.common.constant.SysConfigConstant;
 import com.yonge.toolset.base.exception.BizException;
 import com.yonge.toolset.mybatis.support.PageUtil;
 import lombok.extern.slf4j.Slf4j;
@@ -71,6 +75,8 @@ public class TenantGroupServiceImpl extends ServiceImpl<TenantGroupMapper, Tenan
     private SysUserService sysUserService;
     @Autowired
     private TenantGroupAlbumMapper tenantGroupAlbumMapper;
+    @Autowired
+    private SysConfigService sysConfigService;
 
     /**
      * 查询详情
@@ -162,6 +168,12 @@ public class TenantGroupServiceImpl extends ServiceImpl<TenantGroupMapper, Tenan
 
         this.save(entity);
         if (adminId != null && Boolean.TRUE.equals(imGroupCreate)) {
+            // 群成员数量限制校验
+            SysConfig config = sysConfigService.findByParamName(SysConfigConstant.GROUP_MEMBER_LIMIT);
+            if (config != null && Integer.parseInt(config.getParamValue()) < (userIds.size() + 1)) {
+                throw new BizException("群成员人数上限为:" + config.getParamValue() + "人");
+            }
+
             // 建群
             try {
                 ImGroupWrapper.ImGroup imGroup = new ImGroupWrapper.ImGroup();
@@ -231,6 +243,11 @@ public class TenantGroupServiceImpl extends ServiceImpl<TenantGroupMapper, Tenan
             ImGroup imGroup = imGroupService.getById(oldImGroupId);
             // 群被删除过,并且需要重新建群
             if (imGroup == null) {
+                SysConfig config = sysConfigService.findByParamName(SysConfigConstant.GROUP_MEMBER_LIMIT);
+                if (config != null && Integer.parseInt(config.getParamValue()) < (tenantGroup.getUserIds().size() + 1)) {
+                    throw new BizException("群成员人数上限为:" + config.getParamValue() + "人");
+                }
+
                 String imGroupId = createImGroup(entity.getAdminId(), tenantGroup.getName());
                 entity.setImGroupId(imGroupId);
 
@@ -431,8 +448,8 @@ public class TenantGroupServiceImpl extends ServiceImpl<TenantGroupMapper, Tenan
                     }
 
                     try {
-                        imGroupCoreService.changeGroupOwner(imGroupId, String.valueOf(toTeacher),
-                                String.valueOf(teacherId));
+                        imGroupCoreService.changeGroupOwner(imGroupId, imGroupCoreService.getImUserId(toTeacher, ClientEnum.TEACHER),
+                                imGroupCoreService.getImUserId(teacherId, ClientEnum.TEACHER));
                         imGroupCoreService.groupQuit(teacherId, ClientEnum.TEACHER.getCode(),
                                 imGroupId, true);
                         imGroupService.lambdaUpdate()
@@ -537,8 +554,8 @@ public class TenantGroupServiceImpl extends ServiceImpl<TenantGroupMapper, Tenan
 
         try {
             imGroupCoreService.changeGroupOwner(imGroupId,
-                    String.valueOf(newGroup.getAdminId()),
-                    String.valueOf(admin.getUserId()));
+                    imGroupCoreService.getImUserId(newGroup.getAdminId(), ClientEnum.TEACHER),
+                    imGroupCoreService.getImUserId(admin.getUserId(), ClientEnum.TEACHER));
             imGroupCoreService.groupQuit(admin.getUserId(), ClientEnum.TEACHER.getCode(), imGroupId, true);
             imGroupService.lambdaUpdate()
                     .set(ImGroup::getCreateBy, newGroup.getAdminId())

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

@@ -103,6 +103,7 @@ public class UserAccountRecordServiceImpl extends ServiceImpl<UserAccountRecordD
         paramNames.add(AccountBizTypeEnum.ALBUM.getCode());
         paramNames.add(AccountBizTypeEnum.ALBUM_SHARE.getCode());
         paramNames.add(AccountBizTypeEnum.VIP.getCode());
+        paramNames.add(AccountBizTypeEnum.SVIP.getCode());
         paramNames.add(AccountBizTypeEnum.VIP_SHARE.getCode());
         List<UserAccountRecord> accountRecords = baseMapper.queryCanAccountByBizType(paramNames);
         for (UserAccountRecord accountRecord : accountRecords) {
@@ -158,6 +159,10 @@ public class UserAccountRecordServiceImpl extends ServiceImpl<UserAccountRecordD
             bizIds.add(userOrderDetailVo.getBizId());
             records.addAll(baseMapper.selectRecordByOrderDetail(userOrderDetailVo.getOrderNo(),AccountBizTypeEnum.VIP, bizIds));
             records.addAll(baseMapper.selectRecordByOrderDetail(userOrderDetailVo.getOrderNo(),AccountBizTypeEnum.VIP_SHARE, bizIds));
+        }else if (GoodTypeEnum.SVIP.equals(userOrderDetailVo.getGoodType())){
+            bizIds.add(userOrderDetailVo.getBizId());
+            records.addAll(baseMapper.selectRecordByOrderDetail(userOrderDetailVo.getOrderNo(),AccountBizTypeEnum.SVIP, bizIds));
+            records.addAll(baseMapper.selectRecordByOrderDetail(userOrderDetailVo.getOrderNo(),AccountBizTypeEnum.VIP_SHARE, bizIds));
         }else if(GoodTypeEnum.VIDEO.equals(userOrderDetailVo.getGoodType())){
             bizIds.add(userOrderDetailVo.getBizId());
             records.addAll(baseMapper.selectRecordByOrderDetail(userOrderDetailVo.getOrderNo(),AccountBizTypeEnum.VIDEO, bizIds));

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

@@ -11,14 +11,19 @@ import com.yonge.cooleshow.biz.dal.entity.Student;
 import com.yonge.cooleshow.biz.dal.entity.StudentAttendance;
 import com.yonge.cooleshow.biz.dal.entity.Subject;
 import com.yonge.cooleshow.biz.dal.entity.UserBindingTeacher;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.CourseScheduleEnum;
+import com.yonge.cooleshow.biz.dal.enums.EUserVipType;
 import com.yonge.cooleshow.biz.dal.enums.StudentCourseEnum;
 import com.yonge.cooleshow.biz.dal.queryInfo.TeacherBindingUserQueryInfo;
 import com.yonge.cooleshow.biz.dal.service.StudentAttendanceService;
 import com.yonge.cooleshow.biz.dal.service.SysConfigService;
 import com.yonge.cooleshow.biz.dal.service.UserBindingTeacherService;
+import com.yonge.cooleshow.biz.dal.service.VipCardRecordService;
 import com.yonge.cooleshow.biz.dal.vo.userBindingTeacher.UserBindingCourseWrapper;
 import com.yonge.cooleshow.biz.dal.vo.userBindingTeacher.UserBindingTeacherWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.StudentWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.common.constant.SysConfigConstant;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import com.yonge.toolset.base.exception.BizException;
@@ -34,7 +39,6 @@ import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -64,6 +68,9 @@ public class UserBindingTeacherServiceImpl extends ServiceImpl<UserBindingTeache
     @Autowired
     private StudentAttendanceService studentAttendanceService;
 
+    @Autowired
+    private VipCardRecordService vipCardRecordService;
+
     @Override
     public void unbindTask() {
         String days = sysConfigService.findConfigValue(SysConfigConstant.PIANO_ROOM_UNBIND_DAYS);
@@ -105,10 +112,14 @@ public class UserBindingTeacherServiceImpl extends ServiceImpl<UserBindingTeache
         // vip
         List<Student> students = studentDao.selectBatchIds(studentIdList);
 
-        Map<Long, YesOrNoEnum> userIdVipMap = students.stream()
-                                                      .collect(Collectors.toMap(Student::getUserId,
-                                           student -> student.getMembershipEndTime() != null && student.getMembershipEndTime()
-                                           .compareTo(new Date()) > 0?YesOrNoEnum.YES:YesOrNoEnum.NO, (o, n) -> n));
+        List<VipCardRecordWrapper.UserVipInfo> studentVipInfoList = vipCardRecordService.queryUserVipInfo(studentIdList, ClientEnum.STUDENT.getCode());
+        Map<Long, EUserVipType> vipMap = studentVipInfoList.stream().collect(Collectors.toMap(VipCardRecordWrapper.UserVipInfo::getUserId,
+                VipCardRecordWrapper.UserVipInfo::getCurrentVipType));
+
+//        Map<Long, YesOrNoEnum> userIdVipMap = students.stream()
+//                                                      .collect(Collectors.toMap(Student::getUserId,
+//                                           student -> student.getMembershipEndTime() != null && student.getMembershipEndTime()
+//                                           .compareTo(new Date()) > 0?YesOrNoEnum.YES:YesOrNoEnum.NO, (o, n) -> n));
 
         // 声部
         List<Long> subjectIdList = new ArrayList<>();
@@ -134,7 +145,9 @@ public class UserBindingTeacherServiceImpl extends ServiceImpl<UserBindingTeache
                                                                                             UserBindingTeacherWrapper.CourseNum::getStudentId));
 
         for (UserBindingTeacherWrapper record : records) {
-            record.setIsVip(userIdVipMap.get(record.getUserId()));
+            EUserVipType vipType = vipMap.getOrDefault(record.getUserId(), EUserVipType.NORMAL);
+            record.setIsVip(EUserVipType.NORMAL.equals(vipType)?YesOrNoEnum.NO:YesOrNoEnum.YES);
+            record.setVipType(vipType);
             record.setSubjectName(userIdSubjectMap.getOrDefault(record.getUserId(), ""));
 
             List<UserBindingTeacherWrapper.CourseNum> courseNums = userIdCourseStatusMap.get(record.getUserId());

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

@@ -8,6 +8,7 @@ import com.microsvc.toolkit.common.webportal.exception.BizException;
 import com.microsvc.toolkit.config.jwt.utils.JwtUserInfo;
 import com.yonge.cooleshow.biz.dal.entity.*;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.EVipType;
 import com.yonge.cooleshow.biz.dal.mapper.UserMusicMapper;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.wrapper.UserMusicStarWrapper;
@@ -69,6 +70,9 @@ public class UserMusicServiceImpl extends ServiceImpl<UserMusicMapper, UserMusic
     @Autowired
     private UserMusicMapper userMusicMapper;
 
+    @Autowired
+    private VipCardRecordService vipCardRecordService;
+
 
     /**
      * 查询详情
@@ -277,11 +281,16 @@ public class UserMusicServiceImpl extends ServiceImpl<UserMusicMapper, UserMusic
         List<Long> studentIds = records.stream().filter(o -> o.getClientType() == ClientEnum.STUDENT).map(UserMusicWrapper.UserMusic::getUserId).collect(Collectors.toList());
 
         Map<Long, Student> studentMap = studentService.getMapByIds(studentIds);
+        // 学生vip状态
+        Map<Long, EVipType> studentVipTypeMap = vipCardRecordService.getVipTypeMapByUserIds(studentIds, ClientEnum.STUDENT);
 
 
         // 老师ID集合
         List<Long> teacherIds = records.stream().filter(o -> o.getClientType() == ClientEnum.TEACHER).map(UserMusicWrapper.UserMusic::getUserId).collect(Collectors.toList());
 
+        // 老师vip状态
+        Map<Long, EVipType> teacherVipTypeMap = vipCardRecordService.getVipTypeMapByUserIds(teacherIds, ClientEnum.TEACHER);
+
         Map<Long, Teacher> teacherMap = teacherService.getMapByIds(teacherIds);
         studentIds.addAll(teacherIds);
         Map<Long, com.yonge.cooleshow.biz.dal.entity.SysUser> userMap = sysUserService.getMapByIds(studentIds);
@@ -301,7 +310,7 @@ public class UserMusicServiceImpl extends ServiceImpl<UserMusicMapper, UserMusic
                 if (student != null) {
 
                     record.setSubjectId(student.getSubjectId());
-                    record.setVipFlag(student.getMembershipEndTime() != null && student.getMembershipEndTime().after(new Date()));
+                    record.setVipType(studentVipTypeMap.getOrDefault(student.getUserId(),EVipType.NOT_VIP));
                 }
                 if (StringUtil.isEmpty(record.getAvatar())) {
                     record.setAvatar(studentAvatar);
@@ -310,7 +319,7 @@ public class UserMusicServiceImpl extends ServiceImpl<UserMusicMapper, UserMusic
                 Teacher teacher = teacherMap.get(record.getUserId());
                 if (teacher != null) {
                     record.setSubjectId(teacher.getSubjectId());
-                    record.setVipFlag(teacher.getMembershipEndTime() != null && teacher.getMembershipEndTime().after(new Date()));
+                    record.setVipType(teacherVipTypeMap.getOrDefault(teacher.getUserId(),EVipType.NOT_VIP));
                 }
                 if (StringUtil.isEmpty(record.getAvatar())) {
                     record.setAvatar(teacherAvatar);

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

@@ -27,6 +27,7 @@ import com.yonge.cooleshow.biz.dal.vo.res.OrderPayRes;
 import com.yonge.cooleshow.biz.dal.wrapper.PaymentDivMemberRecordWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.UserPaymentOrderWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.coupon.CouponOrderWrapper;
 import com.yonge.cooleshow.common.constant.SysConfigConstant;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
@@ -157,6 +158,10 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
     @Autowired
     private TenantAlbumPurchaseService tenantAlbumPurchaseService;
 
+    @Autowired
+    private VipCardRecordService vipCardRecordService;
+
+
     //验证订单是否可以下单,获取订单金额信息
     private static final Map<GoodTypeEnum, Function<OrderReq.OrderReqInfo, HttpResponseResult<OrderCreateRes>>> orderCreate = new HashMap<>();
     //插入订单后执行
@@ -171,6 +176,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
         /**********订单生成前******************/
         //vip开通缴费
         orderCreate.put(GoodTypeEnum.VIP, memberPriceSettingsService::orderCreate);
+        orderCreate.put(GoodTypeEnum.SVIP, memberPriceSettingsService::orderCreate);
         //直播课程购买
         orderCreate.put(GoodTypeEnum.LIVE, courseGroupService::buyLiveCourse);
         //陪练课购买
@@ -195,6 +201,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
         /**********订单完成后******************/
         //vip开通缴费
         orderSuccess.put(GoodTypeEnum.VIP, memberPriceSettingsService::orderSuccess);
+        orderSuccess.put(GoodTypeEnum.SVIP, memberPriceSettingsService::orderSuccess);
         //直播课程购买
         orderSuccess.put(GoodTypeEnum.LIVE, courseGroupService::buyLiveCourseSuccess);
         //陪练课购买
@@ -264,6 +271,11 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
     @Override
     public UserOrderVo detailApp(UserOrder param) {
         UserOrderVo userOrderVo = baseMapper.detailApp(param);
+        userOrderDetail(userOrderVo);
+        return userOrderVo;
+    }
+
+    private void userOrderDetail( UserOrderVo userOrderVo) {
         if (null != userOrderVo) {
             userOrderVo.setFeeAmt(null);
             userOrderVo.setPlantformFee(null);
@@ -278,7 +290,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
             CouponOrderWrapper couponOrderWrapper  = couponInfoService.queryUserOrderCouponInfo(userOrderVo.getUserId(),
                     CouponInfoQuery.CouponOrderQuery.builder()
                             .clientType(userOrderVo.getOrderClient())
-                            .orderNo(param.getOrderNo())
+                            .orderNo(userOrderVo.getOrderNo())
                             .amount(userOrderVo.getExpectPrice().doubleValue())
                             .build());
             userOrderVo.setDiscountPrice(BigDecimal.valueOf(couponOrderWrapper.getDiscountedPrices()));
@@ -290,12 +302,14 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
                 if (o.getGoodType().equals(GoodTypeEnum.TENANT_ALBUM) && userOrderVo.getOrderClient().equals(ClientEnum.TENANT)) {
                     TenantAlbumPurchase albumPurchase = tenantAlbumPurchaseService.getByOrderNo(userOrderVo.getOrderNo());
                     o.getBizInfo().setRecordId(albumPurchase.getId());
+                } else if (o.getGoodType().equals(GoodTypeEnum.SVIP)) {
+                    VipCardRecordWrapper.UserVip userVip = vipCardRecordService.userVipInfo(o.getUserId(), o.getOrderClient());
+                    o.setVipEndDays(userVip.getVipEndDays());
                 }
             });
 
             userOrderVo.setOrderDetailList(userOrderDetailVos);
         }
-        return userOrderVo;
     }
 
     @Override
@@ -535,6 +549,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
                     break;
                 }
                 case VIP:
+                case SVIP:
                 {
 
                     for (UserOrderDetailVo userOrderDetailVo : list) {
@@ -589,6 +604,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
             info.setRecomUserId(orderReq.getRecomUserId());
             info.setActivityId(orderReq.getActivityId());
             info.setActualPrice(orderReq.getActualPrice());
+            info.setOrderClient(orderReq.getOrderClient());
             HttpResponseResult<OrderCreateRes> createResult = createFunction.apply(info);
             OrderCreateRes createRes = createResult.getData();
             if (!createResult.getStatus() || null == createRes || !createRes.getRes()) {
@@ -696,9 +712,15 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
 
     @Override
     public HttpResponseResult<UserOrderVo> getPendingOrder(OrderSearch query) {
+        if (query.getGoodType().equals(GoodTypeEnum.VIP.name()) || query.getGoodType().equals(GoodTypeEnum.SVIP.name())) {
+            query.setGoodType(Lists.newArrayList(GoodTypeEnum.VIP, GoodTypeEnum.SVIP).stream().map(GoodTypeEnum::name).collect(Collectors.joining(",")));
+        }
         UserOrderVo userOrderVo = baseMapper.getPendingOrder(query);
+
+
+        // SVIP和VIP同时只能存在一个待支付订单
         if (null != userOrderVo) {
-            userOrderVo.setOrderDetailList(orderDetailService.getOrderDetilListByOrderNo(userOrderVo.getOrderNo()));
+            userOrderDetail(userOrderVo);
 
 
             // 查询用户下单配置
@@ -922,6 +944,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
 
             UserOrderDetailVo orderDetail = new UserOrderDetailVo();
             orderDetail.setOrderNo(data.getOrderNo());
+            orderDetail.setBizJson(res.getBizJson());
             orderDetail.setOrderType(orderReq.getOrderType());
             orderDetail.setSubOrderNo(data.getSubOrderNo());
             orderDetail.setMerchId(res.getMerchId());
@@ -1036,6 +1059,8 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
             configValue = sysConfigService.findConfigValue(SysConfigConstant.GOOD_LOGO_ACTI_REGIST);
         } else if (GoodTypeEnum.ALBUM.equals(goodTypeEnum)) {
             configValue = sysConfigService.findConfigValue(SysConfigConstant.GOOD_LOGO_ALBUM);
+        } else if (GoodTypeEnum.SVIP.equals(goodTypeEnum)) {
+            configValue = sysConfigService.findConfigValue(SysConfigConstant.GOOD_LOGO_SVIP);
         }
         return configValue;
     }
@@ -1278,7 +1303,12 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
                 //入老师账户
                 BigDecimal shareFee = platformFee.multiply(shareFeeRate).setScale(2, RoundingMode.HALF_UP);
                 if (shareFee.compareTo(BigDecimal.ZERO) > 0) {
-                    AccountBizTypeEnum bizTypeEnum = AccountBizTypeEnum.valueOf(orderDetailVo.getGoodType().getCode() + "_SHARE");
+                    AccountBizTypeEnum bizTypeEnum;
+                    if (orderDetailVo.getGoodType() == GoodTypeEnum.SVIP || orderDetailVo.getGoodType() == GoodTypeEnum.VIP) {
+                        bizTypeEnum= AccountBizTypeEnum.VIP_SHARE;
+                    } else {
+                        bizTypeEnum = AccountBizTypeEnum.valueOf(orderDetailVo.getGoodType().getCode() + "_SHARE");
+                    }
                     if (null != bizTypeEnum) {
                         //插入分润老师账户变更记录-分润老师预收
                         HttpResponseResult<UserAccountRecord> recomRecordRes = userAccountService.accountRecord(
@@ -1308,7 +1338,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
         Calendar instance = Calendar.getInstance();
         GoodTypeEnum goodType = orderDetailVo.getGoodType();
 
-        if (GoodTypeEnum.VIP.equals(goodType)) {
+        if (GoodTypeEnum.VIP.equals(goodType) || GoodTypeEnum.SVIP.equals(goodType)) {
             instance.add(Calendar.DAY_OF_MONTH, Integer.parseInt(sysConfigService.findConfigValue(SysConfigConstant.VIP_ACCOUNT_PERIOD)));
         } else if (GoodTypeEnum.PRACTICE.equals(goodType)) {
             instance.add(Calendar.DAY_OF_MONTH, Integer.parseInt(sysConfigService.findConfigValue(SysConfigConstant.PRACTICE_ACCOUNT_PERIOD)));
@@ -1337,7 +1367,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
      */
     @Override
     public BigDecimal getShareFreeByGoodType(GoodTypeEnum goodType, Long bizId) {
-        if (GoodTypeEnum.VIP.equals(goodType)) {
+        if (GoodTypeEnum.VIP.equals(goodType) ||GoodTypeEnum.SVIP.equals(goodType)) {
             return getShareFreeByConfigName(SysConfigConstant.VIP_SHARE_FEE);
         }
         if (GoodTypeEnum.LIVE.equals(goodType)) {
@@ -1391,7 +1421,7 @@ public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> i
      */
     private BigDecimal getPlatformFreeByGoodType(GoodTypeEnum goodType) {
         //会员|琴房时长,平台全额收益
-        if (GoodTypeEnum.VIP.equals(goodType) || GoodTypeEnum.PIANO_ROOM.equals(goodType)
+        if (GoodTypeEnum.VIP.equals(goodType)|| GoodTypeEnum.SVIP.equals(goodType) || GoodTypeEnum.PIANO_ROOM.equals(goodType)
                 || GoodTypeEnum.ACTI_REGIST.equals(goodType)) {
             return BigDecimal.ONE;
         }

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

@@ -161,6 +161,7 @@ public class UserPaymentCoreServiceImpl implements UserPaymentCoreService {
         /**********订单生成前 商品校验******************/
         //vip开通缴费
         orderGoodsCreate.put(GoodTypeEnum.VIP, memberPriceSettingsService::orderCreate);
+        orderGoodsCreate.put(GoodTypeEnum.SVIP, memberPriceSettingsService::orderCreate);
         //直播课程购买
         orderGoodsCreate.put(GoodTypeEnum.LIVE, courseGroupService::buyLiveCourse);
         //陪练课购买
@@ -198,6 +199,7 @@ public class UserPaymentCoreServiceImpl implements UserPaymentCoreService {
         paymentSuccess.put(GoodTypeEnum.VIDEO, paymentDivMemberRecordService::videoCourse);
         paymentSuccess.put(GoodTypeEnum.ALBUM, paymentDivMemberRecordService::musicSheet);
         paymentSuccess.put(GoodTypeEnum.VIP, paymentDivMemberRecordService::vip);
+        paymentSuccess.put(GoodTypeEnum.SVIP, paymentDivMemberRecordService::vip);
         paymentSuccess.put(GoodTypeEnum.ACTI_REGIST, paymentDivMemberRecordService::activity);
 
         /**********订单取消后******************/
@@ -546,6 +548,10 @@ public class UserPaymentCoreServiceImpl implements UserPaymentCoreService {
                 orderGoodsCreate.get(item.getGoodType()).accept(item);
                 UserOrderDetail userOrderDetail = item.getUserOrderDetail();
                 orderDetails.add(userOrderDetail);
+                couponAmount = userOrderDetail.getCouponAmount();
+                if (couponAmount == null) {
+                    couponAmount = BigDecimal.ZERO;
+                }
                 // 根据优惠券计算实际优惠金额
                 // 计算优惠券金额
                 {

+ 43 - 43
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserTenantAlbumRecordServiceImpl.java

@@ -169,49 +169,49 @@ public class UserTenantAlbumRecordServiceImpl extends ServiceImpl<UserTenantAlbu
                     vo.setTenantImg(tenantInfo.getLogo());
                 }
                 //查询机构专辑曲目表
-                List<TenantAlbumMusic> tenantAlbumMusics = tenantAlbumMusicService.lambdaQuery()
-                        .eq(TenantAlbumMusic::getTenantAlbumId, i.getId())
-                        .eq(TenantAlbumMusic::getDelFlag, false)
-                        .list();
-
-                Map<SubjectTypeEnum, List<TenantAlbumMusic>> groupByType =
-                        tenantAlbumMusics.stream().collect(Collectors.groupingBy(TenantAlbumMusic::getSubjectType));
-
-                List<Long> musicSheetIdlist = tenantAlbumMusics.stream().map(next -> next.getMusicSheetId()).distinct().collect(Collectors.toList());
-
-                StudentMusicSheetSearch search = new StudentMusicSheetSearch();
-                search.setMusicSheetIdlist(musicSheetIdlist);
-                search.setPage(1);
-                search.setRows(9999);
-
-                IPage<MusicSheetVo> records = musicSheetService.selectStudentPage(PageUtil.getPage(search), search, ClientEnum.TENANT_STUDENT);
-
-                Map<Long, MusicSheetVo> idMsMap = records.getRecords().stream()
-                        .collect(Collectors.toMap(MusicSheet::getId, Function.identity()));
-
-                List<TenantAlbumWrapper.MusicSheetData> musicSheetData = vo.getMusicSheetData();
-
-                groupByType.forEach((key, value) -> {
-                    value.sort(Comparator.comparing(TenantAlbumMusic::getSortNumber));
-                    TenantAlbumWrapper.MusicSheetData sheetData = new TenantAlbumWrapper.MusicSheetData();
-                    sheetData.setSubjectType(key);
-                    List<TenantAlbumWrapper.TenantAlbumSheet> tenantAlbumSheets = value.stream().map(next -> {
-
-                        TenantAlbumWrapper.TenantAlbumSheet tenantAlbumSheet = new TenantAlbumWrapper.TenantAlbumSheet();
-                        BeanUtils.copyProperties(next, tenantAlbumSheet);
-                        Long musicSheetId = tenantAlbumSheet.getMusicSheetId();
-                        MusicSheetVo musicSheet = idMsMap.getOrDefault(musicSheetId, new MusicSheetVo());
-                        tenantAlbumSheet.setMusicSheetName(musicSheet.getMusicSheetName());
-                        tenantAlbumSheet.setMusicTag(musicSheet.getMusicTag());
-                        tenantAlbumSheet.setComposer(musicSheet.getComposer());
-                        return tenantAlbumSheet;
-                    }).collect(Collectors.toList());
-
-
-                    sheetData.setTenantAlbumSheetList(tenantAlbumSheets);
-                    musicSheetData.add(sheetData);
-                    vo.setMusicSheetData(musicSheetData);
-                });
+//                List<TenantAlbumMusic> tenantAlbumMusics = tenantAlbumMusicService.lambdaQuery()
+//                        .eq(TenantAlbumMusic::getTenantAlbumId, i.getId())
+//                        .eq(TenantAlbumMusic::getDelFlag, false)
+//                        .list();
+//
+//                Map<SubjectTypeEnum, List<TenantAlbumMusic>> groupByType =
+//                        tenantAlbumMusics.stream().collect(Collectors.groupingBy(TenantAlbumMusic::getSubjectType));
+//
+//                List<Long> musicSheetIdlist = tenantAlbumMusics.stream().map(next -> next.getMusicSheetId()).distinct().collect(Collectors.toList());
+
+//                StudentMusicSheetSearch search = new StudentMusicSheetSearch();
+//                search.setMusicSheetIdlist(musicSheetIdlist);
+//                search.setPage(1);
+//                search.setRows(9999);
+//
+//                IPage<MusicSheetVo> records = musicSheetService.selectStudentPage(PageUtil.getPage(search), search, ClientEnum.TENANT_STUDENT);
+//
+//                Map<Long, MusicSheetVo> idMsMap = records.getRecords().stream()
+//                        .collect(Collectors.toMap(MusicSheet::getId, Function.identity()));
+//
+//                List<TenantAlbumWrapper.MusicSheetData> musicSheetData = vo.getMusicSheetData();
+//
+//                groupByType.forEach((key, value) -> {
+//                    value.sort(Comparator.comparing(TenantAlbumMusic::getSortNumber));
+//                    TenantAlbumWrapper.MusicSheetData sheetData = new TenantAlbumWrapper.MusicSheetData();
+//                    sheetData.setSubjectType(key);
+//                    List<TenantAlbumWrapper.TenantAlbumSheet> tenantAlbumSheets = value.stream().map(next -> {
+//
+//                        TenantAlbumWrapper.TenantAlbumSheet tenantAlbumSheet = new TenantAlbumWrapper.TenantAlbumSheet();
+//                        BeanUtils.copyProperties(next, tenantAlbumSheet);
+//                        Long musicSheetId = tenantAlbumSheet.getMusicSheetId();
+//                        MusicSheetVo musicSheet = idMsMap.getOrDefault(musicSheetId, new MusicSheetVo());
+//                        tenantAlbumSheet.setMusicSheetName(musicSheet.getMusicSheetName());
+//                        tenantAlbumSheet.setMusicTag(musicSheet.getMusicTag());
+//                        tenantAlbumSheet.setComposer(musicSheet.getComposer());
+//                        return tenantAlbumSheet;
+//                    }).collect(Collectors.toList());
+//
+//
+//                    sheetData.setTenantAlbumSheetList(tenantAlbumSheets);
+//                    musicSheetData.add(sheetData);
+//                    vo.setMusicSheetData(musicSheetData);
+//                });
                 list.add(vo);
             });
         }

+ 750 - 67
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/VipCardRecordServiceImpl.java

@@ -1,21 +1,26 @@
 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.CollectionUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.beust.jcommander.internal.Lists;
+import com.microsvc.toolkit.common.webportal.exception.BizException;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dao.MemberPriceSettingsDao;
 import com.yonge.cooleshow.biz.dal.dto.search.VipRecordSearch;
 import com.yonge.cooleshow.biz.dal.entity.ActivityReward;
 import com.yonge.cooleshow.biz.dal.entity.MemberPriceSettings;
 import com.yonge.cooleshow.biz.dal.entity.Student;
-import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
-import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
-import com.yonge.cooleshow.biz.dal.enums.PeriodEnum;
-import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
+import com.yonge.cooleshow.biz.dal.enums.*;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.vo.*;
+import com.yonge.cooleshow.biz.dal.wrapper.VipCardRecordWrapper;
 import com.yonge.toolset.base.page.PageInfo;
 import com.yonge.toolset.mybatis.support.PageUtil;
 import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
+import com.yonge.toolset.utils.date.DateUtil;
+import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
@@ -24,9 +29,13 @@ import org.springframework.stereotype.Service;
 import com.yonge.cooleshow.biz.dal.entity.VipCardRecord;
 import com.yonge.cooleshow.biz.dal.dto.search.VipCardRecordSearch;
 import com.yonge.cooleshow.biz.dal.dao.VipCardRecordDao;
+import org.springframework.transaction.annotation.Transactional;
 
+import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
 
 
 @Service
@@ -49,6 +58,10 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
     @Autowired
     private UserOrderDetailService orderDetailService;
 
+    @Autowired
+    private SysUserService sysUserService;
+
+
     @Override
     public VipCardRecordVo detail(Long orderDetilId) {
         return baseMapper.detail(orderDetilId, null);
@@ -84,24 +97,24 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
             return null;
         }
         // 按时间区分 个数
-        Integer timeNum = 0;
+        Integer timeNum = orderDetailVo.getGoodNum();
         String periodType  = null;
 
         if (PeriodEnum.DAY.equals(detail.getPeriod())) {
-            timeNum = 1;
             periodType = PeriodEnum.DAY.getCode();
         } else if (PeriodEnum.MONTH.equals(detail.getPeriod())) {
-            timeNum = 1;
             periodType = PeriodEnum.MONTH.getCode();
         } else if (PeriodEnum.QUARTERLY.equals(detail.getPeriod())) {
-            timeNum = 3;
+            timeNum = timeNum*3;
             periodType = PeriodEnum.MONTH.getCode();
         } else if (PeriodEnum.YEAR_HALF.equals(detail.getPeriod())) {
-            timeNum = 6;
+            timeNum = timeNum*6;
             periodType = PeriodEnum.MONTH.getCode();
         } else if (PeriodEnum.YEAR.equals(detail.getPeriod())) {
-            timeNum = 1;
             periodType = PeriodEnum.YEAR.getCode();
+        } else {
+            periodType = PeriodEnum.PERPETUAL.getCode();
+
         }
 
         return getVipCardRecord(orderDetailVo.getUserId(),orderDetailVo.getOrderClient(),orderDetailVo.getOrderNo(),
@@ -118,23 +131,6 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
     @Override
     public VipCardRecord getVipCardRecord(Long userId, ClientEnum client, String orderNo, String subOrderNo, String periodType,
                                           Long memberPriceSettingsId, Integer timeNum, SourceTypeEnum sourceType, Long createBy, String reason) {
-        //修改用户会员时长
-        Date membershipEndTime = null;
-        if (client.equals(ClientEnum.STUDENT)) {
-            StudentVo studentVo = studentService.detail(userId);
-            if (null == studentVo) {
-                return null;
-            }
-            membershipEndTime = studentVo.getMembershipEndTime();
-        } else if (client.equals(ClientEnum.TEACHER)){
-            TeacherVo teacherVo = teacherService.detail(userId);
-            if (null == teacherVo) {
-                return null;
-            }
-            membershipEndTime = teacherVo.getMembershipEndTime();
-        } else {
-            return null;
-        }
 
         VipCardRecord vipCardRecord = new VipCardRecord();
         vipCardRecord.setUserId(userId);
@@ -149,11 +145,32 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
         vipCardRecord.setCreateBy(createBy);
         vipCardRecord.setReason(reason);
 
-        if (null == membershipEndTime || membershipEndTime.before(new Date())) {
-            //没有会员、会员已过期 会员卡生效时间为当前时间
+        MemberPriceSettings memberPriceSettings = memberPriceSettingsDao.selectById(memberPriceSettingsId);
+        if (memberPriceSettings == null) {
+            return null;
+        }
+
+        VipCardRecordWrapper.UserVip userVip = userVipInfo(userId, client);
+        boolean flag= false;
+
+        if (userVip.getVipType() == EVipType.NOT_VIP) {
             vipCardRecord.setStartTime(new Date());
-        } else {
-            vipCardRecord.setStartTime(membershipEndTime);
+        } else if (userVip.getVipType() == EVipType.VIP && memberPriceSettings.getVipType() ==EVipType.VIP){
+            vipCardRecord.setStartTime(userVip.getVipEndDate());
+            flag= true;
+        } else if  (userVip.getVipType() == EVipType.VIP && memberPriceSettings.getVipType() ==EVipType.SVIP){
+            vipCardRecord.setStartTime(new Date());
+        }else if  (userVip.getVipType() == EVipType.SVIP && memberPriceSettings.getVipType() ==EVipType.VIP){
+            if (userVip.getVipEndDate() !=null) {
+                flag= true;
+                vipCardRecord.setStartTime(userVip.getVipEndDate());
+            } else {
+                flag= true;
+                vipCardRecord.setStartTime(userVip.getSvipEndDate());
+            }
+        }else if  (userVip.getVipType() == EVipType.SVIP && memberPriceSettings.getVipType() ==EVipType.SVIP){
+            flag= true;
+            vipCardRecord.setStartTime(userVip.getSvipEndDate());
         }
         Calendar cal = Calendar.getInstance();
         cal.setTime(vipCardRecord.getStartTime());
@@ -165,7 +182,18 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
         } else if (PeriodEnum.YEAR.getCode().equals(periodType)) {
             cal.add(Calendar.YEAR, timeNum);
         }
+
         vipCardRecord.setEndTime(cal.getTime());
+        if (flag) {
+            DateTime dateTime = DateTime.parse(DateUtil.format(vipCardRecord.getStartTime(), "yyyy-MM-dd"))
+                .plusDays(1)
+                .withHourOfDay(0)
+                .withMinuteOfHour(0)
+                .withSecondOfMinute(0)
+                .withMillisOfSecond(0);
+            vipCardRecord.setStartTime(dateTime.toDate());
+        }
+
         return vipCardRecord;
     }
 
@@ -179,15 +207,16 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
         //提前三天提示
         List<VipCardRecordVo> temporaryRecords = baseMapper.selectTemporaryRecord();
         //标识
-        Map<Long, Long> temporaryFlagMap = new HashMap<>();
+        Set<String> sendFlag = new HashSet<>();
         for (VipCardRecordVo record : temporaryRecords) {
-            if (null != temporaryFlagMap.get(record.getUserId())) {
+            String key = record.getUserId() + "_" + record.getVipType().getCode() + "_" + record.getClientType().getCode();
+            if (sendFlag.contains(key)) {
                 continue;
             }
-            temporaryFlagMap.put(record.getUserId(), record.getUserId());
+            sendFlag.add(key);
             //发送消息
             CompletableFuture.runAsync(() -> {
-                temporary3DaysSend(record.getUserId(), record.getPhone(),record.getClientType());
+                temporary3DaysSend(record.getUserId(), record.getPhone(), record.getClientType(), record.getVipType());
             });
             record.setMsgStatus(1);
             record.setUpdateTime(new Date());
@@ -200,16 +229,17 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
         //到期提示
         List<VipCardRecordVo> expireRecords = baseMapper.selectExpireRecord();
         //标识
-        Map<Long, Long> expireFlagMap = new HashMap<>();
+        Set<String> expireSendFlag = new HashSet<>();
         for (VipCardRecordVo record : expireRecords) {
-            if (null != expireFlagMap.get(record.getUserId())) {
+            String key = record.getUserId() + "_" + record.getVipType().getCode() + "_" + record.getClientType().getCode();
+            if (expireSendFlag.contains(key)) {
                 continue;
             }
-            expireFlagMap.put(record.getUserId(), record.getUserId());
+            expireSendFlag.add(key);
             //发送消息
             //发送消息
             CompletableFuture.runAsync(() -> {
-                expireSend(record.getUserId(),record.getPhone(), record.getClientType());
+                expireSend(record.getUserId(),record.getPhone(), record.getClientType(), record.getVipType());
             });
             record.setMsgStatus(2);
             record.setUpdateTime(new Date());
@@ -228,59 +258,712 @@ public class VipCardRecordServiceImpl extends ServiceImpl<VipCardRecordDao, VipC
 
     }
 
+    /**
+     * 获取生效中的会员记录
+     * @param userId
+     * @param clientEnum
+     * @return
+     */
+    @Override
+    public List<VipCardRecord> getEfficientVipRecord(List<Long> userId, ClientEnum clientEnum) {
+        if (CollectionUtils.isEmpty(userId)) {
+            return new ArrayList<>();
+        }
+        return this.lambdaQuery()
+            .in(VipCardRecord::getUserId, userId)
+            .eq(VipCardRecord::getEfficientFlag, true)
+            .eq(VipCardRecord::getClientType, clientEnum.name())
+            .in(VipCardRecord::getVipType, Lists.newArrayList(EVipType.VIP,EVipType.SVIP))
+            .and(wrapper -> wrapper
+                .gt(VipCardRecord::getEndTime, new Date())
+            )
+            .list();
+    }
+
+    @Override
+    public VipCardRecordWrapper.UserVip UserVipInfo(Long userId, ClientEnum clientEnum) {
+        return userVipInfo(userId,clientEnum);
+    }
+    /**
+     * 用户会员信息
+     *
+     * @param userId
+     * @param clientEnum
+     * @return
+     */
+    @Override
+    public VipCardRecordWrapper.UserVip userVipInfo(Long userId, ClientEnum clientEnum) {
+        // 获取生效中的会员记录
+        VipCardRecordWrapper.UserVip userVip = new VipCardRecordWrapper.UserVip();
+        List<VipCardRecord> vipCardRecords = this.getEfficientVipRecord(Lists.newArrayList(userId),clientEnum);
+        if (CollectionUtils.isEmpty(vipCardRecords)) {
+            userVip.setVipType(EVipType.NOT_VIP);
+            // 判断有没有过期的会员类型
+            Integer vipCount = this.lambdaQuery()
+                .eq(VipCardRecord::getUserId, userId)
+                .eq(VipCardRecord::getEfficientFlag, true)
+                .eq(VipCardRecord::getVipType, EVipType.VIP)
+                .eq(VipCardRecord::getClientType, clientEnum.name())
+                .count();
+            Integer svipCount = this.lambdaQuery()
+                .eq(VipCardRecord::getUserId, userId)
+                .eq(VipCardRecord::getEfficientFlag, true)
+                .eq(VipCardRecord::getVipType, EVipType.SVIP)
+                .eq(VipCardRecord::getClientType, clientEnum.name())
+                .count();
+            if (vipCount>0&&svipCount>0) {
+                userVip.setExpireVipType(EVipType.ALL_VIP);
+            } else if (vipCount>0) {
+                userVip.setExpireVipType(EVipType.VIP);
+            } else if (svipCount>0) {
+                userVip.setExpireVipType(EVipType.SVIP);
+            }
+        } else {
+            // 存在没有结束时间的SVIP记录 永久SVIP
+            List<VipCardRecord> svipList = vipCardRecords.stream().filter(o -> o.getVipType() == EVipType.SVIP).collect(Collectors.toList());
+            Date svipEndDate = null;
+            if (CollectionUtils.isNotEmpty(svipList)) {
+                userVip.setVipType(EVipType.SVIP);
+
+                Optional<VipCardRecord> first = svipList.stream().filter(o ->o.getType()==PeriodEnum.PERPETUAL).findFirst();
+                if (first.isPresent()) {
+                    userVip.setVipType(EVipType.PERMANENT_SVIP);
+                }
+//                else {
+                Optional<VipCardRecord> max = svipList.stream().filter(o -> !PeriodEnum.PERPETUAL.equals(o.getType())).max(Comparator.comparing(VipCardRecord::getEndTime));
+                max.ifPresent(vipCardRecord -> userVip.setSvipEndDate(vipCardRecord.getEndTime()));
+//                }
+                Optional<VipCardRecord> max1 = svipList.stream().max(Comparator.comparing(VipCardRecord::getEndTime));
+                if (max1.isPresent()) {
+                    svipEndDate = max1.get().getEndTime();
+                }
+            } else {
+                Integer svipCount = this.lambdaQuery()
+                    .eq(VipCardRecord::getUserId, userId)
+                    .eq(VipCardRecord::getEfficientFlag, true)
+                    .eq(VipCardRecord::getVipType, EVipType.SVIP)
+                    .eq(VipCardRecord::getClientType, clientEnum.name())
+                    .count();
+                if (svipCount>0) {
+                    userVip.setExpireVipType(EVipType.SVIP);
+
+                }
+            }
+            // 过滤出VIP数据
+            List<VipCardRecord> vipList = vipCardRecords.stream().filter(o -> o.getVipType() == EVipType.VIP).collect(Collectors.toList());
+            if (CollectionUtils.isNotEmpty(vipList)) {
+                if (userVip.getVipType() == null) {
+                    userVip.setVipType(EVipType.VIP);
+                }
+                Optional<VipCardRecord> max = vipList.stream().max(Comparator.comparing(VipCardRecord::getEndTime));
+                Optional<VipCardRecord> min = vipList.stream().min(Comparator.comparing(VipCardRecord::getStartTime));
+                max.ifPresent(vipCardRecord -> userVip.setVipEndDate(vipCardRecord.getEndTime()));
+                Date minDate = null;
+                if (min.isPresent()) {
+                    minDate = min.get().getStartTime();
+                }
+                // 设置VIP剩余天数
+                if (userVip.getVipEndDate() != null) {
+                    int num;
+                    if (svipEndDate != null && svipEndDate.after(new Date())) {
+                        num = DateUtil.daysBetween(svipEndDate, userVip.getVipEndDate());
+                    } else if (minDate != null && minDate.after(new Date())){
+                        num = DateUtil.daysBetween(minDate, userVip.getVipEndDate());
+                    } else {
+                        num = DateUtil.daysBetween(new Date(), userVip.getVipEndDate()) +1;
+                    }
+                    userVip.setVipEndDays(Math.max(num, 0));
+                }
+            } else {
+                Integer vipCount = this.lambdaQuery()
+                    .eq(VipCardRecord::getUserId, userId)
+                    .eq(VipCardRecord::getEfficientFlag, true)
+                    .eq(VipCardRecord::getVipType, EVipType.VIP)
+                    .eq(VipCardRecord::getClientType, clientEnum.name())
+                    .count();
+                if (vipCount>0) {
+                    userVip.setExpireVipType(EVipType.VIP);
+                }
+            }
+        }
+
+        if (userVip.getSvipEndDate() != null) {
+            int num = DateUtil.daysBetween(new Date(), userVip.getSvipEndDate()) +1;
+            userVip.setSvipEndDays(Math.max(num, 0));
+        }
+
+        // 设置会员过期时间
+        EVipType expireVipType = userVip.getExpireVipType();
+        List<VipCardRecordWrapper.UserVipInfo> userVipInfos = this.baseMapper.queryUserVipInfo(Collections.singletonList(userId), clientEnum.getCode());
+        if(!userVipInfos.isEmpty()){
+            VipCardRecordWrapper.UserVipInfo userVipInfo = userVipInfos.get(0);
+            Date date = new Date();
+            if (EVipType.VIP.equals(expireVipType) || EVipType.ALL_VIP.equals(expireVipType)) {
+                Date vipEndTime = userVipInfo.getVipEndTime();
+                if (vipEndTime != null && vipEndTime.before(date)) {
+                    double days = Math.ceil((date.getTime() - vipEndTime.getTime()) * 1.0D / (24 * 60 * 60 * 1000));
+                    userVip.setVipExpireDays((int) days);
+                }
+            }
+            if (EVipType.SVIP.equals(expireVipType) || EVipType.ALL_VIP.equals(expireVipType)) {
+                Date svipEndTime = userVipInfo.getSvipEndTime();
+                if (svipEndTime != null && svipEndTime.before(date)) {
+                    double days = Math.ceil((date.getTime() - svipEndTime.getTime()) * 1.0D / (24 * 60 * 60 * 1000));
+                    userVip.setSvipExpireDays((int) days);
+                }
+            }
+        }
+        return userVip;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void add(VipCardRecordWrapper.AddVipCardRecord addVipCardRecord) {
+        ClientEnum clientType = addVipCardRecord.getClientType();
+        if (!ClientEnum.STUDENT.equals(clientType) && !ClientEnum.TEACHER.equals(clientType)) {
+            throw new BizException("暂不支持非老师学生会员的增加或扣减");
+        }
+        if (EVipRecordStatus.DEDUCTION.equals(addVipCardRecord.getStatus())) {
+            VipCardRecord vipCardRecord = deductVip(addVipCardRecord);
+            vipCardRecord.setDisplayFlag(true);
+            this.save(vipCardRecord);
+        } else if (EVipRecordStatus.ADD.equals(addVipCardRecord.getStatus())) {
+            VipCardRecord addVip = addVip(addVipCardRecord);
+            this.save(addVip);
+            Integer vipDays = addVipCardRecord.getVipDays();
+            // 存在转换,先扣除,再添加
+            if (vipDays != null && vipDays > 0) {
+                VipCardRecordWrapper.AddVipCardRecord dedectRecord = JSON.parseObject(JSON.toJSONString(addVipCardRecord), VipCardRecordWrapper.AddVipCardRecord.class);
+                dedectRecord.setStatus(EVipRecordStatus.DEDUCTION);
+                dedectRecord.setVipType(EVipType.VIP);
+                dedectRecord.setType(PeriodEnum.DAY);
+                dedectRecord.setTimes(vipDays);
+                dedectRecord.setReason("后台转换扣减");
+                deductVip(dedectRecord);
+
+                VipCardRecordWrapper.AddVipCardRecord addRecord = JSON.parseObject(JSON.toJSONString(addVipCardRecord), VipCardRecordWrapper.AddVipCardRecord.class);
+                addRecord.setStatus(EVipRecordStatus.ADD);
+                addRecord.setVipType(EVipType.SVIP);
+                addRecord.setType(PeriodEnum.DAY);
+                addRecord.setTimes(vipDays);
+                addRecord.setReason("购买SVIP升级原VIP");
+                VipCardRecord convertVip = addVip(addRecord);
+
+                convertVip.setDisplayFlag(true);
+                convertVip.setStatus(EVipRecordStatus.UPDATE);
+                convertVip.setSourceType(SourceTypeEnum.FREE_UPGRADE);
+                // 添加转换记录
+                this.save(convertVip);
+
+            }
+        }
+
+        if (Boolean.TRUE.equals(addVipCardRecord.getSendMsg())) {
+            sendAddVipMsg(addVipCardRecord);
+        }
+    }
+
+    @Override
+    public Map<Long, EVipType> getVipTypeMapByUserIds(List<Long> studentIds, ClientEnum client) {
+
+        List<VipCardRecord> vipCardRecords = this.getEfficientVipRecord(studentIds,client);
+
+        // 根据用户ID分组
+        Map<Long, List<VipCardRecord>> vipCardRecordMap = vipCardRecords.stream().collect(Collectors.groupingBy(VipCardRecord::getUserId));
+        Map<Long, EVipType> vipTypeMap = new HashMap<>();
+        vipCardRecordMap.forEach((k, v) -> {
+            List<VipCardRecord> svipList = v.stream().filter(o -> o.getVipType() == EVipType.SVIP).collect(Collectors.toList());
+            if (CollectionUtils.isNotEmpty(svipList)) {
+                vipTypeMap.put(k, EVipType.SVIP);
+            } else {
+                List<VipCardRecord> vipList = v.stream().filter(o -> o.getVipType() == EVipType.VIP).collect(Collectors.toList());
+                if (CollectionUtils.isNotEmpty(vipList)) {
+                    vipTypeMap.put(k, EVipType.VIP);
+                }
+            }
+        });
+        return vipTypeMap;
+    }
+
+    // 会员添加
+    @Override
+    public VipCardRecord addVip(VipCardRecordWrapper.AddVipCardRecord addVipCardRecord) {
+        List<VipCardRecord> vipCardRecordList = this.lambdaQuery()
+                .eq(VipCardRecord::getClientType, addVipCardRecord.getClientType())
+                .eq(VipCardRecord::getUserId, addVipCardRecord.getUserId())
+                .ge(VipCardRecord::getEndTime, new Date())
+                .eq(VipCardRecord::getEfficientFlag, true)
+                .list()
+                .stream()
+//                .filter(n -> n.getEndTime() == null || n.getEndTime().after(new Date()))
+                .sorted(Comparator.comparing(VipCardRecord::getStartTime))
+                .collect(Collectors.toList());
+
+
+        EVipType addVipType = addVipCardRecord.getVipType();
+//        List<VipCardRecord> perpetualRecords = vipCardRecordList.stream()
+//                .filter(n -> n.getVipType().equals(addVipType) && PeriodEnum.PERPETUAL.equals(n.getType()))
+//                .collect(Collectors.toList());
+//        if (!perpetualRecords.isEmpty()) {
+//            throw new BizException("已经是永久会员");
+//        }
+
+        Date now = new Date();
+        long startTimeMills = now.getTime();
+        // 没有会员信息
+        if (vipCardRecordList.isEmpty()) {
+            PeriodEnum period = addVipCardRecord.getType();
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(now);
+            calendar.set(Calendar.HOUR_OF_DAY, 23);
+            calendar.set(Calendar.MINUTE, 59);
+            calendar.set(Calendar.SECOND, 59);
+            calendar.set(Calendar.MILLISECOND, 0);
+            Date endDate = plusDate(calendar.getTime(), period, Long.valueOf(addVipCardRecord.getTimes()));
+
+            VipCardRecord addRecord = JSON.parseObject(JSON.toJSONString(addVipCardRecord), VipCardRecord.class);
+            addRecord.setSourceType(addVipCardRecord.getSourceType() !=null?addVipCardRecord.getSourceType():SourceTypeEnum.BACKEND_GIVE);
+            addRecord.setStatus(EVipRecordStatus.ADD);
+            addRecord.setDisplayFlag(true);
+            addRecord.setEfficientFlag(true);
+            addRecord.setStartTime(now);
+            addRecord.setEndTime(endDate);
+            return addRecord;
+        }
+
+        // 找到插入数据的位置
+        int index = 0;
+        if (addVipType.equals(EVipType.VIP)) { // vip 放到最后
+            index = vipCardRecordList.size();
+            startTimeMills = vipCardRecordList.stream().map(VipCardRecord::getEndTime).max(Date::compareTo).get().getTime() + 1000L;
+        }
+        if (addVipType.equals(EVipType.SVIP)) { //放到VIP的前面
+            index = (int) vipCardRecordList.stream().filter(n -> EVipType.SVIP.equals(n.getVipType()) && !PeriodEnum.PERPETUAL.equals(n.getType())).count();
+            if (index > 0) {
+                startTimeMills = vipCardRecordList.stream().filter(n -> EVipType.SVIP.equals(n.getVipType()) && !PeriodEnum.PERPETUAL.equals(n.getType()))
+                        .map(VipCardRecord::getEndTime).max(Date::compareTo).get().getTime() + 1000;
+            }
+        }
+
+        VipCardRecord newRecord = JSON.parseObject(JSON.toJSONString(addVipCardRecord), VipCardRecord.class);
+        newRecord.setSourceType(addVipCardRecord.getSourceType() !=null?addVipCardRecord.getSourceType():SourceTypeEnum.BACKEND_GIVE);
+        newRecord.setStatus(EVipRecordStatus.ADD);
+        newRecord.setStartTime(new Date(startTimeMills));
+        if (index == 0) { // 当天剩余时间属于赠送
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(new Date(startTimeMills));
+            calendar.set(Calendar.HOUR_OF_DAY, 23);
+            calendar.set(Calendar.MINUTE, 59);
+            calendar.set(Calendar.SECOND, 59);
+            calendar.set(Calendar.MILLISECOND, 0);
+            Date endDate = plusDate(calendar.getTime(), addVipCardRecord.getType(), Long.valueOf(addVipCardRecord.getTimes()));
+            newRecord.setEndTime(new Date(endDate.getTime()));
+        } else {
+            Date endDate = plusDate(new Date(startTimeMills - 1000), addVipCardRecord.getType(), Long.valueOf(addVipCardRecord.getTimes()));
+            newRecord.setEndTime(endDate);
+        }
+
+        newRecord.setDisplayFlag(true);
+        newRecord.setEfficientFlag(true);
+
+        // 平移时间
+//        long plusMills = newRecord.getEndTime().getTime() - startTimeMills;
+        long beforeEndTime = newRecord.getEndTime().getTime();
+        for (int i = 0; i < vipCardRecordList.size(); i++) {
+            VipCardRecord vipCardRecord = vipCardRecordList.get(i);
+            if (i >= index) {
+                VipCardRecord addRecord = JSON.parseObject(JSON.toJSONString(vipCardRecord), VipCardRecord.class);
+                addRecord.setStatus(EVipRecordStatus.UPDATE);
+
+                addRecord.setStartTime(new Date(beforeEndTime + 1000));
+
+//                int days = (int) Math.ceil(plusMills * 1.0D / (24 * 60 * 60 * 1000));
+                Date endTime = plusDate(vipCardRecord.getEndTime(), addVipCardRecord.getType(), addVipCardRecord.getTimes());
+                addRecord.setEndTime(endTime);
+                addRecord.setDisplayFlag(false);
+                addRecord.setEfficientFlag(true);
+                save(addRecord);
+                Long refId = addRecord.getId();
+
+                VipCardRecord updateRecord = JSON.parseObject(JSON.toJSONString(vipCardRecord), VipCardRecord.class);
+                updateRecord.setEfficientFlag(false);
+                updateRecord.setRefId(refId);
+                updateById(updateRecord);
+                beforeEndTime = endTime.getTime();
+            }
+        }
+        return newRecord;
+    }
+
+    @Override
+    public List<VipCardRecordWrapper.UserVipInfo> queryUserVipInfo(List<Long> userIdList, String clientType) {
+        return baseMapper.queryUserVipInfo(userIdList, clientType);
+    }
+
+
+    // 会员扣减
+    private VipCardRecord deductVip(VipCardRecordWrapper.AddVipCardRecord addVipCardRecord) {
+
+        // 所有的会员重新生成
+        List<VipCardRecord> vipCardRecordList = this.lambdaQuery()
+                .eq(VipCardRecord::getClientType, addVipCardRecord.getClientType())
+                .eq(VipCardRecord::getUserId, addVipCardRecord.getUserId())
+                .ge(VipCardRecord::getEndTime, new Date())
+                .eq(VipCardRecord::getEfficientFlag, true)
+                .list()
+                .stream()
+                .sorted(Comparator.comparing(VipCardRecord::getStartTime))
+                .collect(Collectors.toList());
+
+        // 当前类型的VIP
+        PeriodEnum period = addVipCardRecord.getType();
+        // 扣减永久
+        if (PeriodEnum.PERPETUAL.equals(period)) {
+            addVipCardRecord.setTimes(1);
+            return deductedSVipPerpetual(addVipCardRecord, vipCardRecordList);
+        }
+
+        // 扣减非永久
+        List<VipCardRecord> collect = vipCardRecordList.stream()
+                .filter(n -> n.getVipType().equals(addVipCardRecord.getVipType()) && !PeriodEnum.PERPETUAL.equals(n.getType())).collect(Collectors.toList());
+        if (collect.isEmpty()) {
+            throw new BizException("剩余扣减数量不足");
+        }
+
+        Date now = new Date();
+        LocalDateTime maxEndTime = collect.stream().map(VipCardRecord::getEndTime).max(Comparator.naturalOrder()).get().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+        // 扣减后的开始时间
+        LocalDateTime deductedStartTime;
+        switch (period) {
+            case DAY:
+                deductedStartTime = maxEndTime.minusDays(addVipCardRecord.getTimes());
+                break;
+            case MONTH:
+                deductedStartTime = maxEndTime.minusMonths(addVipCardRecord.getTimes());
+                break;
+            case QUARTERLY:
+                deductedStartTime = maxEndTime.minusMonths(addVipCardRecord.getTimes() * 3L);
+                break;
+            case YEAR_HALF:
+                deductedStartTime = maxEndTime.minusMonths(addVipCardRecord.getTimes() * 6L);
+                break;
+            case YEAR:
+                deductedStartTime = maxEndTime.minusYears(addVipCardRecord.getTimes());
+                break;
+            default:
+                throw new BizException("不支持的扣减类型");
+        }
+        Date deductedStartDate =  Date.from(deductedStartTime.atZone(ZoneId.systemDefault()).toInstant());;
+
+        Date minStartTime = collect.stream().map(VipCardRecord::getStartTime).min(Comparator.naturalOrder()).get();
+        // 如果扣减的数量超过1天,则提示扣减数量不足
+        if (deductedStartDate.before(minStartTime)) {
+            double day = (minStartTime.getTime() - deductedStartDate.getTime()) * 1.0D / (24 * 60 * 60 * 1000);
+            if (day > 1.0D) {
+                if (addVipCardRecord.isOrderFlag()) {
+                    collect.stream().forEach(o->o.setEfficientFlag(false));
+
+                    this.updateBatchById(collect, 100);
+                    return null;
+                }
+
+                throw new BizException("剩余扣减数量不足");
+            }
+//            deductedStartDate = minStartTime;
+        }
+
+        // 重新计算会员时间,每一条记录置换成一条新的记录,时间区间重新计算
+        List<VipCardRecord> updateRecords = new ArrayList<>();
+        Long deductMills = null;
+        Long endDeductMills = null;
+
+        EVipType vipType = addVipCardRecord.getVipType();
+        boolean giveFlag = false; // 扣减后,剩余时间前移,第一条记录赠送当天的时间
+        for (VipCardRecord vipCardRecord : vipCardRecordList) {
+            Date startTime = vipCardRecord.getStartTime();
+            Date endTime = vipCardRecord.getEndTime();
+            if (endTime.before(deductedStartDate) || endTime.equals(deductedStartDate)) {
+                continue;
+            }
+            // 扣减vip,跳过SVIP
+            if (EVipType.VIP.equals(vipType) && EVipType.SVIP.equals(vipCardRecord.getVipType())) {
+                continue;
+            }
+
+            Long addId = null;
+            // 扣减到当前时间区间
+            if ((deductedStartDate.after(startTime) || deductedStartDate.equals(startTime)) && deductedStartDate.before(endTime)) {
+                if (deductedStartDate.after(now)) { // 还有剩余天数,不足一天,补充到当前全天
+                    VipCardRecord addRecord = JSON.parseObject(JSON.toJSONString(vipCardRecord), VipCardRecord.class);
+                    addRecord.setId(null);
+                    addRecord.setDisplayFlag(false);
+                    addRecord.setEfficientFlag(true);
+                    addRecord.setEndTime(formatEnd(deductedStartDate));
+                    addRecord.setStatus(EVipRecordStatus.UPDATE);
+                    save(addRecord);
+                    addId = addRecord.getId();
+                }
+
+
+                deductMills = endTime.getTime() - deductedStartDate.getTime();
+                endDeductMills = endTime.getTime() - formatEnd(deductedStartDate).getTime();
+            } else {
+                if (vipCardRecord.getVipType().equals(vipType) && !PeriodEnum.PERPETUAL.equals(vipCardRecord.getType())) {
+                    deductMills = endTime.getTime() - deductedStartDate.getTime();
+                    endDeductMills = endTime.getTime() - formatEnd(deductedStartDate).getTime();
+                } else {
+                    // 有扣减,整体时间前移
+                    if (deductMills != null) {
+                        VipCardRecord newRecord = JSON.parseObject(JSON.toJSONString(vipCardRecord), VipCardRecord.class);
+                        newRecord.setId(null);
+                        newRecord.setDisplayFlag(false);
+                        newRecord.setEfficientFlag(true);
+                        if (!giveFlag) {
+                            newRecord.setStartTime(new Date(newRecord.getStartTime().getTime() - deductMills));
+                            giveFlag = true;
+                        } else {
+                            newRecord.setStartTime(new Date(newRecord.getStartTime().getTime() - endDeductMills));
+                        }
+                        newRecord.setEndTime(new Date(newRecord.getEndTime().getTime() - endDeductMills));
+                        newRecord.setStatus(EVipRecordStatus.UPDATE);
+                        save(newRecord);
+                        addId = newRecord.getId();
+                    }
+                }
+            }
+
+            VipCardRecord updateRecord = JSON.parseObject(JSON.toJSONString(vipCardRecord), VipCardRecord.class);
+            updateRecord.setEfficientFlag(false);
+            updateRecord.setRefId(addId);
+            updateRecords.add(updateRecord);
+        }
+
+        this.updateBatchById(updateRecords, 100);
+
+        VipCardRecord vipCardRecord = JSON.parseObject(JSON.toJSONString(addVipCardRecord), VipCardRecord.class);
+        vipCardRecord.setEfficientFlag(false);
+        vipCardRecord.setStartTime(deductedStartDate);
+        vipCardRecord.setEndTime(Date.from(maxEndTime.atZone(ZoneId.systemDefault()).toInstant()));
+        vipCardRecord.setStatus(EVipRecordStatus.DEDUCTION);
+        return vipCardRecord;
+    }
+
+    // 扣减永久SVIP会员
+    private VipCardRecord deductedSVipPerpetual(VipCardRecordWrapper.AddVipCardRecord addVipCardRecord, List<VipCardRecord> vipCardRecordList) {
+        List<VipCardRecord> collect = vipCardRecordList.stream()
+                .filter(n -> n.getVipType().equals(addVipCardRecord.getVipType()) && n.getType().equals(PeriodEnum.PERPETUAL))
+                .collect(Collectors.toList());
+        if (collect.isEmpty()) {
+            throw new BizException("剩余扣减数量不足");
+        }
+
+
+        // 最后一个非永久SVIP的结束时间
+        Date lastUnPereutalDate = new Date();
+        Date lastEndUnPereutalDate = formatEnd(new Date());
+        Long deductMills = null;
+        Long endDeductMills = null;
+        boolean giveFlag = false;
+        for (VipCardRecord vipCardRecord : vipCardRecordList) {
+            if (EVipType.SVIP.equals(vipCardRecord.getVipType())) {
+                // 获取后续VIP向前平移的开始时间
+                if (!PeriodEnum.PERPETUAL.equals(vipCardRecord.getType())) {
+                    if (vipCardRecord.getEndTime().after(lastUnPereutalDate)) {
+                        lastUnPereutalDate = vipCardRecord.getEndTime();
+                        lastEndUnPereutalDate = vipCardRecord.getEndTime();
+                    }
+                    continue;
+                }
+                vipCardRecord.setEfficientFlag(false);
+                updateById(vipCardRecord);
+            } else {
+                VipCardRecord newRecord = JSON.parseObject(JSON.toJSONString(vipCardRecord), VipCardRecord.class);
+                newRecord.setId(null);
+                newRecord.setDisplayFlag(false);
+                newRecord.setEfficientFlag(true);
+                if (vipCardRecord.getVipType().equals(addVipCardRecord.getVipType()) && !giveFlag) {
+                    deductMills = vipCardRecord.getStartTime().getTime() - lastUnPereutalDate.getTime();
+                    endDeductMills = vipCardRecord.getStartTime().getTime() - lastEndUnPereutalDate.getTime();
+                    newRecord.setStartTime(new Date(newRecord.getStartTime().getTime() - deductMills));
+                    giveFlag = true;
+                } else {
+                    endDeductMills = vipCardRecord.getStartTime().getTime() - lastEndUnPereutalDate.getTime();
+                    newRecord.setStartTime(new Date(newRecord.getStartTime().getTime() - endDeductMills));
+                }
+                newRecord.setEndTime(new Date(newRecord.getEndTime().getTime() - endDeductMills));
+                save(newRecord);
+                Long refId = newRecord.getId();
+
+                VipCardRecord updateRecord = JSON.parseObject(JSON.toJSONString(vipCardRecord), VipCardRecord.class);
+                updateRecord.setEfficientFlag(false);
+                updateRecord.setRefId(refId);
+                updateById(updateRecord);
+            }
+        }
+        VipCardRecord vipCardRecord = JSON.parseObject(JSON.toJSONString(addVipCardRecord), VipCardRecord.class);
+        vipCardRecord.setEfficientFlag(false);
+        vipCardRecord.setStatus(EVipRecordStatus.DEDUCTION);
+        return vipCardRecord;
+    }
+
+    private Date plusDate(Date start, PeriodEnum period, long times) {
+//        Calendar calendar = Calendar.getInstance();
+//        calendar.setTime(start);
+//        calendar.set(Calendar.HOUR_OF_DAY, 23);
+//        calendar.set(Calendar.MINUTE, 59);
+//        calendar.set(Calendar.SECOND, 59);
+//        calendar.set(Calendar.MILLISECOND, 0);
+        LocalDateTime localDateTimeMaxTime =  LocalDateTime.ofInstant(start.toInstant(),ZoneId.systemDefault());
+
+        LocalDateTime end;
+        switch (period) {
+            case DAY:
+                end = localDateTimeMaxTime.plusDays(times);
+                break;
+            case MONTH:
+                end = localDateTimeMaxTime.plusMonths(times);
+                break;
+            case QUARTERLY:
+                end = localDateTimeMaxTime.plusMonths(times * 3);
+                break;
+            case YEAR_HALF:
+                end = localDateTimeMaxTime.plusMonths(times * 6);
+                break;
+            case YEAR:
+                end = localDateTimeMaxTime.plusYears(times);
+                break;
+            case PERPETUAL:
+                // 永久默认给100年
+                end = localDateTimeMaxTime.plusYears(100);
+                break;
+            default:
+                throw new BizException("不支持的扣减类型");
+        }
+        return Date.from(end.atZone(ZoneId.systemDefault()).toInstant());
+    }
+
     // 发送会员到期3天消息推送
-    private void temporary3DaysSend(Long userId, String phone, ClientEnum clientType) {
+    private void temporary3DaysSend(Long userId, String phone, ClientEnum clientType, EVipType vipType) {
         Map<Long, String> receivers = new HashMap<>();
         receivers.put(userId, phone);
         // 判断是否是机构学生 机构学生推送走另一个
         if (clientType.equals(ClientEnum.STUDENT)) {
-        } else {
-            try {
-                String url = sysMessageService.selectConfigUrl(MessageTypeEnum.VIP_EXPIRE_THIRTY_DAY.getCode());
-                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.VIP_EXPIRE_THIRTY_DAY,
-                        receivers, null, 0, url, ClientEnum.STUDENT.getCode());
-            } catch (Exception e) {
-                log.error("会员到期3天极光消息推送异常,userId={}", userId);
+            Student student = studentService.getById(userId);
+            if (student == null || (student.getTenantId() != null && student.getTenantId() > 0 )) {
+                return;
             }
+        }
+        try {
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,
+                    EVipType.VIP.equals(vipType) ? MessageTypeEnum.VIP_EXPIRE_THIRTY_DAY : MessageTypeEnum.SVIP_EXPIRE_THIRTY_DAY
+                    , receivers, null, 0, null, clientType.getCode());
+        } catch (Exception e) {
+            log.error("会员到期3天极光消息推送异常,userId={}", userId);
+        }
 
-            try {
-                String url = sysMessageService.selectConfigUrl(MessageTypeEnum.SMS_VIP_EXPIRE_THIRTY_DAY.getCode());
-                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS, MessageTypeEnum.SMS_VIP_EXPIRE_THIRTY_DAY,
-                        receivers, null, 0, null, ClientEnum.STUDENT.getCode(), url);
-            } catch (Exception e) {
-                log.error("会员到期3天短信消息推送异常,userId={}", userId);
-            }
+        try {
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS,
+                    EVipType.VIP.equals(vipType) ? MessageTypeEnum.SMS_VIP_EXPIRE_THIRTY_DAY : MessageTypeEnum.SMS_SVIP_EXPIRE_THIRTY_DAY
+                    , receivers, null, 0, null, clientType.getCode());
+        } catch (Exception e) {
+            log.error("会员到期3天短信消息推送异常,userId={}", userId);
         }
     }
 
     // 发送会员到期消息推送
-    private void expireSend(Long userId,String phone,ClientEnum userType) {
+    private void expireSend(Long userId,String phone,ClientEnum userType, EVipType vipType) {
         Map<Long, String> receivers = new HashMap<>();
         receivers.put(userId, phone);
         Student student = studentService.getById(userId);
         if (userType.equals(ClientEnum.STUDENT) && student != null  && student.getTenantId() != null && student.getTenantId() >0) {
-            try {
-                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.TENANT_VIP_EXPIRE,
-                        receivers, null, 0, null, ClientEnum.TENANT_STUDENT.getCode());
-            } catch (Exception e) {
-                log.error("会员到期极光消息推送异常,userId={}", userId);
-            }
+//            try {
+//                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.TENANT_VIP_EXPIRE,
+//                        receivers, null, 0, null, ClientEnum.TENANT_STUDENT.getCode());
+//            } catch (Exception e) {
+//                log.error("会员到期极光消息推送异常,userId={}", userId);
+//            }
         } else {
             try {
-                String url = sysMessageService.selectConfigUrl(MessageTypeEnum.VIP_EXPIRE.getCode());
-                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.VIP_EXPIRE,
-                        receivers, null, 0, url, userType.getCode());
+                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,
+                        EVipType.VIP.equals(vipType) ? MessageTypeEnum.VIP_EXPIRE : MessageTypeEnum.SVIP_EXPIRE
+                        ,receivers, null, 0, null, userType.getCode());
             } catch (Exception e) {
                 log.error("会员到期3天极光消息推送异常,userId={}", userId);
             }
 
             try {
-                String url = sysMessageService.selectConfigUrl(MessageTypeEnum.SMS_VIP_EXPIRE.getCode());
-                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS, MessageTypeEnum.SMS_VIP_EXPIRE,
-                        receivers, null, 0, null, userType.getCode(), url);
+                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS,
+                        EVipType.VIP.equals(vipType) ? MessageTypeEnum.SMS_VIP_EXPIRE : MessageTypeEnum.SMS_SVIP_EXPIRE,
+                        receivers, null, 0, null, userType.getCode());
             } catch (Exception e) {
                 log.error("会员到期3天短信消息推送异常,userId={}", userId);
             }
         }
     }
+
+    // 添加、扣除会员发送推送
+    private void sendAddVipMsg(VipCardRecordWrapper.AddVipCardRecord addVipCardRecord) {
+        SysUser sysUser = sysUserService.getByUserId(addVipCardRecord.getUserId());
+        if (sysUser == null) {
+            return;
+        }
+        MessageTypeEnum messageTypeEnum;
+        EVipRecordStatus status = addVipCardRecord.getStatus();
+        EVipType vipType = addVipCardRecord.getVipType();
+        if (EVipRecordStatus.ADD.equals(status)) {
+            if (EVipType.VIP.equals(vipType)) {
+                messageTypeEnum = MessageTypeEnum.PLATFORM_ADD_VIP;
+            }else {
+                PeriodEnum period = addVipCardRecord.getType();
+                if (PeriodEnum.PERPETUAL.equals(period)) {
+                    messageTypeEnum = MessageTypeEnum.PLATFORM_ADD_PER_SVIP;
+                } else {
+                    messageTypeEnum = MessageTypeEnum.PLATFORM_ADD_SVIP;
+                }
+            }
+        } else if (EVipRecordStatus.DEDUCTION.equals(status)) {
+            if (EVipType.VIP.equals(vipType)) {
+                messageTypeEnum = MessageTypeEnum.PLATFORM_ADD_DUDECT_VIP;
+            }else {
+                PeriodEnum period = addVipCardRecord.getType();
+                if (PeriodEnum.PERPETUAL.equals(period)) {
+                    messageTypeEnum = MessageTypeEnum.PLATFORM_ADD_DUDECT_PER_SVIP;
+                } else {
+                    messageTypeEnum = MessageTypeEnum.PLATFORM_ADD_DUDECT_SVIP;
+                }
+            }
+        } else {
+            throw new BizException("不支持类型");
+        }
+
+        Map<Long, String> receivers = new HashMap<>();
+        receivers.put(addVipCardRecord.getUserId(), sysUser.getPhone());
+
+        try {
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, messageTypeEnum,
+                    receivers, null, 0, null, addVipCardRecord.getClientType().getCode(), String.valueOf(addVipCardRecord.getTimes()), addVipCardRecord.getType().getMsg(),
+                    addVipCardRecord.getReason());
+        } catch (Exception e) {
+            log.error("会员添加消息发送失败 : {}", e.getMessage());
+        }
+    }
+
+    private Date formatEnd(Date date) {
+        Calendar c1 = Calendar.getInstance();
+        c1.setTime(date);
+        c1.set(Calendar.HOUR_OF_DAY, 23);
+        c1.set(Calendar.MINUTE, 59);
+        c1.set(Calendar.SECOND, 59);
+        return c1.getTime();
+    }
+
+    private Date formatStart(Date date) {
+        Calendar c1 = Calendar.getInstance();
+        c1.setTime(date);
+        c1.set(Calendar.HOUR_OF_DAY, 0);
+        c1.set(Calendar.MINUTE, 0);
+        c1.set(Calendar.SECOND, 0);
+        c1.set(Calendar.MILLISECOND, 0);
+        return c1.getTime();
+    }
 }

+ 2 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/vo/MusicSheetDetailVo.java

@@ -28,6 +28,8 @@ public class MusicSheetDetailVo extends MusicSheet {
     @ApiModelProperty("是否能播放(0:否,1:是) 学生端进入小酷Ai判断 试用/完整 播放")
     private YesOrNoEnum play;
 
+    @ApiModelProperty("是否购买(0:否,1:是)")
+    private Boolean buyed = false;
 
     @ApiModelProperty("收藏0:否,1:是")
     private YesOrNoEnum favorite;

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä