Browse Source

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

zouxuan 1 year ago
parent
commit
5e74a37423
100 changed files with 4148 additions and 727 deletions
  1. 8 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/AdminFeignService.java
  2. 4 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/TeacherFeignService.java
  3. 5 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/fallback/AdminFeignServiceFallback.java
  4. 5 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/fallback/TeacherFeignServiceFallback.java
  5. 39 3
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/StudentController.java
  6. 3 2
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TeacherController.java
  7. 147 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TenantAlbumCategoryController.java
  8. 43 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TenantGroupController.java
  9. 39 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/open/OpenTenantGroupController.java
  10. 62 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/TenantAlbumCategoryDetailVo.java
  11. 93 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/TenantAlbumCategoryVo.java
  12. 6 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/TenantAlbumVo.java
  13. 15 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/task/TaskController.java
  14. 14 1
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/ImGroupController.java
  15. 1 11
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/SysMessageController.java
  16. 35 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/open/OpenTenantGroupController.java
  17. 17 3
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/ImGroupController.java
  18. 23 1
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/StudentController.java
  19. 46 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/TenantGroupController.java
  20. 63 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/open/OpenSubjectController.java
  21. 10 4
      cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/task/TaskController.java
  22. 72 4
      cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/IndexController.java
  23. 83 10
      cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/StudentController.java
  24. 8 7
      cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/SysMusicCompareRecordController.java
  25. 44 1
      cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/TeacherController.java
  26. 27 21
      cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/TenantActivationCodeController.java
  27. 131 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/TenantGroupController.java
  28. 10 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/open/OpenStudentController.java
  29. 35 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/open/OpenTenantGroupController.java
  30. 3 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/vo/StudentVo.java
  31. 72 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/vo/TenantGroupVo.java
  32. 29 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/ETenantAlbumCategoryType.java
  33. 1 0
      cooleshow-gateway/gateway-web/src/main/java/com/yonge/gateway/web/config/SwaggerDocumentConfig.java
  34. 20 0
      cooleshow-task/src/main/java/com/yonge/cooleshow/task/jobs/DivBackTask.java
  35. 19 0
      cooleshow-task/src/main/java/com/yonge/cooleshow/task/jobs/SendTenantAlbumMessageTask.java
  36. 37 2
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/StudentController.java
  37. 3 2
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TeacherController.java
  38. 149 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantAlbumCategoryController.java
  39. 43 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantGroupController.java
  40. 35 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/OpenTenantGroupController.java
  41. 62 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/io/request/TenantAlbumCategoryDetailVo.java
  42. 93 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/io/request/TenantAlbumCategoryVo.java
  43. 6 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/io/request/TenantAlbumVo.java
  44. 15 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/task/TaskController.java
  45. 4 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/StudentDao.java
  46. 1 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/SysMusicCompareWeekDataDao.java
  47. 11 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/JumpUrlDto.java
  48. 1 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dto/search/StudentSearch.java
  49. 66 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/DivBackRecord.java
  50. 9 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/PaymentDivMemberRecord.java
  51. 4 136
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/SysMessage.java
  52. 4 103
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/SysMessageConfig.java
  53. 8 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/TenantAlbum.java
  54. 58 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/TenantAlbumCategory.java
  55. 36 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/TenantAlbumCategoryDetail.java
  56. 53 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/TenantGroup.java
  57. 9 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/MessageTypeEnum.java
  58. 27 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/DivBackRecordMapper.java
  59. 27 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/TenantAlbumCategoryDetailMapper.java
  60. 28 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/TenantAlbumCategoryMapper.java
  61. 31 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/TenantGroupMapper.java
  62. 13 9
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/UserTenantAlbumRecordMapper.java
  63. 44 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/queryInfo/SysMusicCompareRecordQueryInfo.java
  64. 47 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/DivBackRecordService.java
  65. 1 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/ImGroupService.java
  66. 3 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/OssFileService.java
  67. 8 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/PaymentDivMemberRecordService.java
  68. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/StudentService.java
  69. 2 37
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/SysMessageService.java
  70. 3 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/SysUserService.java
  71. 3 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/TeacherService.java
  72. 7 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/TenantActivationCodeService.java
  73. 43 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/TenantAlbumCategoryDetailService.java
  74. 46 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/TenantAlbumCategoryService.java
  75. 54 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/TenantGroupService.java
  76. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/UserOrderRefundService.java
  77. 2 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/UserPaymentCoreService.java
  78. 8 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/UserTenantAlbumRecordService.java
  79. 1 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseGroupServiceImpl.java
  80. 152 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/DivBackRecordServiceImpl.java
  81. 2 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImGroupServiceImpl.java
  82. 4 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/ImUserFriendServiceImpl.java
  83. 39 23
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/MemberPriceSettingsServiceImpl.java
  84. 29 15
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/MusicSheetServiceImpl.java
  85. 41 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/OssFileServiceImpl.java
  86. 15 10
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/PaymentDivMemberRecordServiceImpl.java
  87. 180 25
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/StudentServiceImpl.java
  88. 28 146
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/SysMessageServiceImpl.java
  89. 16 15
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/SysMusicCompareRecordServiceImpl.java
  90. 6 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/SysUserServiceImpl.java
  91. 65 30
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TeacherServiceImpl.java
  92. 68 30
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantActivationCodeServiceImpl.java
  93. 66 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantAlbumCategoryDetailServiceImpl.java
  94. 250 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantAlbumCategoryServiceImpl.java
  95. 55 16
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantAlbumMusicServiceImpl.java
  96. 56 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantAlbumServiceImpl.java
  97. 526 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantGroupServiceImpl.java
  98. 37 11
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantUnbindRecordServiceImpl.java
  99. 25 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserOrderRefundServiceImpl.java
  100. 147 43
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserPaymentCoreServiceImpl.java

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

@@ -195,4 +195,12 @@ public interface AdminFeignService {
      */
     @GetMapping("/task/sendPlatformAuditMessage")
     HttpResponseResult<Object> sendPlatformAuditMessage();
+
+    /**
+     * 机构学生训练教材过期
+     */
+    @GetMapping("/task/sendTenantAlbumMessage")
+    HttpResponseResult<Object> sendTenantAlbumMessage();
+
+
 }

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

@@ -72,4 +72,8 @@ public interface TeacherFeignService {
      */
     @GetMapping("/open/teacher/identity/{ID}")
     HttpResponseResult<Boolean> userTeacherIdentityInfo(@PathVariable("ID") Long userId);
+
+
+    @GetMapping("/task/divBack")
+    public HttpResponseResult<Object> divBack();
 }

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

@@ -188,6 +188,11 @@ public class AdminFeignServiceFallback implements AdminFeignService {
     }
 
     @Override
+    public HttpResponseResult<Object> sendTenantAlbumMessage() {
+        return null;
+    }
+
+    @Override
     public ImUserInfo register(String userId, String clientType, String username, String avatar) {
         return null;
     }

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

@@ -52,4 +52,9 @@ public class TeacherFeignServiceFallback implements TeacherFeignService {
     public HttpResponseResult<Boolean> userTeacherIdentityInfo(Long userId) {
         return null;
     }
+
+    @Override
+    public HttpResponseResult<Object> divBack() {
+        return null;
+    }
 }

+ 39 - 3
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/StudentController.java

@@ -7,9 +7,11 @@ import com.yonge.cooleshow.biz.dal.dto.VipSubmitReq;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.VipRecordSearch;
 import com.yonge.cooleshow.biz.dal.entity.Student;
+import com.yonge.cooleshow.biz.dal.entity.TenantGroup;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.MemberPriceSettingsService;
 import com.yonge.cooleshow.biz.dal.service.StudentService;
+import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
 import com.yonge.cooleshow.biz.dal.service.VipCardRecordService;
 import com.yonge.cooleshow.biz.dal.vo.StudentVo;
 import com.yonge.cooleshow.biz.dal.vo.VipRecordVo;
@@ -41,12 +43,16 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 @RestController
 @RequestMapping("${app-config.url.admin:}/student")
@@ -55,7 +61,7 @@ public class StudentController extends BaseController {
     @Autowired
     private StudentService studentService;
 
-    @Autowired
+    @Resource
     private SysUserFeignService sysUserFeignService;
 
     @Autowired
@@ -64,6 +70,9 @@ public class StudentController extends BaseController {
     @Autowired
     private VipCardRecordService vipCardRecordService;
 
+    @Autowired
+    private TenantGroupService tenantGroupService;
+
     @GetMapping("/detail/{id}")
     @ApiOperation(value = "详情", notes = "传入id")
     @ApiImplicitParams({
@@ -72,6 +81,10 @@ public class StudentController extends BaseController {
     @PreAuthorize("@pcs.hasPermissions('student/detail')")
     public HttpResponseResult<StudentVo> detail(@PathVariable("id") Long id) {
         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);
     }
 
@@ -100,6 +113,17 @@ public class StudentController extends BaseController {
         IPage<StudentVo> pages = studentService.selectPage(PageUtil.getPage(query), query);
         List<StudentVo> rows = pages.getRecords();
 
+        List<Long> tenantGroupIds = rows.stream().map(Student::getTenantGroupId)
+                .filter(next -> next != null && next != -1L).distinct().collect(Collectors.toList());
+        Map<Long, String> tenantGroupIdNameMap = new HashMap<>();
+        if (!tenantGroupIds.isEmpty()) {
+            Map<Long, String> tenantGroupMap = tenantGroupService.lambdaQuery()
+                    .in(TenantGroup::getId, tenantGroupIds)
+                    .list().stream().collect(Collectors.toMap(TenantGroup::getId, TenantGroup::getName));
+            tenantGroupIdNameMap.putAll(tenantGroupMap);
+        }
+
+
         for (StudentVo vo : rows) {
             if (vo.getDelFlag() == YesOrNoEnum.YES) {
                 vo.setUserStatus(UserStatusEnum.CLOSED);
@@ -110,6 +134,7 @@ public class StudentController extends BaseController {
                     vo.setUserStatus(UserStatusEnum.NORMAL);
                 }
             }
+            vo.setTenantGroupName(tenantGroupIdNameMap.getOrDefault(vo.getTenantGroupId(), ""));
         }
         return succeed(PageUtil.pageInfo(pages));
     }
@@ -142,6 +167,16 @@ public class StudentController extends BaseController {
             throw new BizException("没有可导出数据");
         }
 
+        List<Long> tenantGroupIds = rows.stream().map(Student::getTenantGroupId)
+                .filter(next -> next != null && next != -1L).distinct().collect(Collectors.toList());
+        Map<Long, String> tenantGroupIdNameMap = new HashMap<>();
+        if (!tenantGroupIds.isEmpty()) {
+            Map<Long, String> tenantGroupMap = tenantGroupService.lambdaQuery()
+                    .in(TenantGroup::getId, tenantGroupIds)
+                    .list().stream().collect(Collectors.toMap(TenantGroup::getId, TenantGroup::getName));
+            tenantGroupIdNameMap.putAll(tenantGroupMap);
+        }
+
         for (StudentVo vo : rows) {
             if (vo.getDelFlag() == YesOrNoEnum.YES) {
                 vo.setUserStatus(UserStatusEnum.CLOSED);
@@ -152,13 +187,14 @@ public class StudentController extends BaseController {
                     vo.setUserStatus(UserStatusEnum.NORMAL);
                 }
             }
+            vo.setTenantGroupName(tenantGroupIdNameMap.getOrDefault(vo.getTenantGroupId(), ""));
         }
         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"}, rows);
+                    "isVip.msg", "createTime", "userStatus.msg", "tenantName", "tenantGroupName"}, rows);
             response.setContentType("application/octet-stream");
             response.setHeader("Content-Disposition", "attac:wq" +
                     "hment;filename=学生列表-" + DateUtil.getDate(new Date()) + ".xls");

+ 3 - 2
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TeacherController.java

@@ -218,9 +218,10 @@ 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"}, rows);
+                    "entryAuthDate","userStatus.msg", "isVip.code == 1 ? '是' : '否'", "tag", "tenantName",
+                    "tenantGroupName"}, rows);
             response.setContentType("application/octet-stream");
             response.setHeader("Content-Disposition", "attac:wq" +
                     "hment;filename=老师列表-" + DateUtil.getDate(new Date()) + ".xls");

+ 147 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TenantAlbumCategoryController.java

@@ -0,0 +1,147 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.response.template.R;
+import com.yonge.cooleshow.admin.io.request.TenantAlbumCategoryVo;
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategory;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategoryDetail;
+import com.yonge.cooleshow.biz.dal.service.SysUserService;
+import com.yonge.cooleshow.biz.dal.service.TenantAlbumCategoryDetailService;
+import com.yonge.cooleshow.biz.dal.service.TenantAlbumCategoryService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumCategoryWrapper;
+import com.yonge.toolset.base.exception.BizException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+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;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("${app-config.url.admin:}/tenantAlbumCategory")
+@Api(tags = "机构专辑分类")
+public class TenantAlbumCategoryController {
+
+    @Autowired
+    private TenantAlbumCategoryService tenantAlbumCategoryService;
+
+    @Autowired
+    private TenantAlbumCategoryDetailService tenantAlbumCategoryDetailService;
+
+    @Resource
+    private SysUserFeignService sysUserFeignService;
+
+    @Autowired
+    private SysUserService sysUserService;
+
+    @ApiOperation(value = "详情", notes = "机构专辑分类-根据详情ID查询单条, 传入id")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbumCategory/detail', {'BACKEND'})")
+    @GetMapping("/detail/{id}")
+    public R<TenantAlbumCategoryWrapper.TenantAlbumCategory> detail(@PathVariable("id") Long id) {
+        return R.from(tenantAlbumCategoryService.detail(id));
+    }
+
+    @ApiOperation(value = "查询分页", notes = "机构专辑分类- 传入 TenantAlbumCategoryVo.TenantAlbumCategoryQuery")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbumCategory/page', {'BACKEND'})")
+    @PostMapping("/page")
+    public R<PageInfo<TenantAlbumCategoryVo.TenantAlbumCategory>> page(@RequestBody TenantAlbumCategoryWrapper.TenantAlbumCategoryQuery query) {
+
+        // 查询数据
+        IPage<TenantAlbumCategoryWrapper.TenantAlbumCategory> pages =
+                tenantAlbumCategoryService.selectPage(QueryInfo.getPage(query), query);
+        // 数据类型转换
+        List<TenantAlbumCategoryVo.TenantAlbumCategory> records = JSON.parseArray(JSON.toJSONString(pages.getRecords()),
+                TenantAlbumCategoryVo.TenantAlbumCategory.class);
+
+        if (CollectionUtils.isNotEmpty(records)) {
+            List<Long> updateUserIds =
+                    records.stream().map(TenantAlbumCategoryVo.TenantAlbumCategory::getUpdateBy).distinct().collect(Collectors.toList());
+            Map<Long, com.yonge.cooleshow.biz.dal.entity.SysUser> mapByIds = sysUserService.getMapByIds(updateUserIds);
+            records.forEach(next -> {
+                com.yonge.cooleshow.biz.dal.entity.SysUser sysUser = mapByIds.get(next.getUpdateBy());
+                next.setUpdateUserName(sysUser == null ? "" : sysUser.getUsername());
+
+                List<String> values = next.getValues().stream().map(TenantAlbumCategoryDetail::getValue)
+                        .filter(StringUtils::isNotEmpty).collect(Collectors.toList());
+                next.setTenantAlbumCategoryContent(String.join(",",values));
+            });
+        }
+
+        return R.from(QueryInfo.pageInfo(pages, records));
+    }
+
+    @ApiOperation(value = "新增", notes = "机构专辑分类- 传入 TenantAlbumCategoryVo.TenantAlbumCategory")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbumCategory/save', {'BACKEND'})")
+    @PostMapping("/save")
+    public R<JSONObject> add(@Validated @RequestBody TenantAlbumCategoryVo.TenantAlbumCategory tenantAlbumCategoryVo) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        // 新增数据
+        TenantAlbumCategoryWrapper.TenantAlbumCategory albumCategory =
+                JSON.parseObject(tenantAlbumCategoryVo.jsonString(),
+                        TenantAlbumCategoryWrapper.TenantAlbumCategory.class);
+        albumCategory.setCreateBy(sysUser.getId());
+        albumCategory.setUpdateBy(sysUser.getId());
+        tenantAlbumCategoryService.add(albumCategory);
+
+        return R.defaultR();
+    }
+
+    @ApiOperation(value = "修改", notes = "机构专辑分类- 传入 TenantAlbumCategoryVo.TenantAlbumCategory")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbumCategory/update', {'BACKEND'})")
+    @PostMapping("/update")
+    public R<JSONObject> update(@Validated @RequestBody TenantAlbumCategoryVo.TenantAlbumCategory tenantAlbumCategoryVo) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        // 更新数据
+        TenantAlbumCategoryWrapper.TenantAlbumCategory albumCategory =
+                JSON.parseObject(tenantAlbumCategoryVo.jsonString(),
+                        TenantAlbumCategoryWrapper.TenantAlbumCategory.class);
+        albumCategory.setUpdateBy(sysUser.getId());
+        tenantAlbumCategoryService.update(albumCategory);
+
+        return R.defaultR();
+    }
+
+    @ApiOperation(value = "删除", notes = "机构专辑分类- 传入id")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbumCategory/remove', {'BACKEND'})")
+    @PostMapping("/remove")
+    public R<Boolean> remove(@RequestParam Long id) {
+
+        return R.from(tenantAlbumCategoryService.delete(id));
+    }
+
+    @ApiOperation(value = "获取专辑分类值列表")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbumCategory/queryCategoryValue', {'BACKEND'})")
+    @GetMapping("/queryCategoryValue")
+    public R<List<TenantAlbumCategoryDetail>> queryCategoryValue(@RequestParam("id") Long id) {
+        TenantAlbumCategory albumCategory = tenantAlbumCategoryService.getById(id);
+        if (albumCategory == null) {
+            throw new BizException("专辑分类不存在");
+        }
+        List<TenantAlbumCategoryDetail> detailList = tenantAlbumCategoryDetailService.lambdaQuery()
+                .eq(TenantAlbumCategoryDetail::getTenantAlbumCategoryId, id)
+                .list();
+        return R.from(detailList);
+    }
+}

+ 43 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TenantGroupController.java

@@ -0,0 +1,43 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.response.template.R;
+import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupWrapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+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.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("${app-config.url.admin:}/tenantGroup")
+@Api(tags = "机构小组表")
+public class TenantGroupController {
+
+    @Autowired
+    private TenantGroupService tenantGroupService;
+
+    @ApiOperation(value = "查询分页", notes = "机构小组表- 传入 TenantGroupWrapper.TenantGroupQuery")
+    @PreAuthorize("@pcs.hasPermissions('tenantGroup/page', {'BACKEND'})")
+    @PostMapping("/page")
+    public R<PageInfo<TenantGroupWrapper.TenantGroup>> page(@RequestBody TenantGroupWrapper.TenantGroupQuery query) {
+        return R.from(QueryInfo.pageInfo(tenantGroupService.selectPage(QueryInfo.getPage(query), query)));
+    }
+
+    @ApiOperation(value = "处理机构小组交接", notes = "处理机构小组交接")
+    @PreAuthorize("@pcs.hasPermissions('tenantGroup/adjustTenantGroup', {'BACKEND'})")
+    @PostMapping("/adjustTenantGroup")
+    public R<Boolean> adjustTenantGroup(@RequestBody TenantGroupWrapper.AdjustTenantGroup adjustTenantGroup) {
+        return R.from(tenantGroupService.adjustTenantGroup(adjustTenantGroup));
+    }
+
+}

+ 39 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/open/OpenTenantGroupController.java

@@ -0,0 +1,39 @@
+package com.yonge.cooleshow.admin.controller.open;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.response.template.R;
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupWrapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("{app-config.url.admin:}/open/tenantGroup")
+@Api(tags = "机构小组表")
+public class OpenTenantGroupController {
+
+    @Autowired
+    private TenantGroupService tenantGroupService;
+
+    @ApiOperation(value = "查询分页", notes = "机构小组表- 传入 TenantGroupWrapper.TenantGroupQuery")
+    @PostMapping("/page")
+    public R<PageInfo<TenantGroupWrapper.TenantGroup>> page(@RequestBody TenantGroupWrapper.TenantGroupQuery query) {
+        IPage<TenantGroupWrapper.TenantGroup> pages = tenantGroupService.selectPage(QueryInfo.getPage(query), query);
+        return R.from(QueryInfo.pageInfo(pages));
+    }
+}

+ 62 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/TenantAlbumCategoryDetailVo.java

@@ -0,0 +1,62 @@
+package com.yonge.cooleshow.admin.io.request;
+
+import com.alibaba.fastjson.JSON;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import lombok.Data;
+
+/**
+ * 机构专辑分类详情
+ * 2023-10-10 10:17:38
+ */
+@ApiModel(value = "TenantAlbumCategoryDetailVo对象", description = "机构专辑分类详情查询视图对象")
+public class TenantAlbumCategoryDetailVo {
+
+    @Data
+    @ApiModel(" TenantAlbumCategoryDetailQuery-机构专辑分类详情")
+    public static class TenantAlbumCategoryDetailQuery implements QueryInfo {
+
+        @ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static TenantAlbumCategoryDetailQuery from(String json) {
+            return JSON.parseObject(json, TenantAlbumCategoryDetailQuery.class);
+        }
+    }
+
+    @Data
+    @ApiModel(" TenantAlbumCategoryDetail-机构专辑分类详情")
+    public static class TenantAlbumCategoryDetail {
+
+
+        @ApiModelProperty("主键ID")
+        private Long id;
+
+
+        @ApiModelProperty("机构专辑分类ID")
+        private Long tenantAlbumCategoryId;
+
+
+        @ApiModelProperty("级别/类别")
+        private String value;
+
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static TenantAlbumCategoryDetail from(String json) {
+            return JSON.parseObject(json, TenantAlbumCategoryDetail.class);
+        }
+    }
+
+}

+ 93 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/TenantAlbumCategoryVo.java

@@ -0,0 +1,93 @@
+package com.yonge.cooleshow.admin.io.request;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategoryDetail;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumCategoryDetailWrapper;
+import com.yonge.cooleshow.common.enums.ETenantAlbumCategoryType;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import lombok.Data;
+
+/**
+ * 机构专辑分类
+ * 2023-10-10 09:48:46
+ */
+@ApiModel(value = "TenantAlbumCategoryVo对象", description = "机构专辑分类查询视图对象")
+public class TenantAlbumCategoryVo {
+
+    @Data
+    @ApiModel(" TenantAlbumCategoryQuery-机构专辑分类")
+    public static class TenantAlbumCategoryQuery implements QueryInfo {
+
+        @ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static TenantAlbumCategoryQuery from(String json) {
+            return JSON.parseObject(json, TenantAlbumCategoryQuery.class);
+        }
+    }
+
+    @Data
+    @ApiModel(" TenantAlbumCategory-机构专辑分类")
+    public static class TenantAlbumCategory {
+
+
+        @ApiModelProperty("主键ID")
+        private Long id;
+
+
+        @ApiModelProperty("专辑分类名称")
+        private String name;
+
+        @ApiModelProperty("创建人")
+        private Long createBy;
+
+        @ApiModelProperty("创建时间")
+        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+        private Date createTime;
+
+        @ApiModelProperty("修改人")
+        private Long updateBy;
+
+        @ApiModelProperty("修改人")
+        private String updateUserName;
+
+        @ApiModelProperty("更新时间")
+        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+        private Date updateTime;
+
+
+        @ApiModelProperty("专辑分类类别,CATEGORY_TYPE:类型,CATEGORY_LEVEL:级别")
+        private ETenantAlbumCategoryType categoryType;
+
+        @ApiModelProperty("专辑分类级别/类别值")
+        private List<TenantAlbumCategoryDetail> values = new ArrayList<>();
+
+        @ApiModelProperty("专辑分类级别/类别值内容")
+        private String tenantAlbumCategoryContent;
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static TenantAlbumCategory from(String json) {
+            return JSON.parseObject(json, TenantAlbumCategory.class);
+        }
+    }
+
+}

+ 6 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/TenantAlbumVo.java

@@ -63,6 +63,12 @@ public class TenantAlbumVo {
         @ApiModelProperty("曲目相关信息")
         private List<MusicSheetData> musicSheetData = new ArrayList<>();
 
+        @ApiModelProperty("专辑分类类型ID")
+        private Long categoryTypeId;
+
+        @ApiModelProperty("专辑分类等级ID")
+        private Long categoryLevelId;
+
         public String jsonString() {
             return JSON.toJSONString(this);
         }

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

@@ -75,6 +75,9 @@ public class TaskController extends BaseController {
     @Autowired
     private ImGroupService imGroupService;
 
+    @Autowired
+    private UserTenantAlbumRecordService userTenantAlbumRecordService;
+
     /***
      * 轮询用户订单
      * @author liweifan
@@ -231,4 +234,16 @@ public class TaskController extends BaseController {
     }
 
 
+    /**
+     * 机构学生训练教材过期
+     */
+    @GetMapping("/sendTenantAlbumMessage")
+    public HttpResponseResult<Object> sendTenantAlbumMessage() {
+
+        // 群发消息定时
+        userTenantAlbumRecordService.sendTenantAlbumMessage();
+
+        return HttpResponseResult.succeed();
+    }
+
 }

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

@@ -7,10 +7,12 @@ import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.ImGroupResultDto;
 import com.yonge.cooleshow.biz.dal.dto.ImGroupSearchDto;
 import com.yonge.cooleshow.biz.dal.entity.ImGroup;
+import com.yonge.cooleshow.biz.dal.entity.ImGroupMember;
 import com.yonge.cooleshow.biz.dal.entity.ImUserFriend;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
 import com.yonge.cooleshow.biz.dal.enums.MK;
+import com.yonge.cooleshow.biz.dal.service.ImGroupMemberService;
 import com.yonge.cooleshow.biz.dal.service.ImGroupService;
 import com.yonge.cooleshow.biz.dal.service.ImUserFriendService;
 import com.yonge.cooleshow.biz.dal.service.SysUserService;
@@ -61,6 +63,9 @@ public class ImGroupController extends BaseController {
     @Autowired
     private ImUserFriendService imUserFriendService;
 
+    @Autowired
+    private ImGroupMemberService imGroupMemberService;
+
     @ApiOperation("获取群详情")
     @PostMapping(value = "/getDetail/{groupId}")
     public HttpResponseResult<ImGroup> getDetail(@ApiParam(value = "群编号", required = true) @PathVariable("groupId") String groupId) throws Exception {
@@ -76,6 +81,14 @@ public class ImGroupController extends BaseController {
         if (group == null) {
             return failed(HttpStatus.NO_CONTENT, "群组不存在");
         }
+        ImGroupMember admin = imGroupMemberService.lambdaQuery()
+                .eq(ImGroupMember::getGroupId, group.getId())
+                .eq(ImGroupMember::getUserId, sysUserService.getUser().getId())
+                .last("limit 1").one();
+        if (admin == null) {
+            // 该用户不在该群,无权限查看,处理用户退出群后,查看历史消息校验
+            return failed(HttpStatus.NO_CONTENT, "群组不存在");
+        }
         return succeed(group);
     }
 
@@ -108,7 +121,7 @@ public class ImGroupController extends BaseController {
     @PostMapping(value = "/quit/{groupId}")
     public HttpResponseResult quit(@ApiParam(value = "群编号", required = true) @PathVariable("groupId") String groupId,
                                    @RequestParam(value = "quit",required = false,defaultValue = "false") boolean quit
-                                   ) throws Exception {
+    ) throws Exception {
         imGroupService.quit(groupId,sysUserService.getUserId(), ClientEnum.STUDENT, quit);
         return succeed();
     }

+ 1 - 11
cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/SysMessageController.java

@@ -2,7 +2,6 @@ package com.yonge.cooleshow.student.controller;
 
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
-import com.yonge.cooleshow.biz.dal.dao.AppVersionInfoDao;
 import com.yonge.cooleshow.biz.dal.dto.search.SysMessageQueryInfo;
 import com.yonge.cooleshow.biz.dal.entity.SysMessage;
 import com.yonge.cooleshow.biz.dal.enums.MessageSendMode;
@@ -19,12 +18,7 @@ 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.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
 
@@ -35,13 +29,9 @@ public class SysMessageController extends BaseController {
 
 	@Autowired
 	private SysMessageService sysMessageService;
-
 	@Autowired
 	private SysUserFeignService sysUserFeignService;
 
-	@Autowired
-	private AppVersionInfoDao appVersionInfoDao;
-
 	@ApiOperation("获取所有消息列表")
 	@PostMapping(value = "list")
 	public HttpResponseResult<PageInfo<SysMessage>> list(@RequestBody SysMessageQueryInfo queryInfo){

+ 35 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/student/controller/open/OpenTenantGroupController.java

@@ -0,0 +1,35 @@
+package com.yonge.cooleshow.student.controller.open;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.response.template.R;
+import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupWrapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("${app-config.url.student:}/open/tenantGroup")
+@Api(tags = "机构小组表")
+public class OpenTenantGroupController {
+
+    @Autowired
+    private TenantGroupService tenantGroupService;
+
+    @ApiOperation(value = "查询分页", notes = "机构小组表- 传入 TenantGroupWrapper.TenantGroupQuery")
+    @PostMapping("/page")
+    public R<PageInfo<TenantGroupWrapper.TenantGroup>> page(@RequestBody TenantGroupWrapper.TenantGroupQuery query) {
+        IPage<TenantGroupWrapper.TenantGroup> pages = tenantGroupService.selectPage(QueryInfo.getPage(query), query);
+        return R.from(QueryInfo.pageInfo(pages));
+    }
+}

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

@@ -5,10 +5,12 @@ import com.alibaba.fastjson.JSON;
 import com.yonge.cooleshow.biz.dal.dto.ImGroupResultDto;
 import com.yonge.cooleshow.biz.dal.dto.ImGroupSearchDto;
 import com.yonge.cooleshow.biz.dal.entity.ImGroup;
+import com.yonge.cooleshow.biz.dal.entity.ImGroupMember;
 import com.yonge.cooleshow.biz.dal.entity.ImUserFriend;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
 import com.yonge.cooleshow.biz.dal.enums.MK;
+import com.yonge.cooleshow.biz.dal.service.ImGroupMemberService;
 import com.yonge.cooleshow.biz.dal.service.ImGroupService;
 import com.yonge.cooleshow.biz.dal.service.ImUserFriendService;
 import com.yonge.cooleshow.biz.dal.service.SysUserService;
@@ -32,6 +34,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
 import javax.validation.Valid;
 import java.util.HashSet;
 import java.util.List;
@@ -51,14 +54,17 @@ public class ImGroupController extends BaseController {
     /**
      * 服务对象
      */
-    @Autowired
+    @Resource
     private ImGroupService imGroupService;
-    @Autowired
+    @Resource
     private SysUserService sysUserService;
 
     @Autowired
     private ImUserFriendService imUserFriendService;
 
+    @Autowired
+    private ImGroupMemberService imGroupMemberService;
+
     @ApiOperation("创建群聊")
     @PostMapping(value = "/create")
     public HttpResponseResult create(@Valid @RequestBody ImGroupWrapper.ImGroup imGroup, BindingResult bindingResult) throws Exception {
@@ -123,7 +129,7 @@ public class ImGroupController extends BaseController {
     @PostMapping(value = "/quit/{groupId}")
     public HttpResponseResult quit(@ApiParam(value = "群编号", required = true) @PathVariable("groupId") String groupId,
                                    @RequestParam(value = "quit",required = false, defaultValue = "false") boolean quit
-                                   ) throws Exception {
+    ) throws Exception {
         imGroupService.quit(groupId, sysUserService.getUserId(), ClientEnum.TEACHER, quit);
         return succeed();
     }
@@ -135,6 +141,14 @@ public class ImGroupController extends BaseController {
         if (group == null) {
             return failed(HttpStatus.NO_CONTENT, "群组不存在");
         }
+        ImGroupMember admin = imGroupMemberService.lambdaQuery()
+                .eq(ImGroupMember::getGroupId, group.getId())
+                .eq(ImGroupMember::getUserId, sysUserService.getUser().getId())
+                .last("limit 1").one();
+        if (admin == null) {
+            // 该用户不在该群,无权限查看,处理用户退出群后,查看历史消息校验
+            return failed(HttpStatus.NO_CONTENT, "群组不存在");
+        }
         return succeed(group);
     }
 

+ 23 - 1
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/StudentController.java

@@ -4,9 +4,12 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentSearch;
+import com.yonge.cooleshow.biz.dal.entity.Student;
+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.TenantGroupService;
 import com.yonge.cooleshow.biz.dal.vo.StudentVo;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
@@ -29,7 +32,10 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 @RestController
 @RequestMapping("${app-config.url.teacher:}/student")
@@ -41,9 +47,13 @@ public class StudentController extends BaseController {
     @Resource
     private SysUserFeignService sysUserFeignService;
 
-
     @Autowired
     private ImGroupService imGroupService;
+
+    @Autowired
+    private TenantGroupService tenantGroupService;
+
+
     @ApiOperation(value = "查询指定学员信息-融云token")
     @GetMapping("/queryUserById")
     public HttpResponseResult<StudentVo> queryUserById(String rongCloudUserId) {
@@ -106,6 +116,17 @@ public class StudentController extends BaseController {
         IPage<StudentVo> pages = studentService.selectPage(PageUtil.getPage(query), query);
         List<StudentVo> rows = pages.getRecords();
 
+        List<Long> tenantGroupIds = rows.stream().map(Student::getTenantGroupId)
+                .filter(next -> next != null && next != -1L).distinct().collect(Collectors.toList());
+        Map<Long, String> tenantGroupIdNameMap = new HashMap<>();
+        if (!tenantGroupIds.isEmpty()) {
+            Map<Long, String> tenantGroupMap = tenantGroupService.lambdaQuery()
+                    .eq(TenantGroup::getTenantId, tenantId)
+                    .in(TenantGroup::getId, tenantGroupIds)
+                    .list().stream().collect(Collectors.toMap(TenantGroup::getId, TenantGroup::getName));
+            tenantGroupIdNameMap.putAll(tenantGroupMap);
+        }
+
         for (StudentVo vo : rows) {
             if (vo.getDelFlag() == YesOrNoEnum.YES) {
                 vo.setUserStatus(UserStatusEnum.CLOSED);
@@ -117,6 +138,7 @@ public class StudentController extends BaseController {
                 }
             }
             vo.setImUserId(imGroupService.getImUserId(vo.getUserId(), ClientEnum.STUDENT));
+            vo.setTenantGroupName(tenantGroupIdNameMap.getOrDefault(vo.getTenantGroupId(), ""));
         }
         return succeed(PageUtil.pageInfo(pages));
     }

+ 46 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/TenantGroupController.java

@@ -0,0 +1,46 @@
+package com.yonge.cooleshow.teacher.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.response.template.R;
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupWrapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("${app-config.url.teacher:}/tenantGroup")
+@Api(tags = "机构小组表")
+public class TenantGroupController {
+
+    @Autowired
+    private TenantGroupService tenantGroupService;
+
+    @Resource
+    private SysUserFeignService sysUserFeignService;
+
+    @ApiOperation(value = "查询分页", notes = "机构小组表- 传入 TenantGroupWrapper.TenantGroupQuery")
+    @PostMapping("/page")
+    public R<PageInfo<TenantGroupWrapper.TenantGroup>> page(@RequestBody TenantGroupWrapper.TenantGroupQuery query) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        query.setTenantId(sysUser.getTenantId());
+        IPage<TenantGroupWrapper.TenantGroup> pages = tenantGroupService.selectPage(QueryInfo.getPage(query), query);
+
+        return R.from(QueryInfo.pageInfo(pages));
+    }
+
+}

+ 63 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/controller/open/OpenSubjectController.java

@@ -0,0 +1,63 @@
+package com.yonge.cooleshow.teacher.controller.open;
+
+import com.yonge.cooleshow.biz.dal.entity.Subject;
+import com.yonge.cooleshow.biz.dal.queryInfo.SubjectQueryInfo;
+import com.yonge.cooleshow.biz.dal.service.SubjectService;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.toolset.base.page.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@RequestMapping("${app-config.url.teacher:}/open/subject")
+@Api(tags = "声部服务")
+@RestController
+public class OpenSubjectController extends BaseController {
+
+    @Autowired
+    private SubjectService subjectService;
+
+    @ApiOperation(value = "根据声部编号查询声部")
+    @GetMapping("/get/{id}")
+    public Object get(@ApiParam(value = "声部编号", required = true) @PathVariable("id") Long id) {
+        return succeed(subjectService.get(id));
+    }
+
+    @ApiOperation(value = "分页查询声部树状列表")
+    @PostMapping("/queryPageTree")
+    public HttpResponseResult<PageInfo<Subject>> queryPageTree(@RequestBody SubjectQueryInfo queryInfo) {
+        return succeed(subjectService.queryPageTree(queryInfo));
+    }
+
+    @ApiOperation(value = "分页查询声部列表")
+    @GetMapping("/queryPage")
+    public HttpResponseResult<PageInfo<Subject>> queryPage(SubjectQueryInfo queryInfo) {
+        PageInfo<Subject> pageInfo = subjectService.queryPage(queryInfo);
+
+        if (pageInfo.getRows().size() == 0) {
+            return succeed(pageInfo);
+        }
+
+        Map<Long, Subject> map =
+                subjectService.findBySubjectByIdList(pageInfo.getRows().stream().map(Subject::getParentSubjectId).collect(Collectors.toList())).stream()
+                .collect(Collectors.toMap(Subject::getId, t -> t));
+
+        pageInfo.getRows().forEach(row -> {
+            if (row.getParentSubjectId() != null && row.getParentSubjectId() > 0) {
+                row.setParentSubjectName(map.get(row.getParentSubjectId()).getName());
+            }
+        });
+        return succeed(pageInfo);
+    }
+}

+ 10 - 4
cooleshow-app/src/main/java/com/yonge/cooleshow/teacher/task/TaskController.java

@@ -1,10 +1,7 @@
 package com.yonge.cooleshow.teacher.task;
 
 import com.yonge.cooleshow.biz.dal.entity.TeacherTotal;
-import com.yonge.cooleshow.biz.dal.service.CourseGroupService;
-import com.yonge.cooleshow.biz.dal.service.CourseScheduleService;
-import com.yonge.cooleshow.biz.dal.service.LiveRoomService;
-import com.yonge.cooleshow.biz.dal.service.TeacherTotalService;
+import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import io.swagger.annotations.ApiOperation;
@@ -33,6 +30,8 @@ public class TaskController extends BaseController {
     @Autowired
     private LiveRoomService liveRoomService;
 
+    @Autowired
+    private DivBackRecordService divBackRecordService;
 
     /***
      * 查询所有老师统计数据
@@ -89,4 +88,11 @@ public class TaskController extends BaseController {
         scheduleService.teacherSalaryTask();
         return HttpResponseResult.succeed();
     }
+
+
+    @GetMapping("/divBack")
+    public HttpResponseResult<Object> divBack() {
+        divBackRecordService.divBack();
+        return HttpResponseResult.succeed();
+    }
 }

+ 72 - 4
cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/IndexController.java

@@ -5,12 +5,11 @@ import com.microsvc.toolkit.common.webportal.exception.BizException;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.queryInfo.SysMusicCompareRecordQueryInfo;
-import com.yonge.cooleshow.biz.dal.service.PaymentDivMemberRecordService;
-import com.yonge.cooleshow.biz.dal.service.SysMusicCompareRecordService;
-import com.yonge.cooleshow.biz.dal.service.TenantPersonStatService;
-import com.yonge.cooleshow.biz.dal.service.UserOrderService;
+import com.yonge.cooleshow.biz.dal.service.*;
+import com.yonge.cooleshow.biz.dal.wrapper.OssFileWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.PaymentDivMemberRecordWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantPersonStatWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.teacher.TeacherWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.toolset.base.page.PageInfo;
@@ -24,7 +23,11 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 @Api(tags = "首页统计")
 @RequestMapping("${app-config.url.tenant:}/index")
@@ -41,6 +44,8 @@ public class IndexController extends BaseController {
     private PaymentDivMemberRecordService paymentDivMemberRecordService;
     @Autowired
     private UserOrderService userOrderService;
+    @Autowired
+    private OssFileService ossFileService;
 
 
     @ApiOperation("学员训练数据统计列表")
@@ -58,6 +63,39 @@ public class IndexController extends BaseController {
         return succeed(sysMusicCompareRecordService.weChatStudentTrainData(queryInfo));
     }
 
+    @ApiOperation("导出学员训练数据统计列表")
+    @PostMapping("exportStudentTrainData")
+    public HttpResponseResult<OssFileWrapper.ExportFile> exportStudentTrainData
+            (@RequestBody SysMusicCompareRecordQueryInfo.WechatCompareRecordQueryInfo queryInfo){
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        if (sysUser == null) {
+            return failed("获取用户信息失败");
+        }
+        if(StringUtils.isEmpty(queryInfo.getStartTime())){
+            throw new BizException("请选择筛选时间");
+        }
+        queryInfo.setTenantId(sysUser.getTenantId());
+        List<SysMusicCompareRecordQueryInfo.WechatCompareRecordPageDto> rows = sysMusicCompareRecordService.weChatStudentTrainData(queryInfo).getRows();
+        if (rows.isEmpty()) {
+            throw new BizException("没有可导出数据");
+        }
+
+        List<SysMusicCompareRecordQueryInfo.WechatCompareRecordExportDto> templates = rows.stream().map(next -> {
+            SysMusicCompareRecordQueryInfo.WechatCompareRecordExportDto template = new SysMusicCompareRecordQueryInfo.WechatCompareRecordExportDto();
+            template.setUsername(next.getUsername());
+            template.setSubjectName(next.getSubjectName());
+            template.setAvgTrainTimes(next.getAvgTrainTimes());
+            template.setTrainTimes(next.getTrainTimes());
+            template.setTrainDays(next.getTrainDays());
+            return template;
+        }).collect(Collectors.toList());
+
+        String format = new SimpleDateFormat("yyyyMMddHHmm").format(new Date());
+        OssFileWrapper.ExportFile exportFile = ossFileService.uploadFile(templates,
+                SysMusicCompareRecordQueryInfo.WechatCompareRecordExportDto.class, format, "练习统计列表");
+        return succeed(exportFile);
+    }
+
 
     @ApiOperation("首页学员训练数据统计列表、汇总")
     @PostMapping("studentTrainData")
@@ -125,6 +163,36 @@ public class IndexController extends BaseController {
         return succeed(PageUtil.pageInfo(paymentDivMemberRecordService.queryIncome(QueryInfo.getPage(query), query)));
     }
 
+    @ApiOperation("导出收入明细列表")
+    @PostMapping("exportIncome")
+    public HttpResponseResult<OssFileWrapper.ExportFile>
+    exportIncome(@RequestBody PaymentDivMemberRecordWrapper.IndexIncomeQuery query){
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        if (sysUser == null) {
+            return failed("获取用户信息失败");
+        }
+        query.setTenantId(sysUser.getTenantId());
+        List<PaymentDivMemberRecordWrapper.IndexIncomeQueryDto> rows = paymentDivMemberRecordService.queryIncome(QueryInfo.getPage(query), query).getRecords();
+        if (rows.isEmpty()) {
+            throw new BizException("没有可导出数据");
+        }
+
+        List<PaymentDivMemberRecordWrapper.IndexIncomeExportDto> templates = rows.stream().map(next -> {
+            PaymentDivMemberRecordWrapper.IndexIncomeExportDto template = new PaymentDivMemberRecordWrapper.IndexIncomeExportDto();
+            template.setName(next.getName());
+            template.setPhone(next.getPhone());
+            template.setAmount(next.getAmount());
+            template.setPayTime(next.getPayTime());
+            template.setOrderType(next.getOrderType().getName());
+            return template;
+        }).collect(Collectors.toList());
+
+        String format = new SimpleDateFormat("yyyyMMddHHmm").format(new Date());
+        OssFileWrapper.ExportFile exportFile = ossFileService.uploadFile(templates,
+                TeacherWrapper.ExportTeacherTemplate.class, format, "练习统计列表");
+        return succeed(exportFile);
+    }
+
     @ApiOperation("收入订单详情")
     @PostMapping("getIncomeOrderDetail")
     public HttpResponseResult<PaymentDivMemberRecordWrapper.OrderDetailDto> getIncomeOrderDetail(String orderNo){

+ 83 - 10
cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/StudentController.java

@@ -7,14 +7,18 @@ 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.TenantActivationCode;
+import com.yonge.cooleshow.biz.dal.entity.TenantGroup;
 import com.yonge.cooleshow.biz.dal.entity.TenantInfo;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.ImUserFriendService;
+import com.yonge.cooleshow.biz.dal.service.OssFileService;
 import com.yonge.cooleshow.biz.dal.service.StudentService;
 import com.yonge.cooleshow.biz.dal.service.TeacherService;
 import com.yonge.cooleshow.biz.dal.service.TenantActivationCodeService;
+import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
 import com.yonge.cooleshow.biz.dal.service.TenantInfoService;
 import com.yonge.cooleshow.biz.dal.vo.StudentVo;
+import com.yonge.cooleshow.biz.dal.wrapper.OssFileWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.StudentWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
@@ -44,7 +48,10 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.annotation.Resource;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -58,22 +65,28 @@ public class StudentController extends BaseController {
 
     @Autowired
     private StudentService studentService;
-    @Autowired
-    private TeacherService teacherService;
-    @Autowired
+    @Resource
     private SysUserFeignService sysUserFeignService;
     @Autowired
-    private ImUserFriendService imUserFriendService;
-    @Autowired
     private TenantInfoService tenantInfoService;
 
     @Autowired
     private TenantActivationCodeService tenantActivationCodeService;
 
+    @Autowired
+    private OssFileService ossFileService;
+
+    @Autowired
+    private TenantGroupService tenantGroupService;
+
     @GetMapping("/detail/{id}")
     @ApiOperation(value = "详情", notes = "传入id")
     public HttpResponseResult<StudentVo> detail(@PathVariable("id") Long id) {
         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);
     }
 
@@ -89,11 +102,15 @@ public class StudentController extends BaseController {
         IPage<StudentVo> pages = studentService.selectPage(PageUtil.getPage(query), query);
         List<StudentVo> rows = pages.getRecords();
 
+        if (rows.isEmpty()) {
+            return succeed(PageUtil.pageInfo(pages));
+        }
+
         //如果真实姓名字段为空 把真实姓名赋值给昵称
-        rows.stream().forEach(r->{
-            if (StringUtils.isEmpty(r.getRealName())){
+        rows.stream().forEach(r -> {
+            if (StringUtils.isEmpty(r.getRealName())) {
                 if (StringUtils.isNotEmpty(r.getUsername()))
-                r.setRealName(r.getUsername());
+                    r.setRealName(r.getUsername());
             }
         });
 
@@ -102,11 +119,22 @@ public class StudentController extends BaseController {
         if (!rows.isEmpty() && query.getTenantAlbumPurchaseId() != null) {
             List<String> studentPhones =
                     rows.stream().map(StudentVo::getPhone).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
-             groupByPhone = tenantActivationCodeService.lambdaQuery()
-                    .eq(TenantActivationCode::getId, query.getTenantAlbumPurchaseId())
+            groupByPhone = tenantActivationCodeService.lambdaQuery()
+                    .eq(TenantActivationCode::getTenantAlbumPurchaseId, query.getTenantAlbumPurchaseId())
                     .in(TenantActivationCode::getActivationPhone, studentPhones)
                     .list().stream().collect(Collectors.groupingBy(TenantActivationCode::getActivationPhone));
         }
+        List<Long> tenantGroupIds = rows.stream().map(Student::getTenantGroupId)
+                .filter(next -> next != null && next != -1L).distinct().collect(Collectors.toList());
+        Map<Long, String> tenantGroupIdNameMap = new HashMap<>();
+        if (!tenantGroupIds.isEmpty()) {
+            Map<Long, String> tenantGroupMap = tenantGroupService.lambdaQuery()
+                    .eq(TenantGroup::getTenantId, tenantInfo.getId())
+                    .in(TenantGroup::getId, tenantGroupIds)
+                    .list().stream().collect(Collectors.toMap(TenantGroup::getId, TenantGroup::getName));
+            tenantGroupIdNameMap.putAll(tenantGroupMap);
+        }
+
 
         for (StudentVo vo : rows) {
             vo.setSendActiveCodeNum(groupByPhone.getOrDefault(vo.getPhone(), new ArrayList<>()).size());
@@ -122,10 +150,55 @@ public class StudentController extends BaseController {
                     vo.setUserStatus(UserStatusEnum.NORMAL);
                 }
             }
+            vo.setTenantGroupName(tenantGroupIdNameMap.getOrDefault(vo.getTenantGroupId(), ""));
         }
         return succeed(PageUtil.pageInfo(pages));
     }
 
+    @PostMapping("/exportStudent")
+    @ApiOperation(value = "导出学生", notes = "传入TeacherSearch")
+    public HttpResponseResult<OssFileWrapper.ExportFile> exportTeacher(@RequestBody StudentSearch query) {
+        TenantInfo tenantInfo = getTenantInfo();
+        query.setTenantId(tenantInfo.getId());
+        query.setDelFlag(YesOrNoEnum.NO);
+        query.setLockFlag(UserLockFlag.NORMAL);
+        query.setOrderBy("u.username_ asc");
+        query.setPage(1);
+        query.setRows(9999);
+
+        IPage<StudentVo> pages = studentService.selectPage(PageUtil.getPage(query), query);
+        List<StudentVo> rows = pages.getRecords();
+
+        if (rows.isEmpty()) {
+            throw new BizException("没有可导出数据");
+        }
+
+        List<Long> tenantGroupIds = rows.stream().map(Student::getTenantGroupId)
+                .filter(next -> next != null && next != -1L).distinct().collect(Collectors.toList());
+        Map<Long, String> tenantGroupIdNameMap = new HashMap<>();
+        if (!tenantGroupIds.isEmpty()) {
+            Map<Long, String> tenantGroupMap = tenantGroupService.lambdaQuery()
+                    .eq(TenantGroup::getTenantId, tenantInfo.getId())
+                    .in(TenantGroup::getId, tenantGroupIds)
+                    .list().stream().collect(Collectors.toMap(TenantGroup::getId, TenantGroup::getName));
+            tenantGroupIdNameMap.putAll(tenantGroupMap);
+        }
+
+        List<StudentWrapper.ExportStudentTemplate> templateList = rows.stream().map(next -> {
+            StudentWrapper.ExportStudentTemplate template = new StudentWrapper.ExportStudentTemplate();
+            template.setUserName(next.getUsername());
+            template.setPhone(next.getPhone());
+            template.setSubjectName(next.getSubjectName());
+            template.setTenantGroupName(tenantGroupIdNameMap.getOrDefault(next.getTenantGroupId(), ""));
+            return template;
+        }).collect(Collectors.toList());
+
+        String format = new SimpleDateFormat("yyyyMMddHHmm").format(new Date());
+        OssFileWrapper.ExportFile exportFile = ossFileService.uploadFile(templateList,
+                StudentWrapper.ExportStudentTemplate.class, format, "学生");
+        return succeed(exportFile);
+    }
+
     @PostMapping("/save")
     @ApiOperation(value = "新增/修改", notes = "传入Student")
     public HttpResponseResult<Boolean> save(

+ 8 - 7
cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/SysMusicCompareRecordController.java

@@ -10,8 +10,8 @@ import com.yonge.toolset.base.page.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -29,7 +29,7 @@ public class SysMusicCompareRecordController extends BaseController {
     @ApiOperation("学生端学员评测记录")
     @PostMapping("queryStudentTrain")
     public HttpResponseResult<PageInfo<SysMusicCompareRecordQueryInfo.StudentMusicCompareRecord>>
-    queryStudentTrain(SysMusicCompareRecordQueryInfo.StudentMusicCompareRecordQuery query){
+    queryStudentTrain(@RequestBody SysMusicCompareRecordQueryInfo.StudentMusicCompareRecordQuery query){
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (sysUser == null) {
             return failed("获取用户信息失败");
@@ -41,7 +41,7 @@ public class SysMusicCompareRecordController extends BaseController {
     @ApiOperation("学员训练统计以及基本信息查询")
     @PostMapping("studentTrainStat")
     public HttpResponseResult<SysMusicCompareRecordQueryInfo.StudentMusicCompareRecordDto>
-    studentTrainStat(SysMusicCompareRecordQueryInfo.StudentMusicCompareRecordQuery query){
+    studentTrainStat(@RequestBody SysMusicCompareRecordQueryInfo.StudentMusicCompareRecordQuery query){
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (sysUser == null) {
             return failed("获取用户信息失败");
@@ -51,8 +51,9 @@ public class SysMusicCompareRecordController extends BaseController {
     }
 
     @ApiOperation("云教练排行榜")
-    @GetMapping("rankingList")
-    public HttpResponseResult<SysMusicCompareRecordQueryInfo.StatDto> rankingList(SysMusicCompareRecordQueryInfo.StudentCompareRecordQueryInfo queryInfo){
+    @PostMapping("rankingList")
+    public HttpResponseResult<SysMusicCompareRecordQueryInfo.StatDto> rankingList(
+            @RequestBody SysMusicCompareRecordQueryInfo.StudentCompareRecordQueryInfo queryInfo){
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (sysUser == null) {
             return failed("获取用户信息失败");
@@ -63,8 +64,8 @@ public class SysMusicCompareRecordController extends BaseController {
     }
 
     @ApiOperation("学员训练数据统计")
-    @GetMapping("studentTrainData")
-    public HttpResponseResult studentTrainData(SysMusicCompareRecordQueryInfo.TeacherCompareRecordQueryInfo queryInfo){
+    @PostMapping("studentTrainData")
+    public HttpResponseResult studentTrainData(@RequestBody SysMusicCompareRecordQueryInfo.TeacherCompareRecordQueryInfo queryInfo){
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (sysUser == null) {
             return failed("获取用户信息失败");

+ 44 - 1
cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/TeacherController.java

@@ -10,9 +10,11 @@ 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.enums.AuthStatusEnum;
+import com.yonge.cooleshow.biz.dal.service.OssFileService;
 import com.yonge.cooleshow.biz.dal.service.TeacherService;
 import com.yonge.cooleshow.biz.dal.service.TenantInfoService;
 import com.yonge.cooleshow.biz.dal.vo.TeacherVo;
+import com.yonge.cooleshow.biz.dal.wrapper.OssFileWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.teacher.TeacherWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
@@ -33,7 +35,10 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
 import javax.validation.Valid;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -45,12 +50,15 @@ public class TeacherController extends BaseController {
     @Autowired
     private TeacherService teacherService;
 
-    @Autowired
+    @Resource
     private SysUserFeignService sysUserFeignService;
 
     @Autowired
     private TenantInfoService tenantInfoService;
 
+    @Autowired
+    private OssFileService ossFileService;
+
     /**
      * 查询单条
      */
@@ -102,6 +110,41 @@ public class TeacherController extends BaseController {
         return succeed(PageUtil.pageInfo(pages));
     }
 
+
+    @PostMapping("/exportTeacher")
+    @ApiOperation(value = "导出老师", notes = "传入TeacherSearch")
+    public HttpResponseResult<OssFileWrapper.ExportFile> exportTeacher(@RequestBody TeacherSearch query) {
+        TenantInfo tenantInfo = getTenantInfo();
+        query.setTenantId(tenantInfo.getId());
+        query.setDelFlag(YesOrNoEnum.NO);
+        query.setLockFlag(UserLockFlag.NORMAL);
+        query.setPage(1);
+        query.setRows(9999);
+        query.setOrderBy("u.username_ asc");
+
+        IPage<TeacherVo> pages = teacherService.selectPage(PageUtil.getPage(query), query);
+        List<TeacherVo> rows = pages.getRecords();
+
+        if (rows.isEmpty()) {
+            throw new BizException("没有可导出数据");
+        }
+
+        List<TeacherWrapper.ExportTeacherTemplate> templates = rows.stream().map(next -> {
+            TeacherWrapper.ExportTeacherTemplate template = new TeacherWrapper.ExportTeacherTemplate();
+            template.setUserName(next.getUsername());
+            template.setPhone(next.getPhone());
+            template.setMusicSheet(next.getMusicSheetName());
+            template.setSubjectName(next.getSubjectName());
+            template.setSettlementFrom(next.getSettlementFrom() == null ? "" : next.getSettlementFrom().getMsg());
+            return template;
+        }).collect(Collectors.toList());
+
+        String format = new SimpleDateFormat("yyyyMMddHHmm").format(new Date());
+        OssFileWrapper.ExportFile exportFile = ossFileService.uploadFile(templates,
+                TeacherWrapper.ExportTeacherTemplate.class, format, "老师");
+        return succeed(exportFile);
+    }
+
     /**
      * 新增或修改
      */

+ 27 - 21
cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/TenantActivationCodeController.java

@@ -16,13 +16,19 @@ import com.microsvc.toolkit.middleware.oss.impl.TencentOssPlugin;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.entity.TenantActivationCode;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbum;
 import com.yonge.cooleshow.biz.dal.entity.TenantAlbumPurchase;
 import com.yonge.cooleshow.biz.dal.entity.TenantInfo;
 import com.yonge.cooleshow.biz.dal.entity.TenantStaff;
+import com.yonge.cooleshow.biz.dal.entity.UserOrder;
+import com.yonge.cooleshow.biz.dal.service.OssFileService;
 import com.yonge.cooleshow.biz.dal.service.TenantActivationCodeService;
 import com.yonge.cooleshow.biz.dal.service.TenantAlbumPurchaseService;
+import com.yonge.cooleshow.biz.dal.service.TenantAlbumService;
 import com.yonge.cooleshow.biz.dal.service.TenantInfoService;
 import com.yonge.cooleshow.biz.dal.service.TenantStaffService;
+import com.yonge.cooleshow.biz.dal.service.UserOrderService;
+import com.yonge.cooleshow.biz.dal.wrapper.OssFileWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantActivationCodeWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
@@ -48,14 +54,13 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.text.MessageFormat;
 import java.text.ParsePosition;
 import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
 
 
 @Slf4j
@@ -71,7 +76,7 @@ public class TenantActivationCodeController extends BaseController {
     @Autowired
     private TenantAlbumPurchaseService tenantAlbumPurchaseService;
 
-    @Autowired
+    @Resource
     private SysUserFeignService sysUserFeignService;
 
     @Autowired
@@ -81,6 +86,12 @@ public class TenantActivationCodeController extends BaseController {
     private TenantStaffService tenantStaffService;
     @Autowired
     private OssPluginContext ossPluginContext;
+    @Autowired
+    private UserOrderService userOrderService;
+    @Autowired
+    private TenantAlbumService tenantAlbumService;
+    @Autowired
+    private OssFileService ossFileService;
 
     @ApiOperation(value = "详情", notes = "机构激活码-根据详情ID查询单条, 传入id")
 //    @GetMapping("/detail/{id}")
@@ -160,33 +171,20 @@ public class TenantActivationCodeController extends BaseController {
     public HttpResponseResult<Boolean> sendCancel(@RequestParam("id") Long id) {
         TenantInfo tenantInfo = getTenantInfo();
         TenantActivationCode activationCode = tenantActivationCodeService.getById(id);
-        if (activationCode == null || !tenantInfo.getId().equals(activationCode.getTenantId())) {
-            throw new BizException("激活码不存在");
-        }
-        boolean update = tenantActivationCodeService.lambdaUpdate()
-                .set(TenantActivationCode::getSendStatus, EActivationCode.WAIT)
-                .set(TenantActivationCode::getActivationPhone, "")
-                .eq(TenantActivationCode::getId, id)
-                .eq(TenantActivationCode::getActivationStatus, false)
-                .eq(TenantActivationCode::getSendStatus, EActivationCode.SEND)
-                .update();
-        if (!update) {
-            throw new BizException("激活码已经激活");
-        }
+        tenantActivationCodeService.sendCancel(tenantInfo, activationCode);
         return succeed();
     }
 
     @ApiOperation(value = "批量激活码发放取消", notes = "传入 激活码的ID")
     @PostMapping("/batchSendCancel")
     public HttpResponseResult<Boolean> batchSendCancel(@RequestParam("ids") String ids) {
-        TenantInfo tenantInfo = getTenantInfo();
-        tenantActivationCodeService.batchSendCancel(tenantInfo, ids);
+        tenantActivationCodeService.batchSendCancel(getTenantInfo(), ids);
         return succeed();
     }
 
     @GetMapping("/exportActiveCode")
     @ApiOperation(value = "导出模板")
-    public HttpResponseResult<TenantActivationCodeWrapper.ExportFile> exportActiveCode(HttpServletResponse response, String orderNo) {
+    public HttpResponseResult<OssFileWrapper.ExportFile> exportActiveCode(HttpServletResponse response, String orderNo) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (sysUser == null) {
             throw new BizException("请登录");
@@ -212,7 +210,15 @@ public class TenantActivationCodeController extends BaseController {
         List<TenantActivationCodeWrapper.ExportTemplate> templates = JSONArray.parseArray(JSON.toJSONString(rows), TenantActivationCodeWrapper.ExportTemplate.class);
         templates.forEach(next->next.setActivationPhone(""));
 
-        TenantActivationCodeWrapper.ExportFile exportFile = generateExportExcelFile(templates, TenantActivationCodeWrapper.ExportTemplate.class, "激活码导出", "激活码");
+        TenantAlbumPurchase tenantAlbumPurchase = tenantAlbumPurchaseService.getById(Long.valueOf(orderNo));
+        TenantAlbum tenantAlbum = tenantAlbumService.getById(tenantAlbumPurchase.getTenantAlbumId());
+        UserOrder userOrder = userOrderService.getByOrderNo(tenantAlbumPurchase.getOrderNo());
+
+        String format = new SimpleDateFormat("yyyyMMddHHmm").format(userOrder.getCreateTime());
+
+
+        OssFileWrapper.ExportFile exportFile = ossFileService.uploadFile(templates,
+                TenantActivationCodeWrapper.ExportTemplate.class, format + tenantAlbum.getName(), "激活码");
         return succeed(exportFile);
     }
 

+ 131 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/TenantGroupController.java

@@ -0,0 +1,131 @@
+package com.yonge.cooleshow.tenant.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.response.template.R;
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.entity.ImGroup;
+import com.yonge.cooleshow.biz.dal.entity.TenantGroup;
+import com.yonge.cooleshow.biz.dal.service.ImGroupService;
+import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupWrapper;
+import com.yonge.cooleshow.tenant.vo.TenantGroupVo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+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;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("${app-config.url.tenant:}/tenantGroup")
+@Api(tags = "机构小组表")
+public class TenantGroupController {
+
+    @Autowired
+    private TenantGroupService tenantGroupService;
+
+    @Resource
+    private SysUserFeignService sysUserFeignService;
+
+    @Autowired
+    private ImGroupService imGroupService;
+
+    @ApiOperation(value = "详情", notes = "机构小组表-根据详情ID查询单条, 传入id")
+    @GetMapping("/detail/{id}")
+    public R<TenantGroupWrapper.TenantGroup> detail(@PathVariable("id") Long id) {
+        TenantGroup wrapper = tenantGroupService.detail(id);
+        if (wrapper == null) {
+            return R.from(new TenantGroupWrapper.TenantGroup());
+        }
+        TenantGroupWrapper.TenantGroup group = TenantGroupWrapper.TenantGroup.from(JSON.toJSONString(wrapper));
+        group.setImGroupExist(false);
+        if (StringUtils.isNotEmpty(wrapper.getImGroupId())) {
+            ImGroup imGroup = imGroupService.getById(wrapper.getImGroupId());
+            if (imGroup != null) {
+                group.setImGroupExist(true);
+            }
+        }
+        List<TenantGroupWrapper.TenantGroupMember> members =
+                tenantGroupService.queryGroupMember(wrapper.getTenantId(), id);
+        List<Long> userIds = members.stream().map(TenantGroupWrapper.TenantGroupMember::getUserId)
+                .collect(Collectors.toList());
+        group.setUserIds(userIds);
+        group.setGroupUserCount(members.size());
+        group.setUserList(members);
+        return R.from(group);
+    }
+
+    @ApiOperation(value = "查询机构群成员", notes = "查询机构群成员")
+    @GetMapping("/queryGroupMember/{tenantGroupId}")
+    public R<List<TenantGroupWrapper.TenantGroupMember>> queryGroupMember(@PathVariable("tenantGroupId") Long tenantGroupId) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        return R.from(tenantGroupService.queryGroupMember(sysUser.getTenantId(), tenantGroupId));
+    }
+
+    @ApiOperation(value = "查询分页", notes = "机构小组表- 传入 TenantGroupWrapper.TenantGroupQuery")
+    @PostMapping("/page")
+    public R<PageInfo<TenantGroupWrapper.TenantGroup>> page(@RequestBody TenantGroupWrapper.TenantGroupQuery query) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        query.setTenantId(sysUser.getTenantId());
+        IPage<TenantGroupWrapper.TenantGroup> pages = tenantGroupService.selectPage(QueryInfo.getPage(query), query);
+
+        return R.from(QueryInfo.pageInfo(pages));
+    }
+
+    @ApiOperation(value = "新增", notes = "机构小组表- 传入 TenantGroupWrapper.TenantGroup")
+    @PostMapping("/save")
+    public R<JSONObject> add(@Validated @RequestBody TenantGroupVo.TenantGroup tenantGroup) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        TenantGroupWrapper.TenantGroup group = TenantGroupWrapper.TenantGroup.from(tenantGroup.jsonString());
+        group.setCreateBy(sysUser.getId());
+        group.setTenantId(sysUser.getTenantId());
+        // 新增数据
+        tenantGroupService.add(group, tenantGroup.getImGroupCreate());
+
+        return R.defaultR();
+    }
+
+    @ApiOperation(value = "修改", notes = "机构小组表- 传入 TenantGroupWrapper.TenantGroup")
+    @PostMapping("/update")
+    public R<JSONObject> update(@Validated @RequestBody TenantGroupVo.TenantGroup tenantGroup) {
+        // 更新数据
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        TenantGroupWrapper.TenantGroup group = TenantGroupWrapper.TenantGroup.from(tenantGroup.jsonString());
+        group.setCreateBy(sysUser.getId());
+        group.setTenantId(sysUser.getTenantId());
+        tenantGroupService.update(group, tenantGroup.getImGroupCreate());
+
+        return R.defaultR();
+    }
+
+    @ApiOperation(value = "删除", notes = "机构小组表- 传入id")
+    @PostMapping("/remove")
+    public R<Boolean> remove(@RequestParam Long id) {
+
+        return R.from(tenantGroupService.delete(id));
+    }
+
+    @ApiOperation(value = "处理机构小组交接", notes = "处理机构小组交接")
+    @PostMapping("/adjustTenantGroup")
+    public R<Boolean> adjustTenantGroup(@RequestBody TenantGroupWrapper.AdjustTenantGroup adjustTenantGroup) {
+        return R.from(tenantGroupService.adjustTenantGroup(adjustTenantGroup));
+    }
+}

+ 10 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/open/OpenStudentController.java

@@ -4,8 +4,10 @@ import com.alibaba.fastjson.JSON;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.entity.Student;
+import com.yonge.cooleshow.biz.dal.entity.TenantGroup;
 import com.yonge.cooleshow.biz.dal.entity.TenantInfo;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+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.ImUserFriendService;
@@ -62,6 +64,9 @@ public class OpenStudentController extends BaseController {
     @Autowired
     private ImGroupMemberService imGroupMemberService;
 
+    @Autowired
+    private TenantGroupMapper tenantGroupMapper;
+
     @PostMapping("/save")
     @ApiOperation(value = "新增/修改", notes = "传入Student,换绑时按照返回错误码5004判断,是否需要换绑,updateTenant=true表示换绑")
     public HttpResponseResult<Boolean> save(@Validated @RequestBody StudentVo.Student student) {
@@ -80,6 +85,11 @@ public class OpenStudentController extends BaseController {
         if (tenantInfo == null) {
             throw new BizException("机构不存在");
         }
+        Long tenantGroupId = student.getTenantGroupId();
+        TenantGroup tenantGroup = tenantGroupMapper.selectById(tenantGroupId);
+        if (tenantGroup == null) {
+            throw new BizException("该链接已失效");
+        }
         Long studentId = student.getId();
 
         if (studentId == null) {

+ 35 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/open/OpenTenantGroupController.java

@@ -0,0 +1,35 @@
+package com.yonge.cooleshow.tenant.controller.open;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.response.template.R;
+import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupWrapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("${app-config.url.tenant:}/open/tenantGroup")
+@Api(tags = "机构小组表")
+public class OpenTenantGroupController {
+
+    @Autowired
+    private TenantGroupService tenantGroupService;
+
+    @ApiOperation(value = "查询分页", notes = "机构小组表- 传入 TenantGroupWrapper.TenantGroupQuery")
+    @PostMapping("/page")
+    public R<PageInfo<TenantGroupWrapper.TenantGroup>> page(@RequestBody TenantGroupWrapper.TenantGroupQuery query) {
+        IPage<TenantGroupWrapper.TenantGroup> pages = tenantGroupService.selectPage(QueryInfo.getPage(query), query);
+        return R.from(QueryInfo.pageInfo(pages));
+    }
+}

+ 3 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/vo/StudentVo.java

@@ -22,6 +22,9 @@ public class StudentVo {
         @ApiModelProperty("所属机构,开放接口必填")
         private Long tenantId;
 
+        @ApiModelProperty("机构小组ID")
+        private Long tenantGroupId;
+
         @ApiModelProperty("姓名")
         @NotNull
         private String name;

+ 72 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/vo/TenantGroupVo.java

@@ -0,0 +1,72 @@
+package com.yonge.cooleshow.tenant.vo;
+
+import com.alibaba.fastjson.JSON;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 机构小组表
+ * 2023-10-11 09:24:50
+ */
+@ApiModel(value = "TenantGroupVo对象", description = "机构小组表查询视图对象")
+public class TenantGroupVo {
+
+    @Data
+    @ApiModel(" TenantGroupQuery-机构小组表")
+    public static class TenantGroupQuery implements QueryInfo {
+
+        @ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static TenantGroupQuery from(String json) {
+            return JSON.parseObject(json, TenantGroupQuery.class);
+        }
+    }
+
+    @Data
+    @ApiModel(" TenantGroup-机构小组表")
+    public static class TenantGroup {
+
+        @ApiModelProperty("主键ID")
+        private Long id;
+
+        @ApiModelProperty("机构ID")
+        private Long tenantId;
+
+        @ApiModelProperty("小组名称")
+        @NotNull(message = "小组名称不能为空")
+        private String name;
+
+        @ApiModelProperty("小组负责人")
+        @NotNull(message = "小组负责人不能为空")
+        private Long adminId;
+
+        @ApiModelProperty("群成员列表")
+        private List<Long> userIds = new ArrayList<>();
+
+        @ApiModelProperty("是否创建群聊")
+        private Boolean imGroupCreate = false;
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static TenantGroup from(String json) {
+            return JSON.parseObject(json, TenantGroup.class);
+        }
+    }
+
+}

+ 29 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/ETenantAlbumCategoryType.java

@@ -0,0 +1,29 @@
+package com.yonge.cooleshow.common.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+
+public enum ETenantAlbumCategoryType implements BaseEnum<String, ETenantAlbumCategoryType> {
+
+    CATEGORY_TYPE("类型"),
+    CATEGORY_LEVEL("级别"),
+    ;
+
+    @EnumValue
+    private String code;
+    private String msg;
+
+    ETenantAlbumCategoryType(String msg) {
+        this.code = this.name();
+        this.msg = msg;
+    }
+
+    @Override
+    public String getCode() {
+        return this.code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+}

+ 1 - 0
cooleshow-gateway/gateway-web/src/main/java/com/yonge/gateway/web/config/SwaggerDocumentConfig.java

@@ -29,6 +29,7 @@ public class SwaggerDocumentConfig implements SwaggerResourcesProvider {
 		resources.add(swaggerResource("MALL_PORTAL服务", "/mall-portal-server/v2/api-docs", "2.0"));
 		resources.add(swaggerResource("网络教室", "/classroom-server/v2/api-docs", "2.0"));
 		resources.add(swaggerResource("TENANT服务", "/tenant-server/v2/api-docs", "2.0"));
+		resources.add(swaggerResource("App服务", "/app-server/v2/api-docs", "2.0"));
 		return resources;
 	}
 

+ 20 - 0
cooleshow-task/src/main/java/com/yonge/cooleshow/task/jobs/DivBackTask.java

@@ -0,0 +1,20 @@
+package com.yonge.cooleshow.task.jobs;
+
+import com.yonge.cooleshow.api.feign.AdminFeignService;
+import com.yonge.cooleshow.api.feign.TeacherFeignService;
+import com.yonge.cooleshow.task.core.BaseTask;
+import com.yonge.cooleshow.task.core.TaskException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class DivBackTask extends BaseTask {
+
+    @Autowired
+    private TeacherFeignService teacherFeignService;
+
+    @Override
+    public void execute() throws TaskException {
+        Object o = teacherFeignService.divBack();
+    }
+}

+ 19 - 0
cooleshow-task/src/main/java/com/yonge/cooleshow/task/jobs/SendTenantAlbumMessageTask.java

@@ -0,0 +1,19 @@
+package com.yonge.cooleshow.task.jobs;
+
+import com.yonge.cooleshow.api.feign.AdminFeignService;
+import com.yonge.cooleshow.task.core.BaseTask;
+import com.yonge.cooleshow.task.core.TaskException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class SendTenantAlbumMessageTask extends BaseTask {
+
+    @Autowired
+    private AdminFeignService adminFeignService;
+
+    @Override
+    public void execute() throws TaskException {
+        Object o = adminFeignService.sendTenantAlbumMessage();
+    }
+}

+ 37 - 2
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/StudentController.java

@@ -7,9 +7,11 @@ import com.yonge.cooleshow.biz.dal.dto.VipSubmitReq;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.VipRecordSearch;
 import com.yonge.cooleshow.biz.dal.entity.Student;
+import com.yonge.cooleshow.biz.dal.entity.TenantGroup;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.MemberPriceSettingsService;
 import com.yonge.cooleshow.biz.dal.service.StudentService;
+import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
 import com.yonge.cooleshow.biz.dal.service.VipCardRecordService;
 import com.yonge.cooleshow.biz.dal.vo.StudentVo;
 import com.yonge.cooleshow.biz.dal.vo.VipRecordVo;
@@ -47,7 +49,10 @@ import javax.validation.Valid;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 @RestController
 @RequestMapping("/student")
@@ -65,6 +70,9 @@ public class StudentController extends BaseController {
     @Autowired
     private VipCardRecordService vipCardRecordService;
 
+    @Autowired
+    private TenantGroupService tenantGroupService;
+
     @GetMapping("/detail/{id}")
     @ApiOperation(value = "详情", notes = "传入id")
     @ApiImplicitParams({
@@ -73,6 +81,10 @@ public class StudentController extends BaseController {
     @PreAuthorize("@pcs.hasPermissions('student/detail')")
     public HttpResponseResult<StudentVo> detail(@PathVariable("id") Long id) {
         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);
     }
 
@@ -101,6 +113,17 @@ public class StudentController extends BaseController {
         IPage<StudentVo> pages = studentService.selectPage(PageUtil.getPage(query), query);
         List<StudentVo> rows = pages.getRecords();
 
+        List<Long> tenantGroupIds = rows.stream().map(Student::getTenantGroupId)
+                .filter(next -> next != null && next != -1L).distinct().collect(Collectors.toList());
+        Map<Long, String> tenantGroupIdNameMap = new HashMap<>();
+        if(!tenantGroupIds.isEmpty()){
+            Map<Long, String> tenantGroupMap = tenantGroupService.lambdaQuery()
+                    .in(TenantGroup::getId, tenantGroupIds)
+                    .list().stream().collect(Collectors.toMap(TenantGroup::getId, TenantGroup::getName));
+            tenantGroupIdNameMap.putAll(tenantGroupMap);
+        }
+
+
         for (StudentVo vo : rows) {
             if (vo.getDelFlag() == YesOrNoEnum.YES) {
                 vo.setUserStatus(UserStatusEnum.CLOSED);
@@ -111,6 +134,7 @@ public class StudentController extends BaseController {
                     vo.setUserStatus(UserStatusEnum.NORMAL);
                 }
             }
+            vo.setTenantGroupName(tenantGroupIdNameMap.getOrDefault(vo.getTenantGroupId(), ""));
         }
         return succeed(PageUtil.pageInfo(pages));
     }
@@ -143,6 +167,16 @@ public class StudentController extends BaseController {
             throw new BizException("没有可导出数据");
         }
 
+        List<Long> tenantGroupIds = rows.stream().map(Student::getTenantGroupId)
+                .filter(next -> next != null && next != -1L).distinct().collect(Collectors.toList());
+        Map<Long, String> tenantGroupIdNameMap = new HashMap<>();
+        if (!tenantGroupIds.isEmpty()) {
+            Map<Long, String> tenantGroupMap = tenantGroupService.lambdaQuery()
+                    .in(TenantGroup::getId, tenantGroupIds)
+                    .list().stream().collect(Collectors.toMap(TenantGroup::getId, TenantGroup::getName));
+            tenantGroupIdNameMap.putAll(tenantGroupMap);
+        }
+
         for (StudentVo vo : rows) {
             if (vo.getDelFlag() == YesOrNoEnum.YES) {
                 vo.setUserStatus(UserStatusEnum.CLOSED);
@@ -153,13 +187,14 @@ public class StudentController extends BaseController {
                     vo.setUserStatus(UserStatusEnum.NORMAL);
                 }
             }
+            vo.setTenantGroupName(tenantGroupIdNameMap.getOrDefault(vo.getTenantGroupId(), ""));
         }
         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"}, rows);
+                    "isVip.msg", "createTime", "userStatus.msg", "tenantName", "tenantGroupName"}, rows);
             response.setContentType("application/octet-stream");
             response.setHeader("Content-Disposition", "attac:wq" +
                     "hment;filename=学生列表-" + DateUtil.getDate(new Date()) + ".xls");

+ 3 - 2
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TeacherController.java

@@ -223,9 +223,10 @@ 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"}, rows);
+                    "entryAuthDate","userStatus.msg", "isVip.code == 1 ? '是' : '否'", "tag", "tenantName",
+                    "tenantGroupName"}, rows);
             response.setContentType("application/octet-stream");
             response.setHeader("Content-Disposition", "attac:wq" +
                     "hment;filename=老师列表-" + DateUtil.getDate(new Date()) + ".xls");

+ 149 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantAlbumCategoryController.java

@@ -0,0 +1,149 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.response.template.R;
+import com.yonge.cooleshow.admin.io.request.TenantAlbumCategoryVo;
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategory;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategoryDetail;
+import com.yonge.cooleshow.biz.dal.service.SysUserService;
+import com.yonge.cooleshow.biz.dal.service.TenantAlbumCategoryDetailService;
+import com.yonge.cooleshow.biz.dal.service.TenantAlbumCategoryService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumCategoryWrapper;
+import com.yonge.toolset.base.exception.BizException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+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;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/tenantAlbumCategory")
+@Api(tags = "机构专辑分类")
+public class TenantAlbumCategoryController {
+
+    @Autowired
+    private TenantAlbumCategoryService tenantAlbumCategoryService;
+
+    @Autowired
+    private TenantAlbumCategoryDetailService tenantAlbumCategoryDetailService;
+
+    @Resource
+    private SysUserFeignService sysUserFeignService;
+
+    @Autowired
+    private SysUserService sysUserService;
+
+    @ApiOperation(value = "详情", notes = "机构专辑分类-根据详情ID查询单条, 传入id")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbumCategory/detail', {'BACKEND'})")
+    @GetMapping("/detail/{id}")
+    public R<TenantAlbumCategoryWrapper.TenantAlbumCategory> detail(@PathVariable("id") Long id) {
+        return R.from(tenantAlbumCategoryService.detail(id));
+    }
+
+    @ApiOperation(value = "查询分页", notes = "机构专辑分类- 传入 TenantAlbumCategoryVo.TenantAlbumCategoryQuery")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbumCategory/page', {'BACKEND'})")
+    @PostMapping("/page")
+    public R<PageInfo<TenantAlbumCategoryVo.TenantAlbumCategory>> page(@RequestBody TenantAlbumCategoryWrapper.TenantAlbumCategoryQuery query) {
+
+        // 查询数据
+        IPage<TenantAlbumCategoryWrapper.TenantAlbumCategory> pages =
+                tenantAlbumCategoryService.selectPage(QueryInfo.getPage(query), query);
+        // 数据类型转换
+        List<TenantAlbumCategoryVo.TenantAlbumCategory> records = JSON.parseArray(JSON.toJSONString(pages.getRecords()),
+                TenantAlbumCategoryVo.TenantAlbumCategory.class);
+
+        if (CollectionUtils.isNotEmpty(records)) {
+            List<Long> updateUserIds =
+                    records.stream().map(TenantAlbumCategoryVo.TenantAlbumCategory::getUpdateBy).distinct().collect(Collectors.toList());
+            Map<Long, com.yonge.cooleshow.biz.dal.entity.SysUser> mapByIds = sysUserService.getMapByIds(updateUserIds);
+            records.forEach(next -> {
+                com.yonge.cooleshow.biz.dal.entity.SysUser sysUser = mapByIds.get(next.getUpdateBy());
+                next.setUpdateUserName(sysUser == null ? "" : sysUser.getUsername());
+
+                List<String> values = next.getValues().stream().map(TenantAlbumCategoryDetail::getValue)
+                        .filter(StringUtils::isNotEmpty).collect(Collectors.toList());
+                next.setTenantAlbumCategoryContent(String.join(",",values));
+            });
+        }
+
+        return R.from(QueryInfo.pageInfo(pages, records));
+    }
+
+    @ApiOperation(value = "新增", notes = "机构专辑分类- 传入 TenantAlbumCategoryVo.TenantAlbumCategory")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbumCategory/save', {'BACKEND'})")
+    @PostMapping("/save")
+    public R<JSONObject> add(@Validated @RequestBody TenantAlbumCategoryVo.TenantAlbumCategory tenantAlbumCategoryVo) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        // 新增数据
+        TenantAlbumCategoryWrapper.TenantAlbumCategory albumCategory =
+                JSON.parseObject(tenantAlbumCategoryVo.jsonString(),
+                        TenantAlbumCategoryWrapper.TenantAlbumCategory.class);
+        albumCategory.setCreateBy(sysUser.getId());
+        albumCategory.setUpdateBy(sysUser.getId());
+        tenantAlbumCategoryService.add(albumCategory);
+
+        return R.defaultR();
+    }
+
+    @ApiOperation(value = "修改", notes = "机构专辑分类- 传入 TenantAlbumCategoryVo.TenantAlbumCategory")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbumCategory/update', {'BACKEND'})")
+    @PostMapping("/update")
+    public R<JSONObject> update(@Validated @RequestBody TenantAlbumCategoryVo.TenantAlbumCategory tenantAlbumCategoryVo) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        // 更新数据
+        TenantAlbumCategoryWrapper.TenantAlbumCategory albumCategory =
+                JSON.parseObject(tenantAlbumCategoryVo.jsonString(),
+                        TenantAlbumCategoryWrapper.TenantAlbumCategory.class);
+        albumCategory.setUpdateBy(sysUser.getId());
+        tenantAlbumCategoryService.update(albumCategory);
+
+        return R.defaultR();
+    }
+
+    @ApiOperation(value = "删除", notes = "机构专辑分类- 传入id")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbumCategory/remove', {'BACKEND'})")
+    @PostMapping("/remove")
+    public R<Boolean> remove(@RequestParam Long id) {
+
+        return R.from(tenantAlbumCategoryService.delete(id));
+    }
+
+    @ApiOperation(value = "获取专辑分类值列表")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbumCategory/queryCategoryValue', {'BACKEND'})")
+    @GetMapping("/queryCategoryValue")
+    public R<List<TenantAlbumCategoryDetail>> queryCategoryValue(@RequestParam("id") Long id) {
+        TenantAlbumCategory albumCategory = tenantAlbumCategoryService.getById(id);
+        if (albumCategory == null) {
+            throw new BizException("专辑分类不存在");
+        }
+        List<TenantAlbumCategoryDetail> detailList = tenantAlbumCategoryDetailService.lambdaQuery()
+                .eq(TenantAlbumCategoryDetail::getTenantAlbumCategoryId, id)
+                .list();
+        return R.from(detailList);
+    }
+}

+ 43 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantGroupController.java

@@ -0,0 +1,43 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.response.template.R;
+import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupWrapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+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.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/tenantGroup")
+@Api(tags = "机构小组表")
+public class TenantGroupController {
+
+    @Autowired
+    private TenantGroupService tenantGroupService;
+
+    @ApiOperation(value = "查询分页", notes = "机构小组表- 传入 TenantGroupWrapper.TenantGroupQuery")
+    @PreAuthorize("@pcs.hasPermissions('tenantGroup/page', {'BACKEND'})")
+    @PostMapping("/page")
+    public R<PageInfo<TenantGroupWrapper.TenantGroup>> page(@RequestBody TenantGroupWrapper.TenantGroupQuery query) {
+        return R.from(QueryInfo.pageInfo(tenantGroupService.selectPage(QueryInfo.getPage(query), query)));
+    }
+
+    @ApiOperation(value = "处理机构小组交接", notes = "处理机构小组交接")
+    @PreAuthorize("@pcs.hasPermissions('tenantGroup/adjustTenantGroup', {'BACKEND'})")
+    @PostMapping("/adjustTenantGroup")
+    public R<Boolean> adjustTenantGroup(@RequestBody TenantGroupWrapper.AdjustTenantGroup adjustTenantGroup) {
+        return R.from(tenantGroupService.adjustTenantGroup(adjustTenantGroup));
+    }
+
+}

+ 35 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/OpenTenantGroupController.java

@@ -0,0 +1,35 @@
+package com.yonge.cooleshow.admin.controller.open;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.response.template.R;
+import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupWrapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/open/tenantGroup")
+@Api(tags = "机构小组表")
+public class OpenTenantGroupController {
+
+    @Autowired
+    private TenantGroupService tenantGroupService;
+
+    @ApiOperation(value = "查询分页", notes = "机构小组表- 传入 TenantGroupWrapper.TenantGroupQuery")
+    @PostMapping("/page")
+    public R<PageInfo<TenantGroupWrapper.TenantGroup>> page(@RequestBody TenantGroupWrapper.TenantGroupQuery query) {
+        IPage<TenantGroupWrapper.TenantGroup> pages = tenantGroupService.selectPage(QueryInfo.getPage(query), query);
+        return R.from(QueryInfo.pageInfo(pages));
+    }
+}

+ 62 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/io/request/TenantAlbumCategoryDetailVo.java

@@ -0,0 +1,62 @@
+package com.yonge.cooleshow.admin.io.request;
+
+import com.alibaba.fastjson.JSON;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import lombok.Data;
+
+/**
+ * 机构专辑分类详情
+ * 2023-10-10 10:17:38
+ */
+@ApiModel(value = "TenantAlbumCategoryDetailVo对象", description = "机构专辑分类详情查询视图对象")
+public class TenantAlbumCategoryDetailVo {
+
+    @Data
+    @ApiModel(" TenantAlbumCategoryDetailQuery-机构专辑分类详情")
+    public static class TenantAlbumCategoryDetailQuery implements QueryInfo {
+
+        @ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static TenantAlbumCategoryDetailQuery from(String json) {
+            return JSON.parseObject(json, TenantAlbumCategoryDetailQuery.class);
+        }
+    }
+
+    @Data
+    @ApiModel(" TenantAlbumCategoryDetail-机构专辑分类详情")
+    public static class TenantAlbumCategoryDetail {
+
+
+        @ApiModelProperty("主键ID")
+        private Long id;
+
+
+        @ApiModelProperty("机构专辑分类ID")
+        private Long tenantAlbumCategoryId;
+
+
+        @ApiModelProperty("级别/类别")
+        private String value;
+
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static TenantAlbumCategoryDetail from(String json) {
+            return JSON.parseObject(json, TenantAlbumCategoryDetail.class);
+        }
+    }
+
+}

+ 93 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/io/request/TenantAlbumCategoryVo.java

@@ -0,0 +1,93 @@
+package com.yonge.cooleshow.admin.io.request;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategoryDetail;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumCategoryDetailWrapper;
+import com.yonge.cooleshow.common.enums.ETenantAlbumCategoryType;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import lombok.Data;
+
+/**
+ * 机构专辑分类
+ * 2023-10-10 09:48:46
+ */
+@ApiModel(value = "TenantAlbumCategoryVo对象", description = "机构专辑分类查询视图对象")
+public class TenantAlbumCategoryVo {
+
+    @Data
+    @ApiModel(" TenantAlbumCategoryQuery-机构专辑分类")
+    public static class TenantAlbumCategoryQuery implements QueryInfo {
+
+        @ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static TenantAlbumCategoryQuery from(String json) {
+            return JSON.parseObject(json, TenantAlbumCategoryQuery.class);
+        }
+    }
+
+    @Data
+    @ApiModel(" TenantAlbumCategory-机构专辑分类")
+    public static class TenantAlbumCategory {
+
+
+        @ApiModelProperty("主键ID")
+        private Long id;
+
+
+        @ApiModelProperty("专辑分类名称")
+        private String name;
+
+        @ApiModelProperty("创建人")
+        private Long createBy;
+
+        @ApiModelProperty("创建时间")
+        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+        private Date createTime;
+
+        @ApiModelProperty("修改人")
+        private Long updateBy;
+
+        @ApiModelProperty("修改人")
+        private String updateUserName;
+
+        @ApiModelProperty("更新时间")
+        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+        private Date updateTime;
+
+
+        @ApiModelProperty("专辑分类类别,CATEGORY_TYPE:类型,CATEGORY_LEVEL:级别")
+        private ETenantAlbumCategoryType categoryType;
+
+        @ApiModelProperty("专辑分类级别/类别值")
+        private List<TenantAlbumCategoryDetail> values = new ArrayList<>();
+
+        @ApiModelProperty("专辑分类级别/类别值内容")
+        private String tenantAlbumCategoryContent;
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static TenantAlbumCategory from(String json) {
+            return JSON.parseObject(json, TenantAlbumCategory.class);
+        }
+    }
+
+}

+ 6 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/io/request/TenantAlbumVo.java

@@ -66,6 +66,12 @@ public class TenantAlbumVo {
         @ApiModelProperty("原价")
         private BigDecimal costPrice;
 
+        @ApiModelProperty("专辑分类类型ID")
+        private Long categoryTypeId;
+
+        @ApiModelProperty("专辑分类等级ID")
+        private Long categoryLevelId;
+
         @ApiModelProperty("曲目相关信息")
         private List<MusicSheetData> musicSheetData = new ArrayList<>();
 

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

@@ -90,6 +90,9 @@ public class TaskController extends BaseController {
     @Autowired
     private LiveRoomService liveRoomService;
 
+    @Autowired
+    private UserTenantAlbumRecordService userTenantAlbumRecordService;
+
     /***
      * 轮询用户订单
      * @author liweifan
@@ -247,4 +250,16 @@ public class TaskController extends BaseController {
 
         }
     }
+
+    /**
+     * 机构学生训练教材过期
+     */
+    @GetMapping("/sendTenantAlbumMessage")
+    public HttpResponseResult<Object> sendTenantAlbumMessage() {
+
+        // 群发消息定时
+        userTenantAlbumRecordService.sendTenantAlbumMessage();
+
+        return HttpResponseResult.succeed();
+    }
 }

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

@@ -11,6 +11,7 @@ import com.yonge.cooleshow.biz.dal.entity.Student;
 import com.yonge.cooleshow.biz.dal.entity.Subject;
 import com.yonge.cooleshow.biz.dal.vo.MyFollow;
 import com.yonge.cooleshow.biz.dal.vo.StudentVo;
+import com.yonge.cooleshow.biz.dal.wrapper.StudentWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantInfoWrapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -72,11 +73,13 @@ public interface StudentDao extends BaseMapper<Student> {
      */
     List<MyFollow> queryMyFollow(@Param("page") IPage page, @Param("param") QueryMyFollowSearch query);
 
-    List<Map<Integer, String>> getStudentSubjectMapList(List<Long> studentIds);
+    List<Map<Integer, String>> getStudentSubjectMapList(@Param("studentIds") List<Long> studentIds);
 
     int countStudentsWithTenant(Map<String, Object> params);
 
     List<TenantInfoWrapper.UserCount> countTeacherByTenantIds(@Param("tenantIdList") List<Long> tenantIdList);
 
     Integer queryStudentCounts(@Param("id") Long id);
+
+    List<StudentWrapper.UserCount> countStudentByTenantGroupIds(@Param("tenantId") Long tenantId, @Param("groupIdList") List<Long> groupIdList);
 }

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

@@ -12,7 +12,7 @@ public interface SysMusicCompareWeekDataDao extends BaseDAO<Integer, SysMusicCom
     SysMusicCompareWeekData getWithUserAndMonday(@Param("userId") Long userId,
                                                  @Param("monday") String monday);
 
-    List<SysMusicCompareRecordQueryInfo.MusicCompareRankingDto> getUserTrainStat(@Param("monday") String monday,
+    List<SysMusicCompareRecordQueryInfo.MusicCompareRankingDto> queryUserTrainStat(@Param("monday") String monday,
                                                                                  @Param("orderType") Integer orderType,
                                                                                  @Param("heardLevel") String heardLevel,
                                                                                  @Param("tenantId") Long tenantId);

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

@@ -25,6 +25,17 @@ public class JumpUrlDto {
     @ApiModelProperty("其它参数")
     private String params ="";
 
+    @ApiModelProperty("客户端")
+    private String clientType ="";
+
+    public String getClientType() {
+        return clientType;
+    }
+
+    public void setClientType(String clientType) {
+        this.clientType = clientType;
+    }
+
     public String getAction() {
         return action;
     }

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

@@ -69,7 +69,7 @@ public class StudentSearch extends QueryInfo{
     private Long tenantId;
 
     @ApiModelProperty("机构小组ID")
-    private Long tenantGroupId = -1L;
+    private String tenantGroupId;
 
     @ApiModelProperty("机构名称")
     private String tenantName;

+ 66 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/DivBackRecord.java

@@ -0,0 +1,66 @@
+package com.yonge.cooleshow.biz.dal.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import lombok.Data;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 分账归还记录
+ * 2023-10-18 10:59:05
+ */
+@Data
+@ApiModel(" DivBackRecord-分账归还记录")
+@TableName("div_back_record")
+public class DivBackRecord implements Serializable {
+
+    @ApiModelProperty("主键") 
+	    @TableId(value = "id_",type = IdType.AUTO)
+	    private Long id;
+
+
+    @ApiModelProperty("支付三方")
+    @TableField(value = "payment_vendor_")
+    private String  paymentVendor;
+
+    @ApiModelProperty("分账记录ID") 
+	@TableField(value = "payment_div_member_record_id_")
+    private Long paymentDivMemberRecordId;
+
+    @ApiModelProperty("分账归还订单号") 
+	@TableField(value = "divide_back_order_no_")
+    private String divideBackOrderNo;
+
+    @ApiModelProperty("分账归还三方号") 
+	@TableField(value = "divide_back_trans_no_")
+    private String divideBackTransNo;
+
+    @ApiModelProperty("分账归还状态") 
+	@TableField(value = "status_")
+    private String status;
+
+    @ApiModelProperty("失败原因") 
+	@TableField(value = "reason_")
+    private String reason;
+
+    @ApiModelProperty("尝试次数")
+    @TableField(value = "times_")
+    private Integer times;
+
+    @ApiModelProperty("创建时间") 
+	@TableField(value = "create_time_")
+    private Date createTime;
+
+    @ApiModelProperty("更新时间") 
+	@TableField(value = "update_time_")
+    private Date updateTime;
+
+}

+ 9 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/PaymentDivMemberRecord.java

@@ -4,11 +4,13 @@ import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.IdType;
+import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
 import java.util.Date;
@@ -21,6 +23,8 @@ import java.math.BigDecimal;
  */
 @Data
 @Builder
+@NoArgsConstructor
+@AllArgsConstructor
 @ApiModel(" PaymentDivMemberRecord-分账子账户记录表")
 @TableName("payment_div_member_record")
 public class PaymentDivMemberRecord implements Serializable {
@@ -54,6 +58,11 @@ public class PaymentDivMemberRecord implements Serializable {
 	@TableField(value = "trans_no_")
     private String transNo;
 
+
+    @ApiModelProperty("分账对象")
+    @TableField(value = "div_member_json_")
+    private String divMemberJson;
+
     @ApiModelProperty("分账金额") 
 	@TableField(value = "amount_")
     private BigDecimal amount;

+ 4 - 136
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/SysMessage.java

@@ -2,6 +2,7 @@ package com.yonge.cooleshow.biz.dal.entity;
 
 import io.swagger.annotations.ApiModelProperty;
 
+import lombok.Data;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 
 import com.yonge.cooleshow.biz.dal.enums.MessageSendMode;
@@ -11,6 +12,7 @@ import com.yonge.cooleshow.common.entity.BaseEntity;
 /**
  * 对应数据库表(sys_message):
  */
+@Data
 public class SysMessage extends BaseEntity {
 
 	/** 主键 */
@@ -75,13 +77,8 @@ public class SysMessage extends BaseEntity {
 	@ApiModelProperty(value = "极光推送客户端标识",required = false)
 	private String clientId;
 
-	public String getClientId() {
-		return clientId;
-	}
-
-	public void setClientId(String clientId) {
-		this.clientId = clientId;
-	}
+	@ApiModelProperty(value = "图标",required = false)
+	private String img;
 
 	public SysMessage() {
 	}
@@ -94,137 +91,8 @@ public class SysMessage extends BaseEntity {
 		this.userId = userId;
 		this.memo = memo;
 	}
-
-	public void setId(Long id){
-		this.id = id;
-	}
-	
-	public Long getId(){
-		return this.id;
-	}
-			
-	public void setTitle(String title){
-		this.title = title;
-	}
-	
-	public String getTitle(){
-		return this.title;
-	}
-			
-	public void setContent(String content){
-		this.content = content;
-	}
-	
-	public String getContent(){
-		return this.content;
-	}
-			
-	public void setReceiver(String receiver){
-		this.receiver = receiver;
-	}
-	
-	public String getReceiver(){
-		return this.receiver;
-	}
-			
-	public void setSendTime(java.util.Date sendTime){
-		this.sendTime = sendTime;
-	}
-	
-	public java.util.Date getSendTime(){
-		return this.sendTime;
-	}
-			
-	public void setErrorMsg(String errorMsg){
-		this.errorMsg = errorMsg;
-	}
-	
-	public String getErrorMsg(){
-		return this.errorMsg;
-	}
-			
-	public void setCreateOn(java.util.Date createOn){
-		this.createOn = createOn;
-	}
-	
-	public java.util.Date getCreateOn(){
-		return this.createOn;
-	}
-			
-	public void setModifyOn(java.util.Date modifyOn){
-		this.modifyOn = modifyOn;
-	}
-	
-	public java.util.Date getModifyOn(){
-		return this.modifyOn;
-	}
-			
-	public void setUserId(Long userId){
-		this.userId = userId;
-	}
-	
-	public Long getUserId(){
-		return this.userId;
-	}
-			
-	public void setMemo(String memo){
-		this.memo = memo;
-	}
-	
-	public String getMemo(){
-		return this.memo;
-	}
-
-	public MessageSendMode getType() {
-		return type;
-	}
-
-	public void setType(MessageSendMode type) {
-		this.type = type;
-	}
-
-	public SendStatusEnum getStatus() {
-		return status;
-	}
-
-	public void setStatus(SendStatusEnum status) {
-		this.status = status;
-	}
-
-	public Integer getReadStatus() {
-		return readStatus;
-	}
-
-	public void setReadStatus(Integer readStatus) {
-		this.readStatus = readStatus;
-	}
-
-	public String getGroup() {
-		return group;
-	}
-
-	public void setGroup(String group) {
-		this.group = group;
-	}
-
 	@Override
 	public String toString() {
 		return ToStringBuilder.reflectionToString(this);
 	}
-
-	public Long getMessageConfigId() {
-		return messageConfigId;
-	}
-
-	public void setMessageConfigId(Long messageConfigId) {
-		this.messageConfigId = messageConfigId;
-	}
-
-	public String getSubType() {
-		return subType;
-	}
-
-	public void setSubType(String subType) {
-		this.subType = subType;
-	}
 }

+ 4 - 103
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/SysMessageConfig.java

@@ -2,6 +2,7 @@ package com.yonge.cooleshow.biz.dal.entity;
 
 import com.yonge.cooleshow.biz.dal.enums.MessageIconTypeEnum;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 
 import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
@@ -9,6 +10,7 @@ import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
 /**
  * 对应数据库表(sys_message_config):
  */
+@Data
 public class SysMessageConfig {
 
 	/**  */
@@ -48,112 +50,11 @@ public class SysMessageConfig {
 	@ApiModelProperty("h5跳转链接")
 	private String actionUrl;
 
-	public String getAction() {
-		return action;
-	}
-
-	public void setAction(String action) {
-		this.action = action;
-	}
-
-	public String getPageTag() {
-		return pageTag;
-	}
-
-	public void setPageTag(String pageTag) {
-		this.pageTag = pageTag;
-	}
-
-	public String getParams() {
-		return params;
-	}
-
-	public void setParams(String params) {
-		this.params = params;
-	}
-
-	public String getActionUrl() {
-		return actionUrl;
-	}
-
-	public void setActionUrl(String actionUrl) {
-		this.actionUrl = actionUrl;
-	}
-
-	public Integer getSendFlag() {
-		return sendFlag;
-	}
-
-	public void setSendFlag(Integer sendFlag) {
-		this.sendFlag = sendFlag;
-	}
-
-	public void setId(Long id) {
-		this.id = id;
-	}
-
-	public Long getId() {
-		return this.id;
-	}
-
-	public MessageTypeEnum getMessageType() {
-		return messageType;
-	}
-
-	public void setMessageType(MessageTypeEnum messageType) {
-		this.messageType = messageType;
-	}
-
-	public void setContent(String content) {
-		this.content = content;
-	}
-
-	public String getContent() {
-		return this.content;
-	}
-
-	public void setDescription(String description) {
-		this.description = description;
-	}
-
-	public String getDescription() {
-		return this.description;
-	}
-
-	public void setModifyOn(java.util.Date modifyOn) {
-		this.modifyOn = modifyOn;
-	}
-
-	public java.util.Date getModifyOn() {
-		return this.modifyOn;
-	}
-
-	public void setUrl(String url) {
-		this.url = url;
-	}
-
-	public String getUrl() {
-		return this.url;
-	}
-
-	public String getGroup() {
-		return group;
-	}
-
-	public void setGroup(String group) {
-		this.group = group;
-	}
+	@ApiModelProperty("图标")
+	private String icon;
 
 	@Override
 	public String toString() {
 		return ToStringBuilder.reflectionToString(this);
 	}
-
-	public MessageIconTypeEnum getSubType() {
-		return subType;
-	}
-
-	public void setSubType(MessageIconTypeEnum subType) {
-		this.subType = subType;
-	}
 }

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

@@ -80,4 +80,12 @@ public class TenantAlbum implements Serializable {
 	@TableField(value = "create_time_")
     private Date createTime;
 
+    @ApiModelProperty("专辑分类类型ID")
+    @TableField(value = "category_type_id_")
+    private Long categoryTypeId;
+
+    @ApiModelProperty("专辑分类等级ID")
+    @TableField(value = "category_level_id_")
+    private Long categoryLevelId;
+
 }

+ 58 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/TenantAlbumCategory.java

@@ -0,0 +1,58 @@
+package com.yonge.cooleshow.biz.dal.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.yonge.cooleshow.common.enums.ETenantAlbumCategoryType;
+import lombok.Data;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 机构专辑分类
+ * 2023-10-10 09:48:46
+ */
+@Data
+@ApiModel(" TenantAlbumCategory-机构专辑分类")
+@TableName("tenant_album_category")
+public class TenantAlbumCategory implements Serializable {
+
+    @ApiModelProperty("主键ID")
+    @TableId(value = "id_", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty("专辑分类名称")
+    @TableField(value = "name_")
+    private String name;
+
+    @ApiModelProperty("专辑分类类别")
+    @TableField(value = "category_type_")
+    private ETenantAlbumCategoryType categoryType;
+
+    @ApiModelProperty("删除标记")
+    @TableField(value = "del_flag_")
+    private Boolean delFlag;
+
+    @ApiModelProperty("创建人")
+    @TableField(value = "create_by_")
+    private Long createBy;
+
+    @ApiModelProperty("创建时间")
+    @TableField(value = "create_time_")
+    private Date createTime;
+
+    @ApiModelProperty("修改人")
+    @TableField(value = "update_by_")
+    private Long updateBy;
+
+    @ApiModelProperty("更新时间")
+    @TableField(value = "update_time_")
+    private Date updateTime;
+
+}

+ 36 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/TenantAlbumCategoryDetail.java

@@ -0,0 +1,36 @@
+package com.yonge.cooleshow.biz.dal.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import lombok.Data;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+
+/**
+ * 机构专辑分类详情
+ * 2023-10-10 10:17:38
+ */
+@Data
+@ApiModel(" TenantAlbumCategoryDetail-机构专辑分类详情")
+@TableName("tenant_album_category_detail")
+public class TenantAlbumCategoryDetail implements Serializable {
+
+    @ApiModelProperty("主键ID")
+    @TableId(value = "id_", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty("机构专辑分类ID")
+    @TableField(value = "tenant_album_category_id_")
+    private Long tenantAlbumCategoryId;
+
+    @ApiModelProperty("级别/类别")
+    @TableField(value = "value_")
+    private String value;
+
+}

+ 53 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/TenantGroup.java

@@ -0,0 +1,53 @@
+package com.yonge.cooleshow.biz.dal.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import lombok.Data;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 机构小组表
+ * 2023-10-11 09:24:50
+ */
+@Data
+@ApiModel(" TenantGroup-机构小组表")
+@TableName("tenant_group")
+public class TenantGroup implements Serializable {
+
+    @ApiModelProperty("主键ID")
+    @TableId(value = "id_", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty("机构ID")
+    @TableField(value = "tenant_id_")
+    private Long tenantId;
+
+    @ApiModelProperty("小组名称")
+    @TableField(value = "name_")
+    private String name;
+
+    @ApiModelProperty("管理员ID")
+    @TableField(value = "admin_id_")
+    private Long adminId;
+
+    @ApiModelProperty("IM群ID")
+    @TableField(value = "im_group_id_")
+    private String imGroupId;
+
+    @ApiModelProperty("创建人")
+    @TableField(value = "create_by_")
+    private Long createBy;
+
+    @ApiModelProperty("创建时间")
+    @TableField(value = "create_time_")
+    private Date createTime;
+
+}

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

@@ -121,6 +121,15 @@ public enum MessageTypeEnum implements BaseEnum<String, MessageTypeEnum> {
 
     // 平台审核提醒
     PLATFORM_AUDIT_UNBIND("平台审核提醒"),
+    TENANT_VIP_BUY("开通平台会员"),
+    TENANT_VIP_EXPIRE("平台会员到期"),
+    TENANT_PLATFORM_ADD_VIP("后台添加平台会员"),
+    TENANT_ALBUM_BUY("购买训练教程"),
+    TENANT_ALBUM_EXPIRE("训练教程到期"),
+    TENANT_SEND_CODE("发放激活码"),
+    TENANT_CODE_SENDCANCEL("激活码被撤回"),
+    TENANT_MUSIC_BUY("购买曲目"),
+    TENANT_STUDENT_CHANGE("机构变更"),
     ;
 
     MessageTypeEnum(String msg) {

+ 27 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/DivBackRecordMapper.java

@@ -0,0 +1,27 @@
+package com.yonge.cooleshow.biz.dal.mapper;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+import com.yonge.cooleshow.biz.dal.entity.DivBackRecord;
+import com.yonge.cooleshow.biz.dal.wrapper.DivBackRecordWrapper;
+
+/**
+ * 分账归还记录
+ * 2023-10-18 10:59:05
+ */
+@Repository
+public interface DivBackRecordMapper extends BaseMapper<DivBackRecord> {
+
+	/**
+	 * 分页查询
+	 * @param page IPage<DivBackRecordWrapper.DivBackRecord>
+	 * @param param DivBackRecordWrapper.DivBackRecordQuery
+	 * @return List<DivBackRecordWrapper.DivBackRecord>
+	 */
+	List<DivBackRecord> selectPage(@Param("page") IPage<DivBackRecord> page, @Param("param") DivBackRecordWrapper.DivBackRecordQuery param);
+	
+}

+ 27 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/TenantAlbumCategoryDetailMapper.java

@@ -0,0 +1,27 @@
+package com.yonge.cooleshow.biz.dal.mapper;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategoryDetail;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumCategoryDetailWrapper;
+
+/**
+ * 机构专辑分类详情
+ * 2023-10-10 10:17:38
+ */
+@Repository
+public interface TenantAlbumCategoryDetailMapper extends BaseMapper<TenantAlbumCategoryDetail> {
+
+    /**
+     * 分页查询
+     * @param page IPage<TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetail>
+     * @param param TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetailQuery
+     * @return List<TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetail>
+     */
+    List<TenantAlbumCategoryDetail> selectPage(@Param("page") IPage<TenantAlbumCategoryDetail> page, @Param("param") TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetailQuery param);
+
+}

+ 28 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/TenantAlbumCategoryMapper.java

@@ -0,0 +1,28 @@
+package com.yonge.cooleshow.biz.dal.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategory;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumCategoryWrapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 机构专辑分类
+ * 2023-10-10 09:48:46
+ */
+@Repository
+public interface TenantAlbumCategoryMapper extends BaseMapper<TenantAlbumCategory> {
+
+    /**
+     * 分页查询
+     * @param page IPage<TenantAlbumCategoryWrapper.TenantAlbumCategory>
+     * @param param TenantAlbumCategoryWrapper.TenantAlbumCategoryQuery
+     * @return List<TenantAlbumCategoryWrapper.TenantAlbumCategory>
+     */
+    List<TenantAlbumCategory> selectPage(@Param("page") IPage<TenantAlbumCategoryWrapper.TenantAlbumCategory> page,
+                                         @Param("param") TenantAlbumCategoryWrapper.TenantAlbumCategoryQuery param);
+
+}

+ 31 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/TenantGroupMapper.java

@@ -0,0 +1,31 @@
+package com.yonge.cooleshow.biz.dal.mapper;
+
+import java.util.List;
+import java.util.Map;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import org.apache.ibatis.annotations.Param;
+import org.apache.poi.ss.formula.functions.T;
+import org.springframework.stereotype.Repository;
+import com.yonge.cooleshow.biz.dal.entity.TenantGroup;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupWrapper;
+
+/**
+ * 机构小组表
+ * 2023-10-11 09:24:50
+ */
+@Repository
+public interface TenantGroupMapper extends BaseMapper<TenantGroup> {
+
+    /**
+     * 分页查询
+     * @param page IPage<TenantGroupWrapper.TenantGroup>
+     * @param param TenantGroupWrapper.TenantGroupQuery
+     * @return List<TenantGroupWrapper.TenantGroup>
+     */
+    List<TenantGroupWrapper.TenantGroup> selectPage(@Param("page") IPage<TenantGroupWrapper.TenantGroup> page,
+                                                    @Param("param") TenantGroupWrapper.TenantGroupQuery param);
+
+}

+ 13 - 9
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/UserTenantAlbumRecordMapper.java

@@ -5,6 +5,7 @@ import java.util.List;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.yonge.cooleshow.biz.dal.entity.TenantAlbum;
+import com.yonge.cooleshow.biz.dal.vo.VipCardRecordVo;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumWrapper;
 import org.apache.ibatis.annotations.Param;
 import org.springframework.stereotype.Repository;
@@ -18,17 +19,20 @@ import com.yonge.cooleshow.biz.dal.wrapper.UserTenantAlbumRecordWrapper;
 @Repository
 public interface UserTenantAlbumRecordMapper extends BaseMapper<UserTenantAlbumRecord> {
 
-	/**
-	 * 分页查询
-	 * @param page IPage<UserTenantAlbumRecordWrapper.UserTenantAlbumRecord>
-	 * @param param UserTenantAlbumRecordWrapper.UserTenantAlbumRecordQuery
-	 * @return List<UserTenantAlbumRecordWrapper.UserTenantAlbumRecord>
-	 */
-	List<TenantAlbumWrapper.TenantAlbum> selectPage(@Param("page") IPage<UserTenantAlbumRecord> page, @Param("param") UserTenantAlbumRecordWrapper.UserTenantAlbumRecordQuery param);
+    /**
+     * 分页查询
+     *
+     * @param page  IPage<UserTenantAlbumRecordWrapper.UserTenantAlbumRecord>
+     * @param param UserTenantAlbumRecordWrapper.UserTenantAlbumRecordQuery
+     * @return List<UserTenantAlbumRecordWrapper.UserTenantAlbumRecord>
+     */
+    List<TenantAlbumWrapper.TenantAlbum> selectPage(@Param("page") IPage<UserTenantAlbumRecord> page, @Param("param") UserTenantAlbumRecordWrapper.UserTenantAlbumRecordQuery param);
 
-	List<Long> selectTenantIds(@Param("id") Long id);
+    List<Long> selectTenantIds(@Param("id") Long id);
 
-	List<TenantAlbum> selectTenantAlbumInfo(@Param("tenantIds") List<Long> tenantIds);
+    List<TenantAlbum> selectTenantAlbumInfo(@Param("tenantIds") List<Long> tenantIds);
 
     Long ifBuy(@Param("tenantAlbumId") Long tenantAlbumId, @Param("studentId") Long studentId);
+
+    List<UserTenantAlbumRecordWrapper.UserTenantAlbumRecord> selectTemporaryRecord();
 }

+ 44 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/queryInfo/SysMusicCompareRecordQueryInfo.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.biz.dal.queryInfo;
 
+import com.alibaba.excel.annotation.ExcelProperty;
 import com.yonge.cooleshow.biz.dal.enums.FeatureType;
 import com.yonge.cooleshow.biz.dal.enums.HeardLevelEnum;
 import com.yonge.toolset.base.page.QueryInfo;
@@ -49,6 +50,24 @@ public class SysMusicCompareRecordQueryInfo {
         @ApiModelProperty(name = "机构编号")
         private Long tenantId;
 
+        @ApiModelProperty(name = "最小训练总时长")
+        private Integer minTrainTimes;
+
+        @ApiModelProperty(name = "最大训练总时长")
+        private Integer maxTrainTimes;
+
+        @ApiModelProperty(name = "最小训练天数")
+        private Integer minTrainDays;
+
+        @ApiModelProperty(name = "最大训练天数")
+        private Integer maxTrainDays;
+
+        @ApiModelProperty(name = "最小平均训练时长")
+        private Integer minAvgTrainTimes;
+
+        @ApiModelProperty(name = "最大平均训练时长")
+        private Integer maxAvgTrainTimes;
+
         @ApiModelProperty(name = "排序字段")
         private String sortField = "trainTimes";
 
@@ -133,26 +152,51 @@ public class SysMusicCompareRecordQueryInfo {
     @Data
     public static class WechatCompareRecordPageDto{
         @ApiModelProperty(name = "用户编号")
+        @ExcelProperty(value = "用户编号")
         private Long userId;
 
         @ApiModelProperty(name = "头像")
+        @ExcelProperty(value = "头像")
         private String avatar;
 
         @ApiModelProperty(name = "姓名")
+        @ExcelProperty(value = "姓名")
         private String username;
 
         @ApiModelProperty(name = "声部")
+        @ExcelProperty(value = "声部")
         private String subjectName;
 
         @ApiModelProperty(name = "训练总时长")
+        @ExcelProperty(value = "训练总时长")
         private Integer trainTimes = 0;
 
         @ApiModelProperty(name = "训练天数")
+        @ExcelProperty(value = "训练天数")
         private Integer trainDays = 0;
 
         @ApiModelProperty(name = "平均训练时长")
+        @ExcelProperty(value = "平均训练时长")
+        private Integer avgTrainTimes = 0;
+
+    }
+    @Data
+    public static class WechatCompareRecordExportDto{
+        @ExcelProperty(value = "姓名")
+        private String username;
+
+        @ExcelProperty(value = "声部")
+        private String subjectName;
+
+        @ExcelProperty(value = "平均训练时长")
         private Integer avgTrainTimes = 0;
 
+        @ExcelProperty(value = "总时长")
+        private Integer trainTimes = 0;
+
+        @ExcelProperty(value = "训练天数")
+        private Integer trainDays = 0;
+
     }
 
     @Data

+ 47 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/DivBackRecordService.java

@@ -0,0 +1,47 @@
+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.wrapper.DivBackRecordWrapper;
+import com.yonge.cooleshow.biz.dal.entity.DivBackRecord;
+
+/**
+ * 分账归还记录
+ * 2023-10-18 10:59:05
+ */
+public interface DivBackRecordService extends IService<DivBackRecord>  {
+
+	/**
+     * 查询详情
+     * @param id 详情ID
+     * @return DivBackRecord
+     */
+	DivBackRecord detail(Long id);
+
+    /**
+     * 分页查询
+     * @param page IPage<DivBackRecord>
+     * @param query DivBackRecordWrapper.DivBackRecordQuery
+     * @return IPage<DivBackRecord>
+     */
+    IPage<DivBackRecord> selectPage(IPage<DivBackRecord> page, DivBackRecordWrapper.DivBackRecordQuery query);
+	
+    /**
+     * 添加
+     * @param divBackRecord DivBackRecordWrapper.DivBackRecord
+     * @return Boolean
+     */
+     Boolean add(DivBackRecordWrapper.DivBackRecord divBackRecord);   
+
+    /**
+     * 更新
+     * @param divBackRecord DivBackRecordWrapper.DivBackRecord
+     * @return Boolean
+     */
+     Boolean update(DivBackRecordWrapper.DivBackRecord divBackRecord);
+
+    /**
+     * 分账回归
+     */
+    void divBack();
+}

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

@@ -79,7 +79,7 @@ public interface ImGroupService extends IService<ImGroup> {
     * @author zx
     * @date 2022/3/22 11:17
     */
-    void create(ImGroupWrapper.ImGroup imGroup) throws Exception;
+    String create(ImGroupWrapper.ImGroup imGroup) throws Exception;
 
     /**
     * @description: 成课后自动创建群聊,建议放在最后执行

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

@@ -12,4 +12,7 @@ public interface OssFileService {
 
     OssFileWrapper.ExportFile uploadFile(List<?> dataList, Class<?> clazz,
                                          String fileName, String sheetName);
+
+    OssFileWrapper.ExportFile uploadFileWithShortUrl(List<?> dataList, Class<?> clazz,
+                                                     String fileName, String sheetName);
 }

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

@@ -95,4 +95,12 @@ public interface PaymentDivMemberRecordService extends IService<PaymentDivMember
      * 活动
      */
     void activity(UserOrderDetailVo userOrderDetailVo);
+
+    /**
+     * 根据订单查询分账记录
+     *
+     * @param orderNo 订单编号
+     * @return
+     */
+    List<PaymentDivMemberRecord> getByOrderNo(String orderNo);
 }

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

@@ -130,4 +130,6 @@ public interface StudentService extends IService<Student> {
      */
     void updateTenant(Student student, Long toTenantId);
 
+    void sendStudentTenantChange(Student student, Long toTenantId);
+
 }

+ 2 - 37
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/SysMessageService.java

@@ -16,24 +16,6 @@ import com.yonge.toolset.mybatis.service.BaseService;
 import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext.MessageSender;
 
 public interface SysMessageService extends BaseService<Long, SysMessage> {
-	
-	public PageInfo<SysMessageDto> queryListPage(QueryInfo queryInfo);
-
-	/**
-	 * 修改消息对象
-	 * @param message
-	 * @return
-	 */
-	public int updateMessage(SysMessage message);
-
-	/**
-	 * 推送站内消息
-	 * @param userIds
-	 * @param messageType
-	 * @return
-	 */
-	boolean batchSeoMessage(Set<Long> userIds, MessageTypeEnum messageType,String memo, Object... args);
-
 	/**
 	 * 发送消息
 	 * @param messageSender 消息发送者
@@ -54,19 +36,6 @@ public interface SysMessageService extends BaseService<Long, SysMessage> {
 
 
 	/**
-	 * 推送极光自定义消息
-	 * @param messageType 消息类型
-	 * @param receivers 消息接收者(Key:用户编号  value:消息接收对象)
-	 * @param triggerTime 触发时间
-	 * @param readStatus 阅读状态(0-未读  1-已读)
-	 * @param url 超链接地址
-	 * @param args 参数
-	 * @return
-	 */
-	public void batchPushMessage(MessageTypeEnum messageType, Map<Long, String> receivers, Date triggerTime,
-			Integer readStatus, String url,String jpushType,String sound,String channelId, Object... args);
-
-	/**
 	 * 发送消息
 	 * @param messageSender 消息发送者
 	 * @param userId 用户编号
@@ -101,12 +70,6 @@ public interface SysMessageService extends BaseService<Long, SysMessage> {
 	 */
 	public String getSendedVerificationCode(MessageTypeEnum type, String mobileNOOrEmailAddr);
 
-	/**
-	 * 删除已有的key
-	 * @param type
-	 * @param mobileNOOrEmailAddr
-	 */
-	public void delSendedVerificationCode(MessageTypeEnum type, String mobileNOOrEmailAddr);
 
 	/**
 	 * 查询消息未读条数
@@ -132,4 +95,6 @@ public interface SysMessageService extends BaseService<Long, SysMessage> {
 	public List<SysMessage> queryUserInRecentMinList(String mobile, int recentMin, MessageSendMode type);
 
 	String selectConfigUrl(String messageType,Object ...param);
+
+	String selectConfigUrlJumpType(String messageType, String jumpType, Object... param);
 }

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

@@ -3,6 +3,7 @@ package com.yonge.cooleshow.biz.dal.service;
 import com.yonge.cooleshow.auth.api.dto.RealnameAuthReq;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.mapper.SysUserMapper;
 import com.yonge.toolset.utils.idcard.IdcardInfoExtractor;
 
 import java.util.List;
@@ -10,6 +11,8 @@ import java.util.Map;
 
 public interface SysUserService{
 
+    SysUserMapper getDao();
+
     Long getUserId();
 
     SysUser getUser();

+ 3 - 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.biz.dal.dao.TeacherDao;
 import com.yonge.cooleshow.biz.dal.dto.TeacherDto;
 import com.yonge.cooleshow.biz.dal.dto.req.TeacherSubmitReq;
 import com.yonge.cooleshow.biz.dal.dto.search.TeacherSearch;
@@ -24,6 +25,8 @@ import java.util.List;
  * @date 2022-03-18
  */
 public interface TeacherService extends IService<Teacher> {
+    TeacherDao getDao();
+
     /***
      * 查询老师详情
      * @author liweifan

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

@@ -9,8 +9,10 @@ import com.yonge.cooleshow.biz.dal.wrapper.TenantActivationCodeWrapper;
 import com.yonge.cooleshow.biz.dal.entity.TenantActivationCode;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.toolset.utils.easyexcel.ExcelDataReaderProperty;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 机构激活码
@@ -55,6 +57,8 @@ public interface TenantActivationCodeService extends IService<TenantActivationCo
     void sendActivationCode(Long tenantId, Long tenantAlbumPurchaseId, List<String> activationCodeList,
                             List<Long> studentIdList);
 
+    void sendCancelActivationCodeMessage(Map<Long, String> receivers, String tenantName);
+
     void active(String activationCode, Long studentId);
 
 
@@ -81,6 +85,9 @@ public interface TenantActivationCodeService extends IService<TenantActivationCo
 
     void resend(String code, Long userId, Long tenantId, Long tenantAlbumPurchaseId);
 
+    @Transactional(rollbackFor = Exception.class)
+    void sendCancel(TenantInfo tenantInfo, TenantActivationCode activationCode);
+
     void batchSendCancel(TenantInfo tenantInfo, String ids);
 
     void batchResend(TenantInfo tenantInfo, Long tenantAlbumPurchaseId, List<String> activationCodeList, List<Long> studentIdList);

+ 43 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/TenantAlbumCategoryDetailService.java

@@ -0,0 +1,43 @@
+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.wrapper.TenantAlbumCategoryDetailWrapper;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategoryDetail;
+
+/**
+ * 机构专辑分类详情
+ * 2023-10-10 10:17:38
+ */
+public interface TenantAlbumCategoryDetailService extends IService<TenantAlbumCategoryDetail>  {
+
+    /**
+     * 查询详情
+     * @param id 详情ID
+     * @return TenantAlbumCategoryDetail
+     */
+    TenantAlbumCategoryDetail detail(Long id);
+
+    /**
+     * 分页查询
+     * @param page IPage<TenantAlbumCategoryDetail>
+     * @param query TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetailQuery
+     * @return IPage<TenantAlbumCategoryDetail>
+     */
+    IPage<TenantAlbumCategoryDetail> selectPage(IPage<TenantAlbumCategoryDetail> page, TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetailQuery query);
+
+    /**
+     * 添加
+     * @param tenantAlbumCategoryDetail TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetail
+     * @return Boolean
+     */
+    Boolean add(TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetail tenantAlbumCategoryDetail);
+
+    /**
+     * 更新
+     * @param tenantAlbumCategoryDetail TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetail
+     * @return Boolean
+     */
+    Boolean update(TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetail tenantAlbumCategoryDetail);
+
+}

+ 46 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/TenantAlbumCategoryService.java

@@ -0,0 +1,46 @@
+package com.yonge.cooleshow.biz.dal.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.microsvc.toolkit.common.response.ParamResponse;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumCategoryWrapper;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategory;
+
+/**
+ * 机构专辑分类
+ * 2023-10-10 09:48:46
+ */
+public interface TenantAlbumCategoryService extends IService<TenantAlbumCategory>  {
+
+    /**
+     * 查询详情
+     * @param id 详情ID
+     * @return TenantAlbumCategory
+     */
+    TenantAlbumCategoryWrapper.TenantAlbumCategory detail(Long id);
+
+    /**
+     * 分页查询
+     * @param page IPage<TenantAlbumCategory>
+     * @param query TenantAlbumCategoryWrapper.TenantAlbumCategoryQuery
+     * @return IPage<TenantAlbumCategory>
+     */
+    IPage<TenantAlbumCategoryWrapper.TenantAlbumCategory> selectPage(IPage<TenantAlbumCategoryWrapper.TenantAlbumCategory> page,
+                                                                     TenantAlbumCategoryWrapper.TenantAlbumCategoryQuery query);
+
+    /**
+     * 添加
+     * @param tenantAlbumCategory TenantAlbumCategoryWrapper.TenantAlbumCategory
+     * @return Boolean
+     */
+    Boolean add(TenantAlbumCategoryWrapper.TenantAlbumCategory tenantAlbumCategory);
+
+    /**
+     * 更新
+     * @param tenantAlbumCategory TenantAlbumCategoryWrapper.TenantAlbumCategory
+     * @return Boolean
+     */
+    Boolean update(TenantAlbumCategoryWrapper.TenantAlbumCategory tenantAlbumCategory);
+
+    Boolean delete(Long id);
+}

+ 54 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/TenantGroupService.java

@@ -0,0 +1,54 @@
+package com.yonge.cooleshow.biz.dal.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.microsvc.toolkit.common.response.ParamResponse;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupWrapper;
+import com.yonge.cooleshow.biz.dal.entity.TenantGroup;
+
+import java.util.List;
+
+/**
+ * 机构小组表
+ * 2023-10-11 09:24:50
+ */
+public interface TenantGroupService extends IService<TenantGroup>  {
+
+    /**
+     * 查询详情
+     * @param id 详情ID
+     * @return TenantGroup
+     */
+    TenantGroup detail(Long id);
+
+    /**
+     * 分页查询
+     * @param page IPage<TenantGroup>
+     * @param query TenantGroupWrapper.TenantGroupQuery
+     * @return IPage<TenantGroup>
+     */
+    IPage<TenantGroupWrapper.TenantGroup> selectPage(IPage<TenantGroupWrapper.TenantGroup> page,
+                                                     TenantGroupWrapper.TenantGroupQuery query);
+
+    /**
+     * 添加
+     * @param tenantGroup TenantGroupWrapper.TenantGroup
+     * @param imGroupCreate 是否创建群聊
+     * @return Boolean
+     */
+    Boolean add(TenantGroupWrapper.TenantGroup tenantGroup, Boolean imGroupCreate);
+
+    /**
+     * 更新
+     * @param tenantGroup TenantGroupWrapper.TenantGroup
+     * @param imGroupCreate 是否创建IM群
+     * @return Boolean
+     */
+    Boolean update(TenantGroupWrapper.TenantGroup tenantGroup, Boolean imGroupCreate);
+
+    Boolean delete(Long id);
+
+    List<TenantGroupWrapper.TenantGroupMember> queryGroupMember(Long tenantId, Long tenantGroupId);
+
+    Boolean adjustTenantGroup(TenantGroupWrapper.AdjustTenantGroup adjustTenantGroup);
+}

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

@@ -84,4 +84,6 @@ public interface UserOrderRefundService extends IService<UserOrderRefund>  {
 	HttpResponseResult<UserOrderRefundBill> orderRefound(String orderNo);
 
 	void orderRefundSuccessBizHandle(Long refundId);
+
+    void orderRefundSuccessBizHandleByOrderNo(String orderNo);
 }

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

@@ -4,7 +4,6 @@ import com.microsvc.toolkit.config.jwt.utils.JwtUserInfo;
 import com.microsvc.toolkit.middleware.payment.common.api.entity.PaymentResp;
 import com.microsvc.toolkit.middleware.payment.common.api.entity.RefundResp;
 import com.yonge.cooleshow.biz.dal.wrapper.UserPaymentOrderWrapper;
-import com.yonge.cooleshow.common.enums.payment.EPaymentType;
 import org.springframework.transaction.annotation.Transactional;
 
 /**
@@ -85,4 +84,6 @@ public interface UserPaymentCoreService {
     void refundPaymentCallback(RefundResp refundResp);
 
     void refundPayment(String orderNo,  String reason);
+
+    void refundOnly(String reason, String orderNo);
 }

+ 8 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/UserTenantAlbumRecordService.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.biz.dal.entity.TenantAlbum;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.UserTenantAlbumRecordWrapper;
@@ -71,4 +72,11 @@ public interface UserTenantAlbumRecordService extends IService<UserTenantAlbumRe
     List<Long> getUseAlbumIdsByUserId(Long userId,ClientEnum clientType);
 
     TenantAlbumWrapper.TenantAlbum detailAlbum(String albumId);
+
+    /**
+     * 训练教程过期通知
+     */
+    void sendTenantAlbumMessage();
+
+    UserTenantAlbumRecord getNewestByTenantAlbumId(Long tenantAlbumId, Long userId, ClientEnum client);
 }

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

@@ -5,6 +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.microsvc.toolkit.config.jwt.utils.JwtUserInfo;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;

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

@@ -0,0 +1,152 @@
+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.microsvc.toolkit.middleware.payment.common.api.BasePaymentService;
+import com.microsvc.toolkit.middleware.payment.common.api.PaymentServiceContext;
+import com.microsvc.toolkit.middleware.payment.common.api.entity.DivideReq;
+import com.microsvc.toolkit.middleware.payment.common.api.entity.DivideResp;
+import com.microsvc.toolkit.middleware.payment.common.api.enums.DivideBackStatus;
+import com.yonge.cooleshow.biz.dal.entity.PaymentDivMemberRecord;
+import com.yonge.cooleshow.biz.dal.service.*;
+import com.yonge.cooleshow.biz.dal.wrapper.UserPaymentOrderWrapper;
+import com.yonge.cooleshow.common.enums.EPayerType;
+import org.checkerframework.checker.units.qual.A;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.beans.BeanUtils;
+import lombok.extern.slf4j.Slf4j;
+import com.yonge.cooleshow.biz.dal.entity.DivBackRecord;
+import com.yonge.cooleshow.biz.dal.wrapper.DivBackRecordWrapper;
+import com.yonge.cooleshow.biz.dal.mapper.DivBackRecordMapper;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * 分账归还记录
+ * 2023-10-18 10:59:05
+ */
+@Slf4j
+@Service
+public class DivBackRecordServiceImpl extends ServiceImpl<DivBackRecordMapper, DivBackRecord> implements DivBackRecordService {
+
+    @Autowired
+    private TenantMemberService tenantMemberService;
+
+    @Autowired
+    private PaymentServiceContext paymentServiceContext;
+
+    @Autowired
+    private PaymentDivMemberRecordService paymentDivMemberRecordService;
+
+    @Autowired
+    private UserPaymentOrderService userPaymentOrderService;
+
+    @Autowired
+    private UserPaymentCoreService userPaymentCoreService;
+
+    /**
+     * 查询详情
+     * @param id 详情ID
+     * @return DivBackRecord
+     */
+    @Override
+    public DivBackRecord detail(Long id) {
+        
+        return baseMapper.selectById(id);
+    }
+    
+    /**
+     * 分页查询
+     * @param page IPage<DivBackRecord>
+     * @param query DivBackRecordWrapper.DivBackRecordQuery
+     * @return IPage<DivBackRecord>
+     */
+    @Override
+    public IPage<DivBackRecord> selectPage(IPage<DivBackRecord> page, DivBackRecordWrapper.DivBackRecordQuery query) {
+        
+        return page.setRecords(baseMapper.selectPage(page, query));
+    }
+
+    /**
+     * 添加
+     * @param divBackRecord DivBackRecordWrapper.DivBackRecord
+     * @return Boolean
+     */
+    @Override
+    public Boolean add(DivBackRecordWrapper.DivBackRecord divBackRecord) {
+
+        return this.save(JSON.parseObject(divBackRecord.jsonString(), DivBackRecord.class));
+    }
+
+    /**
+     * 更新
+     * @param divBackRecord DivBackRecordWrapper.DivBackRecord
+     * @return Boolean
+     */
+    @Override
+    public Boolean update(DivBackRecordWrapper.DivBackRecord divBackRecord){
+
+        return this.updateById(JSON.parseObject(divBackRecord.jsonString(), DivBackRecord.class));       
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void divBack() {
+        // 查询分账回归在等待中的状态 ,遍历调用查询分账回归接口 回归成功的 修改回归状态,在调用退款接口
+        List<DivBackRecord> list = this.lambdaQuery()
+            .eq(DivBackRecord::getStatus, DivideBackStatus.PROCESSING.name())
+            .list();
+
+        for (DivBackRecord divBackRecord : list) {
+
+            PaymentDivMemberRecord divMemberRecord = paymentDivMemberRecordService.getById(divBackRecord.getPaymentDivMemberRecordId());
+            if (divMemberRecord == null){
+                continue;
+            }
+            UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService
+                .getUserPaymentOrderByOrderNo(divMemberRecord.getOrderNo());
+            if (paymentOrder == null) {
+                continue;
+            }
+
+
+            BasePaymentService paymentService = paymentServiceContext.getPaymentService(divBackRecord.getPaymentVendor());
+
+            DivideReq.MemberDivideBack memberDivideBack = DivideReq.MemberDivideBack.builder()
+                .payerName(EPayerType.YEEPAY.getDesc())
+                .memberId(divMemberRecord.getMemberId())
+                .platformPayeeMemberId(paymentService.getPaymentConfig().getMerchantId())
+                .divideBackOrderNo(divBackRecord.getDivideBackOrderNo())
+                .payOrderNo(paymentOrder.getOrderNo())
+                .transNo(paymentOrder.getTransNo())
+                .build();
+            DivideResp.DivideBack divideBack;
+            try {
+                divideBack = paymentService.queryDivideBack(tenantMemberService.getMerchantConfig(divBackRecord.getPaymentVendor()), memberDivideBack);
+                if (divideBack == null) {
+                    continue;
+                }
+            } catch (Exception e) {
+                log.error("分账回归查询异常", e);
+                continue;
+            }
+
+            if (divideBack.getStatus() == DivideBackStatus.SUCCESS) {
+                // 修改回归状态
+                divBackRecord.setStatus(DivideBackStatus.SUCCESS.name());
+                this.updateById(divBackRecord);
+                // 调用退款接口
+                userPaymentCoreService.refundOnly("退款",paymentOrder.getOrderNo());
+            } else if (divideBack.getStatus() == DivideBackStatus.FAIL) {
+                // 修改回归状态
+                divBackRecord.setStatus(DivideBackStatus.FAIL.name());
+                this.updateById(divBackRecord);
+            }
+        }
+
+    }
+}

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

@@ -303,7 +303,7 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void create(ImGroupWrapper.ImGroup imGroup) throws Exception {
+    public String create(ImGroupWrapper.ImGroup imGroup) throws Exception {
         Date now = new Date();
         if (imGroup.getType() == null) {
             imGroup.setType(ImGroupType.FAN.getCode());
@@ -317,6 +317,7 @@ public class ImGroupServiceImpl extends ServiceImpl<ImGroupDao, ImGroup> impleme
         if (!imGroup.getStudentIdList().isEmpty()) {
             addGroupMember(groupId,imGroup.getStudentIdList());
         }
+        return groupId;
 
 
 //        String imGroupId = UUID.randomUUID() + imGroup.getType().getCode();

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

@@ -94,6 +94,10 @@ public class ImUserFriendServiceImpl extends ServiceImpl<ImUserFriendDao, ImUser
         List<ImUserFriend> imUserFriends = new ArrayList<>();
         BasicUserInfo teacherInfo = teacherDao.getBasicUserInfo(teacherId);
         List<BasicUserInfo> studentInfos = teacherDao.findBasicUserInfo(studentIds);
+        if (teacherInfo == null || studentInfos.isEmpty()) {
+            // 过滤注销状态的账号
+            return;
+        }
         studentInfos.add(teacherInfo);
         Map<Long, List<BasicUserInfo>> basicUserInfoMap =
                 studentInfos.stream().collect(Collectors.groupingBy(BasicUserInfo::getUserId));

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

@@ -221,7 +221,7 @@ public class MemberPriceSettingsServiceImpl extends ServiceImpl<MemberPriceSetti
         getUserVipInfoVo(vipCardRecord);
 
         // 发消息
-        sendAddVipMessage(vipSubmitReq.getUserId(),client,vipSubmitReq.getTimes(),vipSubmitReq.getType(),vipSubmitReq.getReason());
+        sendAddVipMessage(vipSubmitReq.getUserId(),sysUser.getPhone(),client,vipSubmitReq.getTimes(),vipSubmitReq.getType(),vipSubmitReq.getReason());
 
         return true;
     }
@@ -296,18 +296,22 @@ public class MemberPriceSettingsServiceImpl extends ServiceImpl<MemberPriceSetti
 
     }
 
-    private void sendAddVipMessage(Long userId, ClientEnum client, Integer times, PeriodEnum type, String reason) {
+    private void sendAddVipMessage(Long userId,String phone, ClientEnum client, Integer times, PeriodEnum type, String reason) {
         try {
-            SysUser user = sysUserFeignService.queryUserById(userId);
-
-            if (user == null) {
-                return;
-            }
-
             Map<Long, String> receivers = new HashMap<>();
-            receivers.put(userId, user.getPhone());
-            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.PLATFORM_ADD_VIP,
-                                               receivers, null, 0, null, client.getCode(), times,type.getMsg(),reason);
+            receivers.put(userId, phone);
+            Student student = studentService.getById(userId);
+            if (client.equals(ClientEnum.STUDENT) && student != null && student.getTenantId() != null && student.getTenantId() >0) {
+                try {
+                    sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.TENANT_PLATFORM_ADD_VIP,
+                            receivers, null, 0, null, ClientEnum.TENANT_STUDENT.getCode(), times +type.getMsg(), reason);
+                } catch (Exception e) {
+                    log.error("会员赠送消息发送失败", e);
+                }
+            } else {
+                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.PLATFORM_ADD_VIP,
+                        receivers, null, 0, null, client.getCode(), times, type.getMsg(), reason);
+            }
         } catch (Exception e) {
             log.error("会员赠送消息发送失败 : {}",e.getMessage());
         }
@@ -339,21 +343,33 @@ public class MemberPriceSettingsServiceImpl extends ServiceImpl<MemberPriceSetti
 
 
     // 发送会员购买消息推送
-    private void authSend(Long userId, String phone, String param1,ClientEnum clientEnum) {
+    private void authSend(Long userId,String phone, String param1,ClientEnum clientEnum) {
         Map<Long, String> receivers = new HashMap<>();
         receivers.put(userId, phone);
-        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 {
-            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS, MessageTypeEnum.SMS_VIP_BUY_SUCCESS,
-                    receivers, null, 0, null, clientEnum.getCode(), param1);
-        } catch (Exception e) {
-            log.error("会员购买短信消息推送异常,userId={}", userId);
+        // 判断是否是机构学生 机构学生推送走另一个
+        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 {
+                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS, MessageTypeEnum.SMS_VIP_BUY_SUCCESS,
+                        receivers, null, 0, null, clientEnum.getCode(), param1);
+            } catch (Exception e) {
+                log.error("会员购买短信消息推送异常,userId={}", userId);
+            }
         }
 
     }

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

@@ -1190,23 +1190,37 @@ public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao, MusicSheet
 
         }
         // 推送学生
-        Map<Long, String> studentReceivers = new HashMap<>();
-        studentReceivers.put(studentId, student.getPhone());
+        Map<Long, String> studentReceivers = new HashMap<>(1);
+        studentReceivers.put(studentId,student.getPhone());
 
+        try {
+            Student studentInfo = studentService.getById(studentId);
+            if (studentInfo != null && orderClient.equals(ClientEnum.STUDENT) &&
+                    studentInfo.getTenantId() != null && studentInfo.getTenantId() > 0 && orderType.equals(OrderTypeEnum.MUSIC)) {
+                try {
+                    sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.TENANT_MUSIC_BUY,
+                            studentReceivers, null, 0, null, ClientEnum.TENANT_STUDENT.getCode(), name);
+                } catch (Exception e) {
+                    log.error("学生购买曲目推送失败,", e);
+                }
+            } else {
 
-        String url = sysMessageService.selectConfigUrl(messageType.getCode());
-
-        sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,
-                                           messageType, studentReceivers, null,
-                0, url, orderClient.getCode(), name);
-        // 推送学生
-        Map<Long, String> studentSMS = new HashMap<>();
-        studentSMS.put(studentId, student.getPhone());
-        // 推送短信
-        url = sysMessageService.selectConfigUrl(smsMessageType.getCode());
-        sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS, smsMessageType,
-                studentSMS, null, 0, url, null, name);
-
+                String url = sysMessageService.selectConfigUrl(messageType.getCode());
+
+                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,
+                        messageType, studentReceivers, null,
+                        0, url, orderClient.getCode(), name);
+                // 推送学生
+                Map<Long, String> studentSMS = new HashMap<>();
+                studentSMS.put(studentId, student.getPhone());
+                // 推送短信
+                url = sysMessageService.selectConfigUrl(smsMessageType.getCode());
+                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS, smsMessageType,
+                        studentSMS, null, 0, url, null, name);
+            }
+        } catch (Exception e) {
+            log.error("购买曲目消息推送失败,", e);
+        }
         return true;
     }
 

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

@@ -40,6 +40,47 @@ public class OssFileServiceImpl implements OssFileService {
         String uploadOssPath = MessageFormat.format("excel-download/{0}", DateTime.now().toString("yyyy-MM"));
 
         // 文件上传下载地址
+        String uploadPath = MessageFormat.format("{0}/{1}-{2}/{3}.xlsx", uploadOssPath,
+                String.valueOf(IdWorker.getId()),
+                DateTime.now().toString("MMddHHmmss"),fileName);
+
+        // 本地文件地址
+        String localPath = DownloadManager.getInstance().path(uploadPath);
+        log.debug("pageExport localPath={}", localPath);
+
+        EasyExcel
+                .write(localPath, clazz)
+                //.withTemplate(resource.getStream()) // 利用模板的输出流
+                .sheet(0, sheetName)
+                .doWrite(dataList);
+
+        // 上传本地文件到OSS服务器
+        String downloadPath = ossPluginContext.getPluginService(TencentOssPlugin.PLUGIN_NAME)
+                .uploadFile(uploadOssPath, new File(localPath));
+        log.debug("pageExport downloadPath={}", downloadPath);
+
+        // 删除本地缓存文件
+        DownloadManager.getInstance().deleteOnExit(localPath);
+
+        // 学生统计下载
+        return OssFileWrapper.ExportFile
+                .builder()
+                .fileName(MessageFormat.format("{0}.xlsx", fileName))
+                .downloadPath(downloadPath)
+                .build();
+    }
+
+    @Override
+    public OssFileWrapper.ExportFile uploadFileWithShortUrl(List<?> dataList, Class<?> clazz,
+                                                            String fileName, String sheetName) {
+        if (CollectionUtils.isEmpty(dataList)) {
+            throw new BizException("导出数据为空");
+        }
+
+        // OSS上传文件目录
+        String uploadOssPath = MessageFormat.format("excel-download/{0}", DateTime.now().toString("yyyy-MM"));
+
+        // 文件上传下载地址
         String uploadPath = MessageFormat.format("{0}/{1}-{2}.xlsx", uploadOssPath, String.valueOf(IdWorker.getId()),
                 DateTime.now().toString("MMddHHmmss"));
 

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

@@ -339,15 +339,12 @@ public class PaymentDivMemberRecordServiceImpl extends ServiceImpl<PaymentDivMem
             serviceFeeAmount = actualPrice;
         }
 
-        // 平台学生 发送推送
-        if(checkSendMessage(userPaymentOrder.getUserId(),userPaymentOrder.getOrderClient())) {
-            // 消息通知
-            CompletableFuture.runAsync(() -> {
-                        musicSheetService.sendBuyMessage(userPaymentOrder.getMerchId(), userPaymentOrder.getUserId(),
-                                userPaymentOrder.getBizId(), userPaymentOrder.getOrderClient(), userPaymentOrder.getOrderType());
-                    }
-            );
-        }
+        // 消息通知
+        CompletableFuture.runAsync(() -> {
+                    musicSheetService.sendBuyMessage(userPaymentOrder.getMerchId(), userPaymentOrder.getUserId(),
+                            userPaymentOrder.getBizId(), userPaymentOrder.getOrderClient(), userPaymentOrder.getOrderType());
+                }
+        );
 
 
         saveData(userPaymentOrder, tenantdivMap, teacherMap, bizMap, serviceFeeAmount);
@@ -752,7 +749,7 @@ public class PaymentDivMemberRecordServiceImpl extends ServiceImpl<PaymentDivMem
         //服务费  原价的平台服务费 ,减去优惠券金额
         BigDecimal serviceFeeAmount = userPaymentOrder.getActualPrice();
 
-        memberPriceSettingsService.orderSuccess(userPaymentOrder,checkSendMessage(userPaymentOrder.getUserId(),userPaymentOrder.getOrderClient()));
+        memberPriceSettingsService.orderSuccess(userPaymentOrder);
 
         saveData(userPaymentOrder, tenantdivMap, teacherMap, bizMap, serviceFeeAmount);
     }
@@ -780,6 +777,13 @@ public class PaymentDivMemberRecordServiceImpl extends ServiceImpl<PaymentDivMem
         saveData(userPaymentOrder, tenantdivMap, teacherMap, bizMap, serviceFeeAmount);
     }
 
+    @Override
+    public List<PaymentDivMemberRecord> getByOrderNo(String orderNo) {
+        return this.lambdaQuery()
+            .eq(PaymentDivMemberRecord::getOrderNo, orderNo)
+            .list();
+    }
+
 
     // 写入数据库
     private void saveData(UserOrderDetailVo userPaymentOrder, Map<Long, BigDecimal> tenantdivMap, Map<Long, BigDecimal> teacherMap, Map<Long, BigDecimal> bizMap, BigDecimal serviceFeeAmount) {
@@ -938,6 +942,7 @@ public class PaymentDivMemberRecordServiceImpl extends ServiceImpl<PaymentDivMem
                 .divOrderNo(divideOrderNo)
                 .transNo(newestPayment != null ? newestPayment.getTransNo() : null)
                 .amount(amount)
+                .divMemberJson(CollectionUtils.isNotEmpty(divide.getDivMembers())?JSON.toJSONString(divide.getDivMembers()):"")
                 .tenantEnterFlag(divide.getStatus()!=null && divide.getStatus().equals(PaymentStatus.SUCCESSED))
                 .status("SUCCESS")
                 .feeFlag(true)

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

@@ -4,39 +4,35 @@ 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.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.yonge.cooleshow.api.feign.dto.ImUserInfo;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.microsvc.toolkit.common.webportal.exception.BizException;
 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.EmployeeDao;
-import com.yonge.cooleshow.biz.dal.dao.StudentDao;
-import com.yonge.cooleshow.biz.dal.dao.SubjectDao;
-import com.yonge.cooleshow.biz.dal.dao.TeacherDao;
-import com.yonge.cooleshow.biz.dal.dao.UserBindingTeacherDao;
+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.mapper.SysUserMapper;
+import com.yonge.cooleshow.biz.dal.mapper.TenantGroupMapper;
 import com.yonge.cooleshow.biz.dal.service.ImGroupService;
 import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumMapper;
-import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumPurchaseMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumRefMapper;
+import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.service.ImGroupMemberService;
-import com.yonge.cooleshow.biz.dal.service.ImGroupService;
 import com.yonge.cooleshow.biz.dal.service.ImUserFriendService;
 import com.yonge.cooleshow.biz.dal.service.StudentService;
 import com.yonge.cooleshow.biz.dal.service.StudentTotalService;
 import com.yonge.cooleshow.biz.dal.service.im.ImGroupCoreService;
 import com.yonge.cooleshow.biz.dal.service.SysConfigService;
-import com.yonge.cooleshow.biz.dal.service.TeacherService;
 import com.yonge.cooleshow.biz.dal.service.TenantInfoService;
 import com.yonge.cooleshow.biz.dal.service.UserTenantAlbumRecordService;
 import com.yonge.cooleshow.biz.dal.vo.MyFollow;
@@ -52,6 +48,7 @@ import com.yonge.cooleshow.common.enums.UserLockFlag;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import com.yonge.toolset.base.util.StringUtil;
 import com.yonge.toolset.mybatis.support.PageUtil;
+import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
 import com.yonge.toolset.utils.date.DateUtil;
 import com.yonge.toolset.utils.easyexcel.ExcelDataReaderProperty;
 import com.yonge.toolset.utils.string.ValueUtil;
@@ -67,7 +64,6 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.text.MessageFormat;
-import java.text.ParseException;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
@@ -121,6 +117,10 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
     @Autowired
     private CustomerServiceConfig customerServiceConfig;
 
+
+    @Autowired
+    private SysMessageService sysMessageService;
+
     @Override
     public StudentDao getDao() {
         return baseMapper;
@@ -129,6 +129,9 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
     @Autowired
     private ImGroupCoreService imGroupCoreService;
 
+    @Autowired
+    private TenantGroupMapper tenantGroupMapper;
+
     @Override
     public StudentVo detail(Long userId) {
         return baseMapper.detail(userId);
@@ -207,11 +210,18 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
                     studentHomeVo.setTenantAlbumStatus(1);
                 }
             }
-            UserTenantAlbumRecord record =
-                    userTenantAlbumRecordService.getNewestByTenantIdAndUserId(tenantInfo.getId(), detail.getUserId(),
-                            ClientEnum.STUDENT);
+            UserTenantAlbumRecord record = userTenantAlbumRecordService.lambdaQuery()
+                    .eq(UserTenantAlbumRecord::getTenantId, tenantInfo.getId())
+                    .eq(UserTenantAlbumRecord::getUserId, detail.getUserId())
+                    .eq(UserTenantAlbumRecord::getClientType, ClientEnum.STUDENT)
+                    .orderByDesc(UserTenantAlbumRecord::getEndTime)
+                    .last("limit 1").one();
             if (record == null || record.getEndTime().getTime() < System.currentTimeMillis()) {
                 studentHomeVo.setTenantAlbumFlag(YesOrNoEnum.NO);
+                if (record != null) {
+                    studentHomeVo.setTenantAlbumStartTime(record.getStartTime());
+                    studentHomeVo.setTenantAlbumEndTime(record.getEndTime());
+                }
             } else {
                 studentHomeVo.setTenantAlbumStatus(2);
                 studentHomeVo.setTenantAlbumFlag(YesOrNoEnum.YES);
@@ -220,6 +230,12 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
             }
 
         }
+        if (detail.getTenantGroupId() != null) {
+            TenantGroup tenantGroup = tenantGroupMapper.selectById(detail.getTenantGroupId());
+            if (tenantGroup != null) {
+                studentHomeVo.setTenantGroupName(tenantGroup.getName());
+            }
+        }
 
         return studentHomeVo;
     }
@@ -434,6 +450,10 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
     @Transactional(rollbackFor = Exception.class)
     @Override
     public Boolean save(StudentWrapper.Student studentInfo) {
+        if (studentInfo.getTenantGroupId() == null) {
+            studentInfo.setTenantGroupId(-1L);
+        }
+
         if (studentInfo.getId() == null) {
             return createStudent(studentInfo);
         } else {
@@ -450,6 +470,11 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
         }
         dataList.sort(Comparator.comparingInt(ExcelDataReaderProperty::getRowIndex));
 
+        QueryWrapper<TenantGroup> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(TenantGroup::getTenantId, tenantId);
+        List<TenantGroup> groups = tenantGroupMapper.selectList(queryWrapper);
+        Map<String, Long> groupNameIdMap = groups.stream().collect(Collectors.toMap(TenantGroup::getName, TenantGroup::getId));
+
         Map<String, Long> subjectIdNamemap = subjectDao.findAll(new HashMap<>())
                 .stream().collect(Collectors.toMap(next -> next.getName(), next -> next.getId()));
         Set<String> subjectNames = subjectIdNamemap.keySet();
@@ -464,16 +489,23 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
             int msgRowNo = rowIndex + 1;
             student.checkValid().forEach(err -> errMsg.add(String.format("第%s行%s", msgRowNo, err)));
 
-            if (phoneMap.containsKey(student.getPhone().trim())) {
-                errMsg.add(String.format("第%s行手机号重复", msgRowNo));
-            } else {
-                phoneMap.put(student.getPhone().trim(), msgRowNo);
+            if (StringUtils.isNotEmpty(student.getPhone())) {
+                if (phoneMap.containsKey(student.getPhone())) {
+                    errMsg.add(String.format("第%s行手机号重复", msgRowNo));
+                } else {
+                    phoneMap.put(student.getPhone(), msgRowNo);
+                }
             }
 
-            if (!subjectNames.contains(student.getSubjectName())) {
+            if (StringUtils.isNotEmpty(student.getSubjectName()) && !subjectNames.contains(student.getSubjectName())) {
                 errMsg.add(String.format("第%s行声部不支持", msgRowNo));
             }
 
+            if (StringUtils.isNotEmpty(student.getTenantGroupName()) &&
+                    !groupNameIdMap.containsKey(student.getTenantGroupName())) {
+                errMsg.add(String.format("第%s行小组不存在", msgRowNo));
+            }
+
             if (errMsg.size() > 100) {
                 break;
             }
@@ -517,6 +549,7 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
             student.setGender("男".equals(studentImport.getGender()) ? 1 : 0);
             student.setSubjectId(subjectIdNamemap.get(studentImport.getSubjectName()).toString());
             student.setPhone(studentImport.getPhone());
+            student.setTenantGroupId(groupNameIdMap.getOrDefault(studentImport.getTenantGroupName(), -1L));
 
             LocalDate birthday = LocalDate.parse(studentImport.getBirthday(), DateTimeFormatter.ISO_LOCAL_DATE);
             student.setBirthdate(birthday);
@@ -569,8 +602,38 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
             }
         }
         this.lambdaUpdate().set(Student::getTenantId, toTenantId)
+                .set(Student::getTenantGroupId, -1L)
                 .eq(Student::getUserId, student.getUserId())
                 .update();
+
+        sendStudentTenantChange(student,toTenantId);
+    }
+
+    @Override
+    public void sendStudentTenantChange(Student student, Long toTenantId) {
+        if (student.getTenantId() == null || student.getTenantId() == -1) {
+            return;
+        }
+        SysUser sysUser = sysUserFeignService.queryUserById(student.getUserId());
+        if (sysUser == null) {
+            return;
+        }
+        TenantInfo tenantInfo = tenantInfoService.getById(student.getTenantId());
+        if (tenantInfo == null) {
+            return;
+        }
+        TenantInfo newTenantInfo = tenantInfoService.getById(toTenantId);
+        if (newTenantInfo == null) {
+            return;
+        }
+        Map<Long, String> receivers = new HashMap<>();
+        receivers.put(student.getUserId(), sysUser.getPhone());
+        try {
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.TENANT_STUDENT_CHANGE,
+                    receivers, null, 0, null, ClientEnum.TENANT_STUDENT.getCode(),tenantInfo.getName(),newTenantInfo.getName());
+        } catch (Exception e) {
+            log.error("学生机构变更极光消息推送异常,", e);
+        }
     }
 
     private Boolean updateStudent(StudentWrapper.Student studentInfo) {
@@ -615,16 +678,22 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
                 studentIds.add(student.getUserId());
                 imUserFriendService.saveUserFriend(teacher.getUserId(), studentIds);
             }
+
+            sendStudentTenantChange(student,newTenantId);
         }
 
 
         // 手机号码修改
+        boolean updatePhone = false;
         if (!student.getPhone().equals(studentInfo.getPhone())) {
-            com.yonge.cooleshow.biz.dal.entity.SysUser sysUser = getOrCreateAccount(studentInfo);
+            updatePhone = true;
+            SysUser oldSysUser = sysUserMapper.getByUserId(studentInfo.getId());
+            com.yonge.cooleshow.biz.dal.entity.SysUser sysUser = getOrCreateAccount(studentInfo, oldSysUser.getPassword());
             this.lambdaUpdate().set(Student::getSubjectId, studentInfo.getSubjectId())
                     .set(Student::getTenantId, studentInfo.getTenantId())
                     .set(Student::getUserId, sysUser.getId())
                     .set(Student::getUpdateTime, new Date())
+                    .set(Student::getTenantGroupId, studentInfo.getTenantGroupId())
                     .set(StringUtils.isNotEmpty(studentInfo.getAvatar()), Student::getAvatar, studentInfo.getAvatar())
                     .eq(Student::getUserId, studentInfo.getId())
                     .update();
@@ -635,6 +704,7 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
             newStudent.setUpdateTime(new Date());
             newStudent.setTenantId(studentInfo.getTenantId());
             newStudent.setAvatar(studentInfo.getAvatar());
+            newStudent.setTenantGroupId(studentInfo.getTenantGroupId());
             this.getBaseMapper().updateById(newStudent);
         }
         com.yonge.cooleshow.biz.dal.entity.SysUser sysUser = sysUserMapper.selectById(studentInfo.getId());
@@ -653,17 +723,92 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
         } catch (Exception e) {
             log.warn("学生注册IM失败:" + e.getMessage());
         }
+        // 手机号修改,退出登录
+        if (updatePhone) {
+            sysUserFeignService.exitByPhone(ClientEnum.STUDENT.getCode().toLowerCase(), student.getPhone());
+        }
 
         return true;
     }
 
+    private void quitFromTenantGroupIM(Long tenantGroupId, Long studentId) {
+        TenantGroup tenantGroup = tenantGroupMapper.selectById(tenantGroupId);
+        if (tenantGroup == null || StringUtils.isEmpty(tenantGroup.getImGroupId())) {
+            return;
+        }
+        String imGroupId = tenantGroup.getImGroupId();
+        ImGroup imGroup = imGroupService.getById(imGroupId);
+        if (imGroup == null) {
+            return;
+        }
+        Integer count = imGroupMemberService.lambdaQuery()
+                .eq(ImGroupMember::getId, imGroupId)
+                .eq(ImGroupMember::getUserId, studentId)
+                .eq(ImGroupMember::getRoleType, ImGroupMemberRoleType.STUDENT)
+                .count();
+        if (count == 0) {
+            return;
+        }
+        try {
+            imGroupService.quit(imGroupId, studentId, ClientEnum.STUDENT, true);
+        } catch (Exception e) {
+            log.error("退出机构小组群失败", e);
+            throw new BizException("退出机构小组群失败");
+        }
+    }
+
+    /**
+     * 添加到机构小组IM群
+     * @param tenantGroupId 机构小组ID
+     * @param studentId 学生ID
+     */
+    private void add2TenantGroupIM(Long tenantGroupId, Long studentId) {
+        TenantGroup tenantGroup = tenantGroupMapper.selectById(tenantGroupId);
+        String imGroupId = tenantGroup.getImGroupId();
+        if (imGroupId == null) {
+            // 建群
+            try {
+                ImGroupWrapper.ImGroup imGroup = new ImGroupWrapper.ImGroup();
+                imGroup.setId(IdWorker.getId());
+                imGroup.setCreateBy(tenantGroup.getAdminId());
+                imGroup.setType(ImGroupType.ORG.getCode());
+                imGroup.setName(tenantGroup.getName());
+                imGroupId = imGroupService.create(imGroup);
+                tenantGroup.setImGroupId(imGroupId);
+                tenantGroupMapper.updateById(tenantGroup);
+            } catch (Exception e) {
+                log.error("创建机构小组群失败", e);
+                throw new BizException("创建机构小组群失败");
+            }
+        }
+        if ("-1".equals(imGroupId)) {
+            // 群已经解散,改为-1标志
+            log.info("群已经解散,不再添加机构小组群:" + imGroupId);
+            return;
+        }
+        try {
+            ImGroup imGroup = imGroupService.getById(imGroupId);
+            if (imGroup != null) {
+                Set<Long> userIds = new HashSet<>();
+                userIds.add(studentId);
+                imGroupService.addGroupMember(imGroupId, userIds);
+            } else {
+                tenantGroup.setImGroupId("-1");
+                tenantGroupMapper.updateById(tenantGroup);
+            }
+        } catch (Exception e) {
+            log.error("加入机构小组群失败", e);
+            throw new BizException("加入机构小组群失败");
+        }
+    }
+
     private Boolean createStudent(StudentWrapper.Student studentInfo) {
         String avatar = studentInfo.getAvatar();
         if (StringUtils.isEmpty(avatar)) {
             avatar = sysConfigService.findConfigValue(SysConfigConstant.STUDENT_AVATAR);
             studentInfo.setAvatar(avatar);
         }
-        com.yonge.cooleshow.biz.dal.entity.SysUser sysUser = getOrCreateAccount(studentInfo);
+        com.yonge.cooleshow.biz.dal.entity.SysUser sysUser = getOrCreateAccount(studentInfo, null);
         Student student = new Student();
         student.setUserId(sysUser.getId());
         student.setTenantId(studentInfo.getTenantId());
@@ -671,6 +816,7 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
         student.setAvatar(studentInfo.getAvatar());
         student.setCreateTime(new Date());
         student.setLockFlag(UserLockFlag.NORMAL);
+        student.setTenantGroupId(studentInfo.getTenantGroupId());
 
         save(student);
         try {
@@ -692,7 +838,7 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
 
         //  与随机一个客服建立好友
         String customerService = customerServiceConfig.getCustomerService();
-        if(StringUtils.isNotBlank(customerService)){
+        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()));
@@ -703,10 +849,16 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
             }
         }
 
+        // 加入机构小组群
+//        if (studentInfo.getTenantGroupId() != -1L) {
+//            add2TenantGroupIM(student.getTenantGroupId(), student.getUserId());
+//        }
+
         return true;
     }
 
-    private com.yonge.cooleshow.biz.dal.entity.SysUser getOrCreateAccount(StudentWrapper.Student studentInfo) {
+    private com.yonge.cooleshow.biz.dal.entity.SysUser getOrCreateAccount(StudentWrapper.Student studentInfo,
+                                                                          String password) {
         QueryWrapper<com.yonge.cooleshow.biz.dal.entity.SysUser> sysUserQueryWrapper = new QueryWrapper<>();
         sysUserQueryWrapper.lambda().eq(com.yonge.cooleshow.biz.dal.entity.SysUser::getPhone, studentInfo.getPhone());
         List<com.yonge.cooleshow.biz.dal.entity.SysUser> sysUsers = sysUserMapper.selectList(sysUserQueryWrapper);
@@ -742,10 +894,13 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
             sysUser.setUserType("STUDENT");
             sysUser.setBirthdate(studentInfo.getBirthdate());
             sysUser.setUsername(studentInfo.getName());
-
-            String newPassword = MessageFormat.format("klx{0}", studentInfo.getPhone().substring(7));
-            String password = new BCryptPasswordEncoder().encode(newPassword);
             sysUser.setPassword(password);
+
+            if (StringUtils.isEmpty(password)) {
+                String newPassword = MessageFormat.format("klx{0}", studentInfo.getPhone().substring(7));
+                sysUser.setPassword(new BCryptPasswordEncoder().encode(newPassword));
+            }
+
             sysUserMapper.insert(sysUser);
         }
         return sysUser;

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

@@ -1,52 +1,38 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Random;
-import java.util.Set;
-import java.util.stream.Collectors;
-
 import com.alibaba.fastjson.JSON;
-import com.yonge.cooleshow.biz.dal.dto.JumpUrlDto;
-import com.yonge.toolset.base.string.MessageFormatter;
-import com.yonge.toolset.mybatis.service.impl.BaseServiceImpl;
-
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
-import com.yonge.cooleshow.biz.dal.dao.SysConfigDao;
 import com.yonge.cooleshow.biz.dal.dao.SysMessageDao;
-import com.yonge.cooleshow.biz.dal.dto.SysMessageDto;
+import com.yonge.cooleshow.biz.dal.dto.JumpUrlDto;
 import com.yonge.cooleshow.biz.dal.entity.SysMessage;
 import com.yonge.cooleshow.biz.dal.entity.SysMessageConfig;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.MessageSendMode;
 import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
 import com.yonge.cooleshow.biz.dal.enums.SendStatusEnum;
 import com.yonge.cooleshow.biz.dal.service.SysMessageConfigService;
 import com.yonge.cooleshow.biz.dal.service.SysMessageService;
-import com.yonge.toolset.mybatis.dal.BaseDAO;
 import com.yonge.cooleshow.common.entity.Mapper;
-import com.yonge.toolset.base.exception.BizException;
-import com.yonge.toolset.base.page.PageInfo;
-import com.yonge.toolset.base.page.QueryInfo;
 import com.yonge.cooleshow.common.redis.service.RedisCache;
+import com.yonge.toolset.base.exception.BizException;
+import com.yonge.toolset.base.string.MessageFormatter;
+import com.yonge.toolset.mybatis.dal.BaseDAO;
+import com.yonge.toolset.mybatis.service.impl.BaseServiceImpl;
 import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
 import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext.MessageSender;
-import com.yonge.toolset.utils.collection.MapUtil;
-
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+
 @Service
 public class SysMessageServiceImpl extends BaseServiceImpl<Long, SysMessage> implements SysMessageService {
 
@@ -61,8 +47,6 @@ public class SysMessageServiceImpl extends BaseServiceImpl<Long, SysMessage> imp
 	@Autowired
 	private SysUserFeignService sysUserFeignService;
 	@Autowired
-	private SysConfigDao sysConfigDao;
-	@Autowired
 	private RedisCache<String, Object> redisCache;
 	// 验证码有效期
 	public static final int CODE_EXPIRE = 60 * 10;
@@ -86,26 +70,6 @@ public class SysMessageServiceImpl extends BaseServiceImpl<Long, SysMessage> imp
 		return sysMessageDao;
 	}
 
-	@Override
-	public PageInfo<SysMessageDto> queryListPage(QueryInfo queryInfo) {
-		PageInfo<SysMessageDto> pageInfo = new PageInfo<SysMessageDto>(queryInfo.getPage(), queryInfo.getRows());
-		Map<String, Object> params = new HashMap<String, Object>();
-		MapUtil.populateMap(params, queryInfo);
-
-		List<SysMessageDto> dataList = null;
-		int count = this.findCount(params);
-		if (count > 0) {
-			pageInfo.setTotal(count);
-			params.put("offset", pageInfo.getOffset());
-			dataList = sysMessageDao.queryListPage(params);
-		}
-		if (count == 0) {
-			dataList = new ArrayList<SysMessageDto>();
-		}
-		pageInfo.setRows(dataList);
-		return pageInfo;
-	}
-
 	/**
 	 * 添加消息
 	 * @param subject 消息主题
@@ -164,52 +128,6 @@ public class SysMessageServiceImpl extends BaseServiceImpl<Long, SysMessage> imp
 		return sysMessageDao.batchInsert(messages);
 	}
 
-	@Override
-	@Transactional(rollbackFor = Exception.class)
-	public int updateMessage(SysMessage message) {
-		return sysMessageDao.update(message);
-	}
-
-	@Override
-	public boolean batchSeoMessage(Set<Long> userIds, MessageTypeEnum messageType,String memo, Object... args) {
-		if(userIds != null){
-			userIds.removeAll(Collections.singleton(null));
-		}
-		if (userIds == null || userIds.size() == 0) {
-			LOGGER.error("接收地址不能为空");
-			return false;
-		}
-		SysMessageConfig messageConfig = sysMessageConfigService.queryByType(messageType.getCode());
-		if (messageConfig == null) {
-			throw new BizException("消息类型错误");
-		}else if(messageConfig.getSendFlag() == null || messageConfig.getSendFlag() == 0){
-			return true;
-		}
-		Date date = new Date();
-		SendStatusEnum status = SendStatusEnum.SUCCESSED;
-		String content = MessageFormatter.arrayFormat(messageConfig.getContent(), args);
-		SysMessage message = null;
-
-		List<SysMessage> messages = new ArrayList<>();
-		for (Long userId : userIds) {
-			message = new SysMessage();
-			message.setUserId(userId);
-			message.setContent(content);
-			message.setCreateOn(date);
-			message.setModifyOn(date);
-			message.setReceiver(userId.toString());
-			message.setSendTime(date);
-			message.setStatus(status);
-			message.setType(MessageSendMode.SEO);
-			message.setTitle(messageConfig.getDescription());
-			message.setReadStatus(0);
-			message.setMemo(memo);
-			message.setGroup(messageConfig.getGroup());
-			messages.add(message);
-		}
-		sysMessageDao.batchInsert(messages);
-		return true;
-	}
 
 	@Override
 	public void batchSendMessage(MessageSender messageSender, MessageTypeEnum type, Map<Long, String> receivers, Date triggerTime, Integer readStatus,
@@ -220,7 +138,7 @@ public class SysMessageServiceImpl extends BaseServiceImpl<Long, SysMessage> imp
 			return;
 		}
 		if (StringUtils.isEmpty(url)) {
-			url = selectConfigUrl(type.getCode());
+			url = selectConfigUrlJumpType(type.getCode(),jpushType);
 		}
 
 		String[] tos;
@@ -271,6 +189,9 @@ public class SysMessageServiceImpl extends BaseServiceImpl<Long, SysMessage> imp
 		} else if (messageSender.getSendMode().equals("EMAIL")) {
 			mode = MessageSendMode.EMAIL;
 		}
+        if (ClientEnum.TENANT_STUDENT.getCode().equals(jpushType)) {
+            jpushType = ClientEnum.STUDENT.getCode();
+        }
 		addMessage(receivers, messageConfig.getDescription(), MessageFormatter.arrayFormat(messageConfig.getContent(), args), triggerTime, mode, status, errorMsg, readStatus,
 				url, messageConfig.getGroup(),jpushType,messageConfig.getId());
 	}
@@ -334,45 +255,6 @@ public class SysMessageServiceImpl extends BaseServiceImpl<Long, SysMessage> imp
 	}
 
 	@Override
-	public void batchPushMessage(MessageTypeEnum type, Map<Long, String> receivers, Date triggerTime, Integer readStatus,
-			String url,String jpushType,String sound,String channelId, Object... args) {
-		if (receivers == null || receivers.size() == 0) {
-			throw new BizException("接收地址不能为空");
-		}
-		String[] tos = receivers.values().toArray(new String[receivers.size()]);
-		SysMessageConfig messageConfig = sysMessageConfigService.queryByType(type.getCode());
-		if (messageConfig == null) {
-			throw new BizException("消息类型错误");
-		}else if(messageConfig.getSendFlag() == null || messageConfig.getSendFlag() == 0){
-			return;
-		}
-		Date date = new Date();
-		SendStatusEnum status = SendStatusEnum.WAIT;
-		String errorMsg = null;
-		// 立即发送
-		if (triggerTime == null || date.after(triggerTime)) {
-			status = SendStatusEnum.SENDING;
-			try {
-				if (isSendRemoteMessage(MessageSender.JIGUANG)) {
-					errorMsg = messageSenderPluginContext.batchSend(MessageSender.JIGUANG, messageConfig.getDescription(),
-														 MessageFormatter.arrayFormat(messageConfig.getContent(), args), tos, url,jpushType,sound,channelId);
-					if (StringUtils.isEmpty(errorMsg)) {
-						status = SendStatusEnum.SUCCESSED;
-					}  else {
-						status = SendStatusEnum.FAILED;
-					}
-				}
-			} catch (Exception e) {
-				status = SendStatusEnum.FAILED;
-				errorMsg = e.getMessage();
-				LOGGER.warn("消息发送失败", e);
-			}
-		}
-		addMessage(receivers, messageConfig.getDescription(), MessageFormatter.arrayFormat(messageConfig.getContent(), args), triggerTime, MessageSendMode.PUSH, status, errorMsg, readStatus,
-				url, messageConfig.getGroup(),jpushType,messageConfig.getId());
-	}
-
-	@Override
 	public void sendMessage(MessageSender messageSender, Long userId, String title, String content, String receiver, Date triggerTime, Integer readStatus, String url, String group,String jpushType) {
 		LOGGER.info("batchSendMessage {}, userId {}, receivers {} ", messageSender, userId, receiver);
 		if (StringUtils.isBlank(receiver)) {
@@ -444,14 +326,6 @@ public class SysMessageServiceImpl extends BaseServiceImpl<Long, SysMessage> imp
 	}
 
 	@Override
-	public void delSendedVerificationCode(MessageTypeEnum type, String mobileNOOrEmailAddr) {
-		String key = getVerificationCodeCacheKey(type, mobileNOOrEmailAddr);
-		if (StringUtils.isNotBlank(key)) {
-			redisCache.delete(key);
-		}
-	}
-
-	@Override
 	public List<Mapper> queryCountOfUnread(MessageSendMode type, Long userId, String jpushType) {
 		return sysMessageDao.queryCountOfUnread(type, userId, jpushType);
 
@@ -503,6 +377,11 @@ public class SysMessageServiceImpl extends BaseServiceImpl<Long, SysMessage> imp
 
 	@Override
 	public String selectConfigUrl(String messageType,Object ...param) {
+        return selectConfigUrlJumpType(messageType,null,param);
+    }
+
+	@Override
+    public String selectConfigUrlJumpType(String messageType,String jumpType,Object ...param) {
 		SysMessageConfig sysMessageConfig = sysMessageConfigService.queryByType(messageType);
 		if (sysMessageConfig == null) {
 			throw new BizException("消息类型错误");
@@ -522,6 +401,9 @@ public class SysMessageServiceImpl extends BaseServiceImpl<Long, SysMessage> imp
 		jumpUrlDto.setUrl(sysMessageConfig.getActionUrl());
 		jumpUrlDto.setPageTag(sysMessageConfig.getPageTag());
 		jumpUrlDto.setParams(sysMessageConfig.getParams());
+        if (StringUtils.isNotBlank(jumpType) && ClientEnum.TENANT_STUDENT.getCode().equals(jumpType)) {
+            jumpUrlDto.setClientType("TENANT");
+        }
 		return JSON.toJSONString(jumpUrlDto);
 	}
 }

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

@@ -6,10 +6,7 @@ import com.google.common.collect.Lists;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dao.MusicSheetDao;
 import com.yonge.cooleshow.biz.dal.dao.SysMusicCompareRecordDao;
-import com.yonge.cooleshow.biz.dal.dto.IndexBaseDto;
-import com.yonge.cooleshow.biz.dal.dto.IndexBaseMonthData;
-import com.yonge.cooleshow.biz.dal.dto.StudentTrainChartDto;
-import com.yonge.cooleshow.biz.dal.dto.StudentTrainOverviewDto;
+import com.yonge.cooleshow.biz.dal.dto.*;
 import com.yonge.cooleshow.biz.dal.entity.*;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.FeatureType;
@@ -452,9 +449,8 @@ public class SysMusicCompareRecordServiceImpl extends BaseServiceImpl<Long, SysM
     @Override
     public SysMusicCompareRecordQueryInfo.StatDto rankingList(SysMusicCompareRecordQueryInfo.StudentCompareRecordQueryInfo queryInfo) {
 		SysMusicCompareRecordQueryInfo.StatDto result = new SysMusicCompareRecordQueryInfo.StatDto();
-		SysMusicCompareRecordQueryInfo.MusicCompareRankingDto head = new SysMusicCompareRecordQueryInfo.MusicCompareRankingDto();
-		head.setUserId(queryInfo.getUserId());
-		List<SysMusicCompareRecordQueryInfo.MusicCompareRankingDto> userTrainStat = sysMusicCompareWeekDataService.getDao().getUserTrainStat(queryInfo.getStartTime(),
+		SysMusicCompareRecordQueryInfo.MusicCompareRankingDto head = null;
+		List<SysMusicCompareRecordQueryInfo.MusicCompareRankingDto> userTrainStat = sysMusicCompareWeekDataService.getDao().queryUserTrainStat(queryInfo.getStartTime(),
 				queryInfo.getOrderType(),
 				Objects.isNull(queryInfo.getHeardLevel())?null:queryInfo.getHeardLevel().getCode(),
 				queryInfo.getTenantId());
@@ -474,9 +470,9 @@ public class SysMusicCompareRecordServiceImpl extends BaseServiceImpl<Long, SysM
 				head = userTrainStat.get(i);
 			}
 			userTrainStat.get(i).setTrainTime(userTrainStat.get(i).getTrainTime()/60);
-			if(userTrainStat.get(i).getVipUser() <= 0){
-				continue;
-			}
+//			if(userTrainStat.get(i).getVipUser() <= 0){
+//				continue;
+//			}
 			userTrainStat.get(i).setRankNum(++rankNum);
 			if(studentSubjectMap.containsKey(userTrainStat.get(i).getUserId())){
 				userTrainStat.get(i).setSubjectName(studentSubjectMap.get(userTrainStat.get(i).getUserId()));
@@ -487,13 +483,18 @@ public class SysMusicCompareRecordServiceImpl extends BaseServiceImpl<Long, SysM
 		}
 		Map<String,Object> params = new HashMap<String, Object>(1);
 		params.put("tenantId", queryInfo.getTenantId());
-		head.setStudentNum(studentService.getDao().countStudentsWithTenant(params));
-		if(StringUtils.isBlank(head.getAvatar())){
-			SysUser user = sysUserService.findUserById(queryInfo.getUserId());
-			if(user != null){
-				head.setAvatar(user.getAvatar());
+		if(Objects.isNull(head)){
+			head = new SysMusicCompareRecordQueryInfo.MusicCompareRankingDto();
+			BasicUserInfo basicUserInfo = teacherService.getDao().getBasicUserInfo(queryInfo.getUserId());
+			head.setUserId(basicUserInfo.getUserId());
+			head.setAvatar(basicUserInfo.getAvatar());
+			head.setStudentName(basicUserInfo.getUsername());
+			List<Subject> subjects = teacherService.getDao().querySubject(basicUserInfo.getUserId());
+			if(CollectionUtils.isNotEmpty(subjects)){
+				head.setSubjectName(subjects.stream().map(e->e.getName()).collect(Collectors.joining()));
 			}
 		}
+		head.setStudentNum(studentService.getDao().countStudentsWithTenant(params));
 		result.setHead(head);
 		detail.sort(Comparator.comparing(SysMusicCompareRecordQueryInfo.MusicCompareRankingDto::getRankNum).
 				thenComparing(SysMusicCompareRecordQueryInfo.MusicCompareRankingDto::getUserId));

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

@@ -37,6 +37,12 @@ public class SysUserServiceImpl implements SysUserService {
 
     @Resource
     private SysUserContractRecordService sysUserContractRecordService;
+
+    @Override
+    public SysUserMapper getDao() {
+        return sysUserMapper;
+    }
+
     @Override
     public Long getUserId() {
         return Optional.ofNullable(sysUserFeignService.queryUserInfo()).

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

@@ -20,10 +20,12 @@ 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.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.mapper.TenantGroupMapper;
 import com.yonge.cooleshow.biz.dal.queryInfo.TeacherQueryInfo;
 import com.yonge.cooleshow.biz.dal.service.ImGroupService;
 import com.yonge.cooleshow.biz.dal.service.StudentService;
@@ -84,13 +86,7 @@ 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;
-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;
 
@@ -107,6 +103,13 @@ 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;
+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;
@@ -197,6 +200,14 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
     @Autowired
     private SysUserMapper sysUserMapper;
 
+    @Autowired
+    private TenantGroupMapper tenantGroupMapper;
+
+
+    @Override
+    public TeacherDao getDao() {
+        return baseMapper;
+    }
 
     @Override
     public TeacherVo detail(Long userId) {
@@ -249,7 +260,24 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
                 .eq(MusicSheet::getSourceType, "TEACHER").list();
 
         Map<Long, List<MusicSheet>> groupByUserId = musicSheets.stream().collect(Collectors.groupingBy(MusicSheet::getUserId));
+
+        // 添加小组信息
+        Map<Long, List<TenantGroup>> groupByAdminId = new HashMap<>();
+        List<Long> teacherIds = teacherVos.stream().map(Teacher::getUserId).distinct().collect(Collectors.toList());
+        if(!teacherIds.isEmpty()){
+            QueryWrapper<TenantGroup> queryWrapper = new QueryWrapper<>();
+            queryWrapper.lambda().in(TenantGroup::getAdminId,teacherIds);
+            List<TenantGroup> tenantGroups = tenantGroupMapper.selectList(queryWrapper);
+            Map<Long, List<TenantGroup>> groupBy = tenantGroups.stream().collect(Collectors.groupingBy(TenantGroup::getAdminId));
+            groupByAdminId.putAll(groupBy);
+        }
+
+
         for (TeacherVo teacherVo : teacherVos) {
+            List<String> groups = groupByAdminId.getOrDefault(teacherVo.getUserId(), new ArrayList<>())
+                    .stream().map(TenantGroup::getName).collect(Collectors.toList());
+            teacherVo.setTenantGroupName(String.join(",", groups));
+
             List<MusicSheet> musicSheetList = groupByUserId.getOrDefault(teacherVo.getUserId(), new ArrayList<>());
             teacherVo.setMusicSheetCount(musicSheetList.size());
             List<String> names = musicSheetList.stream().map(MusicSheet::getMusicSheetName).collect(Collectors.toList());
@@ -475,7 +503,7 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
         }
         //  与客服建立好友
         String customerService = customerServiceConfig.getCustomerService();
-        if(StringUtils.isNotBlank(customerService)){
+        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()));
@@ -553,16 +581,6 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
                 log.error("导入IM账号到三方 teacherId={}", teacher.getUserId(), e);
             }
 
-            // 机构老师与学生互加好友关系
-//            if (Optional.ofNullable(teacher.getTenantId()).orElse(-1L) > 0) {
-//                // 自动与机构老师成为好友
-//                Set<Long> collect = studentService.lambdaQuery()
-//                        .eq(Student::getTenantId, teacher.getTenantId()).list().stream()
-//                        .map(Student::getUserId).collect(Collectors.toSet());
-//
-//                imUserFriendService.saveUserFriend(teacher.getUserId(), collect);
-//            }
-
             //插入老师账户表
             UserAccount oldAcc = userAccountService.getById(teacherSubmitReq.getUserId());
             if (null == oldAcc) {
@@ -1038,7 +1056,7 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
         return wrapper;
     }
 
-//    @Transactional(rollbackFor = Exception.class)
+    @Transactional(rollbackFor = Exception.class)
     @Override
     public void updateTenant(TeacherWrapper.UpdateTenant updateTenant,Long userId) {
         Teacher teacher = this.getById(updateTenant.getTeacherId());
@@ -1047,18 +1065,35 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
         }
         Long oldTenantId = teacher.getTenantId();
         if (oldTenantId != -1L) {
+            // 判断是否存在机构小组群主身份
+            QueryWrapper<TenantGroup> queryWrapper = new QueryWrapper<>();
+            queryWrapper.lambda()
+                    .eq(TenantGroup::getTenantId, oldTenantId)
+                    .eq(TenantGroup::getAdminId, teacher.getUserId());
+            Integer count = tenantGroupMapper.selectCount(queryWrapper);
+            if (count > 0) {
+                throw new BizException("该老师存在机构小组负责人身份,请先更换老师或者退出小组");
+            }
+
             // 机构老师处理流程
-            List<ImGroup> imGroups = imGroupService.lambdaQuery()
-                    .eq(ImGroup::getCreateBy, teacher.getUserId())
-                    .eq(ImGroup::getType, ImGroupType.ORG)
-                    .list();
-            imGroups.forEach(next -> {
-                try {
-                    imGroupService.dismiss(next.getId());
-                } catch (Exception e) {
-                    log.error("老师修改机构,解散机构群失败:{}", e.getMessage());
-                }
-            });
+            List<String> imGroupIds = imGroupMemberService.lambdaQuery()
+                    .eq(ImGroupMember::getUserId, teacher.getUserId())
+                    .eq(ImGroupMember::getIsAdmin, true)
+                    .eq(ImGroupMember::getRoleType, ImGroupMemberRoleType.TEACHER)
+                    .list().stream().map(ImGroupMember::getGroupId).distinct().collect(Collectors.toList());
+            if (!imGroupIds.isEmpty()) {
+                List<ImGroup> imGroups = imGroupService.lambdaQuery()
+                        .in(ImGroup::getId, imGroupIds)
+                        .eq(ImGroup::getType, ImGroupType.ORG)
+                        .list();
+                imGroups.forEach(next -> {
+                    try {
+                        imGroupService.dismiss(next.getId());
+                    } catch (Exception e) {
+                        log.error("老师修改机构,解散机构群失败:{}", e.getMessage());
+                    }
+                });
+            }
             // 删除好友关系
             imUserFriendService.delStudentFriendByTenantId(teacher.getTenantId(), teacher.getUserId(),ClientEnum.TEACHER.getCode());
 

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

@@ -1,30 +1,21 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
 import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.alipay.api.domain.NextUrl;
 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.service.impl.ServiceImpl;
-import com.google.common.collect.Lists;
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.biz.dal.dao.StudentDao;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentSearch;
-import com.yonge.cooleshow.biz.dal.entity.Student;
-import com.yonge.cooleshow.biz.dal.entity.SysUser;
-import com.yonge.cooleshow.biz.dal.entity.TenantActivationCode;
-import com.yonge.cooleshow.biz.dal.entity.TenantAlbumPurchase;
-import com.yonge.cooleshow.biz.dal.entity.TenantInfo;
-import com.yonge.cooleshow.biz.dal.entity.UserTenantAlbumRecord;
+import com.yonge.cooleshow.biz.dal.entity.*;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
 import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
-import com.yonge.cooleshow.biz.dal.enums.im.EImSendStatus;
-import com.yonge.cooleshow.biz.dal.mapper.SysUserMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantActivationCodeMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumPurchaseMapper;
 import com.yonge.cooleshow.biz.dal.mapper.UserTenantAlbumRecordMapper;
-import com.yonge.cooleshow.biz.dal.service.TenantActivationCodeService;
-import com.yonge.cooleshow.biz.dal.service.TenantAlbumService;
+import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.vo.StudentVo;
 import com.yonge.cooleshow.biz.dal.vo.UserOrderDetailVo;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantActivationCodeWrapper;
@@ -33,6 +24,7 @@ import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.enums.EActivationCode;
 import com.yonge.toolset.base.exception.BizException;
 import com.yonge.toolset.mybatis.support.PageUtil;
+import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
 import com.yonge.toolset.utils.easyexcel.ExcelDataReaderProperty;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;
@@ -46,7 +38,6 @@ import java.util.*;
 import java.util.function.Function;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * 机构激活码
@@ -60,7 +51,7 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
     private StudentDao studentDao;
 
     @Autowired
-    private SysUserMapper sysUserMapper;
+    private SysUserService sysUserService;
 
     @Autowired
     private TenantAlbumPurchaseMapper tenantAlbumPurchaseMapper;
@@ -69,7 +60,10 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
     private UserTenantAlbumRecordMapper userTenantAlbumRecordMapper;
 
     @Autowired
-    private TenantAlbumService tenantAlbumService;
+    private TenantInfoService tenantInfoService;
+
+    @Autowired
+    private SysMessageService sysMessageService;
 
     private static final String PHONE_REG = "^1\\d{10}$";
 
@@ -156,7 +150,7 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
         }
 
         List<Long> studentIds = students.stream().map(Student::getUserId).collect(Collectors.toList());
-        Map<Long, String> idPhoneMap = sysUserMapper.selectBatchIds(studentIds).stream()
+        Map<Long, String> idPhoneMap = sysUserService.getDao().selectBatchIds(studentIds).stream()
                 .collect(Collectors.toMap(SysUser::getId, SysUser::getPhone));
 
         for (int i = 0; i < studentIds.size(); i++) {
@@ -171,6 +165,31 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
                 throw new BizException("激活码已被激活:" + tenantActivationCodes.get(i).getActivationCode());
             }
         }
+        if (idPhoneMap.size() >0) {
+            idPhoneMap.forEach(this::sendActivationCodeMessage);
+        }
+    }
+
+    private void sendActivationCodeMessage(Long userId,String phone) {
+
+        Map<Long, String> receivers = new HashMap<>(1);
+        receivers.put(userId, phone);
+        try {
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.TENANT_SEND_CODE,
+                    receivers, null, 0, null, ClientEnum.TENANT_STUDENT.getCode());
+        } catch (Exception e) {
+            log.error("机构发放激活码推送异常", e);
+        }
+    }
+
+    @Override
+    public void sendCancelActivationCodeMessage(Map<Long, String> receivers, String tenantName) {
+        try {
+            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.TENANT_CODE_SENDCANCEL,
+                    receivers, null, 0, null, ClientEnum.TENANT_STUDENT.getCode(),tenantName);
+        } catch (Exception e) {
+            log.error("机构发放激活码推送异常", e);
+        }
     }
 
     @Override
@@ -191,7 +210,7 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
         if (code == null) {
             throw new BizException("激活码不存在");
         }
-        SysUser sysUser = sysUserMapper.selectById(studentId);
+        SysUser sysUser = sysUserService.getDao().selectById(studentId);
         if (Boolean.TRUE.equals(code.getActivationStatus()) || (EActivationCode.SEND.equals(code.getSendStatus()) &&
                 !sysUser.getPhone().equals(code.getActivationPhone()))) {
             throw new BizException("激活码已经被使用");
@@ -243,7 +262,7 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
         if(code == null || !code.getTenantId().equals(tenantId)) {
             throw new BizException("激活码不存在");
         }
-        SysUser sysUser = sysUserMapper.selectById(student.getUserId());
+        SysUser sysUser = sysUserService.getDao().selectById(student.getUserId());
         if(!sysUser.getPhone().equals(code.getActivationPhone())) {
             // 该激活码未指定为当前学生使用
             throw new BizException("激活码不存在");
@@ -299,16 +318,41 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
             throw new BizException("激活码已经被使用");
         }
 
-        SysUser sysUser = sysUserMapper.selectById(userId);
+        SysUser sysUser = sysUserService.getDao().selectById(userId);
         if (sysUser == null) {
             throw new BizException("用户不存在");
         }
         one.setActivationPhone(sysUser.getPhone());
         this.updateById(one);
+        TenantInfo tenantInfo = tenantInfoService.getById(tenantId);
+        Map<Long, String> receivers = new HashMap<>(1);
+        receivers.put(userId, sysUser.getPhone());
+        this.sendCancelActivationCodeMessage(receivers,tenantInfo.getName());
+        this.sendActivationCodeMessage(userId,sysUser.getPhone());
     }
 
     @Transactional(rollbackFor = Exception.class)
     @Override
+    public void sendCancel(TenantInfo tenantInfo, TenantActivationCode activationCode) {
+        boolean update = this.lambdaUpdate()
+                .set(TenantActivationCode::getSendStatus, EActivationCode.WAIT)
+                .set(TenantActivationCode::getActivationPhone, "")
+                .eq(TenantActivationCode::getId, activationCode.getId())
+                .eq(TenantActivationCode::getActivationStatus, false)
+                .eq(TenantActivationCode::getSendStatus, EActivationCode.SEND)
+                .update();
+        if (!update) {
+            throw new BizException("激活码已经激活");
+        }
+        com.yonge.cooleshow.auth.api.entity.SysUser sysUser = sysUserService.findUserByPhone(activationCode.getActivationPhone());
+        if (sysUser != null) {
+            Map<Long, String> receivers = new HashMap<>(1);
+            receivers.put(sysUser.getId(), activationCode.getActivationPhone());
+            this.sendCancelActivationCodeMessage(receivers,tenantInfo.getName());
+        }
+    }
+    @Transactional(rollbackFor = Exception.class)
+    @Override
     public void batchSendCancel(TenantInfo tenantInfo, String ids) {
         List<Long> idList = Arrays.stream(ids.split(",")).map(Long::valueOf).distinct().collect(Collectors.toList());
         Collection<TenantActivationCode> tenantActivationCodes = this.listByIds(idList);
@@ -322,15 +366,9 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
             throw new BizException("无可撤回的激活码");
         }
 
-        this.lambdaUpdate()
-                .set(TenantActivationCode::getSendStatus, EActivationCode.WAIT)
-                .set(TenantActivationCode::getActivationPhone, "")
-                .in(TenantActivationCode::getId, idList)
-                .eq(TenantActivationCode::getActivationStatus, false)
-                .eq(TenantActivationCode::getSendStatus, EActivationCode.SEND)
-                .eq(TenantActivationCode::getTenantId,tenantInfo.getId())
-                .update();
-
+        for (TenantActivationCode code : tenantActivationCodes) {
+            this.sendCancel(tenantInfo, code);
+        }
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -357,7 +395,7 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
             throw new BizException("可发激活码的数量小于学生的数量");
         }
 
-        List<SysUser> sysUsers = sysUserMapper.selectBatchIds(studentIdList);
+        List<SysUser> sysUsers = sysUserService.getDao().selectBatchIds(studentIdList);
         Map<Long, String> mapPhoneById = sysUsers.stream().collect(Collectors.toMap(SysUser::getId, SysUser::getPhone));
 
         List<TenantActivationCode> updates = new ArrayList<>();

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

@@ -0,0 +1,66 @@
+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 org.springframework.stereotype.Service;
+import org.springframework.beans.BeanUtils;
+import lombok.extern.slf4j.Slf4j;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategoryDetail;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumCategoryDetailWrapper;
+import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumCategoryDetailMapper;
+import com.yonge.cooleshow.biz.dal.service.TenantAlbumCategoryDetailService;
+
+/**
+ * 机构专辑分类详情
+ * 2023-10-10 10:17:38
+ */
+@Slf4j
+@Service
+public class TenantAlbumCategoryDetailServiceImpl extends ServiceImpl<TenantAlbumCategoryDetailMapper, TenantAlbumCategoryDetail> implements TenantAlbumCategoryDetailService {
+
+    /**
+     * 查询详情
+     * @param id 详情ID
+     * @return TenantAlbumCategoryDetail
+     */
+    @Override
+    public TenantAlbumCategoryDetail detail(Long id) {
+
+        return baseMapper.selectById(id);
+    }
+
+    /**
+     * 分页查询
+     * @param page IPage<TenantAlbumCategoryDetail>
+     * @param query TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetailQuery
+     * @return IPage<TenantAlbumCategoryDetail>
+     */
+    @Override
+    public IPage<TenantAlbumCategoryDetail> selectPage(IPage<TenantAlbumCategoryDetail> page, TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetailQuery query) {
+
+        return page.setRecords(baseMapper.selectPage(page, query));
+    }
+
+    /**
+     * 添加
+     * @param tenantAlbumCategoryDetail TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetail
+     * @return Boolean
+     */
+    @Override
+    public Boolean add(TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetail tenantAlbumCategoryDetail) {
+
+        return this.save(JSON.parseObject(tenantAlbumCategoryDetail.jsonString(), TenantAlbumCategoryDetail.class));
+    }
+
+    /**
+     * 更新
+     * @param tenantAlbumCategoryDetail TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetail
+     * @return Boolean
+     */
+    @Override
+    public Boolean update(TenantAlbumCategoryDetailWrapper.TenantAlbumCategoryDetail tenantAlbumCategoryDetail){
+
+        return this.updateById(JSON.parseObject(tenantAlbumCategoryDetail.jsonString(), TenantAlbumCategoryDetail.class));
+    }
+}

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

@@ -0,0 +1,250 @@
+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.extension.service.impl.ServiceImpl;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbum;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategory;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategoryDetail;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumMusic;
+import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumCategoryMapper;
+import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumMapper;
+import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumMusicMapper;
+import com.yonge.cooleshow.biz.dal.service.TenantAlbumCategoryDetailService;
+import com.yonge.cooleshow.biz.dal.service.TenantAlbumCategoryService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumCategoryWrapper;
+import com.yonge.cooleshow.common.enums.ETenantAlbumCategoryType;
+import com.yonge.toolset.base.exception.BizException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 机构专辑分类
+ * 2023-10-10 09:48:46
+ */
+@Slf4j
+@Service
+public class TenantAlbumCategoryServiceImpl extends ServiceImpl<TenantAlbumCategoryMapper, TenantAlbumCategory> implements TenantAlbumCategoryService {
+
+    @Autowired
+    private TenantAlbumCategoryDetailService tenantAlbumCategoryDetailService;
+    @Autowired
+    private TenantAlbumMusicMapper tenantAlbumMusicMapper;
+    @Autowired
+    private TenantAlbumMapper tenantAlbumMapper;
+
+    /**
+     * 查询详情
+     *
+     * @param id 详情ID
+     * @return TenantAlbumCategory
+     */
+    @Override
+    public TenantAlbumCategoryWrapper.TenantAlbumCategory detail(Long id) {
+        TenantAlbumCategory albumCategory = baseMapper.selectById(id);
+        if (albumCategory == null) {
+            throw new BizException("专辑分类不存在");
+        }
+        TenantAlbumCategoryWrapper.TenantAlbumCategory tenantAlbumCategory =
+                TenantAlbumCategoryWrapper.TenantAlbumCategory.from(JSON.toJSONString(albumCategory));
+
+        List<TenantAlbumCategoryDetail> list = tenantAlbumCategoryDetailService.lambdaQuery()
+                .eq(TenantAlbumCategoryDetail::getTenantAlbumCategoryId, id)
+                .list();
+        tenantAlbumCategory.setValues(list);
+        return tenantAlbumCategory;
+    }
+
+    /**
+     * 分页查询
+     *
+     * @param page  IPage<TenantAlbumCategory>
+     * @param query TenantAlbumCategoryWrapper.TenantAlbumCategoryQuery
+     * @return IPage<TenantAlbumCategory>
+     */
+    @Override
+    public IPage<TenantAlbumCategoryWrapper.TenantAlbumCategory> selectPage(
+            IPage<TenantAlbumCategoryWrapper.TenantAlbumCategory> page,
+            TenantAlbumCategoryWrapper.TenantAlbumCategoryQuery query) {
+
+        List<TenantAlbumCategory> tenantAlbumCategories = baseMapper.selectPage(page, query);
+
+        List<TenantAlbumCategoryWrapper.TenantAlbumCategory> result = tenantAlbumCategories.stream().map(next -> {
+            TenantAlbumCategoryWrapper.TenantAlbumCategory tenantAlbumCategory =
+                    new TenantAlbumCategoryWrapper.TenantAlbumCategory();
+            BeanUtils.copyProperties(next, tenantAlbumCategory);
+            return tenantAlbumCategory;
+        }).collect(Collectors.toList());
+
+        List<Long> idList = tenantAlbumCategories.stream().map(TenantAlbumCategory::getId).collect(Collectors.toList());
+        if (!idList.isEmpty()) {
+            List<TenantAlbumCategoryDetail> detailList = tenantAlbumCategoryDetailService.lambdaQuery()
+                    .in(TenantAlbumCategoryDetail::getTenantAlbumCategoryId, idList)
+                    .list();
+            Map<Long, List<TenantAlbumCategoryDetail>> groupById = detailList.stream()
+                    .collect(Collectors.groupingBy(TenantAlbumCategoryDetail::getTenantAlbumCategoryId));
+            result.forEach(next -> next.setValues(groupById.getOrDefault(next.getId(), new ArrayList<>())));
+        }
+        return page.setRecords(result);
+    }
+
+    /**
+     * 添加
+     *
+     * @param tenantAlbumCategory TenantAlbumCategoryWrapper.TenantAlbumCategory
+     * @return Boolean
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Boolean add(TenantAlbumCategoryWrapper.TenantAlbumCategory tenantAlbumCategory) {
+        Integer count = this.lambdaQuery()
+                .eq(TenantAlbumCategory::getName, tenantAlbumCategory.getName())
+                .eq(TenantAlbumCategory::getCategoryType, tenantAlbumCategory.getCategoryType())
+                .eq(TenantAlbumCategory::getDelFlag, false)
+                .count();
+        if (count > 0) {
+            throw new BizException("专辑分类名称已存在");
+        }
+
+        // 校验子分类值是否存在重复
+        List<TenantAlbumCategoryDetail> values = tenantAlbumCategory.getValues();
+        Set<String> names = values.stream().map(TenantAlbumCategoryDetail::getValue).collect(Collectors.toSet());
+        if (names.size() != values.size()) {
+            ETenantAlbumCategoryType categoryType = tenantAlbumCategory.getCategoryType();
+            throw new BizException(ETenantAlbumCategoryType.CATEGORY_TYPE.equals(categoryType) ? "类型不能有重复" : "级别不能有重复");
+        }
+
+        TenantAlbumCategory albumCategory = JSON.parseObject(tenantAlbumCategory.jsonString(),
+                TenantAlbumCategory.class);
+        this.save(albumCategory);
+        if (!values.isEmpty()) {
+            values.forEach(next -> next.setTenantAlbumCategoryId(albumCategory.getId()));
+            tenantAlbumCategoryDetailService.saveBatch(values);
+        }
+        return true;
+    }
+
+    /**
+     * 更新
+     *
+     * @param tenantAlbumCategory TenantAlbumCategoryWrapper.TenantAlbumCategory
+     * @return Boolean
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Boolean update(TenantAlbumCategoryWrapper.TenantAlbumCategory tenantAlbumCategory) {
+
+        Integer count = this.lambdaQuery()
+                .eq(TenantAlbumCategory::getName, tenantAlbumCategory.getName())
+                .eq(TenantAlbumCategory::getCategoryType, tenantAlbumCategory.getCategoryType())
+                .eq(TenantAlbumCategory::getDelFlag, false)
+                .ne(TenantAlbumCategory::getId, tenantAlbumCategory.getId())
+                .count();
+        if (count > 0) {
+            throw new BizException("专辑分类名称已存在");
+        }
+
+        // 校验子分类值是否存在重复
+        List<TenantAlbumCategoryDetail> values = tenantAlbumCategory.getValues();
+        Set<String> names = values.stream().map(TenantAlbumCategoryDetail::getValue).collect(Collectors.toSet());
+        if (names.size() != values.size()) {
+            TenantAlbumCategory albumCategory = this.getById(tenantAlbumCategory.getId());
+            ETenantAlbumCategoryType categoryType = albumCategory.getCategoryType();
+            throw new BizException(ETenantAlbumCategoryType.CATEGORY_TYPE.equals(categoryType) ? "类型不允许有重复" :
+                    "级别不允许有重复");
+        }
+
+        // 校验是否存在引用删除
+        List<TenantAlbumCategoryDetail> detailList = tenantAlbumCategoryDetailService.lambdaQuery()
+                .eq(TenantAlbumCategoryDetail::getTenantAlbumCategoryId, tenantAlbumCategory.getId())
+                .list();
+
+        List<Long> newUpdateIds = values.stream().map(TenantAlbumCategoryDetail::getId).filter(Objects::nonNull)
+                .collect(Collectors.toList());
+
+        List<Long> removeDetailIdList = detailList.stream().map(TenantAlbumCategoryDetail::getId)
+                .filter(next -> !newUpdateIds.contains(next)).collect(Collectors.toList());
+        if (!removeDetailIdList.isEmpty()) {
+            // 校验删除的分类值是否被使用,如果有使用,则提示
+            TenantAlbumCategory albumCategory = this.getById(tenantAlbumCategory.getId());
+            QueryWrapper<TenantAlbum> queryWrapper = new QueryWrapper<>();
+            queryWrapper.lambda()
+                    .eq(ETenantAlbumCategoryType.CATEGORY_TYPE.equals(albumCategory.getCategoryType()),
+                            TenantAlbum::getCategoryTypeId, tenantAlbumCategory.getId())
+                    .eq(ETenantAlbumCategoryType.CATEGORY_LEVEL.equals(albumCategory.getCategoryType()),
+                            TenantAlbum::getCategoryLevelId, tenantAlbumCategory.getId());
+            Integer useCount = tenantAlbumMapper.selectCount(queryWrapper);
+            if (useCount > 0) {
+                checkTenantAlbumCategoryDetailUsed(albumCategory.getCategoryType(), removeDetailIdList);
+            }
+            tenantAlbumCategoryDetailService.removeByIds(removeDetailIdList);
+        }
+        if (!values.isEmpty()) {
+            values.forEach(next -> next.setTenantAlbumCategoryId(tenantAlbumCategory.getId()));
+            tenantAlbumCategoryDetailService.saveOrUpdateBatch(values);
+        }
+
+        this.updateById(JSON.parseObject(tenantAlbumCategory.jsonString(), TenantAlbumCategory.class));
+        return true;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Boolean delete(Long id) {
+        TenantAlbumCategory albumCategory = this.getById(id);
+        if (albumCategory == null) {
+            throw new BizException("删除的数据不存在");
+        }
+        QueryWrapper<TenantAlbum> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda()
+                .eq(TenantAlbum::getCategoryLevelId, id)
+                .or()
+                .eq(TenantAlbum::getCategoryTypeId, id);
+        Integer count = tenantAlbumMapper.selectCount(queryWrapper);
+        if (count > 0) {
+            throw new BizException("专辑分类被使用");
+        }
+
+//        List<TenantAlbumCategoryDetail> list = tenantAlbumCategoryDetailService.lambdaQuery()
+//                .eq(TenantAlbumCategoryDetail::getTenantAlbumCategoryId, albumCategory.getId())
+//                .list();
+//        checkTenantAlbumCategoryDetailUsed(albumCategory.getCategoryType(), list);
+        albumCategory.setDelFlag(true);
+        this.updateById(albumCategory);
+        return true;
+    }
+
+    /**
+     * 校验专辑分类中的值是否有被应用
+     */
+    private void checkTenantAlbumCategoryDetailUsed(ETenantAlbumCategoryType categoryType,
+                                                    List<Long> list) {
+        if (list.isEmpty()) {
+            return;
+        }
+        List<String> idStrList = list.stream().map(Object::toString).collect(Collectors.toList());
+        QueryWrapper<TenantAlbumMusic> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda()
+                .in(ETenantAlbumCategoryType.CATEGORY_TYPE.equals(categoryType),
+                        TenantAlbumMusic::getType, idStrList)
+                .in(ETenantAlbumCategoryType.CATEGORY_LEVEL.equals(categoryType),
+                        TenantAlbumMusic::getType, idStrList);
+        Integer useCount = tenantAlbumMusicMapper.selectCount(queryWrapper);
+        // 删除的ID被应用的数量大于0
+        if (useCount > 0) {
+            throw new BizException("专辑分类存在" + (ETenantAlbumCategoryType.CATEGORY_TYPE.equals(categoryType) ? "类型" :
+                    "级别") + "引用");
+        }
+    }
+}

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

@@ -1,28 +1,44 @@
 package com.yonge.cooleshow.biz.dal.service.impl;
 
+import cn.hutool.core.util.NumberUtil;
 import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
-import com.yonge.cooleshow.biz.dal.dao.MusicFavoriteDao;
-import com.yonge.cooleshow.biz.dal.entity.*;
+import com.yonge.cooleshow.biz.dal.entity.MusicFavorite;
+import com.yonge.cooleshow.biz.dal.entity.MusicSheet;
+import com.yonge.cooleshow.biz.dal.entity.MusicTag;
+import com.yonge.cooleshow.biz.dal.entity.Subject;
+import com.yonge.cooleshow.biz.dal.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategory;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumCategoryDetail;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumMusic;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.SubjectTypeEnum;
 import com.yonge.cooleshow.biz.dal.mapper.SysUserMapper;
-import com.yonge.cooleshow.biz.dal.service.*;
+import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumMusicMapper;
+import com.yonge.cooleshow.biz.dal.service.MusicFavoriteService;
+import com.yonge.cooleshow.biz.dal.service.MusicSheetService;
+import com.yonge.cooleshow.biz.dal.service.MusicTagService;
+import com.yonge.cooleshow.biz.dal.service.SubjectService;
+import com.yonge.cooleshow.biz.dal.service.TenantAlbumCategoryDetailService;
+import com.yonge.cooleshow.biz.dal.service.TenantAlbumCategoryService;
+import com.yonge.cooleshow.biz.dal.service.TenantAlbumMusicService;
+import com.yonge.cooleshow.biz.dal.service.UserTenantAlbumRecordService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumMusicWrapper;
 import com.yonge.toolset.base.exception.BizException;
 import jodd.util.StringUtil;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.checkerframework.checker.units.qual.A;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import org.springframework.beans.BeanUtils;
-import lombok.extern.slf4j.Slf4j;
-import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumMusicWrapper;
-import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumMusicMapper;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -64,6 +80,9 @@ public class TenantAlbumMusicServiceImpl extends ServiceImpl<TenantAlbumMusicMap
     @Autowired
     private  SysUserFeignService sysUserFeignService;
 
+    @Autowired
+    private TenantAlbumCategoryDetailService tenantAlbumCategoryDetailService;
+
     /**
      * 查询详情
      * @param id 详情ID
@@ -102,12 +121,12 @@ public class TenantAlbumMusicServiceImpl extends ServiceImpl<TenantAlbumMusicMap
         String s = subjectType.toString();
         String type = query.getType();
         String level = query.getLevel();
-        String keyword = query.getKeyword();
 
         List<Long> musicSheetIds = tenantAlbumMusicMapper.selectMusicSheetIds(albumId, s, type, level);
 
-        if (CollectionUtils.isEmpty(musicSheetIds)){
-            throw new BizException("该声部下没有相关曲目");
+        if (CollectionUtils.isEmpty(musicSheetIds)) {
+            page.setTotal(0);
+            return page.setRecords(new ArrayList<>());
         }
         TenantAlbumMusicWrapper.StudentMusicSheetQuery musicSheetQuery = new TenantAlbumMusicWrapper.StudentMusicSheetQuery();
         musicSheetQuery.setMusicSheetIds(musicSheetIds);
@@ -215,11 +234,31 @@ public class TenantAlbumMusicServiceImpl extends ServiceImpl<TenantAlbumMusicMap
         }
 
         // 类型
-        List<String> types = list.stream().map(TenantAlbumMusic::getType).distinct().filter(StringUtils::isNotBlank).collect(Collectors.toList());
-        data.setTypes(types);
+        List<Long> typeIds =list.stream().map(TenantAlbumMusic::getType).distinct().filter(StringUtils::isNotBlank)
+                .filter(NumberUtil::isNumber).map(Long::valueOf).collect(Collectors.toList());
+        if (!typeIds.isEmpty()) {
+            List<TenantAlbumCategoryDetail> typeList = tenantAlbumCategoryDetailService.lambdaQuery()
+                    .in(TenantAlbumCategoryDetail::getId, typeIds).list();
+            List<String> typeNameList = typeList.stream()
+                    .map(TenantAlbumCategoryDetail::getValue).collect(Collectors.toList());
+            data.setTypes(typeNameList);
+            data.setTypeList(typeList);
+        } else {
+            data.setTypes(new ArrayList<>());
+        }
         // 级别
-        List<String> levels = list.stream().map(TenantAlbumMusic::getLevel).distinct().filter(StringUtils::isNotBlank).collect(Collectors.toList());
-        data.setLevels(levels);
+        List<Long> levelIds =list.stream().map(TenantAlbumMusic::getLevel).distinct().filter(StringUtils::isNotBlank)
+                .filter(NumberUtil::isNumber).map(Long::valueOf).collect(Collectors.toList());
+        if (!levelIds.isEmpty()) {
+            List<TenantAlbumCategoryDetail> levelList = tenantAlbumCategoryDetailService.lambdaQuery()
+                    .in(TenantAlbumCategoryDetail::getId, levelIds).list();
+            List<String> levelNameList = levelList.stream()
+                    .map(TenantAlbumCategoryDetail::getValue).collect(Collectors.toList());
+            data.setLevels(levelNameList);
+            data.setLevelList(levelList);
+        } else {
+            data.setLevels(new ArrayList<>());
+        }
 
         // 声部
         List<Long> subjectIds = musicSheets.stream()

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

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.baomidou.mybatisplus.extension.service.additional.query.impl.LambdaQueryChainWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.entity.*;
 import com.yonge.cooleshow.biz.dal.enums.*;
 import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumMapper;
@@ -18,6 +19,8 @@ import com.yonge.cooleshow.common.enums.PostStatusEnum;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import com.yonge.toolset.base.exception.BizException;
 import com.yonge.toolset.base.util.StringUtil;
+import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
+import com.yonge.toolset.utils.date.DateUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -26,6 +29,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
@@ -76,7 +80,14 @@ public class TenantAlbumServiceImpl extends ServiceImpl<TenantAlbumMapper, Tenan
     @Autowired
     private TenantAccountRecordService tenantAccountRecordService;
 
+    @Autowired
+    private SysMessageService sysMessageService;
+
+    @Autowired
+    private TenantAlbumService tenantAlbumService;
 
+    @Autowired
+    private UserTenantAlbumRecordService userTenantAlbumRecordService;
     /**
      * 查询详情
      *
@@ -291,6 +302,7 @@ public class TenantAlbumServiceImpl extends ServiceImpl<TenantAlbumMapper, Tenan
             case STUDENT: {
                 tenantActivationCodeService.addUserTenantAlbumRecord(userOrderDetailVo.getUserId(),userOrderDetailVo);
 
+                sendMsg(userOrderDetailVo);
                 break;
             }
 
@@ -344,6 +356,50 @@ public class TenantAlbumServiceImpl extends ServiceImpl<TenantAlbumMapper, Tenan
         }
     }
 
+    private void sendMsg(UserOrderDetailVo userOrderDetailVo) {
+        try {
+            SysUser user = sysUserFeignService.queryUserById(userOrderDetailVo.getUserId());
+
+            if (user == null) {
+                return;
+            }
+            Long userId = userOrderDetailVo.getUserId();
+
+            // 查询机构专辑信息
+            TenantAlbum tenantAlbum = tenantAlbumService.getById(userOrderDetailVo.getBizId());
+            if (tenantAlbum == null) {
+                return;
+            }
+
+            // 查询学生当前机构有效时间
+            UserTenantAlbumRecord albumRecord = userTenantAlbumRecordService
+                    .getNewestByTenantAlbumId(tenantAlbum.getId(), userId, userOrderDetailVo.getOrderClient());
+            if (albumRecord == null) {
+                return;
+            }
+            String dateStr = DateUtil.format(albumRecord.getEndTime(), DateUtil.DEFAULT_PATTERN);
+
+
+            Map<Long, String> receivers = new HashMap<>();
+            receivers.put(userId, user.getPhone());
+
+            if (userOrderDetailVo.getOrderClient().equals(ClientEnum.STUDENT)) {
+                Student student = studentService.getById(userId);
+                if (student.getTenantId() != null && student.getTenantId() >0) {
+                    try {
+                        String url = sysMessageService.selectConfigUrlJumpType(MessageTypeEnum.TENANT_ALBUM_BUY.getCode(),ClientEnum.TENANT_STUDENT.getCode(),userOrderDetailVo.getOrderNo());
+                        sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.TENANT_ALBUM_BUY,
+                                receivers, null, 0, url, ClientEnum.TENANT_STUDENT.getCode(),tenantAlbum.getName(),dateStr);
+                    } catch (Exception e) {
+                        log.error("机构学生购买训练教材", e);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("机构学生购买训练教材 : {}",e.getMessage());
+        }
+    }
+
 
     @Transactional(rollbackFor = Exception.class)
     @Override

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

@@ -0,0 +1,526 @@
+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.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.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.dao.StudentDao;
+import com.yonge.cooleshow.biz.dal.dao.SubjectDao;
+import com.yonge.cooleshow.biz.dal.dao.TeacherDao;
+import com.yonge.cooleshow.biz.dal.dto.search.StudentSearch;
+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.Teacher;
+import com.yonge.cooleshow.biz.dal.entity.TenantGroup;
+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.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.SysUserService;
+import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
+import com.yonge.cooleshow.biz.dal.service.im.ImGroupCoreService;
+import com.yonge.cooleshow.biz.dal.vo.StudentVo;
+import com.yonge.cooleshow.biz.dal.wrapper.StudentWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.im.ImGroupWrapper;
+import com.yonge.toolset.base.exception.BizException;
+import com.yonge.toolset.mybatis.support.PageUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 机构小组表
+ * 2023-10-11 09:24:50
+ */
+@Slf4j
+@Service
+public class TenantGroupServiceImpl extends ServiceImpl<TenantGroupMapper, TenantGroup> implements TenantGroupService {
+
+    @Autowired
+    private ImGroupService imGroupService;
+    @Autowired
+    private ImGroupCoreService imGroupCoreService;
+    @Autowired
+    private StudentDao studentDao;
+    @Autowired
+    private SubjectDao subjectDao;
+    @Autowired
+    private TeacherDao teacherDao;
+    @Autowired
+    private ImGroupMemberService imGroupMemberService;
+    @Autowired
+    private SysUserService sysUserService;
+
+    /**
+     * 查询详情
+     *
+     * @param id 详情ID
+     * @return TenantGroup
+     */
+    @Override
+    public TenantGroup detail(Long id) {
+
+        return baseMapper.selectById(id);
+    }
+
+    /**
+     * 分页查询
+     *
+     * @param page  IPage<TenantGroup>
+     * @param query TenantGroupWrapper.TenantGroupQuery
+     * @return IPage<TenantGroup>
+     */
+    @Override
+    public IPage<TenantGroupWrapper.TenantGroup> selectPage(IPage<TenantGroupWrapper.TenantGroup> page,
+                                                            TenantGroupWrapper.TenantGroupQuery query) {
+
+        IPage<TenantGroupWrapper.TenantGroup> iPage = page.setRecords(baseMapper.selectPage(page, query));
+        List<TenantGroupWrapper.TenantGroup> records = iPage.getRecords();
+        // 设置小组成员数量
+        if (!records.isEmpty()) {
+            List<Long> groupIdList =
+                    records.stream().map(TenantGroupWrapper.TenantGroup::getId).collect(Collectors.toList());
+            List<StudentWrapper.UserCount> userCounts = studentDao.countStudentByTenantGroupIds(query.getTenantId(),
+                    groupIdList);
+            Map<Long, Integer> groupBy =
+                    userCounts.stream().collect(Collectors.toMap(StudentWrapper.UserCount::getTenantGroupId
+                            , StudentWrapper.UserCount::getCount));
+
+            List<String> imGroupId = records.stream().map(TenantGroupWrapper.TenantGroup::getImGroupId)
+                    .filter(Objects::nonNull).collect(Collectors.toList());
+            List<String> existImgGroupIds = new ArrayList<>();
+            if (!imGroupId.isEmpty()) {
+                List<String> imgGroupIds = imGroupService.lambdaQuery()
+                        .in(ImGroup::getId, imGroupId)
+                        .list().stream().map(ImGroup::getId).collect(Collectors.toList());
+                existImgGroupIds.addAll(imgGroupIds);
+            }
+
+            for (TenantGroupWrapper.TenantGroup record : records) {
+                record.setGroupUserCount(groupBy.getOrDefault(record.getId(), 0));
+                record.setImGroupExist(existImgGroupIds.contains(record.getImGroupId()));
+            }
+        }
+        return iPage;
+    }
+
+    /**
+     * 添加
+     *
+     * @param tenantGroup TenantGroupWrapper.TenantGroup
+     * @return Boolean
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Boolean add(TenantGroupWrapper.TenantGroup tenantGroup, Boolean imGroupCreate) {
+        TenantGroup entity = JSON.parseObject(tenantGroup.jsonString(), TenantGroup.class);
+        Integer count = this.lambdaQuery()
+                .eq(TenantGroup::getTenantId, tenantGroup.getTenantId())
+                .eq(TenantGroup::getName, entity.getName())
+                .count();
+        if (count > 0) {
+            throw new BizException("小组名称已存在");
+        }
+        this.save(entity);
+        Long adminId = tenantGroup.getAdminId();
+        if (adminId != null && Boolean.TRUE.equals(imGroupCreate)) {
+            // 建群
+            try {
+                ImGroupWrapper.ImGroup imGroup = new ImGroupWrapper.ImGroup();
+                imGroup.setId(IdWorker.getId());
+                imGroup.setCreateBy(tenantGroup.getAdminId());
+                imGroup.setType(ImGroupType.ORG.getCode());
+                imGroup.setName(tenantGroup.getName());
+                String imGroupId = imGroupService.create(imGroup);
+                entity.setImGroupId(imGroupId);
+                this.updateById(entity);
+            } catch (Exception e) {
+                log.error("创建机构小组群失败", e);
+                throw new BizException("创建机构小组群失败");
+            }
+            // 加群成员
+            List<Long> userIds = tenantGroup.getUserIds();
+            if (CollectionUtils.isNotEmpty(userIds)) {
+                try {
+                    imGroupService.addGroupMember(entity.getImGroupId(), new HashSet<>(userIds));
+                } catch (Exception e) {
+                    log.error("加入机构小组群失败", e);
+                    throw new BizException("加入机构小组群失败");
+                }
+            }
+        }
+        // 加群成员
+        List<Long> userIds = tenantGroup.getUserIds();
+        if (CollectionUtils.isNotEmpty(userIds)) {
+            studentDao.update(null, Wrappers.<Student>lambdaUpdate()
+                    .in(Student::getUserId, userIds)
+                    .eq(Student::getTenantId, tenantGroup.getTenantId())
+                    .set(Student::getTenantGroupId, entity.getId()));
+        }
+        return true;
+    }
+
+    /**
+     * 更新
+     *
+     * @param tenantGroup TenantGroupWrapper.TenantGroup
+     * @return Boolean
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Boolean update(TenantGroupWrapper.TenantGroup tenantGroup, Boolean imGroupCreate) {
+        TenantGroup oldGroup = this.getById(tenantGroup.getId());
+
+        Integer count = this.lambdaQuery()
+                .ne(TenantGroup::getId, tenantGroup.getId())
+                .eq(TenantGroup::getTenantId, tenantGroup.getTenantId())
+                .eq(TenantGroup::getName, tenantGroup.getName())
+                .count();
+        if (count > 0) {
+            throw new BizException("小组名称已经存在");
+        }
+
+        TenantGroup entity = JSON.parseObject(tenantGroup.jsonString(), TenantGroup.class);
+        entity.setImGroupId(oldGroup.getImGroupId());
+        // 是否建群
+        if (Boolean.TRUE.equals(imGroupCreate)) {
+            String oldImGroupId = Optional.ofNullable(oldGroup.getImGroupId()).orElse("-1");
+            ImGroup imGroup = imGroupService.getById(oldImGroupId);
+            // 群被删除过,并且需要重新建群
+            if (imGroup == null) {
+                String imGroupId = createImGroup(entity.getAdminId(), tenantGroup.getName());
+                entity.setImGroupId(imGroupId);
+
+                // 添加群成员
+                List<Long> userIds = tenantGroup.getUserIds();
+                if (CollectionUtils.isNotEmpty(userIds)) {
+                    // 加群成员
+                    try {
+                        imGroupService.addGroupMember(imGroupId, new HashSet<>(userIds));
+                    } catch (Exception e) {
+                        log.error("加入机构小组群失败", e);
+                        throw new BizException("加入机构小组群失败");
+                    }
+                }
+                studentDao.update(null, Wrappers.<Student>lambdaUpdate()
+                        .in(Student::getUserId, userIds)
+                        .eq(Student::getTenantId, tenantGroup.getTenantId())
+                        .set(Student::getTenantGroupId, entity.getId()));
+            }
+        }
+        // 修改小组负责人,调整群主,更换群主需要新的群主为该群成员
+        changeGroupOwner(oldGroup, entity);
+        QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda()
+                .eq(Student::getTenantId, tenantGroup.getTenantId())
+                .eq(Student::getTenantGroupId, tenantGroup.getId());
+        List<Long> oldGroupUsers = studentDao.selectList(queryWrapper).stream().map(Student::getUserId)
+                .collect(Collectors.toList());
+
+        List<Long> newGroupUsers = tenantGroup.getUserIds();
+
+        List<Long> removeGroupUsers = oldGroupUsers.stream()
+                .filter(next -> !newGroupUsers.contains(next)).collect(Collectors.toList());
+        // 移除的群成员,退群
+//        ImGroup imGroup = imGroupService.getById(Optional.ofNullable(entity.getImGroupId()).orElse("-1"));
+        if (!removeGroupUsers.isEmpty()) {
+//            if (imGroup != null) {
+//                try {
+//                    for (Long removeUserId : removeGroupUsers) {
+//                        imGroupCoreService.groupQuit(removeUserId, ClientEnum.STUDENT.getCode(),
+//                                oldGroup.getImGroupId(),
+//                                true);
+//                    }
+//                } catch (Exception e) {
+//                    log.error("群成员移出群失败", e);
+//                    throw new BizException("群成员移出群失败");
+//                }
+//            }
+            studentDao.update(null, Wrappers.<Student>lambdaUpdate()
+                    .in(Student::getUserId, removeGroupUsers)
+                    .eq(Student::getTenantId, tenantGroup.getTenantId())
+                    .set(Student::getTenantGroupId, -1L));
+        }
+        // 新增的群成员
+        List<Long> newAddGroupUsers = newGroupUsers.stream().filter(next -> !oldGroupUsers.contains(next))
+                .collect(Collectors.toList());
+        if (!newAddGroupUsers.isEmpty()) {
+            // 加群成员
+//            if (imGroup != null) {
+//                try {
+//                    imGroupService.addGroupMember(oldGroup.getImGroupId(), new HashSet<>(newAddGroupUsers));
+//                } catch (Exception e) {
+//                    log.error("加入机构小组群失败", e);
+//                    throw new BizException("加入机构小组群失败");
+//                }
+//            }
+            studentDao.update(null, Wrappers.<Student>lambdaUpdate()
+                    .in(Student::getUserId, newAddGroupUsers)
+                    .eq(Student::getTenantId, tenantGroup.getTenantId())
+                    .set(Student::getTenantGroupId, entity.getId()));
+        }
+        return this.updateById(entity);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Boolean delete(Long id) {
+        TenantGroup group = this.getById(id);
+        if (group == null) {
+            throw new BizException("机构小组不存在");
+        }
+        String imGroupId = group.getImGroupId();
+        if (imGroupId != null) {
+            ImGroup imGroup = imGroupService.getById(imGroupId);
+            if (imGroup != null) {
+                try {
+                    imGroupCoreService.groupDismiss(imGroupId);
+                } catch (Exception e) {
+                    log.error("解散群失败", e);
+                }
+            }
+        }
+        studentDao.update(null, Wrappers.<Student>lambdaUpdate()
+                .eq(Student::getTenantId, group.getTenantId())
+                .eq(Student::getTenantGroupId, id)
+                .set(Student::getTenantGroupId, -1L));
+        return removeById(id);
+    }
+
+    /**
+     * 查询机构小组群成员
+     *
+     * @param tenantId      机构ID
+     * @param tenantGroupId 机构小组ID
+     * @return 机构小组成员列表
+     */
+    @Override
+    public List<TenantGroupWrapper.TenantGroupMember> queryGroupMember(Long tenantId, Long tenantGroupId) {
+        StudentSearch studentSearch = new StudentSearch();
+        studentSearch.setTenantId(tenantId);
+        studentSearch.setTenantGroupId(tenantGroupId.toString());
+        studentSearch.setRows(9999);
+        studentSearch.setPage(1);
+        List<StudentVo> studentVos = studentDao.selectPage(PageUtil.getPage(studentSearch), studentSearch);
+        if (studentVos.isEmpty()) {
+            return new ArrayList<>();
+        }
+        Map<String, String> subjectIdNameMap = new HashMap<>();
+        List<String> subjectIds = studentVos.stream().map(Student::getSubjectId).filter(StringUtils::isNotEmpty)
+                .distinct().collect(Collectors.toList());
+
+        if (!subjectIds.isEmpty()) {
+            List<Subject> subject = subjectDao.findBySubjectByIdList(String.join(",", subjectIds));
+            Map<String, String> map = subject.stream().collect(Collectors.toMap(next -> next.getId().toString(),
+                    Subject::getName));
+            subjectIdNameMap.putAll(map);
+        }
+
+
+        return studentVos.stream().map(next -> {
+            TenantGroupWrapper.TenantGroupMember member = new TenantGroupWrapper.TenantGroupMember();
+            member.setUserId(next.getUserId());
+            member.setTenantId(next.getTenantId());
+            member.setName(next.getUsername());
+            member.setGender(next.getGender());
+            member.setBirthdate(next.getBirthdate());
+            member.setPhone(next.getPhone());
+            member.setAvatar(next.getAvatar());
+            member.setSubjectId(next.getSubjectId());
+            member.setSubjectName(subjectIdNameMap.getOrDefault(next.getSubjectId(), ""));
+            return member;
+        }).collect(Collectors.toList());
+    }
+
+    /**
+     * 小组交接
+     *
+     * @param adjustTenantGroup 入参
+     * @return 成功/失败
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Boolean adjustTenantGroup(TenantGroupWrapper.AdjustTenantGroup adjustTenantGroup) {
+        Long teacherId = adjustTenantGroup.getTeacherId();
+        Teacher teacher = teacherDao.selectById(teacherId);
+        if (teacher == null) {
+            throw new BizException("移交的老师不存在");
+        }
+        List<TenantGroupWrapper.AdjustTenantGroupDetail> details = adjustTenantGroup.getAdjustTenantGroupDetails();
+        if (details.isEmpty()) {
+            throw new BizException("未选择移交信息");
+        }
+        List<Long> tenantGroupIds =
+                details.stream().map(TenantGroupWrapper.AdjustTenantGroupDetail::getTenantGroupId).collect(Collectors.toList());
+        List<TenantGroup> tenantGroups = this.lambdaQuery().in(TenantGroup::getId, tenantGroupIds).list();
+        Map<Long, String> groupBy = tenantGroups.stream().filter(next -> next.getImGroupId() != null)
+                .collect(Collectors.toMap(TenantGroup::getId, TenantGroup::getImGroupId));
+        for (TenantGroupWrapper.AdjustTenantGroupDetail detail : details) {
+            Long toTeacher = detail.getTeacherId();
+            if (teacherId.equals(toTeacher) && Boolean.FALSE.equals(detail.getDismiss())) {
+                continue;
+            }
+            String imGroupId = groupBy.get(detail.getTenantGroupId());
+            ImGroup imGroup = imGroupService.getById(Optional.ofNullable(imGroupId).orElse("-1"));
+            if (toTeacher != null) {
+                // 更换群主
+                if (imGroup != null) {
+                    // 新负责人加入群
+                    try {
+                        SysUser newTeacher = sysUserService.getByUserId(toTeacher);
+                        ImGroupMember imGroupMember = new ImGroupMember();
+                        imGroupMember.setGroupId(imGroupId);
+                        imGroupMember.setUserId(toTeacher);
+                        imGroupMember.setRoleType(ImGroupMemberRoleType.TEACHER);
+                        imGroupMember.setAvatar(newTeacher.getAvatar());
+                        imGroupMember.setNickname(newTeacher.getUsername());
+                        imGroupMember.setIsAdmin(true);
+                        imGroupMember.setRoleType(ImGroupMemberRoleType.TEACHER);
+
+                        imGroupMemberService.join(Collections.singletonList(imGroupMember), imGroupId);
+                    } catch (Exception e) {
+                        log.error("负责人加入群失败", e);
+                        throw new BizException("负责人加入群失败");
+                    }
+
+                    try {
+                        imGroupCoreService.changeGroupOwner(imGroupId, String.valueOf(toTeacher),
+                                String.valueOf(teacherId));
+                        imGroupCoreService.groupQuit(teacherId, ClientEnum.TEACHER.getCode(),
+                                imGroupId, true);
+                        imGroupService.lambdaUpdate()
+                                .set(ImGroup::getCreateBy, toTeacher)
+                                .eq(ImGroup::getId, imGroupId);
+                    } catch (Exception e) {
+                        log.error("移交负责人失败", e);
+                        throw new BizException("移交负责人失败");
+                    }
+                }
+                this.lambdaUpdate()
+                        .set(TenantGroup::getAdminId, toTeacher)
+                        .set(imGroup == null, TenantGroup::getImGroupId, null)
+                        .eq(TenantGroup::getId, detail.getTenantGroupId())
+                        .update();
+            } else if (Boolean.TRUE.equals(detail.getDismiss())) {
+                // 解散群
+                if (imGroup != null) {
+                    try {
+                        imGroupCoreService.groupDismiss(imGroupId);
+                    } catch (Exception e) {
+                        log.error("解散群失败", e);
+                        throw new BizException("解散群失败");
+                    }
+                }
+                this.lambdaUpdate()
+                        .set(TenantGroup::getAdminId, null)
+                        .set(TenantGroup::getImGroupId, null)
+                        .eq(TenantGroup::getId, detail.getTenantGroupId())
+                        .update();
+            }
+        }
+        return true;
+    }
+
+    public String createImGroup(Long groupAdmin, String groupName) {
+        try {
+            ImGroupWrapper.ImGroup imGroup = new ImGroupWrapper.ImGroup();
+            imGroup.setId(IdWorker.getId());
+            imGroup.setCreateBy(groupAdmin);
+            imGroup.setType(ImGroupType.ORG.getCode());
+            imGroup.setName(groupName);
+            return imGroupService.create(imGroup);
+        } catch (Exception e) {
+            log.error("创建机构小组群失败", e);
+            throw new BizException("创建机构小组群失败");
+        }
+    }
+
+    private void changeGroupOwner(TenantGroup oldGroup, TenantGroup newGroup) {
+        if (newGroup.getAdminId() == null || newGroup.getAdminId().equals(oldGroup.getAdminId())) {
+            return;
+        }
+        String imGroupId = Optional.ofNullable(newGroup.getImGroupId()).orElse("-1");
+        ImGroup imGroup = imGroupService.getById(imGroupId);
+        if (imGroup == null) {
+            // 群不存在
+            return;
+        }
+
+        if (!newGroup.getImGroupId().equals(oldGroup.getImGroupId())) {
+            // 旧的群被删除了,不需要交换身份
+            return;
+        }
+
+        ImGroupMember admin = imGroupMemberService.lambdaQuery()
+                .eq(ImGroupMember::getGroupId, imGroupId)
+                .eq(ImGroupMember::getIsAdmin, true)
+                .last("limit 1").one();
+
+        if (admin.getUserId().equals(newGroup.getAdminId())) {
+            // 处理交接后群主和小组的负责人一致
+            return;
+        }
+
+        // 如果新负责人不在群,先加入群
+        ImGroupMember groupMember = imGroupMemberService.lambdaQuery()
+                .eq(ImGroupMember::getGroupId, newGroup.getImGroupId())
+                .eq(ImGroupMember::getRoleType, ImGroupMemberRoleType.TEACHER)
+                .eq(ImGroupMember::getUserId, newGroup.getAdminId())
+                .eq(ImGroupMember::getIsAdmin, true)
+                .last("limit 1").one();
+        if (groupMember != null) {
+            return;
+        }
+        // 新负责人加入群
+        try {
+            SysUser newTeacher = sysUserService.getByUserId(newGroup.getAdminId());
+            ImGroupMember imGroupMember = new ImGroupMember();
+            imGroupMember.setGroupId(newGroup.getImGroupId());
+            imGroupMember.setUserId(newGroup.getAdminId());
+            imGroupMember.setRoleType(ImGroupMemberRoleType.TEACHER);
+            imGroupMember.setAvatar(newTeacher.getAvatar());
+            imGroupMember.setNickname(newTeacher.getUsername());
+            imGroupMember.setIsAdmin(true);
+
+            imGroupMemberService.join(Collections.singletonList(imGroupMember), newGroup.getImGroupId());
+        } catch (Exception e) {
+            log.error("负责人加入群失败", e);
+            throw new BizException("负责人加入群失败");
+        }
+
+        try {
+            imGroupCoreService.changeGroupOwner(imGroupId,
+                    String.valueOf(newGroup.getAdminId()),
+                    String.valueOf(admin.getUserId()));
+            imGroupCoreService.groupQuit(admin.getUserId(), ClientEnum.TEACHER.getCode(), imGroupId, true);
+            imGroupService.lambdaUpdate()
+                    .set(ImGroup::getCreateBy, newGroup.getAdminId())
+                    .eq(ImGroup::getId, imGroupId);
+        } catch (Exception e) {
+            log.error("更换群主失败", e);
+            throw new BizException("更换群主失败");
+        }
+    }
+
+    public List<Student> queryStudent(Long tenantId, Long tenantGroupId) {
+        QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda()
+                .eq(Student::getTenantId, tenantId)
+                .eq(Student::getTenantGroupId, tenantGroupId);
+        return studentDao.selectList(queryWrapper);
+    }
+}

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

@@ -13,9 +13,11 @@ import com.yonge.cooleshow.biz.dal.dao.SubjectDao;
 import com.yonge.cooleshow.biz.dal.dao.TeacherDao;
 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.mapper.SysAreaMapper;
+import com.yonge.cooleshow.biz.dal.mapper.TenantGroupMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantUnbindRecordMapper;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantUnbindRecordWrapper;
@@ -85,6 +87,12 @@ public class TenantUnbindRecordServiceImpl extends ServiceImpl<TenantUnbindRecor
     @Autowired
     private ImUserFriendService imUserFriendService;
 
+    @Autowired
+    private TenantGroupMapper tenantGroupMapper;
+
+    @Autowired
+    private ImGroupMemberService imGroupMemberService;
+
     /**
      * @param id 详情ID
      * @return TenantUnbindRecord
@@ -211,6 +219,8 @@ public class TenantUnbindRecordServiceImpl extends ServiceImpl<TenantUnbindRecor
         if (unbindRecord == null || !ETenantUnBindAuditStatus.DOING.equals(unbindRecord.getStatus())) {
             throw new BizException("审核记录不存在");
         }
+        Teacher teacher = teacherDao.selectById(unbindRecord.getUserId());
+
         this.lambdaUpdate()
                 .set(TenantUnbindRecord::getStatus, Boolean.TRUE.equals(audio.getStatus()) ?
                         ETenantUnBindAuditStatus.PASS : ETenantUnBindAuditStatus.UNPASS)
@@ -221,20 +231,36 @@ public class TenantUnbindRecordServiceImpl extends ServiceImpl<TenantUnbindRecor
                 .eq(TenantUnbindRecord::getStatus, ETenantUnBindAuditStatus.DOING)
                 .update();
         if (Boolean.TRUE.equals(audio.getStatus())) {
-            Teacher teacher = teacherDao.selectById(unbindRecord.getUserId());
+            // 判断是否存在机构小组群主身份
+            QueryWrapper<TenantGroup> queryWrapper = new QueryWrapper<>();
+            queryWrapper.lambda()
+                    .eq(TenantGroup::getTenantId, teacher.getTenantId())
+                    .eq(TenantGroup::getAdminId, teacher.getUserId());
+            Integer count = tenantGroupMapper.selectCount(queryWrapper);
+            if (count > 0) {
+                throw new BizException("该老师存在机构小组负责人身份,请先更换老师或者退出小组");
+            }
+
             Long tenantId = teacher.getTenantId();
             if (tenantId != -1L) {
                 // 解散机构群
-                List<ImGroup> imGroups = imGroupService.lambdaQuery()
-                        .eq(ImGroup::getCreateBy, unbindRecord.getUserId())
-                        .eq(ImGroup::getType, ImGroupType.ORG)
-                        .list();
-                for (ImGroup imGroup : imGroups) {
-                    try {
-                        imGroupService.dismiss(imGroup.getId());
-                    } catch (Exception e) {
-                        log.error("老师解绑审核成功,解散机构群失败:{}", e.getMessage());
-                    }
+                List<String> imGroupIds = imGroupMemberService.lambdaQuery()
+                        .eq(ImGroupMember::getUserId, unbindRecord.getUserId())
+                        .eq(ImGroupMember::getIsAdmin, true)
+                        .eq(ImGroupMember::getRoleType, ImGroupMemberRoleType.TEACHER)
+                        .list().stream().map(ImGroupMember::getGroupId).distinct().collect(Collectors.toList());
+                if (!imGroupIds.isEmpty()) {
+                    List<ImGroup> imGroups = imGroupService.lambdaQuery()
+                            .in(ImGroup::getId, imGroupIds)
+                            .eq(ImGroup::getType, ImGroupType.ORG)
+                            .list();
+                    imGroups.forEach(next -> {
+                        try {
+                            imGroupService.dismiss(next.getId());
+                        } catch (Exception e) {
+                            log.error("老师修改机构,解散机构群失败:{}", e.getMessage());
+                        }
+                    });
                 }
                 imUserFriendService.delStudentFriendByTenantId(tenantId, unbindRecord.getUserId(),
                         ClientEnum.TEACHER.getCode());

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

@@ -637,6 +637,31 @@ public class UserOrderRefundServiceImpl extends ServiceImpl<UserOrderRefundDao,
         }
     }
 
+
+    /**
+     * 处理退款业务
+     *
+     * @param orderNo 退款单id
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void orderRefundSuccessBizHandleByOrderNo(String orderNo) {
+        //处理业务
+        OrderDetailSearch search = new OrderDetailSearch();
+        search.setOrderNo(orderNo);
+        List<UserOrderDetailVo> userOrderDetails = orderDetailService.selectList(search);
+        UserOrder order = userOrderService.getByOrderNo(orderNo);
+
+        for (UserOrderDetailVo vo : userOrderDetails) {
+            Consumer<UserOrderDetailVo> refundAfterConsumer = refundSuccess.get(vo.getGoodType());
+            if (!Objects.isNull(refundAfterConsumer)) {
+                refundAfterConsumer.accept(vo);
+            }
+            vo.setPaymentVersion(order.getPaymentVersion());
+            accountHandle(vo);
+        }
+    }
+
     /**
      * 处理退款后账户
      *

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

@@ -12,6 +12,7 @@ import com.microsvc.toolkit.config.jwt.utils.JwtUserInfo;
 import com.microsvc.toolkit.middleware.payment.common.api.BasePaymentService;
 import com.microsvc.toolkit.middleware.payment.common.api.PaymentServiceContext;
 import com.microsvc.toolkit.middleware.payment.common.api.entity.*;
+import com.microsvc.toolkit.middleware.payment.common.api.enums.DivideBackStatus;
 import com.microsvc.toolkit.middleware.payment.common.api.enums.PaymentStatus;
 import com.yonge.cooleshow.biz.dal.entity.*;
 import com.yonge.cooleshow.biz.dal.enums.*;
@@ -131,6 +132,11 @@ public class UserPaymentCoreServiceImpl implements UserPaymentCoreService {
     private UserOrderRefundBillService userOrderRefundBillService;
 
 
+    @Autowired
+    private TenantMemberService tenantMemberService;
+
+    @Autowired
+    private DivBackRecordService divBackRecordService;
 
 
     // 订单商品参数校验,获取订单支付金额
@@ -1261,55 +1267,153 @@ public class UserPaymentCoreServiceImpl implements UserPaymentCoreService {
         // 执行状态锁定
         String lockName = redisCacheService.getPaymentCacheKey(paymentOrder.getOrderNo());
         DistributedLock.of(redissonClient).runIfLockCanGet(lockName, () -> {
-            // 提交退款申请记录
-            UserOrderRefund userRefundOrder = new UserOrderRefund();
-            userRefundOrder.setUserId(paymentOrder.getId());
-            userRefundOrder.setOrderId(paymentOrder.getId());
-            userRefundOrder.setOrderNo(paymentOrder.getOrderNo());
-            userRefundOrder.setOredrDetilIds(detail.getOrderDetailList().stream().map(o-> o.getId().toString()).collect(Collectors.joining(",")));
-            userRefundOrder.setStatus(AuthStatusEnum.PASS);
-            userRefundOrder.setApplyAmount(paymentOrder.getPaymentCashAmount());
-            userRefundOrder.setActualAmount(paymentOrder.getPaymentCashAmount());
-            userRefundOrder.setReason(reason);
-            userOrderRefundService.save(userRefundOrder);
-
-            //入退款单表
-            UserOrderRefundBill orderRefundBill = new UserOrderRefundBill();
-            orderRefundBill.setRefundId(userRefundOrder.getId());
-            orderRefundBill.setBillNo(IdWorker.getIdStr());
-            orderRefundBill.setRefundAmt(userRefundOrder.getActualAmount());
-
-
-            RefundOrder refundOrder = new RefundOrder();
-            refundOrder.setUserId(paymentOrder.getUserId().toString());
-            refundOrder.setMerOrderNo(orderRefundBill.getBillNo());
-            refundOrder.setRefundAmount(orderRefundBill.getRefundAmt());
-            refundOrder.setOrderAmount(paymentOrder.getPaymentCashAmount());
-            refundOrder.setReason(reason);
-            refundOrder.setTransNo(paymentOrder.getTransNo());
-            refundOrder.setPaymentOrderNo(paymentOrder.getOrderNo());
-
-            // 执行状态锁定
-            String lockNameInner = redisCacheService.getPaymentCacheKey(orderRefundBill.getBillNo());
-            DistributedLock.of(redissonClient).runIfLockCanGet(lockNameInner, () -> {
-                RefundResp refundResp = paymentServiceContext.getPaymentService(paymentOrder.getPaymentVendor()).refund(refundOrder);
-                // 申请请求失败
-                if (PaymentStatus.FAILED == refundResp.getPaymentStatus()) {
-                    orderRefundBill.setStatus(TradeStatusEnum.failed);
-                    orderRefundBill.setPayFailMsg(refundResp.getMsg());
-                } else {
-                    orderRefundBill.setTransNo(refundResp.getTransNo());
-                    orderRefundBill.setStatus(TradeStatusEnum.pending);
+
+            // 如果是易宝的订单,查询分账是否给到子账户,没有给子账户的直接退款
+
+            // 分账给子账户的 先 分账归还,如果归还成功,再退款,归还失败,不退款,退款后的逻辑还是继续走
+
+            boolean refundFlag = true;
+            if (paymentOrder.getPaymentVendor().equals(EPayerType.YEEPAY.getDesc())) {
+                List<PaymentDivMemberRecord> records = paymentDivMemberRecordService.getByOrderNo(paymentOrder.getOrderNo());
+
+                for (PaymentDivMemberRecord record : records) {
+                    if (record.getTenantEnterFlag()) {
+
+                        refundFlag = saveDivBackRecord(paymentOrder, record);
+
+                    }
                 }
-                userOrderRefundBillService.save(orderRefundBill);
+            }
+
+            if (refundFlag) {
+                refundOnly(reason, paymentOrder.getOrderNo());
+            }
+
+            //处理退款业务
+            userOrderRefundService.orderRefundSuccessBizHandleByOrderNo(paymentOrder.getOrderNo());
+        }, 10L, TimeUnit.SECONDS);
 
-                //处理退款业务
-               userOrderRefundService.orderRefundSuccessBizHandle(userRefundOrder.getId());
+    }
 
-            }, 10L, TimeUnit.SECONDS);
+    /**
+     * 退款
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void refundOnly(String reason, String orderNo) {
+
+        // 查询订单信息,支付状态
+        UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService.getUserPaymentOrderByOrderNo(orderNo);
+        if (Objects.isNull(paymentOrder)) {
+            throw new BizException("订单信息不存在");
+        }
+        if (!OrderStatusEnum.PAID.getCode().equals(paymentOrder.getStatus().getCode())) {
+            throw  new BizException("订单状态异常");
+        }
+        UserOrderVo detail = userOrderService.detail(paymentOrder.getId());
+        if (Objects.isNull(detail)) {
+            throw new BizException("订单信息不存在");
+        }
+
+        // 提交退款申请记录
+        UserOrderRefund userRefundOrder = new UserOrderRefund();
+        userRefundOrder.setUserId(paymentOrder.getId());
+        userRefundOrder.setOrderId(paymentOrder.getId());
+        userRefundOrder.setOrderNo(paymentOrder.getOrderNo());
+        userRefundOrder.setOredrDetilIds(detail.getOrderDetailList().stream().map(o -> o.getId().toString()).collect(Collectors.joining(",")));
+        userRefundOrder.setStatus(AuthStatusEnum.PASS);
+        userRefundOrder.setApplyAmount(paymentOrder.getPaymentCashAmount());
+        userRefundOrder.setActualAmount(paymentOrder.getPaymentCashAmount());
+        userRefundOrder.setReason(reason);
+        userOrderRefundService.save(userRefundOrder);
+
+        //入退款单表
+        UserOrderRefundBill orderRefundBill = new UserOrderRefundBill();
+        orderRefundBill.setRefundId(userRefundOrder.getId());
+        orderRefundBill.setBillNo(IdWorker.getIdStr());
+        orderRefundBill.setRefundAmt(userRefundOrder.getActualAmount());
+
+
+        RefundOrder refundOrder = new RefundOrder();
+        refundOrder.setUserId(paymentOrder.getUserId().toString());
+        refundOrder.setMerOrderNo(orderRefundBill.getBillNo());
+        refundOrder.setRefundAmount(orderRefundBill.getRefundAmt());
+        refundOrder.setOrderAmount(paymentOrder.getPaymentCashAmount());
+        refundOrder.setReason(reason);
+        refundOrder.setTransNo(paymentOrder.getTransNo());
+        refundOrder.setPaymentOrderNo(paymentOrder.getOrderNo());
+
+        // 执行状态锁定
+        String lockNameInner = redisCacheService.getPaymentCacheKey(orderRefundBill.getBillNo());
+        DistributedLock.of(redissonClient).runIfLockCanGet(lockNameInner, () -> {
+            RefundResp refundResp = paymentServiceContext.getPaymentService(paymentOrder.getPaymentVendor()).refund(refundOrder);
+            // 申请请求失败
+            if (PaymentStatus.FAILED == refundResp.getPaymentStatus()) {
+                orderRefundBill.setStatus(TradeStatusEnum.failed);
+                orderRefundBill.setPayFailMsg(refundResp.getMsg());
+            } else {
+                orderRefundBill.setTransNo(refundResp.getTransNo());
+                orderRefundBill.setStatus(TradeStatusEnum.pending);
+            }
+            userOrderRefundBillService.save(orderRefundBill);
 
         }, 10L, TimeUnit.SECONDS);
+    }
+
+    private boolean saveDivBackRecord(UserPaymentOrderWrapper.UserPaymentOrder paymentOrder, PaymentDivMemberRecord record) {
+
 
+        BasePaymentService paymentService = paymentServiceContext.getPaymentService(paymentOrder.getPaymentVendor());
+
+        boolean refundFlag = true;
+        DivBackRecord divBackRecord = new DivBackRecord();
+        divBackRecord.setPaymentDivMemberRecordId(record.getId());
+        divBackRecord.setDivideBackOrderNo(IdWorker.getIdStr());
+        divBackRecord.setTimes(1);
+        divBackRecord.setPaymentVendor(paymentOrder.getPaymentVendor());
+
+        // 分账数据
+        DivideReq.DivideBackDetail divideBackDetail = DivideReq.DivideBackDetail.builder()
+            .amount(record.getAmount())
+            .divideDetailNo(record.getTransNo())
+            .divideBackReason("订单退款")
+            .build();
+
+        List<DivideResp.DivMember> divMembers = JSON.parseArray(record.getDivMemberJson(), DivideResp.DivMember.class);
+        if (CollectionUtils.isNotEmpty(divMembers)) {
+            divideBackDetail.setDivideDetailNo(divMembers.get(0).getDetailNo());
+        }
+
+        DivideReq.MemberDivideBack memberDivideBack = DivideReq.MemberDivideBack.builder()
+            .payerName(EPayerType.YEEPAY.getDesc())
+            .memberId(record.getMemberId())
+            .devOrderNo(record.getDivOrderNo())
+            .platformPayeeMemberId(paymentService.getPaymentConfig().getMerchantId())
+            .divideBackOrderNo(divBackRecord.getDivideBackOrderNo())
+            .payOrderNo(paymentOrder.getOrderNo())
+            .transNo(paymentOrder.getTransNo())
+            .divideBackDetail(Lists.newArrayList(divideBackDetail))
+            .build();
+
+
+        try {
+
+            DivideResp.DivideBack divideBack = paymentService.divideBack(tenantMemberService
+                .getMerchantConfig(paymentOrder.getPaymentVendor()), memberDivideBack);
+            if (divideBack.getStatus() != DivideBackStatus.SUCCESS) {
+                refundFlag = false;
+            }
+            divBackRecord.setReason(divideBack.getReason());
+            divBackRecord.setDivideBackTransNo(divideBack.getDivideBackTransNo());
+            divBackRecord.setStatus(divideBack.getStatus().name());
+
+        }catch (Exception e) {
+            log.error("分账回归失败orderNo={}", memberDivideBack.getDivideBackOrderNo(), e);
+            refundFlag = false;
+            divBackRecord.setReason(e.getMessage());
+        }
+        divBackRecordService.save(divBackRecord);
+        return refundFlag;
     }
 
 }

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